diff --git a/src/device.rs b/src/device.rs index e617730c..8225eec5 100644 --- a/src/device.rs +++ b/src/device.rs @@ -134,6 +134,18 @@ pub trait Render { fn render (&self, _b: &mut Buffer, _a: Rect) -> Usually { 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 { diff --git a/src/device/chain/plugin.rs b/src/device/chain/plugin.rs index 87480749..1a28e145 100644 --- a/src/device/chain/plugin.rs +++ b/src/device/chain/plugin.rs @@ -21,7 +21,7 @@ enum PluginKind { LV2 { world: ::livi::World, features: Arc<::livi::Features>, - portList: Vec<::livi::Port>, + port_list: Vec<::livi::Port>, instance: ::livi::Instance, }, VST2 { @@ -105,7 +105,7 @@ impl Plugin { inputs.push(atom); } let mut outputs = vec![]; - for port in self.midi_outs.iter() { + for _ in self.midi_outs.iter() { outputs.push(::livi::event::LV2AtomSequence::new( &features, 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 mut width = 40u16; 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 end = start + height as usize - 2; //draw_box(buf, Rect { x, y, width, height }); 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) { value } else { @@ -218,7 +218,7 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually { s.selected = s.selected - 1 } else { s.selected = match &s.plugin { - Some(PluginKind::LV2 { portList, .. }) => portList.len() - 1, + Some(PluginKind::LV2 { port_list, .. }) => port_list.len() - 1, _ => 0 } } @@ -229,8 +229,8 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually { |s: &mut Plugin|{ s.selected = s.selected + 1; match &s.plugin { - Some(PluginKind::LV2 { portList, .. }) => { - if s.selected >= portList.len() { + Some(PluginKind::LV2 { port_list, .. }) => { + if s.selected >= port_list.len() { s.selected = 0; } }, @@ -242,8 +242,8 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually { [Char(','), NONE, "decrement", "decrement value", |s: &mut Plugin|{ match s.plugin.as_mut() { - Some(PluginKind::LV2 { portList, ref mut instance, .. }) => { - let index = portList[s.selected].index; + Some(PluginKind::LV2 { 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); } @@ -256,8 +256,8 @@ pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually { [Char('.'), NONE, "increment", "increment value", |s: &mut Plugin|{ match s.plugin.as_mut() { - Some(PluginKind::LV2 { portList, ref mut instance, .. }) => { - let index = portList[s.selected].index; + Some(PluginKind::LV2 { 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); } diff --git a/src/device/chain/plugin/lv2.rs b/src/device/chain/plugin/lv2.rs index 98c56deb..7d1e9d4f 100644 --- a/src/device/chain/plugin/lv2.rs +++ b/src/device/chain/plugin/lv2.rs @@ -13,15 +13,15 @@ pub fn plug (uri: &str) -> Usually { break } let plugin = plugin.unwrap(); - let mut portList = vec![]; + let mut port_list = vec![]; for port in plugin.ports() { - portList.push(port); + port_list.push(port); } Ok(PluginKind::LV2 { instance: unsafe { plugin.instantiate(features.clone(), 48000.0).expect("boop") }, - portList, + port_list, features, world, }) diff --git a/src/device/chain/plugin/vst2.rs b/src/device/chain/plugin/vst2.rs index e51801a6..4d2a3242 100644 --- a/src/device/chain/plugin/vst2.rs +++ b/src/device/chain/plugin/vst2.rs @@ -12,4 +12,3 @@ fn set_vst_plugin (host: &Arc>, path: &str) -> Usually instance: loader.instance()? }) } - //"file:///nix/store/ij3sz7nqg5l7v2dygdvzy3w6cj62bd6r-helm-0.9.0/lib/lxvst/helm.so" diff --git a/src/device/chain/sampler.rs b/src/device/chain/sampler.rs index 088e075a..b56699af 100644 --- a/src/device/chain/sampler.rs +++ b/src/device/chain/sampler.rs @@ -152,9 +152,10 @@ impl PortList for Sampler { pub fn render (state: &Sampler, buf: &mut Buffer, Rect { x, y, height, .. }: Rect) -> Usually { - let width = 40; 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() { let style = if i == state.cursor.0 { 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 { "⯈".blit(buf, x+1, y1, Some(style.bold())); } - let label1 = format!("{note:3} {:10}", sample.name); - let label2 = format!("{:>7} {:>7}", sample.start, sample.end); + let label1 = format!("{note:3} {:8}", sample.name); + let label2 = format!("{:>6} {:>6}", sample.start, sample.end); label1.blit(buf, x+2, y1, Some(style.bold())); 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 ( @@ -225,9 +228,10 @@ pub fn handle (state: &mut Sampler, event: &AppEvent) -> Usually { Ok(handle_keymap(state, event, KEYMAP)?) } pub const KEYMAP: &'static [KeyBinding] = keymap!(Sampler { - [Up, NONE, "cursor_up", "move cursor up", cursor_up], - [Down, NONE, "cursor_down", "move cursor down", cursor_down], - [Enter, NONE, "select", "select item under cursor", select], + [Up, NONE, "cursor_up", "move cursor up", cursor_up], + [Down, NONE, "cursor_down", "move cursor down", cursor_down], + [Char('t'), NONE, "trigger", "play current sample", trigger], + [Enter, NONE, "select", "select item under cursor", select], }); fn cursor_up (state: &mut Sampler) -> Usually { state.cursor.0 = if state.cursor.0 == 0 { @@ -241,7 +245,7 @@ fn cursor_down (state: &mut Sampler) -> Usually { state.cursor.0 = (state.cursor.0 + 1) % state.samples.len(); Ok(true) } -fn select (state: &mut Sampler) -> Usually { +fn trigger (state: &mut Sampler) -> Usually { for (i, sample) in state.samples.values().enumerate() { if i == state.cursor.0 { state.voices.push(sample.play(0)) @@ -249,3 +253,11 @@ fn select (state: &mut Sampler) -> Usually { } Ok(true) } +fn select (state: &mut Sampler) -> Usually { + for (i, sample) in state.samples.values().enumerate() { + if i == state.cursor.0 { + //state.voices.push(sample.play(0)) + } + } + Ok(true) +} diff --git a/src/device/launcher/handle.rs b/src/device/launcher/handle.rs index 3fa5ed0d..14b13407 100644 --- a/src/device/launcher/handle.rs +++ b/src/device/launcher/handle.rs @@ -43,12 +43,31 @@ pub const KEYMAP_TRACKS: &'static [KeyBinding] = keymap!(Launcher { [Char(','), NONE, "clip_prev", "set clip to last phrase", clip_prev], [Delete, CONTROL, "delete_track", "delete track", delete_track], [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 { Ok(true) } -fn clip_enter (_: &mut Launcher) -> Usually { +fn activate (state: &mut Launcher) -> Usually { + 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 scene = state.active_scene(); //if state.cursor.1 >= 2 { diff --git a/src/main.rs b/src/main.rs index 57eb523f..2b397eab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,6 +69,9 @@ fn main () -> Result<(), Box> { MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }, MidiMessage::NoteOn { key: 44.into(), vel: 100.into() }, ] ), + play!(1 => [ + MidiMessage::NoteOn { key: 44.into(), vel: 100.into() }, + ]), play!(2 => [ MidiMessage::NoteOn { key: 44.into(), vel: 100.into() }, ]), @@ -146,6 +149,50 @@ fn main () -> Result<(), Box> { MidiMessage::NoteOff { key: 41.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> { Some(vec![ Scene::new(&"Scene 1", &[Some(0), None, 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 4", &[Some(2), Some(0), None, None]), + Scene::new(&"Scene 3", &[Some(1), Some(1), None, None]), + Scene::new(&"Scene 4", &[Some(2), Some(2), None, None]), //Scene::new(&"Scene#03", &[None, Some(0), None, None]), //Scene::new(&"Scene#04", &[None, None, None, None]), //Scene::new(&"Scene#05", &[None, None, None, None]),