1
0
Fork 0

Add more basic fields for PolyModSynth

This commit is contained in:
Robbert van der Helm 2022-07-06 16:35:07 +02:00
parent e77eca88a5
commit 4ad4f8f76d
6 changed files with 44 additions and 1 deletions

13
Cargo.lock generated
View file

@ -2939,6 +2939,8 @@ name = "poly_mod_synth"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"nih_plug", "nih_plug",
"rand 0.8.5",
"rand_pcg 0.3.1",
] ]
[[package]] [[package]]
@ -3057,7 +3059,7 @@ dependencies = [
"rand_chacha 0.2.2", "rand_chacha 0.2.2",
"rand_core 0.5.1", "rand_core 0.5.1",
"rand_hc", "rand_hc",
"rand_pcg", "rand_pcg 0.2.1",
] ]
[[package]] [[package]]
@ -3127,6 +3129,15 @@ dependencies = [
"rand_core 0.5.1", "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]] [[package]]
name = "range-alloc" name = "range-alloc"
version = "0.1.2" version = "0.1.2"

View file

@ -10,3 +10,6 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
nih_plug = { path = "../../../", features = ["assert_process_allocs"] } nih_plug = { path = "../../../", features = ["assert_process_allocs"] }
rand = "0.8.5"
rand_pcg = "0.3.1"

View file

@ -1,4 +1,6 @@
use nih_plug::prelude::*; use nih_plug::prelude::*;
use rand::Rng;
use rand_pcg::Pcg32;
use std::sync::Arc; use std::sync::Arc;
/// The number of simultaneous voices for this synth. /// The number of simultaneous voices for this synth.
@ -13,6 +15,9 @@ const MAX_BLOCK_SIZE: usize = 64;
struct PolyModSynth { struct PolyModSynth {
params: Arc<PolyModSynthParams>, params: Arc<PolyModSynthParams>,
/// 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. /// The synth's voices. Inactive voices will be set to `None` values.
voices: [Option<Voice>; NUM_VOICES as usize], voices: [Option<Voice>; NUM_VOICES as usize],
/// The next internal voice ID, used only to figure out the oldest voice for voice stealing. /// 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 /// 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. /// voice. This is used to steal the last voice in case all 16 voices are in use.
internal_voice_id: u64, 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 { impl Default for PolyModSynth {
@ -46,6 +60,7 @@ impl Default for PolyModSynth {
Self { Self {
params: Arc::new(PolyModSynthParams::default()), params: Arc::new(PolyModSynthParams::default()),
prng: Pcg32::new(420, 1337),
// `[None; N]` requires the `Some(T)` to be `Copy`able // `[None; N]` requires the `Some(T)` to be `Copy`able
voices: [0; NUM_VOICES as usize].map(|_| None), voices: [0; NUM_VOICES as usize].map(|_| None),
next_internal_voice_id: 0, 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 // `context.set_current_voice_capacity()` in `initialize()` and in `process()` (when the
// capacity changes) to inform the host about this. // capacity changes) to inform the host about this.
fn reset(&mut self) { 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.voices.fill(None);
self.next_internal_voice_id = 0; self.next_internal_voice_id = 0;
} }
@ -125,6 +143,10 @@ impl Plugin for PolyModSynth {
); );
// TODO: Add and set the other fields // 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 { NoteEvent::NoteOff {
timing, timing,
@ -211,6 +233,10 @@ impl PolyModSynth {
internal_voice_id: self.next_internal_voice_id, internal_voice_id: self.next_internal_voice_id,
channel, channel,
note, 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); self.next_internal_voice_id = self.next_internal_voice_id.wrapping_add(1);

View file

@ -131,6 +131,7 @@ impl<P: ClapPlugin> ProcessContext for WrapperProcessContext<'_, P> {
PluginApi::Clap PluginApi::Clap
} }
#[inline]
fn transport(&self) -> &Transport { fn transport(&self) -> &Transport {
&self.transport &self.transport
} }

View file

@ -101,6 +101,7 @@ impl<P: Plugin, B: Backend> ProcessContext for WrapperProcessContext<'_, P, B> {
PluginApi::Standalone PluginApi::Standalone
} }
#[inline]
fn transport(&self) -> &Transport { fn transport(&self) -> &Transport {
&self.transport &self.transport
} }

View file

@ -135,6 +135,7 @@ impl<P: Vst3Plugin> ProcessContext for WrapperProcessContext<'_, P> {
PluginApi::Vst3 PluginApi::Vst3
} }
#[inline]
fn transport(&self) -> &Transport { fn transport(&self) -> &Transport {
&self.transport &self.transport
} }