refactor: merge plugin, sampler -> mixer; transport -> sequencer; time -> core

This commit is contained in:
🪞👃🪞 2024-08-10 21:23:20 +03:00
parent 6206a43b4a
commit a659062dbc
46 changed files with 128 additions and 198 deletions

View file

@ -0,0 +1,211 @@
use crate::*;
/// A plugin device.
pub struct Plugin {
pub name: String,
pub path: Option<String>,
pub plugin: Option<PluginKind>,
pub selected: usize,
pub mapping: bool,
pub ports: JackPorts,
}
render!(Plugin = render_plugin);
handle!(Plugin |self, e| handle_keymap(self, e, KEYMAP_PLUGIN));
process!(Plugin = Plugin::process);
/// Supported plugin formats.
pub enum PluginKind {
LV2(LV2Plugin),
VST2 {
instance: ::vst::host::PluginInstance
},
VST3,
}
impl Plugin {
pub fn new_lv2 (name: &str, path: &str) -> Usually<JackDevice> {
let plugin = LV2Plugin::new(path)?;
jack_from_lv2(name, &plugin.plugin)?
.run(|ports|Box::new(Self {
name: name.into(),
path: Some(String::from(path)),
plugin: Some(PluginKind::LV2(plugin)),
selected: 0,
mapping: false,
ports
}))
}
/// Create a plugin host device.
pub fn new (name: &str) -> Usually<Self> {
Ok(Self {
name: name.into(),
path: None,
plugin: None,
selected: 0,
mapping: false,
ports: JackPorts::default()
})
}
pub fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
match self.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin {
features,
ref mut instance,
ref mut input_buffer,
..
})) => {
let urid = features.midi_urid();
input_buffer.clear();
for port in self.ports.midi_ins.values() {
let mut atom = ::livi::event::LV2AtomSequence::new(
&features,
scope.n_frames() as usize
);
for event in port.iter(scope) {
match event.bytes.len() {
3 => atom.push_midi_event::<3>(
event.time as i64,
urid,
&event.bytes[0..3]
).unwrap(),
_ => {}
}
}
input_buffer.push(atom);
}
let mut outputs = vec![];
for _ in self.ports.midi_outs.iter() {
outputs.push(::livi::event::LV2AtomSequence::new(
&features,
scope.n_frames() as usize
));
}
let ports = ::livi::EmptyPortConnections::new()
.with_atom_sequence_inputs(
input_buffer.iter()
)
.with_atom_sequence_outputs(
outputs.iter_mut()
)
.with_audio_inputs(
self.ports.audio_ins.values().map(|o|o.as_slice(scope))
)
.with_audio_outputs(
self.ports.audio_outs.values_mut().map(|o|o.as_mut_slice(scope))
);
unsafe {
instance.run(scope.n_frames() as usize, ports).unwrap()
};
},
_ => {}
}
Control::Continue
}
}
pub fn render_plugin (state: &Plugin, buf: &mut Buffer, area: Rect)
-> Usually<Rect>
{
let Rect { x, y, height, .. } = area;
let mut width = 20u16;
match &state.plugin {
Some(PluginKind::LV2(LV2Plugin { port_list, instance, .. })) => {
let start = state.selected.saturating_sub((height as usize / 2).saturating_sub(1));
let end = start + height as usize - 2;
//draw_box(buf, Rect { x, y, width, height });
for i in start..end {
if let Some(port) = port_list.get(i) {
let value = if let Some(value) = instance.control_input(port.index) {
value
} else {
port.default_value
};
//let label = &format!("C·· M·· {:25} = {value:.03}", port.name);
let label = &format!("{:25} = {value:.03}", port.name);
width = width.max(label.len() as u16 + 4);
label.blit(buf, x + 2, y + 1 + i as u16 - start as u16, if i == state.selected {
Some(Style::default().green())
} else {
None
})?;
} else {
break
}
}
},
_ => {}
};
draw_header(state, buf, area.x, area.y, width)?;
Ok(Rect { width, ..area })
}
fn draw_header (state: &Plugin, buf: &mut Buffer, x: u16, y: u16, w: u16) -> Usually<Rect> {
let style = Style::default().gray();
let label1 = format!(" {}", state.name);
label1.blit(buf, x + 1, y, Some(style.white().bold()))?;
if let Some(ref path) = state.path {
let label2 = format!("{}", &path[..((w as usize - 10).min(path.len()))]);
label2.blit(buf, x + 2 + label1.len() as u16, y, Some(style.not_dim()))?;
}
Ok(Rect { x, y, width: w, height: 1 })
}
/// Key bindings for plugin device.
pub const KEYMAP_PLUGIN: &'static [KeyBinding<Plugin>] = keymap!(Plugin {
[Up, NONE, "/plugin/cursor_up", "move cursor up", |s: &mut Plugin|{
s.selected = s.selected.saturating_sub(1);
Ok(true)
}],
[Down, NONE, "/plugin/cursor_down", "move cursor down", |s: &mut Plugin|{
s.selected = (s.selected + 1).min(match &s.plugin {
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
_ => unimplemented!()
});
Ok(true)
}],
[PageUp, NONE, "/plugin/cursor_page_up", "move cursor up", |s: &mut Plugin|{
s.selected = s.selected.saturating_sub(8);
Ok(true)
}],
[PageDown, NONE, "/plugin/cursor_page_down", "move cursor down", |s: &mut Plugin|{
s.selected = (s.selected + 10).min(match &s.plugin {
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
_ => unimplemented!()
});
Ok(true)
}],
[Char(','), NONE, "/plugin/decrement", "decrement value", |s: &mut Plugin|{
match s.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
let index = port_list[s.selected].index;
if let Some(value) = instance.control_input(index) {
instance.set_control_input(index, value - 0.01);
}
},
_ => {}
}
Ok(true)
}],
[Char('.'), NONE, "/plugin/decrement", "increment value", |s: &mut Plugin|{
match s.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
let index = port_list[s.selected].index;
if let Some(value) = instance.control_input(index) {
instance.set_control_input(index, value + 0.01);
}
},
_ => {}
}
Ok(true)
}],
[Char('g'), NONE, "/plugin/gui_toggle", "toggle plugin UI", |s: &mut Plugin|{
match s.plugin {
Some(PluginKind::LV2(ref mut plugin)) => {
plugin.ui_thread = Some(run_lv2_ui(LV2PluginUI::new()?)?);
},
Some(_) => unreachable!(),
None => {}
}
Ok(true)
}],
});