bye launcher

This commit is contained in:
🪞👃🪞 2024-07-03 18:11:40 +03:00
parent 7bc396e748
commit 2165e5d45d
10 changed files with 451 additions and 862 deletions

View file

@ -13,18 +13,7 @@ pub mod core;
pub mod model;
pub mod view;
use crate::core::*;
use crate::model::*;
use crate::view::*;
macro_rules! phrase {
($($t:expr => $msg:expr),* $(,)?) => {{
let mut phrase = BTreeMap::new();
$(phrase.insert($t, vec![]);)*
$(phrase.get_mut(&$t).unwrap().push($msg);)*
phrase
}}
}
use crate::{core::*, model::*};
pub fn main () -> Usually<()> {
App::default().run(Some(|app: Arc<Mutex<App>>|{
@ -80,7 +69,10 @@ pub fn main () -> Usually<()> {
];
state.track_cursor = 1;
state.scene_cursor = 1;
state.midi_in = Some(jack.as_client().register_port("midi-in", MidiIn)?);
let client = jack.as_client();
state.midi_in = Some(client.register_port("midi-in", MidiIn)?);
state.transport = Some(client.transport());
state.playing = Some(TransportState::Stopped);
state.jack = Some(jack);
Ok(())
}))
@ -98,385 +90,93 @@ pub struct App {
pub tracks: Vec<Track>,
pub track_cursor: usize,
pub frame: usize,
pub timebase: Arc<Timebase>,
pub modal: Option<Box<dyn Component>>,
pub section: usize,
pub entered: bool,
pub playing: Option<TransportState>,
pub transport: Option<Transport>,
pub timebase: Arc<Timebase>,
pub playhead: usize,
pub midi_in: Option<Port<MidiIn>>,
pub audio_outs: Option<Vec<Port<AudioOut>>>,
pub metronome: bool,
}
process!(App);
render!(App |self, buf, area| {
let Rect { x, mut y, width, height } = area;
y = y + TransportView {
timebase: &self.timebase,
playing: TransportState::Stopped,
record: false,
overdub: false,
monitor: false,
frame: 0,
}.render(buf, area)?.height;
y = y + SceneGridView {
buf,
area: Rect { x, y, width, height: height / 3 },
name: "",
mode: self.grid_mode,
focused: self.section == 0,
scenes: &self.scenes,
tracks: &self.tracks,
cursor: &(self.track_cursor, self.scene_cursor),
}.draw()?.height;
if self.track_cursor > 0 {
let track = self.tracks.get(self.track_cursor - 1);
y = y + ChainView {
focused: self.section == 1,
chain: track.map(|t|&t.chain),
}.render(buf, Rect { x, y, width, height: height / 3 })?.height;
y = y + SequencerView {
focused: self.section == 2,
ppq: self.timebase.ppq() as usize,
track: track,
phrase: track.map(|t|&t.sequencer.phrases[0]),
}.render(buf, Rect { x, y, width, height })?.height;
process!(App |self, client, scope| {
let transport = self.transport.as_ref().unwrap().query().unwrap();
self.playing = Some(transport.state);
self.playhead = transport.pos.frame() as usize;
for Track { sequencer, .. } in self.tracks.iter_mut() {
sequencer.process(client, scope);
}
if let Some(ref modal) = self.modal {
modal.render(buf, area)?;
}
Ok(area)
Control::Continue
});
handle!(App |self, e| {
if let Some(ref mut modal) = self.modal {
if modal.handle(e)? {
self.modal = None;
return Ok(true)
};
}
handle_keymap(self, e, KEYMAP)
});
const KEYMAP: &'static [KeyBinding<App>] = keymap!(App {
[F(1), NONE, "toggle_help", "toggle help", toggle_help],
[Tab, NONE, "focus_next", "focus next area", focus_next],
[Tab, SHIFT, "focus_prev", "focus previous area", focus_prev],
[Up, NONE, "cursor_up", "move cursor up", cursor_up],
[Down, NONE, "cursor_down", "move cursor down", cursor_down],
[Left, NONE, "cursor_left", "move cursor left", cursor_left],
[Right, NONE, "cursor_right", "move cursor right", cursor_right],
[Char('.'), NONE, "increment", "increment value at cursor", increment],
[Char(','), NONE, "decrement", "decrement value at cursor", decrement],
[Delete, CONTROL, "delete", "delete track", delete],
[Char('d'), CONTROL, "duplicate", "duplicate scene or track", duplicate],
[Enter, NONE, "activate", "activate item at cursor", enter],
[Esc, NONE, "escape", "unfocus", escape],
[Char(' '), NONE, "play_toggle", "play or pause", play_toggle],
[Char('r'), NONE, "record_toggle", "toggle recording", record_toggle],
[Char('d'), NONE, "overdub_toggle", "toggle overdub", overdub_toggle],
[Char('m'), NONE, "monitor_toggle", "toggle input monitoring", monitor_toggle],
[Char('r'), CONTROL, "rename", "rename current element", rename],
[Char('t'), CONTROL, "add_track", "add a new track", add_track],
[Char('a'), CONTROL, "add_scene", "add a new scene", add_scene],
[Char('`'), NONE, "switch_mode", "switch the display mode", switch_mode],
//[Char(' '), SHIFT, "play_start", "play from start", play_start],
});
fn switch_mode (app: &mut App) -> Usually<bool> {
match app.section {
0 => {app.grid_mode = !app.grid_mode; Ok(true)},
1 => {app.chain_mode = !app.chain_mode; Ok(true)},
2 => {app.seq_mode = !app.seq_mode; Ok(true)},
_ => Ok(false)
}
}
fn focus_next (app: &mut App) -> Usually<bool> {
if app.section >= 2 {
app.section = 0;
} else {
app.section = app.section + 1;
}
Ok(true)
}
fn focus_prev (app: &mut App) -> Usually<bool> {
if app.section == 0 {
app.section = 2;
} else {
app.section = app.section - 1;
}
Ok(true)
}
fn cursor_up (app: &mut App) -> Usually<bool> {
if app.entered {
match app.section {
0 => match app.grid_mode {
false => {app.scene_cursor = app.scene_cursor.saturating_sub(1); Ok(true)},
true => {app.track_cursor = app.track_cursor.saturating_sub(1); Ok(true)},
},
_ => Ok(false)
}
} else {
focus_prev(app)
}
}
fn cursor_down (app: &mut App) -> Usually<bool> {
if app.entered {
match app.section {
0 => match app.grid_mode {
false => {app.scene_cursor = app.scenes.len().min(app.scene_cursor + 1); Ok(true)},
true => {app.track_cursor = app.tracks.len().min(app.track_cursor + 1); Ok(true)},
},
_ => Ok(false)
}
} else {
focus_next(app)
}
}
fn cursor_left (app: &mut App) -> Usually<bool> {
match app.section {
0 => match app.grid_mode {
false => {app.track_cursor = app.track_cursor.saturating_sub(1); Ok(true)},
true => {app.scene_cursor = app.scene_cursor.saturating_sub(1); Ok(true)},
},
_ => Ok(false)
}
}
fn cursor_right (app: &mut App) -> Usually<bool> {
match app.section {
0 => match app.grid_mode {
false => {app.track_cursor = app.tracks.len().min(app.track_cursor + 1); Ok(true)},
true => {app.scene_cursor = app.scenes.len().min(app.scene_cursor + 1); Ok(true)},
},
_ => Ok(false)
}
}
fn increment (app: &mut App) -> Usually<bool> {
match app.section {
0 => clip_next(app),
_ => Ok(false)
}
}
fn decrement (app: &mut App) -> Usually<bool> {
match app.section {
0 => clip_prev(app),
_ => Ok(false)
}
}
fn delete (app: &mut App) -> Usually<bool> {
match app.section {
0 => delete_track(app),
_ => Ok(false)
}
}
fn duplicate (_: &mut App) -> Usually<bool> { Ok(true) }
fn enter (app: &mut App) -> Usually<bool> {
if app.entered {
activate(app)
} else {
app.entered = true;
Ok(true)
}
}
fn activate (_: &mut App) -> Usually<bool> {
Ok(true)
}
fn escape (app: &mut App) -> Usually<bool> {
if app.entered {
app.entered = false;
Ok(true)
} else {
Ok(false)
}
}
fn rename (_: &mut App) -> Usually<bool> { Ok(true) }
fn add_scene (app: &mut App) -> Usually<bool> {
let name = format!("Scene {}", app.scenes.len() + 1);
app.scenes.push(Scene::new(&name, vec![]));
app.scene_cursor = app.scenes.len();
Ok(true)
}
fn add_track (app: &mut App) -> Usually<bool> {
let name = format!("Track {}", app.tracks.len() + 1);
app.tracks.push(Track::new(&name, app.jack.as_ref().unwrap().as_client(), &app.timebase, None, None)?);
app.track_cursor = app.tracks.len();
Ok(true)
}
fn delete_track (app: &mut App) -> Usually<bool> {
if app.tracks.len() > 0 {
let track = app.tracks.remove(app.track_cursor);
app.track_cursor = app.track_cursor.saturating_sub(1);
app.jack.as_ref().unwrap().as_client().unregister_port(track.midi_out)?;
return Ok(true)
}
Ok(false)
}
fn toggle_help (_: &mut App) -> Usually<bool> { Ok(true) }
fn clip_next (_: &mut App) -> Usually<bool> { Ok(true) }
fn clip_prev (_: &mut App) -> Usually<bool> { Ok(true) }
fn play_toggle (_: &mut App) -> Usually<bool> { Ok(true) }
fn record_toggle (_: &mut App) -> Usually<bool> { Ok(true) }
fn overdub_toggle (_: &mut App) -> Usually<bool> { Ok(true) }
fn monitor_toggle (_: &mut App) -> Usually<bool> { Ok(true) }
//fn main () -> Usually<()> {
//let _cli = cli::Cli::parse();
//let xdg = microxdg::XdgApp::new("tek")?;
//crate::config::create_dirs(&xdg)?;
////run(Sampler::new("Sampler#000")?)
//let (client, _) = Client::new("init", ClientOptions::NO_START_SERVER)?;
//let timebase = Arc::new(Timebase::new(client.sample_rate() as f64, 125.0, 96.0));
//let ppq = timebase.ppq() as usize;
//macro_rules! play {
//($t1:expr => [ $($msg:expr),* $(,)? ]) => {
//( $t1 * ppq / 4, vec![ $($msg),* ] )
impl App {
pub fn connect_tracks (&self) -> Usually<()> {
//let (client, _status) = Client::new(
//&format!("{}-init", &self.name), ClientOptions::NO_START_SERVER
//)?;
//let midi_ins = client.ports(Some(midi_in), None, PortFlags::IS_OUTPUT);
//let audio_outs: Vec<Vec<String>> = audio_outs.iter()
//.map(|pattern|client.ports(Some(pattern), None, PortFlags::IS_INPUT))
//.collect();
//for (i, sequencer) in self.tracks.iter().enumerate() {
//for sequencer_midi_in in sequencer.midi_ins()?.iter() {
//for midi_in in midi_ins.iter() {
//client.connect_ports_by_name(&midi_in, &sequencer_midi_in)?;
//}
//}
//let chain: &Chain = &self.tracks[i].chain;
//for port in sequencer.midi_outs()?.iter() {
//for midi_in in chain.midi_ins()?.iter() {
//client.connect_ports_by_name(&port, &midi_in)?;
//}
//}
//for (j, port) in chain.audio_outs()?.iter().enumerate() {
//for audio_out in audio_outs[j % audio_outs.len()].iter() {
//client.connect_ports_by_name(&port, &audio_out)?;
//}
//}
//}
//}
//Launcher::new("Launcher#0", &timebase,
//Some(vec![
//Track::new("Drums", &timebase, Some(vec![
//Sampler::new("Sampler", Some(BTreeMap::from([
//sample!(36, "Kick", "/home/user/Lab/Music/pak/kik.wav"),
//sample!(40, "Snare", "/home/user/Lab/Music/pak/sna.wav"),
//sample!(44, "Hihat", "/home/user/Lab/Music/pak/chh.wav"),
//])))?.boxed(),
////Plugin::lv2("Panagement", "file:///home/user/.lv2/Auburn Sounds Panagement 2.lv2")?.boxed(),
//]), Some(vec![
//Phrase::new("KSH", ppq * 4, Some(phrase! {
//00 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//00 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//01 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//02 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//04 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
//04 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//06 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//08 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//10 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//10 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//11 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//12 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
//12 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
//14 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
//14 * ppq/4 => MidiMessage::NoteOn { key: 44.into(), vel: 100.into() }
//})),
//Phrase::new("4K", ppq * 4, Some(phrase! {
//00 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//04 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//08 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//12 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//})),
//Phrase::new("KS", ppq * 4, Some(phrase! {
//00 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//04 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
//10 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
//12 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
//})),
//]))?,
//Track::new("Odin2", &timebase, Some(vec![
//Plugin::lv2("Odin2", "file:///home/user/.lv2/Odin2.lv2")?.boxed(),
//]), Some(vec![
//Phrase::new("E G A 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: 39.into(), vel: 100.into() },
//]),
//play!(10 => [
//MidiMessage::NoteOff { key: 39.into(), vel: 100.into() },
//MidiMessage::NoteOn { key: 41.into(), vel: 100.into() },
//]),
//play!(14 => [
//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() },
//]),
//])))
//]))?,
////Plugin::lv2("Helm", "file:///home/user/.lv2/Helm.lv2", &[1, 0, 0, 2])?.boxed(),
////Plugin::lv2("Kick/ChowKick", "file:///home/user/.lv2/ChowKick.lv2", &[1, 1, 0, 2])?.boxed(),
////Plugin::lv2("Bass/Helm", "file:///home/user/.lv2/Helm.lv2", &[1, 0, 0, 2])?.boxed(),
////Plugin::lv2("Pads/Odin2", "file:///home/user/.lv2/Odin2.lv2", &[1, 0, 0, 2])?.boxed(),
//]),
//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(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]),
//])
//)?
//.run(Some(init))
//}
//fn init (state: Arc<Mutex<DynamicDevice<Launcher>>>) -> Usually<()> {
//let input = ".*nanoKEY.*";
//let output = ["Komplete.*:playback_FL", "Komplete.*:playback_FR"];
//let state = state.lock().unwrap();
//state.connect(input, &output)?;
//Ok(())
//}
Ok(())
}
pub fn track (&self) -> Option<(usize, &Track)> {
match self.track_cursor { 0 => None, _ => {
let id = self.track_cursor as usize - 1;
self.tracks.get(id).map(|t|(id, t))
} }
}
pub fn track_mut (&mut self) -> Option<(usize, &mut Track)> {
match self.track_cursor { 0 => None, _ => {
let id = self.track_cursor as usize - 1;
self.tracks.get_mut(id).map(|t|(id, t))
} }
}
pub fn scene (&self) -> Option<(usize, &Scene)> {
match self.scene_cursor { 0 => None, _ => {
let id = self.scene_cursor as usize - 1;
self.scenes.get(id).map(|t|(id, t))
} }
}
pub fn scene_mut (&mut self) -> Option<(usize, &mut Scene)> {
match self.scene_cursor { 0 => None, _ => {
let id = self.scene_cursor as usize - 1;
self.scenes.get_mut(id).map(|t|(id, t))
} }
}
pub fn sequencer (&self) -> Option<&Sequencer> {
Some(&self.track()?.1.sequencer)
}
pub fn sequencer_mut (&mut self) -> Option<&mut Sequencer> {
Some(&mut self.track_mut()?.1.sequencer)
}
pub fn chain (&self) -> Option<&Chain> {
Some(&self.track()?.1.chain)
}
pub fn phrase_id (&self) -> Option<usize> {
let (track_id, _) = self.track()?;
let (_, scene) = self.scene()?;
*scene.clips.get(track_id)?
}
}