Accept incoming note events
This commit is contained in:
parent
51dace591d
commit
02cf16e9c0
3 changed files with 50 additions and 5 deletions
|
@ -32,7 +32,7 @@ pub use param::internals::Params;
|
|||
pub use param::range::Range;
|
||||
pub use param::smoothing::{Smoother, SmoothingStyle};
|
||||
pub use param::{BoolParam, FloatParam, IntParam, Param};
|
||||
pub use plugin::{BufferConfig, BusConfig, Plugin, ProcessStatus, Vst3Plugin};
|
||||
pub use plugin::{BufferConfig, BusConfig, NoteEvent, Plugin, ProcessStatus, Vst3Plugin};
|
||||
|
||||
// The rest is either internal or already re-exported
|
||||
mod buffer;
|
||||
|
|
|
@ -26,7 +26,6 @@ use crate::param::internals::Params;
|
|||
/// This is super basic, and lots of things I didn't need or want to use yet haven't been
|
||||
/// implemented. Notable missing features include:
|
||||
///
|
||||
/// - MIDI
|
||||
/// - Sidechain inputs
|
||||
/// - Multiple output busses
|
||||
/// - Special handling for offline processing
|
||||
|
@ -154,3 +153,13 @@ pub enum ProcessStatus {
|
|||
/// infite tail.
|
||||
KeepAlive,
|
||||
}
|
||||
|
||||
/// Event for (incoming) notes. Right now this only supports a very small subset of the MIDI
|
||||
/// specification.
|
||||
///
|
||||
/// TODO: Add more events as needed
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum NoteEvent {
|
||||
NoteOn { channel: u8, note: u8, velocity: u8 },
|
||||
NoteOff { channel: u8, note: u8, velocity: u8 },
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use crossbeam::atomic::AtomicCell;
|
|||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::ffi::c_void;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
|
@ -34,7 +34,7 @@ use vst3_sys::base::{kInvalidArgument, kNoInterface, kResultFalse, kResultOk, tr
|
|||
use vst3_sys::base::{IBStream, IPluginBase, IPluginFactory, IPluginFactory2, IPluginFactory3};
|
||||
use vst3_sys::utils::SharedVstPtr;
|
||||
use vst3_sys::vst::{
|
||||
IAudioProcessor, IComponent, IComponentHandler, IEditController, IParamValueQueue,
|
||||
IAudioProcessor, IComponent, IComponentHandler, IEditController, IEventList, IParamValueQueue,
|
||||
IParameterChanges, TChar,
|
||||
};
|
||||
use vst3_sys::VST3;
|
||||
|
@ -45,7 +45,7 @@ use crate::context::{EventLoop, MainThreadExecutor, OsEventLoop, ProcessContext}
|
|||
use crate::param::internals::ParamPtr;
|
||||
use crate::param::range::Range;
|
||||
use crate::param::Param;
|
||||
use crate::plugin::{BufferConfig, BusConfig, Plugin, ProcessStatus, Vst3Plugin};
|
||||
use crate::plugin::{BufferConfig, BusConfig, NoteEvent, Plugin, ProcessStatus, Vst3Plugin};
|
||||
use crate::wrapper::state::{ParamValue, State};
|
||||
use crate::wrapper::util::{hash_param_id, process_wrapper, strlcpy, u16strlcpy};
|
||||
|
||||
|
@ -122,6 +122,11 @@ struct WrapperInner<'a, P: Plugin> {
|
|||
/// between process calls. This buffer owns the vector, because otherwise it would need to store
|
||||
/// a mutable reference to the data contained in this mutex.
|
||||
output_buffer: RwLock<Buffer<'a>>,
|
||||
/// The incoming events for the plugin, if `P::ACCEPTS_MIDI` is set.
|
||||
///
|
||||
/// TODO: Maybe load these lazily at some point instead of needing to spool them all to this
|
||||
/// queue first
|
||||
input_events: RwLock<VecDeque<NoteEvent>>,
|
||||
|
||||
/// The keys from `param_map` in a stable order.
|
||||
param_hashes: Vec<u32>,
|
||||
|
@ -203,6 +208,7 @@ impl<P: Plugin> WrapperInner<'_, P> {
|
|||
last_process_status: AtomicCell::new(ProcessStatus::Normal),
|
||||
current_latency: AtomicU32::new(0),
|
||||
output_buffer: RwLock::new(Buffer::default()),
|
||||
input_events: RwLock::new(VecDeque::with_capacity(512)),
|
||||
|
||||
param_hashes: Vec::new(),
|
||||
param_by_hash: HashMap::new(),
|
||||
|
@ -1038,6 +1044,36 @@ impl<P: Plugin> IAudioProcessor for Wrapper<'_, P> {
|
|||
}
|
||||
}
|
||||
|
||||
// And also incoming note events if the plugin accepts MDII
|
||||
if P::ACCEPTS_MIDI {
|
||||
let mut input_events = self.inner.input_events.write();
|
||||
if let Some(events) = data.input_events.upgrade() {
|
||||
let num_events = events.get_event_count();
|
||||
|
||||
input_events.clear();
|
||||
let mut event: MaybeUninit<_> = MaybeUninit::uninit();
|
||||
for i in 0..num_events {
|
||||
nih_debug_assert_eq!(events.get_event(i, event.as_mut_ptr()), kResultOk);
|
||||
let event = event.assume_init();
|
||||
if event.type_ == vst3_sys::vst::EventTypes::kNoteOnEvent as u16 {
|
||||
let event = event.event.note_on;
|
||||
input_events.push_back(NoteEvent::NoteOn {
|
||||
channel: event.channel as u8,
|
||||
note: event.pitch as u8,
|
||||
velocity: (event.velocity * 127.0).round() as u8,
|
||||
});
|
||||
} else if event.type_ == vst3_sys::vst::EventTypes::kNoteOffEvent as u16 {
|
||||
let event = event.event.note_off;
|
||||
input_events.push_back(NoteEvent::NoteOff {
|
||||
channel: event.channel as u8,
|
||||
note: event.pitch as u8,
|
||||
velocity: (event.velocity * 127.0).round() as u8,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It's possible the host only wanted to send new parameter values
|
||||
if data.num_outputs == 0 {
|
||||
nih_log!("VST3 parameter flush");
|
||||
|
|
Loading…
Add table
Reference in a new issue