New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Not sure how to use the timing
of emitted midi events
#46
Comments
Use |
thanks, I'll try to figure it out. |
I had a similar issue when writing a step sequencer. To solve it, I wrote a clock generator that can be used to generate regular events. It can be used as iterator: for (pulse_no, timing) in clock {
} Implementation: //! Clock generator.
use nih_plug::buffer::Buffer;
use nih_plug::context::process::Transport;
/// Clock generator.
#[derive(Debug)]
pub struct Clock {
/// Position in the song in pulses.
pos_pulses: Option<f64>,
/// Duration of a pulse in samples.
pulse_duration_samples: Option<f64>,
/// Buffer length in samples.
buffer_length: usize,
/// Iteration count.
count: usize,
/// Flag if transport is playing.
playing: bool,
}
impl Clock {
/// Returns a new instance of `Clock`.
/// - `buffer:` Reference to the buffer object.
/// - `transport`: Reference to the transport object.
/// - `ppq:` Pulses per quarter note.
pub fn new(buffer: &Buffer, transport: &Transport, ppq: f64) -> Self {
Self {
pos_pulses: transport.pos_beats().map(|v| v * ppq),
pulse_duration_samples: transport
.tempo
.map(|v| 60.0 / (v * ppq) * transport.sample_rate as f64),
buffer_length: buffer.samples(),
count: 0,
playing: transport.playing,
}
}
}
impl Iterator for Clock {
/// Tuple of (pulse number, timing).
type Item = (i32, u32);
/// Returns the next value.
fn next(&mut self) -> Option<Self::Item> {
if !self.playing {
// Transport must be playing, otherwise clock generation makes no sense.
return None;
}
if let (Some(pos_pulses), Some(pulse_duration_samples)) =
(self.pos_pulses, self.pulse_duration_samples)
{
// Distance to the next pulse in samples.
let next_pulse_delta = ((pos_pulses.ceil() - pos_pulses) * pulse_duration_samples
+ self.count as f64 * pulse_duration_samples)
.round() as u32;
if next_pulse_delta < self.buffer_length as u32 {
let pulse = (pos_pulses.ceil() as i32, next_pulse_delta);
// Prepare next pulse.
self.pos_pulses = Some(pos_pulses + 1.0);
self.count += 1;
Some(pulse)
} else {
None
}
} else {
None
}
}
} @robbert-vdh If you find it useful, you could maybe include it as a helper in |
If you have more questions about timing in the context of plugins, feel free to hop on the Rust Audio Discord and ask your question there! |
First, great work ! I could get a vst3+clap plugin going in 5 minutes.
I'm trying to make a simple midi arpeggiator - one note in, multiple notes out. How would I emit a NoteOn midi event, let's say, one quarter noter later than the initial note received ? I'd love a quick sample.
Thanks !
The text was updated successfully, but these errors were encountered: