1
0
Fork 0

Replace ACCEPTS_MIDI bool with new enum

So we can gate future MIDI CC support behind an additional option since
this involves more work on the VST3 side.
This commit is contained in:
Robbert van der Helm 2022-04-07 20:27:37 +02:00
parent 8f359feadb
commit 1141616466
10 changed files with 47 additions and 30 deletions

View file

@ -70,7 +70,7 @@ impl Plugin for Gain {
const DEFAULT_NUM_INPUTS: u32 = 2; const DEFAULT_NUM_INPUTS: u32 = 2;
const DEFAULT_NUM_OUTPUTS: u32 = 2; const DEFAULT_NUM_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false; const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true; const SAMPLE_ACCURATE_AUTOMATION: bool = true;
fn params(&self) -> Arc<dyn Params> { fn params(&self) -> Arc<dyn Params> {

View file

@ -67,7 +67,7 @@ impl Plugin for Gain {
const DEFAULT_NUM_INPUTS: u32 = 2; const DEFAULT_NUM_INPUTS: u32 = 2;
const DEFAULT_NUM_OUTPUTS: u32 = 2; const DEFAULT_NUM_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false; const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true; const SAMPLE_ACCURATE_AUTOMATION: bool = true;
fn params(&self) -> Arc<dyn Params> { fn params(&self) -> Arc<dyn Params> {

View file

@ -67,7 +67,7 @@ impl Plugin for Gain {
const DEFAULT_NUM_INPUTS: u32 = 2; const DEFAULT_NUM_INPUTS: u32 = 2;
const DEFAULT_NUM_OUTPUTS: u32 = 2; const DEFAULT_NUM_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false; const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true; const SAMPLE_ACCURATE_AUTOMATION: bool = true;
fn params(&self) -> Arc<dyn Params> { fn params(&self) -> Arc<dyn Params> {

View file

@ -103,7 +103,7 @@ impl Plugin for Gain {
const DEFAULT_NUM_INPUTS: u32 = 2; const DEFAULT_NUM_INPUTS: u32 = 2;
const DEFAULT_NUM_OUTPUTS: u32 = 2; const DEFAULT_NUM_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false; const MIDI_INPUT: MidiConfig = MidiConfig::None;
// Setting this to `true` will tell the wrapper to split the buffer up into smaller blocks // Setting this to `true` will tell the wrapper to split the buffer up into smaller blocks
// whenever there are inter-buffer parameter changes. This way no changes to the plugin are // whenever there are inter-buffer parameter changes. This way no changes to the plugin are
// required to support sample accurate automation and the wrapper handles all of the boring // required to support sample accurate automation and the wrapper handles all of the boring

View file

@ -103,7 +103,7 @@ impl Plugin for Sine {
const DEFAULT_NUM_INPUTS: u32 = 0; const DEFAULT_NUM_INPUTS: u32 = 0;
const DEFAULT_NUM_OUTPUTS: u32 = 2; const DEFAULT_NUM_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = true; const MIDI_INPUT: MidiConfig = MidiConfig::Basic;
const SAMPLE_ACCURATE_AUTOMATION: bool = true; const SAMPLE_ACCURATE_AUTOMATION: bool = true;
fn params(&self) -> Arc<dyn Params> { fn params(&self) -> Arc<dyn Params> {

View file

@ -87,7 +87,7 @@ impl Plugin for Stft {
const DEFAULT_NUM_INPUTS: u32 = 2; const DEFAULT_NUM_INPUTS: u32 = 2;
const DEFAULT_NUM_OUTPUTS: u32 = 2; const DEFAULT_NUM_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false; const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true; const SAMPLE_ACCURATE_AUTOMATION: bool = true;
fn params(&self) -> Arc<dyn Params> { fn params(&self) -> Arc<dyn Params> {

View file

@ -41,9 +41,9 @@ pub trait Plugin: Default + Send + Sync + 'static {
/// instead of setting up the busses properly. /// instead of setting up the busses properly.
const DEFAULT_NUM_OUTPUTS: u32 = 2; const DEFAULT_NUM_OUTPUTS: u32 = 2;
/// Whether the plugin accepts note events. If this is set to `false`, then the plugin won't /// Whether the plugin accepts note events, and which level of . If this is set to
/// receive any note events. /// [`MidiConfig::None`], then the plugin won't receive any note events.
const ACCEPTS_MIDI: bool = false; const MIDI_INPUT: MidiConfig = MidiConfig::None;
/// If enabled, the audio processing cycle may be split up into multiple smaller chunks if /// If enabled, the audio processing cycle may be split up into multiple smaller chunks if
/// parameter values change occur in the middle of the buffer. Depending on the host these /// parameter values change occur in the middle of the buffer. Depending on the host these
/// blocks may be as small as a single sample. Bitwig Studio sends at most one parameter change /// blocks may be as small as a single sample. Bitwig Studio sends at most one parameter change
@ -303,15 +303,30 @@ pub enum ProcessStatus {
KeepAlive, KeepAlive,
} }
/// Event for (incoming) notes. Right now this only supports a very small subset of the MIDI /// Determines which note events a plugin receives.
/// specification. See the util module for convenient conversion functions. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum MidiConfig {
/// The plugin will not have a note input port and will thus not receive any not events.
None,
/// The plugin receives note on/off events, pressure, and potentially a couple standardized
/// expression types depending on the plugin standard and host.
Basic,
// // TODO:
// /// The plugin receives full MIDI CCs as well as pitch bend information. For VST3 plugins this
// /// involves adding
// MidiCCs,
}
/// Event for (incoming) notes. The set of supported note events depends on the value of
/// [`Plugin::MIDI_INPUT`]. Also check out the [`util`][crate::util] module for convenient
/// conversion functions.
/// ///
/// All of the timings are sample offsets withing the current buffer. /// All of the timings are sample offsets withing the current buffer.
/// ///
/// TODO: Add more events as needed /// TODO: Add more events as needed
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum NoteEvent { pub enum NoteEvent {
/// A note on event. /// A note on event, available on [`MidiConfig::Basic`] and up.
NoteOn { NoteOn {
timing: u32, timing: u32,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
@ -322,7 +337,7 @@ pub enum NoteEvent {
/// 127 levels available in MIDI. /// 127 levels available in MIDI.
velocity: f32, velocity: f32,
}, },
/// A note off event. /// A note off event, available on [`MidiConfig::Basic`] and up.
NoteOff { NoteOff {
timing: u32, timing: u32,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.

View file

@ -19,7 +19,7 @@ pub use crate::param::range::{FloatRange, IntRange};
pub use crate::param::smoothing::{Smoother, SmoothingStyle}; pub use crate::param::smoothing::{Smoother, SmoothingStyle};
pub use crate::param::{BoolParam, FloatParam, IntParam, Param, ParamFlags}; pub use crate::param::{BoolParam, FloatParam, IntParam, Param, ParamFlags};
pub use crate::plugin::{ pub use crate::plugin::{
BufferConfig, BusConfig, ClapPlugin, Editor, NoteEvent, ParentWindowHandle, Plugin, BufferConfig, BusConfig, ClapPlugin, Editor, MidiConfig, NoteEvent, ParentWindowHandle, Plugin,
ProcessStatus, Vst3Plugin, ProcessStatus, Vst3Plugin,
}; };
pub use crate::wrapper::state::PluginState; pub use crate::wrapper::state::PluginState;

View file

@ -72,7 +72,8 @@ use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
use crate::param::internals::{ParamPtr, Params}; use crate::param::internals::{ParamPtr, Params};
use crate::param::ParamFlags; use crate::param::ParamFlags;
use crate::plugin::{ use crate::plugin::{
BufferConfig, BusConfig, ClapPlugin, Editor, NoteEvent, ParentWindowHandle, ProcessStatus, BufferConfig, BusConfig, ClapPlugin, Editor, MidiConfig, NoteEvent, ParentWindowHandle,
ProcessStatus,
}; };
use crate::util::permit_alloc; use crate::util::permit_alloc;
use crate::wrapper::state::{self, PluginState}; use crate::wrapper::state::{self, PluginState};
@ -116,7 +117,8 @@ pub struct Wrapper<P: ClapPlugin> {
/// The current buffer configuration, containing the sample rate and the maximum block size. /// The current buffer configuration, containing the sample rate and the maximum block size.
/// Will be set in `clap_plugin::activate()`. /// Will be set in `clap_plugin::activate()`.
current_buffer_config: AtomicCell<Option<BufferConfig>>, current_buffer_config: AtomicCell<Option<BufferConfig>>,
/// The incoming events for the plugin, if `P::ACCEPTS_MIDI` is set. /// The incoming events for the plugin, if `P::MIDI_INPUT` is set to `MidiConfig::Basic` or
/// higher.
/// ///
/// TODO: Maybe load these lazily at some point instead of needing to spool them all to this /// TODO: Maybe load these lazily at some point instead of needing to spool them all to this
/// queue first /// queue first
@ -867,7 +869,7 @@ impl<P: ClapPlugin> Wrapper<P> {
// true // true
// } // }
(CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_ON) => { (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_ON) => {
if P::ACCEPTS_MIDI { if P::MIDI_INPUT >= MidiConfig::Basic {
let event = &*(event as *const clap_event_note); let event = &*(event as *const clap_event_note);
input_events.push_back(NoteEvent::NoteOn { input_events.push_back(NoteEvent::NoteOn {
// When splitting up the buffer for sample accurate automation all events // When splitting up the buffer for sample accurate automation all events
@ -882,7 +884,7 @@ impl<P: ClapPlugin> Wrapper<P> {
false false
} }
(CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_OFF) => { (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_OFF) => {
if P::ACCEPTS_MIDI { if P::MIDI_INPUT >= MidiConfig::Basic {
let event = &*(event as *const clap_event_note); let event = &*(event as *const clap_event_note);
input_events.push_back(NoteEvent::NoteOff { input_events.push_back(NoteEvent::NoteOff {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
@ -895,7 +897,7 @@ impl<P: ClapPlugin> Wrapper<P> {
false false
} }
(CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_EXPRESSION) => { (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_EXPRESSION) => {
if P::ACCEPTS_MIDI { if P::MIDI_INPUT >= MidiConfig::Basic {
// We currently don't report supporting this at all in the event filter, add that once // We currently don't report supporting this at all in the event filter, add that once
// we support MIDI CCs // we support MIDI CCs
// TODO: Implement pressure and other expressions along with MIDI CCs // TODO: Implement pressure and other expressions along with MIDI CCs
@ -904,7 +906,7 @@ impl<P: ClapPlugin> Wrapper<P> {
false false
} }
(CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI) => { (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI) => {
if P::ACCEPTS_MIDI { if P::MIDI_INPUT >= MidiConfig::Basic {
// We currently don't report supporting this at all in the event filter, add that once // We currently don't report supporting this at all in the event filter, add that once
// we support MIDI CCs // we support MIDI CCs
// TODO: Implement raw MIDI handling once we add CCs // TODO: Implement raw MIDI handling once we add CCs
@ -1392,7 +1394,7 @@ impl<P: ClapPlugin> Wrapper<P> {
&wrapper.clap_plugin_gui as *const _ as *const c_void &wrapper.clap_plugin_gui as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_LATENCY) { } else if id == CStr::from_ptr(CLAP_EXT_LATENCY) {
&wrapper.clap_plugin_latency as *const _ as *const c_void &wrapper.clap_plugin_latency as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_NOTE_PORTS) && P::ACCEPTS_MIDI { } else if id == CStr::from_ptr(CLAP_EXT_NOTE_PORTS) && P::MIDI_INPUT >= MidiConfig::Basic {
&wrapper.clap_plugin_note_ports as *const _ as *const c_void &wrapper.clap_plugin_note_ports as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_PARAMS) { } else if id == CStr::from_ptr(CLAP_EXT_PARAMS) {
&wrapper.clap_plugin_params as *const _ as *const c_void &wrapper.clap_plugin_params as *const _ as *const c_void
@ -1618,7 +1620,7 @@ impl<P: ClapPlugin> Wrapper<P> {
// TODO: Implement midi CC handling // TODO: Implement midi CC handling
// | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_EXPRESSION) // | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_EXPRESSION)
// | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI) // | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI)
if P::ACCEPTS_MIDI => if P::MIDI_INPUT >= MidiConfig::Basic =>
{ {
true true
} }
@ -1870,7 +1872,7 @@ impl<P: ClapPlugin> Wrapper<P> {
unsafe extern "C" fn ext_note_ports_count(_plugin: *const clap_plugin, is_input: bool) -> u32 { unsafe extern "C" fn ext_note_ports_count(_plugin: *const clap_plugin, is_input: bool) -> u32 {
// TODO: Outputting notes // TODO: Outputting notes
match is_input { match is_input {
true if P::ACCEPTS_MIDI => 1, true if P::MIDI_INPUT >= MidiConfig::Basic => 1,
_ => 0, _ => 0,
} }
} }
@ -1882,7 +1884,7 @@ impl<P: ClapPlugin> Wrapper<P> {
info: *mut clap_note_port_info, info: *mut clap_note_port_info,
) -> bool { ) -> bool {
match (index, is_input) { match (index, is_input) {
(0, true) if P::ACCEPTS_MIDI => { (0, true) if P::MIDI_INPUT >= MidiConfig::Basic => {
*info = std::mem::zeroed(); *info = std::mem::zeroed();
let info = &mut *info; let info = &mut *info;

View file

@ -19,7 +19,7 @@ use super::util::VstPtr;
use super::view::WrapperView; use super::view::WrapperView;
use crate::context::Transport; use crate::context::Transport;
use crate::param::ParamFlags; use crate::param::ParamFlags;
use crate::plugin::{BufferConfig, BusConfig, NoteEvent, ProcessStatus, Vst3Plugin}; use crate::plugin::{BufferConfig, BusConfig, MidiConfig, NoteEvent, ProcessStatus, Vst3Plugin};
use crate::util::permit_alloc; use crate::util::permit_alloc;
use crate::wrapper::state; use crate::wrapper::state;
use crate::wrapper::util::{process_wrapper, u16strlcpy}; use crate::wrapper::util::{process_wrapper, u16strlcpy};
@ -71,7 +71,7 @@ impl<P: Vst3Plugin> IComponent for Wrapper<P> {
x if x == vst3_sys::vst::MediaTypes::kAudio as i32 => 1, x if x == vst3_sys::vst::MediaTypes::kAudio as i32 => 1,
x if x == vst3_sys::vst::MediaTypes::kEvent as i32 x if x == vst3_sys::vst::MediaTypes::kEvent as i32
&& dir == vst3_sys::vst::BusDirections::kInput as i32 && dir == vst3_sys::vst::BusDirections::kInput as i32
&& P::ACCEPTS_MIDI => && P::MIDI_INPUT >= MidiConfig::Basic =>
{ {
1 1
} }
@ -119,7 +119,7 @@ impl<P: Vst3Plugin> IComponent for Wrapper<P> {
(t, d, 0) (t, d, 0)
if t == vst3_sys::vst::MediaTypes::kEvent as i32 if t == vst3_sys::vst::MediaTypes::kEvent as i32
&& d == vst3_sys::vst::BusDirections::kInput as i32 && d == vst3_sys::vst::BusDirections::kInput as i32
&& P::ACCEPTS_MIDI => && P::MIDI_INPUT >= MidiConfig::Basic =>
{ {
*info = mem::zeroed(); *info = mem::zeroed();
@ -172,7 +172,7 @@ impl<P: Vst3Plugin> IComponent for Wrapper<P> {
(t, d, 0) (t, d, 0)
if t == vst3_sys::vst::MediaTypes::kEvent as i32 if t == vst3_sys::vst::MediaTypes::kEvent as i32
&& d == vst3_sys::vst::BusDirections::kInput as i32 && d == vst3_sys::vst::BusDirections::kInput as i32
&& P::ACCEPTS_MIDI => && P::MIDI_INPUT >= MidiConfig::Basic =>
{ {
kResultOk kResultOk
} }
@ -743,7 +743,7 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
parameter_values_changed = false; parameter_values_changed = false;
} }
if P::ACCEPTS_MIDI { if P::MIDI_INPUT >= MidiConfig::Basic {
let mut input_events = self.inner.input_events.borrow_mut(); let mut input_events = self.inner.input_events.borrow_mut();
if let Some(events) = data.input_events.upgrade() { if let Some(events) = data.input_events.upgrade() {
let num_events = events.get_event_count(); let num_events = events.get_event_count();