Commit 5f5496b5 authored by Aske Simon Christensen's avatar Aske Simon Christensen
Browse files

Ported to thread-safe rust-vst branch

parent 2b7b702f
...@@ -5,7 +5,7 @@ authors = ["Aske Simon Christensen <blueberry@loonies.dk>"] ...@@ -5,7 +5,7 @@ authors = ["Aske Simon Christensen <blueberry@loonies.dk>"]
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
vst = { git = "https://github.com/rust-dsp/rust-vst" } vst = { git = "https://github.com/askeksa/rust-vst", branch = "thread_safe_plugin" }
rand = "0.3" rand = "0.3"
[build-dependencies] [build-dependencies]
......
...@@ -63,7 +63,7 @@ pub trait SoundParameters { ...@@ -63,7 +63,7 @@ pub trait SoundParameters {
} }
pub trait SoundGenerator { pub trait SoundGenerator {
type Parameters: PartialEq + SoundParameters + Clone; type Parameters: SoundParameters + PartialEq + Clone + Send + Sync;
type Output: Default + Copy + Into<Sample>; type Output: Default + Copy + Into<Sample>;
type Global: Default; type Global: Default;
......
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::RwLock; use std::ops::Deref;
use std::sync::{Arc, RwLock};
use vst::api::{Events, Supported}; use vst::api::{Events, Supported};
use vst::buffer::AudioBuffer; use vst::buffer::AudioBuffer;
use vst::event::{Event, MidiEvent}; use vst::event::{Event, MidiEvent};
use vst::host::Host; use vst::host::Host;
use vst::plugin::{CanDo, Category, HostCallback, Info, Plugin}; use vst::plugin::{CanDo, Category, HostCallback, Info, Plugin, PluginParameters};
use cache::SoundCache; use cache::SoundCache;
use generate::{Sample, SoundGenerator, SoundParameters}; use generate::{Sample, SoundGenerator, SoundParameters};
...@@ -118,7 +119,7 @@ pub trait SynthInfo { ...@@ -118,7 +119,7 @@ pub trait SynthInfo {
fn get_info() -> Info; fn get_info() -> Info;
} }
pub struct SynthPlugin<G: SoundGenerator, S: SynthInfo> { pub struct SynthPlugin<G: SoundGenerator + 'static, S: SynthInfo> {
sample_rate: f32, sample_rate: f32,
time: usize, time: usize,
notes: Vec<Note>, notes: Vec<Note>,
...@@ -126,11 +127,10 @@ pub struct SynthPlugin<G: SoundGenerator, S: SynthInfo> { ...@@ -126,11 +127,10 @@ pub struct SynthPlugin<G: SoundGenerator, S: SynthInfo> {
cache: Vec<SoundCache<G>>, cache: Vec<SoundCache<G>>,
cached_sound_params: G::Parameters, cached_sound_params: G::Parameters,
params: RwLock<SynthPluginParameters<G>>,
global: G::Global, global: G::Global,
params: Arc<RwLockWrapper<SynthPluginParameters<G>>>,
phantom: PhantomData<S> phantom: PhantomData<S>
} }
...@@ -139,6 +139,20 @@ struct SynthPluginParameters<G: SoundGenerator> { ...@@ -139,6 +139,20 @@ struct SynthPluginParameters<G: SoundGenerator> {
values: Vec<f32>, values: Vec<f32>,
map: HashMap<&'static str, f32>, map: HashMap<&'static str, f32>,
sound_params: G::Parameters, sound_params: G::Parameters,
sample_rate: f32,
}
// Work around orphan rule
struct RwLockWrapper<T> {
inner: RwLock<T>
}
impl<T> Deref for RwLockWrapper<T> {
type Target = RwLock<T>;
fn deref(&self) -> &RwLock<T> {
&self.inner
}
} }
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> {
...@@ -164,7 +178,8 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> { ...@@ -164,7 +178,8 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> {
host: None, host: None,
values: param_values, values: param_values,
map: param_map, map: param_map,
sound_params: sound_params.clone() sound_params: sound_params.clone(),
sample_rate: sample_rate,
}; };
SynthPlugin { SynthPlugin {
...@@ -175,7 +190,7 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> { ...@@ -175,7 +190,7 @@ impl<G: SoundGenerator, S: SynthInfo> Default for SynthPlugin<G, S> {
cache: cache, cache: cache,
cached_sound_params: sound_params, cached_sound_params: sound_params,
params: RwLock::new(params), params: Arc::new(RwLockWrapper { inner: RwLock::new(params) }),
global: G::Global::default(), global: G::Global::default(),
...@@ -227,15 +242,7 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> { ...@@ -227,15 +242,7 @@ 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>) {
{ self.update_cache();
let params: &SynthPluginParameters<G> = &self.params.read().unwrap();
if params.sound_params != self.cached_sound_params {
self.cached_sound_params = params.sound_params.clone();
for c in &mut self.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() {
...@@ -252,44 +259,50 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> { ...@@ -252,44 +259,50 @@ impl<G: SoundGenerator, S: SynthInfo> Plugin for SynthPlugin<G, S> {
fn set_sample_rate(&mut self, rate: f32) { fn set_sample_rate(&mut self, rate: f32) {
self.sample_rate = rate; self.sample_rate = rate;
self.build_sound_params(); let params: &mut SynthPluginParameters<G> = &mut self.params.write().unwrap();
params.sample_rate = rate;
params.build_sound_params();
} }
fn get_parameter_object(&mut self) -> Arc<PluginParameters> {
Arc::clone(&self.params) as Arc<PluginParameters>
}
}
impl<G: SoundGenerator> PluginParameters for RwLockWrapper<SynthPluginParameters<G>> {
fn get_parameter_name(&self, index: i32) -> String { fn get_parameter_name(&self, index: i32) -> String {
G::Parameters::names()[index as usize].to_string() G::Parameters::names()[index as usize].to_string()
} }
fn get_parameter_text(&self, index: i32) -> String { fn get_parameter_text(&self, index: i32) -> String {
let params: &SynthPluginParameters<G> = &self.params.read().unwrap(); let params: &SynthPluginParameters<G> = &self.read().unwrap();
params.sound_params.display(G::Parameters::names()[index as usize], &params.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 params: &SynthPluginParameters<G> = &self.params.read().unwrap(); let params: &SynthPluginParameters<G> = &self.read().unwrap();
params.sound_params.display(G::Parameters::names()[index as usize], &params.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 {
let params: &SynthPluginParameters<G> = &self.params.read().unwrap(); let params: &SynthPluginParameters<G> = &self.read().unwrap();
params.values[index as usize] params.values[index as usize]
} }
fn set_parameter(&mut self, index: i32, value: f32) { fn set_parameter(&self, index: i32, value: f32) {
{ let params: &mut SynthPluginParameters<G> = &mut self.write().unwrap();
let params: &mut SynthPluginParameters<G> = &mut self.params.write().unwrap(); params.values[index as usize] = value;
params.values[index as usize] = value;
if let Some(ref mut host) = params.host { if let Some(ref mut host) = params.host {
for name in G::Parameters::influence(G::Parameters::names()[index as usize]) { for name in G::Parameters::influence(G::Parameters::names()[index as usize]) {
if let Some(p) = G::Parameters::names().iter().position(|n| *n == name) { if let Some(p) = G::Parameters::names().iter().position(|n| *n == name) {
params.values[p] = infinitesimal_change(params.values[p]).min(1.0); params.values[p] = infinitesimal_change(params.values[p]).min(1.0);
host.automate(p as i32, params.values[p]); host.automate(p as i32, params.values[p]);
}
} }
} }
} }
self.build_sound_params(); params.build_sound_params();
} }
} }
...@@ -337,10 +350,21 @@ impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> { ...@@ -337,10 +350,21 @@ impl<G: SoundGenerator, S: SynthInfo> SynthPlugin<G, S> {
sample sample
} }
fn update_cache(&mut self) {
let params: &SynthPluginParameters<G> = &self.params.read().unwrap();
if params.sound_params != self.cached_sound_params {
self.cached_sound_params = params.sound_params.clone();
for c in &mut self.cache {
c.invalidate();
}
}
}
}
impl<G: SoundGenerator> SynthPluginParameters<G> {
fn build_sound_params(&mut self) { fn build_sound_params(&mut self) {
let params: &mut SynthPluginParameters<G> = &mut self.params.write().unwrap(); self.map = make_param_map(G::Parameters::names(), &self.values);
params.map = make_param_map(G::Parameters::names(), &params.values); self.sound_params = G::Parameters::build(&self.map, self.sample_rate);
params.sound_params = G::Parameters::build(&params.map, self.sample_rate);
} }
} }
......
Markdown is supported
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