1
0
Fork 0

Add voice ID fields for all non-MIDI note events

This will be useful when adding polyphonic modulation.
This commit is contained in:
Robbert van der Helm 2022-07-04 18:31:59 +02:00
parent f11b3c1a03
commit a2f8a9bebf
6 changed files with 209 additions and 22 deletions

View file

@ -11,6 +11,7 @@ code then it will not be listed here.
- The `CLAP_DESCRIPTION`, `CLAP_MANUAL_URL`, and `CLAP_SUPPORT_URL` associated - The `CLAP_DESCRIPTION`, `CLAP_MANUAL_URL`, and `CLAP_SUPPORT_URL` associated
constants from the `ClapPlugin` are now optional and have the type constants from the `ClapPlugin` are now optional and have the type
`Option<&'static str>` instead of `&'static str`. `Option<&'static str>` instead of `&'static str`.
- Most `NoteEvent` variants now have an additional `voice_id` field.
## [2022-07-02] ## [2022-07-02]

View file

@ -49,99 +49,117 @@ impl Plugin for MidiInverter {
match event { match event {
NoteEvent::NoteOn { NoteEvent::NoteOn {
timing, timing,
voice_id,
channel, channel,
note, note,
velocity, velocity,
} => context.send_event(NoteEvent::NoteOn { } => context.send_event(NoteEvent::NoteOn {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
velocity: 1.0 - velocity, velocity: 1.0 - velocity,
}), }),
NoteEvent::NoteOff { NoteEvent::NoteOff {
timing, timing,
voice_id,
channel, channel,
note, note,
velocity, velocity,
} => context.send_event(NoteEvent::NoteOff { } => context.send_event(NoteEvent::NoteOff {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
velocity: 1.0 - velocity, velocity: 1.0 - velocity,
}), }),
NoteEvent::PolyPressure { NoteEvent::PolyPressure {
timing, timing,
voice_id,
channel, channel,
note, note,
pressure, pressure,
} => context.send_event(NoteEvent::PolyPressure { } => context.send_event(NoteEvent::PolyPressure {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
pressure: 1.0 - pressure, pressure: 1.0 - pressure,
}), }),
NoteEvent::PolyVolume { NoteEvent::PolyVolume {
timing, timing,
voice_id,
channel, channel,
note, note,
gain, gain,
} => context.send_event(NoteEvent::PolyVolume { } => context.send_event(NoteEvent::PolyVolume {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
gain: 1.0 - gain, gain: 1.0 - gain,
}), }),
NoteEvent::PolyPan { NoteEvent::PolyPan {
timing, timing,
voice_id,
channel, channel,
note, note,
pan, pan,
} => context.send_event(NoteEvent::PolyPan { } => context.send_event(NoteEvent::PolyPan {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
pan: 1.0 - pan, pan: 1.0 - pan,
}), }),
NoteEvent::PolyTuning { NoteEvent::PolyTuning {
timing, timing,
voice_id,
channel, channel,
note, note,
tuning, tuning,
} => context.send_event(NoteEvent::PolyTuning { } => context.send_event(NoteEvent::PolyTuning {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
tuning: 1.0 - tuning, tuning: 1.0 - tuning,
}), }),
NoteEvent::PolyVibrato { NoteEvent::PolyVibrato {
timing, timing,
voice_id,
channel, channel,
note, note,
vibrato, vibrato,
} => context.send_event(NoteEvent::PolyVibrato { } => context.send_event(NoteEvent::PolyVibrato {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
vibrato: 1.0 - vibrato, vibrato: 1.0 - vibrato,
}), }),
NoteEvent::PolyExpression { NoteEvent::PolyExpression {
timing, timing,
voice_id,
channel, channel,
note, note,
expression, expression,
} => context.send_event(NoteEvent::PolyExpression { } => context.send_event(NoteEvent::PolyExpression {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
expression: 1.0 - expression, expression: 1.0 - expression,
}), }),
NoteEvent::PolyBrightness { NoteEvent::PolyBrightness {
timing, timing,
voice_id,
channel, channel,
note, note,
brightness, brightness,
} => context.send_event(NoteEvent::PolyBrightness { } => context.send_event(NoteEvent::PolyBrightness {
timing, timing,
voice_id,
channel: 15 - channel, channel: 15 - channel,
note: 127 - note, note: 127 - note,
brightness: 1.0 - brightness, brightness: 1.0 - brightness,

View file

@ -30,6 +30,9 @@ pub enum NoteEvent {
/// A note on event, available on [`MidiConfig::Basic`] and up. /// A note on event, available on [`MidiConfig::Basic`] and up.
NoteOn { NoteOn {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -41,6 +44,9 @@ pub enum NoteEvent {
/// A note off event, available on [`MidiConfig::Basic`] and up. /// A note off event, available on [`MidiConfig::Basic`] and up.
NoteOff { NoteOff {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -59,6 +65,9 @@ pub enum NoteEvent {
/// you may manually combine the polyphonic key pressure and MPE channel pressure. /// you may manually combine the polyphonic key pressure and MPE channel pressure.
PolyPressure { PolyPressure {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -70,6 +79,9 @@ pub enum NoteEvent {
/// support these expressions. /// support these expressions.
PolyVolume { PolyVolume {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -81,6 +93,9 @@ pub enum NoteEvent {
/// support these expressions. /// support these expressions.
PolyPan { PolyPan {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -93,6 +108,9 @@ pub enum NoteEvent {
/// these expressions. /// these expressions.
PolyTuning { PolyTuning {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -104,6 +122,9 @@ pub enum NoteEvent {
/// these expressions. /// these expressions.
PolyVibrato { PolyVibrato {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -115,6 +136,9 @@ pub enum NoteEvent {
/// [`MidiConfig::Basic`] and up. Not all hosts may support these expressions. /// [`MidiConfig::Basic`] and up. Not all hosts may support these expressions.
PolyExpression { PolyExpression {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -126,6 +150,9 @@ pub enum NoteEvent {
/// these expressions. /// these expressions.
PolyBrightness { PolyBrightness {
timing: u32, timing: u32,
/// A unique identifier for this note, if available. Using this to refer to a note is
/// required when allowing overlapping voices for CLAP plugins.
voice_id: Option<i32>,
/// The note's channel, from 0 to 16. /// The note's channel, from 0 to 16.
channel: u8, channel: u8,
/// The note's MIDI key number, from 0 to 127. /// The note's MIDI key number, from 0 to 127.
@ -186,6 +213,24 @@ impl NoteEvent {
} }
} }
/// Returns the event's voice ID, if it has any.
pub fn voice_id(&self) -> Option<i32> {
match &self {
NoteEvent::NoteOn { voice_id, .. } => *voice_id,
NoteEvent::NoteOff { voice_id, .. } => *voice_id,
NoteEvent::PolyPressure { voice_id, .. } => *voice_id,
NoteEvent::PolyVolume { voice_id, .. } => *voice_id,
NoteEvent::PolyPan { voice_id, .. } => *voice_id,
NoteEvent::PolyTuning { voice_id, .. } => *voice_id,
NoteEvent::PolyVibrato { voice_id, .. } => *voice_id,
NoteEvent::PolyExpression { voice_id, .. } => *voice_id,
NoteEvent::PolyBrightness { voice_id, .. } => *voice_id,
NoteEvent::MidiChannelPressure { .. } => None,
NoteEvent::MidiPitchBend { .. } => None,
NoteEvent::MidiCC { .. } => None,
}
}
/// Parse MIDI into a [`NoteEvent`]. Will return `Err(event_type)` if the parsing failed. /// Parse MIDI into a [`NoteEvent`]. Will return `Err(event_type)` if the parsing failed.
pub fn from_midi(timing: u32, midi_data: [u8; 3]) -> Result<Self, u8> { pub fn from_midi(timing: u32, midi_data: [u8; 3]) -> Result<Self, u8> {
// TODO: Maybe add special handling for 14-bit CCs and RPN messages at some // TODO: Maybe add special handling for 14-bit CCs and RPN messages at some
@ -195,18 +240,21 @@ impl NoteEvent {
match event_type { match event_type {
midi::NOTE_ON => Ok(NoteEvent::NoteOn { midi::NOTE_ON => Ok(NoteEvent::NoteOn {
timing, timing,
voice_id: None,
channel, channel,
note: midi_data[1], note: midi_data[1],
velocity: midi_data[2] as f32 / 127.0, velocity: midi_data[2] as f32 / 127.0,
}), }),
midi::NOTE_OFF => Ok(NoteEvent::NoteOff { midi::NOTE_OFF => Ok(NoteEvent::NoteOff {
timing, timing,
voice_id: None,
channel, channel,
note: midi_data[1], note: midi_data[1],
velocity: midi_data[2] as f32 / 127.0, velocity: midi_data[2] as f32 / 127.0,
}), }),
midi::POLYPHONIC_KEY_PRESSURE => Ok(NoteEvent::PolyPressure { midi::POLYPHONIC_KEY_PRESSURE => Ok(NoteEvent::PolyPressure {
timing, timing,
voice_id: None,
channel, channel,
note: midi_data[1], note: midi_data[1],
pressure: midi_data[2] as f32 / 127.0, pressure: midi_data[2] as f32 / 127.0,
@ -239,6 +287,7 @@ impl NoteEvent {
match self { match self {
NoteEvent::NoteOn { NoteEvent::NoteOn {
timing: _, timing: _,
voice_id: _,
channel, channel,
note, note,
velocity, velocity,
@ -249,6 +298,7 @@ impl NoteEvent {
]), ]),
NoteEvent::NoteOff { NoteEvent::NoteOff {
timing: _, timing: _,
voice_id: _,
channel, channel,
note, note,
velocity, velocity,
@ -259,6 +309,7 @@ impl NoteEvent {
]), ]),
NoteEvent::PolyPressure { NoteEvent::PolyPressure {
timing: _, timing: _,
voice_id: _,
channel, channel,
note, note,
pressure, pressure,
@ -341,6 +392,7 @@ mod tests {
fn test_note_on_midi_conversion() { fn test_note_on_midi_conversion() {
let event = NoteEvent::NoteOn { let event = NoteEvent::NoteOn {
timing: TIMING, timing: TIMING,
voice_id: None,
channel: 1, channel: 1,
note: 2, note: 2,
// The value will be rounded in the conversion to MIDI, hence this overly specific value // The value will be rounded in the conversion to MIDI, hence this overly specific value
@ -357,6 +409,7 @@ mod tests {
fn test_note_off_midi_conversion() { fn test_note_off_midi_conversion() {
let event = NoteEvent::NoteOff { let event = NoteEvent::NoteOff {
timing: TIMING, timing: TIMING,
voice_id: None,
channel: 1, channel: 1,
note: 2, note: 2,
velocity: 0.6929134, velocity: 0.6929134,
@ -372,6 +425,7 @@ mod tests {
fn test_poly_pressure_midi_conversion() { fn test_poly_pressure_midi_conversion() {
let event = NoteEvent::PolyPressure { let event = NoteEvent::PolyPressure {
timing: TIMING, timing: TIMING,
voice_id: None,
channel: 1, channel: 1,
note: 2, note: 2,
pressure: 0.6929134, pressure: 0.6929134,

View file

@ -909,6 +909,7 @@ impl<P: ClapPlugin> Wrapper<P> {
let push_successful = match event { let push_successful = match event {
NoteEvent::NoteOn { NoteEvent::NoteOn {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
velocity, velocity,
@ -922,7 +923,7 @@ impl<P: ClapPlugin> Wrapper<P> {
// We don't have a way to denote live events // We don't have a way to denote live events
flags: 0, flags: 0,
}, },
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -933,6 +934,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::NoteOff { NoteEvent::NoteOff {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
velocity, velocity,
@ -945,7 +947,7 @@ impl<P: ClapPlugin> Wrapper<P> {
type_: CLAP_EVENT_NOTE_OFF, type_: CLAP_EVENT_NOTE_OFF,
flags: 0, flags: 0,
}, },
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -956,6 +958,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::PolyPressure { NoteEvent::PolyPressure {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
pressure, pressure,
@ -969,7 +972,7 @@ impl<P: ClapPlugin> Wrapper<P> {
flags: 0, flags: 0,
}, },
expression_id: CLAP_NOTE_EXPRESSION_PRESSURE, expression_id: CLAP_NOTE_EXPRESSION_PRESSURE,
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -980,6 +983,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::PolyVolume { NoteEvent::PolyVolume {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
gain, gain,
@ -993,7 +997,7 @@ impl<P: ClapPlugin> Wrapper<P> {
flags: 0, flags: 0,
}, },
expression_id: CLAP_NOTE_EXPRESSION_VOLUME, expression_id: CLAP_NOTE_EXPRESSION_VOLUME,
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -1004,6 +1008,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::PolyPan { NoteEvent::PolyPan {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
pan, pan,
@ -1017,7 +1022,7 @@ impl<P: ClapPlugin> Wrapper<P> {
flags: 0, flags: 0,
}, },
expression_id: CLAP_NOTE_EXPRESSION_PAN, expression_id: CLAP_NOTE_EXPRESSION_PAN,
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -1028,6 +1033,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::PolyTuning { NoteEvent::PolyTuning {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
tuning, tuning,
@ -1041,7 +1047,7 @@ impl<P: ClapPlugin> Wrapper<P> {
flags: 0, flags: 0,
}, },
expression_id: CLAP_NOTE_EXPRESSION_TUNING, expression_id: CLAP_NOTE_EXPRESSION_TUNING,
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -1052,6 +1058,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::PolyVibrato { NoteEvent::PolyVibrato {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
vibrato, vibrato,
@ -1065,7 +1072,7 @@ impl<P: ClapPlugin> Wrapper<P> {
flags: 0, flags: 0,
}, },
expression_id: CLAP_NOTE_EXPRESSION_VIBRATO, expression_id: CLAP_NOTE_EXPRESSION_VIBRATO,
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -1076,6 +1083,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::PolyExpression { NoteEvent::PolyExpression {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
expression, expression,
@ -1089,7 +1097,7 @@ impl<P: ClapPlugin> Wrapper<P> {
flags: 0, flags: 0,
}, },
expression_id: CLAP_NOTE_EXPRESSION_EXPRESSION, expression_id: CLAP_NOTE_EXPRESSION_EXPRESSION,
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -1100,6 +1108,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
NoteEvent::PolyBrightness { NoteEvent::PolyBrightness {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
brightness, brightness,
@ -1113,7 +1122,7 @@ impl<P: ClapPlugin> Wrapper<P> {
flags: 0, flags: 0,
}, },
expression_id: CLAP_NOTE_EXPRESSION_BRIGHTNESS, expression_id: CLAP_NOTE_EXPRESSION_BRIGHTNESS,
note_id: -1, note_id: voice_id.unwrap_or(-1),
port_index: 0, port_index: 0,
channel: channel as i16, channel: channel as i16,
key: note as i16, key: note as i16,
@ -1264,6 +1273,11 @@ impl<P: ClapPlugin> Wrapper<P> {
// When splitting up the buffer for sample accurate automation all events // When splitting up the buffer for sample accurate automation all events
// should be relative to the block // should be relative to the block
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
velocity: event.velocity as f32, velocity: event.velocity as f32,
@ -1277,6 +1291,11 @@ impl<P: ClapPlugin> Wrapper<P> {
let event = &*(event as *const clap_event_note); let event = &*(event as *const clap_event_note);
input_events.push_back(NoteEvent::NoteOff { input_events.push_back(NoteEvent::NoteOff {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
velocity: event.velocity as f32, velocity: event.velocity as f32,
@ -1293,6 +1312,11 @@ impl<P: ClapPlugin> Wrapper<P> {
CLAP_NOTE_EXPRESSION_PRESSURE => { CLAP_NOTE_EXPRESSION_PRESSURE => {
input_events.push_back(NoteEvent::PolyPressure { input_events.push_back(NoteEvent::PolyPressure {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
pressure: event.value as f32, pressure: event.value as f32,
@ -1301,6 +1325,11 @@ impl<P: ClapPlugin> Wrapper<P> {
CLAP_NOTE_EXPRESSION_VOLUME => { CLAP_NOTE_EXPRESSION_VOLUME => {
input_events.push_back(NoteEvent::PolyVolume { input_events.push_back(NoteEvent::PolyVolume {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
gain: event.value as f32, gain: event.value as f32,
@ -1309,6 +1338,11 @@ impl<P: ClapPlugin> Wrapper<P> {
CLAP_NOTE_EXPRESSION_PAN => { CLAP_NOTE_EXPRESSION_PAN => {
input_events.push_back(NoteEvent::PolyPan { input_events.push_back(NoteEvent::PolyPan {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
// In CLAP this value goes from [0, 1] instead of [-1, 1] // In CLAP this value goes from [0, 1] instead of [-1, 1]
@ -1318,6 +1352,11 @@ impl<P: ClapPlugin> Wrapper<P> {
CLAP_NOTE_EXPRESSION_TUNING => { CLAP_NOTE_EXPRESSION_TUNING => {
input_events.push_back(NoteEvent::PolyTuning { input_events.push_back(NoteEvent::PolyTuning {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
tuning: event.value as f32, tuning: event.value as f32,
@ -1326,6 +1365,11 @@ impl<P: ClapPlugin> Wrapper<P> {
CLAP_NOTE_EXPRESSION_VIBRATO => { CLAP_NOTE_EXPRESSION_VIBRATO => {
input_events.push_back(NoteEvent::PolyVibrato { input_events.push_back(NoteEvent::PolyVibrato {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
vibrato: event.value as f32, vibrato: event.value as f32,
@ -1334,6 +1378,11 @@ impl<P: ClapPlugin> Wrapper<P> {
CLAP_NOTE_EXPRESSION_EXPRESSION => { CLAP_NOTE_EXPRESSION_EXPRESSION => {
input_events.push_back(NoteEvent::PolyExpression { input_events.push_back(NoteEvent::PolyExpression {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
expression: event.value as f32, expression: event.value as f32,
@ -1342,6 +1391,11 @@ impl<P: ClapPlugin> Wrapper<P> {
CLAP_NOTE_EXPRESSION_BRIGHTNESS => { CLAP_NOTE_EXPRESSION_BRIGHTNESS => {
input_events.push_back(NoteEvent::PolyBrightness { input_events.push_back(NoteEvent::PolyBrightness {
timing: raw_event.time - current_sample_idx as u32, timing: raw_event.time - current_sample_idx as u32,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.key as u8, note: event.key as u8,
brightness: event.value as f32, brightness: event.value as f32,

View file

@ -105,7 +105,8 @@ impl NoteExpressionController {
timing: u32, timing: u32,
event: &NoteExpressionValueEvent, event: &NoteExpressionValueEvent,
) -> Option<NoteEvent> { ) -> Option<NoteEvent> {
let (_, note, channel) = *self // We're calling it a voice ID, VST3 (and CLAP) calls it a note ID
let (note_id, note, channel) = *self
.note_ids .note_ids
.iter() .iter()
.find(|(note_id, _, _)| *note_id == event.note_id)?; .find(|(note_id, _, _)| *note_id == event.note_id)?;
@ -113,6 +114,7 @@ impl NoteExpressionController {
match event.type_id { match event.type_id {
VOLUME_EXPRESSION_ID => Some(NoteEvent::PolyVolume { VOLUME_EXPRESSION_ID => Some(NoteEvent::PolyVolume {
timing, timing,
voice_id: Some(note_id),
channel, channel,
note, note,
// Because expression values in VST3 are always in the `[0, 1]` range, they added a // Because expression values in VST3 are always in the `[0, 1]` range, they added a
@ -121,6 +123,7 @@ impl NoteExpressionController {
}), }),
PAN_EXPRESSION_ID => Some(NoteEvent::PolyPan { PAN_EXPRESSION_ID => Some(NoteEvent::PolyPan {
timing, timing,
voice_id: Some(note_id),
channel, channel,
note, note,
// Our panning expressions are symmetrical around 0 // Our panning expressions are symmetrical around 0
@ -128,6 +131,7 @@ impl NoteExpressionController {
}), }),
TUNING_EXPRESSION_ID => Some(NoteEvent::PolyTuning { TUNING_EXPRESSION_ID => Some(NoteEvent::PolyTuning {
timing, timing,
voice_id: Some(note_id),
channel, channel,
note, note,
// This denormalized to the same [-120, 120] range used by CLAP and our expression // This denormalized to the same [-120, 120] range used by CLAP and our expression
@ -136,18 +140,21 @@ impl NoteExpressionController {
}), }),
VIBRATO_EXPRESSION_ID => Some(NoteEvent::PolyVibrato { VIBRATO_EXPRESSION_ID => Some(NoteEvent::PolyVibrato {
timing, timing,
voice_id: Some(note_id),
channel, channel,
note, note,
vibrato: event.value as f32, vibrato: event.value as f32,
}), }),
EXPRESSION_EXPRESSION_ID => Some(NoteEvent::PolyBrightness { EXPRESSION_EXPRESSION_ID => Some(NoteEvent::PolyBrightness {
timing, timing,
voice_id: Some(note_id),
channel, channel,
note, note,
brightness: event.value as f32, brightness: event.value as f32,
}), }),
BRIGHTNESS_EXPRESSION_ID => Some(NoteEvent::PolyExpression { BRIGHTNESS_EXPRESSION_ID => Some(NoteEvent::PolyExpression {
timing, timing,
voice_id: Some(note_id),
channel, channel,
note, note,
expression: event.value as f32, expression: event.value as f32,

View file

@ -1162,6 +1162,11 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
timing, timing,
event: NoteEvent::NoteOn { event: NoteEvent::NoteOn {
timing, timing,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.pitch as u8, note: event.pitch as u8,
velocity: event.velocity, velocity: event.velocity,
@ -1173,6 +1178,11 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
timing, timing,
event: NoteEvent::NoteOff { event: NoteEvent::NoteOff {
timing, timing,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.pitch as u8, note: event.pitch as u8,
velocity: event.velocity, velocity: event.velocity,
@ -1184,6 +1194,11 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
timing, timing,
event: NoteEvent::PolyPressure { event: NoteEvent::PolyPressure {
timing, timing,
voice_id: if event.note_id != -1 {
Some(event.note_id)
} else {
None
},
channel: event.channel as u8, channel: event.channel as u8,
note: event.pitch as u8, note: event.pitch as u8,
pressure: event.pressure, pressure: event.pressure,
@ -1531,9 +1546,13 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
// There's also a ppqPos field, but uh how about no // There's also a ppqPos field, but uh how about no
vst3_event.sample_offset = event.timing() as i32 + block_start as i32; vst3_event.sample_offset = event.timing() as i32 + block_start as i32;
// `voice_id.onwrap_or(|| ...)` triggers
// https://github.com/rust-lang/rust-clippy/issues/8522
#[allow(clippy::unnecessary_lazy_evaluations)]
match event { match event {
NoteEvent::NoteOn { NoteEvent::NoteOn {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
velocity, velocity,
@ -1547,11 +1566,13 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
length: 0, // What? length: 0, // What?
// We'll use this for our note IDs, that way we don't have // We'll use this for our note IDs, that way we don't have
// to do anything complicated here // to do anything complicated here
note_id: ((channel as i32) << 8) | note as i32, note_id: voice_id
.unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
}; };
} }
NoteEvent::NoteOff { NoteEvent::NoteOff {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
velocity, velocity,
@ -1561,12 +1582,14 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
channel: channel as i16, channel: channel as i16,
pitch: note as i16, pitch: note as i16,
velocity, velocity,
note_id: ((channel as i32) << 8) | note as i32, note_id: voice_id
.unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
tuning: 0.0, tuning: 0.0,
}; };
} }
NoteEvent::PolyPressure { NoteEvent::PolyPressure {
timing: _, timing: _,
voice_id,
channel, channel,
note, note,
pressure, pressure,
@ -1575,20 +1598,50 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
vst3_event.event.poly_pressure = PolyPressureEvent { vst3_event.event.poly_pressure = PolyPressureEvent {
channel: channel as i16, channel: channel as i16,
pitch: note as i16, pitch: note as i16,
note_id: ((channel as i32) << 8) | note as i32, note_id: voice_id
.unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
pressure, pressure,
}; };
} }
event @ (NoteEvent::PolyVolume { channel, note, .. } event @ (NoteEvent::PolyVolume {
| NoteEvent::PolyPan { channel, note, .. } voice_id,
| NoteEvent::PolyTuning { channel, note, .. } channel,
| NoteEvent::PolyVibrato { channel, note, .. } note,
| NoteEvent::PolyExpression { channel, note, .. } ..
| NoteEvent::PolyBrightness { channel, note, .. }) }
if P::MIDI_OUTPUT >= MidiConfig::Basic => | NoteEvent::PolyPan {
{ voice_id,
channel,
note,
..
}
| NoteEvent::PolyTuning {
voice_id,
channel,
note,
..
}
| NoteEvent::PolyVibrato {
voice_id,
channel,
note,
..
}
| NoteEvent::PolyExpression {
voice_id,
channel,
note,
..
}
| NoteEvent::PolyBrightness {
voice_id,
channel,
note,
..
}) if P::MIDI_OUTPUT >= MidiConfig::Basic => {
match NoteExpressionController::translate_event_reverse( match NoteExpressionController::translate_event_reverse(
((channel as i32) << 8) | note as i32, voice_id
.unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
&event, &event,
) { ) {
Some(translated_event) => { Some(translated_event) => {