From 24837d1552bfac0ae1f491e0a6a6c586a4c4865d Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Thu, 7 Apr 2022 23:28:31 +0200 Subject: [PATCH] Implement full MIDI support for CLAP --- Cargo.lock | 7 ++ Cargo.toml | 1 + README.md | 4 +- src/context.rs | 2 +- src/lib.rs | 1 + src/midi.rs | 181 ++++++++++++++++++++++++++++++++++++ src/plugin.rs | 148 +---------------------------- src/prelude.rs | 5 +- src/wrapper/clap/context.rs | 3 +- src/wrapper/clap/wrapper.rs | 72 ++++++++++---- src/wrapper/vst3/context.rs | 3 +- src/wrapper/vst3/inner.rs | 3 +- src/wrapper/vst3/wrapper.rs | 3 +- 13 files changed, 260 insertions(+), 173 deletions(-) create mode 100644 src/midi.rs diff --git a/Cargo.lock b/Cargo.lock index 17cc12d2..e5f469d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1934,6 +1934,12 @@ dependencies = [ "objc", ] +[[package]] +name = "midi-consts" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2dd5c7f8aaf48a76e389068ab25ed80bdbc226b887f9013844c415698c9952" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2013,6 +2019,7 @@ dependencies = [ "clap-sys", "crossbeam", "lazy_static", + "midi-consts", "nih_plug_derive", "parking_lot 0.12.0", "raw-window-handle", diff --git a/Cargo.toml b/Cargo.toml index b24bc9ed..d77fb6a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ cfg-if = "1.0" clap-sys = { git = "https://github.com/robbert-vdh/clap-sys", branch = "update/clap-0.24" } crossbeam = "0.8" lazy_static = "1.4" +midi-consts = "0.1" parking_lot = "0.12" raw-window-handle = "0.4" serde = { version = "1.0", features = ["derive"] } diff --git a/README.md b/README.md index 405a4e22..2623533c 100644 --- a/README.md +++ b/README.md @@ -90,8 +90,8 @@ for download links. - A simple and safe API for state saving and restoring from the editor is provided by the framework if you want to do your own internal preset management. -- Basic note/MIDI support. MIDI CC handling and note output is currently not - implemented. Let me know if you need this. +- Basic note/MIDI support for VST3, full support for both expressions and MIDI + CCs for CLAP. Similar support for VST3 is coming. - A plugin bundler accessible through the `cargo xtask bundle ` command that automatically detects which plugin targets your plugin exposes and creates the correct diff --git a/src/context.rs b/src/context.rs index b934f0f1..e2eec046 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,8 +1,8 @@ //! Different contexts the plugin can use to make callbacks to the host in different...contexts. +use crate::midi::NoteEvent; use crate::param::internals::ParamPtr; use crate::param::Param; -use crate::plugin::NoteEvent; use crate::wrapper::state::PluginState; // TODO: ProcessContext for parameter automation and sending events diff --git a/src/lib.rs b/src/lib.rs index 35db5892..c75a9f95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod util; pub mod buffer; pub mod context; mod event_loop; +pub mod midi; pub mod param; pub mod plugin; pub mod wrapper; diff --git a/src/midi.rs b/src/midi.rs new file mode 100644 index 00000000..4cfdf194 --- /dev/null +++ b/src/midi.rs @@ -0,0 +1,181 @@ +//! Constants and definitions surrounding MIDI support. + +pub use midi_consts::channel_event::control_change; + +/// 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, + /// The plugin receives full MIDI CCs as well as pitch bend information. For VST3 plugins this + /// involves adding 130*16 parameters to bind to the the 128 MIDI CCs, pitch bend, and channel + /// pressure. + 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, Clone, Copy, PartialEq)] +#[non_exhaustive] +pub enum NoteEvent { + /// A note on event, available on [`MidiConfig::Basic`] and up. + NoteOn { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's velocity, from 0 to 1. Some plugin APIs may allow higher precision than the + /// 127 levels available in MIDI. + velocity: f32, + }, + /// A note off event, available on [`MidiConfig::Basic`] and up. + NoteOff { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's velocity, from 0 to 1. Some plugin APIs may allow higher precision than the + /// 127 levels available in MIDI. + velocity: f32, + }, + /// A polyphonic note pressure/aftertouch event, available on [`MidiConfig::Basic`] and up. Not + /// all hosts may support polyphonic aftertouch. + PolyPressure { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's pressure, from 0 to 1. + pressure: f32, + }, + /// A volume expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may + /// support these expressions. + Volume { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's voltage gain ratio, where 1.0 is unity gain. + gain: f32, + }, + /// A panning expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may + /// support these expressions. + Pan { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's panning from, from -1 to 1, with -1 being panned hard left, and 1 being + /// panned hard right. + pan: f32, + }, + /// A tuning expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may support + /// these expressions. + Tuning { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's tuning in semitones, from -120 to 120. + tuning: f32, + }, + /// A vibrato expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may support + /// these expressions. + Vibrato { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's vibrato amount, from 0 to 1. + vibrato: f32, + }, + /// A expression expression (yes, expression expression) event, available on + /// [`MidiConfig::Basic`] and up. Not all hosts may support these expressions. + Expression { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's expression amount, from 0 to 1. + expression: f32, + }, + /// A brightness expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may support + /// these expressions. + Brightness { + timing: u32, + /// The note's channel, from 0 to 16. + channel: u8, + /// The note's MIDI key number, from 0 to 127. + note: u8, + /// The note's brightness amount, from 0 to 1. + brightness: f32, + }, + /// A MIDI channel pressure event, available on [`MidiConfig::MidiCCs`] and up. + MidiChannelPressure { + timing: u32, + /// The affected channel, from 0 to 16. + channel: u8, + /// The pressure, normalized to `[0, 1]` to match the poly pressure event. + pressure: f32, + }, + /// A MIDI pitch bend, available on [`MidiConfig::MidiCCs`] and up. + MidiPitchBend { + timing: u32, + /// The affected channel, from 0 to 16. + channel: u8, + /// The pressure, normalized to `[0, 1]`. `0.5` means no pitch bend. + value: f32, + }, + /// A MIDI control change event, available on [`MidiConfig::MidiCCs`] and up. + /// + /// # Note + /// + /// The wrapper does not perform any special handling for two message 14-bit CCs (where the CC + /// number is in the range `[0, 31]`, and the next CC is that number plus 32) or for four + /// message RPN messages. For now you will need to handle these CCs yourself. + MidiCC { + timing: u32, + /// The affected channel, from 0 to 16. + channel: u8, + /// The control change number. See [`control_change`] for a list of CC numbers. + cc: u8, + /// The CC's value, normalized to `[0, 1]`. Multiply by 127 to get the original raw value. + value: f32, + }, +} + +impl NoteEvent { + /// Return the sample within the current buffer this event belongs to. + pub fn timing(&self) -> u32 { + match &self { + NoteEvent::NoteOn { timing, .. } => *timing, + NoteEvent::NoteOff { timing, .. } => *timing, + NoteEvent::PolyPressure { timing, .. } => *timing, + NoteEvent::Volume { timing, .. } => *timing, + NoteEvent::Pan { timing, .. } => *timing, + NoteEvent::Tuning { timing, .. } => *timing, + NoteEvent::Vibrato { timing, .. } => *timing, + NoteEvent::Expression { timing, .. } => *timing, + NoteEvent::Brightness { timing, .. } => *timing, + NoteEvent::MidiChannelPressure { timing, .. } => *timing, + NoteEvent::MidiPitchBend { timing, .. } => *timing, + NoteEvent::MidiCC { timing, .. } => *timing, + } + } +} diff --git a/src/plugin.rs b/src/plugin.rs index ed8e6696..54567e73 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use crate::buffer::Buffer; use crate::context::{GuiContext, ProcessContext}; +use crate::midi::MidiConfig; use crate::param::internals::Params; /// Basic functionality that needs to be implemented by a plugin. The wrappers will use this to @@ -20,7 +21,7 @@ use crate::param::internals::Params; /// - Sidechain inputs /// - Multiple output busses /// - Special handling for offline processing -/// - MIDI CC handling +/// - MIDI CC and expression handling for VST3 (those things are implemented for CLAP) /// - Outputting MIDI events from the process function (you can output parmaeter changes from an /// editor GUI) #[allow(unused_variables)] @@ -302,148 +303,3 @@ pub enum ProcessStatus { /// infite tail. KeepAlive, } - -/// 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 130*16 parameters to bind to the the 128 MIDI CCs, pitch bend, and channel - // /// pressure. - // 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, Clone, Copy, PartialEq)] -#[non_exhaustive] -pub enum NoteEvent { - /// A note on event, available on [`MidiConfig::Basic`] and up. - NoteOn { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's velocity, from 0 to 1. Some plugin APIs may allow higher precision than the - /// 127 levels available in MIDI. - velocity: f32, - }, - /// A note off event, available on [`MidiConfig::Basic`] and up. - NoteOff { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's velocity, from 0 to 1. Some plugin APIs may allow higher precision than the - /// 127 levels available in MIDI. - velocity: f32, - }, - /// A polyphonic note pressure/aftertouch event, available on [`MidiConfig::Basic`] and up. Not - /// all hosts may support polyphonic aftertouch. - PolyPressure { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's pressure, from 0 to 1. - pressure: f32, - }, - /// A volume expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may - /// support these expressions. - Volume { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's voltage gain ratio, where 1.0 is unity gain. - gain: f32, - }, - /// A panning expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may - /// support these expressions. - Pan { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's panning from, from -1 to 1, with -1 being panned hard left, and 1 being - /// panned hard right. - pan: f32, - }, - /// A tuning expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may support - /// these expressions. - Tuning { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's tuning in semitones, from -120 to 120. - tuning: f32, - }, - /// A vibrato expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may support - /// these expressions. - Vibrato { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's vibrato amount, from 0 to 1. - vibrato: f32, - }, - /// A expression expression (yes, expression expression) event, available on - /// [`MidiConfig::Basic`] and up. Not all hosts may support these expressions. - Expression { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's expression amount, from 0 to 1. - expression: f32, - }, - /// A brightness expression event, available on [`MidiConfig::Basic`] and up. Not all hosts may support - /// these expressions. - Brightness { - timing: u32, - /// The note's channel, from 0 to 16. - channel: u8, - /// The note's MIDI key number, from 0 to 127. - note: u8, - /// The note's brightness amount, from 0 to 1. - brightness: f32, - }, - // TODO: Add MIDI channel pressure, pitchbend, and CCs -} - -impl NoteEvent { - /// Return the sample within the current buffer this event belongs to. - pub fn timing(&self) -> u32 { - match &self { - NoteEvent::NoteOn { timing, .. } => *timing, - NoteEvent::NoteOff { timing, .. } => *timing, - NoteEvent::PolyPressure { timing, .. } => *timing, - NoteEvent::Volume { timing, .. } => *timing, - NoteEvent::Pan { timing, .. } => *timing, - NoteEvent::Tuning { timing, .. } => *timing, - NoteEvent::Vibrato { timing, .. } => *timing, - NoteEvent::Expression { timing, .. } => *timing, - NoteEvent::Brightness { timing, .. } => *timing, - } - } -} diff --git a/src/prelude.rs b/src/prelude.rs index bc01fa3d..52efcb0b 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -13,13 +13,14 @@ pub use crate::util; pub use crate::buffer::Buffer; pub use crate::context::{GuiContext, ParamSetter, ProcessContext}; // This also includes the derive macro +pub use crate::midi::{control_change, MidiConfig, NoteEvent}; pub use crate::param::enums::{Enum, EnumParam}; pub use crate::param::internals::{ParamPtr, Params}; 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, MidiConfig, NoteEvent, ParentWindowHandle, Plugin, - ProcessStatus, Vst3Plugin, + BufferConfig, BusConfig, ClapPlugin, Editor, ParentWindowHandle, Plugin, ProcessStatus, + Vst3Plugin, }; pub use crate::wrapper::state::PluginState; diff --git a/src/wrapper/clap/context.rs b/src/wrapper/clap/context.rs index a06f7ea4..ea24d50b 100644 --- a/src/wrapper/clap/context.rs +++ b/src/wrapper/clap/context.rs @@ -6,8 +6,9 @@ use std::sync::Arc; use super::wrapper::{OutputParamEvent, Task, Wrapper}; use crate::context::{GuiContext, ProcessContext, Transport}; use crate::event_loop::EventLoop; +use crate::midi::NoteEvent; use crate::param::internals::ParamPtr; -use crate::plugin::{ClapPlugin, NoteEvent}; +use crate::plugin::ClapPlugin; /// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in /// [`Editor::spawn()`][crate::prelude::Editor::spawn()] so it can interact with the rest of the plugin and diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index 7348a9a4..2e10abf9 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -5,16 +5,17 @@ use atomic_float::AtomicF32; use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use clap_sys::events::{ - clap_event_header, clap_event_note, clap_event_note_expression, clap_event_param_gesture, - clap_event_param_value, clap_event_type, clap_input_events, clap_output_events, - CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_IS_LIVE, CLAP_EVENT_MIDI, CLAP_EVENT_NOTE_EXPRESSION, - CLAP_EVENT_NOTE_OFF, CLAP_EVENT_NOTE_ON, CLAP_EVENT_PARAM_GESTURE_BEGIN, - CLAP_EVENT_PARAM_GESTURE_END, CLAP_EVENT_PARAM_VALUE, CLAP_NOTE_EXPRESSION_BRIGHTNESS, - CLAP_NOTE_EXPRESSION_EXPRESSION, CLAP_NOTE_EXPRESSION_PAN, CLAP_NOTE_EXPRESSION_PRESSURE, - CLAP_NOTE_EXPRESSION_TUNING, CLAP_NOTE_EXPRESSION_VIBRATO, CLAP_NOTE_EXPRESSION_VOLUME, - CLAP_TRANSPORT_HAS_BEATS_TIMELINE, CLAP_TRANSPORT_HAS_SECONDS_TIMELINE, - CLAP_TRANSPORT_HAS_TEMPO, CLAP_TRANSPORT_HAS_TIME_SIGNATURE, CLAP_TRANSPORT_IS_LOOP_ACTIVE, - CLAP_TRANSPORT_IS_PLAYING, CLAP_TRANSPORT_IS_RECORDING, CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL, + clap_event_header, clap_event_midi, clap_event_note, clap_event_note_expression, + clap_event_param_gesture, clap_event_param_value, clap_event_type, clap_input_events, + clap_output_events, CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_IS_LIVE, CLAP_EVENT_MIDI, + CLAP_EVENT_NOTE_EXPRESSION, CLAP_EVENT_NOTE_OFF, CLAP_EVENT_NOTE_ON, + CLAP_EVENT_PARAM_GESTURE_BEGIN, CLAP_EVENT_PARAM_GESTURE_END, CLAP_EVENT_PARAM_VALUE, + CLAP_NOTE_EXPRESSION_BRIGHTNESS, CLAP_NOTE_EXPRESSION_EXPRESSION, CLAP_NOTE_EXPRESSION_PAN, + CLAP_NOTE_EXPRESSION_PRESSURE, CLAP_NOTE_EXPRESSION_TUNING, CLAP_NOTE_EXPRESSION_VIBRATO, + CLAP_NOTE_EXPRESSION_VOLUME, CLAP_TRANSPORT_HAS_BEATS_TIMELINE, + CLAP_TRANSPORT_HAS_SECONDS_TIMELINE, CLAP_TRANSPORT_HAS_TEMPO, + CLAP_TRANSPORT_HAS_TIME_SIGNATURE, CLAP_TRANSPORT_IS_LOOP_ACTIVE, CLAP_TRANSPORT_IS_PLAYING, + CLAP_TRANSPORT_IS_RECORDING, CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL, }; use clap_sys::ext::audio_ports::{ clap_audio_port_info, clap_plugin_audio_ports, CLAP_AUDIO_PORT_IS_MAIN, CLAP_EXT_AUDIO_PORTS, @@ -52,6 +53,7 @@ use clap_sys::stream::{clap_istream, clap_ostream}; use crossbeam::atomic::AtomicCell; use crossbeam::channel::{self, SendTimeoutError}; use crossbeam::queue::ArrayQueue; +use midi_consts::channel_event as midi; use parking_lot::RwLock; use raw_window_handle::RawWindowHandle; use std::any::Any; @@ -72,11 +74,11 @@ use super::util::ClapPtr; use crate::buffer::Buffer; use crate::context::Transport; use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY}; +use crate::midi::{MidiConfig, NoteEvent}; use crate::param::internals::{ParamPtr, Params}; use crate::param::ParamFlags; use crate::plugin::{ - BufferConfig, BusConfig, ClapPlugin, Editor, MidiConfig, NoteEvent, ParentWindowHandle, - ProcessStatus, + BufferConfig, BusConfig, ClapPlugin, Editor, ParentWindowHandle, ProcessStatus, }; use crate::util::permit_alloc; use crate::wrapper::state::{self, PluginState}; @@ -968,10 +970,43 @@ impl Wrapper

{ false } (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_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 + // TODO: We can also handle note on, note off, and polyphonic pressure events, but + // the host should not be sending us those since we prefer CLAP-style events + // on our note ports + if P::MIDI_INPUT >= MidiConfig::MidiCCs { + let event = &*(event as *const clap_event_midi); + + // TODO: Maybe add special handling for 14-bit CCs and RPN messages at some + // point, right now the plugin has to figure it out for itself + let event_type = event.data[0] & midi::EVENT_TYPE_MASK; + let channel = event.data[0] & midi::MIDI_CHANNEL_MASK; + match event_type { + midi::CHANNEL_KEY_PRESSURE => { + input_events.push_back(NoteEvent::MidiChannelPressure { + timing: raw_event.time - current_sample_idx as u32, + channel, + pressure: event.data[1] as f32 / 127.0, + }); + } + midi::PITCH_BEND_CHANGE => { + input_events.push_back(NoteEvent::MidiPitchBend { + timing: raw_event.time - current_sample_idx as u32, + channel, + value: (event.data[1] as u16 + ((event.data[2] as u16) << 7)) + as f32 + / ((1 << 14) - 1) as f32, + }); + } + midi::CONTROL_CHANGE => { + input_events.push_back(NoteEvent::MidiCC { + timing: raw_event.time - current_sample_idx as u32, + channel, + cc: event.data[1], + value: event.data[2] as f32 / 127.0, + }); + } + n => nih_debug_assert_failure!("Unhandled MIDI message type {}", n), + }; } false @@ -1680,12 +1715,13 @@ impl Wrapper

{ (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_ON) | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_OFF) | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_EXPRESSION) - // TODO: Implement midi CC handling - // | (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI) if P::MIDI_INPUT >= MidiConfig::Basic => { true } + (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI) if P::MIDI_INPUT >= MidiConfig::MidiCCs => { + true + } _ => false, } } diff --git a/src/wrapper/vst3/context.rs b/src/wrapper/vst3/context.rs index 20e3d920..beeae62d 100644 --- a/src/wrapper/vst3/context.rs +++ b/src/wrapper/vst3/context.rs @@ -7,8 +7,9 @@ use vst3_sys::vst::{IComponentHandler, RestartFlags}; use super::inner::{Task, WrapperInner}; use crate::context::{GuiContext, ProcessContext, Transport}; use crate::event_loop::EventLoop; +use crate::midi::NoteEvent; use crate::param::internals::ParamPtr; -use crate::plugin::{NoteEvent, Vst3Plugin}; +use crate::plugin::Vst3Plugin; use crate::wrapper::state::PluginState; /// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in diff --git a/src/wrapper/vst3/inner.rs b/src/wrapper/vst3/inner.rs index 94eef9dd..8206523c 100644 --- a/src/wrapper/vst3/inner.rs +++ b/src/wrapper/vst3/inner.rs @@ -18,9 +18,10 @@ use super::view::WrapperView; use crate::buffer::Buffer; use crate::context::Transport; use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop}; +use crate::midi::NoteEvent; use crate::param::internals::{ParamPtr, Params}; use crate::param::ParamFlags; -use crate::plugin::{BufferConfig, BusConfig, Editor, NoteEvent, ProcessStatus, Vst3Plugin}; +use crate::plugin::{BufferConfig, BusConfig, Editor, ProcessStatus, Vst3Plugin}; use crate::wrapper::state::{self, PluginState}; use crate::wrapper::util::{hash_param_id, process_wrapper}; diff --git a/src/wrapper/vst3/wrapper.rs b/src/wrapper/vst3/wrapper.rs index a5330fd6..f57d2ab0 100644 --- a/src/wrapper/vst3/wrapper.rs +++ b/src/wrapper/vst3/wrapper.rs @@ -18,8 +18,9 @@ use super::inner::WrapperInner; use super::util::VstPtr; use super::view::WrapperView; use crate::context::Transport; +use crate::midi::{MidiConfig, NoteEvent}; use crate::param::ParamFlags; -use crate::plugin::{BufferConfig, BusConfig, MidiConfig, NoteEvent, ProcessStatus, Vst3Plugin}; +use crate::plugin::{BufferConfig, BusConfig, ProcessStatus, Vst3Plugin}; use crate::util::permit_alloc; use crate::wrapper::state; use crate::wrapper::util::{process_wrapper, u16strlcpy};