unnieversal/crates/transmute_pitch/src/lib.rs

109 lines
3.4 KiB
Rust

#![allow(incomplete_features)]
#![feature(generic_associated_types)]
use baseplug::{event::Data, Event, Plugin, ProcessContext};
use serde::{Deserialize, Serialize};
use utils::pitch::*;
const BUFFER_LEN: usize = 2 << 9;
baseplug::model! {
#[derive(Debug, Serialize, Deserialize)]
struct TransmutePitchModel {
#[model(min = 0.0, max = 1.0)]
#[parameter(name = "passthrough")]
passthrough: f32,
}
}
impl Default for TransmutePitchModel {
fn default() -> Self {
Self { passthrough: 1.0 }
}
}
struct TransmutePitch {
detector_thread: pitch_detection::PitchDetectorThread<BUFFER_LEN>,
last_note: Option<u8>,
}
impl Plugin for TransmutePitch {
const NAME: &'static str = "transmute pitch";
const PRODUCT: &'static str = "transmute pitch";
const VENDOR: &'static str = "unnieversal";
const INPUT_CHANNELS: usize = 1;
const OUTPUT_CHANNELS: usize = 1;
type Model = TransmutePitchModel;
#[inline]
fn new(_sample_rate: f32, _model: &TransmutePitchModel) -> Self {
let detector_thread = pitch_detection::PitchDetectorThread::<BUFFER_LEN>::new();
Self {
detector_thread,
last_note: None,
}
}
#[inline]
fn process(&mut self, model: &TransmutePitchModelProcess, ctx: &mut ProcessContext<Self>) {
let input = &ctx.inputs[0].buffers;
let output = &mut ctx.outputs[0].buffers;
let enqueue_midi = &mut ctx.enqueue_event;
for i in 0..ctx.nframes {
output[0][i] = model.passthrough[i] * input[0][i];
output[1][i] = model.passthrough[i] * input[1][i];
// pass input to pitch detector
self.detector_thread
.write(input[0][i], 0.0, ctx.sample_rate as u32);
// Try to get a processed buffer from the processor thread
match self.detector_thread.try_get_pitch() {
Some((Some(pitch), _)) => {
let note = pitch_to_midi_note(pitch);
// If note changed
if self.last_note != Some(note) {
// Send note off for last note
if let Some(last_note) = self.last_note {
let note_off = Event::<TransmutePitch> {
frame: i,
data: Data::Midi([0x80, last_note, 0]),
};
enqueue_midi(note_off);
}
// Send note on for the new one
let note_on = Event::<TransmutePitch> {
frame: i,
data: Data::Midi([0x90, note, 64]),
};
enqueue_midi(note_on);
// Update note
self.last_note = Some(note);
}
}
Some((None, _)) => {
if let Some(last_note) = self.last_note {
let note_off = Event::<TransmutePitch> {
frame: i,
data: Data::Midi([0x80, last_note, 0]),
};
enqueue_midi(note_off);
}
self.last_note = None;
}
_ => {}
}
}
}
}
baseplug::vst2!(TransmutePitch, b"trpi");