Skip to content

Commit 395163e

Browse files
committed
fix: scale sinc kernel by bandwidth
1 parent 05cb4a9 commit 395163e

File tree

2 files changed

+63
-6
lines changed

2 files changed

+63
-6
lines changed

dasp_interpolate/src/sinc/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ where
9393

9494
(0..max_depth).fold(Self::Frame::EQUILIBRIUM, |mut v, n| {
9595
v = {
96-
let a = PI * bandwidth * (phil + n as f64);
97-
let first = if a == 0.0 { 1.0 } else { sin(a) / a };
98-
let second = 0.5 + 0.5 * cos(a / (depth as f64 * bandwidth));
96+
let t = phil + n as f64;
97+
let a = PI * bandwidth * t;
98+
let b = PI * t / depth as f64;
99+
let first = if a.abs() < f64::EPSILON { bandwidth } else { bandwidth * sin(a) / a };
100+
let second = 0.5 + 0.5 * cos(b);
99101
v.zip_map(self.frames[nl - n], |vs, r_lag| {
100102
vs.add_amp(
101103
(first * second * r_lag.to_sample::<f64>())
@@ -105,9 +107,11 @@ where
105107
})
106108
};
107109

108-
let a = PI * bandwidth * (phir + n as f64);
109-
let first = if a == 0.0 { 1.0 } else { sin(a) / a };
110-
let second = 0.5 + 0.5 * cos(a / (depth as f64 * bandwidth));
110+
let t = phir + n as f64;
111+
let a = PI * bandwidth * t;
112+
let b = PI * t / depth as f64;
113+
let first = if a.abs() < f64::EPSILON { bandwidth } else { bandwidth * sin(a) / a };
114+
let second = 0.5 + 0.5 * cos(b);
111115
v.zip_map(self.frames[nr + n], |vs, r_lag| {
112116
vs.add_amp(
113117
(first * second * r_lag.to_sample::<f64>())

examples/aliasing.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use dasp::{interpolate::sinc::Sinc, ring_buffer, signal, Signal};
2+
use hound::{WavSpec, WavWriter};
3+
4+
fn main() {
5+
// Scaled version of issue #174:
6+
// Original: 900 Hz @ 2000 Hz → 1500 Hz (Nyquist 750 Hz, aliases to 600 Hz)
7+
// Scaled 8x: 7200 Hz @ 16000 Hz → 12000 Hz (Nyquist 6000 Hz, aliases to 4800 Hz)
8+
let my_signal = signal::rate(16000.0).const_hz(7200.0).sine();
9+
10+
let spec = WavSpec {
11+
channels: 1,
12+
sample_rate: 12000,
13+
bits_per_sample: 16,
14+
sample_format: hound::SampleFormat::Int,
15+
};
16+
17+
let ring_buffer = ring_buffer::Fixed::from([0.0; 100]);
18+
let sinc = Sinc::new(ring_buffer);
19+
let mut my_signal = my_signal.from_hz_to_hz(sinc, 16000.0, 12000.0);
20+
21+
let buffer_size = 100;
22+
let source_hz = 16000.0;
23+
let target_hz = 12000.0;
24+
let samples_to_skip = (buffer_size as f64 / (source_hz / target_hz)).ceil() as usize;
25+
26+
for _ in 0..samples_to_skip {
27+
my_signal.next();
28+
}
29+
30+
// Check first 1000 samples to verify signal
31+
let check_samples: Vec<f64> = (&mut my_signal).take(1000).collect();
32+
let check_rms = (check_samples.iter().map(|s| s * s).sum::<f64>() / check_samples.len() as f64).sqrt();
33+
eprintln!("RMS of resampled signal: {:.4}", check_rms);
34+
eprintln!("Max amplitude: {:.4}", check_samples.iter().map(|s| s.abs()).fold(0.0f64, f64::max));
35+
36+
let mut writer = WavWriter::create("my_output.wav", spec).unwrap();
37+
38+
// Write the check samples first
39+
for &frame in &check_samples {
40+
let clamped = frame.max(-1.0).min(1.0);
41+
writer
42+
.write_sample((clamped * i16::MAX as f64) as i16)
43+
.unwrap();
44+
}
45+
46+
// Then write the rest
47+
for frame in my_signal.take(12000 * 4 - 1000) {
48+
let clamped = frame.max(-1.0).min(1.0);
49+
writer
50+
.write_sample((clamped * i16::MAX as f64) as i16)
51+
.unwrap();
52+
}
53+
}

0 commit comments

Comments
 (0)