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#[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 (_, _) => 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
274pub 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, pub chunk_start: u64, 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 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 pub fn end(self){}
458
459 fn on_drop(&mut self) -> Result<(), AudioWriteError> {
460 if self.ended {
461 return Ok(());
462 }
463 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], pub size: u32, pub chunk_start_pos: u64, }
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, 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, }
681 },
682 other => panic!("Unexpected extension data in the `fmt ` chunk: {:?}", other),
683 }
684 } else {
685 Int }
687 },
688 (3, 32) => Float,
689 (3, 64) => Float,
690 (_, _) => Unknown, }
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 { 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#[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#[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#[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 { 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(¬e.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, <xt.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(<xt.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 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 let mut dict = BTreeMap::<String, String>::new();
1476 while reader.stream_position()? < end_of_chunk {
1477 let key_chunk = ChunkHeader::read(reader)?; 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 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 continue;
1490 }
1491 if dict.contains_key(&key_uppercase) {
1492 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 [ ("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 [ (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 [ (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(<xt.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#[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#[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}