tek/src/device/plugin.rs

130 lines
4.3 KiB
Rust

use crate::prelude::*;
mod lv2;
mod vst2;
mod vst3;
pub struct Plugin {
name: String,
path: String,
plugin: Option<PluginKind>,
offset: usize,
selected: usize,
midi_map_enable: bool,
}
enum PluginKind {
VST2(::vst::host::PluginInstance),
VST3,
LV2(Vec<::livi::Port>, ::livi::Instance),
}
const HELM: &'static str = "file:///nix/store/ij3sz7nqg5l7v2dygdvzy3w6cj62bd6r-helm-0.9.0/lib/lv2/helm.lv2";
impl Plugin {
pub fn new (name: &str) -> Result<DynamicDevice<Self>, Box<dyn Error>> {
let device = DynamicDevice::new(render, handle, process, Self {
name: name.into(),
path: HELM.into(),
plugin: None,
offset: 0,
selected: 0,
midi_map_enable: false
});
device.state.lock().unwrap().plugin = Some(self::lv2::plug_in(HELM)?);
Ok(device)
}
}
impl ::vst::host::Host for Plugin {}
pub fn process (_: &mut Plugin, _: &Client, _: &ProcessScope) -> Control {
Control::Continue
}
pub fn render (state: &Plugin, buf: &mut Buffer, area: Rect)
-> Usually<Rect>
{
let header = draw_header(state, buf, area)?;
let Rect { x, y, width, height } = area;
let height = height - header.height;
let style = Style::default().gray();
match &state.plugin {
Some(PluginKind::LV2(ports, instance)) => {
let mut height = 3;
for (i, port) in ports
.iter()
.filter(|port|port.port_type == ::livi::PortType::ControlInput)
.skip(state.offset)
.enumerate()
{
if i >= 20 {
break
}
buf.set_string(x + 2, y + 3 + i as u16, &format!("C·· M·· {:25} = {:03}",
port.name,
port.default_value
), if i + state.offset == state.selected {
Style::default().white().bold()
} else {
Style::default().not_dim()
});
height = height + 1;
}
Ok(draw_box(buf, Rect { x, y, width, height: height.max(20) }))
},
_ => {
buf.set_string(x + 1, y + 3, &format!(" Parameter 1 0.0"), style);
buf.set_string(x + 1, y + 4, &format!(" Parameter 2 0.0"), style);
buf.set_string(x + 1, y + 5, &format!(" Parameter 3 0.0"), style);
buf.set_string(x + 1, y + 6, &format!(" Parameter 4 0.0"), style);
Ok(draw_box(buf, Rect { x, y, width: 40, height: 7 }))
}
}
}
fn draw_header (state: &Plugin, buf: &mut Buffer, Rect {x, y, width, ..}: Rect) -> Usually<Rect> {
let style = Style::default().gray();
buf.set_string(x + 1, y + 1,
&format!(" {}", state.name), style.white().bold());
buf.set_string(x + 13, y + 1,
&format!("{}...", &HELM[..(width as usize - 20).min(HELM.len())]), style.not_dim());
buf.set_string(x + 0, y + 2,
&format!("{}", "-".repeat(width as usize - 2)), style.dim());
Ok(Rect { x, y, width, height: 3 })
}
pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
handle_keymap(s, event, keymap!(Plugin {
[Up, NONE, "cursor_up", "move cursor up",
|s: &mut Plugin|{
s.selected = s.selected.saturating_sub(1);
if s.selected < s.offset {
s.offset = s.selected;
}
Ok(true)
}],
[Down, NONE, "cursor_down", "move cursor down",
|s: &mut Plugin|{
s.selected = s.selected + 1;
if s.selected >= s.offset + 19 {
s.offset = s.offset + 1;
}
Ok(true)
}],
[Char('m'), NONE, "toggle_midi_map", "toggle midi map mode",
|s: &mut Plugin|{
s.midi_map_enable = !s.midi_map_enable;
Ok(true)
}]
}))
}
impl DevicePorts for Plugin {
fn midi_ins (&self) -> Usually<Vec<String>> {
Ok(vec!["in".into()])
}
fn audio_outs (&self) -> Usually<Vec<String>> {
Ok(vec!["out L".into(), "out R".into()])
}
}