mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-03-13 11:50:44 +01:00
parent
236ee6b810
commit
cb989baf83
8 changed files with 674 additions and 283 deletions
|
|
@ -1,63 +0,0 @@
|
|||
[package]
|
||||
name = "tek"
|
||||
edition = { workspace = true }
|
||||
version = { workspace = true }
|
||||
|
||||
[lib]
|
||||
path = "tek.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "tek"
|
||||
path = "tek.rs"
|
||||
|
||||
[target.'cfg(target_os = "linux")']
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.12.1"
|
||||
atomic_float = { workspace = true }
|
||||
backtrace = { workspace = true }
|
||||
builder-pattern = "0.4.2"
|
||||
clap = { workspace = true, optional = true }
|
||||
jack = { workspace = true }
|
||||
konst = { workspace = true }
|
||||
livi = { workspace = true, optional = true }
|
||||
midly = { workspace = true }
|
||||
palette = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
symphonia = { workspace = true, optional = true }
|
||||
tengri = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
uuid = { workspace = true, optional = true }
|
||||
wavers = { workspace = true, optional = true }
|
||||
winit = { workspace = true, optional = true }
|
||||
xdg = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
proptest = { workspace = true }
|
||||
proptest-derive = { workspace = true }
|
||||
|
||||
[features]
|
||||
arranger = ["port", "editor", "sequencer", "editor", "track", "scene", "clip", "select"]
|
||||
browse = []
|
||||
clap = []
|
||||
cli = ["dep:clap"]
|
||||
clip = []
|
||||
clock = []
|
||||
default = ["cli", "arranger", "sampler", "lv2"]
|
||||
editor = []
|
||||
host = ["lv2"]
|
||||
lv2 = ["port", "livi"]
|
||||
lv2_gui = ["lv2", "winit"]
|
||||
meter = []
|
||||
mixer = []
|
||||
pool = []
|
||||
port = []
|
||||
sampler = ["port", "meter", "mixer", "browse", "symphonia", "wavers"]
|
||||
scene = []
|
||||
select = []
|
||||
sequencer = ["port", "clock", "uuid", "pool"]
|
||||
sf2 = []
|
||||
track = []
|
||||
vst2 = []
|
||||
vst3 = []
|
||||
|
|
@ -1167,7 +1167,7 @@ mod view {
|
|||
&connect.info)))))))))
|
||||
}
|
||||
|
||||
pub fn draw_header (state: &Lv2, to: &mut TuiOut, x: u16, y: u16, w: u16) {
|
||||
#[cfg(feature = "lv2")] pub fn draw_header (state: &Lv2, to: &mut TuiOut, x: u16, y: u16, w: u16) {
|
||||
let style = Style::default().gray();
|
||||
let label1 = format!(" {}", state.name);
|
||||
to.blit(&label1, x + 1, y, Some(style.white().bold()));
|
||||
|
|
|
|||
237
app/tek_impls.rs
237
app/tek_impls.rs
|
|
@ -1850,129 +1850,6 @@ impl HasContent<TuiOut> for OctaveVertical {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Lv2 {
|
||||
|
||||
pub fn new (
|
||||
jack: &Jack<'static>,
|
||||
name: &str,
|
||||
uri: &str,
|
||||
) -> Usually<Self> {
|
||||
let lv2_world = livi::World::with_load_bundle(&uri);
|
||||
let lv2_features = lv2_world.build_features(livi::FeaturesBuilder {
|
||||
min_block_length: 1,
|
||||
max_block_length: 65536,
|
||||
});
|
||||
let lv2_plugin = lv2_world.iter_plugins().nth(0)
|
||||
.unwrap_or_else(||panic!("plugin not found: {uri}"));
|
||||
Ok(Self {
|
||||
jack: jack.clone(),
|
||||
name: name.into(),
|
||||
path: Some(String::from(uri).into()),
|
||||
selected: 0,
|
||||
mapping: false,
|
||||
midi_ins: vec![],
|
||||
midi_outs: vec![],
|
||||
audio_ins: vec![],
|
||||
audio_outs: vec![],
|
||||
lv2_instance: unsafe {
|
||||
lv2_plugin
|
||||
.instantiate(lv2_features.clone(), 48000.0)
|
||||
.expect(&format!("instantiate failed: {uri}"))
|
||||
},
|
||||
lv2_port_list: lv2_plugin.ports().collect::<Vec<_>>(),
|
||||
lv2_input_buffer: Vec::with_capacity(Self::INPUT_BUFFER),
|
||||
lv2_ui_thread: None,
|
||||
lv2_world,
|
||||
lv2_features,
|
||||
lv2_plugin,
|
||||
})
|
||||
}
|
||||
|
||||
const INPUT_BUFFER: usize = 1024;
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn lv2_jack_process (
|
||||
Lv2 {
|
||||
midi_ins, midi_outs, audio_ins, audio_outs,
|
||||
lv2_features, lv2_instance, lv2_input_buffer, ..
|
||||
}: &mut Lv2,
|
||||
_client: &Client,
|
||||
scope: &ProcessScope
|
||||
) -> Control {
|
||||
|
||||
let urid = lv2_features.midi_urid();
|
||||
|
||||
lv2_input_buffer.clear();
|
||||
|
||||
for port in midi_ins.iter() {
|
||||
let mut atom = ::livi::event::LV2AtomSequence::new(
|
||||
&lv2_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(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
lv2_input_buffer.push(atom);
|
||||
}
|
||||
|
||||
let mut outputs = vec![];
|
||||
|
||||
for _ in midi_outs.iter() {
|
||||
outputs.push(::livi::event::LV2AtomSequence::new(
|
||||
lv2_features,
|
||||
scope.n_frames() as usize
|
||||
));
|
||||
}
|
||||
|
||||
let ports = ::livi::EmptyPortConnections::new()
|
||||
.with_atom_sequence_inputs(lv2_input_buffer.iter())
|
||||
.with_atom_sequence_outputs(outputs.iter_mut())
|
||||
.with_audio_inputs(audio_ins.iter().map(|o|o.as_slice(scope)))
|
||||
.with_audio_outputs(audio_outs.iter_mut().map(|o|o.as_mut_slice(scope)));
|
||||
|
||||
unsafe {
|
||||
lv2_instance.run(scope.n_frames() as usize, ports).unwrap()
|
||||
};
|
||||
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "lv2_gui")]
|
||||
impl LV2PluginUI {
|
||||
pub fn new () -> Usually<Self> {
|
||||
Ok(Self { window: None })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "lv2_gui")]
|
||||
impl ApplicationHandler for LV2PluginUI {
|
||||
fn resumed (&mut self, event_loop: &ActiveEventLoop) {
|
||||
self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
|
||||
}
|
||||
fn window_event (&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
self.window.as_ref().unwrap().set_visible(false);
|
||||
event_loop.exit();
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
self.window.as_ref().unwrap().request_redraw();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Layout<TuiOut> for RmsMeter {}
|
||||
impl Layout<TuiOut> for Log10Meter {}
|
||||
impl Pool {
|
||||
|
|
@ -3825,7 +3702,7 @@ mod draw {
|
|||
impl Draw<TuiOut> for MidiEditor {
|
||||
fn draw (&self, to: &mut TuiOut) { self.content().draw(to) }
|
||||
}
|
||||
impl Draw<TuiOut> for Lv2 {
|
||||
#[cfg(feature = "lv2")] impl Draw<TuiOut> for Lv2 {
|
||||
fn draw (&self, to: &mut TuiOut) {
|
||||
let area = to.area();
|
||||
let XYWH(x, y, _, height) = area;
|
||||
|
|
@ -4001,7 +3878,7 @@ impl<J: HasJack<'static>> RegisterPorts for J {
|
|||
#[cfg(feature = "port")] has!(Vec<MidiOutput>: |self: Sequencer|self.midi_outs);
|
||||
|
||||
audio!(App: tek_jack_process, tek_jack_event);
|
||||
audio!(Lv2: lv2_jack_process);
|
||||
#[cfg(feature = "lv2")] audio!(Lv2: lv2_jack_process);
|
||||
audio!(Sampler: sampler_jack_process);
|
||||
has!(Jack<'static>: |self: App|self.jack);
|
||||
has!(Dialog: |self: App|self.dialog);
|
||||
|
|
@ -4119,3 +3996,113 @@ handle!(TuiIn: |self: App, input|{
|
|||
self.history.extend(history.into_iter());
|
||||
Ok(None)
|
||||
});
|
||||
|
||||
#[cfg(feature = "lv2")] impl Lv2 {
|
||||
const INPUT_BUFFER: usize = 1024;
|
||||
pub fn new (
|
||||
jack: &Jack<'static>,
|
||||
name: &str,
|
||||
uri: &str,
|
||||
) -> Usually<Self> {
|
||||
let lv2_world = livi::World::with_load_bundle(&uri);
|
||||
let lv2_features = lv2_world.build_features(livi::FeaturesBuilder {
|
||||
min_block_length: 1,
|
||||
max_block_length: 65536,
|
||||
});
|
||||
let lv2_plugin = lv2_world.iter_plugins().nth(0)
|
||||
.unwrap_or_else(||panic!("plugin not found: {uri}"));
|
||||
Ok(Self {
|
||||
jack: jack.clone(),
|
||||
name: name.into(),
|
||||
path: Some(String::from(uri).into()),
|
||||
selected: 0,
|
||||
mapping: false,
|
||||
midi_ins: vec![],
|
||||
midi_outs: vec![],
|
||||
audio_ins: vec![],
|
||||
audio_outs: vec![],
|
||||
lv2_instance: unsafe {
|
||||
lv2_plugin
|
||||
.instantiate(lv2_features.clone(), 48000.0)
|
||||
.expect(&format!("instantiate failed: {uri}"))
|
||||
},
|
||||
lv2_port_list: lv2_plugin.ports().collect::<Vec<_>>(),
|
||||
lv2_input_buffer: Vec::with_capacity(Self::INPUT_BUFFER),
|
||||
lv2_ui_thread: None,
|
||||
lv2_world,
|
||||
lv2_features,
|
||||
lv2_plugin,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "lv2")] fn lv2_jack_process (
|
||||
Lv2 {
|
||||
midi_ins, midi_outs, audio_ins, audio_outs,
|
||||
lv2_features, lv2_instance, lv2_input_buffer, ..
|
||||
}: &mut Lv2,
|
||||
_client: &Client,
|
||||
scope: &ProcessScope
|
||||
) -> Control {
|
||||
let urid = lv2_features.midi_urid();
|
||||
lv2_input_buffer.clear();
|
||||
for port in midi_ins.iter() {
|
||||
let mut atom = ::livi::event::LV2AtomSequence::new(
|
||||
&lv2_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(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
lv2_input_buffer.push(atom);
|
||||
}
|
||||
let mut outputs = vec![];
|
||||
for _ in midi_outs.iter() {
|
||||
outputs.push(::livi::event::LV2AtomSequence::new(
|
||||
lv2_features,
|
||||
scope.n_frames() as usize
|
||||
));
|
||||
}
|
||||
let ports = ::livi::EmptyPortConnections::new()
|
||||
.with_atom_sequence_inputs(lv2_input_buffer.iter())
|
||||
.with_atom_sequence_outputs(outputs.iter_mut())
|
||||
.with_audio_inputs(audio_ins.iter().map(|o|o.as_slice(scope)))
|
||||
.with_audio_outputs(audio_outs.iter_mut().map(|o|o.as_mut_slice(scope)));
|
||||
unsafe {
|
||||
lv2_instance.run(scope.n_frames() as usize, ports).unwrap()
|
||||
};
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
#[cfg(feature = "lv2_gui")]
|
||||
impl LV2PluginUI {
|
||||
pub fn new () -> Usually<Self> {
|
||||
Ok(Self { window: None })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "lv2_gui")]
|
||||
impl ApplicationHandler for LV2PluginUI {
|
||||
fn resumed (&mut self, event_loop: &ActiveEventLoop) {
|
||||
self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
|
||||
}
|
||||
fn window_event (&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
self.window.as_ref().unwrap().set_visible(false);
|
||||
event_loop.exit();
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
self.window.as_ref().unwrap().request_redraw();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue