1
0
Fork 0

Move event timing clamping to functions

So this doesn't need to be repeated everywhere.
This commit is contained in:
Robbert van der Helm 2023-02-01 17:33:14 +01:00
parent d5a8eb42ec
commit 55c3701d2e
4 changed files with 51 additions and 43 deletions

View file

@ -94,7 +94,9 @@ use crate::plugin::{
use crate::util::permit_alloc; use crate::util::permit_alloc;
use crate::wrapper::clap::util::{read_stream, write_stream}; use crate::wrapper::clap::util::{read_stream, write_stream};
use crate::wrapper::state::{self, PluginState}; use crate::wrapper::state::{self, PluginState};
use crate::wrapper::util::{hash_param_id, process_wrapper, strlcpy}; use crate::wrapper::util::{
clamp_input_event_timing, clamp_output_event_timing, hash_param_id, process_wrapper, strlcpy,
};
/// How many output parameter changes we can store in our output parameter change queue. Storing /// How many output parameter changes we can store in our output parameter change queue. Storing
/// more than this many parameters at a time will cause changes to get lost. /// more than this many parameters at a time will cause changes to get lost.
@ -1079,12 +1081,10 @@ impl<P: ClapPlugin> Wrapper<P> {
let mut output_events = self.output_events.borrow_mut(); let mut output_events = self.output_events.borrow_mut();
while let Some(event) = output_events.pop_front() { while let Some(event) = output_events.pop_front() {
// Out of bounds events are clamped to the buffer's size // Out of bounds events are clamped to the buffer's size
let time = event.timing() + current_sample_idx as u32; let time = clamp_output_event_timing(
nih_debug_assert!( event.timing() + current_sample_idx as u32,
time < total_buffer_len as u32, total_buffer_len as u32,
"Output event is out of bounds, will be clamped to the buffer's size"
); );
let time = time.min(total_buffer_len as u32 - 1);
let push_successful = match event { let push_successful = match event {
NoteEvent::NoteOn { NoteEvent::NoteOn {
@ -1423,12 +1423,10 @@ impl<P: ClapPlugin> Wrapper<P> {
let raw_event = &*event; let raw_event = &*event;
// Out of bounds events are clamped to the buffer's size // Out of bounds events are clamped to the buffer's size
let timing = raw_event.time - current_sample_idx as u32; let timing = clamp_input_event_timing(
nih_debug_assert!( raw_event.time - current_sample_idx as u32,
timing < total_buffer_len as u32, total_buffer_len as u32,
"Input event is out of bounds, will be clamped to the buffer's size"
); );
let timing = timing.min(total_buffer_len as u32 - 1);
match (raw_event.space_id, raw_event.type_) { match (raw_event.space_id, raw_event.type_) {
(CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_PARAM_VALUE) => { (CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_PARAM_VALUE) => {

View file

@ -15,6 +15,7 @@ use crate::buffer::Buffer;
use crate::context::process::Transport; use crate::context::process::Transport;
use crate::midi::{MidiConfig, MidiResult, NoteEvent, PluginNoteEvent}; use crate::midi::{MidiConfig, MidiResult, NoteEvent, PluginNoteEvent};
use crate::plugin::Plugin; use crate::plugin::Plugin;
use crate::wrapper::util::{clamp_input_event_timing, clamp_output_event_timing};
/// Uses JACK audio and MIDI. /// Uses JACK audio and MIDI.
pub struct Jack { pub struct Jack {
@ -122,11 +123,7 @@ impl<P: Plugin> Backend<P> for Jack {
input_events.clear(); input_events.clear();
if let Some(midi_input) = &midi_input { if let Some(midi_input) = &midi_input {
input_events.extend(midi_input.iter(ps).filter_map(|midi| { input_events.extend(midi_input.iter(ps).filter_map(|midi| {
nih_debug_assert!( let timing = clamp_input_event_timing(midi.time, num_frames);
midi.time < num_frames,
"Input event is out of bounds, will be clamped to the buffer's size"
);
let timing = midi.time.min(num_frames - 1);
NoteEvent::from_midi(timing, midi.bytes).ok() NoteEvent::from_midi(timing, midi.bytes).ok()
})); }));
@ -139,11 +136,7 @@ impl<P: Plugin> Backend<P> for Jack {
let mut midi_writer = midi_output.writer(ps); let mut midi_writer = midi_output.writer(ps);
for event in output_events.drain(..) { for event in output_events.drain(..) {
// Out of bounds events are clamped to the buffer's size // Out of bounds events are clamped to the buffer's size
nih_debug_assert!( let timing = clamp_output_event_timing(event.timing(), num_frames as u32);
event.timing() < num_frames,
"Output event is out of bounds, will be clamped to the buffer's size"
);
let timing = event.timing().min(num_frames - 1);
match event.as_midi() { match event.as_midi() {
Some(MidiResult::Basic(midi_data)) => { Some(MidiResult::Basic(midi_data)) => {

View file

@ -61,6 +61,34 @@ pub fn strlcpy(dest: &mut [c_char], src: &str) {
dest[copy_len] = 0; dest[copy_len] = 0;
} }
/// Clamp an input event's timing to the buffer length. Emits a debug assertion failure if it was
/// out of bounds.
#[inline]
pub fn clamp_input_event_timing(timing: u32, total_buffer_len: u32) -> u32 {
let last_valid_index = total_buffer_len.saturating_sub(1);
nih_debug_assert!(
timing < last_valid_index,
"Input event is out of bounds, will be clamped to the buffer's size"
);
timing.min(last_valid_index)
}
/// Clamp an output event's timing to the buffer length. Emits a debug assertion failure if it was
/// out of bounds.
#[inline]
pub fn clamp_output_event_timing(timing: u32, total_buffer_len: u32) -> u32 {
let last_valid_index = total_buffer_len.saturating_sub(1);
nih_debug_assert!(
timing < last_valid_index,
"Output event is out of bounds, will be clamped to the buffer's size"
);
timing.min(last_valid_index)
}
/// Set up the logger so that the `nih_*!()` logging and assertion macros log output to a /// Set up the logger so that the `nih_*!()` logging and assertion macros log output to a
/// centralized location and panics also get written there. By default this logs to STDERR unless /// centralized location and panics also get written there. By default this logs to STDERR unless
/// the user is running Windows and a debugger has been attached, in which case /// the user is running Windows and a debugger has been attached, in which case

View file

@ -37,7 +37,7 @@ use crate::plugin::{
}; };
use crate::util::permit_alloc; use crate::util::permit_alloc;
use crate::wrapper::state; use crate::wrapper::state;
use crate::wrapper::util::process_wrapper; use crate::wrapper::util::{clamp_input_event_timing, clamp_output_event_timing, process_wrapper};
// Alias needed for the VST3 attribute macro // Alias needed for the VST3 attribute macro
use vst3_sys as vst3_com; use vst3_sys as vst3_com;
@ -1101,14 +1101,10 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
// Later this timing will be compensated for block splits by calling // Later this timing will be compensated for block splits by calling
// `event.subtract_timing(block_start)` before it is passed to the // `event.subtract_timing(block_start)` before it is passed to the
// plugin. Out of bounds events are clamped to the buffer> // plugin. Out of bounds events are clamped to the buffer>
let timing = sample_offset as u32; let timing = clamp_input_event_timing(
nih_debug_assert!( sample_offset as u32,
timing < total_buffer_len as u32, total_buffer_len as u32,
"Input event is out of bounds, will be clamped to the \
buffer's size"
); );
let timing = timing.min(total_buffer_len as u32 - 1);
let value = value as f32; let value = value as f32;
// MIDI CC messages, channel pressure, and pitch bend are also sent // MIDI CC messages, channel pressure, and pitch bend are also sent
@ -1175,12 +1171,10 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
nih_debug_assert_eq!(result, kResultOk); nih_debug_assert_eq!(result, kResultOk);
let event = event.assume_init(); let event = event.assume_init();
let timing = event.sample_offset as u32; let timing = clamp_input_event_timing(
nih_debug_assert!( event.sample_offset as u32,
timing < total_buffer_len as u32, total_buffer_len as u32,
"Input event is out of bounds, will be clamped to the buffer's size"
); );
let timing = timing.min(total_buffer_len as u32 - 1);
if event.type_ == EventTypes::kNoteOnEvent as u16 { if event.type_ == EventTypes::kNoteOnEvent as u16 {
let event = event.event.note_on; let event = event.event.note_on;
@ -1573,15 +1567,10 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
let mut vst3_event: Event = mem::zeroed(); let mut vst3_event: Event = mem::zeroed();
vst3_event.bus_index = 0; vst3_event.bus_index = 0;
// 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 = clamp_output_event_timing(
event.timing() + block_start as u32,
// Out of bounds events are clamped to the buffer total_buffer_len as u32,
nih_debug_assert!( ) as i32;
vst3_event.sample_offset < total_buffer_len as i32,
"Output event is out of bounds, will be clamped to the buffer's size"
);
vst3_event.sample_offset =
vst3_event.sample_offset.min(total_buffer_len as i32 - 1);
// `voice_id.unwrap_or(|| ...)` triggers // `voice_id.unwrap_or(|| ...)` triggers
// https://github.com/rust-lang/rust-clippy/issues/8522 // https://github.com/rust-lang/rust-clippy/issues/8522