mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
launch clips
This commit is contained in:
parent
8a2693c297
commit
a4061535b5
7 changed files with 117 additions and 28 deletions
|
|
@ -134,6 +134,18 @@ pub trait Render {
|
||||||
fn render (&self, _b: &mut Buffer, _a: Rect) -> Usually<Rect> {
|
fn render (&self, _b: &mut Buffer, _a: Rect) -> Usually<Rect> {
|
||||||
Ok(Rect { x: 0, y: 0, width: 0, height: 0 })
|
Ok(Rect { x: 0, y: 0, width: 0, height: 0 })
|
||||||
}
|
}
|
||||||
|
fn min_width (&self) -> u16 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
fn max_width (&self) -> u16 {
|
||||||
|
u16::MAX
|
||||||
|
}
|
||||||
|
fn min_height (&self) -> u16 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
fn max_height (&self) -> u16 {
|
||||||
|
u16::MAX
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for Box<dyn Device> {
|
impl Render for Box<dyn Device> {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ enum PluginKind {
|
||||||
LV2 {
|
LV2 {
|
||||||
world: ::livi::World,
|
world: ::livi::World,
|
||||||
features: Arc<::livi::Features>,
|
features: Arc<::livi::Features>,
|
||||||
portList: Vec<::livi::Port>,
|
port_list: Vec<::livi::Port>,
|
||||||
instance: ::livi::Instance,
|
instance: ::livi::Instance,
|
||||||
},
|
},
|
||||||
VST2 {
|
VST2 {
|
||||||
|
|
@ -105,7 +105,7 @@ impl Plugin {
|
||||||
inputs.push(atom);
|
inputs.push(atom);
|
||||||
}
|
}
|
||||||
let mut outputs = vec![];
|
let mut outputs = vec![];
|
||||||
for port in self.midi_outs.iter() {
|
for _ in self.midi_outs.iter() {
|
||||||
outputs.push(::livi::event::LV2AtomSequence::new(
|
outputs.push(::livi::event::LV2AtomSequence::new(
|
||||||
&features,
|
&features,
|
||||||
scope.n_frames() as usize
|
scope.n_frames() as usize
|
||||||
|
|
@ -171,12 +171,12 @@ pub fn render (state: &Plugin, buf: &mut Buffer, area: Rect)
|
||||||
let Rect { x, y, height, .. } = area;
|
let Rect { x, y, height, .. } = area;
|
||||||
let mut width = 40u16;
|
let mut width = 40u16;
|
||||||
match &state.plugin {
|
match &state.plugin {
|
||||||
Some(PluginKind::LV2 { portList, instance, .. }) => {
|
Some(PluginKind::LV2 { port_list, instance, .. }) => {
|
||||||
let start = state.selected.saturating_sub((height as usize / 2).saturating_sub(1));
|
let start = state.selected.saturating_sub((height as usize / 2).saturating_sub(1));
|
||||||
let end = start + height as usize - 2;
|
let end = start + height as usize - 2;
|
||||||
//draw_box(buf, Rect { x, y, width, height });
|
//draw_box(buf, Rect { x, y, width, height });
|
||||||
for i in start..end {
|
for i in start..end {
|
||||||
if let Some(port) = portList.get(i) {
|
if let Some(port) = port_list.get(i) {
|
||||||
let value = if let Some(value) = instance.control_input(port.index) {
|
let value = if let Some(value) = instance.control_input(port.index) {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -218,7 +218,7 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
|
||||||
s.selected = s.selected - 1
|
s.selected = s.selected - 1
|
||||||
} else {
|
} else {
|
||||||
s.selected = match &s.plugin {
|
s.selected = match &s.plugin {
|
||||||
Some(PluginKind::LV2 { portList, .. }) => portList.len() - 1,
|
Some(PluginKind::LV2 { port_list, .. }) => port_list.len() - 1,
|
||||||
_ => 0
|
_ => 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -229,8 +229,8 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
|
||||||
|s: &mut Plugin|{
|
|s: &mut Plugin|{
|
||||||
s.selected = s.selected + 1;
|
s.selected = s.selected + 1;
|
||||||
match &s.plugin {
|
match &s.plugin {
|
||||||
Some(PluginKind::LV2 { portList, .. }) => {
|
Some(PluginKind::LV2 { port_list, .. }) => {
|
||||||
if s.selected >= portList.len() {
|
if s.selected >= port_list.len() {
|
||||||
s.selected = 0;
|
s.selected = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -242,8 +242,8 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
|
||||||
[Char(','), NONE, "decrement", "decrement value",
|
[Char(','), NONE, "decrement", "decrement value",
|
||||||
|s: &mut Plugin|{
|
|s: &mut Plugin|{
|
||||||
match s.plugin.as_mut() {
|
match s.plugin.as_mut() {
|
||||||
Some(PluginKind::LV2 { portList, ref mut instance, .. }) => {
|
Some(PluginKind::LV2 { port_list, ref mut instance, .. }) => {
|
||||||
let index = portList[s.selected].index;
|
let index = port_list[s.selected].index;
|
||||||
if let Some(value) = instance.control_input(index) {
|
if let Some(value) = instance.control_input(index) {
|
||||||
instance.set_control_input(index, value - 0.01);
|
instance.set_control_input(index, value - 0.01);
|
||||||
}
|
}
|
||||||
|
|
@ -256,8 +256,8 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
|
||||||
[Char('.'), NONE, "increment", "increment value",
|
[Char('.'), NONE, "increment", "increment value",
|
||||||
|s: &mut Plugin|{
|
|s: &mut Plugin|{
|
||||||
match s.plugin.as_mut() {
|
match s.plugin.as_mut() {
|
||||||
Some(PluginKind::LV2 { portList, ref mut instance, .. }) => {
|
Some(PluginKind::LV2 { port_list, ref mut instance, .. }) => {
|
||||||
let index = portList[s.selected].index;
|
let index = port_list[s.selected].index;
|
||||||
if let Some(value) = instance.control_input(index) {
|
if let Some(value) = instance.control_input(index) {
|
||||||
instance.set_control_input(index, value + 0.01);
|
instance.set_control_input(index, value + 0.01);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@ pub fn plug (uri: &str) -> Usually<PluginKind> {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
let plugin = plugin.unwrap();
|
let plugin = plugin.unwrap();
|
||||||
let mut portList = vec![];
|
let mut port_list = vec![];
|
||||||
for port in plugin.ports() {
|
for port in plugin.ports() {
|
||||||
portList.push(port);
|
port_list.push(port);
|
||||||
}
|
}
|
||||||
Ok(PluginKind::LV2 {
|
Ok(PluginKind::LV2 {
|
||||||
instance: unsafe {
|
instance: unsafe {
|
||||||
plugin.instantiate(features.clone(), 48000.0).expect("boop")
|
plugin.instantiate(features.clone(), 48000.0).expect("boop")
|
||||||
},
|
},
|
||||||
portList,
|
port_list,
|
||||||
features,
|
features,
|
||||||
world,
|
world,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,3 @@ fn set_vst_plugin (host: &Arc<Mutex<Plugin>>, path: &str) -> Usually<PluginKind>
|
||||||
instance: loader.instance()?
|
instance: loader.instance()?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//"file:///nix/store/ij3sz7nqg5l7v2dygdvzy3w6cj62bd6r-helm-0.9.0/lib/lxvst/helm.so"
|
|
||||||
|
|
|
||||||
|
|
@ -152,9 +152,10 @@ impl PortList for Sampler {
|
||||||
pub fn render (state: &Sampler, buf: &mut Buffer, Rect { x, y, height, .. }: Rect)
|
pub fn render (state: &Sampler, buf: &mut Buffer, Rect { x, y, height, .. }: Rect)
|
||||||
-> Usually<Rect>
|
-> Usually<Rect>
|
||||||
{
|
{
|
||||||
let width = 40;
|
|
||||||
let style = Style::default().gray();
|
let style = Style::default().gray();
|
||||||
format!(" {} ({})", state.name, state.voices.len()).blit(buf, x+1, y, Some(style.white().bold().not_dim()));
|
let title = format!(" {} ({})", state.name, state.voices.len());
|
||||||
|
title.blit(buf, x+1, y, Some(style.white().bold().not_dim()));
|
||||||
|
let mut width = title.len() + 2;
|
||||||
for (i, (note, sample)) in state.samples.iter().enumerate() {
|
for (i, (note, sample)) in state.samples.iter().enumerate() {
|
||||||
let style = if i == state.cursor.0 {
|
let style = if i == state.cursor.0 {
|
||||||
Style::default().green()
|
Style::default().green()
|
||||||
|
|
@ -169,12 +170,14 @@ pub fn render (state: &Sampler, buf: &mut Buffer, Rect { x, y, height, .. }: Rec
|
||||||
if i as usize == state.cursor.0 {
|
if i as usize == state.cursor.0 {
|
||||||
"⯈".blit(buf, x+1, y1, Some(style.bold()));
|
"⯈".blit(buf, x+1, y1, Some(style.bold()));
|
||||||
}
|
}
|
||||||
let label1 = format!("{note:3} {:10}", sample.name);
|
let label1 = format!("{note:3} {:8}", sample.name);
|
||||||
let label2 = format!("{:>7} {:>7}", sample.start, sample.end);
|
let label2 = format!("{:>6} {:>6}", sample.start, sample.end);
|
||||||
label1.blit(buf, x+2, y1, Some(style.bold()));
|
label1.blit(buf, x+2, y1, Some(style.bold()));
|
||||||
label2.blit(buf, x+3+label1.len()as u16, y1, Some(style));
|
label2.blit(buf, x+3+label1.len()as u16, y1, Some(style));
|
||||||
|
width = width.max(label1.len() + label2.len() + 4);
|
||||||
}
|
}
|
||||||
Ok(Rect { x, y, width, height })
|
let height = ((1 + state.samples.len()) as u16).min(height);
|
||||||
|
Ok(Rect { x, y, width: width as u16, height })
|
||||||
}
|
}
|
||||||
|
|
||||||
//fn render_table (
|
//fn render_table (
|
||||||
|
|
@ -225,9 +228,10 @@ pub fn handle (state: &mut Sampler, event: &AppEvent) -> Usually<bool> {
|
||||||
Ok(handle_keymap(state, event, KEYMAP)?)
|
Ok(handle_keymap(state, event, KEYMAP)?)
|
||||||
}
|
}
|
||||||
pub const KEYMAP: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
|
pub const KEYMAP: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
|
||||||
[Up, NONE, "cursor_up", "move cursor up", cursor_up],
|
[Up, NONE, "cursor_up", "move cursor up", cursor_up],
|
||||||
[Down, NONE, "cursor_down", "move cursor down", cursor_down],
|
[Down, NONE, "cursor_down", "move cursor down", cursor_down],
|
||||||
[Enter, NONE, "select", "select item under cursor", select],
|
[Char('t'), NONE, "trigger", "play current sample", trigger],
|
||||||
|
[Enter, NONE, "select", "select item under cursor", select],
|
||||||
});
|
});
|
||||||
fn cursor_up (state: &mut Sampler) -> Usually<bool> {
|
fn cursor_up (state: &mut Sampler) -> Usually<bool> {
|
||||||
state.cursor.0 = if state.cursor.0 == 0 {
|
state.cursor.0 = if state.cursor.0 == 0 {
|
||||||
|
|
@ -241,7 +245,7 @@ fn cursor_down (state: &mut Sampler) -> Usually<bool> {
|
||||||
state.cursor.0 = (state.cursor.0 + 1) % state.samples.len();
|
state.cursor.0 = (state.cursor.0 + 1) % state.samples.len();
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
fn select (state: &mut Sampler) -> Usually<bool> {
|
fn trigger (state: &mut Sampler) -> Usually<bool> {
|
||||||
for (i, sample) in state.samples.values().enumerate() {
|
for (i, sample) in state.samples.values().enumerate() {
|
||||||
if i == state.cursor.0 {
|
if i == state.cursor.0 {
|
||||||
state.voices.push(sample.play(0))
|
state.voices.push(sample.play(0))
|
||||||
|
|
@ -249,3 +253,11 @@ fn select (state: &mut Sampler) -> Usually<bool> {
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
fn select (state: &mut Sampler) -> Usually<bool> {
|
||||||
|
for (i, sample) in state.samples.values().enumerate() {
|
||||||
|
if i == state.cursor.0 {
|
||||||
|
//state.voices.push(sample.play(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,31 @@ pub const KEYMAP_TRACKS: &'static [KeyBinding<Launcher>] = keymap!(Launcher {
|
||||||
[Char(','), NONE, "clip_prev", "set clip to last phrase", clip_prev],
|
[Char(','), NONE, "clip_prev", "set clip to last phrase", clip_prev],
|
||||||
[Delete, CONTROL, "delete_track", "delete track", delete_track],
|
[Delete, CONTROL, "delete_track", "delete track", delete_track],
|
||||||
[Char('d'), CONTROL, "duplicate", "duplicate scene or track", duplicate],
|
[Char('d'), CONTROL, "duplicate", "duplicate scene or track", duplicate],
|
||||||
[Enter, NONE, "clip_enter", "play or record clip or stop and advance", clip_enter],
|
[Enter, NONE, "activate", "activate item at cursor", activate],
|
||||||
});
|
});
|
||||||
fn duplicate (_: &mut Launcher) -> Usually<bool> {
|
fn duplicate (_: &mut Launcher) -> Usually<bool> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
fn clip_enter (_: &mut Launcher) -> Usually<bool> {
|
fn activate (state: &mut Launcher) -> Usually<bool> {
|
||||||
|
if let (
|
||||||
|
Some((scene_id, scene)),
|
||||||
|
Some((track_id, track)),
|
||||||
|
) = (state.scene(), state.track()) {
|
||||||
|
// Launch clip
|
||||||
|
if let Some(Some(phrase_id)) = scene.clips.get(track_id) {
|
||||||
|
track.sequencer.state().sequence = *phrase_id;
|
||||||
|
}
|
||||||
|
} else if let Some((scene_id, scene)) = state.scene() {
|
||||||
|
// Launch scene
|
||||||
|
for (track_id, track) in state.tracks.iter().enumerate() {
|
||||||
|
if let Some(Some(phrase_id)) = scene.clips.get(track_id) {
|
||||||
|
track.sequencer.state().sequence = *phrase_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some((track_id, track)) = state.track() {
|
||||||
|
// Rename track?
|
||||||
|
}
|
||||||
|
|
||||||
//let track = state.active_track().unwrap();
|
//let track = state.active_track().unwrap();
|
||||||
//let scene = state.active_scene();
|
//let scene = state.active_scene();
|
||||||
//if state.cursor.1 >= 2 {
|
//if state.cursor.1 >= 2 {
|
||||||
|
|
|
||||||
51
src/main.rs
51
src/main.rs
|
|
@ -69,6 +69,9 @@ fn main () -> Result<(), Box<dyn Error>> {
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
|
MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
|
||||||
] ),
|
] ),
|
||||||
|
play!(1 => [
|
||||||
|
MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
play!(2 => [
|
play!(2 => [
|
||||||
MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
|
MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
|
||||||
]),
|
]),
|
||||||
|
|
@ -146,6 +149,50 @@ fn main () -> Result<(), Box<dyn Error>> {
|
||||||
MidiMessage::NoteOff { key: 41.into(), vel: 100.into() },
|
MidiMessage::NoteOff { key: 41.into(), vel: 100.into() },
|
||||||
MidiMessage::NoteOn { key: 42.into(), vel: 100.into() },
|
MidiMessage::NoteOn { key: 42.into(), vel: 100.into() },
|
||||||
]),
|
]),
|
||||||
|
]))),
|
||||||
|
Phrase::new("E E G Bb", ppq * 4, Some(BTreeMap::from([
|
||||||
|
play!(2 => [
|
||||||
|
MidiMessage::NoteOff { key: 42.into(), vel: 100.into() },
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(6 => [
|
||||||
|
MidiMessage::NoteOff { key: 36.into(), vel: 100.into() },
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(10 => [
|
||||||
|
MidiMessage::NoteOff { key: 36.into(), vel: 100.into() },
|
||||||
|
MidiMessage::NoteOn { key: 39.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(14 => [
|
||||||
|
MidiMessage::NoteOff { key: 39.into(), vel: 100.into() },
|
||||||
|
MidiMessage::NoteOn { key: 42.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
]))),
|
||||||
|
Phrase::new("E E E E", ppq * 4, Some(BTreeMap::from([
|
||||||
|
play!(0 => [
|
||||||
|
MidiMessage::NoteOff { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(2 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(4 => [
|
||||||
|
MidiMessage::NoteOff { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(6 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(8 => [
|
||||||
|
MidiMessage::NoteOff { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(10 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(12 => [
|
||||||
|
MidiMessage::NoteOff { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(14 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
])))
|
])))
|
||||||
]))?,
|
]))?,
|
||||||
|
|
||||||
|
|
@ -156,8 +203,8 @@ fn main () -> Result<(), Box<dyn Error>> {
|
||||||
Some(vec![
|
Some(vec![
|
||||||
Scene::new(&"Scene 1", &[Some(0), None, None, None]),
|
Scene::new(&"Scene 1", &[Some(0), None, None, None]),
|
||||||
Scene::new(&"Scene 2", &[Some(0), Some(0), None, None]),
|
Scene::new(&"Scene 2", &[Some(0), Some(0), None, None]),
|
||||||
Scene::new(&"Scene 3", &[Some(1), Some(0), None, None]),
|
Scene::new(&"Scene 3", &[Some(1), Some(1), None, None]),
|
||||||
Scene::new(&"Scene 4", &[Some(2), Some(0), None, None]),
|
Scene::new(&"Scene 4", &[Some(2), Some(2), None, None]),
|
||||||
//Scene::new(&"Scene#03", &[None, Some(0), None, None]),
|
//Scene::new(&"Scene#03", &[None, Some(0), None, None]),
|
||||||
//Scene::new(&"Scene#04", &[None, None, None, None]),
|
//Scene::new(&"Scene#04", &[None, None, None, None]),
|
||||||
//Scene::new(&"Scene#05", &[None, None, None, None]),
|
//Scene::new(&"Scene#05", &[None, None, None, None]),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue