mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
turn Plugin keymap to match statement
This commit is contained in:
parent
cd8a808c21
commit
39407c9760
8 changed files with 124 additions and 129 deletions
|
|
@ -25,15 +25,15 @@ pub trait Ports {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A UI component that may be associated with a JACK client by the `Jack` factory.
|
/// A UI component that may be associated with a JACK client by the `Jack` factory.
|
||||||
pub trait Device<E: Engine>: Component<E> + Audio {
|
pub trait AudioComponent<E: Engine>: Component<E> + Audio {
|
||||||
/// Perform type erasure for collecting heterogeneous devices.
|
/// Perform type erasure for collecting heterogeneous devices.
|
||||||
fn boxed (self) -> Box<dyn Device<E>> where Self: Sized + 'static {
|
fn boxed (self) -> Box<dyn AudioComponent<E>> where Self: Sized + 'static {
|
||||||
Box::new(self)
|
Box::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All things that implement the required traits can be treated as `Device`.
|
/// All things that implement the required traits can be treated as `AudioComponent`.
|
||||||
impl<E: Engine, W: Component<E> + Audio> Device<E> for W {}
|
impl<E: Engine, W: Component<E> + Audio> AudioComponent<E> for W {}
|
||||||
|
|
||||||
/// Wraps [Client] or [DynamicAsyncClient] in place.
|
/// Wraps [Client] or [DynamicAsyncClient] in place.
|
||||||
pub enum JackClient {
|
pub enum JackClient {
|
||||||
|
|
@ -112,7 +112,7 @@ pub fn jack_run <T, E: Engine> (name: &str, app: &Arc<RwLock<T>>) -> Usually<Dyn
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
|
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
|
||||||
/// and activation, and encapsulates a `Device` into a `JackDevice`.
|
/// and activation, and encapsulates a `AudioComponent` into a `JackDevice`.
|
||||||
pub struct Jack {
|
pub struct Jack {
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub midi_ins: Vec<String>,
|
pub midi_ins: Vec<String>,
|
||||||
|
|
@ -137,7 +137,7 @@ impl Jack {
|
||||||
pub fn run <'a: 'static, D, E> (
|
pub fn run <'a: 'static, D, E> (
|
||||||
self, state: impl FnOnce(JackPorts)->Box<D>
|
self, state: impl FnOnce(JackPorts)->Box<D>
|
||||||
) -> Usually<JackDevice<E>>
|
) -> Usually<JackDevice<E>>
|
||||||
where D: Device<E> + Sized + 'static,
|
where D: AudioComponent<E> + Sized + 'static,
|
||||||
E: Engine + 'static,
|
E: Engine + 'static,
|
||||||
{
|
{
|
||||||
let owned_ports = JackPorts {
|
let owned_ports = JackPorts {
|
||||||
|
|
@ -154,7 +154,7 @@ impl Jack {
|
||||||
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
let audio_ins = owned_ports.audio_ins.values()
|
let audio_ins = owned_ports.audio_ins.values()
|
||||||
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
let state = Arc::new(RwLock::new(state(owned_ports) as Box<dyn Device<E>>));
|
let state = Arc::new(RwLock::new(state(owned_ports) as Box<dyn AudioComponent<E>>));
|
||||||
let client = self.client.activate_async(
|
let client = self.client.activate_async(
|
||||||
Notifications(Box::new({
|
Notifications(Box::new({
|
||||||
let _state = state.clone();
|
let _state = state.clone();
|
||||||
|
|
@ -288,12 +288,12 @@ impl<T: Fn(JackEvent) + Send> NotificationHandler for Notifications<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Device] bound to a JACK client and a set of ports.
|
/// A [AudioComponent] bound to a JACK client and a set of ports.
|
||||||
pub struct JackDevice<E: Engine> {
|
pub struct JackDevice<E: Engine> {
|
||||||
/// The active JACK client of this device.
|
/// The active JACK client of this device.
|
||||||
pub client: DynamicAsyncClient,
|
pub client: DynamicAsyncClient,
|
||||||
/// The device state, encapsulated for sharing between threads.
|
/// The device state, encapsulated for sharing between threads.
|
||||||
pub state: Arc<RwLock<Box<dyn Device<E>>>>,
|
pub state: Arc<RwLock<Box<dyn AudioComponent<E>>>>,
|
||||||
/// Unowned copies of the device's JACK ports, for connecting to the device.
|
/// Unowned copies of the device's JACK ports, for connecting to the device.
|
||||||
/// The "real" readable/writable `Port`s are owned by the `state`.
|
/// The "real" readable/writable `Port`s are owned by the `state`.
|
||||||
pub ports: UnownedJackPorts,
|
pub ports: UnownedJackPorts,
|
||||||
|
|
@ -338,11 +338,11 @@ impl<E: Engine> Ports for JackDevice<E> {
|
||||||
|
|
||||||
impl<E: Engine> JackDevice<E> {
|
impl<E: Engine> JackDevice<E> {
|
||||||
/// Returns a locked mutex of the state's contents.
|
/// Returns a locked mutex of the state's contents.
|
||||||
pub fn state (&self) -> LockResult<RwLockReadGuard<Box<dyn Device<E>>>> {
|
pub fn state (&self) -> LockResult<RwLockReadGuard<Box<dyn AudioComponent<E>>>> {
|
||||||
self.state.read()
|
self.state.read()
|
||||||
}
|
}
|
||||||
/// Returns a locked mutex of the state's contents.
|
/// Returns a locked mutex of the state's contents.
|
||||||
pub fn state_mut (&self) -> LockResult<RwLockWriteGuard<Box<dyn Device<E>>>> {
|
pub fn state_mut (&self) -> LockResult<RwLockWriteGuard<Box<dyn AudioComponent<E>>>> {
|
||||||
self.state.write()
|
self.state.write()
|
||||||
}
|
}
|
||||||
pub fn connect_midi_in (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
|
pub fn connect_midi_in (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,6 @@ pub struct FillBg(pub Color);
|
||||||
|
|
||||||
impl Widget for FillBg {
|
impl Widget for FillBg {
|
||||||
type Engine = Tui;
|
type Engine = Tui;
|
||||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
|
||||||
Ok(Some(area))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||||
to.fill_bg(to.area(), self.0);
|
to.fill_bg(to.area(), self.0);
|
||||||
Ok(Some(to.area))
|
Ok(Some(to.area))
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,8 @@ where
|
||||||
{
|
{
|
||||||
type Engine = Tui;
|
type Engine = Tui;
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||||
let area = to.area();
|
self.layout(to.area())?
|
||||||
to.blit(&format!("L1 {area:?}"), 10, 10, None)?;
|
.map(|area|(self.0)(&mut |layer| {
|
||||||
let area = self.layout(to.area())?;
|
|
||||||
to.blit(&format!("L2 {area:?}"), 10, 11, None)?;
|
|
||||||
area.map(|area|(self.0)(&mut |layer| {
|
|
||||||
to.blit(&format!("L3 {area:?}"), 10, 12, None)?;
|
|
||||||
to.render_in(area, &layer)?;
|
to.render_in(area, &layer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}).map(|_|area))
|
}).map(|_|area))
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,21 @@ pub struct Plugin<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Plugin<E> {
|
impl<E> Plugin<E> {
|
||||||
|
/// Create a plugin host device.
|
||||||
|
pub fn new (name: &str) -> Usually<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
_engine: Default::default(),
|
||||||
|
name: name.into(),
|
||||||
|
path: None,
|
||||||
|
plugin: None,
|
||||||
|
selected: 0,
|
||||||
|
mapping: false,
|
||||||
|
ports: JackPorts::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin<Tui> {
|
||||||
pub fn new_lv2 (name: &str, path: &str) -> Usually<JackDevice<Tui>> {
|
pub fn new_lv2 (name: &str, path: &str) -> Usually<JackDevice<Tui>> {
|
||||||
let plugin = LV2Plugin::new(path)?;
|
let plugin = LV2Plugin::new(path)?;
|
||||||
jack_from_lv2(name, &plugin.plugin)?
|
jack_from_lv2(name, &plugin.plugin)?
|
||||||
|
|
@ -25,18 +40,6 @@ impl<E> Plugin<E> {
|
||||||
ports
|
ports
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
/// Create a plugin host device.
|
|
||||||
pub fn new (name: &str) -> Usually<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
_engine: Default::default(),
|
|
||||||
name: name.into(),
|
|
||||||
path: None,
|
|
||||||
plugin: None,
|
|
||||||
selected: 0,
|
|
||||||
mapping: false,
|
|
||||||
ports: JackPorts::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Audio for Plugin<E> {
|
impl<E> Audio for Plugin<E> {
|
||||||
|
|
|
||||||
|
|
@ -2,66 +2,64 @@ use crate::*;
|
||||||
|
|
||||||
impl Handle<Tui> for Plugin<Tui> {
|
impl Handle<Tui> for Plugin<Tui> {
|
||||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||||
handle_keymap(self, &from.event(), KEYMAP_PLUGIN).map(|x|Some(x))
|
match from.event() {
|
||||||
|
key!(KeyCode::Up) => {
|
||||||
|
self.selected = self.selected.saturating_sub(1);
|
||||||
|
Ok(Some(true))
|
||||||
|
},
|
||||||
|
key!(KeyCode::Down) => {
|
||||||
|
self.selected = (self.selected + 1).min(match &self.plugin {
|
||||||
|
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
|
||||||
|
_ => unimplemented!()
|
||||||
|
});
|
||||||
|
Ok(Some(true))
|
||||||
|
},
|
||||||
|
key!(KeyCode::PageUp) => {
|
||||||
|
self.selected = self.selected.saturating_sub(8);
|
||||||
|
Ok(Some(true))
|
||||||
|
},
|
||||||
|
key!(KeyCode::PageDown) => {
|
||||||
|
self.selected = (self.selected + 10).min(match &self.plugin {
|
||||||
|
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
|
||||||
|
_ => unimplemented!()
|
||||||
|
});
|
||||||
|
Ok(Some(true))
|
||||||
|
},
|
||||||
|
key!(KeyCode::Char(',')) => {
|
||||||
|
match self.plugin.as_mut() {
|
||||||
|
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
|
||||||
|
let index = port_list[self.selected].index;
|
||||||
|
if let Some(value) = instance.control_input(index) {
|
||||||
|
instance.set_control_input(index, value - 0.01);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(Some(true))
|
||||||
|
},
|
||||||
|
key!(KeyCode::Char('.')) => {
|
||||||
|
match self.plugin.as_mut() {
|
||||||
|
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
|
||||||
|
let index = port_list[self.selected].index;
|
||||||
|
if let Some(value) = instance.control_input(index) {
|
||||||
|
instance.set_control_input(index, value + 0.01);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(Some(true))
|
||||||
|
},
|
||||||
|
key!(KeyCode::Char('g')) => {
|
||||||
|
match self.plugin {
|
||||||
|
Some(PluginKind::LV2(ref mut plugin)) => {
|
||||||
|
plugin.ui_thread = Some(run_lv2_ui(LV2PluginUI::new()?)?);
|
||||||
|
},
|
||||||
|
Some(_) => unreachable!(),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
Ok(Some(true))
|
||||||
|
},
|
||||||
|
_ => Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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)
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl ::vst::host::Host for Plugin {}
|
impl<E: Engine> ::vst::host::Host for Plugin<E> {}
|
||||||
|
|
||||||
fn set_vst_plugin (host: &Arc<Mutex<Plugin>>, _path: &str) -> Usually<PluginKind> {
|
fn set_vst_plugin <E: Engine> (host: &Arc<Mutex<Plugin<E>>>, _path: &str) -> Usually<PluginKind> {
|
||||||
let mut loader = ::vst::host::PluginLoader::load(
|
let mut loader = ::vst::host::PluginLoader::load(
|
||||||
&std::path::Path::new("/nix/store/ij3sz7nqg5l7v2dygdvzy3w6cj62bd6r-helm-0.9.0/lib/lxvst/helm.so"),
|
&std::path::Path::new("/nix/store/ij3sz7nqg5l7v2dygdvzy3w6cj62bd6r-helm-0.9.0/lib/lxvst/helm.so"),
|
||||||
host.clone()
|
host.clone()
|
||||||
|
|
|
||||||
|
|
@ -26,39 +26,41 @@ impl Widget for AddSampleModal {
|
||||||
type Engine = Tui;
|
type Engine = Tui;
|
||||||
fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> {
|
fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> {
|
||||||
todo!()
|
todo!()
|
||||||
|
//Align::Center(()).layout(to)
|
||||||
}
|
}
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||||
let area = to.area();
|
todo!()
|
||||||
to.make_dim();
|
//let area = to.area();
|
||||||
let area = center_box(
|
//to.make_dim();
|
||||||
area,
|
//let area = center_box(
|
||||||
64.max(area.w().saturating_sub(8)),
|
//area,
|
||||||
20.max(area.w().saturating_sub(8)),
|
//64.max(area.w().saturating_sub(8)),
|
||||||
);
|
//20.max(area.w().saturating_sub(8)),
|
||||||
to.fill_fg(area, Color::Reset);
|
//);
|
||||||
to.fill_bg(area, Nord::bg_lo(true, true));
|
//to.fill_fg(area, Color::Reset);
|
||||||
to.fill_char(area, ' ');
|
//to.fill_bg(area, Nord::bg_lo(true, true));
|
||||||
to.blit(&format!("{}", &self.dir.to_string_lossy()), area.x()+2, area.y()+1, Some(Style::default().bold()))?;
|
//to.fill_char(area, ' ');
|
||||||
to.blit(&"Select sample:", area.x()+2, area.y()+2, Some(Style::default().bold()))?;
|
//to.blit(&format!("{}", &self.dir.to_string_lossy()), area.x()+2, area.y()+1, Some(Style::default().bold()))?;
|
||||||
for (i, (is_dir, name)) in self.subdirs.iter()
|
//to.blit(&"Select sample:", area.x()+2, area.y()+2, Some(Style::default().bold()))?;
|
||||||
.map(|path|(true, path))
|
//for (i, (is_dir, name)) in self.subdirs.iter()
|
||||||
.chain(self.files.iter().map(|path|(false, path)))
|
//.map(|path|(true, path))
|
||||||
.enumerate()
|
//.chain(self.files.iter().map(|path|(false, path)))
|
||||||
.skip(self.offset)
|
//.enumerate()
|
||||||
{
|
//.skip(self.offset)
|
||||||
if i >= area.h() as usize - 4 {
|
//{
|
||||||
break
|
//if i >= area.h() as usize - 4 {
|
||||||
}
|
//break
|
||||||
let t = if is_dir { "" } else { "" };
|
//}
|
||||||
let line = format!("{t} {}", name.to_string_lossy());
|
//let t = if is_dir { "" } else { "" };
|
||||||
let line = &line[..line.len().min(area.w() as usize - 4)];
|
//let line = format!("{t} {}", name.to_string_lossy());
|
||||||
to.blit(&line, area.x() + 2, area.y() + 3 + i as u16, Some(if i == self.cursor {
|
//let line = &line[..line.len().min(area.w() as usize - 4)];
|
||||||
Style::default().green()
|
//to.blit(&line, area.x() + 2, area.y() + 3 + i as u16, Some(if i == self.cursor {
|
||||||
} else {
|
//Style::default().green()
|
||||||
Style::default().white()
|
//} else {
|
||||||
}))?;
|
//Style::default().white()
|
||||||
}
|
//}))?;
|
||||||
Lozenge(Style::default()).draw(to)
|
//}
|
||||||
|
//Lozenge(Style::default()).draw(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Handle<Tui> for AddSampleModal {
|
impl Handle<Tui> for AddSampleModal {
|
||||||
|
|
@ -282,4 +284,3 @@ impl Sample {
|
||||||
Ok(sample)
|
Ok(sample)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ impl<E: Engine> Track<E> {
|
||||||
device: 0,
|
device: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn get_device_mut (&self, i: usize) -> Option<RwLockWriteGuard<Box<dyn Device<E>>>> {
|
fn get_device_mut (&self, i: usize) -> Option<RwLockWriteGuard<Box<dyn AudioComponent<E>>>> {
|
||||||
self.devices.get(i).map(|d|d.state.write().unwrap())
|
self.devices.get(i).map(|d|d.state.write().unwrap())
|
||||||
}
|
}
|
||||||
pub fn device_mut (&self) -> Option<RwLockWriteGuard<Box<dyn Device<E>>>> {
|
pub fn device_mut (&self) -> Option<RwLockWriteGuard<Box<dyn AudioComponent<E>>>> {
|
||||||
self.get_device_mut(self.device)
|
self.get_device_mut(self.device)
|
||||||
}
|
}
|
||||||
/// Add a device to the end of the chain.
|
/// Add a device to the end of the chain.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue