|
| 1 | +//! Example demonstrating the new LimitSettings API for audio limiting. |
| 2 | +//! |
| 3 | +//! This example shows how to use the LimitSettings struct with the builder |
| 4 | +//! to configure audio limiting parameters. |
| 5 | +
|
| 6 | +use rodio::source::{LimitSettings, SineWave, Source}; |
| 7 | +use std::time::Duration; |
| 8 | + |
| 9 | +fn main() { |
| 10 | + println!("Example 1: Default LimitSettings"); |
| 11 | + let default_limiting = LimitSettings::default(); |
| 12 | + println!(" Threshold: {} dB", default_limiting.threshold); |
| 13 | + println!(" Knee width: {} dB", default_limiting.knee_width); |
| 14 | + println!(" Attack: {:?}", default_limiting.attack); |
| 15 | + println!(" Release: {:?}", default_limiting.release); |
| 16 | + println!(); |
| 17 | + |
| 18 | + println!("Example 2: Custom LimitSettings with builder pattern"); |
| 19 | + let custom_limiting = LimitSettings::new() |
| 20 | + .with_threshold(-3.0) |
| 21 | + .with_knee_width(2.0) |
| 22 | + .with_attack(Duration::from_millis(10)) |
| 23 | + .with_release(Duration::from_millis(50)); |
| 24 | + |
| 25 | + println!(" Threshold: {} dB", custom_limiting.threshold); |
| 26 | + println!(" Knee width: {} dB", custom_limiting.knee_width); |
| 27 | + println!(" Attack: {:?}", custom_limiting.attack); |
| 28 | + println!(" Release: {:?}", custom_limiting.release); |
| 29 | + println!(); |
| 30 | + |
| 31 | + println!("Example 3: Applying limiter to a sine wave with default settings"); |
| 32 | + |
| 33 | + // Create a sine wave at 440 Hz |
| 34 | + let sine_wave = SineWave::new(440.0) |
| 35 | + .amplify(2.0) // Amplify to cause limiting |
| 36 | + .take_duration(Duration::from_millis(100)); |
| 37 | + |
| 38 | + // Apply limiting with default settings (simplest usage) |
| 39 | + let limited_wave = sine_wave.limit(LimitSettings::default()); |
| 40 | + |
| 41 | + // Collect some samples to demonstrate |
| 42 | + let samples: Vec<f32> = limited_wave.take(100).collect(); |
| 43 | + println!(" Generated {} limited samples", samples.len()); |
| 44 | + |
| 45 | + // Show peak reduction |
| 46 | + let max_sample = samples.iter().fold(0.0f32, |acc, &x| acc.max(x.abs())); |
| 47 | + println!(" Peak amplitude after limiting: {:.3}", max_sample); |
| 48 | + println!(); |
| 49 | + |
| 50 | + println!("Example 4: Custom settings with builder pattern"); |
| 51 | + |
| 52 | + // Create another sine wave for custom limiting |
| 53 | + let sine_wave2 = SineWave::new(880.0) |
| 54 | + .amplify(1.8) |
| 55 | + .take_duration(Duration::from_millis(50)); |
| 56 | + |
| 57 | + // Apply the custom settings from Example 2 |
| 58 | + let custom_limited = sine_wave2.limit(custom_limiting); |
| 59 | + let custom_samples: Vec<f32> = custom_limited.take(50).collect(); |
| 60 | + println!( |
| 61 | + " Generated {} samples with custom settings", |
| 62 | + custom_samples.len() |
| 63 | + ); |
| 64 | + println!(); |
| 65 | + |
| 66 | + println!("Example 5: Comparing different limiting scenarios"); |
| 67 | + |
| 68 | + let gentle_limiting = LimitSettings::default() |
| 69 | + .with_threshold(-6.0) // Higher threshold (less limiting) |
| 70 | + .with_knee_width(8.0) // Wide knee (softer) |
| 71 | + .with_attack(Duration::from_millis(20)) // Slower attack |
| 72 | + .with_release(Duration::from_millis(200)); // Slower release |
| 73 | + |
| 74 | + let aggressive_limiting = LimitSettings::default() |
| 75 | + .with_threshold(-1.0) // Lower threshold (more limiting) |
| 76 | + .with_knee_width(1.0) // Narrow knee (harder) |
| 77 | + .with_attack(Duration::from_millis(2)) // Fast attack |
| 78 | + .with_release(Duration::from_millis(20)); // Fast release |
| 79 | + |
| 80 | + println!(" Gentle limiting:"); |
| 81 | + println!( |
| 82 | + " Threshold: {} dB, Knee: {} dB", |
| 83 | + gentle_limiting.threshold, gentle_limiting.knee_width |
| 84 | + ); |
| 85 | + println!( |
| 86 | + " Attack: {:?}, Release: {:?}", |
| 87 | + gentle_limiting.attack, gentle_limiting.release |
| 88 | + ); |
| 89 | + |
| 90 | + println!(" Aggressive limiting:"); |
| 91 | + println!( |
| 92 | + " Threshold: {} dB, Knee: {} dB", |
| 93 | + aggressive_limiting.threshold, aggressive_limiting.knee_width |
| 94 | + ); |
| 95 | + println!( |
| 96 | + " Attack: {:?}, Release: {:?}", |
| 97 | + aggressive_limiting.attack, aggressive_limiting.release |
| 98 | + ); |
| 99 | + println!(); |
| 100 | + |
| 101 | + println!("Example 6: Limiting with -6dB threshold"); |
| 102 | + |
| 103 | + // Create a sine wave that will definitely trigger limiting |
| 104 | + const AMPLITUDE: f32 = 2.5; // High amplitude to ensure limiting occurs |
| 105 | + let test_sine = SineWave::new(440.0) |
| 106 | + .amplify(AMPLITUDE) |
| 107 | + .take_duration(Duration::from_millis(100)); // 100ms = ~4410 samples |
| 108 | + |
| 109 | + // Apply limiting with -6dB threshold (should limit to ~0.5) |
| 110 | + let strict_limiting = LimitSettings::default() |
| 111 | + .with_threshold(-6.0) |
| 112 | + .with_knee_width(0.5) // Narrow knee for precise limiting |
| 113 | + .with_attack(Duration::from_millis(3)) // Fast attack |
| 114 | + .with_release(Duration::from_millis(12)); // Moderate release |
| 115 | + |
| 116 | + let limited_sine = test_sine.limit(strict_limiting.clone()); |
| 117 | + let test_samples: Vec<f32> = limited_sine.take(4410).collect(); |
| 118 | + |
| 119 | + // Analyze peaks at different time periods |
| 120 | + let early_peak = test_samples[0..500] |
| 121 | + .iter() |
| 122 | + .fold(0.0f32, |acc, &x| acc.max(x.abs())); |
| 123 | + let mid_peak = test_samples[1000..1500] |
| 124 | + .iter() |
| 125 | + .fold(0.0f32, |acc, &x| acc.max(x.abs())); |
| 126 | + let settled_peak = test_samples[2000..] |
| 127 | + .iter() |
| 128 | + .fold(0.0f32, |acc, &x| acc.max(x.abs())); |
| 129 | + |
| 130 | + // With -6dB threshold, ALL samples are well below 1.0! |
| 131 | + let target_linear = 10.0_f32.powf(strict_limiting.threshold / 20.0); |
| 132 | + let max_settled = test_samples[2000..] |
| 133 | + .iter() |
| 134 | + .fold(0.0f32, |acc, &x| acc.max(x.abs())); |
| 135 | + |
| 136 | + println!( |
| 137 | + " {}dB threshold limiting results:", |
| 138 | + strict_limiting.threshold |
| 139 | + ); |
| 140 | + println!(" Original max amplitude: {AMPLITUDE}"); |
| 141 | + println!(" Target threshold: {:.3}", target_linear); |
| 142 | + println!(" Early peak (0-500 samples): {:.3}", early_peak); |
| 143 | + println!(" Mid peak (1000-1500 samples): {:.3}", mid_peak); |
| 144 | + println!(" Settled peak (2000+ samples): {:.3}", settled_peak); |
| 145 | + println!( |
| 146 | + " ALL samples now well below 1.0: max = {:.3}", |
| 147 | + max_settled |
| 148 | + ); |
| 149 | +} |
0 commit comments