Skip to content

Commit

Permalink
Prevent pops after unpause
Browse files Browse the repository at this point in the history
Sudden jump to far-from-zero amplitude on input during unpause is fed
into the feedback which then repeats the pop indefinitely.

With this patch, input audio is faded-in/out after/before unpause.

Signed-off-by: Petr Horacek <petr@zlosynth.com>
  • Loading branch information
phoracek committed Nov 14, 2023
1 parent a1ed1f0 commit 7486e0a
Showing 1 changed file with 87 additions and 15 deletions.
102 changes: 87 additions & 15 deletions dsp/src/delay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub struct Delay {
buffer_reset: BufferReset,
compressor: [Compressor; 4],
dc_blocker: [DCBlocker; 4],
playback_controls: PlayControls,
play_state: PlayState,
}

#[derive(Default, Debug)]
Expand Down Expand Up @@ -114,9 +114,11 @@ pub struct Reaction {

#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum PlayControls {
Play,
Pause,
enum PlayState {
Playing,
Pausing(usize, usize),
Unpausing(usize, usize),
Paused,
}

impl Delay {
Expand Down Expand Up @@ -158,7 +160,7 @@ impl Delay {
DCBlocker::default(),
DCBlocker::default(),
],
playback_controls: PlayControls::default(),
play_state: PlayState::default(),
}
}

Expand All @@ -181,11 +183,17 @@ impl Delay {
random: &mut impl Random,
) -> Reaction {
let buffer_len = input_buffer.len();

for (i, x) in input_buffer.iter_mut().enumerate() {
let amp = self.buffer_reset.calculate_input_amplitude(i, buffer_len);
*x *= amp;
}

for (i, x) in input_buffer.iter_mut().enumerate() {
let amp = self.play_state.calculate_input_amplitude(i, buffer_len);
*x *= amp;
}

if self.filter_placement.is_input() {
tone.tone_1.process(input_buffer);
}
Expand All @@ -204,7 +212,7 @@ impl Delay {
wow_flutter.dry_process(input_buffer);
}

if self.playback_controls.is_playing() {
if self.play_state.is_playing() {
for x in input_buffer.iter() {
self.buffer.write(*x);
}
Expand Down Expand Up @@ -258,7 +266,9 @@ impl Delay {
wow_flutter.buffer_reset(index * wow_flutter_chunk, wow_flutter_chunk);
}

let impulse = if self.playback_controls.is_playing() {
self.play_state.tick();

let impulse = if self.play_state.is_playing() {
self.consider_impulse(input_buffer.len(), random)
} else {
false
Expand Down Expand Up @@ -341,11 +351,11 @@ impl Delay {
self.buffer_reset = BufferReset::Armed;
}

self.playback_controls = if attributes.paused {
PlayControls::Pause
if attributes.paused {
self.play_state.pause();
} else {
PlayControls::Play
};
self.play_state.unpause();
}
}
}

Expand Down Expand Up @@ -458,14 +468,76 @@ impl BufferReset {
}
}

impl Default for PlayControls {
impl Default for PlayState {
fn default() -> Self {
Self::Pause
Self::Playing
}
}

impl PlayControls {
impl PlayState {
fn is_playing(self) -> bool {
matches!(self, Self::Play)
matches!(self, Self::Playing)
|| matches!(self, Self::Pausing(_, _))
|| matches!(self, Self::Unpausing(_, _))
}

fn calculate_input_amplitude(&mut self, i: usize, buffer_len: usize) -> f32 {
match self {
Self::Pausing(j, n) => {
let part = 1.0 / *n as f32;
let start = *j as f32 / *n as f32;
let phase_in_buffer = i as f32 / buffer_len as f32;
1.0 - (start + phase_in_buffer * part)
}
Self::Unpausing(j, n) => {
let part = 1.0 / *n as f32;
let start = *j as f32 / *n as f32;
let phase_in_buffer = i as f32 / buffer_len as f32;
start + phase_in_buffer * part
}
Self::Paused => 0.0,
Self::Playing => 1.0,
}
}

fn tick(&mut self) {
*self = match self {
Self::Pausing(mut j, n) => {
j += 1;
if j == *n {
Self::Paused
} else {
Self::Pausing(j, *n)
}
}
Self::Unpausing(mut j, n) => {
j += 1;
if j == *n {
Self::Playing
} else {
Self::Unpausing(j, *n)
}
}
Self::Paused => Self::Paused,
Self::Playing => Self::Playing,
}
}

fn pause(&mut self) {
*self = match self {
Self::Playing => Self::Pausing(0, 10),
Self::Paused => Self::Paused,
Self::Pausing(j, n) => Self::Pausing(*j, *n),
Self::Unpausing(j, n) => Self::Pausing(*n - *j, *n),
};
}

fn unpause(&mut self) {
*self = match self {
Self::Playing => Self::Playing,
Self::Paused => Self::Unpausing(0, 10),
Self::Pausing(j, n) => Self::Unpausing(*n - *j, *n),
Self::Unpausing(j, n) => Self::Unpausing(*j, *n),
};
}
}

0 comments on commit 7486e0a

Please sign in to comment.