/*! Noted listens for incoming midi notes, and replaces them */ #![allow(incomplete_features)] #![feature(generic_associated_types)] use baseplug::{event::Data, Event, MidiReceiver, Plugin, ProcessContext}; use serde::{Deserialize, Serialize}; baseplug::model! { #[derive(Debug, Serialize, Deserialize)] struct NotedModel { #[model(min = 0.001, max = 4.0)] #[parameter(name = "tempo", gradient = "Exponential")] tempo: f32, } } impl Default for NotedModel { fn default() -> Self { Self { tempo: 1.0 } } } struct Noted { notes: [bool; 128], frame_count: u64, note_off_buffer: Vec, } impl Plugin for Noted { const NAME: &'static str = "noted"; const PRODUCT: &'static str = "noted"; const VENDOR: &'static str = "unnieversal"; const INPUT_CHANNELS: usize = 2; const OUTPUT_CHANNELS: usize = 2; type Model = NotedModel; #[inline] fn new(_sample_rate: f32, _model: &NotedModel) -> Self { Self { notes: [false; 128], frame_count: 0, note_off_buffer: Vec::with_capacity(200), } } #[inline] fn process(&mut self, model: &NotedModelProcess, ctx: &mut ProcessContext) { let output = &mut ctx.outputs[0].buffers; let enqueue_midi = &mut ctx.enqueue_event; let is_playing = ctx.musical_time.is_playing; let curr_bpm = ctx.musical_time.bpm; let beat_in_seconds = 60.0 / curr_bpm; let smth = beat_in_seconds * ctx.sample_rate as f64; while let Some(note) = self.note_off_buffer.pop() { let note_off = Event:: { frame: 0, data: Data::Midi([0x80, note as u8, 0]), }; enqueue_midi(note_off); } for i in 0..ctx.nframes { // write silence output[0][i] = 0.0; output[1][i] = 0.0; if is_playing { let tempo_in_samples = model.tempo[i] as f64 * smth; let tempo_in_samples = tempo_in_samples.round() as u64; self.frame_count += 1; // Send note ons for active notes if self.frame_count >= tempo_in_samples { for (note, is_on) in self.notes.iter().enumerate() { if *is_on { // Send note off let note_off = Event:: { frame: i, data: Data::Midi([0x80, note as u8, 0]), }; enqueue_midi(note_off); // Send note on let note_on = Event:: { frame: i, data: Data::Midi([0x90, note as u8, 120]), }; enqueue_midi(note_on); } } self.frame_count = 0; } } else { self.frame_count = 0; } } } } impl MidiReceiver for Noted { fn midi_input(&mut self, _model: &NotedModelProcess, data: [u8; 3]) { match data[0] { // note on 0x90 => { self.notes[data[1] as usize] = true; } // note off 0x80 => { self.notes[data[1] as usize] = false; self.note_off_buffer.push(data[1]); } _ => (), } } } baseplug::vst2!(Noted, b"NoTe");