Hold the RwLock guard in the process context
This avoids having to constantly acquire a new lock.
This commit is contained in:
parent
ce3da8ea44
commit
bbc190c67f
5 changed files with 22 additions and 16 deletions
|
@ -111,7 +111,7 @@ impl Plugin for Gain {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
_buffer_config: &BufferConfig,
|
_buffer_config: &BufferConfig,
|
||||||
_context: &impl ProcessContext,
|
_context: &mut impl ProcessContext,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// This plugin doesn't need any special initialization, but if you need to do anything
|
// This plugin doesn't need any special initialization, but if you need to do anything
|
||||||
// expensive then this would be the place. State is kept around while when the host
|
// expensive then this would be the place. State is kept around while when the host
|
||||||
|
@ -119,7 +119,11 @@ impl Plugin for Gain {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&mut self, buffer: &mut Buffer, _context: &impl ProcessContext) -> ProcessStatus {
|
fn process(
|
||||||
|
&mut self,
|
||||||
|
buffer: &mut Buffer,
|
||||||
|
_context: &mut impl ProcessContext,
|
||||||
|
) -> ProcessStatus {
|
||||||
for samples in buffer.iter_mut() {
|
for samples in buffer.iter_mut() {
|
||||||
// Smoothing is optionally built into the parameters themselves
|
// Smoothing is optionally built into the parameters themselves
|
||||||
let gain = self.params.gain.smoothed.next();
|
let gain = self.params.gain.smoothed.next();
|
||||||
|
|
|
@ -145,14 +145,14 @@ impl Plugin for Sine {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &impl ProcessContext,
|
_context: &mut impl ProcessContext,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.sample_rate = buffer_config.sample_rate;
|
self.sample_rate = buffer_config.sample_rate;
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&mut self, buffer: &mut Buffer, context: &impl ProcessContext) -> ProcessStatus {
|
fn process(&mut self, buffer: &mut Buffer, context: &mut impl ProcessContext) -> ProcessStatus {
|
||||||
let mut next_event = context.next_midi_event();
|
let mut next_event = context.next_midi_event();
|
||||||
for (sample_id, samples) in buffer.iter_mut().enumerate() {
|
for (sample_id, samples) in buffer.iter_mut().enumerate() {
|
||||||
// Smoothing is optionally built into the parameters themselves
|
// Smoothing is optionally built into the parameters themselves
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub trait ProcessContext {
|
||||||
/// TODO: Rethink this API, both in terms of ergonomics, and if we can do this in a way that
|
/// TODO: Rethink this API, both in terms of ergonomics, and if we can do this in a way that
|
||||||
/// doesn't require locks (because of the thread safe-ness, which we don't really need
|
/// doesn't require locks (because of the thread safe-ness, which we don't really need
|
||||||
/// here)
|
/// here)
|
||||||
fn next_midi_event(&self) -> Option<NoteEvent>;
|
fn next_midi_event(&mut self) -> Option<NoteEvent>;
|
||||||
|
|
||||||
// // TODO: Add this next
|
// // TODO: Add this next
|
||||||
// fn set_parameter<P>(&self, param: &P, value: P::Plain)
|
// fn set_parameter<P>(&self, param: &P, value: P::Plain)
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub trait Plugin: Default + Send + Sync {
|
||||||
&mut self,
|
&mut self,
|
||||||
bus_config: &BusConfig,
|
bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
context: &impl ProcessContext,
|
context: &mut impl ProcessContext,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ pub trait Plugin: Default + Send + Sync {
|
||||||
/// TODO: Provide a way to access auxiliary input channels if the IO configuration is
|
/// TODO: Provide a way to access auxiliary input channels if the IO configuration is
|
||||||
/// assymetric
|
/// assymetric
|
||||||
/// TODO: Pass transport and other context information to the plugin
|
/// TODO: Pass transport and other context information to the plugin
|
||||||
fn process(&mut self, buffer: &mut Buffer, context: &impl ProcessContext) -> ProcessStatus;
|
fn process(&mut self, buffer: &mut Buffer, context: &mut impl ProcessContext) -> ProcessStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides auxiliary metadata needed for a VST3 plugin.
|
/// Provides auxiliary metadata needed for a VST3 plugin.
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::{RwLock, RwLockWriteGuard};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
@ -152,6 +152,7 @@ pub(crate) struct Wrapper<P: Plugin> {
|
||||||
/// unnecessary atomic operations to lock the uncontested RwLocks.
|
/// unnecessary atomic operations to lock the uncontested RwLocks.
|
||||||
struct WrapperProcessContext<'a, P: Plugin> {
|
struct WrapperProcessContext<'a, P: Plugin> {
|
||||||
inner: &'a WrapperInner<P>,
|
inner: &'a WrapperInner<P>,
|
||||||
|
input_events_guard: RwLockWriteGuard<'a, VecDeque<NoteEvent>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Plugin> ProcessContext for WrapperProcessContext<'_, P> {
|
impl<P: Plugin> ProcessContext for WrapperProcessContext<'_, P> {
|
||||||
|
@ -167,10 +168,8 @@ impl<P: Plugin> ProcessContext for WrapperProcessContext<'_, P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_midi_event(&self) -> Option<NoteEvent> {
|
fn next_midi_event(&mut self) -> Option<NoteEvent> {
|
||||||
// TODO: Instead of having to lock this queue, move the lock guard into
|
self.input_events_guard.pop_front()
|
||||||
// `WrapperProcessContext`. That's the whole reason this was split up.
|
|
||||||
self.inner.input_events.write().pop_front()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +292,10 @@ impl<P: Plugin> WrapperInner<P> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_process_context(&self) -> WrapperProcessContext<'_, P> {
|
pub fn make_process_context(&self) -> WrapperProcessContext<'_, P> {
|
||||||
WrapperProcessContext { inner: self }
|
WrapperProcessContext {
|
||||||
|
inner: self,
|
||||||
|
input_events_guard: self.input_events.write(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function for setting a value for a parameter as triggered by a VST3 parameter
|
/// Convenience function for setting a value for a parameter as triggered by a VST3 parameter
|
||||||
|
@ -607,7 +609,7 @@ impl<P: Plugin> IComponent for Wrapper<P> {
|
||||||
self.inner.plugin.write().initialize(
|
self.inner.plugin.write().initialize(
|
||||||
&bus_config,
|
&bus_config,
|
||||||
&buffer_config,
|
&buffer_config,
|
||||||
&self.inner.make_process_context(),
|
&mut self.inner.make_process_context(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,7 +996,7 @@ impl<P: Plugin> IAudioProcessor for Wrapper<P> {
|
||||||
if self.inner.plugin.write().initialize(
|
if self.inner.plugin.write().initialize(
|
||||||
&bus_config,
|
&bus_config,
|
||||||
&buffer_config,
|
&buffer_config,
|
||||||
&self.inner.make_process_context(),
|
&mut self.inner.make_process_context(),
|
||||||
) {
|
) {
|
||||||
// Preallocate enough room in the output slices vector so we can convert a `*mut *mut
|
// Preallocate enough room in the output slices vector so we can convert a `*mut *mut
|
||||||
// f32` to a `&mut [&mut f32]` in the process call
|
// f32` to a `&mut [&mut f32]` in the process call
|
||||||
|
@ -1173,7 +1175,7 @@ impl<P: Plugin> IAudioProcessor for Wrapper<P> {
|
||||||
.plugin
|
.plugin
|
||||||
.write()
|
.write()
|
||||||
// SAFETY: Same here
|
// SAFETY: Same here
|
||||||
.process(&mut output_buffer, &self.inner.make_process_context())
|
.process(&mut output_buffer, &mut self.inner.make_process_context())
|
||||||
{
|
{
|
||||||
ProcessStatus::Error(err) => {
|
ProcessStatus::Error(err) => {
|
||||||
nih_debug_assert_failure!("Process error: {}", err);
|
nih_debug_assert_failure!("Process error: {}", err);
|
||||||
|
|
Loading…
Add table
Reference in a new issue