update
This commit is contained in:
@@ -10,4 +10,9 @@ crate-type = ["cdylib"]
|
||||
[dependencies]
|
||||
params = { workspace = true }
|
||||
engine = { workspace = true }
|
||||
lv2 = { workspace = true }
|
||||
lv2 = { workspace = true, features = [
|
||||
"lv2-atom",
|
||||
"lv2-units",
|
||||
"lv2-urid",
|
||||
"lv2-midi",
|
||||
] }
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
|
||||
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
|
||||
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
|
||||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
@@ -6,16 +9,24 @@
|
||||
a lv2:Plugin, lv2:InstrumentPlugin ;
|
||||
|
||||
doap:name "Tenko" ;
|
||||
doap:license <https://spdx.org/licenses/MIT> ;
|
||||
|
||||
lv2:requiredFeature urid:map ;
|
||||
|
||||
lv2:port [
|
||||
a lv2:InputPort, atom:AtomPort ;
|
||||
lv2:index 0 ;
|
||||
lv2:symbol "midi_in" ;
|
||||
rdfs:label "MIDI In" ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports midi:MidiEvent
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:AudioPort ;
|
||||
lv2:index 0 ;
|
||||
lv2:index 1 ;
|
||||
lv2:symbol "out_l" ;
|
||||
rdfs:label "Left Out"
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:AudioPort ;
|
||||
lv2:index 1 ;
|
||||
lv2:index 2 ;
|
||||
lv2:symbol "out_r" ;
|
||||
rdfs:label "Right Out"
|
||||
] .
|
||||
|
||||
@@ -1,35 +1,98 @@
|
||||
use engine::Engine;
|
||||
use lv2::prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
use engine::{oscillator::WavetableBank, synth::Synth};
|
||||
use lv2::lv2_urid::LV2Map;
|
||||
use lv2::{lv2_atom, prelude::*};
|
||||
use params::ParamStore;
|
||||
|
||||
#[derive(URIDCollection)]
|
||||
struct TenkoUrids {
|
||||
atom: AtomURIDCollection,
|
||||
midi: MidiURIDCollection,
|
||||
units: UnitURIDCollection,
|
||||
}
|
||||
|
||||
#[derive(FeatureCollection)]
|
||||
struct InitFeatures<'a> {
|
||||
map: LV2Map<'a>,
|
||||
}
|
||||
|
||||
#[derive(PortCollection)]
|
||||
struct Ports {
|
||||
midi_in: InputPort<AtomPort>,
|
||||
out_l: OutputPort<Audio>,
|
||||
out_r: OutputPort<Audio>,
|
||||
}
|
||||
|
||||
#[uri("https://git.yokai.digital/deadYokai/tenko")]
|
||||
struct TenkoLv2 {
|
||||
engine: Engine,
|
||||
synth: Synth,
|
||||
urids: TenkoUrids,
|
||||
host_bpm: f32,
|
||||
}
|
||||
|
||||
impl Plugin for TenkoLv2 {
|
||||
type Ports = Ports;
|
||||
type InitFeatures = ();
|
||||
type InitFeatures = InitFeatures<'static>;
|
||||
type AudioFeatures = ();
|
||||
|
||||
fn new(info: &PluginInfo, _features: &mut ()) -> Option<Self> {
|
||||
fn new(info: &PluginInfo, features: &mut InitFeatures<'static>) -> Option<Self> {
|
||||
let urids = TenkoUrids::from_map(&features.map)?;
|
||||
let params = ParamStore::new();
|
||||
let engine = Engine::new(params, info.sample_rate() as f32);
|
||||
Some(Self { engine })
|
||||
let bank = Arc::new(WavetableBank::new());
|
||||
let synth = Synth::new(info.sample_rate() as f32, params, bank);
|
||||
Some(Self {
|
||||
synth,
|
||||
urids,
|
||||
host_bpm: 120.0,
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&mut self, ports: &mut Ports, _: &mut (), _: u32) {
|
||||
for s in ports.out_l.iter_mut() {
|
||||
*s = 0.0;
|
||||
fn run(&mut self, ports: &mut Ports, _features: &mut (), _count: u32) {
|
||||
if let Some(seq) = ports
|
||||
.midi_in
|
||||
.read(self.urids.atom.sequence, self.urids.units.beat)
|
||||
{
|
||||
for (_, atom) in seq {
|
||||
if let Some(raw) = atom.read(self.urids.midi.raw, ()) {
|
||||
self.dispatch_midi(raw);
|
||||
} else if let Some((_header, reader)) = atom.read(self.urids.atom.object, ()) {
|
||||
self.handle_time_position(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
for s in ports.out_r.iter_mut() {
|
||||
*s = 0.0;
|
||||
|
||||
for (l, r) in ports.out_l.iter_mut().zip(ports.out_r.iter_mut()) {
|
||||
let (sl, sr) = self.synth.process(self.host_bpm);
|
||||
*l = sl;
|
||||
*r = sr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TenkoLv2 {
|
||||
#[inline]
|
||||
fn dispatch_midi(&mut self, raw: &[u8]) {
|
||||
if raw.len() < 3 {
|
||||
return;
|
||||
}
|
||||
let note = raw[1];
|
||||
let vel = raw[2];
|
||||
match raw[0] & 0xF0 {
|
||||
0x90 if vel > 0 => self.synth.note_on(note, vel),
|
||||
0x90 | 0x80 => self.synth.note_off(note),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn handle_time_position(&mut self, reader: lv2_atom::object::ObjectReader) {
|
||||
for (_, atom) in reader {
|
||||
if let Some(bpm) = atom.read(self.urids.atom.float, ())
|
||||
&& bpm > 0.0
|
||||
{
|
||||
self.host_bpm = bpm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user