Commit 4e55936e authored by Aske Simon Christensen's avatar Aske Simon Christensen
Browse files

Plugin parameters struct. Lazy cache invalidation.

parent c03986c0
...@@ -63,7 +63,7 @@ pub trait SoundParameters { ...@@ -63,7 +63,7 @@ pub trait SoundParameters {
} }
pub trait SoundGenerator { pub trait SoundGenerator {
type Parameters: PartialEq + SoundParameters; type Parameters: PartialEq + SoundParameters + Clone;
type Output: Default + Copy + Into<Sample>; type Output: Default + Copy + Into<Sample>;
type Global: Default; type Global: Default;
......
...@@ -127,15 +127,20 @@ pub struct SynthPlugin<G: SoundGenerator, S: SynthInfo> { ...@@ -127,15 +127,20 @@ pub struct SynthPlugin<G: SoundGenerator, S: SynthInfo> {
events: VecDeque<TimedMidiCommand>, events: VecDeque<TimedMidiCommand>,
cache: RwLock<Vec<SoundCache<G>>>, cache: RwLock<Vec<SoundCache<G>>>,
sound_params: G::Parameters, cached_sound_params: G::Parameters,
param_values: Vec<f32>, param_values: Vec<f32>,
param_map: RwLock<HashMap<&'static str, f32>>, params: RwLock<SynthPluginParameters<G>>,
global: G::Global, global: G::Global,
phantom: PhantomData<S> phantom: PhantomData<S>
} }
struct SynthPluginParameters<G: SoundGenerator> {
map: HashMap<&'static str, f32>,
sound_params: G::Parameters,
}
fn make_param_map(param_names: &[&'static str], param_values: &[f32]) -> HashMap<&'static str, f32> { fn make_param_map(param_names: &[&'static str], param_values: &[f32]) -> HashMap<&'static str, f32> {
let mut param_map = HashMap::new(); let mut param_map = HashMap::new();
for (s, v) in param_names.iter().zip(param_values) { for (s, v) in param_names.iter().zip(param_values) {
...@@ -153,6 +158,13 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> { ...@@ -153,6 +158,13 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> {
let sample_rate = 44100.0; let sample_rate = 44100.0;
let sound_params = G::Parameters::build(&param_map, sample_rate);
let params = SynthPluginParameters {
map: param_map,
sound_params: sound_params.clone()
};
SynthPlugin { SynthPlugin {
host: None, host: None,
...@@ -162,9 +174,9 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> { ...@@ -162,9 +174,9 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> {
events: VecDeque::new(), events: VecDeque::new(),
cache: RwLock::new(cache), cache: RwLock::new(cache),
sound_params: G::Parameters::build(&param_map, sample_rate), cached_sound_params: sound_params,
param_values: param_values, param_values: param_values,
param_map: RwLock::new(param_map), params: RwLock::new(params),
global: G::Global::default(), global: G::Global::default(),
...@@ -217,6 +229,17 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> { ...@@ -217,6 +229,17 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> {
} }
fn process(&mut self, buffer: &mut AudioBuffer<f32>) { fn process(&mut self, buffer: &mut AudioBuffer<f32>) {
{
let params: &SynthPluginParameters<G> = &self.params.read().unwrap();
if params.sound_params != self.cached_sound_params {
let cache: &mut Vec<SoundCache<G>> = &mut self.cache.write().unwrap();
self.cached_sound_params = params.sound_params.clone();
for c in cache {
c.invalidate();
}
}
}
let mut outputs = buffer.split().1; let mut outputs = buffer.split().1;
for i in 0..outputs[0].len() { for i in 0..outputs[0].len() {
while !self.events.is_empty() && self.events.front().unwrap().time == self.time { while !self.events.is_empty() && self.events.front().unwrap().time == self.time {
...@@ -240,13 +263,13 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> { ...@@ -240,13 +263,13 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> {
} }
fn get_parameter_text(&self, index: i32) -> String { fn get_parameter_text(&self, index: i32) -> String {
let param_map: &HashMap<&'static str, f32> = &self.param_map.read().unwrap(); let params: &SynthPluginParameters<G> = &self.params.read().unwrap();
self.sound_params.display(G::Parameters::names()[index as usize], param_map).0 params.sound_params.display(G::Parameters::names()[index as usize], &params.map).0
} }
fn get_parameter_label(&self, index: i32) -> String { fn get_parameter_label(&self, index: i32) -> String {
let param_map: &HashMap<&'static str, f32> = &self.param_map.read().unwrap(); let params: &SynthPluginParameters<G> = &self.params.read().unwrap();
self.sound_params.display(G::Parameters::names()[index as usize], param_map).1 params.sound_params.display(G::Parameters::names()[index as usize], &params.map).1
} }
fn get_parameter(&self, index: i32) -> f32 { fn get_parameter(&self, index: i32) -> f32 {
...@@ -271,11 +294,11 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> { ...@@ -271,11 +294,11 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> {
impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> { impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> {
fn handle_event(&mut self, event: TimedMidiCommand) { fn handle_event(&mut self, event: TimedMidiCommand) {
let param_map: &HashMap<&'static str, f32> = &self.param_map.read().unwrap(); let params: &SynthPluginParameters<G> = &self.params.read().unwrap();
match event.command { match event.command {
MidiCommand::NoteOn { key, velocity, .. } => { MidiCommand::NoteOn { key, velocity, .. } => {
let attack = G::Parameters::attack(param_map, self.sample_rate); let attack = G::Parameters::attack(&params.map, self.sample_rate);
let release = G::Parameters::release(param_map, self.sample_rate); let release = G::Parameters::release(&params.map, self.sample_rate);
let note = Note::new(key, velocity, attack, release, Some(self.sample_rate as usize)); let note = Note::new(key, velocity, attack, release, Some(self.sample_rate as usize));
self.notes.push(note); self.notes.push(note);
}, },
...@@ -306,7 +329,7 @@ impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> { ...@@ -306,7 +329,7 @@ impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> {
let mut sample: Sample = Sample::from(0.0); let mut sample: Sample = Sample::from(0.0);
for i in (0..self.notes.len()).rev() { for i in (0..self.notes.len()).rev() {
if self.notes[i].is_alive() { if self.notes[i].is_alive() {
sample += self.notes[i].produce_sample(cache, &self.sound_params, &self.global); sample += self.notes[i].produce_sample(cache, &self.cached_sound_params, &self.global);
} else { } else {
self.notes.remove(i); self.notes.remove(i);
} }
...@@ -315,16 +338,9 @@ impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> { ...@@ -315,16 +338,9 @@ impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> {
} }
fn build_sound_params(&mut self) { fn build_sound_params(&mut self) {
let param_map: &mut HashMap<&'static str, f32> = &mut self.param_map.write().unwrap(); let params: &mut SynthPluginParameters<G> = &mut self.params.write().unwrap();
*param_map = make_param_map(G::Parameters::names(), &self.param_values); params.map = make_param_map(G::Parameters::names(), &self.param_values);
let new_sound_params = G::Parameters::build(param_map, self.sample_rate); params.sound_params = G::Parameters::build(&params.map, self.sample_rate);
if new_sound_params != self.sound_params {
let cache: &mut Vec<SoundCache<G>> = &mut self.cache.write().unwrap();
self.sound_params = new_sound_params;
for c in cache {
c.invalidate();
}
}
} }
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment