Implement full MIDI support for CLAP
This commit is contained in:
parent
0b3a5cd297
commit
24837d1552
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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 <package> <build_arguments>` command that automatically
|
||||
detects which plugin targets your plugin exposes and creates the correct
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
181
src/midi.rs
Normal file
181
src/midi.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
148
src/plugin.rs
148
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<P: ClapPlugin> Wrapper<P> {
|
|||
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<P: ClapPlugin> Wrapper<P> {
|
|||
(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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
Loading…
Reference in a new issue