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",
]
[[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",

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" }
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"] }

View file

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

View file

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

View file

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

View file

@ -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;

View file

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

View file

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

View file

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

View file

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

View file

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