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",
|
"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",
|
||||||
|
|
|
@ -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"] }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
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::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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
@ -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};
|
||||||
|
|
Loading…
Reference in a new issue