rustwav_lib/
wavcore.rs

1#![allow(dead_code)]
2
3use std::{io::{self, Read, Write, SeekFrom}, fmt::{self, Debug, Display, Formatter}, convert::From, collections::{HashMap, BTreeMap}};
4
5use crate::SampleType;
6use crate::{Reader, Writer};
7use crate::{AudioError, AudioReadError, AudioWriteError};
8use crate::adpcm::ms::AdpcmCoeffSet;
9use crate::readwrite::string_io::*;
10use crate::savagestr::{StringCodecMaps, SavageStringCodecs};
11
12#[allow(unused_imports)]
13pub use crate::encoders::mp3::{Mp3EncoderOptions, Mp3Channels, Mp3Quality, Mp3Bitrate, Mp3VbrMode};
14
15#[allow(unused_imports)]
16pub use crate::encoders::opus::{OpusEncoderOptions, OpusBitrate, OpusEncoderSampleDuration};
17
18#[allow(unused_imports)]
19pub use crate::flac::{
20    FlacEncoderParams,
21    FlacCompression,
22};
23
24// Did you assume WAV is solely for storing PCM data?
25#[derive(Debug, Clone, Copy, PartialEq)]
26#[allow(clippy::large_enum_variant)]
27pub enum DataFormat{
28    Unspecified,
29    Pcm,
30    Adpcm(AdpcmSubFormat),
31    PcmALaw,
32    PcmMuLaw,
33    Mp3(Mp3EncoderOptions),
34    Opus(OpusEncoderOptions),
35    Flac(FlacEncoderParams),
36}
37
38#[derive(Debug, Clone, Copy, PartialEq)]
39#[repr(u16)]
40pub enum AdpcmSubFormat {
41    Ms = 0x0002,
42    Ima = 0x0011,
43    Yamaha = 0x0020,
44}
45
46impl From<AdpcmSubFormat> for u16 {
47    fn from(val: AdpcmSubFormat) -> Self {
48        val as u16
49    }
50}
51
52impl Display for DataFormat {
53    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
54        match self {
55            Self::Unspecified => write!(f, "Unspecified"),
56            Self::Pcm => write!(f, "PCM"),
57            Self::Adpcm(subformat) => write!(f, "{:?}", subformat),
58            Self::PcmALaw => write!(f, "PCM-ALaw"),
59            Self::PcmMuLaw => write!(f, "PCM-MuLaw"),
60            Self::Mp3(options) => write!(f, "MP3({:?})", options),
61            Self::Opus(options) => write!(f, "Opus({:?})", options),
62            Self::Flac(options) => write!(f, "Flac({:?})", options),
63       }
64    }
65}
66
67impl Display for AdpcmSubFormat {
68    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
69        match self {
70            Self::Ms => write!(f, "ADPCM-MS"),
71            Self::Ima => write!(f, "ADPCM-IMA"),
72            Self::Yamaha => write!(f, "ADPCM-YAMAHA"),
73       }
74    }
75}
76
77#[derive(Debug, Clone, Copy)]
78pub enum SampleFormat {
79    Unknown,
80    Float,
81    UInt,
82    Int,
83}
84
85impl Display for SampleFormat {
86    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
87        match self {
88            SampleFormat::Unknown => write!(f, "Unknown"),
89            SampleFormat::Float => write!(f, "Floating Point Number"),
90            SampleFormat::UInt => write!(f, "Unsigned Integer"),
91            SampleFormat::Int => write!(f, "Integer"),
92       }
93    }
94}
95
96#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
97pub enum WaveSampleType {
98    Unknown,
99    S8,
100    S16,
101    S24,
102    S32,
103    S64,
104    U8,
105    U16,
106    U24,
107    U32,
108    U64,
109    F32,
110    F64,
111}
112
113impl Display for WaveSampleType {
114    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
115        use WaveSampleType::{Unknown, S8, S16, S24, S32, S64, U8, U16, U24, U32, U64, F32, F64};
116        match self {
117            Unknown => write!(f, "Unknown"),
118            S8  => write!(f, "i8"),
119            S16 => write!(f, "i16"),
120            S24 => write!(f, "i24"),
121            S32 => write!(f, "i32"),
122            S64 => write!(f, "i64"),
123            U8  => write!(f, "u8"),
124            U16 => write!(f, "u16"),
125            U24 => write!(f, "u24"),
126            U32 => write!(f, "u32"),
127            U64 => write!(f, "u64"),
128            F32 => write!(f, "f32"),
129            F64 => write!(f, "f64"),
130       }
131    }
132}
133
134impl WaveSampleType {
135    pub fn sizeof(&self) -> u16 {
136        use WaveSampleType::{Unknown, S8, S16, S24, S32, S64, U8, U16, U24, U32, U64, F32, F64};
137        match self {
138            S8 =>  1,
139            S16 => 2,
140            S24 => 3,
141            S32 => 4,
142            S64 => 8,
143            U8 =>  1,
144            U16 => 2,
145            U24 => 3,
146            U32 => 4,
147            U64 => 8,
148            F32 => 4,
149            F64 => 8,
150            Unknown => 0,
151        }
152    }
153}
154
155
156#[allow(unused_imports)]
157pub fn get_sample_type(bits_per_sample: u16, sample_format: SampleFormat) -> WaveSampleType {
158    use SampleFormat::{UInt, Int, Float};
159    use WaveSampleType::{Unknown, S8, S16, S24, S32, S64, U8, U16, U24, U32, U64, F32, F64};
160    match (bits_per_sample, sample_format) {
161        (8, UInt) => U8,
162        (16, Int) => S16,
163        (24, Int) => S24,
164        (32, Int) => S32,
165        (64, Int) => S64,
166        (32, Float) => F32,
167        (64, Float) => F64,
168        // PCM supports only the formats listed above.
169        (_, _) => Unknown,
170    }
171}
172
173#[derive(Clone, Copy, PartialEq)]
174#[allow(clippy::upper_case_acronyms)]
175pub struct GUID (pub u32, pub u16, pub u16, pub [u8; 8]);
176
177pub const GUID_PCM_FORMAT: GUID = GUID(0x00000001, 0x0000, 0x0010, [0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]);
178pub const GUID_IEEE_FLOAT_FORMAT: GUID = GUID(0x00000003, 0x0000, 0x0010, [0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]);
179
180impl Debug for GUID {
181    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
182        fmt.debug_tuple("GUID")
183            .field(&format_args!("{:08x}-{:04x}-{:04x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
184                self.0, self.1, self.2, self.3[0], self.3[1], self.3[2], self.3[3], self.3[4], self.3[5], self.3[6], self.3[7]))
185            .finish()
186    }
187}
188
189impl GUID {
190    pub fn read<T>(r: &mut T) -> Result<Self, io::Error>
191    where T: Read {
192        Ok( Self (
193            u32::read_le(r)?,
194            u16::read_le(r)?,
195            u16::read_le(r)?,
196            [
197                u8::read_le(r)?,
198                u8::read_le(r)?,
199                u8::read_le(r)?,
200                u8::read_le(r)?,
201                u8::read_le(r)?,
202                u8::read_le(r)?,
203                u8::read_le(r)?,
204                u8::read_le(r)?,
205            ]
206        ))
207    }
208
209    pub fn write<T>(&self, w: &mut T) -> Result<(), io::Error>
210    where T: Write + ?Sized {
211        self.0.write_le(w)?;
212        self.1.write_le(w)?;
213        self.2.write_le(w)?;
214        w.write_all(&self.3)?;
215        Ok(())
216    }
217}
218
219
220#[derive(Clone, Copy, Debug)]
221#[repr(u32)]
222pub enum SpeakerPosition {
223    FrontLeft = 0x1,
224    FrontRight = 0x2,
225    FrontCenter = 0x4,
226    LowFreq = 0x8,
227    BackLeft = 0x10,
228    BackRight = 0x20,
229    FrontLeftOfCenter = 0x40,
230    FrontRightOfCenter = 0x80,
231    BackCenter = 0x100,
232    SideLeft = 0x200,
233    SideRight = 0x400,
234    TopCenter = 0x800,
235    TopFrontLeft = 0x1000,
236    TopFrontCenter = 0x2000,
237    TopFrontRight = 0x4000,
238    TopBackLeft = 0x8000,
239    TopBackCenter = 0x10000,
240    TopBackRight = 0x20000,
241}
242
243impl From<SpeakerPosition> for u32 {
244    fn from(val: SpeakerPosition) -> Self {
245        val as u32
246    }
247}
248
249impl Display for SpeakerPosition {
250    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
251        match self {
252            SpeakerPosition::FrontLeft           => write!(f, "front_left"),
253            SpeakerPosition::FrontRight          => write!(f, "front_right"),
254            SpeakerPosition::FrontCenter         => write!(f, "front_center"),
255            SpeakerPosition::LowFreq             => write!(f, "low_freq"),
256            SpeakerPosition::BackLeft            => write!(f, "back_left"),
257            SpeakerPosition::BackRight           => write!(f, "back_right"),
258            SpeakerPosition::FrontLeftOfCenter   => write!(f, "front_left_of_center"),
259            SpeakerPosition::FrontRightOfCenter  => write!(f, "front_right_of_center"),
260            SpeakerPosition::BackCenter          => write!(f, "back_center"),
261            SpeakerPosition::SideLeft            => write!(f, "side_left"),
262            SpeakerPosition::SideRight           => write!(f, "side_right"),
263            SpeakerPosition::TopCenter           => write!(f, "top_center"),
264            SpeakerPosition::TopFrontLeft        => write!(f, "top_front_left"),
265            SpeakerPosition::TopFrontCenter      => write!(f, "top_front_center"),
266            SpeakerPosition::TopFrontRight       => write!(f, "top_front_right"),
267            SpeakerPosition::TopBackLeft         => write!(f, "top_back_left"),
268            SpeakerPosition::TopBackCenter       => write!(f, "top_back_center"),
269            SpeakerPosition::TopBackRight        => write!(f, "top_back_right"),
270        }
271    }
272}
273
274// TODO
275// Algorithm Design:
276// 1. Spatial Mapping: 
277//    - Assign a 3D direction vector to each audio source, representing its position relative to the listener's head.
278//    - Vectors are normalized (magnitude = 1.0) to abstract distance, focusing on angular positioning.
279//
280// 2. Directional Influence Calculation:
281//    - Compute dot products between each source vector and the listener's facing direction (head orientation vector).
282//    - Sources behind the listener (dot product < 0.0) are attenuated by a decay factor (e.g., 0.2x gain).
283//
284// 3. Energy-Preserving Mixdown:
285//    - Apply weighted summation: mixed_sample = Σ (source_sample * dot_product * decay_factor)
286//    - Normalize weights dynamically to ensure Σ (effective_gain) ≤ 1.0, preventing clipping.
287//
288// This achieves lossless channel layout conversion (e.g., 5.1 → stereo) with spatial accuracy.
289
290pub fn channel_mask_to_speaker_positions(channels: u16, channel_mask: u32) -> Result<Vec<SpeakerPosition>, AudioError> {
291    let enums = [
292        SpeakerPosition::FrontLeft,
293        SpeakerPosition::FrontRight,
294        SpeakerPosition::FrontCenter,
295        SpeakerPosition::LowFreq,
296        SpeakerPosition::BackLeft,
297        SpeakerPosition::BackRight,
298        SpeakerPosition::FrontLeftOfCenter,
299        SpeakerPosition::FrontRightOfCenter,
300        SpeakerPosition::BackCenter,
301        SpeakerPosition::SideLeft,
302        SpeakerPosition::SideRight,
303        SpeakerPosition::TopCenter,
304        SpeakerPosition::TopFrontLeft,
305        SpeakerPosition::TopFrontCenter,
306        SpeakerPosition::TopFrontRight,
307        SpeakerPosition::TopBackLeft,
308        SpeakerPosition::TopBackCenter,
309        SpeakerPosition::TopBackRight,
310    ];
311    let mut ret = Vec::<SpeakerPosition>::new();
312    for (i, m) in enums.iter().enumerate() {
313        let m = *m as u32;
314        if channel_mask & m == m {ret.push(enums[i]);}
315    }
316    if ret.len() == channels as usize {
317        Ok(ret)
318    } else {
319        Err(AudioError::ChannelNotMatchMask)
320    }
321}
322
323pub fn channel_mask_to_speaker_positions_desc(channels: u16, channel_mask: u32) -> Result<Vec<String>, AudioError> {
324    match channel_mask_to_speaker_positions(channels, channel_mask) {
325        Ok(v) => {
326            let mut ret = Vec::with_capacity(v.len());
327            for e in v.iter() {
328                ret.push(format!("{:?}", e));
329            }
330            Ok(ret)
331        },
332        Err(e) => Err(e),
333    }
334}
335
336pub fn guess_channel_mask(channels: u16) -> Result<u32, AudioError> {
337    match channels {
338        0 => Err(AudioError::GuessChannelMaskFailed(channels)),
339        1 => Ok(SpeakerPosition::FrontCenter.into()),
340        2 => Ok(SpeakerPosition::FrontLeft as u32 | SpeakerPosition::FrontRight as u32),
341        o => {
342            let mut mask = 0;
343            for i in 0..o {
344                let bit = 1 << i;
345                if bit > 0x20000 {
346                    return Err(AudioError::GuessChannelMaskFailed(channels));
347                }
348                mask |= bit;
349            }
350            Ok(mask)
351        }
352    }
353}
354
355#[derive(Debug, Clone, Copy)]
356pub struct Spec {
357    pub channels: u16,
358    pub channel_mask: u32,
359    pub sample_rate: u32,
360    pub bits_per_sample: u16,
361    pub sample_format: SampleFormat,
362}
363
364impl Default for Spec {
365    fn default() -> Self {
366        Self::new()
367    }
368}
369
370impl Spec {
371    pub fn new() -> Self {
372        Self {
373            channels: 0,
374            channel_mask: 0,
375            sample_rate: 0,
376            bits_per_sample: 0,
377            sample_format: SampleFormat::Unknown,
378        }
379    }
380
381    pub fn get_sample_type(&self) -> WaveSampleType {
382        get_sample_type(self.bits_per_sample, self.sample_format)
383    }
384
385    pub fn guess_channel_mask(&self) -> Result<u32, AudioError> {
386        guess_channel_mask(self.channels)
387    }
388
389    pub fn channel_mask_to_speaker_positions(&self) -> Result<Vec<SpeakerPosition>, AudioError> {
390        channel_mask_to_speaker_positions(self.channels, self.channel_mask)
391    }
392
393    pub fn channel_mask_to_speaker_positions_desc(&self) -> Result<Vec<String>, AudioError> {
394        channel_mask_to_speaker_positions_desc(self.channels, self.channel_mask)
395    }
396
397    pub fn verify_for_pcm(&self) -> Result<(), AudioError> {
398        self.guess_channel_mask()?;
399        if self.get_sample_type() == WaveSampleType::Unknown {
400            Err(AudioError::InvalidArguments(format!("PCM doesn't support {} bits per sample {:?}", self.bits_per_sample, self.sample_format)))
401        } else {
402            Ok(())
403        }
404    }
405
406    pub fn is_channel_mask_valid(&self) -> bool {
407        if self.channels <= 2 && self.channel_mask == 0 {
408            return true;
409        }
410        let mut counter: u16 = 0;
411        for i in 0..32 {
412            if ((1 << i) & self.channel_mask) != 0 {
413                counter += 1;
414            }
415        }
416        counter == self.channels
417    }
418}
419
420pub struct ChunkWriter<'a> {
421    pub writer: &'a mut dyn Writer,
422    pub flag: [u8; 4],
423    pub pos_of_chunk_len: u64, // Byte position where the chunk size field is written (to be backfilled later)
424    pub chunk_start: u64, // File offset marking the start of this chunk's payload data
425    ended: bool,
426}
427
428impl Debug for ChunkWriter<'_> {
429    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
430        fmt.debug_struct("ChunkWriter")
431            .field("writer", &self.writer)
432            .field("flag", &format_args!("{}", String::from_utf8_lossy(&self.flag)))
433            .field("pos_of_chunk_len", &self.pos_of_chunk_len)
434            .field("chunk_start", &self.chunk_start)
435            .finish()
436    }
437}
438
439impl<'a> ChunkWriter<'a> {
440    // Starts writing a chunk by first writing the chunk Flag, then recording the positions
441    // for both the chunk size and the chunk data.
442    pub fn begin(writer: &'a mut dyn Writer, flag: &[u8; 4]) -> Result<Self, AudioWriteError> {
443        writer.write_all(flag)?;
444        let pos_of_chunk_len = writer.stream_position()?;
445        0u32.write_le(writer)?;
446        let chunk_start = writer.stream_position()?;
447        Ok(Self{
448            writer,
449            flag: *flag,
450            pos_of_chunk_len,
451            chunk_start,
452            ended: false,
453        })
454    }
455
456    // At the end of the chunk, the chunk size will be updated since the ownership of `self` moved there, and `drop()` will be called.
457    pub fn end(self){}
458
459    fn on_drop(&mut self) -> Result<(), AudioWriteError> {
460        if self.ended {
461            return Ok(());
462        }
463        // Chunk size handling constraints:
464        // ---------------------------------------------------------------
465        // 1. u32 Overflow Handling:
466        //    - RIFF/RF64/data chunks: If size exceeds u32::MAX (0xFFFFFFFF), 
467        //      write 0xFFFFFFFF and store the actual u64 size in the ds64 chunk.
468        //    - Other chunks: Size must not exceed u32::MAX. If violated, returns an error.
469        //
470        // 2. ds64 Table Limitations:
471        //    - The ds64 chunk's table can store u64 sizes for non-RIFF/RF64/data chunks,
472        //      but adding entries increases the ds64 chunk's own size.
473        //    - Current implementation does NOT pre-allocate space in the ds64 chunk.
474        //
475        // 3. Enforcement:
476        //    - Non-RIFF/RF64/data chunks exceeding 0xFFFFFFFF bytes will fail encoding.
477        //    - Callers must ensure chunks (except RIFF/RF64/data) stay within u32 limits.
478        let mut chunk_size = self.get_chunk_data_size()?;
479        if chunk_size >= 0xFFFFFFFFu64 {
480            match &self.flag {
481                b"RIFF" | b"data" => {
482                    chunk_size = 0xFFFFFFFF;
483                },
484                other => {
485                    let chunk_flag = String::from_utf8_lossy(other);
486                    return Err(AudioWriteError::ChunkSizeTooBig(format!("{} is 0x{:x} bytes long.", chunk_flag, chunk_size)));
487                },
488            }
489        }
490        self.end_and_write_size(chunk_size as u32)
491    }
492
493    fn end_and_write_size(&mut self, chunk_size_to_write: u32) -> Result<(), AudioWriteError> {
494        let end_of_chunk = self.writer.stream_position()?;
495        self.writer.seek(SeekFrom::Start(self.pos_of_chunk_len))?;
496        chunk_size_to_write.write_le(self.writer)?;
497        self.writer.seek(SeekFrom::Start(end_of_chunk))?;
498        if end_of_chunk & 1 > 0 {
499            0u8.write_le(self.writer)?;
500        }
501        self.ended = true;
502        Ok(())
503    }
504
505    pub fn get_chunk_start_pos(&self) -> u64 {
506        self.chunk_start
507    }
508
509    pub fn get_chunk_data_size(&mut self) -> Result<u64, AudioWriteError> {
510        Ok(self.writer.stream_position()? - self.get_chunk_start_pos())
511    }
512}
513
514impl Drop for ChunkWriter<'_> {
515    fn drop(&mut self) {
516        self.on_drop().unwrap()
517    }
518}
519
520#[derive(Debug, Clone, Copy)]
521pub struct ChunkHeader {
522    pub flag: [u8; 4],        // The 4-byte identifier stored in the file (e.g., "RIFF", "fmt ")
523    pub size: u32,            // The chunk size stored in the file header (may be 0xFFFFFFFF if actual size is in ds64 chunk)
524    pub chunk_start_pos: u64, // File offset of the chunk's payload (excludes the 8-byte header)
525}
526
527impl ChunkHeader {
528    pub fn new() -> Self {
529        Self {
530            flag: [0u8; 4],
531            size: 0,
532            chunk_start_pos: 0,
533        }
534    }
535
536    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
537        let mut flag = [0u8; 4];
538        reader.read_exact(&mut flag)?;
539        Ok(Self {
540            flag,
541            size: u32::read_le(reader)?,
542            chunk_start_pos: reader.stream_position()?
543        })
544    }
545
546    pub fn align(addr: u64) -> u64 {
547        addr + (addr & 1)
548    }
549
550    pub fn next_chunk_pos(&self) -> u64 {
551        Self::align(self.chunk_start_pos + self.size as u64)
552    }
553
554    pub fn seek_to_next_chunk(&self, reader: &mut dyn Reader) -> Result<u64, AudioReadError> {
555        Ok(reader.seek(SeekFrom::Start(self.next_chunk_pos()))?)
556    }
557}
558
559impl Default for ChunkHeader {
560    fn default() -> Self {
561        Self::new()
562    }
563}
564
565#[derive(Debug, Clone, Copy)]
566pub struct FmtChunk {
567    pub format_tag: u16, // https://github.com/tpn/winsdk-10/blob/master/Include/10.0.14393.0/shared/mmreg.h
568    pub channels: u16,
569    pub sample_rate: u32,
570    pub byte_rate: u32,
571    pub block_align: u16,
572    pub bits_per_sample: u16,
573    pub extension: Option<FmtExtension>,
574}
575
576#[derive(Debug, Clone, Copy)]
577pub struct FmtExtension {
578    pub ext_len: u16,
579    pub data: ExtensionData,
580}
581
582#[derive(Debug, Clone, Copy)]
583pub enum ExtensionData{
584    Nodata,
585    AdpcmMs(AdpcmMsData),
586    AdpcmIma(AdpcmImaData),
587    Mp3(Mp3Data),
588    Extensible(ExtensibleData),
589}
590
591#[derive(Debug, Clone, Copy)]
592pub struct AdpcmMsData{
593    pub samples_per_block: u16,
594    pub num_coeff: u16,
595    pub coeffs: [AdpcmCoeffSet; 7],
596}
597
598#[derive(Debug, Clone, Copy)]
599pub struct AdpcmImaData{
600    pub samples_per_block: u16,
601}
602
603#[derive(Debug, Clone, Copy)]
604pub struct Mp3Data{
605    pub id: u16,
606    pub flags: u32,
607    pub block_size: u16,
608    pub frames_per_block: u16,
609    pub codec_delay: u16,
610}
611
612#[derive(Debug, Clone, Copy)]
613pub struct ExtensibleData {
614    pub valid_bits_per_sample: u16,
615    pub channel_mask: u32,
616    pub sub_format: GUID,
617}
618
619impl FmtChunk {
620    pub fn new() -> Self {
621        Self {
622            format_tag: 0,
623            channels: 0,
624            sample_rate: 0,
625            byte_rate: 0,
626            block_align: 0,
627            bits_per_sample: 0,
628            extension: None,
629        }
630    }
631
632    pub fn read(reader: &mut impl Reader, chunk_size: u32) -> Result<Self, AudioReadError> {
633        let mut ret = FmtChunk{
634            format_tag: u16::read_le(reader)?,
635            channels: u16::read_le(reader)?,
636            sample_rate: u32::read_le(reader)?,
637            byte_rate: u32::read_le(reader)?,
638            block_align: u16::read_le(reader)?,
639            bits_per_sample: u16::read_le(reader)?,
640            extension: None,
641        };
642        if chunk_size > 16 {
643            ret.extension = Some(FmtExtension::read(reader, ret.format_tag)?);
644        }
645        Ok(ret)
646    }
647
648    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
649        self.format_tag.write_le(writer)?;
650        self.channels.write_le(writer)?;
651        self.sample_rate.write_le(writer)?;
652        self.byte_rate.write_le(writer)?;
653        self.block_align.write_le(writer)?;
654        self.bits_per_sample.write_le(writer)?;
655        if let Some(extension) = self.extension {
656            extension.write(writer)?;
657        }
658        Ok(())
659    }
660
661    pub fn get_sample_format(&self) -> SampleFormat {
662        use SampleFormat::{Int, UInt, Float, Unknown};
663        match (self.format_tag, self.bits_per_sample) {
664            (1, 8) => UInt,
665            (1, 16) => Int,
666            (1, 24) => Int,
667            (1, 32) => Int,
668            (1, 64) => Int,
669            (0xFFFE, 8) => UInt,
670            (0xFFFE, 16) => Int,
671            (0xFFFE, 24) => Int,
672            (0xFFFE, 32) | (0xFFFE, 64) => {
673                if let Some(extension) = self.extension {
674                    match extension.data{
675                        ExtensionData::Extensible(extensible) => {
676                            match extensible.sub_format {
677                                GUID_PCM_FORMAT => Int,
678                                GUID_IEEE_FLOAT_FORMAT => Float,
679                                _ => Unknown, // Let the decoders to decide
680                            }
681                        },
682                        other => panic!("Unexpected extension data in the `fmt ` chunk: {:?}", other),
683                    }
684                } else {
685                    Int // 我们还是宽松的,0xFFFE 也允许没有扩展数据。
686                }
687            },
688            (3, 32) => Float,
689            (3, 64) => Float,
690            (_, _) => Unknown, // Let the decoders to decide
691        }
692    }
693
694    pub fn get_sample_type(&self) -> WaveSampleType {
695        get_sample_type(self.bits_per_sample, self.get_sample_format())
696    }
697}
698
699impl Default for FmtChunk {
700    fn default() -> Self {
701        Self::new()
702    }
703}
704
705impl FmtExtension {
706    pub fn new_adpcm_ms(adpcm_ms: AdpcmMsData) -> Self {
707        Self {
708            ext_len: AdpcmMsData::sizeof() as u16,
709            data: ExtensionData::AdpcmMs(adpcm_ms),
710        }
711    }
712
713    pub fn new_adpcm_ima(adpcm_ima: AdpcmImaData) -> Self {
714        Self {
715            ext_len: AdpcmImaData::sizeof() as u16,
716            data: ExtensionData::AdpcmIma(adpcm_ima),
717        }
718    }
719
720    pub fn new_mp3(mp3: Mp3Data) -> Self {
721        Self {
722            ext_len: Mp3Data::sizeof() as u16,
723            data: ExtensionData::Mp3(mp3),
724        }
725    }
726
727    pub fn new_extensible(extensible: ExtensibleData) -> Self {
728        Self {
729            ext_len: ExtensibleData::sizeof() as u16,
730            data: ExtensionData::Extensible(extensible),
731        }
732    }
733
734    pub fn get_length(&self) -> u16 {
735        self.ext_len
736    }
737
738    pub fn read(reader: &mut impl Reader, format_tag: u16) -> Result<Self, AudioReadError> {
739        const TAG_ADPCM_IMA: u16 = AdpcmSubFormat::Ima as u16;
740        const TAG_ADPCM_MS: u16 = AdpcmSubFormat::Ms as u16;
741        let ext_len = u16::read_le(reader)?;
742        Ok(Self{
743            ext_len,
744            data: match format_tag {
745                TAG_ADPCM_MS => {
746                    if ext_len as usize >= AdpcmMsData::sizeof() {
747                        Ok(ExtensionData::AdpcmMs(AdpcmMsData::read(reader)?))
748                    } else {
749                        Err(AudioReadError::IncompleteData(format!("The extension data for ADPCM-MS should be bigger than {}, got {ext_len}", AdpcmMsData::sizeof())))
750                    }
751                },
752                TAG_ADPCM_IMA => {
753                    if ext_len as usize >= AdpcmImaData::sizeof() {
754                        Ok(ExtensionData::AdpcmIma(AdpcmImaData::read(reader)?))
755                    } else {
756                        Err(AudioReadError::IncompleteData(format!("The extension data for ADPCM-IMA should be bigger than {}, got {ext_len}", AdpcmImaData::sizeof())))
757                    }
758                },
759                0x0055 => {
760                    if ext_len as usize >= Mp3Data::sizeof() {
761                        Ok(ExtensionData::Mp3(Mp3Data::read(reader)?))
762                    } else {
763                        Err(AudioReadError::IncompleteData(format!("The extension data for Mpeg Layer III should be bigger than {}, got {ext_len}", Mp3Data::sizeof())))
764                    }
765                },
766                0xFFFE => {
767                    if ext_len as usize >= ExtensibleData::sizeof() {
768                        Ok(ExtensionData::Extensible(ExtensibleData::read(reader)?))
769                    } else {
770                        Err(AudioReadError::IncompleteData(format!("The extension data for EXTENSIBLE should be bigger than {}, got {ext_len}", ExtensibleData::sizeof())))
771                    }
772                },
773                _ => Ok(ExtensionData::Nodata),
774            }?,
775        })
776    }
777
778    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
779        const TAG_ADPCM_IMA: u16 = AdpcmSubFormat::Ima as u16;
780        const TAG_ADPCM_MS: u16 = AdpcmSubFormat::Ms as u16;
781        self.ext_len.write_le(writer)?;
782        if self.ext_len != 0 { // 这里我们也是宽松的,允许在这里存个表示长度为 0 的数值。
783            match self.data {
784                ExtensionData::Nodata => Err(AudioWriteError::InvalidArguments(format!("There should be data in {} bytes to be written, but the data is `Nodata`.", self.ext_len))),
785                ExtensionData::AdpcmMs(data) => Ok(data.write(writer)?),
786                ExtensionData::AdpcmIma(data) => Ok(data.write(writer)?),
787                ExtensionData::Mp3(data) => Ok(data.write(writer)?),
788                ExtensionData::Extensible(data) => Ok(data.write(writer)?),
789            }
790        } else {
791            Ok(())
792        }
793    }
794}
795
796impl AdpcmMsData {
797    pub fn new() -> Self {
798        Self {
799            samples_per_block: 0,
800            num_coeff: 7,
801            coeffs: [
802                AdpcmCoeffSet{coeff1: 256, coeff2: 0   },
803                AdpcmCoeffSet{coeff1: 512, coeff2: -256},
804                AdpcmCoeffSet{coeff1: 0  , coeff2: 0   },
805                AdpcmCoeffSet{coeff1: 192, coeff2: 64  },
806                AdpcmCoeffSet{coeff1: 240, coeff2: 0   },
807                AdpcmCoeffSet{coeff1: 460, coeff2: -208},
808                AdpcmCoeffSet{coeff1: 392, coeff2: -232},
809            ],
810        }
811    }
812
813    pub fn sizeof() -> usize {
814        32
815    }
816
817    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
818        Ok(Self{
819            samples_per_block: u16::read_le(reader)?,
820            num_coeff: u16::read_le(reader)?,
821            coeffs: [
822                AdpcmCoeffSet{coeff1: i16::read_le(reader)?, coeff2: i16::read_le(reader)?},
823                AdpcmCoeffSet{coeff1: i16::read_le(reader)?, coeff2: i16::read_le(reader)?},
824                AdpcmCoeffSet{coeff1: i16::read_le(reader)?, coeff2: i16::read_le(reader)?},
825                AdpcmCoeffSet{coeff1: i16::read_le(reader)?, coeff2: i16::read_le(reader)?},
826                AdpcmCoeffSet{coeff1: i16::read_le(reader)?, coeff2: i16::read_le(reader)?},
827                AdpcmCoeffSet{coeff1: i16::read_le(reader)?, coeff2: i16::read_le(reader)?},
828                AdpcmCoeffSet{coeff1: i16::read_le(reader)?, coeff2: i16::read_le(reader)?},
829            ],
830        })
831    }
832
833    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
834        self.samples_per_block.write_le(writer)?;
835        self.num_coeff.write_le(writer)?;
836        for coeff in self.coeffs {
837            coeff.coeff1.write_le(writer)?;
838            coeff.coeff2.write_le(writer)?;
839        }
840        Ok(())
841    }
842}
843
844impl Default for AdpcmMsData {
845    fn default() -> Self {
846        Self::new()
847    }
848}
849
850impl AdpcmImaData {
851    pub fn new(samples_per_block: u16) -> Self {
852        Self {
853            samples_per_block,
854        }
855    }
856
857    pub fn sizeof() -> usize {
858        2
859    }
860
861    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
862        Ok(Self{
863            samples_per_block: u16::read_le(reader)?,
864        })
865    }
866
867    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
868        self.samples_per_block.write_le(writer)?;
869        Ok(())
870    }
871}
872
873impl Mp3Data {
874    pub const MPEGLAYER3_FLAG_PADDING_ISO: u32 = 0x00000000;
875    pub const MPEGLAYER3_FLAG_PADDING_ON : u32 = 0x00000001;
876    pub const MPEGLAYER3_FLAG_PADDING_OFF: u32 = 0x00000002;
877
878    pub fn new(bitrate: u32, sample_rate: u32) -> Self {
879        Self {
880            id: 1,
881            flags: Self::MPEGLAYER3_FLAG_PADDING_OFF,
882            block_size: (144 * bitrate / sample_rate) as u16,
883            frames_per_block: 1,
884            codec_delay: 0,
885        }
886    }
887
888    pub fn sizeof() -> usize {
889        12
890    }
891
892    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
893        Ok(Self{
894            id: u16::read_le(reader)?,
895            flags: u32::read_le(reader)?,
896            block_size: u16::read_le(reader)?,
897            frames_per_block: u16::read_le(reader)?,
898            codec_delay: u16::read_le(reader)?,
899        })
900    }
901
902    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
903        self.id.write_le(writer)?;
904        self.flags.write_le(writer)?;
905        self.block_size.write_le(writer)?;
906        self.frames_per_block.write_le(writer)?;
907        self.codec_delay.write_le(writer)?;
908        Ok(())
909    }
910}
911
912impl ExtensibleData {
913    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
914        Ok(Self{
915            valid_bits_per_sample: u16::read_le(reader)?,
916            channel_mask: u32::read_le(reader)?,
917            sub_format: GUID::read(reader)?,
918        })
919    }
920
921    pub fn sizeof() -> usize {
922        22
923    }
924
925    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
926        self.valid_bits_per_sample.write_le(writer)?;
927        self.channel_mask.write_le(writer)?;
928        self.sub_format.write(writer)?;
929        Ok(())
930    }
931}
932
933// https://www.recordingblogs.com/wiki/silent-chunk-of-a-wave-file
934#[derive(Debug, Clone, Copy)]
935pub struct SlntChunk {
936    data: u32,
937}
938
939impl SlntChunk {
940    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
941        Ok(Self{
942            data: u32::read_le(reader)?,
943        })
944    }
945
946    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
947        let cw = ChunkWriter::begin(writer, b"bext")?;
948        self.data.write_le(cw.writer)?;
949        Ok(())
950    }
951}
952
953#[derive(Clone)]
954pub struct BextChunk {
955    pub description: String,
956    pub originator: String,
957    pub originator_ref: String,
958    pub origination_date: String,
959    pub origination_time: String,
960    pub time_ref: u64,
961    pub version: u16,
962    pub umid: [u8; 64],
963    pub reserved: [u8; 190],
964    pub coding_history: [u8; 1],
965}
966
967impl BextChunk {
968    pub fn read(reader: &mut impl Reader, text_encoding: &StringCodecMaps) -> Result<Self, AudioReadError> {
969        let description = read_str(reader, 256, text_encoding)?;
970        let originator = read_str(reader, 32, text_encoding)?;
971        let originator_ref = read_str(reader, 32, text_encoding)?;
972        let origination_date = read_str(reader, 10, text_encoding)?;
973        let origination_time = read_str(reader, 8, text_encoding)?;
974        let time_ref = u64::read_le(reader)?;
975        let version = u16::read_le(reader)?;
976        let mut umid = [0u8; 64];
977        let mut reserved = [0u8; 190];
978        let mut coding_history = [0u8; 1];
979        reader.read_exact(&mut umid)?;
980        reader.read_exact(&mut reserved)?;
981        reader.read_exact(&mut coding_history)?;
982        Ok(Self {
983            description,
984            originator,
985            originator_ref,
986            origination_date,
987            origination_time,
988            time_ref,
989            version,
990            umid,
991            reserved,
992            coding_history,
993        })
994    }
995
996    pub fn write(&self, writer: &mut dyn Writer, text_encoding: &StringCodecMaps) -> Result<(), AudioWriteError> {
997        let cw = ChunkWriter::begin(writer, b"bext")?;
998        write_str_sized(cw.writer, &self.description, 256, text_encoding)?;
999        write_str_sized(cw.writer, &self.originator, 32, text_encoding)?;
1000        write_str_sized(cw.writer, &self.originator_ref, 32, text_encoding)?;
1001        write_str_sized(cw.writer, &self.origination_date, 10, text_encoding)?;
1002        write_str_sized(cw.writer, &self.origination_time, 8, text_encoding)?;
1003        self.time_ref.write_le(cw.writer)?;
1004        self.version.write_le(cw.writer)?;
1005        cw.writer.write_all(&self.umid)?;
1006        cw.writer.write_all(&self.reserved)?;
1007        cw.writer.write_all(&self.coding_history)?;
1008        Ok(())
1009    }
1010}
1011
1012impl Debug for BextChunk{
1013    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
1014        fmt.debug_struct("BextChunk")
1015            .field("description", &self.description)
1016            .field("originator", &self.originator)
1017            .field("originator_ref", &self.originator_ref)
1018            .field("origination_date", &self.origination_date)
1019            .field("origination_time", &self.origination_time)
1020            .field("time_ref", &self.time_ref)
1021            .field("version", &self.version)
1022            .field("umid", &format_args!("[{}]", self.umid.iter().map(|byte|{format!("0x{:02x}", byte)}).collect::<Vec<String>>().join(",")))
1023            .field("reserved", &format_args!("[u8; {}]", self.reserved.len()))
1024            .field("coding_history", &self.coding_history)
1025            .finish()
1026    }
1027}
1028
1029#[derive(Debug, Clone)]
1030pub struct SmplChunk {
1031    pub manufacturer: u32,
1032    pub product: u32,
1033    pub sample_period: u32,
1034    pub midi_unity_note: u32,
1035    pub midi_pitch_fraction: u32,
1036    pub smpte_format: u32,
1037    pub smpte_offset: u32,
1038    pub num_sample_loops: u32,
1039    pub sampler_data: u32,
1040    pub loops: Vec<SmplSampleLoop>,
1041}
1042
1043#[derive(Debug, Clone, Copy)]
1044pub struct SmplSampleLoop {
1045    pub identifier: u32,
1046    pub type_: u32,
1047    pub start: u32,
1048    pub end: u32,
1049    pub fraction: u32,
1050    pub play_count: u32,
1051}
1052
1053impl SmplChunk {
1054    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1055        let mut ret = Self{
1056            manufacturer: u32::read_le(reader)?,
1057            product: u32::read_le(reader)?,
1058            sample_period: u32::read_le(reader)?,
1059            midi_unity_note: u32::read_le(reader)?,
1060            midi_pitch_fraction: u32::read_le(reader)?,
1061            smpte_format: u32::read_le(reader)?,
1062            smpte_offset: u32::read_le(reader)?,
1063            num_sample_loops: u32::read_le(reader)?,
1064            sampler_data: u32::read_le(reader)?,
1065            loops: Vec::<SmplSampleLoop>::new(),
1066        };
1067        for _ in 0..ret.num_sample_loops {
1068            ret.loops.push(SmplSampleLoop::read(reader)?);
1069        }
1070        Ok(ret)
1071    }
1072
1073    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1074        let cw = ChunkWriter::begin(writer, b"smpl")?;
1075        self.manufacturer.write_le(cw.writer)?;
1076        self.product.write_le(cw.writer)?;
1077        self.sample_period.write_le(cw.writer)?;
1078        self.midi_unity_note.write_le(cw.writer)?;
1079        self.midi_pitch_fraction.write_le(cw.writer)?;
1080        self.smpte_format.write_le(cw.writer)?;
1081        self.smpte_offset.write_le(cw.writer)?;
1082        self.num_sample_loops.write_le(cw.writer)?;
1083        self.sampler_data.write_le(cw.writer)?;
1084        for l in self.loops.iter() {
1085            l.write(cw.writer)?;
1086        }
1087        Ok(())
1088    }
1089}
1090
1091impl SmplSampleLoop {
1092    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1093        Ok(Self{
1094            identifier: u32::read_le(reader)?,
1095            type_: u32::read_le(reader)?,
1096            start: u32::read_le(reader)?,
1097            end: u32::read_le(reader)?,
1098            fraction: u32::read_le(reader)?,
1099            play_count: u32::read_le(reader)?,
1100        })
1101    }
1102
1103    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1104        self.identifier.write_le(writer)?;
1105        self.type_.write_le(writer)?;
1106        self.start.write_le(writer)?;
1107        self.end.write_le(writer)?;
1108        self.fraction.write_le(writer)?;
1109        self.play_count.write_le(writer)?;
1110        Ok(())
1111    }
1112}
1113
1114#[derive(Debug, Clone, Copy)]
1115pub struct InstChunk {
1116    pub base_note: u8,
1117    pub detune: u8,
1118    pub gain: u8,
1119    pub low_note: u8,
1120    pub high_note: u8,
1121    pub low_velocity: u8,
1122    pub high_velocity: u8,
1123}
1124
1125impl InstChunk {
1126    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1127        Ok(Self{
1128            base_note: u8::read_le(reader)?,
1129            detune: u8::read_le(reader)?,
1130            gain: u8::read_le(reader)?,
1131            low_note: u8::read_le(reader)?,
1132            high_note: u8::read_le(reader)?,
1133            low_velocity: u8::read_le(reader)?,
1134            high_velocity: u8::read_le(reader)?,
1135        })
1136    }
1137
1138    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1139        let cw = ChunkWriter::begin(writer, b"INST")?;
1140        self.base_note.write_le(cw.writer)?;
1141        self.detune.write_le(cw.writer)?;
1142        self.gain.write_le(cw.writer)?;
1143        self.low_note.write_le(cw.writer)?;
1144        self.high_note.write_le(cw.writer)?;
1145        self.low_velocity.write_le(cw.writer)?;
1146        self.high_velocity.write_le(cw.writer)?;
1147        Ok(())
1148    }
1149}
1150
1151// https://www.recordingblogs.com/wiki/playlist-chunk-of-a-wave-file
1152#[derive(Debug, Clone)]
1153pub struct PlstChunk {
1154    pub playlist_len: u32,
1155    pub data: Vec<Plst>,
1156}
1157
1158#[derive(Debug, Clone, Copy)]
1159pub struct Plst {
1160    pub cue_point_id: u32,
1161    pub num_samples: u32,
1162    pub repeats: u32,
1163}
1164
1165impl PlstChunk {
1166    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1167        let playlist_len = u32::read_le(reader)?;
1168        Ok(Self {
1169            playlist_len,
1170            data: (0..playlist_len).map(|_| -> Result<Plst, AudioReadError> {
1171                Plst::read(reader)
1172            }).collect::<Result<Vec<Plst>, AudioReadError>>()?,
1173        })
1174    }
1175
1176    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1177        let cw = ChunkWriter::begin(writer, b"plst")?;
1178        self.playlist_len.write_le(cw.writer)?;
1179        for data in self.data.iter() {
1180            data.write(cw.writer)?;
1181        }
1182        Ok(())
1183    }
1184
1185    pub fn build_map(&self) -> BTreeMap<u32, Plst> {
1186        self.data.iter().map(|plst|{(plst.cue_point_id, *plst)}).collect()
1187    }
1188}
1189
1190impl Plst {
1191    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1192        Ok(Self{
1193            cue_point_id: u32::read_le(reader)?,
1194            num_samples: u32::read_le(reader)?,
1195            repeats: u32::read_le(reader)?,
1196        })
1197    }
1198
1199    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1200        self.cue_point_id.write_le(writer)?;
1201        self.num_samples.write_le(writer)?;
1202        self.repeats.write_le(writer)?;
1203        Ok(())
1204    }
1205}
1206
1207// https://www.recordingblogs.com/wiki/cue-chunk-of-a-wave-file
1208// https://wavref.til.cafe/chunk/cue/
1209#[derive(Debug, Clone)]
1210pub struct CueChunk {
1211    pub num_cues: u32,
1212    pub cue_points: Vec<CuePoint>,
1213}
1214
1215#[derive(Debug, Clone, Copy)]
1216pub struct CuePoint {
1217    pub cue_point_id: u32,
1218    pub position: u32,
1219    pub data_chunk_id: [u8; 4],
1220    pub chunk_start: u32,
1221    pub block_start: u32,
1222    pub offset: u32,
1223}
1224
1225impl CueChunk {
1226    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1227        let num_cues = u32::read_le(reader)?;
1228        Ok(Self {
1229            num_cues,
1230            cue_points: (0.. num_cues).map(|_| -> Result<CuePoint, AudioReadError> {
1231                CuePoint::read(reader)
1232            }).collect::<Result<Vec<CuePoint>, AudioReadError>>()?,
1233        })
1234    }
1235
1236    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1237        let cw = ChunkWriter::begin(writer, b"cue ")?;
1238        self.num_cues.write_le(cw.writer)?;
1239        for cue_point in self.cue_points.iter() {
1240            cue_point.write(cw.writer)?;
1241        }
1242        Ok(())
1243    }
1244
1245    pub fn build_map(&self) -> BTreeMap<u32, &CuePoint> {
1246        self.cue_points.iter().map(|cue|{(cue.cue_point_id, cue)}).collect()
1247    }
1248}
1249
1250impl CuePoint {
1251    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1252        let mut data_chunk_id = [0u8; 4];
1253        reader.read_exact(&mut data_chunk_id)?;
1254        Ok(Self{
1255            cue_point_id: u32::read_le(reader)?,
1256            position: u32::read_le(reader)?,
1257            data_chunk_id,
1258            chunk_start: u32::read_le(reader)?,
1259            block_start: u32::read_le(reader)?,
1260            offset: u32::read_le(reader)?,
1261        })
1262    }
1263
1264    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1265        self.cue_point_id.write_le(writer)?;
1266        self.position.write_le(writer)?;
1267        writer.write_all(&self.data_chunk_id)?;
1268        self.chunk_start.write_le(writer)?;
1269        self.block_start.write_le(writer)?;
1270        self.offset.write_le(writer)?;
1271        Ok(())
1272    }
1273}
1274
1275#[derive(Debug, Clone)]
1276pub enum ListChunk {
1277    Info(BTreeMap<String, String>),
1278    Adtl(BTreeMap<u32, AdtlChunk>),
1279}
1280
1281#[derive(Debug, Clone)]
1282pub enum AdtlChunk { // https://wavref.til.cafe/chunk/adtl/
1283    Labl(LablChunk),
1284    Note(NoteChunk),
1285    Ltxt(LtxtChunk),
1286    File(FileChunk),
1287}
1288
1289#[derive(Debug, Clone)]
1290pub struct LablChunk {
1291    pub cue_point_id: u32,
1292    pub data: String,
1293}
1294
1295#[derive(Debug, Clone)]
1296pub struct NoteChunk {
1297    pub cue_point_id: u32,
1298    pub data: String,
1299}
1300
1301#[derive(Debug, Clone)]
1302pub struct LtxtChunk {
1303    pub cue_point_id: u32,
1304    pub sample_length: u32,
1305    pub purpose_id: String,
1306    pub country: u16,
1307    pub language: u16,
1308    pub dialect: u16,
1309    pub code_page: u16,
1310    pub data: String,
1311}
1312
1313#[derive(Clone)]
1314pub struct FileChunk {
1315    pub cue_point_id: u32,
1316    pub media_type: u32,
1317    pub file_data: Vec<u8>,
1318}
1319
1320impl Debug for FileChunk{
1321    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
1322        fmt.debug_struct("FileChunk")
1323            .field("cue_point_id", &self.cue_point_id)
1324            .field("media_type", &self.media_type)
1325            .field("file_data", &format_args!("[u8; {}]", self.file_data.len()))
1326            .finish()
1327    }
1328}
1329
1330impl AdtlChunk {
1331    pub fn read(reader: &mut impl Reader, text_encoding: &StringCodecMaps) -> Result<Self, AudioReadError> {
1332        let sub_chunk = ChunkHeader::read(reader)?;
1333        let ret = match &sub_chunk.flag {
1334            b"labl" => {
1335                Self::Labl(LablChunk{
1336                    cue_point_id: u32::read_le(reader)?,
1337                    data: read_str(reader, (sub_chunk.size - 4) as usize, text_encoding)?,
1338                })
1339            },
1340            b"note" => {
1341                Self::Note(NoteChunk{
1342                    cue_point_id: u32::read_le(reader)?,
1343                    data: read_str(reader, (sub_chunk.size - 4) as usize, text_encoding)?,
1344                })
1345            },
1346            b"ltxt" => {
1347                let mut ltxt = LtxtChunk{
1348                    cue_point_id: u32::read_le(reader)?,
1349                    sample_length: u32::read_le(reader)?,
1350                    purpose_id: read_str(reader, 4, text_encoding)?,
1351                    country: u16::read_le(reader)?,
1352                    language: u16::read_le(reader)?,
1353                    dialect: u16::read_le(reader)?,
1354                    code_page: u16::read_le(reader)?,
1355                    data: String::new(),
1356                };
1357                ltxt.data = read_str_by_code_page(reader, (sub_chunk.size - 20) as usize, text_encoding, ltxt.code_page as u32)?;
1358                Self::Ltxt(ltxt)
1359            },
1360            b"file" => {
1361                Self::File(FileChunk{
1362                    cue_point_id: u32::read_le(reader)?,
1363                    media_type: u32::read_le(reader)?,
1364                    file_data: read_bytes(reader, (sub_chunk.size - 8) as usize)?,
1365                })
1366            }
1367            other => {
1368                return Err(AudioReadError::UnexpectedFlag("labl/note/ltxt".to_owned(), String::from_utf8_lossy(other).to_string()));
1369            },
1370        };
1371        sub_chunk.seek_to_next_chunk(reader)?;
1372        Ok(ret)
1373    }
1374
1375    pub fn write(&self, writer: &mut dyn Writer, text_encoding: &StringCodecMaps) -> Result<(), AudioWriteError> {
1376        fn to_sz(s: &str) -> String {
1377            if !s.is_empty() {
1378                let mut s = s.to_owned();
1379                if !s.ends_with('\0') {s.push('\0');}
1380                s
1381            } else {
1382                "\0".to_owned()
1383            }
1384        }
1385        match self {
1386            Self::Labl(labl) => {
1387                let cw = ChunkWriter::begin(writer, b"labl")?;
1388                labl.cue_point_id.write_le(cw.writer)?;
1389                write_str(cw.writer, &to_sz(&labl.data), text_encoding)?;
1390            },
1391            Self::Note(note) => {
1392                let cw = ChunkWriter::begin(writer, b"note")?;
1393                note.cue_point_id.write_le(cw.writer)?;
1394                write_str(cw.writer, &to_sz(&note.data), text_encoding)?;
1395            },
1396            Self::Ltxt(ltxt) => {
1397                let cw = ChunkWriter::begin(writer, b"ltxt")?;
1398                ltxt.cue_point_id.write_le(cw.writer)?;
1399                ltxt.sample_length.write_le(cw.writer)?;
1400                write_str_sized(cw.writer, &ltxt.purpose_id, 4, text_encoding)?;
1401                ltxt.country.write_le(cw.writer)?;
1402                ltxt.language.write_le(cw.writer)?;
1403                ltxt.dialect.write_le(cw.writer)?;
1404                ltxt.code_page.write_le(cw.writer)?;
1405                write_str(cw.writer, &to_sz(&ltxt.data), text_encoding)?;
1406            },
1407            Self::File(file) => {
1408                let cw = ChunkWriter::begin(writer, b"file")?;
1409                file.cue_point_id.write_le(cw.writer)?;
1410                file.media_type.write_le(cw.writer)?;
1411                cw.writer.write_all(&file.file_data)?;
1412            },
1413        }
1414        Ok(())
1415    }
1416
1417    pub fn get_cue_point_id(&self) -> u32 {
1418        match self {
1419            Self::Labl(labl) => labl.cue_point_id,
1420            Self::Note(lote) => lote.cue_point_id,
1421            Self::Ltxt(ltxt) => ltxt.cue_point_id,
1422            Self::File(lile) => lile.cue_point_id,
1423        }
1424    }
1425}
1426
1427impl ListChunk {
1428    pub fn read(reader: &mut impl Reader, chunk_size: u64, text_encoding: &StringCodecMaps) -> Result<Self, AudioReadError> {
1429        let end_of_chunk = ChunkHeader::align(reader.stream_position()? + chunk_size);
1430        let mut flag = [0u8; 4];
1431        reader.read_exact(&mut flag)?;
1432        match &flag {
1433            b"info" | b"INFO" => {
1434                let dict = Self::read_dict(reader, end_of_chunk, text_encoding)?;
1435                Ok(Self::Info(dict))
1436            },
1437            b"adtl" => {
1438                let mut adtl_map = BTreeMap::<u32, AdtlChunk>::new();
1439                while reader.stream_position()? < end_of_chunk {
1440                    let adtl = AdtlChunk::read(reader, text_encoding)?;
1441                    let cue_point_id = adtl.get_cue_point_id();
1442                    if let Some(dup) = adtl_map.insert(cue_point_id, adtl.clone()) {
1443                        // If the chunk point ID duplicates,  the new one will be used to overwrite the old one.
1444                        eprintln!("Duplicated chunk point ID {cue_point_id} for the `Adtl` data: old is {:?}, and will be overwritten by the new one: {:?}", dup, adtl);
1445                    }
1446                }
1447                Ok(Self::Adtl(adtl_map))
1448            },
1449            other => {
1450                Err(AudioReadError::Unimplemented(format!("Unknown indentifier in LIST chunk: {}", text_encoding.decode_flags(other))))
1451            },
1452        }
1453    }
1454
1455    pub fn write(&self, writer: &mut dyn Writer, text_encoding: &StringCodecMaps) -> Result<(), AudioWriteError> {
1456        let mut cw = ChunkWriter::begin(writer, b"LIST")?;
1457        match self {
1458            Self::Info(dict) => {
1459                cw.writer.write_all(b"INFO")?;
1460                Self::write_dict(&mut cw.writer, dict, text_encoding)?;
1461            },
1462            Self::Adtl(adtls) => {
1463                cw.writer.write_all(b"adtl")?;
1464                for (_cue_point_id, adtl) in adtls.iter() {
1465                    adtl.write(&mut cw.writer, text_encoding)?;
1466                }
1467            },
1468        };
1469        Ok(())
1470    }
1471
1472    fn read_dict(reader: &mut impl Reader, end_of_chunk: u64, text_encoding: &StringCodecMaps) -> Result<BTreeMap<String, String>, AudioReadError> {
1473        // The INFO chunk consists of multiple key-value pairs for song metadata. 
1474        // Within its byte size constraints, read all key-value entries.
1475        let mut dict = BTreeMap::<String, String>::new();
1476        while reader.stream_position()? < end_of_chunk {
1477            let key_chunk = ChunkHeader::read(reader)?; // Every chunk's name is a key, its content is the value.
1478            let value_str = read_str(reader, key_chunk.size as usize, text_encoding)?;
1479            let key_str = text_encoding.decode(&key_chunk.flag);
1480            dict.insert(key_str, value_str);
1481            key_chunk.seek_to_next_chunk(reader)?;
1482        }
1483        // Let's try to store the key in uppercase form, if the INFO chunk provides both uppercase or lowercase, we store both of them.
1484        let mut to_be_added = Vec::<(String, String)>::new();
1485        for (key, val) in dict.iter() {
1486            let key_uppercase = key.to_uppercase();
1487            if key_uppercase == *key {
1488                // It is uppercase originally.
1489                continue;
1490            }
1491            if dict.contains_key(&key_uppercase) {
1492                // The LIST INFO chunk provided the uppercase key, and its value may be different from the lowercase key value, better not to overwrite it.
1493                continue;
1494            }
1495            to_be_added.push((key_uppercase, val.clone()));
1496        }
1497        for (key_uppercase, val) in to_be_added.into_iter() {
1498            dict.insert(key_uppercase, val);
1499        }
1500        Ok(dict)
1501    }
1502
1503    fn write_dict(writer: &mut dyn Writer, dict: &BTreeMap<String, String>, text_encoding: &StringCodecMaps) -> Result<(), AudioWriteError> {
1504        for (key, val) in dict.iter() {
1505            if key.len() != 4 {
1506                return Err(AudioWriteError::InvalidArguments("flag must be 4 bytes".to_owned()));
1507            }
1508            let bytes = key.as_bytes();
1509            let flag = [bytes[0], bytes[1], bytes[2], bytes[3]];
1510            let cw = ChunkWriter::begin(writer, &flag)?;
1511            let mut val = val.clone();
1512            val.push('\0');
1513            write_str(cw.writer, &val, text_encoding)?;
1514        }
1515        Ok(())
1516    }
1517}
1518
1519pub fn get_list_info_map() -> BTreeMap<&'static str, &'static str> {
1520    [ // https://www.recordingblogs.com/wiki/list-chunk-of-a-wave-file
1521        ("IARL", "The location where the subject of the file is archived"),
1522        ("IART", "The artist of the original subject of the file"),
1523        ("ICMS", "The name of the person or organization that commissioned the original subject of the file"),
1524        ("ICMT", "General comments about the file or its subject"),
1525        ("ICOP", "Copyright information about the file (e.g., \"Copyright Some Company 2011\")"),
1526        ("ICRD", "The date the subject of the file was created (creation date) (e.g., \"2022-12-31\")"),
1527        ("ICRP", "Whether and how an image was cropped"),
1528        ("IDIM", "The dimensions of the original subject of the file"),
1529        ("IDPI", "Dots per inch settings used to digitize the file"),
1530        ("IENG", "The name of the engineer who worked on the file"),
1531        ("IGNR", "The genre of the subject"),
1532        ("IKEY", "A list of keywords for the file or its subject"),
1533        ("ILGT", "Lightness settings used to digitize the file"),
1534        ("IMED", "Medium for the original subject of the file"),
1535        ("INAM", "Title of the subject of the file (name)"),
1536        ("IPLT", "The number of colors in the color palette used to digitize the file"),
1537        ("IPRD", "Name of the title the subject was originally intended for"),
1538        ("ISBJ", "Description of the contents of the file (subject)"),
1539        ("ISFT", "Name of the software package used to create the file"),
1540        ("ISRC", "The name of the person or organization that supplied the original subject of the file"),
1541        ("ISRF", "The original form of the material that was digitized (source form)"),
1542        ("ITCH", "The name of the technician who digitized the subject file"),
1543        ("ITRK", "The track number of the file")
1544    ].iter().copied().collect()
1545}
1546
1547pub trait ListInfo {
1548    fn get_is_list_info(&self) -> bool;
1549    fn get(&self, key: &str) -> Option<&String>;
1550    fn set(&mut self, key: &str, value: &str) -> Result<Option<String>, AudioError>;
1551
1552    fn get_archive(&self) -> Option<&String> {self.get("IARL")}
1553    fn get_artist(&self) -> Option<&String> {self.get("IART")}
1554    fn get_comment(&self) -> Option<&String> {self.get("ICMT")}
1555    fn get_producer(&self) -> Option<&String> {self.get("ICMS")}
1556    fn get_copyright(&self) -> Option<&String> {self.get("ICOP")}
1557    fn get_create_date(&self) -> Option<&String> {self.get("ICRD")}
1558    fn get_engineer(&self) -> Option<&String> {self.get("IENG")}
1559    fn get_genre(&self) -> Option<&String> {self.get("IGNR")}
1560    fn get_keywords(&self) -> Option<&String> {self.get("IKEY")}
1561    fn get_lightness(&self) -> Option<&String> {self.get("ILGT")}
1562    fn get_medium(&self) -> Option<&String> {self.get("IMED")}
1563    fn get_name(&self) -> Option<&String> {self.get("INAM")}
1564    fn get_album(&self) -> Option<&String> {self.get("IPRD")}
1565    fn get_description(&self) -> Option<&String> {self.get("ISBJ")}
1566    fn get_software(&self) -> Option<&String> {self.get("ISFT")}
1567    fn get_source(&self) -> Option<&String> {self.get("ISRC")}
1568    fn get_orig_form(&self) -> Option<&String> {self.get("ISRF")}
1569    fn get_technician(&self) -> Option<&String> {self.get("ITCH")}
1570    fn get_track_no(&self) -> Option<&String> {self.get("ITRK")}
1571
1572    fn get_track_no_as_number(&self) -> Result<u32, AudioError> {
1573        if let Some(track_no) = self.get_track_no() {
1574            match track_no.parse::<u32>() {
1575                Ok(track_no) => Ok(track_no),
1576                Err(_) => Err(AudioError::Unparseable(track_no.clone())),
1577            }
1578        } else {
1579            Err(AudioError::NoSuchData("ITRK".to_owned()))
1580        }
1581    }
1582
1583    fn set_archive(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("IARL", value)}
1584    fn set_artist(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("IART", value)}
1585    fn set_comment(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ICMT", value)}
1586    fn set_producer(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ICMS", value)}
1587    fn set_copyright(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ICOP", value)}
1588    fn set_create_date(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ICRD", value)}
1589    fn set_engineer(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("IENG", value)}
1590    fn set_genre(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("IGNR", value)}
1591    fn set_keywords(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("IKEY", value)}
1592    fn set_lightness(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ILGT", value)}
1593    fn set_medium(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("IMED", value)}
1594    fn set_name(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("INAM", value)}
1595    fn set_album(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("IPRD", value)}
1596    fn set_description(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ISBJ", value)}
1597    fn set_software(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ISFT", value)}
1598    fn set_source(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ISRC", value)}
1599    fn set_orig_form(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ISRF", value)}
1600    fn set_technician(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ITCH", value)}
1601    fn set_track_no(&mut self, value: &str) -> Result<Option<String>, AudioError> {self.set("ITRK", value)}
1602    fn set_track_no_as_number(&mut self, track_no: u32) -> Result<u32, AudioError> {
1603        match self.set_track_no(&format!("{track_no}")) {
1604            Err(e) => Err(e),
1605            Ok(track_no) => {
1606                if let Some(track_no) = track_no {
1607                    match track_no.parse::<u32>() {
1608                        Ok(track_no) => Ok(track_no),
1609                        Err(_) => Err(AudioError::Unparseable(track_no.clone())),
1610                    }
1611                } else {
1612                    Ok(0)
1613                }
1614            },
1615        }
1616    }
1617}
1618
1619impl ListInfo for ListChunk {
1620    fn get_is_list_info(&self) -> bool {
1621        matches!(self, Self::Info(_))
1622    }
1623
1624    fn get(&self, key: &str) -> Option<&String> {
1625        if let Self::Info(dict) = self {dict.get(key)} else {None}
1626    }
1627
1628    fn set(&mut self, key: &str, value: &str) -> Result<Option<String>, AudioError> {
1629        if let Self::Info(ref mut dict) = self {
1630            Ok(dict.insert(key.to_owned(), value.to_string()))
1631        } else {
1632            Err(AudioError::InvalidArguments("The type of the `LIST` chunk is `adtl`, not `INFO`, so can not set the metadata values.".to_owned()))
1633        }
1634    }
1635}
1636
1637#[allow(clippy::zero_prefixed_literal)]
1638pub fn get_country_code_map() -> HashMap<u16, &'static str> {
1639    [ // https://wavref.til.cafe/chunk/cset/
1640        (000, "None (assume 001 = USA)"),
1641        (001, "USA"),
1642        (002, "Canada"),
1643        (003, "Latin America"),
1644        (030, "Greece"),
1645        (031, "Netherlands"),
1646        (032, "Belgium"),
1647        (033, "France"),
1648        (034, "Spain"),
1649        (039, "Italy"),
1650        (041, "Switzerland"),
1651        (043, "Austria"),
1652        (044, "United Kingdom"),
1653        (045, "Denmark"),
1654        (046, "Sweden"),
1655        (047, "Norway"),
1656        (049, "West Germany"),
1657        (052, "Mexico"),
1658        (055, "Brazil"),
1659        (061, "Australia"),
1660        (064, "New Zealand"),
1661        (081, "Japan"),
1662        (082, "Korea"),
1663        (086, "People’s Republic of China"),
1664        (088, "Taiwan"),
1665        (090, "Turkey"),
1666        (351, "Portugal"),
1667        (352, "Luxembourg"),
1668        (354, "Iceland"),
1669        (358, "Finland"),
1670    ].iter().copied().collect()
1671}
1672
1673#[derive(Debug, Clone, Copy, Hash, PartialEq)]
1674pub struct LanguageDialect {
1675    lang: u16,
1676    dial: u16,
1677}
1678
1679impl Eq for LanguageDialect{}
1680
1681#[derive(Debug, Clone, Copy)]
1682pub struct LanguageSpecification {
1683    lang: &'static str,
1684    spec: &'static str,
1685}
1686
1687pub fn get_language_dialect_code_map() -> HashMap<LanguageDialect, LanguageSpecification> {
1688    [ // https://wavref.til.cafe/chunk/cset/
1689        (LanguageDialect{lang: 0 ,  dial: 0}, LanguageSpecification{lang: "None (assume 9,1 = US English)", spec: "RIFF1991"}),
1690        (LanguageDialect{lang: 1 ,  dial: 1}, LanguageSpecification{lang: "Arabic", spec: "RIFF1991"}),
1691        (LanguageDialect{lang: 2 ,  dial: 1}, LanguageSpecification{lang: "Bulgarian", spec: "RIFF1991"}),
1692        (LanguageDialect{lang: 3 ,  dial: 1}, LanguageSpecification{lang: "Catalan", spec: "RIFF1991"}),
1693        (LanguageDialect{lang: 4 ,  dial: 1}, LanguageSpecification{lang: "Traditional Chinese", spec: "RIFF1991"}),
1694        (LanguageDialect{lang: 4 ,  dial: 2}, LanguageSpecification{lang: "Simplified Chinese", spec: "RIFF1991"}),
1695        (LanguageDialect{lang: 5 ,  dial: 1}, LanguageSpecification{lang: "Czech", spec: "RIFF1991"}),
1696        (LanguageDialect{lang: 6 ,  dial: 1}, LanguageSpecification{lang: "Danish", spec: "RIFF1991"}),
1697        (LanguageDialect{lang: 7 ,  dial: 1}, LanguageSpecification{lang: "German", spec: "RIFF1991"}),
1698        (LanguageDialect{lang: 7 ,  dial: 2}, LanguageSpecification{lang: "Swiss German", spec: "RIFF1991"}),
1699        (LanguageDialect{lang: 8 ,  dial: 1}, LanguageSpecification{lang: "Greek", spec: "RIFF1991"}),
1700        (LanguageDialect{lang: 9 ,  dial: 1}, LanguageSpecification{lang: "US English", spec: "RIFF1991"}),
1701        (LanguageDialect{lang: 9 ,  dial: 2}, LanguageSpecification{lang: "UK English", spec: "RIFF1991"}),
1702        (LanguageDialect{lang: 10,  dial: 1}, LanguageSpecification{lang: "Spanish", spec: "RIFF1991"}),
1703        (LanguageDialect{lang: 10,  dial: 2}, LanguageSpecification{lang: "Spanish", spec: "Mexican RIFF1991"}),
1704        (LanguageDialect{lang: 11,  dial: 1}, LanguageSpecification{lang: "Finnish", spec: "RIFF1991"}),
1705        (LanguageDialect{lang: 12,  dial: 1}, LanguageSpecification{lang: "French", spec: "RIFF1991"}),
1706        (LanguageDialect{lang: 12,  dial: 2}, LanguageSpecification{lang: "Belgian French", spec: "RIFF1991"}),
1707        (LanguageDialect{lang: 12,  dial: 3}, LanguageSpecification{lang: "Canadian French", spec: "RIFF1991"}),
1708        (LanguageDialect{lang: 12,  dial: 4}, LanguageSpecification{lang: "Swiss French", spec: "RIFF1991"}),
1709        (LanguageDialect{lang: 13,  dial: 1}, LanguageSpecification{lang: "Hebrew", spec: "RIFF1991"}),
1710        (LanguageDialect{lang: 14,  dial: 1}, LanguageSpecification{lang: "Hungarian", spec: "RIFF1994"}),
1711        (LanguageDialect{lang: 15,  dial: 1}, LanguageSpecification{lang: "Icelandic", spec: "RIFF1994"}),
1712        (LanguageDialect{lang: 16,  dial: 1}, LanguageSpecification{lang: "Italian", spec: "RIFF1994"}),
1713        (LanguageDialect{lang: 16,  dial: 2}, LanguageSpecification{lang: "Swiss Italian", spec: "RIFF1994"}),
1714        (LanguageDialect{lang: 17,  dial: 1}, LanguageSpecification{lang: "Japanese", spec: "RIFF1994"}),
1715        (LanguageDialect{lang: 18,  dial: 1}, LanguageSpecification{lang: "Korean", spec: "RIFF1994"}),
1716        (LanguageDialect{lang: 19,  dial: 1}, LanguageSpecification{lang: "Dutch", spec: "RIFF1994"}),
1717        (LanguageDialect{lang: 19,  dial: 2}, LanguageSpecification{lang: "Belgian Dutch", spec: "RIFF1994"}),
1718        (LanguageDialect{lang: 20,  dial: 1}, LanguageSpecification{lang: "Norwegian - Bokmal", spec: "RIFF1994"}),
1719        (LanguageDialect{lang: 20,  dial: 2}, LanguageSpecification{lang: "Norwegian - Nynorsk", spec: "RIFF1994"}),
1720        (LanguageDialect{lang: 21,  dial: 1}, LanguageSpecification{lang: "Polish", spec: "RIFF1994"}),
1721        (LanguageDialect{lang: 22,  dial: 1}, LanguageSpecification{lang: "Brazilian Portuguese", spec: "RIFF1994"}),
1722        (LanguageDialect{lang: 22,  dial: 2}, LanguageSpecification{lang: "Portuguese", spec: "RIFF1994"}),
1723        (LanguageDialect{lang: 23,  dial: 1}, LanguageSpecification{lang: "Rhaeto-Romanic", spec: "RIFF1994"}),
1724        (LanguageDialect{lang: 24,  dial: 1}, LanguageSpecification{lang: "Romanian", spec: "RIFF1994"}),
1725        (LanguageDialect{lang: 25,  dial: 1}, LanguageSpecification{lang: "Russian", spec: "RIFF1994"}),
1726        (LanguageDialect{lang: 26,  dial: 1}, LanguageSpecification{lang: "Serbo-Croatian (Latin)", spec: "RIFF1994"}),
1727        (LanguageDialect{lang: 26,  dial: 2}, LanguageSpecification{lang: "Serbo-Croatian (Cyrillic)", spec: "RIFF1994"}),
1728        (LanguageDialect{lang: 27,  dial: 1}, LanguageSpecification{lang: "Slovak", spec: "RIFF1994"}),
1729        (LanguageDialect{lang: 28,  dial: 1}, LanguageSpecification{lang: "Albanian", spec: "RIFF1994"}),
1730        (LanguageDialect{lang: 29,  dial: 1}, LanguageSpecification{lang: "Swedish", spec: "RIFF1994"}),
1731        (LanguageDialect{lang: 30,  dial: 1}, LanguageSpecification{lang: "Thai", spec: "RIFF1994"}),
1732        (LanguageDialect{lang: 31,  dial: 1}, LanguageSpecification{lang: "Turkish", spec: "RIFF1994"}),
1733        (LanguageDialect{lang: 32,  dial: 1}, LanguageSpecification{lang: "Urdu", spec: "RIFF1994"}),
1734        (LanguageDialect{lang: 33,  dial: 1}, LanguageSpecification{lang: "Bahasa", spec: "RIFF1994"}),
1735    ].iter().copied().collect()
1736}
1737
1738#[derive(Debug, Clone)]
1739pub struct FullInfoCuePoint {
1740    pub data_chunk_id: [u8; 4],
1741    pub label: String,
1742    pub note: String,
1743    pub sample_length: u32,
1744    pub purpose_id: String,
1745    pub country: String,
1746    pub language: String,
1747    pub text_data: String,
1748    pub media_type: u32,
1749    pub file_data: Vec<u8>,
1750    pub start_sample: u32,
1751    pub num_samples: u32,
1752    pub repeats: u32,
1753}
1754
1755impl FullInfoCuePoint {
1756    pub fn new(cue_point_id: u32, cue_point: &CuePoint, adtl_chunks: &BTreeMap<u32, AdtlChunk>, plst: &Option<&Plst>, country_code_map: &HashMap<u16, &'static str>, dialect_code_map: &HashMap<LanguageDialect, LanguageSpecification>) -> Result<Self, AudioError> {
1757        let mut ret = Self {
1758            data_chunk_id: cue_point.data_chunk_id,
1759            label: String::new(),
1760            note: String::new(),
1761            sample_length: 0,
1762            purpose_id: String::new(),
1763            country: String::new(),
1764            language: String::new(),
1765            text_data: String::new(),
1766            media_type: 0,
1767            file_data: Vec::<u8>::new(),
1768            start_sample: cue_point.position,
1769            num_samples: 0,
1770            repeats: 0,
1771        };
1772        if let Some(plst) = plst{
1773            ret.num_samples = plst.num_samples;
1774            ret.repeats = plst.repeats;
1775        } else {
1776            eprintln!("Lack of `plst` chunk, `num_samples` should be calculated by yourself, and `repeats` remains zero.");
1777        }
1778        if let Some(adtl) = adtl_chunks.get(&cue_point_id) {
1779            match adtl {
1780                AdtlChunk::Labl(labl) => ret.label = labl.data.clone(),
1781                AdtlChunk::Note(note) => ret.note = note.data.clone(),
1782                AdtlChunk::Ltxt(ltxt) => {
1783                    let lang_dial = LanguageDialect{
1784                        lang: ltxt.language,
1785                        dial: ltxt.dialect,
1786                    };
1787                    let unknown_lang_spec = LanguageSpecification{
1788                        lang: "Unknown",
1789                        spec: "UKNW1994"
1790                    };
1791                    let country = if let Some(country) = country_code_map.get(&ltxt.country) {
1792                        country.to_string()
1793                    } else {
1794                        format!("Unknown country code {}", ltxt.country)
1795                    };
1796                    let language = if let Some(lang_dial) = dialect_code_map.get(&lang_dial) {
1797                        *lang_dial
1798                    } else {
1799                        unknown_lang_spec
1800                    }.lang.to_owned();
1801                    ret.sample_length = ltxt.sample_length;
1802                    ret.purpose_id = ltxt.purpose_id.clone();
1803                    ret.country = country;
1804                    ret.language = language;
1805                    ret.text_data = ltxt.data.clone();
1806                },
1807                AdtlChunk::File(file) => {
1808                    ret.media_type = file.media_type;
1809                    ret.file_data = file.file_data.clone();
1810                },
1811            }
1812            Ok(ret)
1813        } else {
1814            Err(AudioError::NoSuchData(format!("ADTL data for cue point ID: {cue_point_id}")))
1815        }
1816    }
1817}
1818
1819pub fn create_full_info_cue_data(cue_chunk: &CueChunk, adtl_chunks: &BTreeMap<u32, AdtlChunk>, plstchunk: &Option<PlstChunk>) -> Result<BTreeMap<u32, FullInfoCuePoint>, AudioError> {
1820    let country_code_map = get_country_code_map();
1821    let dialect_code_map = get_language_dialect_code_map();
1822    let plstmap = if let Some(plstchunk) = plstchunk {
1823        plstchunk.build_map()
1824    } else {
1825        BTreeMap::<u32, Plst>::new()
1826    };
1827    cue_chunk.cue_points.iter().map(|cue| -> Result<(u32, FullInfoCuePoint), AudioError> {
1828        match FullInfoCuePoint::new(cue.cue_point_id, cue, adtl_chunks, &plstmap.get(&cue.cue_point_id), &country_code_map, &dialect_code_map) {
1829            Ok(full_info_cue_data) => Ok((cue.cue_point_id, full_info_cue_data)),
1830            Err(e) => Err(e),
1831        }
1832    }).collect::<Result<BTreeMap<u32, FullInfoCuePoint>, AudioError>>()
1833}
1834
1835#[derive(Debug, Clone)]
1836pub struct AcidChunk {
1837    pub flags: u32,
1838    pub root_node: u16,
1839    pub reserved1: u16,
1840    pub reserved2: f32,
1841    pub num_beats: u32,
1842    pub meter_denominator: u16,
1843    pub meter_numerator: u16,
1844    pub tempo: f32,
1845}
1846
1847impl AcidChunk {
1848    pub fn read(reader: &mut impl Reader) -> Result<Self, AudioReadError> {
1849        Ok(Self {
1850            flags: u32::read_le(reader)?,
1851            root_node: u16::read_le(reader)?,
1852            reserved1: u16::read_le(reader)?,
1853            reserved2: f32::read_le(reader)?,
1854            num_beats: u32::read_le(reader)?,
1855            meter_denominator: u16::read_le(reader)?,
1856            meter_numerator: u16::read_le(reader)?,
1857            tempo: f32::read_le(reader)?,
1858        })
1859    }
1860
1861    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1862        let cw = ChunkWriter::begin(writer, b"acid")?;
1863        self.flags.write_le(cw.writer)?;
1864        self.root_node.write_le(cw.writer)?;
1865        self.reserved1.write_le(cw.writer)?;
1866        self.reserved2.write_le(cw.writer)?;
1867        self.num_beats.write_le(cw.writer)?;
1868        self.meter_denominator.write_le(cw.writer)?;
1869        self.meter_numerator.write_le(cw.writer)?;
1870        self.tempo.write_le(cw.writer)?;
1871        Ok(())
1872    }
1873}
1874
1875#[derive(Clone)]
1876pub enum JunkChunk{
1877    FullZero(u64),
1878    SomeData(Vec<u8>),
1879}
1880
1881impl JunkChunk {
1882    pub fn from(data: Vec<u8>) -> Self {
1883        let mut is_all_zero = true;
1884        for i in data.iter() {
1885            if *i != 0 {
1886                is_all_zero = false;
1887                break;
1888            }
1889        }
1890        if is_all_zero {
1891            Self::FullZero(data.len() as u64)
1892        } else {
1893            Self::SomeData(data)
1894        }
1895    }
1896
1897    pub fn write(&self, writer: &mut dyn Writer) -> Result<(), AudioWriteError> {
1898        let cw = ChunkWriter::begin(writer, b"JUNK")?;
1899        match self {
1900            Self::FullZero(size) => cw.writer.write_all(&vec![0u8; *size as usize])?,
1901            Self::SomeData(data) => cw.writer.write_all(data)?,
1902        }
1903        Ok(())
1904    }
1905}
1906
1907impl Debug for JunkChunk {
1908    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1909        match self {
1910            Self::FullZero(size) => write!(f, "[0u8; {size}]"),
1911            Self::SomeData(data) => write!(f, "[{}]", data.iter().map(|byte|{format!("0x{:02}", byte)}).collect::<Vec<String>>().join(", ")),
1912        }
1913    }
1914}
1915
1916// If the `id3` feature is enabled, use it to read ID3 data.
1917#[cfg(feature = "id3")]
1918#[allow(non_snake_case)]
1919pub mod Id3{
1920    use std::{io::{Read, Write, Seek}};
1921    use crate::errors::{AudioReadError, AudioWriteError, IOErrorInfo};
1922    pub type Tag = id3::Tag;
1923
1924    pub fn id3_read<R>(reader: &mut R, _size: usize) -> Result<Tag, AudioReadError>
1925    where R: Read + Seek + ?Sized {
1926        Ok(Tag::read_from2(reader)?)
1927    }
1928
1929    pub fn id3_write<W>(tag: &Tag, writer: &mut W) -> Result<(), AudioWriteError>
1930    where W: Write + ?Sized {
1931        Ok(tag.write_to(writer, tag.version())?)
1932    }
1933
1934    impl From<id3::Error> for AudioReadError {
1935        fn from(err: id3::Error) -> Self {
1936            match err.kind {
1937                id3::ErrorKind::Io(ioerr) => AudioReadError::IOError(IOErrorInfo{kind: ioerr.kind(), message: ioerr.to_string()}),
1938                id3::ErrorKind::StringDecoding(bytes) => AudioReadError::StringDecodeError(bytes),
1939                id3::ErrorKind::NoTag => AudioReadError::FormatError(err.description),
1940                id3::ErrorKind::Parsing => AudioReadError::DataCorrupted(err.description),
1941                id3::ErrorKind::InvalidInput => AudioReadError::DataCorrupted(err.description),
1942                id3::ErrorKind::UnsupportedFeature => AudioReadError::Unsupported(err.description),
1943            }
1944        }
1945    }
1946
1947    impl From<id3::Error> for AudioWriteError {
1948        fn from(err: id3::Error) -> Self {
1949            match err.kind {
1950                id3::ErrorKind::Io(ioerr) => AudioWriteError::IOError(IOErrorInfo{kind: ioerr.kind(), message: ioerr.to_string()}),
1951                id3::ErrorKind::StringDecoding(bytes) => AudioWriteError::StringDecodeError(bytes),
1952                id3::ErrorKind::NoTag => AudioWriteError::OtherReason(err.description),
1953                id3::ErrorKind::Parsing => AudioWriteError::OtherReason(err.description),
1954                id3::ErrorKind::InvalidInput => AudioWriteError::OtherReason(err.description),
1955                id3::ErrorKind::UnsupportedFeature => AudioWriteError::Unsupported(err.description),
1956            }
1957        }
1958    }
1959}
1960
1961// If the `id3` feature is disabled, read the raw bytes.
1962#[cfg(not(feature = "id3"))]
1963#[allow(non_snake_case)]
1964pub mod Id3{
1965    use std::io::Read;
1966    use std::vec::Vec;
1967    use std::error::Error;
1968    #[derive(Clone)]
1969    pub struct Tag {
1970        pub data: Vec<u8>,
1971    }
1972    impl Tag {
1973        fn new(data: Vec<u8>) -> Self {
1974            Self {
1975                data,
1976            }
1977        }
1978    }
1979
1980    pub fn id3_read<R>(reader: &mut R, size: usize) -> Result<Tag, AudioReadError>
1981    where R: Read + Seek + ?Sized {
1982        #[cfg(debug_assertions)]
1983        println!("Feature \"id3\" was not enabled, consider compile with \"cargo build --features id3\"");
1984        Ok(Tag::new(super::read_bytes(reader, size)?))
1985    }
1986
1987    pub fn id3_write<W>(tag: &Tag, writer: &mut W) -> Result<(), AudioWriteError>
1988    where W: Write + ?Sized {
1989        #[cfg(debug_assertions)]
1990        println!("Feature \"id3\" was not enabled, the saved id3 binary bytes may not correct, consider compile with \"cargo build --features id3\"");
1991        Ok(writer.write_all(&tag.data))
1992    }
1993
1994    impl std::fmt::Debug for Tag {
1995        fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
1996            fmt.debug_struct("Tag")
1997                .finish_non_exhaustive()
1998        }
1999    }
2000}