1use crate::{Error, Result};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::io::{Read, Write};
7use std::path::Path;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum AudioFormatType {
12 Wav,
14 Flac,
16 Mp3,
18 Aac,
20 Opus,
22 Ogg,
24 Aiff,
26 Raw,
28 Wav24,
30 Wav32f,
32}
33
34impl AudioFormatType {
35 pub fn extensions(&self) -> &[&str] {
37 match self {
38 AudioFormatType::Wav => &["wav"],
39 AudioFormatType::Flac => &["flac"],
40 AudioFormatType::Mp3 => &["mp3"],
41 AudioFormatType::Aac => &["aac", "m4a"],
42 AudioFormatType::Opus => &["opus"],
43 AudioFormatType::Ogg => &["ogg"],
44 AudioFormatType::Aiff => &["aiff", "aif"],
45 AudioFormatType::Raw => &["raw", "pcm"],
46 AudioFormatType::Wav24 => &["wav"],
47 AudioFormatType::Wav32f => &["wav"],
48 }
49 }
50
51 pub fn mime_type(&self) -> &str {
53 match self {
54 AudioFormatType::Wav | AudioFormatType::Wav24 | AudioFormatType::Wav32f => "audio/wav",
55 AudioFormatType::Flac => "audio/flac",
56 AudioFormatType::Mp3 => "audio/mpeg",
57 AudioFormatType::Aac => "audio/aac",
58 AudioFormatType::Opus => "audio/opus",
59 AudioFormatType::Ogg => "audio/ogg",
60 AudioFormatType::Aiff => "audio/aiff",
61 AudioFormatType::Raw => "application/octet-stream",
62 }
63 }
64
65 pub fn is_lossy(&self) -> bool {
67 matches!(
68 self,
69 AudioFormatType::Mp3
70 | AudioFormatType::Aac
71 | AudioFormatType::Opus
72 | AudioFormatType::Ogg
73 )
74 }
75
76 pub fn is_lossless(&self) -> bool {
78 !self.is_lossy()
79 }
80
81 pub fn typical_bitrates(&self) -> Option<&[u32]> {
83 match self {
84 AudioFormatType::Mp3 => Some(&[128, 192, 256, 320]),
85 AudioFormatType::Aac => Some(&[128, 192, 256]),
86 AudioFormatType::Opus => Some(&[64, 96, 128, 192]),
87 AudioFormatType::Ogg => Some(&[112, 160, 192, 256]),
88 _ => None,
89 }
90 }
91}
92
93#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
95pub struct AudioFormat {
96 pub format_type: AudioFormatType,
98 pub sample_rate: u32,
100 pub channels: u16,
102 pub bits_per_sample: Option<u16>,
104 pub bit_rate: Option<u32>,
106 pub duration: Option<f64>,
108 pub metadata: HashMap<String, String>,
110}
111
112impl AudioFormat {
113 pub fn new(format_type: AudioFormatType, sample_rate: u32, channels: u16) -> Self {
115 Self {
116 format_type,
117 sample_rate,
118 channels,
119 bits_per_sample: Some(16),
120 bit_rate: None,
121 duration: None,
122 metadata: HashMap::new(),
123 }
124 }
125
126 pub fn with_bits_per_sample(mut self, bits: u16) -> Self {
128 self.bits_per_sample = Some(bits);
129 self
130 }
131
132 pub fn with_bit_rate(mut self, rate: u32) -> Self {
134 self.bit_rate = Some(rate);
135 self
136 }
137
138 pub fn with_duration(mut self, duration: f64) -> Self {
140 self.duration = Some(duration);
141 self
142 }
143
144 pub fn with_metadata(mut self, key: String, value: String) -> Self {
146 self.metadata.insert(key, value);
147 self
148 }
149
150 pub fn estimated_file_size(&self, duration_seconds: f64) -> u64 {
152 match self.format_type {
153 AudioFormatType::Wav | AudioFormatType::Aiff | AudioFormatType::Raw => {
155 let bytes_per_second = self.sample_rate as u64
156 * self.channels as u64
157 * (self.bits_per_sample.unwrap_or(16) as u64 / 8);
158 (bytes_per_second as f64 * duration_seconds) as u64
159 }
160 AudioFormatType::Wav24 => {
161 let bytes_per_second = self.sample_rate as u64 * self.channels as u64 * 3; (bytes_per_second as f64 * duration_seconds) as u64
163 }
164 AudioFormatType::Wav32f => {
165 let bytes_per_second = self.sample_rate as u64 * self.channels as u64 * 4; (bytes_per_second as f64 * duration_seconds) as u64
167 }
168 _ => {
170 let bit_rate = self.bit_rate.unwrap_or(128); ((bit_rate as f64 * 1000.0) / 8.0 * duration_seconds) as u64
172 }
173 }
174 }
175
176 pub fn supports_sample_rate(&self, sample_rate: u32) -> bool {
178 match self.format_type {
179 AudioFormatType::Opus => matches!(sample_rate, 8000 | 12000 | 16000 | 24000 | 48000),
180 AudioFormatType::Mp3 => sample_rate <= 48000,
181 _ => sample_rate <= 192000, }
183 }
184}
185
186impl Default for AudioFormat {
187 fn default() -> Self {
188 Self::new(AudioFormatType::Wav, 44100, 2) }
190}
191
192#[derive(Debug, Clone)]
194pub struct AudioData {
195 pub samples: Vec<f32>,
197 pub format: AudioFormat,
199}
200
201impl AudioData {
202 pub fn new(samples: Vec<f32>, format: AudioFormat) -> Self {
204 Self { samples, format }
205 }
206
207 pub fn duration(&self) -> f64 {
209 self.samples.len() as f64 / (self.format.sample_rate as f64 * self.format.channels as f64)
210 }
211
212 pub fn frames(&self) -> usize {
214 self.samples.len() / self.format.channels as usize
215 }
216
217 pub fn split_channels(&self) -> Vec<Vec<f32>> {
219 let channels = self.format.channels as usize;
220 let frames = self.frames();
221 let mut channel_data = vec![Vec::with_capacity(frames); channels];
222
223 for (i, &sample) in self.samples.iter().enumerate() {
224 let channel = i % channels;
225 channel_data[channel].push(sample);
226 }
227
228 channel_data
229 }
230
231 pub fn from_channels(channels: Vec<Vec<f32>>, format: AudioFormat) -> Result<Self> {
233 if channels.is_empty() {
234 return Err(Error::audio("No channels provided".to_string()));
235 }
236
237 let frames = channels[0].len();
238 let num_channels = channels.len();
239
240 for (i, channel) in channels.iter().enumerate() {
242 if channel.len() != frames {
243 return Err(Error::audio(format!(
244 "Channel {} has different length: {} vs {}",
245 i,
246 channel.len(),
247 frames
248 )));
249 }
250 }
251
252 let mut samples = Vec::with_capacity(frames * num_channels);
253 for frame in 0..frames {
254 for channel in &channels {
255 samples.push(channel[frame]);
256 }
257 }
258
259 Ok(AudioData::new(samples, format))
260 }
261
262 pub fn to_mono(&self) -> AudioData {
264 if self.format.channels == 1 {
265 return self.clone();
266 }
267
268 let channels = self.format.channels as usize;
269 let frames = self.frames();
270 let mut mono_samples = Vec::with_capacity(frames);
271
272 for frame in 0..frames {
273 let mut sum = 0.0;
274 for channel in 0..channels {
275 sum += self.samples[frame * channels + channel];
276 }
277 mono_samples.push(sum / channels as f32);
278 }
279
280 let mut mono_format = self.format.clone();
281 mono_format.channels = 1;
282
283 AudioData::new(mono_samples, mono_format)
284 }
285
286 pub fn resample(&self, target_sample_rate: u32) -> AudioData {
288 if self.format.sample_rate == target_sample_rate {
289 return self.clone();
290 }
291
292 let ratio = target_sample_rate as f64 / self.format.sample_rate as f64;
293 let channels = self.format.channels as usize;
294 let input_frames = self.frames();
295 let output_frames = (input_frames as f64 * ratio).round() as usize;
296 let mut output_samples = vec![0.0f32; output_frames * channels];
297
298 for output_frame in 0..output_frames {
299 let input_position = output_frame as f64 / ratio;
300 let input_frame = input_position.floor() as usize;
301 let fraction = input_position - input_frame as f64;
302
303 if input_frame + 1 < input_frames {
304 for channel in 0..channels {
306 let sample1 = self.samples[input_frame * channels + channel];
307 let sample2 = self.samples[(input_frame + 1) * channels + channel];
308 let interpolated = sample1 + (sample2 - sample1) * fraction as f32;
309 output_samples[output_frame * channels + channel] = interpolated;
310 }
311 } else if input_frame < input_frames {
312 for channel in 0..channels {
314 output_samples[output_frame * channels + channel] =
315 self.samples[input_frame * channels + channel];
316 }
317 }
318 }
319
320 let mut new_format = self.format.clone();
321 new_format.sample_rate = target_sample_rate;
322
323 AudioData::new(output_samples, new_format)
324 }
325}
326
327pub struct FormatDetector;
329
330impl FormatDetector {
331 pub fn detect_from_extension<P: AsRef<Path>>(path: P) -> Option<AudioFormatType> {
333 let extension = path.as_ref().extension()?.to_str()?.to_lowercase();
334
335 match extension.as_str() {
336 "wav" => Some(AudioFormatType::Wav),
337 "flac" => Some(AudioFormatType::Flac),
338 "mp3" => Some(AudioFormatType::Mp3),
339 "aac" | "m4a" => Some(AudioFormatType::Aac),
340 "opus" => Some(AudioFormatType::Opus),
341 "ogg" => Some(AudioFormatType::Ogg),
342 "aiff" | "aif" => Some(AudioFormatType::Aiff),
343 "raw" | "pcm" => Some(AudioFormatType::Raw),
344 _ => None,
345 }
346 }
347
348 pub fn detect_from_header(data: &[u8]) -> Option<AudioFormatType> {
350 if data.len() < 12 {
351 return None;
352 }
353
354 if &data[0..4] == b"RIFF" && &data[8..12] == b"WAVE" {
356 return Some(AudioFormatType::Wav);
357 }
358
359 if &data[0..4] == b"fLaC" {
361 return Some(AudioFormatType::Flac);
362 }
363
364 if &data[0..3] == b"ID3" {
366 return Some(AudioFormatType::Mp3);
367 }
368 if data.len() >= 2 && data[0] == 0xFF && (data[1] & 0xE0) == 0xE0 {
369 return Some(AudioFormatType::Mp3);
370 }
371
372 if &data[0..4] == b"OggS" {
374 return Some(AudioFormatType::Ogg);
375 }
376
377 if data.len() >= 12 && &data[0..4] == b"FORM" && &data[8..12] == b"AIFF" {
379 return Some(AudioFormatType::Aiff);
380 }
381
382 None
383 }
384
385 pub fn detect_from_mime_type(mime_type: &str) -> Option<AudioFormatType> {
387 match mime_type {
388 "audio/wav" | "audio/wave" | "audio/x-wav" => Some(AudioFormatType::Wav),
389 "audio/flac" => Some(AudioFormatType::Flac),
390 "audio/mpeg" | "audio/mp3" => Some(AudioFormatType::Mp3),
391 "audio/aac" | "audio/mp4" => Some(AudioFormatType::Aac),
392 "audio/opus" => Some(AudioFormatType::Opus),
393 "audio/ogg" => Some(AudioFormatType::Ogg),
394 "audio/aiff" | "audio/x-aiff" => Some(AudioFormatType::Aiff),
395 _ => None,
396 }
397 }
398}
399
400pub struct FormatConverter;
402
403impl FormatConverter {
404 pub fn convert(audio: &AudioData, target_format: &AudioFormat) -> Result<AudioData> {
406 let mut result = audio.clone();
407
408 if audio.format.sample_rate != target_format.sample_rate {
410 result = result.resample(target_format.sample_rate);
411 }
412
413 if audio.format.channels != target_format.channels {
415 if target_format.channels == 1 && audio.format.channels > 1 {
416 result = result.to_mono();
418 } else if target_format.channels > 1 && audio.format.channels == 1 {
419 let channels_needed = target_format.channels as usize;
421 let frames = result.frames();
422 let mut multi_channel_samples = Vec::with_capacity(frames * channels_needed);
423
424 for frame in 0..frames {
425 let mono_sample = result.samples[frame];
426 for _ in 0..channels_needed {
427 multi_channel_samples.push(mono_sample);
428 }
429 }
430
431 result.samples = multi_channel_samples;
432 result.format.channels = target_format.channels;
433 }
434 else {
436 result.samples = Self::convert_complex_channels(
437 &result.samples,
438 audio.format.channels,
439 target_format.channels,
440 result.frames(),
441 )?;
442 result.format.channels = target_format.channels;
443 }
444 }
445
446 result.format.format_type = target_format.format_type;
448 result.format.bits_per_sample = target_format.bits_per_sample;
449 result.format.bit_rate = target_format.bit_rate;
450
451 Ok(result)
452 }
453
454 pub fn get_optimal_format(
456 source_format: &AudioFormat,
457 target_type: AudioFormatType,
458 quality_preference: FormatQuality,
459 ) -> AudioFormat {
460 let sample_rate = match quality_preference {
461 FormatQuality::Low => 22050,
462 FormatQuality::Medium => 44100,
463 FormatQuality::High => source_format.sample_rate.max(44100),
464 FormatQuality::Highest => source_format.sample_rate.max(48000),
465 };
466
467 let channels = source_format.channels;
468
469 let mut format = AudioFormat::new(target_type, sample_rate, channels);
470
471 match target_type {
473 AudioFormatType::Wav => {
474 format = format.with_bits_per_sample(match quality_preference {
475 FormatQuality::Low => 16,
476 FormatQuality::Medium => 16,
477 FormatQuality::High => 24,
478 FormatQuality::Highest => 24,
479 });
480 }
481 AudioFormatType::Wav24 => {
482 format = format.with_bits_per_sample(24);
483 }
484 AudioFormatType::Wav32f => {
485 format = format.with_bits_per_sample(32);
486 }
487 AudioFormatType::Mp3 => {
488 format = format.with_bit_rate(match quality_preference {
489 FormatQuality::Low => 128,
490 FormatQuality::Medium => 192,
491 FormatQuality::High => 256,
492 FormatQuality::Highest => 320,
493 });
494 }
495 AudioFormatType::Aac => {
496 format = format.with_bit_rate(match quality_preference {
497 FormatQuality::Low => 96,
498 FormatQuality::Medium => 128,
499 FormatQuality::High => 192,
500 FormatQuality::Highest => 256,
501 });
502 }
503 AudioFormatType::Opus => {
504 format = format.with_bit_rate(match quality_preference {
505 FormatQuality::Low => 64,
506 FormatQuality::Medium => 96,
507 FormatQuality::High => 128,
508 FormatQuality::Highest => 192,
509 });
510 }
511 _ => {} }
513
514 format
515 }
516
517 fn convert_complex_channels(
519 samples: &[f32],
520 source_channels: u16,
521 target_channels: u16,
522 frames: usize,
523 ) -> Result<Vec<f32>> {
524 let source_ch = source_channels as usize;
525 let target_ch = target_channels as usize;
526
527 match (source_ch, target_ch) {
533 (6, 2) => {
535 let mut result = Vec::with_capacity(frames * 2);
536 for frame in 0..frames {
537 let base_idx = frame * 6;
538 let fl = samples[base_idx]; let fr = samples[base_idx + 1]; let center = samples[base_idx + 2]; let _lfe = samples[base_idx + 3]; let rl = samples[base_idx + 4]; let rr = samples[base_idx + 5]; let left = fl + (center * 0.707) + (rl * 0.707);
547 let right = fr + (center * 0.707) + (rr * 0.707);
548
549 result.push(left);
550 result.push(right);
551 }
552 Ok(result)
553 }
554
555 (8, 2) => {
557 let mut result = Vec::with_capacity(frames * 2);
558 for frame in 0..frames {
559 let base_idx = frame * 8;
560 let fl = samples[base_idx]; let fr = samples[base_idx + 1]; let center = samples[base_idx + 2]; let _lfe = samples[base_idx + 3]; let sl = samples[base_idx + 4]; let sr = samples[base_idx + 5]; let rl = samples[base_idx + 6]; let rr = samples[base_idx + 7]; let left = fl + (center * 0.707) + (sl * 0.5) + (rl * 0.5);
571 let right = fr + (center * 0.707) + (sr * 0.5) + (rr * 0.5);
572
573 result.push(left);
574 result.push(right);
575 }
576 Ok(result)
577 }
578
579 (8, 6) => {
581 let mut result = Vec::with_capacity(frames * 6);
582 for frame in 0..frames {
583 let base_idx = frame * 8;
584 let fl = samples[base_idx]; let fr = samples[base_idx + 1]; let center = samples[base_idx + 2]; let lfe = samples[base_idx + 3]; let sl = samples[base_idx + 4]; let sr = samples[base_idx + 5]; let rl = samples[base_idx + 6]; let rr = samples[base_idx + 7]; let mixed_rl = (sl + rl) * 0.707; let mixed_rr = (sr + rr) * 0.707; result.push(fl);
598 result.push(fr);
599 result.push(center);
600 result.push(lfe);
601 result.push(mixed_rl);
602 result.push(mixed_rr);
603 }
604 Ok(result)
605 }
606
607 (2, 6) => {
609 let mut result = Vec::with_capacity(frames * 6);
610 for frame in 0..frames {
611 let base_idx = frame * 2;
612 let left = samples[base_idx];
613 let right = samples[base_idx + 1];
614
615 result.push(left); result.push(right); result.push((left + right) * 0.5); result.push(0.0); result.push(left * 0.5); result.push(right * 0.5); }
623 Ok(result)
624 }
625
626 _ => {
628 let mut result = Vec::with_capacity(frames * target_ch);
629 for frame in 0..frames {
630 for target_ch_idx in 0..target_ch {
631 let source_ch_idx = if source_ch > target_ch {
632 (target_ch_idx * source_ch) / target_ch
634 } else {
635 target_ch_idx % source_ch
637 };
638
639 let sample_idx = frame * source_ch + source_ch_idx;
640 let sample = if sample_idx < samples.len() {
641 samples[sample_idx]
642 } else {
643 0.0 };
645 result.push(sample);
646 }
647 }
648 Ok(result)
649 }
650 }
651 }
652}
653
654#[derive(Debug, Clone, Copy, PartialEq, Eq)]
656pub enum FormatQuality {
657 Low,
659 Medium,
661 High,
663 Highest,
665}
666
667pub struct AudioReader;
669
670impl AudioReader {
671 pub fn read_file<P: AsRef<Path>>(path: P) -> Result<AudioData> {
673 let format_type = FormatDetector::detect_from_extension(&path)
680 .ok_or_else(|| Error::audio("Unsupported file format".to_string()))?;
681
682 match format_type {
683 AudioFormatType::Wav | AudioFormatType::Wav24 | AudioFormatType::Wav32f => {
684 Self::read_wav_placeholder(path)
685 }
686 _ => Err(Error::audio(format!(
687 "Format {format_type:?} not yet implemented - requires additional dependencies"
688 ))),
689 }
690 }
691
692 fn read_wav_placeholder<P: AsRef<Path>>(path: P) -> Result<AudioData> {
694 let format = AudioFormat::new(AudioFormatType::Wav, 44100, 2);
696 let samples = vec![0.0f32; 44100]; Ok(AudioData::new(samples, format))
698 }
699
700 pub fn read_buffer(buffer: &[u8]) -> Result<AudioData> {
702 let format_type = FormatDetector::detect_from_header(buffer)
703 .ok_or_else(|| Error::audio("Unknown audio format in buffer".to_string()))?;
704
705 match format_type {
706 AudioFormatType::Wav => Self::read_wav_buffer(buffer),
707 _ => Err(Error::audio(format!(
708 "Buffer format {format_type:?} not yet implemented"
709 ))),
710 }
711 }
712
713 fn read_wav_buffer(buffer: &[u8]) -> Result<AudioData> {
714 let format = AudioFormat::new(AudioFormatType::Wav, 44100, 2);
716 let samples = vec![0.0f32; 1024]; Ok(AudioData::new(samples, format))
718 }
719}
720
721pub struct AudioWriter;
723
724impl AudioWriter {
725 pub fn write_file<P: AsRef<Path>>(
727 audio: &AudioData,
728 path: P,
729 target_format: Option<AudioFormatType>,
730 ) -> Result<()> {
731 let format_type = target_format
732 .or_else(|| FormatDetector::detect_from_extension(&path))
733 .unwrap_or(AudioFormatType::Wav);
734
735 match format_type {
736 AudioFormatType::Wav | AudioFormatType::Wav24 | AudioFormatType::Wav32f => {
737 Self::write_wav_placeholder(audio, path)
738 }
739 _ => Err(Error::audio(format!(
740 "Writing format {format_type:?} not yet implemented - requires additional dependencies"
741 ))),
742 }
743 }
744
745 fn write_wav_placeholder<P: AsRef<Path>>(audio: &AudioData, path: P) -> Result<()> {
746 Ok(())
748 }
749
750 pub fn write_buffer(audio: &AudioData, format_type: AudioFormatType) -> Result<Vec<u8>> {
752 match format_type {
753 AudioFormatType::Wav => Self::write_wav_buffer(audio),
754 _ => Err(Error::audio(format!(
755 "Buffer format {format_type:?} not yet implemented"
756 ))),
757 }
758 }
759
760 fn write_wav_buffer(audio: &AudioData) -> Result<Vec<u8>> {
761 Ok(vec![])
763 }
764}
765
766#[cfg(test)]
767mod tests {
768 use super::*;
769
770 #[test]
771 fn test_audio_format_type_properties() {
772 assert_eq!(AudioFormatType::Wav.extensions(), &["wav"]);
773 assert_eq!(AudioFormatType::Mp3.mime_type(), "audio/mpeg");
774 assert!(AudioFormatType::Mp3.is_lossy());
775 assert!(AudioFormatType::Wav.is_lossless());
776 assert!(AudioFormatType::Mp3.typical_bitrates().is_some());
777 assert!(AudioFormatType::Wav.typical_bitrates().is_none());
778 }
779
780 #[test]
781 fn test_audio_format_creation() {
782 let format = AudioFormat::new(AudioFormatType::Wav, 44100, 2)
783 .with_bits_per_sample(24)
784 .with_metadata("title".to_string(), "Test Audio".to_string());
785
786 assert_eq!(format.format_type, AudioFormatType::Wav);
787 assert_eq!(format.sample_rate, 44100);
788 assert_eq!(format.channels, 2);
789 assert_eq!(format.bits_per_sample, Some(24));
790 assert_eq!(
791 format.metadata.get("title"),
792 Some(&"Test Audio".to_string())
793 );
794 }
795
796 #[test]
797 fn test_file_size_estimation() {
798 let format = AudioFormat::new(AudioFormatType::Wav, 44100, 2).with_bits_per_sample(16);
799
800 let size = format.estimated_file_size(1.0);
802 assert_eq!(size, 176400);
803
804 let mp3_format = AudioFormat::new(AudioFormatType::Mp3, 44100, 2).with_bit_rate(128);
805
806 let mp3_size = mp3_format.estimated_file_size(1.0);
808 assert_eq!(mp3_size, 16000);
809 }
810
811 #[test]
812 fn test_sample_rate_support() {
813 let opus_format = AudioFormat::new(AudioFormatType::Opus, 48000, 2);
814 assert!(opus_format.supports_sample_rate(48000));
815 assert!(!opus_format.supports_sample_rate(44100));
816
817 let wav_format = AudioFormat::new(AudioFormatType::Wav, 44100, 2);
818 assert!(wav_format.supports_sample_rate(44100));
819 assert!(wav_format.supports_sample_rate(96000));
820 }
821
822 #[test]
823 fn test_audio_data_operations() {
824 let samples = vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6]; let format = AudioFormat::new(AudioFormatType::Wav, 44100, 2);
827 let audio = AudioData::new(samples, format);
828
829 assert_eq!(audio.frames(), 3);
830 assert_eq!(audio.duration(), 3.0 / 44100.0);
831
832 let channels = audio.split_channels();
834 assert_eq!(channels.len(), 2);
835 assert_eq!(channels[0], vec![0.1, 0.3, 0.5]);
836 assert_eq!(channels[1], vec![0.2, 0.4, 0.6]);
837
838 let mono = audio.to_mono();
840 assert_eq!(mono.format.channels, 1);
841 let expected = vec![0.15, 0.35, 0.55];
843 for (i, (&actual, &expected)) in mono.samples.iter().zip(expected.iter()).enumerate() {
844 assert!(
845 (actual - expected).abs() < 1e-6,
846 "Sample {} mismatch: {} vs {}",
847 i,
848 actual,
849 expected
850 );
851 }
852 }
853
854 #[test]
855 fn test_format_detection() {
856 assert_eq!(
857 FormatDetector::detect_from_extension("test.wav"),
858 Some(AudioFormatType::Wav)
859 );
860 assert_eq!(
861 FormatDetector::detect_from_extension("test.mp3"),
862 Some(AudioFormatType::Mp3)
863 );
864 assert_eq!(FormatDetector::detect_from_extension("test.unknown"), None);
865
866 let wav_header = b"RIFF\x00\x00\x00\x00WAVE";
868 assert_eq!(
869 FormatDetector::detect_from_header(wav_header),
870 Some(AudioFormatType::Wav)
871 );
872
873 let flac_header = b"fLaC\x00\x00\x00\x22\x10\x00\x10\x00";
874 assert_eq!(
875 FormatDetector::detect_from_header(flac_header),
876 Some(AudioFormatType::Flac)
877 );
878 }
879
880 #[test]
881 fn test_format_converter() {
882 let source_format = AudioFormat::new(AudioFormatType::Wav, 22050, 1);
883 let target_format = AudioFormat::new(AudioFormatType::Mp3, 44100, 2);
884
885 let optimal = FormatConverter::get_optimal_format(
886 &source_format,
887 AudioFormatType::Mp3,
888 FormatQuality::High,
889 );
890
891 assert_eq!(optimal.format_type, AudioFormatType::Mp3);
892 assert_eq!(optimal.sample_rate, 44100);
893 assert_eq!(optimal.channels, 1); assert_eq!(optimal.bit_rate, Some(256)); }
896
897 #[test]
898 fn test_audio_resampling() {
899 let samples: Vec<f32> = (0..22050).map(|i| (i as f32 * 0.01).sin()).collect();
901 let format = AudioFormat::new(AudioFormatType::Wav, 22050, 1);
902 let audio = AudioData::new(samples, format);
903
904 let resampled = audio.resample(44100);
906 assert_eq!(resampled.format.sample_rate, 44100);
907 assert_eq!(resampled.samples.len(), 44100); }
909
910 #[test]
911 fn test_channel_conversion() {
912 let mono_samples = vec![0.1, 0.2, 0.3];
914 let mono_format = AudioFormat::new(AudioFormatType::Wav, 44100, 1);
915 let mono_audio = AudioData::new(mono_samples, mono_format);
916
917 let stereo_format = AudioFormat::new(AudioFormatType::Wav, 44100, 2);
918 let stereo_audio = FormatConverter::convert(&mono_audio, &stereo_format).unwrap();
919
920 assert_eq!(stereo_audio.format.channels, 2);
921 assert_eq!(stereo_audio.samples.len(), 6); assert_eq!(stereo_audio.samples, vec![0.1, 0.1, 0.2, 0.2, 0.3, 0.3]);
923 }
924}