From 4ad4f8f76d9161907c61a127954e2fd11292e2cb Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Wed, 6 Jul 2022 16:35:07 +0200 Subject: [PATCH] Add more basic fields for PolyModSynth --- Cargo.lock | 13 ++++++++++- plugins/examples/poly_mod_synth/Cargo.toml | 3 +++ plugins/examples/poly_mod_synth/src/lib.rs | 26 ++++++++++++++++++++++ src/wrapper/clap/context.rs | 1 + src/wrapper/standalone/context.rs | 1 + src/wrapper/vst3/context.rs | 1 + 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 169faa58..a2c720c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2939,6 +2939,8 @@ name = "poly_mod_synth" version = "0.1.0" dependencies = [ "nih_plug", + "rand 0.8.5", + "rand_pcg 0.3.1", ] [[package]] @@ -3057,7 +3059,7 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg", + "rand_pcg 0.2.1", ] [[package]] @@ -3127,6 +3129,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core 0.6.3", +] + [[package]] name = "range-alloc" version = "0.1.2" diff --git a/plugins/examples/poly_mod_synth/Cargo.toml b/plugins/examples/poly_mod_synth/Cargo.toml index b48ac13a..bdd62d80 100644 --- a/plugins/examples/poly_mod_synth/Cargo.toml +++ b/plugins/examples/poly_mod_synth/Cargo.toml @@ -10,3 +10,6 @@ crate-type = ["cdylib"] [dependencies] nih_plug = { path = "../../../", features = ["assert_process_allocs"] } + +rand = "0.8.5" +rand_pcg = "0.3.1" diff --git a/plugins/examples/poly_mod_synth/src/lib.rs b/plugins/examples/poly_mod_synth/src/lib.rs index 42515848..00d62da5 100644 --- a/plugins/examples/poly_mod_synth/src/lib.rs +++ b/plugins/examples/poly_mod_synth/src/lib.rs @@ -1,4 +1,6 @@ use nih_plug::prelude::*; +use rand::Rng; +use rand_pcg::Pcg32; use std::sync::Arc; /// The number of simultaneous voices for this synth. @@ -13,6 +15,9 @@ const MAX_BLOCK_SIZE: usize = 64; struct PolyModSynth { params: Arc, + /// A pseudo-random number generator. This will always be reseeded with the same seed when the + /// synth is reset. That way the output is deterministic when rendering multiple times. + prng: Pcg32, /// The synth's voices. Inactive voices will be set to `None` values. voices: [Option; NUM_VOICES as usize], /// The next internal voice ID, used only to figure out the oldest voice for voice stealing. @@ -39,6 +44,15 @@ struct Voice { /// The voices internal ID. Each voice has an internal voice ID one higher than the previous /// voice. This is used to steal the last voice in case all 16 voices are in use. internal_voice_id: u64, + + /// The voice's current phase. This is randomized at the start of the voice + phase: f32, + /// The phase increment. This is based on the voice's frequency, derived from the note index. + /// Since we don't support pitch expressions or pitch bend, this value stays constant for the + /// duration of the voice. + phase_delta: f32, + /// The square root of the note's velocity. This is used as a gain multiplier. + velocity_sqrt: f32, } impl Default for PolyModSynth { @@ -46,6 +60,7 @@ impl Default for PolyModSynth { Self { params: Arc::new(PolyModSynthParams::default()), + prng: Pcg32::new(420, 1337), // `[None; N]` requires the `Some(T)` to be `Copy`able voices: [0; NUM_VOICES as usize].map(|_| None), next_internal_voice_id: 0, @@ -77,6 +92,9 @@ impl Plugin for PolyModSynth { // `context.set_current_voice_capacity()` in `initialize()` and in `process()` (when the // capacity changes) to inform the host about this. fn reset(&mut self) { + // This ensures the output is at least somewhat deterministic when rendering to audio + self.prng = Pcg32::new(420, 1337); + self.voices.fill(None); self.next_internal_voice_id = 0; } @@ -125,6 +143,10 @@ impl Plugin for PolyModSynth { ); // TODO: Add and set the other fields + voice.phase = self.prng.gen(); + voice.phase_delta = + util::midi_note_to_freq(note) / context.transport().sample_rate; + voice.velocity_sqrt = velocity.sqrt(); } NoteEvent::NoteOff { timing, @@ -211,6 +233,10 @@ impl PolyModSynth { internal_voice_id: self.next_internal_voice_id, channel, note, + + velocity_sqrt: 1.0, + phase: 0.0, + phase_delta: 0.0, }; self.next_internal_voice_id = self.next_internal_voice_id.wrapping_add(1); diff --git a/src/wrapper/clap/context.rs b/src/wrapper/clap/context.rs index 0e54d415..8a58b78b 100644 --- a/src/wrapper/clap/context.rs +++ b/src/wrapper/clap/context.rs @@ -131,6 +131,7 @@ impl ProcessContext for WrapperProcessContext<'_, P> { PluginApi::Clap } + #[inline] fn transport(&self) -> &Transport { &self.transport } diff --git a/src/wrapper/standalone/context.rs b/src/wrapper/standalone/context.rs index 1086993c..b7a1eb47 100644 --- a/src/wrapper/standalone/context.rs +++ b/src/wrapper/standalone/context.rs @@ -101,6 +101,7 @@ impl ProcessContext for WrapperProcessContext<'_, P, B> { PluginApi::Standalone } + #[inline] fn transport(&self) -> &Transport { &self.transport } diff --git a/src/wrapper/vst3/context.rs b/src/wrapper/vst3/context.rs index 166a80fb..0c829b89 100644 --- a/src/wrapper/vst3/context.rs +++ b/src/wrapper/vst3/context.rs @@ -135,6 +135,7 @@ impl ProcessContext for WrapperProcessContext<'_, P> { PluginApi::Vst3 } + #[inline] fn transport(&self) -> &Transport { &self.transport }