1
0
Fork 0

Implement full MIDI support for CLAP

This commit is contained in:
Robbert van der Helm 2022-04-07 23:28:31 +02:00
parent 0b3a5cd297
commit 24837d1552
13 changed files with 260 additions and 173 deletions

7
Cargo.lock generated
View file

@ -1934,6 +1934,12 @@ dependencies = [
"objc", "objc",
] ]
[[package]]
name = "midi-consts"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f2dd5c7f8aaf48a76e389068ab25ed80bdbc226b887f9013844c415698c9952"
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@ -2013,6 +2019,7 @@ dependencies = [
"clap-sys", "clap-sys",
"crossbeam", "crossbeam",
"lazy_static", "lazy_static",
"midi-consts",
"nih_plug_derive", "nih_plug_derive",
"parking_lot 0.12.0", "parking_lot 0.12.0",
"raw-window-handle", "raw-window-handle",

View file

@ -52,6 +52,7 @@ cfg-if = "1.0"
clap-sys = { git = "https://github.com/robbert-vdh/clap-sys", branch = "update/clap-0.24" } clap-sys = { git = "https://github.com/robbert-vdh/clap-sys", branch = "update/clap-0.24" }
crossbeam = "0.8" crossbeam = "0.8"
lazy_static = "1.4" lazy_static = "1.4"
midi-consts = "0.1"
parking_lot = "0.12" parking_lot = "0.12"
raw-window-handle = "0.4" raw-window-handle = "0.4"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View file

@ -90,8 +90,8 @@ for download links.
- A simple and safe API for state saving and restoring from the editor is - 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 provided by the framework if you want to do your own internal preset
management. management.
- Basic note/MIDI support. MIDI CC handling and note output is currently not - Basic note/MIDI support for VST3, full support for both expressions and MIDI
implemented. Let me know if you need this. CCs for CLAP. Similar support for VST3 is coming.
- A plugin bundler accessible through the - A plugin bundler accessible through the
`cargo xtask bundle <package> <build_arguments>` command that automatically `cargo xtask bundle <package> <build_arguments>` command that automatically
detects which plugin targets your plugin exposes and creates the correct detects which plugin targets your plugin exposes and creates the correct

View file

@ -1,8 +1,8 @@
//! Different contexts the plugin can use to make callbacks to the host in different...contexts. //! 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::internals::ParamPtr;
use crate::param::Param; use crate::param::Param;
use crate::plugin::NoteEvent;
use crate::wrapper::state::PluginState; use crate::wrapper::state::PluginState;
// TODO: ProcessContext for parameter automation and sending events // TODO: ProcessContext for parameter automation and sending events

View file

@ -16,6 +16,7 @@ pub mod util;
pub mod buffer; pub mod buffer;
pub mod context; pub mod context;
mod event_loop; mod event_loop;
pub mod midi;
pub mod param; pub mod param;
pub mod plugin; pub mod plugin;
pub mod wrapper; pub mod wrapper;

181
src/midi.rs Normal file
View file

@ -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,
}
}
}

View file

@ -6,6 +6,7 @@ use std::sync::Arc;
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::context::{GuiContext, ProcessContext}; use crate::context::{GuiContext, ProcessContext};
use crate::midi::MidiConfig;
use crate::param::internals::Params; use crate::param::internals::Params;
/// Basic functionality that needs to be implemented by a plugin. The wrappers will use this to /// 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 /// - Sidechain inputs
/// - Multiple output busses /// - Multiple output busses
/// - Special handling for offline processing /// - 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 /// - Outputting MIDI events from the process function (you can output parmaeter changes from an
/// editor GUI) /// editor GUI)
#[allow(unused_variables)] #[allow(unused_variables)]
@ -302,148 +303,3 @@ pub enum ProcessStatus {
/// infite tail. /// infite tail.
KeepAlive, 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,
}
}
}

View file

@ -13,13 +13,14 @@ pub use crate::util;
pub use crate::buffer::Buffer; pub use crate::buffer::Buffer;
pub use crate::context::{GuiContext, ParamSetter, ProcessContext}; pub use crate::context::{GuiContext, ParamSetter, ProcessContext};
// This also includes the derive macro // 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::enums::{Enum, EnumParam};
pub use crate::param::internals::{ParamPtr, Params}; pub use crate::param::internals::{ParamPtr, Params};
pub use crate::param::range::{FloatRange, IntRange}; 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, MidiConfig, NoteEvent, ParentWindowHandle, Plugin, BufferConfig, BusConfig, ClapPlugin, Editor, ParentWindowHandle, Plugin, ProcessStatus,
ProcessStatus, Vst3Plugin, Vst3Plugin,
}; };
pub use crate::wrapper::state::PluginState; pub use crate::wrapper::state::PluginState;

View file

@ -6,8 +6,9 @@ use std::sync::Arc;
use super::wrapper::{OutputParamEvent, Task, Wrapper}; use super::wrapper::{OutputParamEvent, Task, Wrapper};
use crate::context::{GuiContext, ProcessContext, Transport}; use crate::context::{GuiContext, ProcessContext, Transport};
use crate::event_loop::EventLoop; use crate::event_loop::EventLoop;
use crate::midi::NoteEvent;
use crate::param::internals::ParamPtr; 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 /// 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 /// [`Editor::spawn()`][crate::prelude::Editor::spawn()] so it can interact with the rest of the plugin and

View file

@ -5,16 +5,17 @@
use atomic_float::AtomicF32; use atomic_float::AtomicF32;
use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use clap_sys::events::{ use clap_sys::events::{
clap_event_header, clap_event_note, clap_event_note_expression, clap_event_param_gesture, clap_event_header, clap_event_midi, clap_event_note, clap_event_note_expression,
clap_event_param_value, clap_event_type, clap_input_events, clap_output_events, clap_event_param_gesture, clap_event_param_value, clap_event_type, clap_input_events,
CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_IS_LIVE, CLAP_EVENT_MIDI, CLAP_EVENT_NOTE_EXPRESSION, clap_output_events, CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_IS_LIVE, CLAP_EVENT_MIDI,
CLAP_EVENT_NOTE_OFF, CLAP_EVENT_NOTE_ON, CLAP_EVENT_PARAM_GESTURE_BEGIN, CLAP_EVENT_NOTE_EXPRESSION, CLAP_EVENT_NOTE_OFF, CLAP_EVENT_NOTE_ON,
CLAP_EVENT_PARAM_GESTURE_END, CLAP_EVENT_PARAM_VALUE, CLAP_NOTE_EXPRESSION_BRIGHTNESS, CLAP_EVENT_PARAM_GESTURE_BEGIN, CLAP_EVENT_PARAM_GESTURE_END, CLAP_EVENT_PARAM_VALUE,
CLAP_NOTE_EXPRESSION_EXPRESSION, CLAP_NOTE_EXPRESSION_PAN, CLAP_NOTE_EXPRESSION_PRESSURE, CLAP_NOTE_EXPRESSION_BRIGHTNESS, CLAP_NOTE_EXPRESSION_EXPRESSION, CLAP_NOTE_EXPRESSION_PAN,
CLAP_NOTE_EXPRESSION_TUNING, CLAP_NOTE_EXPRESSION_VIBRATO, CLAP_NOTE_EXPRESSION_VOLUME, CLAP_NOTE_EXPRESSION_PRESSURE, CLAP_NOTE_EXPRESSION_TUNING, CLAP_NOTE_EXPRESSION_VIBRATO,
CLAP_TRANSPORT_HAS_BEATS_TIMELINE, CLAP_TRANSPORT_HAS_SECONDS_TIMELINE, CLAP_NOTE_EXPRESSION_VOLUME, CLAP_TRANSPORT_HAS_BEATS_TIMELINE,
CLAP_TRANSPORT_HAS_TEMPO, CLAP_TRANSPORT_HAS_TIME_SIGNATURE, CLAP_TRANSPORT_IS_LOOP_ACTIVE, CLAP_TRANSPORT_HAS_SECONDS_TIMELINE, CLAP_TRANSPORT_HAS_TEMPO,
CLAP_TRANSPORT_IS_PLAYING, CLAP_TRANSPORT_IS_RECORDING, CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL, 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::{ use clap_sys::ext::audio_ports::{
clap_audio_port_info, clap_plugin_audio_ports, CLAP_AUDIO_PORT_IS_MAIN, CLAP_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::atomic::AtomicCell;
use crossbeam::channel::{self, SendTimeoutError}; use crossbeam::channel::{self, SendTimeoutError};
use crossbeam::queue::ArrayQueue; use crossbeam::queue::ArrayQueue;
use midi_consts::channel_event as midi;
use parking_lot::RwLock; use parking_lot::RwLock;
use raw_window_handle::RawWindowHandle; use raw_window_handle::RawWindowHandle;
use std::any::Any; use std::any::Any;
@ -72,11 +74,11 @@ use super::util::ClapPtr;
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::context::Transport; use crate::context::Transport;
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY}; use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
use crate::midi::{MidiConfig, NoteEvent};
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, MidiConfig, NoteEvent, ParentWindowHandle, BufferConfig, BusConfig, ClapPlugin, Editor, ParentWindowHandle, ProcessStatus,
ProcessStatus,
}; };
use crate::util::permit_alloc; use crate::util::permit_alloc;
use crate::wrapper::state::{self, PluginState}; use crate::wrapper::state::{self, PluginState};
@ -968,10 +970,43 @@ 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::MIDI_INPUT >= MidiConfig::Basic { // TODO: We can also handle note on, note off, and polyphonic pressure events, but
// We currently don't report supporting this at all in the event filter, add that once // the host should not be sending us those since we prefer CLAP-style events
// we support MIDI CCs // on our note ports
// TODO: Implement raw MIDI handling once we add CCs 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 false
@ -1680,12 +1715,13 @@ impl<P: ClapPlugin> Wrapper<P> {
(CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_ON) (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_OFF)
| (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_NOTE_EXPRESSION) | (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 => if P::MIDI_INPUT >= MidiConfig::Basic =>
{ {
true true
} }
(CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI) if P::MIDI_INPUT >= MidiConfig::MidiCCs => {
true
}
_ => false, _ => false,
} }
} }

View file

@ -7,8 +7,9 @@ use vst3_sys::vst::{IComponentHandler, RestartFlags};
use super::inner::{Task, WrapperInner}; use super::inner::{Task, WrapperInner};
use crate::context::{GuiContext, ProcessContext, Transport}; use crate::context::{GuiContext, ProcessContext, Transport};
use crate::event_loop::EventLoop; use crate::event_loop::EventLoop;
use crate::midi::NoteEvent;
use crate::param::internals::ParamPtr; use crate::param::internals::ParamPtr;
use crate::plugin::{NoteEvent, Vst3Plugin}; use crate::plugin::Vst3Plugin;
use crate::wrapper::state::PluginState; use crate::wrapper::state::PluginState;
/// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in /// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in

View file

@ -18,9 +18,10 @@ use super::view::WrapperView;
use crate::buffer::Buffer; use crate::buffer::Buffer;
use crate::context::Transport; use crate::context::Transport;
use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop}; use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop};
use crate::midi::NoteEvent;
use crate::param::internals::{ParamPtr, Params}; use crate::param::internals::{ParamPtr, Params};
use crate::param::ParamFlags; 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::state::{self, PluginState};
use crate::wrapper::util::{hash_param_id, process_wrapper}; use crate::wrapper::util::{hash_param_id, process_wrapper};

View file

@ -18,8 +18,9 @@ use super::inner::WrapperInner;
use super::util::VstPtr; use super::util::VstPtr;
use super::view::WrapperView; use super::view::WrapperView;
use crate::context::Transport; use crate::context::Transport;
use crate::midi::{MidiConfig, NoteEvent};
use crate::param::ParamFlags; 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::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};