1use anyhow::{Context, Result, bail};
12use std::fs::File;
13use std::io::{Cursor, Read, Seek, SeekFrom};
14use std::path::Path;
15
16#[derive(Debug, Clone)]
17pub struct NwaHeader {
18 pub channels: u16,
19 pub bits_per_sample: u16,
20 pub samples_per_sec: u32,
21 pub pack_mod: i32,
22 pub zero_mod: i32,
23 pub unit_cnt: u32,
24 pub original_size: u32,
25 pub pack_size: u32,
26 pub sample_cnt: u32,
27 pub unit_sample_cnt: u32,
28 pub last_sample_cnt: u32,
29 pub last_sample_pack_size: u32,
30}
31
32impl NwaHeader {
33 pub fn is_uncompressed(&self) -> bool {
34 self.pack_mod == -1
35 }
36
37 pub fn frame_count(&self) -> u32 {
38 if self.channels == 0 {
39 return 0;
40 }
41 self.sample_cnt / (self.channels as u32)
42 }
43}
44
45#[derive(Debug)]
46struct UnitCache {
47 unit_no: i32,
48 unit_sample_cnt: u32,
49 buf: Vec<u8>,
50}
51
52impl UnitCache {
53 fn new() -> Self {
54 Self {
55 unit_no: -1,
56 unit_sample_cnt: 0,
57 buf: Vec::new(),
58 }
59 }
60}
61
62trait ReadSeek: Read + Seek + Send {}
64impl<T: Read + Seek + Send> ReadSeek for T {}
65
66pub struct NwaReader {
68 file: Box<dyn ReadSeek>,
69 base_offset: u64,
70 header: NwaHeader,
71 unit_offsets: Vec<u32>,
72 one_sample_byte_size: u32,
73 read_sample_pos: u32,
74 cache: UnitCache,
75}
76
77impl std::fmt::Debug for NwaReader {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 f.debug_struct("NwaReader")
80 .field("base_offset", &self.base_offset)
81 .field("header", &self.header)
82 .field("unit_offsets_len", &self.unit_offsets.len())
83 .field("one_sample_byte_size", &self.one_sample_byte_size)
84 .field("read_sample_pos", &self.read_sample_pos)
85 .finish()
86 }
87}
88
89impl NwaReader {
90 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
91 Self::open_with_offset(path, 0)
92 }
93
94 pub fn open_with_offset(path: impl AsRef<Path>, base_offset: u64) -> Result<Self> {
95 let mut file =
96 File::open(&path).with_context(|| format!("open NWA: {}", path.as_ref().display()))?;
97 if base_offset != 0 {
98 file.seek(SeekFrom::Start(base_offset))?;
99 }
100 let header = read_header(&mut file)?;
101
102 let mut unit_offsets = Vec::new();
103 if header.pack_mod != -1 {
104 unit_offsets.resize(header.unit_cnt as usize, 0);
105 let mut tmp = vec![0u8; header.unit_cnt as usize * 4];
106 file.read_exact(&mut tmp)?;
107 for i in 0..header.unit_cnt as usize {
108 let o = u32::from_le_bytes([
109 tmp[i * 4],
110 tmp[i * 4 + 1],
111 tmp[i * 4 + 2],
112 tmp[i * 4 + 3],
113 ]);
114 unit_offsets[i] = o;
115 }
116 }
117
118 let one_sample_byte_size = (header.bits_per_sample as u32) / 8;
119
120 Ok(Self {
121 file: Box::new(file),
122 base_offset,
123 header,
124 unit_offsets,
125 one_sample_byte_size,
126 read_sample_pos: 0,
127 cache: UnitCache::new(),
128 })
129 }
130
131 pub fn open_from_bytes(bytes: Vec<u8>) -> Result<Self> {
132 let mut file = Cursor::new(bytes);
133 let header = read_header_from_reader(&mut file)?;
134
135 let mut unit_offsets = Vec::new();
136 if header.pack_mod != -1 {
137 unit_offsets.resize(header.unit_cnt as usize, 0);
138 let mut tmp = vec![0u8; header.unit_cnt as usize * 4];
139 file.read_exact(&mut tmp)?;
140 for i in 0..header.unit_cnt as usize {
141 let o = u32::from_le_bytes([
142 tmp[i * 4],
143 tmp[i * 4 + 1],
144 tmp[i * 4 + 2],
145 tmp[i * 4 + 3],
146 ]);
147 unit_offsets[i] = o;
148 }
149 }
150
151 let one_sample_byte_size = (header.bits_per_sample as u32) / 8;
152
153 Ok(Self {
154 file: Box::new(file),
155 base_offset: 0,
156 header,
157 unit_offsets,
158 one_sample_byte_size,
159 read_sample_pos: 0,
160 cache: UnitCache::new(),
161 })
162 }
163
164 pub fn header(&self) -> &NwaHeader {
165 &self.header
166 }
167
168 pub fn set_read_sample_pos(&mut self, frame_pos: u32) {
170 self.read_sample_pos = frame_pos.saturating_mul(self.header.channels as u32);
171 }
172
173 pub fn get_read_sample_pos(&self) -> u32 {
175 let ch = self.header.channels as u32;
176 self.read_sample_pos.checked_div(ch).unwrap_or(0)
177 }
178
179 pub fn read_samples(&mut self, frame_cnt: u32) -> Result<Vec<u8>> {
183 if self.header.channels != 1 && self.header.channels != 2 {
184 bail!("unsupported channels: {}", self.header.channels);
185 }
186 if self.header.bits_per_sample != 8 && self.header.bits_per_sample != 16 {
187 bail!(
188 "unsupported bits_per_sample: {}",
189 self.header.bits_per_sample
190 );
191 }
192
193 let need_byte_size =
194 (frame_cnt as u64) * (self.header.channels as u64) * (self.one_sample_byte_size as u64);
195 let mut out = vec![0u8; need_byte_size as usize];
196 let mut dp = 0usize;
197 let mut need = need_byte_size as i64;
198
199 while need > 0 {
200 if self.read_sample_pos >= self.header.sample_cnt {
201 break;
202 }
203
204 let copy_byte_size: usize = if self.header.pack_mod == -1 {
205 self.read_no_pack_data(need as u64, &mut out[dp..])?
207 } else {
208 let unit_no = self.read_sample_pos / self.header.unit_sample_cnt;
210 self.read_unit(unit_no)?;
211
212 let ofs = ((self.read_sample_pos % self.header.unit_sample_cnt) as usize)
213 * (self.one_sample_byte_size as usize);
214 let mut cb = (self.cache.unit_sample_cnt as usize
215 * self.one_sample_byte_size as usize)
216 .saturating_sub(ofs);
217 if cb > need as usize {
218 cb = need as usize;
219 }
220 if cb == 0 {
221 break;
222 }
223 out[dp..dp + cb].copy_from_slice(&self.cache.buf[ofs..ofs + cb]);
224 cb
225 };
226
227 if copy_byte_size == 0 {
228 break;
229 }
230 dp += copy_byte_size;
231 need -= copy_byte_size as i64;
232 self.read_sample_pos += (copy_byte_size as u32) / self.one_sample_byte_size;
233 }
234
235 out.truncate(dp);
236 Ok(out)
237 }
238
239 pub fn to_wav_bytes(&mut self) -> Result<Vec<u8>> {
241 let total_frames = self.header.frame_count();
242 self.set_read_sample_pos(0);
243 let pcm = self.read_samples(total_frames)?;
244
245 let fmt_tag: u16 = 1; let channels = self.header.channels;
247 let sample_rate = self.header.samples_per_sec;
248 let bits = self.header.bits_per_sample;
249 let block_align = (channels as u32 * (bits as u32 / 8)) as u16;
250 let byte_rate = sample_rate * (block_align as u32);
251 let data_len = pcm.len() as u32;
252
253 let mut wav = Vec::with_capacity(44 + pcm.len());
254 wav.extend_from_slice(b"RIFF");
255 wav.extend_from_slice(&(36u32 + data_len).to_le_bytes());
256 wav.extend_from_slice(b"WAVE");
257
258 wav.extend_from_slice(b"fmt ");
259 wav.extend_from_slice(&16u32.to_le_bytes());
260 wav.extend_from_slice(&fmt_tag.to_le_bytes());
261 wav.extend_from_slice(&channels.to_le_bytes());
262 wav.extend_from_slice(&sample_rate.to_le_bytes());
263 wav.extend_from_slice(&byte_rate.to_le_bytes());
264 wav.extend_from_slice(&block_align.to_le_bytes());
265 wav.extend_from_slice(&bits.to_le_bytes());
266
267 wav.extend_from_slice(b"data");
268 wav.extend_from_slice(&data_len.to_le_bytes());
269 wav.extend_from_slice(&pcm);
270 Ok(wav)
271 }
272
273 fn read_no_pack_data(&mut self, need_byte_size: u64, out: &mut [u8]) -> Result<usize> {
274 let data_ofs = (self.read_sample_pos as u64) * (self.one_sample_byte_size as u64);
275 let file_ofs = self.base_offset + 44 + data_ofs; self.file.seek(SeekFrom::Start(file_ofs))?;
278
279 let max_data_len = (self.header.sample_cnt as u64) * (self.one_sample_byte_size as u64);
281 let remain = max_data_len.saturating_sub(data_ofs);
282 let to_read = std::cmp::min(need_byte_size, std::cmp::min(remain, out.len() as u64));
283 let buf = &mut out[..to_read as usize];
284 self.file.read_exact(buf)?;
285 Ok(to_read as usize)
286 }
287
288 fn read_unit(&mut self, unit_no: u32) -> Result<()> {
289 if self.cache.unit_no == unit_no as i32 {
290 return Ok(());
291 }
292
293 if unit_no >= self.header.unit_cnt {
294 bail!(
295 "unit_no out of range: {} >= {}",
296 unit_no,
297 self.header.unit_cnt
298 );
299 }
300
301 if self.header.pack_mod == -1 {
302 bail!("read_unit called for uncompressed NWA");
303 }
304 if self.header.bits_per_sample != 16 {
305 bail!(
306 "compressed NWA currently requires 16-bit PCM (got {})",
307 self.header.bits_per_sample
308 );
309 }
310
311 let src_ofs = self.base_offset + (self.unit_offsets[unit_no as usize] as u64);
312 self.file.seek(SeekFrom::Start(src_ofs))?;
313
314 let init_byte_cnt = (self.header.channels as usize) * (self.one_sample_byte_size as usize);
317 let mut init_bytes = vec![0u8; init_byte_cnt.max(1)];
318 self.file.read_exact(&mut init_bytes)?;
319 let mut init_l = 0i32;
320 let mut init_r = 0i32;
321 if self.one_sample_byte_size == 2 {
322 init_l = i16::from_le_bytes([init_bytes[0], init_bytes[1]]) as i32;
323 if self.header.channels == 2 {
324 init_r = i16::from_le_bytes([init_bytes[2], init_bytes[3]]) as i32;
325 }
326 } else {
327 init_l = init_bytes[0] as i32;
328 if self.header.channels == 2 {
329 init_r = init_bytes[1] as i32;
330 }
331 }
332
333 let (unit_sample_cnt, src_size) = if unit_no == self.header.unit_cnt - 1 {
334 (
335 self.header.last_sample_cnt,
336 self.header.last_sample_pack_size as usize,
337 )
338 } else {
339 let a = self.unit_offsets[unit_no as usize] as u64;
340 let b = self.unit_offsets[unit_no as usize + 1] as u64;
341 (self.header.unit_sample_cnt, (b.saturating_sub(a)) as usize)
342 };
343 let mut src = vec![0u8; src_size.saturating_sub(init_byte_cnt)];
344 self.file.read_exact(&mut src)?;
345
346 self.cache.buf.resize(unit_sample_cnt as usize * 2, 0);
347 nwa_unpack_unit(
348 &src,
349 self.header.pack_mod,
350 self.header.zero_mod != 0,
351 self.header.channels,
352 init_l,
353 init_r,
354 unit_sample_cnt,
355 &mut self.cache.buf,
356 )?;
357
358 self.cache.unit_no = unit_no as i32;
359 self.cache.unit_sample_cnt = unit_sample_cnt;
360 Ok(())
361 }
362}
363
364fn read_header(file: &mut File) -> Result<NwaHeader> {
365 read_header_from_reader(file)
366}
367
368fn read_header_from_reader<R: Read + ?Sized>(file: &mut R) -> Result<NwaHeader> {
369 let mut buf = [0u8; 44];
370 file.read_exact(&mut buf)?;
371 let mut o = 0usize;
372
373 let channels = u16::from_le_bytes([buf[o], buf[o + 1]]);
374 o += 2;
375 let bits_per_sample = u16::from_le_bytes([buf[o], buf[o + 1]]);
376 o += 2;
377 let samples_per_sec = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
378 o += 4;
379 let pack_mod = i32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
380 o += 4;
381 let zero_mod = i32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
382 o += 4;
383 let unit_cnt = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
384 o += 4;
385 let original_size = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
386 o += 4;
387 let pack_size = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
388 o += 4;
389 let sample_cnt = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
390 o += 4;
391 let unit_sample_cnt = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
392 o += 4;
393 let last_sample_cnt = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
394 o += 4;
395 let last_sample_pack_size = u32::from_le_bytes([buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]);
396
397 Ok(NwaHeader {
398 channels,
399 bits_per_sample,
400 samples_per_sec,
401 pack_mod,
402 zero_mod,
403 unit_cnt,
404 original_size,
405 pack_size,
406 sample_cnt,
407 unit_sample_cnt,
408 last_sample_cnt,
409 last_sample_pack_size,
410 })
411}
412
413struct BitReaderLE<'a> {
414 buf: &'a [u8],
415 byte_pos: usize,
416 bit_pos: u8,
417}
418
419impl<'a> BitReaderLE<'a> {
420 fn new(buf: &'a [u8]) -> Self {
421 Self {
422 buf,
423 byte_pos: 0,
424 bit_pos: 0,
425 }
426 }
427
428 fn read_bits(&mut self, n: u8) -> u32 {
429 debug_assert!(n <= 8);
430 let b0 = *self.buf.get(self.byte_pos).unwrap_or(&0);
431 let b1 = *self.buf.get(self.byte_pos + 1).unwrap_or(&0);
432 let w = u16::from_le_bytes([b0, b1]);
433 let v = ((w as u32) >> (self.bit_pos as u32)) & ((1u32 << n) - 1);
434
435 self.bit_pos = self.bit_pos.wrapping_add(n);
436 if self.bit_pos >= 8 {
437 self.byte_pos += (self.bit_pos / 8) as usize;
438 self.bit_pos &= 7;
439 }
440 v
441 }
442}
443
444fn nwa_unpack_unit(
445 src: &[u8],
446 pack_mod: i32,
447 zero_mod: bool,
448 channels: u16,
449 init_l: i32,
450 init_r: i32,
451 src_smp_cnt: u32,
452 dst_le_i16: &mut [u8],
453) -> Result<()> {
454 if dst_le_i16.len() < src_smp_cnt as usize * 2 {
455 bail!("dst buffer too small");
456 }
457
458 let mut br = BitReaderLE::new(src);
459 let mut now_l: i32 = init_l;
460 let mut now_r: i32 = init_r;
461 let mut zero_cnt: u32 = 0;
462 let mono = channels <= 1;
463
464 let mut mod_map = pack_mod;
465 match mod_map {
466 0 => mod_map = 2,
467 1 => mod_map = 1,
468 2 => mod_map = 0,
469 _ => {}
470 }
471
472 match mod_map {
473 0 => unpack16(
474 &mut br,
475 zero_mod,
476 src_smp_cnt,
477 dst_le_i16,
478 3,
479 mono,
480 &mut now_l,
481 &mut now_r,
482 &mut zero_cnt,
483 ),
484 1 => unpack16(
485 &mut br,
486 zero_mod,
487 src_smp_cnt,
488 dst_le_i16,
489 4,
490 mono,
491 &mut now_l,
492 &mut now_r,
493 &mut zero_cnt,
494 ),
495 2 => unpack16(
496 &mut br,
497 zero_mod,
498 src_smp_cnt,
499 dst_le_i16,
500 5,
501 mono,
502 &mut now_l,
503 &mut now_r,
504 &mut zero_cnt,
505 ),
506 3 => unpack16(
507 &mut br,
508 zero_mod,
509 src_smp_cnt,
510 dst_le_i16,
511 6,
512 mono,
513 &mut now_l,
514 &mut now_r,
515 &mut zero_cnt,
516 ),
517 4 => unpack16(
518 &mut br,
519 zero_mod,
520 src_smp_cnt,
521 dst_le_i16,
522 7,
523 mono,
524 &mut now_l,
525 &mut now_r,
526 &mut zero_cnt,
527 ),
528 5 => unpack16(
529 &mut br,
530 zero_mod,
531 src_smp_cnt,
532 dst_le_i16,
533 8,
534 mono,
535 &mut now_l,
536 &mut now_r,
537 &mut zero_cnt,
538 ),
539 _ => bail!("invalid pack_mod: {}", pack_mod),
540 }
541}
542
543fn get_zero_count(br: &mut BitReaderLE) -> u32 {
544 let mut zero_cnt = br.read_bits(1);
545 if zero_cnt == 1 {
546 zero_cnt = br.read_bits(2);
547 if zero_cnt == 3 {
548 zero_cnt = br.read_bits(8);
549 }
550 }
551 zero_cnt
552}
553
554fn apply_delta(br: &mut BitReaderLE, mod_n: u8, data_n: u8, nowsmp: &mut i32) {
555 let (bits, sign_mask, shift): (u8, u32, u8) = match (mod_n, data_n) {
556 (3, 1) => (3, 0x04, 5),
557 (3, 2) => (3, 0x04, 6),
558 (3, 3) => (3, 0x04, 7),
559 (3, 4) => (3, 0x04, 8),
560 (3, 5) => (3, 0x04, 9),
561 (3, 6) => (3, 0x04, 10),
562 (3, 7) => (6, 0x20, 11),
563
564 (4, 1) => (4, 0x08, 4),
565 (4, 2) => (4, 0x08, 5),
566 (4, 3) => (4, 0x08, 6),
567 (4, 4) => (4, 0x08, 7),
568 (4, 5) => (4, 0x08, 8),
569 (4, 6) => (4, 0x08, 9),
570 (4, 7) => (7, 0x40, 10),
571
572 (5, 1) => (5, 0x10, 3),
573 (5, 2) => (5, 0x10, 4),
574 (5, 3) => (5, 0x10, 5),
575 (5, 4) => (5, 0x10, 6),
576 (5, 5) => (5, 0x10, 7),
577 (5, 6) => (5, 0x10, 8),
578 (5, 7) => (8, 0x80, 9),
579
580 (6, 1) => (6, 0x20, 2),
581 (6, 2) => (6, 0x20, 3),
582 (6, 3) => (6, 0x20, 4),
583 (6, 4) => (6, 0x20, 5),
584 (6, 5) => (6, 0x20, 6),
585 (6, 6) => (6, 0x20, 7),
586 (6, 7) => (8, 0x80, 9),
587
588 (7, 1) => (7, 0x40, 2),
589 (7, 2) => (7, 0x40, 3),
590 (7, 3) => (7, 0x40, 4),
591 (7, 4) => (7, 0x40, 5),
592 (7, 5) => (7, 0x40, 6),
593 (7, 6) => (7, 0x40, 7),
594 (7, 7) => (8, 0x80, 9),
595
596 (8, 1) => (8, 0x80, 2),
597 (8, 2) => (8, 0x80, 3),
598 (8, 3) => (8, 0x80, 4),
599 (8, 4) => (8, 0x80, 5),
600 (8, 5) => (8, 0x80, 6),
601 (8, 6) => (8, 0x80, 7),
602 (8, 7) => (8, 0x80, 9),
603 _ => return,
604 };
605
606 let mut dat_code = br.read_bits(bits);
607 if (dat_code & sign_mask) != 0 {
608 dat_code &= !sign_mask;
609 *nowsmp -= (dat_code as i32) << shift;
610 } else {
611 *nowsmp += (dat_code as i32) << shift;
612 }
613}
614
615fn unpack16(
616 br: &mut BitReaderLE,
617 zero_mod: bool,
618 src_smp_cnt: u32,
619 dst_le_i16: &mut [u8],
620 mod_n: u8,
621 mono: bool,
622 now_l: &mut i32,
623 now_r: &mut i32,
624 zero_cnt: &mut u32,
625) -> Result<()> {
626 for i in 0..src_smp_cnt {
627 let nowsmp_ref: &mut i32 = if mono || (i & 1) == 0 { now_l } else { now_r };
630
631 if *zero_cnt != 0 {
632 *zero_cnt -= 1;
633 } else {
634 let mod_code = br.read_bits(3) as u8;
635 match mod_code {
636 0 => {
637 if zero_mod {
638 *zero_cnt = get_zero_count(br);
639 }
640 }
641 1 => apply_delta(br, mod_n, 1, nowsmp_ref),
642 2 => apply_delta(br, mod_n, 2, nowsmp_ref),
643 3 => apply_delta(br, mod_n, 3, nowsmp_ref),
644 4 => apply_delta(br, mod_n, 4, nowsmp_ref),
645 5 => apply_delta(br, mod_n, 5, nowsmp_ref),
646 6 => apply_delta(br, mod_n, 6, nowsmp_ref),
647 7 => {
648 let b = br.read_bits(1);
649 if b == 0 {
650 apply_delta(br, mod_n, 7, nowsmp_ref);
651 } else {
652 *nowsmp_ref = 0;
653 }
654 }
655 _ => {}
656 }
657 }
658
659 let s = (*nowsmp_ref as i16).to_le_bytes();
661 let o = (i as usize) * 2;
662 dst_le_i16[o] = s[0];
663 dst_le_i16[o + 1] = s[1];
664 }
665 Ok(())
666}