Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for modulation #31

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions bbx_dsp/src/effectors/amplifier.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bbx_buffer::buffer::{AudioBuffer, Buffer};

use crate::{
process::{AudioInput, Process},
process::{AudioInput, ModulationInput, Process},
utils::{clear_output, sum_audio_inputs},
};

Expand All @@ -22,11 +22,17 @@ impl AmplifierEffector {
}

impl Process for AmplifierEffector {
fn process(&mut self, inputs: &[AudioInput], output: &mut [AudioBuffer<f32>]) {
clear_output(output);
sum_audio_inputs(inputs, output);
fn process(
&mut self,
audio_inputs: &[AudioInput],
audio_output: &mut [AudioBuffer<f32>],
_mod_inputs: &[ModulationInput],
_mod_output: &mut Vec<f32>,
) {
clear_output(audio_output);
sum_audio_inputs(audio_inputs, audio_output);

for channel_buffer in output.iter_mut() {
for channel_buffer in audio_output.iter_mut() {
channel_buffer.apply(|s| s * self.gain);
}
}
Expand Down
20 changes: 13 additions & 7 deletions bbx_dsp/src/effectors/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bbx_buffer::buffer::{AudioBuffer, Buffer};

use crate::{
context::Context,
process::{AudioInput, Process},
process::{AudioInput, ModulationInput, Process},
utils::{clear_output, sum_audio_inputs},
};

Expand All @@ -25,14 +25,20 @@ impl FilterEffector {
}

impl Process for FilterEffector {
fn process(&mut self, inputs: &[AudioInput], output: &mut [AudioBuffer<f32>]) {
clear_output(output);
sum_audio_inputs(inputs, output);

for sample_idx in 0..output[0].len() {
fn process(
&mut self,
audio_inputs: &[AudioInput],
audio_output: &mut [AudioBuffer<f32>],
_mod_inputs: &[ModulationInput],
_mod_output: &mut Vec<f32>,
) {
clear_output(audio_output);
sum_audio_inputs(audio_inputs, audio_output);

for sample_idx in 0..audio_output[0].len() {
let g = (std::f32::consts::PI * self.cutoff / self.context.sample_rate as f32).sin();

for channel_buffer in output.iter_mut() {
for channel_buffer in audio_output.iter_mut() {
let input_sample = channel_buffer[sample_idx];
let feedback = self.resonance * self.stages[3];

Expand Down
16 changes: 11 additions & 5 deletions bbx_dsp/src/effectors/flanger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bbx_buffer::buffer::{AudioBuffer, Buffer};

use crate::{
context::Context,
process::{AudioInput, Process},
process::{AudioInput, ModulationInput, Process},
utils::{clear_output, sum_audio_inputs},
};

Expand Down Expand Up @@ -42,9 +42,15 @@ impl FlangerEffector {
}

impl Process for FlangerEffector {
fn process(&mut self, inputs: &[AudioInput], output: &mut [AudioBuffer<f32>]) {
clear_output(output);
sum_audio_inputs(inputs, output);
fn process(
&mut self,
audio_input: &[AudioInput],
audio_output: &mut [AudioBuffer<f32>],
_mod_inputs: &[ModulationInput],
_mod_output: &mut Vec<f32>,
) {
clear_output(audio_output);
sum_audio_inputs(audio_input, audio_output);

let max_delay_samples = (self.delay_time * self.context.sample_rate as f32).round() as usize;

Expand All @@ -53,7 +59,7 @@ impl Process for FlangerEffector {
let modulated_delay = (self.delay_time + lfo) * self.context.sample_rate as f32;
let delay_samples = modulated_delay.round() as usize;

for (channel_idx, channel_buffer) in output.iter_mut().enumerate() {
for (channel_idx, channel_buffer) in audio_output.iter_mut().enumerate() {
let delayed_sample = self.delay_buffer[channel_idx]
[(self.delay_idx + max_delay_samples - delay_samples) % max_delay_samples];
let wet_sample = channel_buffer[sample_idx] + self.feedback * delayed_sample;
Expand Down
14 changes: 10 additions & 4 deletions bbx_dsp/src/effectors/mixer.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
use bbx_buffer::buffer::AudioBuffer;

use crate::{
process::{AudioInput, Process},
process::{AudioInput, ModulationInput, Process},
utils::{clear_output, sum_audio_inputs},
};

pub struct MixerEffector;

impl Process for MixerEffector {
fn process(&mut self, inputs: &[AudioInput], output: &mut [AudioBuffer<f32>]) {
clear_output(output);
sum_audio_inputs(inputs, output);
fn process(
&mut self,
audio_inputs: &[AudioInput],
audio_output: &mut [AudioBuffer<f32>],
_mod_inputs: &[ModulationInput],
_mod_output: &mut Vec<f32>,
) {
clear_output(audio_output);
sum_audio_inputs(audio_inputs, audio_output);
}
}
16 changes: 11 additions & 5 deletions bbx_dsp/src/effectors/overdrive.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
use bbx_buffer::buffer::{AudioBuffer, Buffer};

use crate::{
process::{AudioInput, Process},
process::{AudioInput, ModulationInput, Process},
utils::{clear_output, sum_audio_inputs},
};

pub struct OverdriveEffector;

impl Process for OverdriveEffector {
fn process(&mut self, inputs: &[AudioInput], output: &mut [AudioBuffer<f32>]) {
clear_output(output);
sum_audio_inputs(inputs, output);
fn process(
&mut self,
audio_inputs: &[AudioInput],
audio_output: &mut [AudioBuffer<f32>],
_mod_inputs: &[ModulationInput],
_mod_output: &mut Vec<f32>,
) {
clear_output(audio_output);
sum_audio_inputs(audio_inputs, audio_output);

for channel_buffer in output.iter_mut() {
for channel_buffer in audio_output.iter_mut() {
channel_buffer.apply(|s| s - (s.powi(3) / 3.0));
}
}
Expand Down
6 changes: 6 additions & 0 deletions bbx_dsp/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub enum BbxAudioDspError {
#[error("cannot add generator node to graph")]
CannotAddGeneratorNode,

#[error("cannot add modulator node to graph")]
CannotAddModulatorNode,

#[error("cannot retrieve the current node (`{0}`)")]
CannotRetrieveCurrentNode(String),

Expand All @@ -36,6 +39,9 @@ pub enum BbxAudioDspError {
#[error("graph has non-converging paths")]
GraphContainsNonConvergingPaths,

#[error("modulation has already been created")]
ModulationAlreadyCreated,

#[error("node (`{0}`) has no inputs")]
NodeHasNoInputs(String),

Expand Down
16 changes: 11 additions & 5 deletions bbx_dsp/src/generators/file_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bbx_file::{reader::Reader, readers::wav::WavFileReader};

use crate::{
context::Context,
process::{AudioInput, Process},
process::{AudioInput, ModulationInput, Process},
utils::clear_output,
};

Expand All @@ -20,14 +20,20 @@ impl FileReaderGenerator {
}

impl Process for FileReaderGenerator {
fn process(&mut self, _inputs: &[AudioInput], output: &mut [AudioBuffer<f32>]) {
clear_output(output);
for (channel_idx, channel_buffer) in output.iter_mut().enumerate() {
fn process(
&mut self,
_audio_inputs: &[AudioInput],
audio_output: &mut [AudioBuffer<f32>],
_mod_inputs: &[ModulationInput],
_mod_output: &mut Vec<f32>,
) {
clear_output(audio_output);
for (channel_idx, channel_buffer) in audio_output.iter_mut().enumerate() {
channel_buffer.copy_from_slice(
self.reader
.read_channel(channel_idx, self.sample_idx, channel_buffer.len()),
)
}
self.sample_idx += output[0].len();
self.sample_idx += audio_output[0].len();
}
}
31 changes: 26 additions & 5 deletions bbx_dsp/src/generators/wave_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use bbx_buffer::buffer::{AudioBuffer, Buffer};

use crate::{
context::Context,
process::{AudioInput, Process},
modulator::ModulationDestination,
process::{AudioInput, ModulationInput, Process},
utils::clear_output,
};

Expand All @@ -24,7 +25,7 @@ pub struct WaveTableGenerator {
}

impl WaveTableGenerator {
pub fn new(context: Context, frequency: f32, waveform: Waveform) -> WaveTableGenerator {
pub fn new(context: Context, frequency: f32, waveform: Waveform) -> Self {
let wave_table = Self::create_wave_table(WAVE_TABLE_SIZE);
let phase_increment = Self::calculate_phase_increment(context.sample_rate, frequency, wave_table.len());
WaveTableGenerator {
Expand All @@ -51,6 +52,10 @@ impl WaveTableGenerator {
}

impl WaveTableGenerator {
pub fn get_frequency(&self) -> f32 {
(self.phase_increment * self.context.sample_rate as f32) / self.wave_table.len() as f32
}

pub fn set_frequency(&mut self, frequency: f32) {
self.phase_increment =
Self::calculate_phase_increment(self.context.sample_rate, frequency, self.wave_table.len());
Expand Down Expand Up @@ -83,15 +88,31 @@ impl WaveTableGenerator {
}

impl Process for WaveTableGenerator {
fn process(&mut self, _inputs: &[AudioInput], output: &mut [AudioBuffer<f32>]) {
clear_output(output);
fn process(
&mut self,
_audio_inputs: &[AudioInput],
audio_output: &mut [AudioBuffer<f32>],
mod_inputs: &[ModulationInput],
_mod_output: &mut Vec<f32>,
) {
clear_output(audio_output);

let mut output_iter = output.iter_mut();
let mut output_iter = audio_output.iter_mut();
let mut sample_idx: usize = 0;
let model_buffer = output_iter.next().unwrap();
model_buffer.apply_mut(|_| {
let sine_value = self.lerp();

self.phase += self.phase_increment;
self.phase %= self.wave_table.len() as f32;

if let Some(freq_mod_idx) = self.get_mod_index(ModulationDestination::Frequency, mod_inputs) {
// TOOD: Change hard-coded value (aka depth)
let freq_mod = 55.0 * mod_inputs[freq_mod_idx].as_slice()[sample_idx];
self.set_frequency(self.get_frequency() + freq_mod);
sample_idx += 1;
}

self.get_waveform_value(sine_value)
});

Expand Down
Loading
Loading