move project contents to main

This commit is contained in:
🪞👃🪞 2024-06-29 05:27:41 +03:00
parent 8a8d7b8704
commit 1b7892d11f
4 changed files with 102 additions and 104 deletions

View file

@ -10,14 +10,15 @@ mod sequencer;
mod track; mod track;
mod transport; mod transport;
pub use self::track::Track;
pub use self::launcher::{Launcher, Scene};
pub use self::sequencer::{Sequencer, Phrase};
pub use self::chain::Chain; pub use self::chain::Chain;
pub use self::launcher::Launcher; pub use self::plugin::Plugin;
pub use self::looper::Looper; pub use self::looper::Looper;
pub use self::mixer::Mixer; pub use self::mixer::Mixer;
pub use self::plugin::Plugin;
pub use self::sampler::Sampler; pub use self::sampler::Sampler;
pub use self::sequencer::{Sequencer, Phrase};
pub use self::track::Track;
pub use self::transport::Transport; pub use self::transport::Transport;
use crossterm::event; use crossterm::event;

View file

@ -42,65 +42,14 @@ impl Scene {
} }
} }
impl Launcher { impl Launcher {
pub fn new_with_controller ( pub fn new (
name: &str, name: &str,
midi_in: &str, timebase: &Arc<Timebase>,
audio_outs: &[&str], tracks: Option<Vec<Track>>,
) scenes: Option<Vec<Scene>>
-> Result<DynamicDevice<Self>, Box<dyn Error>> ) -> Result<DynamicDevice<Self>, Box<dyn Error>> {
{
let launcher = Self::new(name)?;
{
let state = &launcher.state();
let (client, _status) = Client::new(
&format!("{name}-init"),
ClientOptions::NO_START_SERVER
)?;
let midi_ins = client.ports(
Some(midi_in),
None,
::jack::PortFlags::IS_OUTPUT
);
let audio_outs: Vec<Vec<String>> = audio_outs
.iter()
.map(|pattern|client.ports(
Some(pattern),
None,
::jack::PortFlags::IS_INPUT
))
.collect();
for (i, sequencer) in state.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: &DynamicDevice<Chain> = &state.tracks[i].chain;
for midi_out in sequencer.midi_outs()?.iter() {
for midi_in in chain.midi_ins()?.iter() {
client.connect_ports_by_name(&midi_out, &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)?;
}
}
}
}
Ok(launcher)
}
pub fn new (name: &str,) -> Result<DynamicDevice<Self>, Box<dyn Error>> {
let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?; let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?;
let transport = client.transport(); let transport = client.transport();
let timebase = Arc::new(Timebase {
rate: AtomicUsize::new(client.sample_rate()),
tempo: AtomicUsize::new(113000),
ppq: AtomicUsize::new(96),
});
let ppq = timebase.ppq() as u32; let ppq = timebase.ppq() as u32;
DynamicDevice::new(render, handle, process, Self { DynamicDevice::new(render, handle, process, Self {
name: name.into(), name: name.into(),
@ -112,47 +61,18 @@ impl Launcher {
transport, transport,
cursor: (1, 1), cursor: (1, 1),
position: 0, position: 0,
scenes: vec![ scenes: scenes.unwrap_or_else(||vec![Scene::new(&"Scene 1", &[None])]),
Scene::new(&"Scene#01", &[Some(0), None, None, None]), tracks: if let Some(tracks) = tracks { tracks } else { vec![
Scene::new(&"Scene#02", &[Some(0), Some(0), None, None]), Track::new("Track 1", &timebase, None, Some(vec![
Scene::new(&"Scene#03", &[None, Some(0), None, None]), Phrase::new("MIDI Clip 1", ppq * 4, Some(BTreeMap::from([
Scene::new(&"Scene#04", &[None, None, None, None]),
Scene::new(&"Scene#05", &[None, None, None, None]),
],
tracks: vec![
Track::new("Kick", &timebase, Some(vec![
//Sampler::new("Sampler")?.boxed(),
Plugin::lv2("Kick/ChowKick", "file:///home/user/.lv2/ChowKick.lv2", &[1, 1, 0, 2])?.boxed(),
]), Some(vec![
Phrase::new("HelloKick", ppq * 4, Some(BTreeMap::from([
( ppq * 0, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ), ( ppq * 0, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq * 1, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ), ( ppq * 1, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq * 2, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ), ( ppq * 2, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq * 3, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ), ( ppq * 3, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
]))) ])))
]))?, ]))?,
] },
Track::new("Helm", &timebase, Some(vec![ timebase: timebase.clone(),
Plugin::lv2("Helm", "file:///home/user/.lv2/Helm.lv2", &[1, 0, 0, 2])?.boxed(),
]), Some(vec![
Phrase::new("HelloBass", ppq * 4, Some(BTreeMap::from([
( ppq / 2 + ppq * 0, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 1 / 2, vec![MidiMessage::NoteOff { key: 36.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 1, vec![MidiMessage::NoteOn { key: 39.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 3 / 2, vec![MidiMessage::NoteOff { key: 39.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 2, vec![MidiMessage::NoteOn { key: 41.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 5 / 2, vec![MidiMessage::NoteOff { key: 41.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 3, vec![MidiMessage::NoteOn { key: 42.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 7 / 2 - 1, vec![MidiMessage::NoteOff { key: 42.into(), vel: 100.into() }] ),
])))
]))?,
//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(),
],
timebase,
show_help: true show_help: true
}).activate(client) }).activate(client)
} }
@ -211,6 +131,39 @@ impl Launcher {
self.active_track().map(|t|t.chain.state()) self.active_track().map(|t|t.chain.state())
} }
} }
impl DynamicDevice<Launcher> {
pub fn connect (self, midi_in: &str, audio_outs: &[&str]) -> Usually<Self> {
{
let state = &self.state();
let (client, _status) = Client::new(
&format!("{}-init", &state.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 state.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: &DynamicDevice<Chain> = &state.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)?;
}
}
}
}
Ok(self)
}
}
impl PortList for Launcher {} impl PortList for Launcher {}
pub fn process (state: &mut Launcher, _: &Client, _: &ProcessScope) -> Control { pub fn process (state: &mut Launcher, _: &Client, _: &ProcessScope) -> Control {
let transport = state.transport.query().unwrap(); let transport = state.transport.query().unwrap();

View file

@ -20,12 +20,55 @@ fn main () -> Result<(), Box<dyn Error>> {
let xdg = microxdg::XdgApp::new("tek")?; let xdg = microxdg::XdgApp::new("tek")?;
crate::config::create_dirs(&xdg)?; crate::config::create_dirs(&xdg)?;
//run(Sampler::new("Sampler#000")?) //run(Sampler::new("Sampler#000")?)
run(Launcher::new_with_controller( let input = ".*nanoKEY.*";
"Launcher#0", let output = ["Komplete.*:playback_FL", "Komplete.*:playback_FR"];
".*nanoKEY.*", let (client, _) = Client::new("init", ClientOptions::NO_START_SERVER)?;
&[ let timebase = Arc::new(Timebase {
"Komplete.*:playback_FL", rate: AtomicUsize::new(client.sample_rate()),
"Komplete.*:playback_FR", tempo: AtomicUsize::new(113000),
] ppq: AtomicUsize::new(96),
)?) });
let ppq = timebase.ppq() as u32;
run(Launcher::new("Launcher#0", &timebase,
Some(vec![
Track::new("Kick", &timebase, Some(vec![
//Sampler::new("Sampler")?.boxed(),
Plugin::lv2("Kick/ChowKick", "file:///home/user/.lv2/ChowKick.lv2", &[1, 1, 0, 2])?.boxed(),
]), Some(vec![
Phrase::new("HelloKick", ppq * 4, Some(BTreeMap::from([
( ppq * 0, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq * 1, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq * 2, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq * 3, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
])))
]))?,
Track::new("Helm", &timebase, Some(vec![
Plugin::lv2("Helm", "file:///home/user/.lv2/Helm.lv2", &[1, 0, 0, 2])?.boxed(),
]), Some(vec![
Phrase::new("HelloBass", ppq * 4, Some(BTreeMap::from([
( ppq / 2 + ppq * 0, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 1 / 2, vec![MidiMessage::NoteOff { key: 36.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 1, vec![MidiMessage::NoteOn { key: 39.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 3 / 2, vec![MidiMessage::NoteOff { key: 39.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 2, vec![MidiMessage::NoteOn { key: 41.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 5 / 2, vec![MidiMessage::NoteOff { key: 41.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 3, vec![MidiMessage::NoteOn { key: 42.into(), vel: 100.into() }] ),
( ppq / 2 + ppq * 7 / 2 - 1, vec![MidiMessage::NoteOff { key: 42.into(), vel: 100.into() }] ),
])))
]))?,
//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#01", &[Some(0), None, None, None]),
Scene::new(&"Scene#02", &[Some(0), Some(0), 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]),
])
)?.connect(input, &output)?)
} }

View file

@ -57,6 +57,7 @@ pub use jack::{
MidiOut, MidiOut,
NotificationHandler, NotificationHandler,
Port, Port,
PortFlags,
PortId, PortId,
ProcessHandler, ProcessHandler,
ProcessScope, ProcessScope,