1use crate::Error;
37use serde::{Deserialize, Serialize};
38use std::collections::HashMap;
39
40#[derive(Debug, Clone)]
42pub struct CompressionConfig {
43 pub target: CompressionTarget,
45 pub quality_factor: f32,
47 pub adaptive_mode: bool,
49 pub masking_threshold: f32,
51 pub max_latency_ms: f32,
53 pub min_compression_ratio: f32,
55 pub perceptual_weighting: bool,
57 pub frame_size: usize,
59 pub overlap_factor: f32,
61 pub multi_scale: bool,
63 pub vad_threshold: f32,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum CompressionTarget {
70 RealTimeStreaming,
72 Balanced,
74 MaxCompression,
76 Archival,
78 VoiceOptimized,
80}
81
82impl Default for CompressionConfig {
83 fn default() -> Self {
84 Self {
85 target: CompressionTarget::RealTimeStreaming,
86 quality_factor: 0.75,
87 adaptive_mode: true,
88 masking_threshold: 0.1,
89 max_latency_ms: 10.0,
90 min_compression_ratio: 2.0,
91 perceptual_weighting: true,
92 frame_size: 512,
93 overlap_factor: 0.5,
94 multi_scale: false,
95 vad_threshold: 0.01,
96 }
97 }
98}
99
100impl CompressionConfig {
101 pub fn with_target(mut self, target: CompressionTarget) -> Self {
103 self.target = target;
104 self
105 }
106
107 pub fn with_quality_factor(mut self, quality: f32) -> Self {
109 self.quality_factor = quality.clamp(0.0, 1.0);
110 self
111 }
112
113 pub fn with_adaptive_mode(mut self, enable: bool) -> Self {
115 self.adaptive_mode = enable;
116 self
117 }
118
119 pub fn with_max_latency(mut self, latency_ms: f32) -> Self {
121 self.max_latency_ms = latency_ms.max(1.0);
122 self
123 }
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct CompressedAudio {
129 pub data: Vec<u8>,
131 pub original_samples: usize,
133 pub compression_ratio: f32,
135 pub quality_score: f32,
137 pub algorithm: CompressionAlgorithm,
139 pub parameters: CompressionParameters,
141 pub stats: CompressionStats,
143}
144
145#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
147pub enum CompressionAlgorithm {
148 PerceptualLPC,
150 PsychoacousticTransform,
152 AdaptiveDPCM,
154 VectorQuantization,
156 HybridPerceptual,
158 MultiResolution,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct CompressionParameters {
165 pub quantization_levels: Vec<u8>,
167 pub prediction_coefficients: Vec<f32>,
169 pub masking_thresholds: Vec<f32>,
171 pub spectral_envelope: Vec<f32>,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct CompressionStats {
178 pub compression_time_ms: f32,
180 pub decompression_time_ms: f32,
182 pub memory_usage_bytes: usize,
184 pub perceptual_distortion: f32,
186 pub spectral_distortion: f32,
188 pub complexity_score: f32,
190}
191
192pub struct CompressionResearcher {
194 config: CompressionConfig,
196 psychoacoustic_analyzer: PsychoacousticAnalyzer,
198 prediction_analyzer: PredictionAnalyzer,
200 vector_quantizer: VectorQuantizer,
202 performance_cache: HashMap<String, CompressedAudio>,
204 analysis_count: usize,
206}
207
208#[derive(Debug, Clone)]
210pub struct PsychoacousticAnalyzer {
211 critical_bands: Vec<f32>,
213 masking_curves: Vec<f32>,
215 tonality_detector: TonalityDetector,
217}
218
219#[derive(Debug, Clone)]
221pub struct PredictionAnalyzer {
222 lpc_order: usize,
224 coefficients: Vec<f32>,
226 residual_energy: f32,
228}
229
230#[derive(Debug, Clone)]
232pub struct VectorQuantizer {
233 codebook: Vec<Vec<f32>>,
235 vector_dim: usize,
237 codebook_size: usize,
239}
240
241#[derive(Debug, Clone)]
243pub struct TonalityDetector {
244 flatness_threshold: f32,
246 tonal_weights: Vec<f32>,
248}
249
250impl CompressionResearcher {
251 pub fn new(config: CompressionConfig) -> Result<Self, Error> {
253 let psychoacoustic_analyzer = PsychoacousticAnalyzer::new(&config);
254 let prediction_analyzer = PredictionAnalyzer::new(12); let vector_quantizer = VectorQuantizer::new(8, 256); Ok(Self {
258 config,
259 psychoacoustic_analyzer,
260 prediction_analyzer,
261 vector_quantizer,
262 performance_cache: HashMap::new(),
263 analysis_count: 0,
264 })
265 }
266
267 pub fn compress(&mut self, audio: &[f32], sample_rate: u32) -> Result<CompressedAudio, Error> {
269 let start_time = std::time::Instant::now();
270
271 if audio.is_empty() {
272 return Err(Error::validation("Audio cannot be empty".to_string()));
273 }
274
275 let algorithm = self.select_compression_algorithm(audio, sample_rate)?;
277
278 let compressed = match algorithm {
280 CompressionAlgorithm::PerceptualLPC => {
281 self.compress_perceptual_lpc(audio, sample_rate)?
282 }
283 CompressionAlgorithm::PsychoacousticTransform => {
284 self.compress_psychoacoustic_transform(audio, sample_rate)?
285 }
286 CompressionAlgorithm::AdaptiveDPCM => {
287 self.compress_adaptive_dpcm(audio, sample_rate)?
288 }
289 CompressionAlgorithm::VectorQuantization => {
290 self.compress_vector_quantization(audio, sample_rate)?
291 }
292 CompressionAlgorithm::HybridPerceptual => {
293 self.compress_hybrid_perceptual(audio, sample_rate)?
294 }
295 CompressionAlgorithm::MultiResolution => {
296 self.compress_multi_resolution(audio, sample_rate)?
297 }
298 };
299
300 let compression_time = start_time.elapsed().as_secs_f32() * 1000.0;
301
302 let original_size = std::mem::size_of_val(audio);
304 let compression_ratio = original_size as f32 / compressed.len() as f32;
305
306 let quality_score = self.estimate_compression_quality(audio, &compressed, sample_rate)?;
308
309 let parameters = self.extract_compression_parameters(audio, algorithm)?;
311
312 let stats = CompressionStats {
313 compression_time_ms: compression_time,
314 decompression_time_ms: 0.0, memory_usage_bytes: compressed.len() + std::mem::size_of::<CompressedAudio>(),
316 perceptual_distortion: 1.0 - quality_score,
317 spectral_distortion: self.calculate_spectral_distortion(audio, &compressed)?,
318 complexity_score: self.calculate_algorithm_complexity_score(algorithm),
319 };
320
321 self.analysis_count += 1;
322
323 Ok(CompressedAudio {
324 data: compressed,
325 original_samples: audio.len(),
326 compression_ratio,
327 quality_score,
328 algorithm,
329 parameters,
330 stats,
331 })
332 }
333
334 pub fn decompress(
336 &mut self,
337 compressed: &CompressedAudio,
338 sample_rate: u32,
339 ) -> Result<Vec<f32>, Error> {
340 let start_time = std::time::Instant::now();
341
342 let decompressed = match compressed.algorithm {
343 CompressionAlgorithm::PerceptualLPC => self.decompress_perceptual_lpc(
344 &compressed.data,
345 &compressed.parameters,
346 compressed.original_samples,
347 )?,
348 CompressionAlgorithm::PsychoacousticTransform => self
349 .decompress_psychoacoustic_transform(
350 &compressed.data,
351 &compressed.parameters,
352 compressed.original_samples,
353 )?,
354 CompressionAlgorithm::AdaptiveDPCM => self.decompress_adaptive_dpcm(
355 &compressed.data,
356 &compressed.parameters,
357 compressed.original_samples,
358 )?,
359 CompressionAlgorithm::VectorQuantization => self.decompress_vector_quantization(
360 &compressed.data,
361 &compressed.parameters,
362 compressed.original_samples,
363 )?,
364 CompressionAlgorithm::HybridPerceptual => self.decompress_hybrid_perceptual(
365 &compressed.data,
366 &compressed.parameters,
367 compressed.original_samples,
368 )?,
369 CompressionAlgorithm::MultiResolution => self.decompress_multi_resolution(
370 &compressed.data,
371 &compressed.parameters,
372 compressed.original_samples,
373 )?,
374 };
375
376 let decompression_time = start_time.elapsed().as_secs_f32() * 1000.0;
377
378 Ok(decompressed)
382 }
383
384 fn select_compression_algorithm(
386 &self,
387 audio: &[f32],
388 sample_rate: u32,
389 ) -> Result<CompressionAlgorithm, Error> {
390 match self.config.target {
391 CompressionTarget::RealTimeStreaming => {
392 if self.is_voice_content(audio)? {
394 Ok(CompressionAlgorithm::AdaptiveDPCM)
395 } else {
396 Ok(CompressionAlgorithm::PerceptualLPC)
397 }
398 }
399 CompressionTarget::Balanced => {
400 Ok(CompressionAlgorithm::HybridPerceptual)
402 }
403 CompressionTarget::MaxCompression => {
404 Ok(CompressionAlgorithm::VectorQuantization)
406 }
407 CompressionTarget::Archival => {
408 Ok(CompressionAlgorithm::PsychoacousticTransform)
410 }
411 CompressionTarget::VoiceOptimized => {
412 Ok(CompressionAlgorithm::PerceptualLPC)
414 }
415 }
416 }
417
418 fn is_voice_content(&self, audio: &[f32]) -> Result<bool, Error> {
420 if audio.is_empty() {
422 return Ok(false);
423 }
424
425 let energy = audio.iter().map(|&x| x * x).sum::<f32>() / audio.len() as f32;
427 let zero_crossing_rate = self.calculate_zero_crossing_rate(audio);
428
429 let is_voice = energy > self.config.vad_threshold
431 && zero_crossing_rate > 0.02
432 && zero_crossing_rate < 0.3;
433
434 Ok(is_voice)
435 }
436
437 fn calculate_zero_crossing_rate(&self, audio: &[f32]) -> f32 {
439 if audio.len() < 2 {
440 return 0.0;
441 }
442
443 let mut crossings = 0;
444 for i in 1..audio.len() {
445 if (audio[i] >= 0.0) != (audio[i - 1] >= 0.0) {
446 crossings += 1;
447 }
448 }
449
450 crossings as f32 / (audio.len() - 1) as f32
451 }
452
453 fn compress_perceptual_lpc(
455 &mut self,
456 audio: &[f32],
457 sample_rate: u32,
458 ) -> Result<Vec<u8>, Error> {
459 let masking_thresholds = self
461 .psychoacoustic_analyzer
462 .analyze_masking(audio, sample_rate)?;
463
464 let lpc_coeffs = self.prediction_analyzer.analyze_lpc(audio)?;
466
467 let quantized_coeffs = self.quantize_with_masking(&lpc_coeffs, &masking_thresholds)?;
469
470 let compressed = self.encode_lpc_data(&quantized_coeffs)?;
472
473 Ok(compressed)
474 }
475
476 fn compress_psychoacoustic_transform(
478 &mut self,
479 audio: &[f32],
480 sample_rate: u32,
481 ) -> Result<Vec<u8>, Error> {
482 let spectrum = self.calculate_spectrum(audio);
484
485 let masking_thresholds = self
487 .psychoacoustic_analyzer
488 .analyze_masking(audio, sample_rate)?;
489
490 let quantized_spectrum =
492 self.quantize_spectrum_with_masking(&spectrum, &masking_thresholds)?;
493
494 let compressed = self.encode_spectrum_data(&quantized_spectrum)?;
496
497 Ok(compressed)
498 }
499
500 fn compress_adaptive_dpcm(
502 &mut self,
503 audio: &[f32],
504 _sample_rate: u32,
505 ) -> Result<Vec<u8>, Error> {
506 if audio.is_empty() {
507 return Ok(Vec::new());
508 }
509
510 let mut compressed = Vec::new();
511 let mut predictor = 0.0f32;
512 let mut step_size = 0.1f32;
513
514 let first_sample_bytes = audio[0].to_le_bytes();
516 compressed.extend_from_slice(&first_sample_bytes);
517
518 for &sample in &audio[1..] {
520 let prediction_error = sample - predictor;
521
522 let quantized_error = (prediction_error / step_size).round() as i8;
524 compressed.push(quantized_error as u8);
525
526 let reconstructed_error = quantized_error as f32 * step_size;
528 predictor += reconstructed_error;
529
530 step_size *= if quantized_error.abs() > 2 { 1.1 } else { 0.95 };
532 step_size = step_size.clamp(0.01, 1.0);
533 }
534
535 Ok(compressed)
536 }
537
538 fn compress_vector_quantization(
540 &mut self,
541 audio: &[f32],
542 _sample_rate: u32,
543 ) -> Result<Vec<u8>, Error> {
544 let vector_dim = self.vector_quantizer.vector_dim;
545 let mut compressed = Vec::new();
546
547 for chunk in audio.chunks(vector_dim) {
549 let mut vector = vec![0.0; vector_dim];
550 for (i, &sample) in chunk.iter().enumerate() {
551 vector[i] = sample;
552 }
553
554 let codebook_index = self.vector_quantizer.find_closest_vector(&vector)?;
556 compressed.push(codebook_index as u8);
557 }
558
559 Ok(compressed)
560 }
561
562 fn compress_hybrid_perceptual(
564 &mut self,
565 audio: &[f32],
566 sample_rate: u32,
567 ) -> Result<Vec<u8>, Error> {
568 let voice_regions = self.detect_voice_regions(audio)?;
570 let mut compressed = Vec::new();
571
572 for (start, end, is_voice) in voice_regions {
573 let segment = &audio[start..end];
574
575 let segment_compressed = if is_voice {
576 self.compress_perceptual_lpc(segment, sample_rate)?
577 } else {
578 self.compress_psychoacoustic_transform(segment, sample_rate)?
579 };
580
581 compressed.push(if is_voice { 1 } else { 0 }); let length_bytes = (segment_compressed.len() as u32).to_le_bytes();
584 compressed.extend_from_slice(&length_bytes);
585 compressed.extend(segment_compressed);
586 }
587
588 Ok(compressed)
589 }
590
591 fn compress_multi_resolution(
593 &mut self,
594 audio: &[f32],
595 sample_rate: u32,
596 ) -> Result<Vec<u8>, Error> {
597 let mut compressed = Vec::new();
599 let mut current_signal = audio.to_vec();
600
601 for level in 0..3 {
603 let decimated = self.decimate_signal(¤t_signal, 2);
604 let detail = self.calculate_detail_coefficients(¤t_signal, &decimated)?;
605
606 let detail_compressed = self.compress_adaptive_dpcm(&detail, sample_rate >> level)?;
608
609 let length_bytes = (detail_compressed.len() as u32).to_le_bytes();
611 compressed.extend_from_slice(&length_bytes);
612 compressed.extend(detail_compressed);
613
614 current_signal = decimated;
615 }
616
617 let final_compressed = self.compress_adaptive_dpcm(¤t_signal, sample_rate >> 3)?;
619 let length_bytes = (final_compressed.len() as u32).to_le_bytes();
620 compressed.extend_from_slice(&length_bytes);
621 compressed.extend(final_compressed);
622
623 Ok(compressed)
624 }
625
626 fn decompress_perceptual_lpc(
629 &self,
630 compressed: &[u8],
631 parameters: &CompressionParameters,
632 original_samples: usize,
633 ) -> Result<Vec<f32>, Error> {
634 let coeffs = ¶meters.prediction_coefficients;
636 let mut decompressed = vec![0.0; original_samples];
637
638 for i in coeffs.len()..decompressed.len() {
640 let mut prediction = 0.0;
641 for (j, &coeff) in coeffs.iter().enumerate() {
642 if i > j {
643 prediction += coeff * decompressed[i - j - 1];
644 }
645 }
646
647 let residual_index = (i - coeffs.len()) % compressed.len();
649 let residual = (compressed[residual_index] as f32 - 128.0) / 128.0 * 0.1;
650 decompressed[i] = prediction + residual;
651 }
652
653 Ok(decompressed)
654 }
655
656 fn decompress_psychoacoustic_transform(
657 &self,
658 compressed: &[u8],
659 parameters: &CompressionParameters,
660 original_samples: usize,
661 ) -> Result<Vec<f32>, Error> {
662 let mut decompressed = vec![0.0; original_samples];
664
665 let envelope = ¶meters.spectral_envelope;
667 for (i, &env_val) in envelope.iter().enumerate() {
668 if i < decompressed.len() {
669 let compressed_index = i % compressed.len();
670 let compressed_val = (compressed[compressed_index] as f32 - 128.0) / 128.0;
671 decompressed[i] = env_val * compressed_val;
672 }
673 }
674
675 Ok(decompressed)
676 }
677
678 fn decompress_adaptive_dpcm(
679 &self,
680 compressed: &[u8],
681 _parameters: &CompressionParameters,
682 original_samples: usize,
683 ) -> Result<Vec<f32>, Error> {
684 if compressed.len() < 4 {
685 return Ok(vec![0.0; original_samples]);
686 }
687
688 let mut decompressed = Vec::with_capacity(original_samples);
689
690 let first_sample =
692 f32::from_le_bytes([compressed[0], compressed[1], compressed[2], compressed[3]]);
693 decompressed.push(first_sample);
694
695 let mut predictor = first_sample;
696 let mut step_size = 0.1f32;
697
698 for &byte in &compressed[4..] {
700 let quantized_error = byte as i8;
701 let reconstructed_error = quantized_error as f32 * step_size;
702 predictor += reconstructed_error;
703 decompressed.push(predictor);
704
705 step_size *= if quantized_error.abs() > 2 { 1.1 } else { 0.95 };
707 step_size = step_size.clamp(0.01, 1.0);
708
709 if decompressed.len() >= original_samples {
710 break;
711 }
712 }
713
714 while decompressed.len() < original_samples {
716 decompressed.push(predictor);
717 }
718
719 Ok(decompressed)
720 }
721
722 fn decompress_vector_quantization(
723 &self,
724 compressed: &[u8],
725 _parameters: &CompressionParameters,
726 original_samples: usize,
727 ) -> Result<Vec<f32>, Error> {
728 let mut decompressed = Vec::with_capacity(original_samples);
729 let vector_dim = self.vector_quantizer.vector_dim;
730
731 for &index in compressed {
732 if (index as usize) < self.vector_quantizer.codebook.len() {
733 let vector = &self.vector_quantizer.codebook[index as usize];
734 decompressed.extend_from_slice(vector);
735
736 if decompressed.len() >= original_samples {
737 break;
738 }
739 }
740 }
741
742 decompressed.truncate(original_samples);
743 Ok(decompressed)
744 }
745
746 fn decompress_hybrid_perceptual(
747 &self,
748 compressed: &[u8],
749 parameters: &CompressionParameters,
750 original_samples: usize,
751 ) -> Result<Vec<f32>, Error> {
752 let mut decompressed = Vec::with_capacity(original_samples);
753 let mut pos = 0;
754
755 while pos < compressed.len() && decompressed.len() < original_samples {
756 if pos >= compressed.len() {
757 break;
758 }
759
760 let algorithm_type = compressed[pos];
761 pos += 1;
762
763 if pos + 4 > compressed.len() {
764 break;
765 }
766
767 let segment_length = u32::from_le_bytes([
768 compressed[pos],
769 compressed[pos + 1],
770 compressed[pos + 2],
771 compressed[pos + 3],
772 ]) as usize;
773 pos += 4;
774
775 if pos + segment_length > compressed.len() {
776 break;
777 }
778
779 let segment_data = &compressed[pos..pos + segment_length];
780 pos += segment_length;
781
782 let remaining_samples = original_samples - decompressed.len();
783 let segment_decompressed = if algorithm_type == 1 {
784 self.decompress_perceptual_lpc(segment_data, parameters, remaining_samples)?
785 } else {
786 self.decompress_psychoacoustic_transform(
787 segment_data,
788 parameters,
789 remaining_samples,
790 )?
791 };
792
793 decompressed.extend(segment_decompressed);
794 }
795
796 decompressed.truncate(original_samples);
797 Ok(decompressed)
798 }
799
800 fn decompress_multi_resolution(
801 &self,
802 compressed: &[u8],
803 _parameters: &CompressionParameters,
804 original_samples: usize,
805 ) -> Result<Vec<f32>, Error> {
806 let mut pos = 0;
808 let mut detail_levels = Vec::new();
809
810 for _ in 0..3 {
812 if pos + 4 > compressed.len() {
813 break;
814 }
815
816 let length = u32::from_le_bytes([
817 compressed[pos],
818 compressed[pos + 1],
819 compressed[pos + 2],
820 compressed[pos + 3],
821 ]) as usize;
822 pos += 4;
823
824 if pos + length > compressed.len() {
825 break;
826 }
827
828 let detail_data = &compressed[pos..pos + length];
829 pos += length;
830
831 let detail = self.decompress_adaptive_dpcm(
832 detail_data,
833 &CompressionParameters::default(),
834 length,
835 )?;
836 detail_levels.push(detail);
837 }
838
839 let final_length = if pos + 4 <= compressed.len() {
841 u32::from_le_bytes([
842 compressed[pos],
843 compressed[pos + 1],
844 compressed[pos + 2],
845 compressed[pos + 3],
846 ]) as usize
847 } else {
848 0
849 };
850 pos += 4;
851
852 let final_data = if pos + final_length <= compressed.len() {
853 &compressed[pos..pos + final_length]
854 } else {
855 &[]
856 };
857
858 let mut reconstructed = if !final_data.is_empty() {
859 self.decompress_adaptive_dpcm(
860 final_data,
861 &CompressionParameters::default(),
862 original_samples / 8,
863 )?
864 } else {
865 vec![0.0; original_samples / 8]
866 };
867
868 for detail in detail_levels.iter().rev() {
870 reconstructed = self.upsample_and_add_detail(&reconstructed, detail);
871 }
872
873 reconstructed.truncate(original_samples);
874 Ok(reconstructed)
875 }
876
877 fn calculate_spectrum(&self, audio: &[f32]) -> Vec<f32> {
880 let n = audio.len();
882 let mut spectrum = vec![0.0; n / 2 + 1];
883
884 for (k, spectrum_value) in spectrum.iter_mut().enumerate() {
885 let mut real = 0.0;
886 let mut imag = 0.0;
887
888 for (i, &sample) in audio.iter().enumerate() {
889 let angle = -2.0 * std::f32::consts::PI * (k as f32) * (i as f32) / (n as f32);
890 real += sample * angle.cos();
891 imag += sample * angle.sin();
892 }
893
894 *spectrum_value = (real * real + imag * imag).sqrt();
895 }
896
897 spectrum
898 }
899
900 fn quantize_with_masking(
901 &self,
902 coeffs: &[f32],
903 masking_thresholds: &[f32],
904 ) -> Result<Vec<u8>, Error> {
905 let mut quantized = Vec::new();
906
907 for (i, &coeff) in coeffs.iter().enumerate() {
908 let threshold = masking_thresholds.get(i).copied().unwrap_or(0.01);
909 let quantization_step = threshold * self.config.quality_factor;
910
911 let quantized_val = (coeff / quantization_step).round() as i16;
912 let clamped_val = quantized_val.clamp(-128, 127) as i8;
913 quantized.push((clamped_val as u8).wrapping_add(128));
914 }
915
916 Ok(quantized)
917 }
918
919 fn quantize_spectrum_with_masking(
920 &self,
921 spectrum: &[f32],
922 masking_thresholds: &[f32],
923 ) -> Result<Vec<u8>, Error> {
924 let mut quantized = Vec::new();
925
926 for (i, &mag) in spectrum.iter().enumerate() {
927 let threshold = masking_thresholds.get(i).copied().unwrap_or(0.01);
928 let quantization_step = threshold * self.config.quality_factor;
929
930 let quantized_val = (mag / quantization_step).round() as u16;
931 let clamped_val = quantized_val.min(255) as u8;
932 quantized.push(clamped_val);
933 }
934
935 Ok(quantized)
936 }
937
938 fn encode_lpc_data(&self, quantized_coeffs: &[u8]) -> Result<Vec<u8>, Error> {
939 Ok(quantized_coeffs.to_vec())
941 }
942
943 fn encode_spectrum_data(&self, quantized_spectrum: &[u8]) -> Result<Vec<u8>, Error> {
944 Ok(quantized_spectrum.to_vec())
946 }
947
948 fn detect_voice_regions(&self, audio: &[f32]) -> Result<Vec<(usize, usize, bool)>, Error> {
949 let frame_size = 1024;
950 let mut regions = Vec::new();
951
952 for (i, chunk) in audio.chunks(frame_size).enumerate() {
953 let start = i * frame_size;
954 let end = (start + chunk.len()).min(audio.len());
955 let is_voice = self.is_voice_content(chunk)?;
956 regions.push((start, end, is_voice));
957 }
958
959 Ok(regions)
960 }
961
962 fn decimate_signal(&self, signal: &[f32], factor: usize) -> Vec<f32> {
963 signal.iter().step_by(factor).cloned().collect()
964 }
965
966 fn calculate_detail_coefficients(
967 &self,
968 original: &[f32],
969 decimated: &[f32],
970 ) -> Result<Vec<f32>, Error> {
971 let mut detail = Vec::new();
972
973 for (i, &orig_sample) in original.iter().enumerate() {
974 let decimated_idx = i / 2;
975 let interpolated = if decimated_idx < decimated.len() {
976 decimated[decimated_idx]
977 } else {
978 0.0
979 };
980
981 detail.push(orig_sample - interpolated);
982 }
983
984 Ok(detail)
985 }
986
987 fn upsample_and_add_detail(&self, low_res: &[f32], detail: &[f32]) -> Vec<f32> {
988 let mut upsampled = Vec::with_capacity(low_res.len() * 2);
989
990 for &sample in low_res {
991 upsampled.push(sample);
992 upsampled.push(sample); }
994
995 for (i, &detail_coeff) in detail.iter().enumerate() {
997 if i < upsampled.len() {
998 upsampled[i] += detail_coeff;
999 }
1000 }
1001
1002 upsampled
1003 }
1004
1005 fn estimate_compression_quality(
1006 &self,
1007 original: &[f32],
1008 compressed: &[u8],
1009 _sample_rate: u32,
1010 ) -> Result<f32, Error> {
1011 let compression_ratio = (original.len() * 4) as f32 / compressed.len() as f32;
1013
1014 let quality = 1.0 - (compression_ratio - self.config.min_compression_ratio).max(0.0) / 10.0;
1016
1017 Ok(quality.clamp(0.0, 1.0))
1018 }
1019
1020 fn calculate_spectral_distortion(
1021 &self,
1022 original: &[f32],
1023 _compressed: &[u8],
1024 ) -> Result<f32, Error> {
1025 let spectrum = self.calculate_spectrum(original);
1027 let avg_magnitude = spectrum.iter().sum::<f32>() / spectrum.len() as f32;
1028
1029 let distortion = 0.1 * (1.0 - self.config.quality_factor);
1031
1032 Ok(distortion.clamp(0.0, 1.0))
1033 }
1034
1035 fn calculate_algorithm_complexity_score(&self, algorithm: CompressionAlgorithm) -> f32 {
1036 match algorithm {
1037 CompressionAlgorithm::AdaptiveDPCM => 0.2,
1038 CompressionAlgorithm::PerceptualLPC => 0.4,
1039 CompressionAlgorithm::VectorQuantization => 0.6,
1040 CompressionAlgorithm::PsychoacousticTransform => 0.7,
1041 CompressionAlgorithm::HybridPerceptual => 0.8,
1042 CompressionAlgorithm::MultiResolution => 1.0,
1043 }
1044 }
1045
1046 fn extract_compression_parameters(
1047 &self,
1048 audio: &[f32],
1049 algorithm: CompressionAlgorithm,
1050 ) -> Result<CompressionParameters, Error> {
1051 let prediction_coefficients = if matches!(algorithm, CompressionAlgorithm::PerceptualLPC) {
1053 self.prediction_analyzer.coefficients.clone()
1054 } else {
1055 vec![1.0; 12] };
1057
1058 let spectral_envelope =
1059 if matches!(algorithm, CompressionAlgorithm::PsychoacousticTransform) {
1060 self.calculate_spectrum(audio)
1061 } else {
1062 vec![1.0; audio.len().min(256)] };
1064
1065 let masking_thresholds = vec![self.config.masking_threshold; audio.len().min(256)];
1066 let quantization_levels = vec![8; audio.len().min(256)]; Ok(CompressionParameters {
1069 quantization_levels,
1070 prediction_coefficients,
1071 masking_thresholds,
1072 spectral_envelope,
1073 })
1074 }
1075
1076 pub fn get_analysis_count(&self) -> usize {
1078 self.analysis_count
1079 }
1080
1081 pub fn clear_cache(&mut self) {
1083 self.performance_cache.clear();
1084 }
1085}
1086
1087impl PsychoacousticAnalyzer {
1090 fn new(config: &CompressionConfig) -> Self {
1091 let critical_bands = (0..24).map(|i| 600.0 * ((i as f32 / 4.0).sinh())).collect();
1093
1094 let masking_curves = vec![config.masking_threshold; 24];
1095 let tonality_detector = TonalityDetector::new();
1096
1097 Self {
1098 critical_bands,
1099 masking_curves,
1100 tonality_detector,
1101 }
1102 }
1103
1104 fn analyze_masking(&self, audio: &[f32], _sample_rate: u32) -> Result<Vec<f32>, Error> {
1105 let spectrum = self.calculate_spectrum(audio);
1106 let mut masking_thresholds = Vec::new();
1107
1108 for (i, &magnitude) in spectrum.iter().enumerate() {
1109 let base_threshold = self
1111 .masking_curves
1112 .get(i % self.masking_curves.len())
1113 .cloned()
1114 .unwrap_or(0.01);
1115 let energy_factor = (magnitude * magnitude).sqrt();
1116 let threshold = base_threshold * (1.0 + energy_factor);
1117 masking_thresholds.push(threshold);
1118 }
1119
1120 Ok(masking_thresholds)
1121 }
1122
1123 fn calculate_spectrum(&self, audio: &[f32]) -> Vec<f32> {
1124 let n = audio.len();
1126 let mut spectrum = vec![0.0; n.min(512)];
1127
1128 for (k, spec_val) in spectrum.iter_mut().enumerate() {
1129 let mut real = 0.0;
1130 let mut imag = 0.0;
1131
1132 for (i, &sample) in audio.iter().enumerate() {
1133 let angle = -2.0 * std::f32::consts::PI * (k as f32) * (i as f32) / (n as f32);
1134 real += sample * angle.cos();
1135 imag += sample * angle.sin();
1136 }
1137
1138 *spec_val = (real * real + imag * imag).sqrt();
1139 }
1140
1141 spectrum
1142 }
1143}
1144
1145impl PredictionAnalyzer {
1146 fn new(order: usize) -> Self {
1147 Self {
1148 lpc_order: order,
1149 coefficients: vec![0.0; order],
1150 residual_energy: 0.0,
1151 }
1152 }
1153
1154 fn analyze_lpc(&mut self, audio: &[f32]) -> Result<Vec<f32>, Error> {
1155 if audio.len() <= self.lpc_order {
1156 return Ok(vec![0.0; self.lpc_order]);
1157 }
1158
1159 let mut autocorr = vec![0.0; self.lpc_order + 1];
1161
1162 for lag in 0..=self.lpc_order {
1164 for i in lag..audio.len() {
1165 autocorr[lag] += audio[i] * audio[i - lag];
1166 }
1167 }
1168
1169 let mut coeffs = vec![0.0; self.lpc_order];
1171
1172 if autocorr[0] > 1e-10 {
1173 for i in 0..self.lpc_order {
1174 coeffs[i] = autocorr[i + 1] / autocorr[0];
1175 }
1176 }
1177
1178 self.coefficients = coeffs.clone();
1179 Ok(coeffs)
1180 }
1181}
1182
1183impl VectorQuantizer {
1184 fn new(vector_dim: usize, codebook_size: usize) -> Self {
1185 let mut codebook = Vec::new();
1187 for _ in 0..codebook_size {
1188 let mut vector = Vec::new();
1189 for _ in 0..vector_dim {
1190 vector.push(fastrand::f32() * 2.0 - 1.0); }
1192 codebook.push(vector);
1193 }
1194
1195 Self {
1196 codebook,
1197 vector_dim,
1198 codebook_size,
1199 }
1200 }
1201
1202 fn find_closest_vector(&self, input_vector: &[f32]) -> Result<usize, Error> {
1203 let mut min_distance = f32::INFINITY;
1204 let mut best_index = 0;
1205
1206 for (i, codebook_vector) in self.codebook.iter().enumerate() {
1207 let distance = self.euclidean_distance(input_vector, codebook_vector);
1208 if distance < min_distance {
1209 min_distance = distance;
1210 best_index = i;
1211 }
1212 }
1213
1214 Ok(best_index)
1215 }
1216
1217 fn euclidean_distance(&self, a: &[f32], b: &[f32]) -> f32 {
1218 a.iter()
1219 .zip(b.iter())
1220 .map(|(x, y)| (x - y).powi(2))
1221 .sum::<f32>()
1222 .sqrt()
1223 }
1224}
1225
1226impl TonalityDetector {
1227 fn new() -> Self {
1228 Self {
1229 flatness_threshold: 0.1,
1230 tonal_weights: vec![1.0; 24],
1231 }
1232 }
1233}
1234
1235impl Default for CompressionParameters {
1236 fn default() -> Self {
1237 Self {
1238 quantization_levels: vec![8; 256],
1239 prediction_coefficients: vec![0.0; 12],
1240 masking_thresholds: vec![0.01; 256],
1241 spectral_envelope: vec![1.0; 256],
1242 }
1243 }
1244}
1245
1246#[cfg(test)]
1247mod tests {
1248 use super::*;
1249
1250 #[test]
1251 fn test_compression_config_creation() {
1252 let config = CompressionConfig::default();
1253 assert_eq!(config.target, CompressionTarget::RealTimeStreaming);
1254 assert_eq!(config.quality_factor, 0.75);
1255 assert!(config.adaptive_mode);
1256 }
1257
1258 #[test]
1259 fn test_compression_config_builder() {
1260 let config = CompressionConfig::default()
1261 .with_target(CompressionTarget::MaxCompression)
1262 .with_quality_factor(0.9)
1263 .with_adaptive_mode(false);
1264
1265 assert_eq!(config.target, CompressionTarget::MaxCompression);
1266 assert_eq!(config.quality_factor, 0.9);
1267 assert!(!config.adaptive_mode);
1268 }
1269
1270 #[test]
1271 fn test_compression_researcher_creation() {
1272 let config = CompressionConfig::default();
1273 let researcher = CompressionResearcher::new(config);
1274 assert!(researcher.is_ok());
1275 }
1276
1277 #[test]
1278 fn test_compression_and_decompression() {
1279 let config = CompressionConfig::default();
1280 let mut researcher = CompressionResearcher::new(config).unwrap();
1281
1282 let original = vec![0.1, 0.2, 0.3, 0.2, 0.1, 0.0, -0.1, -0.2];
1283 let compressed = researcher.compress(&original, 16000).unwrap();
1284
1285 assert!(compressed.compression_ratio > 1.0);
1286 assert!(compressed.quality_score >= 0.0 && compressed.quality_score <= 1.0);
1287 assert!(!compressed.data.is_empty());
1288
1289 let decompressed = researcher.decompress(&compressed, 16000).unwrap();
1290 assert_eq!(decompressed.len(), original.len());
1291 }
1292
1293 #[test]
1294 fn test_voice_content_detection() {
1295 let config = CompressionConfig::default();
1296 let researcher = CompressionResearcher::new(config).unwrap();
1297
1298 let voice_signal = vec![0.1, -0.1, 0.2, -0.15, 0.12, -0.08];
1300 let is_voice = researcher.is_voice_content(&voice_signal).unwrap();
1301
1302 let empty_signal = vec![];
1304 let is_empty_voice = researcher.is_voice_content(&empty_signal).unwrap();
1305 assert!(!is_empty_voice);
1306 }
1307
1308 #[test]
1309 fn test_zero_crossing_rate() {
1310 let config = CompressionConfig::default();
1311 let researcher = CompressionResearcher::new(config).unwrap();
1312
1313 let alternating_signal = vec![1.0, -1.0, 1.0, -1.0, 1.0, -1.0];
1314 let zcr = researcher.calculate_zero_crossing_rate(&alternating_signal);
1315 assert!(zcr > 0.8); let constant_signal = vec![1.0, 1.0, 1.0, 1.0];
1318 let zcr_constant = researcher.calculate_zero_crossing_rate(&constant_signal);
1319 assert_eq!(zcr_constant, 0.0); }
1321
1322 #[test]
1323 fn test_adaptive_dpcm_compression() {
1324 let config = CompressionConfig::default();
1325 let mut researcher = CompressionResearcher::new(config).unwrap();
1326
1327 let audio = vec![0.1, 0.2, 0.15, 0.25, 0.3];
1328 let compressed = researcher.compress_adaptive_dpcm(&audio, 16000).unwrap();
1329
1330 assert!(!compressed.is_empty());
1331 assert!(compressed.len() >= 4); }
1333
1334 #[test]
1335 fn test_spectrum_calculation() {
1336 let config = CompressionConfig::default();
1337 let researcher = CompressionResearcher::new(config).unwrap();
1338
1339 let audio = vec![1.0, 0.0, -1.0, 0.0]; let spectrum = researcher.calculate_spectrum(&audio);
1341
1342 assert_eq!(spectrum.len(), audio.len() / 2 + 1);
1343 assert!(spectrum.iter().all(|&x| x >= 0.0)); }
1345
1346 #[test]
1347 fn test_vector_quantizer() {
1348 let vq = VectorQuantizer::new(4, 16);
1349 let test_vector = vec![0.1, 0.2, 0.3, 0.4];
1350
1351 let index = vq.find_closest_vector(&test_vector).unwrap();
1352 assert!(index < vq.codebook_size);
1353 }
1354
1355 #[test]
1356 fn test_algorithm_selection() {
1357 let config = CompressionConfig::default().with_target(CompressionTarget::VoiceOptimized);
1358 let researcher = CompressionResearcher::new(config).unwrap();
1359
1360 let voice_audio = vec![0.1, -0.1, 0.2, -0.15, 0.12];
1361 let algorithm = researcher
1362 .select_compression_algorithm(&voice_audio, 16000)
1363 .unwrap();
1364
1365 assert_eq!(algorithm, CompressionAlgorithm::PerceptualLPC);
1366 }
1367
1368 #[test]
1369 fn test_compression_statistics() {
1370 let config = CompressionConfig::default();
1371 let mut researcher = CompressionResearcher::new(config).unwrap();
1372
1373 assert_eq!(researcher.get_analysis_count(), 0);
1374
1375 let audio = vec![0.1, 0.2, 0.3];
1376 let _ = researcher.compress(&audio, 16000).unwrap();
1377
1378 assert_eq!(researcher.get_analysis_count(), 1);
1379
1380 researcher.clear_cache();
1381 assert_eq!(researcher.performance_cache.len(), 0);
1382 }
1383}