1use crate::error::{IoError, IoResult};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum CompressionMethod {
12 None,
14 RLE,
16 Delta,
18 DeltaRLE,
20 Quantize { bits: u8 },
22 DPCM { predictor_order: usize },
24}
25
26#[derive(Debug, Clone)]
28pub struct CompressedSignal {
29 pub method: CompressionMethod,
31 pub data: Vec<u8>,
33 pub original_length: usize,
35 pub metadata: CompressionMetadata,
37}
38
39#[derive(Debug, Clone)]
41pub struct CompressionMetadata {
42 pub sample_rate: Option<f32>,
44 pub min_value: f32,
46 pub max_value: f32,
48 pub first_sample: f32,
50 pub custom: HashMap<String, String>,
52}
53
54impl Default for CompressionMetadata {
55 fn default() -> Self {
56 Self {
57 sample_rate: None,
58 min_value: 0.0,
59 max_value: 0.0,
60 first_sample: 0.0,
61 custom: HashMap::new(),
62 }
63 }
64}
65
66pub struct SignalCompressor {
68 method: CompressionMethod,
69}
70
71impl SignalCompressor {
72 pub fn new(method: CompressionMethod) -> Self {
74 Self { method }
75 }
76
77 pub fn compress(&self, signal: &[f32]) -> IoResult<CompressedSignal> {
79 if signal.is_empty() {
80 return Err(IoError::InvalidConfig(
81 "Cannot compress empty signal".to_string(),
82 ));
83 }
84
85 let min_value = signal.iter().copied().fold(f32::INFINITY, f32::min);
86 let max_value = signal.iter().copied().fold(f32::NEG_INFINITY, f32::max);
87 let metadata = CompressionMetadata {
88 first_sample: signal[0],
89 min_value,
90 max_value,
91 ..Default::default()
92 };
93
94 let data = match self.method {
95 CompressionMethod::None => self.compress_none(signal)?,
96 CompressionMethod::RLE => self.compress_rle(signal)?,
97 CompressionMethod::Delta => self.compress_delta(signal)?,
98 CompressionMethod::DeltaRLE => self.compress_delta_rle(signal)?,
99 CompressionMethod::Quantize { bits } => {
100 self.compress_quantize(signal, bits, metadata.min_value, metadata.max_value)?
101 }
102 CompressionMethod::DPCM { predictor_order } => {
103 self.compress_dpcm(signal, predictor_order)?
104 }
105 };
106
107 Ok(CompressedSignal {
108 method: self.method,
109 data,
110 original_length: signal.len(),
111 metadata,
112 })
113 }
114
115 pub fn decompress(&self, compressed: &CompressedSignal) -> IoResult<Vec<f32>> {
117 match compressed.method {
118 CompressionMethod::None => {
119 self.decompress_none(&compressed.data, compressed.original_length)
120 }
121 CompressionMethod::RLE => self.decompress_rle(&compressed.data),
122 CompressionMethod::Delta => {
123 self.decompress_delta(&compressed.data, compressed.metadata.first_sample)
124 }
125 CompressionMethod::DeltaRLE => {
126 self.decompress_delta_rle(&compressed.data, compressed.metadata.first_sample)
127 }
128 CompressionMethod::Quantize { bits } => self.decompress_quantize(
129 &compressed.data,
130 bits,
131 compressed.metadata.min_value,
132 compressed.metadata.max_value,
133 compressed.original_length,
134 ),
135 CompressionMethod::DPCM { predictor_order } => self.decompress_dpcm(
136 &compressed.data,
137 predictor_order,
138 compressed.metadata.first_sample,
139 ),
140 }
141 }
142
143 pub fn compression_ratio(&self, original: &[f32], compressed: &CompressedSignal) -> f32 {
145 let original_bytes = std::mem::size_of_val(original);
146 let compressed_bytes = compressed.data.len();
147 original_bytes as f32 / compressed_bytes as f32
148 }
149
150 fn compress_none(&self, signal: &[f32]) -> IoResult<Vec<u8>> {
153 let mut data = Vec::with_capacity(std::mem::size_of_val(signal));
154 for &sample in signal {
155 data.extend_from_slice(&sample.to_le_bytes());
156 }
157 Ok(data)
158 }
159
160 fn compress_rle(&self, signal: &[f32]) -> IoResult<Vec<u8>> {
161 let mut data = Vec::new();
162 let mut i = 0;
163
164 while i < signal.len() {
165 let value = signal[i];
166 let mut count = 1u16;
167
168 while i + (count as usize) < signal.len()
170 && signal[i + (count as usize)] == value
171 && count < u16::MAX
172 {
173 count += 1;
174 }
175
176 data.extend_from_slice(&count.to_le_bytes());
178 data.extend_from_slice(&value.to_le_bytes());
179
180 i += count as usize;
181 }
182
183 Ok(data)
184 }
185
186 fn compress_delta(&self, signal: &[f32]) -> IoResult<Vec<u8>> {
187 let mut data = Vec::with_capacity(std::mem::size_of_val(signal));
188
189 for i in 1..signal.len() {
190 let delta = signal[i] - signal[i - 1];
191 data.extend_from_slice(&delta.to_le_bytes());
192 }
193
194 Ok(data)
195 }
196
197 fn compress_delta_rle(&self, signal: &[f32]) -> IoResult<Vec<u8>> {
198 let mut deltas = Vec::with_capacity(signal.len() - 1);
200 for i in 1..signal.len() {
201 deltas.push(signal[i] - signal[i - 1]);
202 }
203
204 self.compress_rle(&deltas)
206 }
207
208 fn compress_quantize(
209 &self,
210 signal: &[f32],
211 bits: u8,
212 min_val: f32,
213 max_val: f32,
214 ) -> IoResult<Vec<u8>> {
215 if bits == 0 || bits > 16 {
216 return Err(IoError::InvalidConfig(
217 "Quantization bits must be 1-16".to_string(),
218 ));
219 }
220
221 let levels = (1u32 << bits) - 1;
222 let range = max_val - min_val;
223
224 if range.abs() < 1e-10 {
225 return Ok(vec![0]);
227 }
228
229 let mut data = Vec::new();
230
231 for &sample in signal {
232 let normalized = ((sample - min_val) / range).clamp(0.0, 1.0);
233 let quantized = (normalized * levels as f32).round() as u16;
234
235 if bits <= 8 {
236 data.push(quantized as u8);
237 } else {
238 data.extend_from_slice(&quantized.to_le_bytes());
239 }
240 }
241
242 Ok(data)
243 }
244
245 fn compress_dpcm(&self, signal: &[f32], order: usize) -> IoResult<Vec<u8>> {
246 if order == 0 || order >= signal.len() {
247 return Err(IoError::InvalidConfig(
248 "Invalid predictor order".to_string(),
249 ));
250 }
251
252 let mut data = Vec::new();
253
254 for &sample in signal.iter().take(order) {
256 data.extend_from_slice(&sample.to_le_bytes());
257 }
258
259 for i in order..signal.len() {
261 let predicted = self.linear_predict(&signal[i - order..i]);
262 let residual = signal[i] - predicted;
263 data.extend_from_slice(&residual.to_le_bytes());
264 }
265
266 Ok(data)
267 }
268
269 fn linear_predict(&self, history: &[f32]) -> f32 {
270 if history.is_empty() {
272 return 0.0;
273 }
274 history.iter().sum::<f32>() / history.len() as f32
275 }
276
277 fn decompress_none(&self, data: &[u8], length: usize) -> IoResult<Vec<f32>> {
280 let mut signal = Vec::with_capacity(length);
281
282 for chunk in data.chunks_exact(4) {
283 let bytes: [u8; 4] = chunk
284 .try_into()
285 .map_err(|_| IoError::ParseError("Invalid float data".to_string()))?;
286 signal.push(f32::from_le_bytes(bytes));
287 }
288
289 Ok(signal)
290 }
291
292 fn decompress_rle(&self, data: &[u8]) -> IoResult<Vec<f32>> {
293 let mut signal = Vec::new();
294 let mut i = 0;
295
296 while i + 6 <= data.len() {
297 let count_bytes: [u8; 2] = data[i..i + 2]
298 .try_into()
299 .expect("RLE decode: slice must be exactly 2 bytes");
300 let count = u16::from_le_bytes(count_bytes);
301
302 let value_bytes: [u8; 4] = data[i + 2..i + 6]
303 .try_into()
304 .expect("RLE decode: slice must be exactly 4 bytes");
305 let value = f32::from_le_bytes(value_bytes);
306
307 for _ in 0..count {
308 signal.push(value);
309 }
310
311 i += 6;
312 }
313
314 Ok(signal)
315 }
316
317 fn decompress_delta(&self, data: &[u8], first_sample: f32) -> IoResult<Vec<f32>> {
318 let mut signal = vec![first_sample];
319
320 for chunk in data.chunks_exact(4) {
321 let bytes: [u8; 4] = chunk
322 .try_into()
323 .map_err(|_| IoError::ParseError("Invalid delta data".to_string()))?;
324 let delta = f32::from_le_bytes(bytes);
325 let next = signal
326 .last()
327 .expect("Delta decode: signal must be non-empty")
328 + delta;
329 signal.push(next);
330 }
331
332 Ok(signal)
333 }
334
335 fn decompress_delta_rle(&self, data: &[u8], first_sample: f32) -> IoResult<Vec<f32>> {
336 let deltas = self.decompress_rle(data)?;
337 let mut signal = vec![first_sample];
338
339 for delta in deltas {
340 let next = signal
341 .last()
342 .expect("Delta decode: signal must be non-empty")
343 + delta;
344 signal.push(next);
345 }
346
347 Ok(signal)
348 }
349
350 fn decompress_quantize(
351 &self,
352 data: &[u8],
353 bits: u8,
354 min_val: f32,
355 max_val: f32,
356 length: usize,
357 ) -> IoResult<Vec<f32>> {
358 let levels = (1u32 << bits) - 1;
359 let range = max_val - min_val;
360 let mut signal = Vec::with_capacity(length);
361
362 if bits <= 8 {
363 for &byte in data {
364 let normalized = byte as f32 / levels as f32;
365 let value = min_val + normalized * range;
366 signal.push(value);
367 }
368 } else {
369 for chunk in data.chunks_exact(2) {
370 let bytes: [u8; 2] = chunk
371 .try_into()
372 .expect("Quantization decode: chunk must be 2 bytes");
373 let quantized = u16::from_le_bytes(bytes);
374 let normalized = quantized as f32 / levels as f32;
375 let value = min_val + normalized * range;
376 signal.push(value);
377 }
378 }
379
380 Ok(signal)
381 }
382
383 fn decompress_dpcm(&self, data: &[u8], order: usize, first_sample: f32) -> IoResult<Vec<f32>> {
384 let mut signal = Vec::new();
385
386 let init_bytes = order * 4;
388 for chunk in data[..init_bytes.min(data.len())].chunks_exact(4) {
389 let bytes: [u8; 4] = chunk
390 .try_into()
391 .expect("DPCM decode: chunk must be 4 bytes");
392 signal.push(f32::from_le_bytes(bytes));
393 }
394
395 if signal.is_empty() {
396 signal.push(first_sample);
397 }
398
399 for chunk in data[init_bytes..].chunks_exact(4) {
401 let bytes: [u8; 4] = chunk
402 .try_into()
403 .expect("DPCM decode: chunk must be 4 bytes");
404 let residual = f32::from_le_bytes(bytes);
405 let predicted = self.linear_predict(&signal[signal.len().saturating_sub(order)..]);
406 signal.push(predicted + residual);
407 }
408
409 Ok(signal)
410 }
411}
412
413pub struct AdaptiveCompressor {
415 methods: Vec<CompressionMethod>,
416}
417
418impl AdaptiveCompressor {
419 pub fn new() -> Self {
421 Self {
422 methods: vec![
423 CompressionMethod::Delta,
424 CompressionMethod::DeltaRLE,
425 CompressionMethod::Quantize { bits: 8 },
426 CompressionMethod::DPCM { predictor_order: 4 },
427 ],
428 }
429 }
430
431 pub fn compress(&self, signal: &[f32]) -> IoResult<CompressedSignal> {
433 let mut best_compressed: Option<CompressedSignal> = None;
434 let mut best_size = usize::MAX;
435
436 for &method in &self.methods {
437 let compressor = SignalCompressor::new(method);
438 if let Ok(compressed) = compressor.compress(signal) {
439 if compressed.data.len() < best_size {
440 best_size = compressed.data.len();
441 best_compressed = Some(compressed);
442 }
443 }
444 }
445
446 best_compressed
447 .ok_or_else(|| IoError::SignalError("All compression methods failed".to_string()))
448 }
449
450 pub fn decompress(&self, compressed: &CompressedSignal) -> IoResult<Vec<f32>> {
452 let compressor = SignalCompressor::new(compressed.method);
453 compressor.decompress(compressed)
454 }
455}
456
457impl Default for AdaptiveCompressor {
458 fn default() -> Self {
459 Self::new()
460 }
461}
462
463#[cfg(test)]
464mod tests {
465 use super::*;
466
467 #[test]
468 fn test_compress_none() {
469 let signal = vec![1.0, 2.0, 3.0, 4.0, 5.0];
470 let compressor = SignalCompressor::new(CompressionMethod::None);
471
472 let compressed = compressor.compress(&signal).unwrap();
473 let decompressed = compressor.decompress(&compressed).unwrap();
474
475 assert_eq!(signal, decompressed);
476 }
477
478 #[test]
479 fn test_compress_delta() {
480 let signal = vec![1.0, 2.0, 3.0, 4.0, 5.0];
481 let compressor = SignalCompressor::new(CompressionMethod::Delta);
482
483 let compressed = compressor.compress(&signal).unwrap();
484 let decompressed = compressor.decompress(&compressed).unwrap();
485
486 for (a, b) in signal.iter().zip(decompressed.iter()) {
487 assert!((a - b).abs() < 1e-6);
488 }
489 }
490
491 #[test]
492 fn test_compress_rle() {
493 let signal = vec![1.0, 1.0, 1.0, 2.0, 2.0, 3.0];
494 let compressor = SignalCompressor::new(CompressionMethod::RLE);
495
496 let compressed = compressor.compress(&signal).unwrap();
497 let decompressed = compressor.decompress(&compressed).unwrap();
498
499 assert_eq!(signal, decompressed);
500
501 let raw_size = signal.len() * 4;
503 assert!(compressed.data.len() < raw_size);
504 }
505
506 #[test]
507 fn test_compress_quantize() {
508 let signal = vec![0.0, 0.25, 0.5, 0.75, 1.0];
509 let compressor = SignalCompressor::new(CompressionMethod::Quantize { bits: 8 });
510
511 let compressed = compressor.compress(&signal).unwrap();
512 let decompressed = compressor.decompress(&compressed).unwrap();
513
514 for (a, b) in signal.iter().zip(decompressed.iter()) {
516 assert!((a - b).abs() < 0.01);
517 }
518 }
519
520 #[test]
521 fn test_adaptive_compressor() {
522 let signal = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
523 let compressor = AdaptiveCompressor::new();
524
525 let compressed = compressor.compress(&signal).unwrap();
526 let decompressed = compressor.decompress(&compressed).unwrap();
527
528 assert_eq!(signal.len(), decompressed.len());
529 }
530
531 #[test]
532 fn test_compression_ratio() {
533 let signal = vec![1.0; 100]; let compressor = SignalCompressor::new(CompressionMethod::RLE);
535
536 let compressed = compressor.compress(&signal).unwrap();
537 let ratio = compressor.compression_ratio(&signal, &compressed);
538
539 assert!(ratio > 10.0); }
541}