Commit | Line | Data |
---|---|---|
98b31ef7 | 1 | extern crate nihav_core; |
3660c127 | 2 | |
98b31ef7 KS |
3 | use nihav_core::io::byteio::*; |
4 | use nihav_core::frame::*; | |
3660c127 KS |
5 | use std::fs::File; |
6 | use std::io::SeekFrom; | |
7 | ||
8 | pub struct WavWriter<'a> { | |
9 | io: Box<ByteWriter<'a>>, | |
10 | data_pos: u64, | |
2e4688a6 KS |
11 | be: bool, |
12 | bits: u8, | |
3660c127 KS |
13 | } |
14 | ||
15 | fn write_byte(wr: &mut ByteWriter, sample: u8) -> ByteIOResult<()> { | |
16 | wr.write_byte(sample) | |
17 | } | |
18 | ||
19 | fn write_s16(wr: &mut ByteWriter, sample: i16) -> ByteIOResult<()> { | |
20 | wr.write_u16le(sample as u16) | |
21 | } | |
22 | ||
23 | fn write_s32(wr: &mut ByteWriter, sample: i32) -> ByteIOResult<()> { | |
24 | wr.write_u16le((sample >> 16) as u16) | |
25 | } | |
26 | ||
27 | fn write_f32(wr: &mut ByteWriter, sample: f32) -> ByteIOResult<()> { | |
28 | let mut out = (sample * 32768.0) as i32; | |
29 | if out < -32768 { out = -32768; } | |
30 | if out > 32767 { out = 32767; } | |
31 | if out < 0 { out += 65536; } | |
32 | wr.write_u16le(out as u16) | |
33 | } | |
34 | ||
35 | macro_rules! write_data { | |
36 | ($wr:expr, $buf:expr, $write:ident) => ({ | |
37 | let len = $buf.get_length(); | |
38 | let ainfo = $buf.get_info(); | |
39 | let nch = ainfo.get_channels() as usize; | |
40 | let mut offs: Vec<usize> = Vec::with_capacity(nch); | |
41 | for ch in 0..nch { offs.push($buf.get_offset(ch)); } | |
bcaa61db | 42 | let is_planar = $buf.get_step() == 1; |
3660c127 KS |
43 | let data = $buf.get_data(); |
44 | ||
bcaa61db KS |
45 | if is_planar { |
46 | for i in 0..len { | |
47 | for ch in 0..nch { | |
48 | let sample = data[offs[ch] + i]; | |
49 | $write($wr, sample)?; | |
50 | } | |
51 | } | |
52 | } else { | |
53 | for i in 0..len*nch { | |
54 | let sample = data[i]; | |
3660c127 KS |
55 | $write($wr, sample)?; |
56 | } | |
57 | } | |
58 | }) | |
59 | } | |
60 | ||
61 | impl<'a> WavWriter<'a> { | |
e47ee411 | 62 | pub fn new(name: &str) -> Self { |
3660c127 | 63 | let file = File::create(name).unwrap(); |
f7e9662a | 64 | let file = std::io::BufWriter::new(file); |
3660c127 KS |
65 | let fw = Box::new(FileWriter::new_write(file)); |
66 | let io = ByteWriter::new(Box::leak(fw)); | |
2e4688a6 | 67 | WavWriter { io: Box::new(io), data_pos: 0, be: false, bits: 0 } |
3660c127 KS |
68 | } |
69 | pub fn write_header(&mut self, ainfo: NAAudioInfo) -> ByteIOResult<()> { | |
70 | let bits = ainfo.get_format().get_bits() as usize; | |
71 | ||
72 | self.io.write_buf(b"RIFF")?; | |
73 | self.io.write_u32le(0)?; | |
74 | self.io.write_buf(b"WAVE")?; | |
75 | ||
76 | self.io.write_buf(b"fmt ")?; | |
77 | self.io.write_u32le(16)?; | |
78 | self.io.write_u16le(0x0001)?; // PCM | |
79 | self.io.write_u16le(ainfo.get_channels() as u16)?; | |
b338b484 | 80 | self.io.write_u32le(ainfo.get_sample_rate())?; |
3660c127 | 81 | |
033d6b00 | 82 | if bits <= 8 { |
b338b484 | 83 | self.io.write_u32le((ainfo.get_channels() as u32) * ainfo.get_sample_rate())?; |
3660c127 KS |
84 | self.io.write_u16le(ainfo.get_channels() as u16)?; // block align |
85 | self.io.write_u16le(8)?; | |
86 | } else { | |
b338b484 | 87 | self.io.write_u32le(2 * (ainfo.get_channels() as u32) * ainfo.get_sample_rate())?; |
3660c127 KS |
88 | self.io.write_u16le((2 * ainfo.get_channels()) as u16)?; // block align |
89 | self.io.write_u16le(16)?; | |
90 | } | |
91 | ||
92 | self.io.write_buf(b"data")?; | |
93 | self.io.write_u32le(0)?; | |
94 | ||
2e4688a6 KS |
95 | self.bits = bits as u8; |
96 | self.be = ainfo.get_format().is_be(); | |
3660c127 KS |
97 | self.data_pos = self.io.tell(); |
98 | Ok(()) | |
99 | } | |
100 | pub fn write_frame(&mut self, abuf: NABufferType) -> ByteIOResult<()> { | |
101 | match abuf { | |
102 | NABufferType::AudioU8(ref buf) => { | |
103 | write_data!(&mut self.io, buf, write_byte); | |
104 | } | |
105 | NABufferType::AudioI16(ref buf) => { | |
106 | write_data!(&mut self.io, buf, write_s16); | |
107 | } | |
108 | NABufferType::AudioI32(ref buf) => { | |
109 | write_data!(&mut self.io, buf, write_s32); | |
110 | } | |
111 | NABufferType::AudioF32(ref buf) => { | |
112 | write_data!(&mut self.io, buf, write_f32); | |
113 | } | |
114 | NABufferType::AudioPacked(ref buf) => { | |
033d6b00 KS |
115 | let data = buf.get_data(); |
116 | match self.bits { | |
117 | _ if !self.be && (self.bits & 7) == 0 => { | |
118 | self.io.write_buf(data.as_slice())?; | |
119 | }, | |
120 | 8 => { | |
121 | self.io.write_buf(data.as_slice())?; | |
122 | }, | |
123 | 12 if !self.be => { | |
124 | let mut src = data.chunks_exact(3); | |
b338b484 | 125 | for chunk in src.by_ref() { |
033d6b00 KS |
126 | self.io.write_byte(chunk[0] << 4)?; |
127 | self.io.write_byte((chunk[1] << 4) | (chunk[0] >> 4))?; | |
128 | self.io.write_byte(chunk[1] & 0xF0)?; | |
129 | self.io.write_byte(chunk[2])?; | |
130 | } | |
131 | let tail = src.remainder(); | |
132 | if tail.len() == 2 { | |
133 | self.io.write_byte(tail[0] << 4)?; | |
134 | self.io.write_byte(tail[1] << 4)?; | |
135 | } | |
136 | } | |
137 | 16 => { | |
138 | for samp in data.chunks(2) { | |
139 | self.io.write_byte(samp[1])?; | |
140 | self.io.write_byte(samp[0])?; | |
141 | } | |
142 | }, | |
143 | 24 => { | |
144 | for samp in data.chunks(3) { | |
145 | self.io.write_byte(samp[2])?; | |
146 | self.io.write_byte(samp[1])?; | |
147 | self.io.write_byte(samp[0])?; | |
148 | } | |
149 | }, | |
150 | 32 => { | |
151 | for samp in data.chunks(4) { | |
152 | self.io.write_byte(samp[3])?; | |
153 | self.io.write_byte(samp[2])?; | |
154 | self.io.write_byte(samp[1])?; | |
155 | self.io.write_byte(samp[0])?; | |
156 | } | |
157 | }, | |
158 | _ => unimplemented!(), | |
159 | }; | |
3660c127 KS |
160 | } |
161 | _ => {}, | |
162 | }; | |
163 | Ok(()) | |
164 | } | |
165 | } | |
166 | ||
167 | impl<'a> Drop for WavWriter<'a> { | |
168 | #[allow(unused_variables)] | |
169 | fn drop(&mut self) { | |
170 | let size = self.io.tell(); | |
171 | if (self.data_pos > 0) && (size >= self.data_pos) { | |
172 | let res = self.io.seek(SeekFrom::Start(4)); | |
173 | let res = self.io.write_u32le((size - 8) as u32); | |
174 | let res = self.io.seek(SeekFrom::Start(self.data_pos - 4)); | |
b338b484 | 175 | let res = self.io.write_u32le((size - self.data_pos) as u32); |
ad8d992f | 176 | let res = self.io.flush(); |
3660c127 KS |
177 | } |
178 | } | |
179 | } |