From 333ff2c05ec8c4b7846f9cf2e5fb307205b1ddfe Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Wed, 9 Nov 2022 18:38:44 +0100 Subject: [PATCH] Add an octave shift to Buffr Glitch --- plugins/buffr_glitch/src/buffer.rs | 11 +++++++---- plugins/buffr_glitch/src/lib.rs | 23 +++++++++++++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/plugins/buffr_glitch/src/buffer.rs b/plugins/buffr_glitch/src/buffer.rs index 704e3c45..ce852968 100644 --- a/plugins/buffr_glitch/src/buffer.rs +++ b/plugins/buffr_glitch/src/buffer.rs @@ -16,7 +16,7 @@ use nih_plug::prelude::*; -use crate::NormalizationMode; +use crate::{NormalizationMode, MAX_OCTAVE_SHIFT}; /// A super simple ring buffer abstraction that records audio into a recording ring buffer, and then /// copies audio to a playback buffer when a note is pressed so audio can be repeated while still @@ -47,9 +47,12 @@ impl RingBuffer { /// MIDI note 0 at the specified sample rate, rounded up to a power of two. Make sure to call /// [`reset()`][Self::reset()] after this. pub fn resize(&mut self, num_channels: usize, sample_rate: f32) { - let note_frequency = util::midi_note_to_freq(0); - let note_period_samples = (note_frequency.recip() * sample_rate).ceil() as usize; - let buffer_len = note_period_samples.next_power_of_two(); + // NOTE: We need to take the octave shift into account + let lowest_note_frequency = + util::midi_note_to_freq(0) / 2.0f32.powi(MAX_OCTAVE_SHIFT as i32); + let loest_note_period_samples = + (lowest_note_frequency.recip() * sample_rate).ceil() as usize; + let buffer_len = loest_note_period_samples.next_power_of_two(); // Used later to compute period sizes in samples based on frequencies self.sample_rate = sample_rate; diff --git a/plugins/buffr_glitch/src/lib.rs b/plugins/buffr_glitch/src/lib.rs index 637b265a..da2f8a55 100644 --- a/plugins/buffr_glitch/src/lib.rs +++ b/plugins/buffr_glitch/src/lib.rs @@ -19,6 +19,10 @@ use std::sync::Arc; mod buffer; +/// The maximum number of octaves the sample can be pitched down. This is used in calculating the +/// recording buffer's size. +pub const MAX_OCTAVE_SHIFT: u32 = 2; + struct BuffrGlitch { params: Arc, @@ -38,6 +42,10 @@ struct BuffrGlitchParams { /// Controls if and how grains are normalization. #[id = "normalization_mode"] normalization_mode: EnumParam, + /// The number of octaves the input signal should be increased or decreased by. Useful to allow + /// larger grain sizes. + #[id = "octave_shift"] + octave_shift: IntParam, } /// Controls how grains are normalized. @@ -69,6 +77,14 @@ impl Default for BuffrGlitchParams { fn default() -> Self { Self { normalization_mode: EnumParam::new("Normalization", NormalizationMode::Auto), + octave_shift: IntParam::new( + "Octave Shift", + 0, + IntRange::Linear { + min: -(MAX_OCTAVE_SHIFT as i32), + max: MAX_OCTAVE_SHIFT as i32, + }, + ), } } } @@ -140,9 +156,12 @@ impl Plugin for BuffrGlitch { self.midi_note_id = Some(note); // We'll copy audio to the playback buffer to match the pitch of the note - // that was just played + // that was just played. The octave shift parameter makes it possible to get + // larger window sizes. + let note_frequency = util::midi_note_to_freq(note) + * 2.0f32.powi(self.params.octave_shift.value()); self.buffer.prepare_playback( - util::midi_note_to_freq(note), + note_frequency, self.params.normalization_mode.value(), ); }