add option for not stopping on the first decoding error
[nihav-tool.git] / src / wavwriter.rs
CommitLineData
98b31ef7 1extern crate nihav_core;
3660c127 2
98b31ef7
KS
3use nihav_core::io::byteio::*;
4use nihav_core::frame::*;
3660c127
KS
5use std::fs::File;
6use std::io::SeekFrom;
7
8pub struct WavWriter<'a> {
9 io: Box<ByteWriter<'a>>,
10 data_pos: u64,
11}
12
13fn write_byte(wr: &mut ByteWriter, sample: u8) -> ByteIOResult<()> {
14 wr.write_byte(sample)
15}
16
17fn write_s16(wr: &mut ByteWriter, sample: i16) -> ByteIOResult<()> {
18 wr.write_u16le(sample as u16)
19}
20
21fn write_s32(wr: &mut ByteWriter, sample: i32) -> ByteIOResult<()> {
22 wr.write_u16le((sample >> 16) as u16)
23}
24
25fn write_f32(wr: &mut ByteWriter, sample: f32) -> ByteIOResult<()> {
26 let mut out = (sample * 32768.0) as i32;
27 if out < -32768 { out = -32768; }
28 if out > 32767 { out = 32767; }
29 if out < 0 { out += 65536; }
30 wr.write_u16le(out as u16)
31}
32
33macro_rules! write_data {
34 ($wr:expr, $buf:expr, $write:ident) => ({
35 let len = $buf.get_length();
36 let ainfo = $buf.get_info();
37 let nch = ainfo.get_channels() as usize;
38 let mut offs: Vec<usize> = Vec::with_capacity(nch);
39 for ch in 0..nch { offs.push($buf.get_offset(ch)); }
bcaa61db 40 let is_planar = $buf.get_step() == 1;
3660c127
KS
41 let data = $buf.get_data();
42
bcaa61db
KS
43 if is_planar {
44 for i in 0..len {
45 for ch in 0..nch {
46 let sample = data[offs[ch] + i];
47 $write($wr, sample)?;
48 }
49 }
50 } else {
51 for i in 0..len*nch {
52 let sample = data[i];
3660c127
KS
53 $write($wr, sample)?;
54 }
55 }
56 })
57}
58
59impl<'a> WavWriter<'a> {
e47ee411 60 pub fn new(name: &str) -> Self {
3660c127
KS
61 let file = File::create(name).unwrap();
62 let fw = Box::new(FileWriter::new_write(file));
63 let io = ByteWriter::new(Box::leak(fw));
64 WavWriter { io: Box::new(io), data_pos: 0 }
65 }
66 pub fn write_header(&mut self, ainfo: NAAudioInfo) -> ByteIOResult<()> {
67 let bits = ainfo.get_format().get_bits() as usize;
68
69 self.io.write_buf(b"RIFF")?;
70 self.io.write_u32le(0)?;
71 self.io.write_buf(b"WAVE")?;
72
73 self.io.write_buf(b"fmt ")?;
74 self.io.write_u32le(16)?;
75 self.io.write_u16le(0x0001)?; // PCM
76 self.io.write_u16le(ainfo.get_channels() as u16)?;
77 self.io.write_u32le(ainfo.get_sample_rate() as u32)?;
78
79 if bits < 16 {
80 self.io.write_u32le((ainfo.get_channels() as u32) * (ainfo.get_sample_rate() as u32))?;
81 self.io.write_u16le(ainfo.get_channels() as u16)?; // block align
82 self.io.write_u16le(8)?;
83 } else {
84 self.io.write_u32le(2 * (ainfo.get_channels() as u32) * (ainfo.get_sample_rate() as u32))?;
85 self.io.write_u16le((2 * ainfo.get_channels()) as u16)?; // block align
86 self.io.write_u16le(16)?;
87 }
88
89 self.io.write_buf(b"data")?;
90 self.io.write_u32le(0)?;
91
92 self.data_pos = self.io.tell();
93 Ok(())
94 }
95 pub fn write_frame(&mut self, abuf: NABufferType) -> ByteIOResult<()> {
96 match abuf {
97 NABufferType::AudioU8(ref buf) => {
98 write_data!(&mut self.io, buf, write_byte);
99 }
100 NABufferType::AudioI16(ref buf) => {
101 write_data!(&mut self.io, buf, write_s16);
102 }
103 NABufferType::AudioI32(ref buf) => {
104 write_data!(&mut self.io, buf, write_s32);
105 }
106 NABufferType::AudioF32(ref buf) => {
107 write_data!(&mut self.io, buf, write_f32);
108 }
109 NABufferType::AudioPacked(ref buf) => {
110 self.io.write_buf(buf.get_data().as_slice())?;
111 }
112 _ => {},
113 };
114 Ok(())
115 }
116}
117
118impl<'a> Drop for WavWriter<'a> {
119 #[allow(unused_variables)]
120 fn drop(&mut self) {
121 let size = self.io.tell();
122 if (self.data_pos > 0) && (size >= self.data_pos) {
123 let res = self.io.seek(SeekFrom::Start(4));
124 let res = self.io.write_u32le((size - 8) as u32);
125 let res = self.io.seek(SeekFrom::Start(self.data_pos - 4));
126 let res = self.io.write_u32le(((size as u64) - self.data_pos) as u32);
127 }
128 }
129}