1
0
Fork 0

Avoid clicks in the MIDI sine example

This commit is contained in:
Robbert van der Helm 2022-02-04 15:26:37 +01:00
parent 073fe743c2
commit 2c0b797c40

View file

@ -33,8 +33,14 @@ struct Sine {
/// The current phase of the sine wave, always kept between in `[0, 1]`. /// The current phase of the sine wave, always kept between in `[0, 1]`.
phase: f32, phase: f32,
/// The active frequency, if triggered by MIDI.
active_note_freq: Option<f32>, /// The frequency if the active note, if triggered by MIDI.
midi_note_freq: f32,
/// A simple attack and release envelope to avoid clicks.
///
/// Smoothing is built into the parameters, but you can also use them manually if you need to
/// smooth soemthing that isn't a parameter.
midi_note_gain: Smoother<f32>,
} }
#[derive(Params)] #[derive(Params)]
@ -56,7 +62,8 @@ impl Default for Sine {
sample_rate: 1.0, sample_rate: 1.0,
phase: 0.0, phase: 0.0,
active_note_freq: None, midi_note_freq: 1.0,
midi_note_gain: Smoother::new(SmoothingStyle::Linear(5.0)),
} }
} }
} }
@ -158,16 +165,12 @@ impl Plugin for Sine {
match next_event { match next_event {
Some(event) if event.timing() == sample_id as u32 => match event { Some(event) if event.timing() == sample_id as u32 => match event {
nih_plug::NoteEvent::NoteOn { note, .. } => { nih_plug::NoteEvent::NoteOn { note, .. } => {
// Reset the phase if this is a new note self.midi_note_freq = util::midi_note_to_freq(note);
if self.active_note_freq.is_none() { self.midi_note_gain.set_target(self.sample_rate, 1.0);
self.phase = 0.0;
}
self.active_note_freq = Some(util::midi_note_to_freq(note));
} }
nih_plug::NoteEvent::NoteOff { note, .. } => { nih_plug::NoteEvent::NoteOff { note, .. } => {
if self.active_note_freq == Some(util::midi_note_to_freq(note)) { if self.midi_note_freq == util::midi_note_to_freq(note) {
self.active_note_freq = None; self.midi_note_gain.set_target(self.sample_rate, 0.0);
} }
} }
}, },
@ -177,10 +180,8 @@ impl Plugin for Sine {
next_event = context.next_midi_event(); next_event = context.next_midi_event();
} }
match self.active_note_freq { // This gain envelope prevents clicks with new notes and with released notes
Some(frequency) => self.calculate_sine(frequency), self.calculate_sine(self.midi_note_freq) * self.midi_note_gain.next()
None => 0.0,
}
} else { } else {
let frequency = self.params.frequency.smoothed.next(); let frequency = self.params.frequency.smoothed.next();
self.calculate_sine(frequency) self.calculate_sine(frequency)