-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunused_compression.rs
118 lines (99 loc) · 3.87 KB
/
unused_compression.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use sirena::memory_manager::MemoryManager;
#[allow(unused_imports)]
use micromath::F32Ext as _;
use crate::math;
use crate::ring_buffer::RingBuffer;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Compressor {
original_peaks: RingBuffer,
processed_peaks: RingBuffer,
}
impl Compressor {
pub fn new(sample_rate: u32, memory_manager: &mut MemoryManager) -> Self {
// The average should capture at least one wave cycle, considering 20 Hz
// as the lowest frequency.
let buffer_len = math::upper_power_of_two(sample_rate as usize / 20);
Self {
original_peaks: RingBuffer::from(memory_manager.allocate(buffer_len).unwrap()),
processed_peaks: RingBuffer::from(memory_manager.allocate(buffer_len).unwrap()),
}
}
pub fn prepare(&mut self, buffer: &[f32]) {
feed_buffer_with_abs(buffer, &mut self.original_peaks);
}
pub fn process(&mut self, buffer: &mut [f32]) {
feed_buffer_with_abs(buffer, &mut self.processed_peaks);
let original_peak = self.original_peak();
let processed_peak = self.processed_peak();
let ratio = original_peak / processed_peak;
for x in buffer.iter_mut() {
*x *= ratio;
}
}
fn original_peak(&self) -> f32 {
find_max(self.original_peaks.buffer())
}
fn processed_peak(&self) -> f32 {
find_max(self.processed_peaks.buffer())
}
}
// TODO: Try if basic iteration makes it faster
fn find_max(buffer: &[f32]) -> f32 {
buffer.iter().map(|x| x.abs()).fold(0.0, |a, b| a.max(b))
}
// TODO: Try if custom abs works faster
fn feed_buffer_with_abs(source_buffer: &[f32], destination_buffer: &mut RingBuffer) {
for x in source_buffer {
destination_buffer.write(x.abs());
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::mem::MaybeUninit;
fn sine_block(amplitude: f32) -> [f32; 32] {
let mut buffer = [0.0; 32];
for (i, x) in buffer.iter_mut().enumerate() {
*x = libm::sinf(2.0 * core::f32::consts::PI * i as f32 / 32.0) * amplitude;
}
buffer
}
fn max(buffer: &[f32]) -> f32 {
buffer.iter().fold(0.0, |a, b| a.max(*b))
}
#[test]
fn it_initialize() {
static mut MEMORY: [MaybeUninit<u32>; 16] = unsafe { MaybeUninit::uninit().assume_init() };
let mut memory_manager = MemoryManager::from(unsafe { &mut MEMORY[..] });
let _compressor = Compressor::new(100, &mut memory_manager);
}
#[test]
fn it_can_measure_peak() {
static mut MEMORY: [MaybeUninit<u32>; 16] = unsafe { MaybeUninit::uninit().assume_init() };
let mut memory_manager = MemoryManager::from(unsafe { &mut MEMORY[..] });
let mut compressor = Compressor::new(100, &mut memory_manager);
compressor.prepare(&sine_block(1.0));
assert_relative_eq!(compressor.original_peak(), 1.0);
}
#[test]
fn it_increases_buffer_below_original() {
static mut MEMORY: [MaybeUninit<u32>; 16] = unsafe { MaybeUninit::uninit().assume_init() };
let mut memory_manager = MemoryManager::from(unsafe { &mut MEMORY[..] });
let mut compressor = Compressor::new(100, &mut memory_manager);
compressor.prepare(&sine_block(1.0));
let mut buffer = sine_block(0.5);
compressor.process(&mut buffer);
assert_relative_eq!(max(&buffer), 1.0);
}
#[test]
fn it_silences_buffer_above_original() {
static mut MEMORY: [MaybeUninit<u32>; 16] = unsafe { MaybeUninit::uninit().assume_init() };
let mut memory_manager = MemoryManager::from(unsafe { &mut MEMORY[..] });
let mut compressor = Compressor::new(100, &mut memory_manager);
compressor.prepare(&sine_block(1.0));
let mut buffer = sine_block(1.5);
compressor.process(&mut buffer);
assert_relative_eq!(max(&buffer), 1.0);
}
}