unnieversal/crates/opiate/src/lib.rs

119 lines
3.4 KiB
Rust

#![allow(incomplete_features)]
#![feature(generic_associated_types)]
// morphing algorithm from https://ccrma.stanford.edu/~jhsu/421b/
use baseplug::{Plugin, ProcessContext};
use pvoc::{PhaseBin, PhaseVocoder};
use serde::{Deserialize, Serialize};
use utils::logs::*;
baseplug::model! {
#[derive(Debug, Serialize, Deserialize)]
struct OpiateModel {
#[model(min = 0.0, max = 1.0)]
#[parameter(name = "morph")]
morph: f32,
}
}
impl Default for OpiateModel {
fn default() -> Self {
Self { morph: 0.0 }
}
}
struct Opiate {
pvoc: PhaseVocoder<PhaseBin>,
out_0: Vec<f32>,
out_1: Vec<f32>,
out_2: Vec<f32>,
out_3: Vec<f32>,
}
impl Plugin for Opiate {
const NAME: &'static str = "opiate";
const PRODUCT: &'static str = "opiate";
const VENDOR: &'static str = "unnieversal";
const INPUT_CHANNELS: usize = 4;
const OUTPUT_CHANNELS: usize = 2;
type Model = OpiateModel;
#[inline]
fn new(sample_rate: f32, _model: &OpiateModel) -> Self {
setup_logging("opiate.log");
Self {
pvoc: PhaseVocoder::new(4, sample_rate as f64, 64, 4),
out_0: vec![0.0; 300],
out_1: vec![0.0; 300],
out_2: vec![0.0; 300],
out_3: vec![0.0; 300],
}
}
#[inline]
fn process(&mut self, model: &OpiateModelProcess, ctx: &mut ProcessContext<Self>) {
let input = &ctx.inputs[0].buffers;
let output = &mut ctx.outputs[0].buffers;
if input.len() != 4 {
for i in 0..ctx.nframes {
output[0][i] = 0.0;
output[1][i] = 0.0;
}
return;
}
let out = &mut [
&mut self.out_0[0..ctx.nframes],
&mut self.out_1[0..ctx.nframes],
&mut self.out_2[0..ctx.nframes],
&mut self.out_3[0..ctx.nframes],
][..];
let morph = model.morph[0] as f64;
let imorph = 1.0 - morph;
self.pvoc.process(
input,
out,
|_channels: usize,
bins: usize,
input: &[Vec<PhaseBin>],
output: &mut [Vec<PhaseBin>]| {
for j in 0..bins {
// left
let mags = morph * (1.0 - input[0][j].amp) + input[0][j].amp;
let mags2 = imorph * (1.0 - input[2][j].amp) + input[2][j].amp;
let phases = input[0][j].phase - (input[0][j].phase * morph);
let phases2 = input[2][j].phase - (input[2][j].phase * imorph);
output[0][j].amp = mags * mags2;
output[0][j].phase = phases + phases2;
// right
let mags = morph * (1.0 - input[1][j].amp) + input[1][j].amp;
let mags2 = imorph * (1.0 - input[3][j].amp) + input[3][j].amp;
let phases = input[1][j].phase - (input[1][j].phase * morph);
let phases2 = input[3][j].phase - (input[3][j].phase * imorph);
output[1][j].amp = mags * mags2;
output[1][j].phase = phases + phases2;
}
},
);
for i in 0..ctx.nframes {
output[0][i] = self.out_0[i];
output[1][i] = self.out_1[i];
self.out_0[i] = 0.0;
self.out_1[i] = 0.0;
}
}
}
baseplug::vst2!(Opiate, b"opiu");