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_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false;
const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
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_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false;
const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
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_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false;
const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
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_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
// 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

View file

@ -103,7 +103,7 @@ impl Plugin for Sine {
const DEFAULT_NUM_INPUTS: u32 = 0;
const DEFAULT_NUM_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = true;
const MIDI_INPUT: MidiConfig = MidiConfig::Basic;
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
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_OUTPUTS: u32 = 2;
const ACCEPTS_MIDI: bool = false;
const MIDI_INPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
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.
const DEFAULT_NUM_OUTPUTS: u32 = 2;
/// Whether the plugin accepts note events. If this is set to `false`, then the plugin won't
/// receive any note events.
const ACCEPTS_MIDI: bool = false;
/// Whether the plugin accepts note events, and which level of . If this is set to
/// [`MidiConfig::None`], then the plugin won't receive any note events.
const MIDI_INPUT: MidiConfig = MidiConfig::None;
/// 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
/// 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,
}
/// Event for (incoming) notes. Right now this only supports a very small subset of the MIDI
/// specification. See the util module for convenient conversion functions.
/// Determines which note events a plugin receives.
#[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.
///
/// TODO: Add more events as needed
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum NoteEvent {
/// A note on event.
/// A note on event, available on [`MidiConfig::Basic`] and up.
NoteOn {
timing: u32,
/// The note's channel, from 0 to 16.
@ -322,7 +337,7 @@ pub enum NoteEvent {
/// 127 levels available in MIDI.
velocity: f32,
},
/// A note off event.
/// A note off event, available on [`MidiConfig::Basic`] and up.
NoteOff {
timing: u32,
/// 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::{BoolParam, FloatParam, IntParam, Param, ParamFlags};
pub use crate::plugin::{
BufferConfig, BusConfig, ClapPlugin, Editor, NoteEvent, ParentWindowHandle, Plugin,
BufferConfig, BusConfig, ClapPlugin, Editor, MidiConfig, NoteEvent, ParentWindowHandle, Plugin,
ProcessStatus, Vst3Plugin,
};
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::ParamFlags;
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::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.
/// Will be set in `clap_plugin::activate()`.
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
/// queue first
@ -867,7 +869,7 @@ impl<P: ClapPlugin> Wrapper<P> {
// true
// }
(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);
input_events.push_back(NoteEvent::NoteOn {
// When splitting up the buffer for sample accurate automation all events
@ -882,7 +884,7 @@ impl<P: ClapPlugin> Wrapper<P> {
false
}
(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);
input_events.push_back(NoteEvent::NoteOff {
timing: raw_event.time - current_sample_idx as u32,
@ -895,7 +897,7 @@ impl<P: ClapPlugin> Wrapper<P> {
false
}
(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 support MIDI CCs
// TODO: Implement pressure and other expressions along with MIDI CCs
@ -904,7 +906,7 @@ impl<P: ClapPlugin> Wrapper<P> {
false
}
(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 support MIDI 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
} else if id == CStr::from_ptr(CLAP_EXT_LATENCY) {
&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
} else if id == CStr::from_ptr(CLAP_EXT_PARAMS) {
&wrapper.clap_plugin_params as *const _ as *const c_void
@ -1618,7 +1620,7 @@ impl<P: ClapPlugin> Wrapper<P> {
// TODO: Implement midi CC handling
// | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_EXPRESSION)
// | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI)
if P::ACCEPTS_MIDI =>
if P::MIDI_INPUT >= MidiConfig::Basic =>
{
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 {
// TODO: Outputting notes
match is_input {
true if P::ACCEPTS_MIDI => 1,
true if P::MIDI_INPUT >= MidiConfig::Basic => 1,
_ => 0,
}
}
@ -1882,7 +1884,7 @@ impl<P: ClapPlugin> Wrapper<P> {
info: *mut clap_note_port_info,
) -> bool {
match (index, is_input) {
(0, true) if P::ACCEPTS_MIDI => {
(0, true) if P::MIDI_INPUT >= MidiConfig::Basic => {
*info = std::mem::zeroed();
let info = &mut *info;

View file

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