1use std::fs::File;
24use std::io::{prelude::*, BufReader};
25use std::path;
26
27use crate::hound;
29
30use crate::decoder;
32use crate::error;
33use crate::{crc, x3};
34
35use crate::x3::{FrameHeader, X3aSpec};
36use error::X3Error;
37use quick_xml::events::Event;
38use quick_xml::Reader;
39
40pub const X3_READ_BUFFER_SIZE: usize = 1024 * 24;
41pub const X3_WRITE_BUFFER_SIZE: usize = X3_READ_BUFFER_SIZE * 8;
42
43pub struct X3aReader {
44 reader: BufReader<File>,
45 spec: X3aSpec,
46 remaing_bytes: usize,
47 read_buf: [u8; X3_READ_BUFFER_SIZE],
48
49 frame_errors: usize,
52}
53
54impl X3aReader {
55 pub fn open<P: AsRef<path::Path>>(filename: P) -> Result<Self, X3Error> {
56 let file = File::open(filename).unwrap();
57 let mut remaing_bytes = file.metadata()?.len() as usize;
58 let mut reader = BufReader::with_capacity(64 * 1024, file);
59
60 let (spec, header_size) = read_archive_header(&mut reader)?;
61 remaing_bytes -= header_size;
62
63 Ok(Self {
64 reader,
65 spec,
66 remaing_bytes,
67 read_buf: [0u8; X3_READ_BUFFER_SIZE],
68 frame_errors: 0,
69 })
70 }
71
72 pub fn spec(&self) -> &X3aSpec {
73 &self.spec
74 }
75
76 fn read_bytes(&mut self, mut buf_len: usize) -> std::io::Result<()> {
77 if self.remaing_bytes < buf_len {
78 buf_len = self.remaing_bytes;
79 }
80 self.remaing_bytes -= buf_len;
81 self.reader.read_exact(&mut self.read_buf[0..buf_len])
82 }
83
84 fn read_frame_header(&mut self) -> Result<FrameHeader, X3Error> {
85 self.read_bytes(x3::FrameHeader::LENGTH)?;
86 decoder::read_frame_header(&self.read_buf[0..x3::FrameHeader::LENGTH])
87 }
88
89 fn read_frame_payload(&mut self, header: &FrameHeader) -> Result<(), X3Error> {
90 self.read_bytes(header.payload_len)?;
91
92 let payload = &self.read_buf[0..header.payload_len];
93 let crc = crc::crc16(&payload);
94 if crc != header.payload_crc {
95 return Err(X3Error::FrameHeaderInvalidPayloadCRC);
96 }
97
98 Ok(())
99 }
100
101 pub fn decode_next_frame(&mut self, wav_buf: &mut [i16; X3_WRITE_BUFFER_SIZE]) -> Result<Option<usize>, X3Error> {
102 if self.remaing_bytes <= x3::FrameHeader::LENGTH {
104 return Ok(None);
105 }
106
107 let frame_header = self.read_frame_header()?;
109 let samples = frame_header.samples as usize;
110 if self.remaing_bytes < frame_header.payload_len {
111 return Ok(None);
112 }
113
114 if frame_header.payload_len > X3_READ_BUFFER_SIZE {
115 return Err(X3Error::FrameHeaderInvalidPayloadLen);
117 }
118
119 self.read_frame_payload(&frame_header)?;
121 let x3_bytes = &mut self.read_buf[0..frame_header.payload_len];
122
123 match decoder::decode_frame(x3_bytes, wav_buf, &self.spec.params, samples) {
125 Ok(result) => Ok(result),
126 Err(err) => {
127 self.frame_errors += 1;
128 println!("Frame error: {:?}", err);
129 Ok(None)
130 }
131 }
132 }
133}
134
135fn read_archive_header(reader: &mut BufReader<File>) -> Result<(X3aSpec, usize), X3Error> {
139 {
141 let mut arc_header = [0u8; x3::Archive::ID.len()];
142 reader.read_exact(&mut arc_header)?;
143 if !arc_header.eq(x3::Archive::ID) {
144 return Err(X3Error::ArchiveHeaderXMLInvalidKey);
145 }
146 }
147
148 let header = {
150 let mut header_buf = [0u8; x3::FrameHeader::LENGTH];
151 reader.read_exact(&mut header_buf)?;
152 decoder::read_frame_header(&mut header_buf)?
153 };
154
155 let mut payload: Vec<u8> = vec![0; header.payload_len];
157 reader.read_exact(&mut payload)?;
158 let xml = String::from_utf8_lossy(&payload);
159
160 let (sample_rate, params) = parse_xml(&xml)?;
161
162 let header_size = x3::FrameHeader::LENGTH + payload.len();
163
164 Ok((
165 X3aSpec {
166 sample_rate,
167 params,
168 channels: header.channels,
169 },
170 header_size,
171 ))
172}
173
174pub fn x3a_to_wav<P: AsRef<path::Path>>(x3a_filename: P, wav_filename: P) -> Result<(), X3Error> {
186 let mut x3a_reader = X3aReader::open(x3a_filename)?;
187
188 let x3_spec = x3a_reader.spec();
189 let spec = hound::WavSpec {
190 channels: 1, sample_rate: x3_spec.sample_rate,
192 bits_per_sample: 16,
193 sample_format: hound::SampleFormat::Int,
194 };
195
196 let mut writer = hound::WavWriter::create(wav_filename, spec)?;
197 let mut wav = [0i16; X3_WRITE_BUFFER_SIZE];
198 loop {
199 match x3a_reader.decode_next_frame(&mut wav)? {
200 Some(samples) => {
201 write_samples(&mut writer, &wav, samples)?;
202 }
203 None => break,
204 }
205 }
206
207 Ok(())
208}
209
210fn write_samples(
211 writer: &mut hound::WavWriter<std::io::BufWriter<std::fs::File>>,
212 buf: &[i16],
213 num_samples: usize,
214) -> Result<(), X3Error> {
215 let mut fast_writer = writer.get_i16_writer(num_samples as u32);
216 for i in 0..num_samples {
217 unsafe {
218 fast_writer.write_sample_unchecked(buf[i]);
219 }
220 }
221 fast_writer.flush()?;
222 Ok(())
223}
224
225fn parse_xml(xml: &str) -> Result<(u32, x3::Parameters), X3Error> {
229 let mut reader = Reader::from_str(xml);
230 reader.trim_text(true);
231
232 let mut buf = Vec::new();
233 let mut fs = Vec::with_capacity(3);
234 let mut bl = Vec::with_capacity(3);
235 let mut codes = Vec::with_capacity(3);
236 let mut th = Vec::with_capacity(3);
237
238 loop {
240 match reader.read_event(&mut buf) {
241 Ok(Event::Start(ref e)) => match e.name() {
242 b"FS" => fs.push(reader.read_text(e.name(), &mut Vec::new()).unwrap()),
243 b"BLKLEN" => bl.push(reader.read_text(e.name(), &mut Vec::new()).unwrap()),
244 b"CODES" => codes.push(reader.read_text(e.name(), &mut Vec::new()).unwrap()),
245 b"T" => th.push(reader.read_text(e.name(), &mut Vec::new()).unwrap()),
246 _ => (),
247 },
248 Ok(Event::Eof) => break, Err(e) => {
250 println!(
251 "Error reading X3 Archive header (XML) at position {}: {:?}",
252 reader.buffer_position(),
253 e
254 );
255 return Err(X3Error::ArchiveHeaderXMLInvalid);
256 }
257 _ => (), }
259
260 buf.clear();
262 }
263 println!("sample rate: {}", fs[0]);
264 println!("block length: {}", bl[0]);
265 println!("Rice codes: {}", codes[0]);
266 println!("thresholds: {}", th[0]);
267
268 let sample_rate = fs[0].parse::<u32>().unwrap();
269 let block_len = bl[0].parse::<u32>().unwrap();
270 let mut rice_code_ids = Vec::new();
271 for word in codes[0].split(',') {
272 match word {
273 "RICE0" => rice_code_ids.push(0),
274 "RICE1" => rice_code_ids.push(1),
275 "RICE2" => rice_code_ids.push(2),
276 "RICE3" => rice_code_ids.push(3),
277 "BFP" => (),
278 _ => return Err(X3Error::ArchiveHeaderXMLRiceCode),
279 };
280 }
281 let thresholds: Vec<usize> = th[0].split(',').map(|s| s.parse::<usize>().unwrap()).collect();
282
283 let mut rc_array: [usize; 3] = [0; 3];
284 let mut th_array: [usize; 3] = [0; 3];
285
286 #[allow(clippy::manual_memcpy)]
287 for i in 0..3 {
288 rc_array[i] = rice_code_ids[i];
289 th_array[i] = thresholds[i];
290 }
291 let params = x3::Parameters::new(
292 block_len as usize,
293 x3::Parameters::DEFAULT_BLOCKS_PER_FRAME,
294 rc_array,
295 th_array,
296 )?;
297
298 Ok((sample_rate, params))
299}
300
301#[cfg(test)]
314mod tests {
315 }