mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
merge tek_jack into tek_core
This commit is contained in:
parent
a659062dbc
commit
278b3caad3
23 changed files with 285 additions and 456 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -2512,7 +2512,6 @@ dependencies = [
|
||||||
"clojure-reader",
|
"clojure-reader",
|
||||||
"microxdg",
|
"microxdg",
|
||||||
"tek_core",
|
"tek_core",
|
||||||
"tek_jack",
|
|
||||||
"tek_mixer",
|
"tek_mixer",
|
||||||
"tek_sequencer",
|
"tek_sequencer",
|
||||||
]
|
]
|
||||||
|
|
@ -2527,20 +2526,13 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"clojure-reader",
|
"clojure-reader",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
"jack",
|
||||||
"midly",
|
"midly",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tek_jack"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"jack",
|
|
||||||
"tek_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tek_mixer"
|
name = "tek_mixer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -2549,7 +2541,6 @@ dependencies = [
|
||||||
"suil-rs",
|
"suil-rs",
|
||||||
"symphonia",
|
"symphonia",
|
||||||
"tek_core",
|
"tek_core",
|
||||||
"tek_jack",
|
|
||||||
"vst",
|
"vst",
|
||||||
"wavers",
|
"wavers",
|
||||||
"winit",
|
"winit",
|
||||||
|
|
@ -2560,7 +2551,6 @@ name = "tek_sequencer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tek_core",
|
"tek_core",
|
||||||
"tek_jack",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ clojure-reader = "0.1.0"
|
||||||
microxdg = "0.1.2"
|
microxdg = "0.1.2"
|
||||||
|
|
||||||
tek_core = { path = "../tek_core" }
|
tek_core = { path = "../tek_core" }
|
||||||
tek_jack = { path = "../tek_jack" }
|
|
||||||
tek_sequencer = { path = "../tek_sequencer" }
|
tek_sequencer = { path = "../tek_sequencer" }
|
||||||
tek_mixer = { path = "../tek_mixer" }
|
tek_mixer = { path = "../tek_mixer" }
|
||||||
#jack = "0.10"
|
#jack = "0.10"
|
||||||
|
|
|
||||||
139
crates/tek/example.edn
Normal file
139
crates/tek/example.edn
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
;(bpm 150)
|
||||||
|
|
||||||
|
;(midi-in "nanoKEY Studio.*capture.*")
|
||||||
|
;(midi-in "nanoKEY Studio.*capture.*")
|
||||||
|
;(audio-out "Built-.+:playback_FL", "Built-.+:playback_FR")
|
||||||
|
|
||||||
|
;(scene { :name "Intro" } 0 0 _ _)
|
||||||
|
;(scene { :name "Hook" } 1 1 0 _)
|
||||||
|
;(scene { :name "Verse" } 2 2 1 _)
|
||||||
|
;(scene { :name "Chorus" } 3 3 2 _)
|
||||||
|
;(scene { :name "Bridge" } _ 4 3 _)
|
||||||
|
;(scene { :name "Outro" } 4 1 4 _)
|
||||||
|
|
||||||
|
;(track { :name "Drums" :gain +0.0 }
|
||||||
|
;(phrase { :name "4 kicks" :beats 4 :steps 16 }
|
||||||
|
;(:00 (36 128))
|
||||||
|
;(:04 (36 100))
|
||||||
|
;(:08 (36 100))
|
||||||
|
;(:12 (36 100)))
|
||||||
|
;(phrase { :name "5 kicks" :beats 4 :steps 16 }
|
||||||
|
;(:00 (36 128))
|
||||||
|
;(:04 (36 100))
|
||||||
|
;(:08 (36 128))
|
||||||
|
;(:12 (36 100))
|
||||||
|
;(:14 (36 110)))
|
||||||
|
;(phrase { :name "D Beat" :beats 8 :steps 32 }
|
||||||
|
;(:00 (44 70) (36 128) (49 110))
|
||||||
|
;(:02 (44 30))
|
||||||
|
;(:04 (44 80) (40 100))
|
||||||
|
;(:06 (44 50))
|
||||||
|
;(:08 (44 30) (36 100))
|
||||||
|
;(:10 (44 50) (36 100))
|
||||||
|
;(:12 (44 80) (40 100))
|
||||||
|
;(:14 (44 50))
|
||||||
|
;(:15 (36 50))
|
||||||
|
;(:16 (44 60) (36 80))
|
||||||
|
;(:18 (44 60) (36 80))
|
||||||
|
;(:20 (44 60) (40 80))
|
||||||
|
;(:22 (44 60))
|
||||||
|
;(:24 (44 60))
|
||||||
|
;(:26 (44 30) (36 80))
|
||||||
|
;(:27 (44 60))
|
||||||
|
;(:28 (44 60) (40 80))
|
||||||
|
;(:30 (44 60)))
|
||||||
|
;(phrase { :name "Garage" :beats 4 :steps 16 }
|
||||||
|
;(:00 (44 100) (36 100) (35 100))
|
||||||
|
;(:01 (44 100))
|
||||||
|
;(:02 (44 100) (35 100))
|
||||||
|
;(:03 (44 100))
|
||||||
|
;(:04 (44 100) (40 100))
|
||||||
|
;(:06 (44 100))
|
||||||
|
;(:07 (44 100) (34 100))
|
||||||
|
;(:09 (44 100))
|
||||||
|
;(:10 (44 100))
|
||||||
|
;(:11 (35 100) (36 100))
|
||||||
|
;(:12 (44 100) (40 100))
|
||||||
|
;(:14 (44 100)))
|
||||||
|
|
||||||
|
;(phrase { :name "Trap Pinging" :beats 8 :steps 96 }
|
||||||
|
;(:00 (42 100) (36 100) (34 120) (49 100))
|
||||||
|
;(:01 (42 100))
|
||||||
|
;(:02 (42 100))
|
||||||
|
;(:06 (42 100) (35 80) (36 80) (49 100))
|
||||||
|
;(:07 (42 100))
|
||||||
|
;(:08 (42 100))
|
||||||
|
;(:12 (42 100))
|
||||||
|
;(:15 (39 100) (34 100))
|
||||||
|
;(:18 (42 100))
|
||||||
|
;(:24 (42 100) (38 50) (40 50))
|
||||||
|
;(:27 (42 100) (36 50))
|
||||||
|
;(:30 (42 100))
|
||||||
|
;(:33 (42 100) (36 50) (34 100))
|
||||||
|
;(:36 (42 90))
|
||||||
|
;(:39 (42 80))
|
||||||
|
;(:42 (42 70))
|
||||||
|
;(:45 (42 60))
|
||||||
|
|
||||||
|
;(:48 (42 100) (36 100) (34 100))
|
||||||
|
;(:50 (42 100))
|
||||||
|
;(:52 (42 110))
|
||||||
|
;(:54 (46 50) (42 120))
|
||||||
|
;(:56 (42 90))
|
||||||
|
;(:58 (42 100))
|
||||||
|
;(:60 (42 100) (35 100))
|
||||||
|
;(:64 (39 100))
|
||||||
|
;(:66 (42 100) (34 100))
|
||||||
|
|
||||||
|
;(:70 (42 100))
|
||||||
|
;(:71 (42 100))
|
||||||
|
;(:72 (42 100) (38 50) (40 50))
|
||||||
|
;(:75 (42 100) (36 50) (34 80))
|
||||||
|
;(:78 (42 100))
|
||||||
|
;(:81 (42 100) (36 50))
|
||||||
|
;(:84 (38 40) (40 50) (34 90))
|
||||||
|
;(:87 (42 90) (35 40))
|
||||||
|
;(:90 (42 70)))
|
||||||
|
|
||||||
|
;(sampler { :name "DrumKit1" :dir "/home/user/Lab/Music/pak" }
|
||||||
|
;(sample { :midi 34 :name "808 D" :file "808.wav" })
|
||||||
|
;(sample { :midi 35 :name "Kick 1" :file "kik.wav" })
|
||||||
|
;(sample { :midi 36 :name "Kick 2" :file "kik2.wav" })
|
||||||
|
;(sample { :midi 37 :name "Rim" :file "rim.wav" })
|
||||||
|
;(sample { :midi 38 :name "Snare 1" :file "sna.wav" })
|
||||||
|
;(sample { :midi 39 :name "Shaker" :file "shk.wav" })
|
||||||
|
;(sample { :midi 40 :name "Snare 2" :file "sna2.wav" })
|
||||||
|
;(sample { :midi 42 :name "Closed HH 1" :file "chh.wav" })
|
||||||
|
;(sample { :midi 44 :name "Closed HH 2" :file "chh2.wav" })
|
||||||
|
;(sample { :midi 45 :name "Open HH 0" :file "ohh.wav" })
|
||||||
|
;(sample { :midi 46 :name "Open HH 1" :file "ohh1.wav" })
|
||||||
|
;(sample { :midi 47 :name "Open HH 2" :file "ohh2.wav" })
|
||||||
|
;(sample { :midi 49 :name "Crash" :file "crs.wav" })))
|
||||||
|
|
||||||
|
;(track { :name "Bass" :gain +0.0 }
|
||||||
|
;(phrase { :name "Bass 1" :beats 4 })
|
||||||
|
;(phrase { :name "Bass 2" :beats 4 })
|
||||||
|
;(phrase { :name "Bass 3" :beats 4 })
|
||||||
|
;(phrase { :name "Bass 4" :beats 4 })
|
||||||
|
;(phrase { :name "Bass 5" :beats 4 })
|
||||||
|
;(phrase { :name "Bass 6" :beats 4 })
|
||||||
|
;(phrase { :name "Bass 7" :beats 4 })
|
||||||
|
;(phrase { :name "Bass 8" :beats 4 })
|
||||||
|
;(lv2 {
|
||||||
|
;:name "Odin2"
|
||||||
|
;:path "file:///home/user/.lv2/Odin2.lv2"
|
||||||
|
;}))
|
||||||
|
|
||||||
|
;(track { :name "Lead" :gain +0.0 }
|
||||||
|
;(phrase { :name "Lead 1" :beats 4 })
|
||||||
|
;(phrase { :name "Lead 2" :beats 4 })
|
||||||
|
;(phrase { :name "Lead 3" :beats 4 })
|
||||||
|
;(phrase { :name "Lead 4" :beats 4 })
|
||||||
|
;(phrase { :name "Lead 5" :beats 4 })
|
||||||
|
;(phrase { :name "Lead 6" :beats 4 })
|
||||||
|
;(phrase { :name "Lead 7" :beats 4 })
|
||||||
|
;(phrase { :name "Lead 8" :beats 4 })
|
||||||
|
;(lv2 {
|
||||||
|
;:name "Odin2"
|
||||||
|
;:path "file:///home/user/.lv2/Odin2.lv2"
|
||||||
|
;}))
|
||||||
|
|
@ -37,17 +37,18 @@ fn handle_modal (e: &AppEvent) -> Usually<bool> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_focused (state: &mut App, e: &AppEvent) -> Usually<bool> {
|
fn handle_focused (state: &mut App, e: &AppEvent) -> Usually<bool> {
|
||||||
match state.section {
|
unimplemented!()
|
||||||
AppFocus::Transport => state.transport.handle(e),
|
//match state.section {
|
||||||
AppFocus::Arranger => state.arranger.sequencer_mut().map(|s|s.handle(e)),
|
//AppFocus::Transport => state.transport.handle(e),
|
||||||
AppFocus::Sequencer => state.arranger.sequencer_mut().map(|s|s.handle(e)),
|
//AppFocus::Arranger => state.arranger.sequencer_mut().map(|s|s.handle(e)),
|
||||||
AppFocus::Chain => Ok(false)/*if state.entered {
|
//AppFocus::Sequencer => state.arranger.sequencer_mut().map(|s|s.handle(e)),
|
||||||
handle_device(state, e)? ||
|
//AppFocus::Chain => Ok(false)[>if state.entered {
|
||||||
handle_keymap(state, e, crate::control::KEYMAP_CHAIN)?
|
//handle_device(state, e)? ||
|
||||||
} else {
|
//handle_keymap(state, e, crate::control::KEYMAP_CHAIN)?
|
||||||
handle_keymap(state, e, crate::control::KEYMAP_CHAIN)? || handle_device(state, e)?
|
//} else {
|
||||||
})*/
|
//handle_keymap(state, e, crate::control::KEYMAP_CHAIN)? || handle_device(state, e)?
|
||||||
}
|
//})*/
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_device (state: &mut App, e: &AppEvent) -> Usually<bool> {
|
fn handle_device (state: &mut App, e: &AppEvent) -> Usually<bool> {
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]
|
#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]
|
||||||
#![allow(ambiguous_glob_reexports)]
|
#![allow(ambiguous_glob_reexports)]
|
||||||
|
|
||||||
pub(crate) use tek_core::*;
|
pub(crate) use tek_core::{*, jack::*};
|
||||||
pub(crate) use tek_jack::{*, jack::*};
|
|
||||||
pub(crate) use tek_sequencer::*;
|
pub(crate) use tek_sequencer::*;
|
||||||
|
pub(crate) use tek_mixer::*;
|
||||||
pub(crate) use microxdg::XdgApp;
|
pub(crate) use microxdg::XdgApp;
|
||||||
|
|
||||||
submod! {
|
submod! {
|
||||||
|
|
@ -29,7 +29,7 @@ pub static MODAL: Lazy<Arc<Mutex<Option<Box<dyn ExitableComponent>>>>> =
|
||||||
|
|
||||||
/// Application entrypoint.
|
/// Application entrypoint.
|
||||||
pub fn main () -> Usually<()> {
|
pub fn main () -> Usually<()> {
|
||||||
run(App::from_edn(include_str!("../../../demos/project.edn"))?
|
run(App::from_edn(include_str!("../example.edn"))?
|
||||||
.activate(Some(|app: &Arc<RwLock<App>>|Ok({
|
.activate(Some(|app: &Arc<RwLock<App>>|Ok({
|
||||||
let (midi_in, mut midi_outs) = {
|
let (midi_in, mut midi_outs) = {
|
||||||
let app = app.read().unwrap();
|
let app = app.read().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ edition = "2021"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm = "0.27"
|
atomic_float = "1.0.0"
|
||||||
ratatui = { version = "0.26.3", features = [ "unstable-widget-ref", "underline-color" ] }
|
|
||||||
backtrace = "0.3.72"
|
backtrace = "0.3.72"
|
||||||
toml = "0.8.12"
|
|
||||||
better-panic = "0.3.0"
|
better-panic = "0.3.0"
|
||||||
midly = "0.5"
|
|
||||||
clap = { version = "4.5.4", features = [ "derive" ] }
|
clap = { version = "4.5.4", features = [ "derive" ] }
|
||||||
clojure-reader = "0.1.0"
|
clojure-reader = "0.1.0"
|
||||||
|
crossterm = "0.27"
|
||||||
|
jack = "0.10"
|
||||||
|
midly = "0.5"
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
atomic_float = "1.0.0"
|
ratatui = { version = "0.26.3", features = [ "unstable-widget-ref", "underline-color" ] }
|
||||||
|
toml = "0.8.12"
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,4 @@
|
||||||
//! Audio engine.
|
use crate::{*, jack::*};
|
||||||
|
|
||||||
pub use jack;
|
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock, LockResult, RwLockReadGuard, RwLockWriteGuard};
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
submod!( device event factory ports );
|
|
||||||
|
|
||||||
pub(crate) use tek_core::*;
|
|
||||||
pub(crate) use tek_core::ratatui::prelude::{Buffer, Rect};
|
|
||||||
pub(crate) use ::jack::{
|
|
||||||
AsyncClient,
|
|
||||||
AudioIn,
|
|
||||||
AudioOut,
|
|
||||||
Client,
|
|
||||||
ClientOptions,
|
|
||||||
ClientStatus,
|
|
||||||
ClosureProcessHandler,
|
|
||||||
Control,
|
|
||||||
//CycleTimes,
|
|
||||||
Frames,
|
|
||||||
MidiIn,
|
|
||||||
//MidiIter,
|
|
||||||
MidiOut,
|
|
||||||
NotificationHandler,
|
|
||||||
Port,
|
|
||||||
//PortFlags,
|
|
||||||
PortId,
|
|
||||||
PortSpec,
|
|
||||||
ProcessScope,
|
|
||||||
//RawMidi,
|
|
||||||
Transport,
|
|
||||||
//TransportState,
|
|
||||||
Unowned
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A UI component that may be associated with a JACK client by the `Jack` factory.
|
/// A UI component that may be associated with a JACK client by the `Jack` factory.
|
||||||
pub trait Device: Render + Handle + Process + Send + Sync {
|
pub trait Device: Render + Handle + Process + Send + Sync {
|
||||||
|
|
@ -156,3 +121,109 @@ pub fn jack_run <T: Sync> (name: &str, app: &Arc<RwLock<T>>) -> Usually<DynamicA
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
|
||||||
|
/// and activation, and encapsulates a `Device` into a `JackDevice`.
|
||||||
|
pub struct Jack {
|
||||||
|
pub client: Client,
|
||||||
|
pub midi_ins: Vec<String>,
|
||||||
|
pub audio_ins: Vec<String>,
|
||||||
|
pub midi_outs: Vec<String>,
|
||||||
|
pub audio_outs: Vec<String>,
|
||||||
|
}
|
||||||
|
impl Jack {
|
||||||
|
pub fn new (name: &str) -> Usually<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
midi_ins: vec![],
|
||||||
|
audio_ins: vec![],
|
||||||
|
midi_outs: vec![],
|
||||||
|
audio_outs: vec![],
|
||||||
|
client: Client::new(
|
||||||
|
name,
|
||||||
|
ClientOptions::NO_START_SERVER
|
||||||
|
)?.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn run <T: Device + Process + Sized + 'static> (
|
||||||
|
self, state: impl FnOnce(JackPorts)->Box<T>
|
||||||
|
)
|
||||||
|
-> Usually<JackDevice>
|
||||||
|
{
|
||||||
|
let owned_ports = JackPorts {
|
||||||
|
audio_ins: register_ports(&self.client, self.audio_ins, AudioIn)?,
|
||||||
|
audio_outs: register_ports(&self.client, self.audio_outs, AudioOut)?,
|
||||||
|
midi_ins: register_ports(&self.client, self.midi_ins, MidiIn)?,
|
||||||
|
midi_outs: register_ports(&self.client, self.midi_outs, MidiOut)?,
|
||||||
|
};
|
||||||
|
let midi_outs = owned_ports.midi_outs.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
|
let midi_ins = owned_ports.midi_ins.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
|
let audio_outs = owned_ports.audio_outs.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
|
let audio_ins = owned_ports.audio_ins.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
|
let state = Arc::new(RwLock::new(state(owned_ports) as Box<dyn Device>));
|
||||||
|
let client = self.client.activate_async(
|
||||||
|
Notifications(Box::new({
|
||||||
|
let _state = state.clone();
|
||||||
|
move|_event|{
|
||||||
|
// FIXME: this deadlocks
|
||||||
|
//state.lock().unwrap().handle(&event).unwrap();
|
||||||
|
}
|
||||||
|
}) as Box<dyn Fn(JackEvent) + Send + Sync>),
|
||||||
|
ClosureProcessHandler::new(Box::new({
|
||||||
|
let state = state.clone();
|
||||||
|
move|c: &Client, s: &ProcessScope|{
|
||||||
|
state.write().unwrap().process(c, s)
|
||||||
|
}
|
||||||
|
}) as BoxedProcessHandler)
|
||||||
|
)?;
|
||||||
|
Ok(JackDevice {
|
||||||
|
ports: UnownedJackPorts {
|
||||||
|
audio_ins: query_ports(&client.as_client(), audio_ins),
|
||||||
|
audio_outs: query_ports(&client.as_client(), audio_outs),
|
||||||
|
midi_ins: query_ports(&client.as_client(), midi_ins),
|
||||||
|
midi_outs: query_ports(&client.as_client(), midi_outs),
|
||||||
|
},
|
||||||
|
client,
|
||||||
|
state,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn audio_in (mut self, name: &str) -> Self {
|
||||||
|
self.audio_ins.push(name.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn audio_out (mut self, name: &str) -> Self {
|
||||||
|
self.audio_outs.push(name.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn midi_in (mut self, name: &str) -> Self {
|
||||||
|
self.midi_ins.push(name.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn midi_out (mut self, name: &str) -> Self {
|
||||||
|
self.midi_outs.push(name.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_ports <T: PortSpec + Copy> (
|
||||||
|
client: &Client, names: Vec<String>, spec: T
|
||||||
|
) -> Usually<BTreeMap<String, Port<T>>> {
|
||||||
|
names.into_iter().try_fold(BTreeMap::new(), |mut ports, name|{
|
||||||
|
let port = client.register_port(&name, spec)?;
|
||||||
|
ports.insert(name, port);
|
||||||
|
Ok(ports)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_ports (
|
||||||
|
client: &Client, names: Vec<String>
|
||||||
|
) -> BTreeMap<String, Port<Unowned>> {
|
||||||
|
names.into_iter().fold(BTreeMap::new(), |mut ports, name|{
|
||||||
|
let port = client.port_by_name(&name).unwrap();
|
||||||
|
ports.insert(name, port);
|
||||||
|
ports
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
//! Wrap JACK-enabled [Device]s.
|
use crate::{*, jack::*};
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use tek_core::ratatui::prelude::{Buffer, Rect};
|
|
||||||
|
|
||||||
/// A [Device] bound to a JACK client and a set of ports.
|
/// A [Device] bound to a JACK client and a set of ports.
|
||||||
pub struct JackDevice {
|
pub struct JackDevice {
|
||||||
|
|
@ -52,3 +49,4 @@ impl JackDevice {
|
||||||
Ok(self.client.as_client().connect_ports(self.audio_outs()?[index], port)?)
|
Ok(self.client.as_client().connect_ports(self.audio_outs()?[index], port)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
//! JACK event handling.
|
use crate::{*, jack::*};
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Notification handler used by the [Jack] factory
|
/// Notification handler used by the [Jack] factory
|
||||||
/// when constructing [JackDevice]s.
|
/// when constructing [JackDevice]s.
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
//! Handling JACK ports.
|
use crate::{*, jack::*};
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut].
|
/// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut].
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
|
@ -92,3 +91,4 @@ pub trait Ports {
|
||||||
)?}
|
)?}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
pub use ratatui;
|
pub use ratatui;
|
||||||
pub use crossterm;
|
pub use crossterm;
|
||||||
|
pub use jack;
|
||||||
pub use midly;
|
pub use midly;
|
||||||
pub use clap;
|
pub use clap;
|
||||||
pub use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
pub use std::sync::{Arc, Mutex, LockResult, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
pub use std::collections::BTreeMap;
|
pub use std::collections::BTreeMap;
|
||||||
pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
|
pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
|
||||||
pub use ratatui::prelude::{Rect, Style, Color, Buffer};
|
pub use ratatui::prelude::{Rect, Style, Color, Buffer};
|
||||||
|
|
@ -16,7 +17,6 @@ pub(crate) use std::io::{stdout};
|
||||||
pub(crate) use std::thread::{spawn, JoinHandle};
|
pub(crate) use std::thread::{spawn, JoinHandle};
|
||||||
pub(crate) use std::time::Duration;
|
pub(crate) use std::time::Duration;
|
||||||
pub(crate) use atomic_float::*;
|
pub(crate) use atomic_float::*;
|
||||||
//, LockResult, RwLockReadGuard, RwLockWriteGuard};
|
|
||||||
//pub(crate) use std::path::PathBuf;
|
//pub(crate) use std::path::PathBuf;
|
||||||
//pub(crate) use std::fs::read_dir;
|
//pub(crate) use std::fs::read_dir;
|
||||||
//pub(crate) use std::ffi::OsString;
|
//pub(crate) use std::ffi::OsString;
|
||||||
|
|
@ -48,6 +48,10 @@ submod! {
|
||||||
time_base
|
time_base
|
||||||
time_note
|
time_note
|
||||||
time_tick
|
time_tick
|
||||||
|
jack_core
|
||||||
|
jack_device
|
||||||
|
jack_event
|
||||||
|
jack_ports
|
||||||
}
|
}
|
||||||
|
|
||||||
/// EDN parsing helper.
|
/// EDN parsing helper.
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ impl Render for () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Render> Render for Option<T> {
|
impl<T: Render + Send + Sync> Render for Option<&T> {
|
||||||
fn render (&self, b: &mut Buffer, a: Rect) -> Usually<Rect> {
|
fn render (&self, b: &mut Buffer, a: Rect) -> Usually<Rect> {
|
||||||
match self {
|
match self {
|
||||||
Some(widget) => widget.render(b, a),
|
Some(widget) => widget.render(b, a),
|
||||||
|
|
|
||||||
|
|
@ -46,63 +46,3 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (pulses, name)
|
|
||||||
pub const NOTE_DURATIONS: [(usize, &str);26] = [
|
|
||||||
(1, "1/384"),
|
|
||||||
(2, "1/192"),
|
|
||||||
(3, "1/128"),
|
|
||||||
(4, "1/96"),
|
|
||||||
(6, "1/64"),
|
|
||||||
(8, "1/48"),
|
|
||||||
(12, "1/32"),
|
|
||||||
(16, "1/24"),
|
|
||||||
(24, "1/16"),
|
|
||||||
(32, "1/12"),
|
|
||||||
(48, "1/8"),
|
|
||||||
(64, "1/6"),
|
|
||||||
(96, "1/4"),
|
|
||||||
(128, "1/3"),
|
|
||||||
(192, "1/2"),
|
|
||||||
(256, "2/3"),
|
|
||||||
(384, "1/1"),
|
|
||||||
(512, "4/3"),
|
|
||||||
(576, "3/2"),
|
|
||||||
(768, "2/1"),
|
|
||||||
(1152, "3/1"),
|
|
||||||
(1536, "4/1"),
|
|
||||||
(2304, "6/1"),
|
|
||||||
(3072, "8/1"),
|
|
||||||
(3456, "9/1"),
|
|
||||||
(6144, "16/1"),
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Returns the next shorter length
|
|
||||||
pub fn prev_note_length (ppq: usize) -> usize {
|
|
||||||
for i in 1..=16 {
|
|
||||||
let length = NOTE_DURATIONS[16-i].0;
|
|
||||||
if length < ppq {
|
|
||||||
return length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ppq
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the next longer length
|
|
||||||
pub fn next_note_length (ppq: usize) -> usize {
|
|
||||||
for (length, _) in &NOTE_DURATIONS {
|
|
||||||
if *length > ppq {
|
|
||||||
return *length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ppq
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ppq_to_name (ppq: usize) -> &'static str {
|
|
||||||
for (length, name) in &NOTE_DURATIONS {
|
|
||||||
if *length == ppq {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "tek_jack"
|
|
||||||
edition = "2021"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
tek_core = { path = "../tek_core" }
|
|
||||||
jack = "0.10"
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
# `tek_jack`
|
|
||||||
|
|
||||||
This crate interfaces with the JACK Audio Connection Kit API.
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
//! Encapsulate and run [Device]s as [JackDevice]s.
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
|
|
||||||
/// and activation, and encapsulates a `Device` into a `JackDevice`.
|
|
||||||
pub struct Jack {
|
|
||||||
pub client: Client,
|
|
||||||
pub midi_ins: Vec<String>,
|
|
||||||
pub audio_ins: Vec<String>,
|
|
||||||
pub midi_outs: Vec<String>,
|
|
||||||
pub audio_outs: Vec<String>,
|
|
||||||
}
|
|
||||||
impl Jack {
|
|
||||||
pub fn new (name: &str) -> Usually<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
midi_ins: vec![],
|
|
||||||
audio_ins: vec![],
|
|
||||||
midi_outs: vec![],
|
|
||||||
audio_outs: vec![],
|
|
||||||
client: Client::new(
|
|
||||||
name,
|
|
||||||
ClientOptions::NO_START_SERVER
|
|
||||||
)?.0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn run <T: Device + Process + Sized + 'static> (
|
|
||||||
self, state: impl FnOnce(JackPorts)->Box<T>
|
|
||||||
)
|
|
||||||
-> Usually<JackDevice>
|
|
||||||
{
|
|
||||||
let owned_ports = JackPorts {
|
|
||||||
audio_ins: register_ports(&self.client, self.audio_ins, AudioIn)?,
|
|
||||||
audio_outs: register_ports(&self.client, self.audio_outs, AudioOut)?,
|
|
||||||
midi_ins: register_ports(&self.client, self.midi_ins, MidiIn)?,
|
|
||||||
midi_outs: register_ports(&self.client, self.midi_outs, MidiOut)?,
|
|
||||||
};
|
|
||||||
let midi_outs = owned_ports.midi_outs.values()
|
|
||||||
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
|
||||||
let midi_ins = owned_ports.midi_ins.values()
|
|
||||||
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
|
||||||
let audio_outs = owned_ports.audio_outs.values()
|
|
||||||
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
|
||||||
let audio_ins = owned_ports.audio_ins.values()
|
|
||||||
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
|
||||||
let state = Arc::new(RwLock::new(state(owned_ports) as Box<dyn Device>));
|
|
||||||
let client = self.client.activate_async(
|
|
||||||
Notifications(Box::new({
|
|
||||||
let _state = state.clone();
|
|
||||||
move|_event|{
|
|
||||||
// FIXME: this deadlocks
|
|
||||||
//state.lock().unwrap().handle(&event).unwrap();
|
|
||||||
}
|
|
||||||
}) as Box<dyn Fn(JackEvent) + Send + Sync>),
|
|
||||||
ClosureProcessHandler::new(Box::new({
|
|
||||||
let state = state.clone();
|
|
||||||
move|c: &Client, s: &ProcessScope|{
|
|
||||||
state.write().unwrap().process(c, s)
|
|
||||||
}
|
|
||||||
}) as BoxedProcessHandler)
|
|
||||||
)?;
|
|
||||||
Ok(JackDevice {
|
|
||||||
ports: UnownedJackPorts {
|
|
||||||
audio_ins: query_ports(&client.as_client(), audio_ins),
|
|
||||||
audio_outs: query_ports(&client.as_client(), audio_outs),
|
|
||||||
midi_ins: query_ports(&client.as_client(), midi_ins),
|
|
||||||
midi_outs: query_ports(&client.as_client(), midi_outs),
|
|
||||||
},
|
|
||||||
client,
|
|
||||||
state,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn audio_in (mut self, name: &str) -> Self {
|
|
||||||
self.audio_ins.push(name.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn audio_out (mut self, name: &str) -> Self {
|
|
||||||
self.audio_outs.push(name.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn midi_in (mut self, name: &str) -> Self {
|
|
||||||
self.midi_ins.push(name.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn midi_out (mut self, name: &str) -> Self {
|
|
||||||
self.midi_outs.push(name.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_ports <T: PortSpec + Copy> (
|
|
||||||
client: &Client, names: Vec<String>, spec: T
|
|
||||||
) -> Usually<BTreeMap<String, Port<T>>> {
|
|
||||||
names.into_iter().try_fold(BTreeMap::new(), |mut ports, name|{
|
|
||||||
let port = client.register_port(&name, spec)?;
|
|
||||||
ports.insert(name, port);
|
|
||||||
Ok(ports)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_ports (
|
|
||||||
client: &Client, names: Vec<String>
|
|
||||||
) -> BTreeMap<String, Port<Unowned>> {
|
|
||||||
names.into_iter().fold(BTreeMap::new(), |mut ports, name|{
|
|
||||||
let port = client.port_by_name(&name).unwrap();
|
|
||||||
ports.insert(name, port);
|
|
||||||
ports
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,6 @@ version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tek_core = { path = "../tek_core" }
|
tek_core = { path = "../tek_core" }
|
||||||
tek_jack = { path = "../tek_jack" }
|
|
||||||
|
|
||||||
livi = "0.7.4"
|
livi = "0.7.4"
|
||||||
suil-rs = { path = "../suil" }
|
suil-rs = { path = "../suil" }
|
||||||
|
|
@ -32,4 +31,4 @@ path = "src/sampler_main.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "tek_plugin"
|
name = "tek_plugin"
|
||||||
path = "src/sampler_main.rs"
|
path = "src/plugin_main.rs"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ pub(crate) use tek_core::*;
|
||||||
pub(crate) use tek_core::ratatui::prelude::*;
|
pub(crate) use tek_core::ratatui::prelude::*;
|
||||||
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
|
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
|
||||||
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
|
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
|
||||||
pub(crate) use tek_jack::{*, jack::*};
|
pub(crate) use tek_core::jack::*;
|
||||||
|
|
||||||
pub(crate) use std::collections::BTreeMap;
|
pub(crate) use std::collections::BTreeMap;
|
||||||
pub(crate) use std::sync::{Arc, Mutex, RwLock};
|
pub(crate) use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tek_core = { path = "../tek_core" }
|
tek_core = { path = "../tek_core" }
|
||||||
tek_jack = { path = "../tek_jack" }
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@ impl Arranger {
|
||||||
arr.transport = Some(Arc::new(RwLock::new(TransportToolbar::new(None))));
|
arr.transport = Some(Arc::new(RwLock::new(TransportToolbar::new(None))));
|
||||||
}
|
}
|
||||||
if let Some(tracks) = args.tracks {
|
if let Some(tracks) = args.tracks {
|
||||||
for track in 0..tracks {
|
for _ in 0..tracks {
|
||||||
arr.track_add(None)?;
|
arr.track_add(None)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(scenes) = args.scenes {
|
if let Some(scenes) = args.scenes {
|
||||||
for scene in 0..scenes {
|
for _ in 0..scenes {
|
||||||
arr.scene_add(None)?;
|
arr.scene_add(None)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ pub(crate) use tek_core::*;
|
||||||
pub(crate) use tek_core::ratatui::prelude::*;
|
pub(crate) use tek_core::ratatui::prelude::*;
|
||||||
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
|
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
|
||||||
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
|
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
|
||||||
pub(crate) use tek_jack::{*, jack::*};
|
pub(crate) use tek_core::jack::*;
|
||||||
pub(crate) use std::sync::{Arc, RwLock};
|
pub(crate) use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
submod! {
|
submod! {
|
||||||
|
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
(bpm 150)
|
|
||||||
|
|
||||||
(midi-in "nanoKEY Studio.*capture.*")
|
|
||||||
(midi-in "nanoKEY Studio.*capture.*")
|
|
||||||
(audio-out "Built-.+:playback_FL", "Built-.+:playback_FR")
|
|
||||||
|
|
||||||
(scene { :name "Intro" } 0 0 _ _)
|
|
||||||
(scene { :name "Hook" } 1 1 0 _)
|
|
||||||
(scene { :name "Verse" } 2 2 1 _)
|
|
||||||
(scene { :name "Chorus" } 3 3 2 _)
|
|
||||||
(scene { :name "Bridge" } _ 4 3 _)
|
|
||||||
(scene { :name "Outro" } 4 1 4 _)
|
|
||||||
|
|
||||||
(track { :name "Drums" :gain +0.0 }
|
|
||||||
(phrase { :name "4 kicks" :beats 4 :steps 16 }
|
|
||||||
(:00 (36 128))
|
|
||||||
(:04 (36 100))
|
|
||||||
(:08 (36 100))
|
|
||||||
(:12 (36 100)))
|
|
||||||
(phrase { :name "5 kicks" :beats 4 :steps 16 }
|
|
||||||
(:00 (36 128))
|
|
||||||
(:04 (36 100))
|
|
||||||
(:08 (36 128))
|
|
||||||
(:12 (36 100))
|
|
||||||
(:14 (36 110)))
|
|
||||||
(phrase { :name "D Beat" :beats 8 :steps 32 }
|
|
||||||
(:00 (44 70) (36 128) (49 110))
|
|
||||||
(:02 (44 30))
|
|
||||||
(:04 (44 80) (40 100))
|
|
||||||
(:06 (44 50))
|
|
||||||
(:08 (44 30) (36 100))
|
|
||||||
(:10 (44 50) (36 100))
|
|
||||||
(:12 (44 80) (40 100))
|
|
||||||
(:14 (44 50))
|
|
||||||
(:15 (36 50))
|
|
||||||
(:16 (44 60) (36 80))
|
|
||||||
(:18 (44 60) (36 80))
|
|
||||||
(:20 (44 60) (40 80))
|
|
||||||
(:22 (44 60))
|
|
||||||
(:24 (44 60))
|
|
||||||
(:26 (44 30) (36 80))
|
|
||||||
(:27 (44 60))
|
|
||||||
(:28 (44 60) (40 80))
|
|
||||||
(:30 (44 60)))
|
|
||||||
(phrase { :name "Garage" :beats 4 :steps 16 }
|
|
||||||
(:00 (44 100) (36 100) (35 100))
|
|
||||||
(:01 (44 100))
|
|
||||||
(:02 (44 100) (35 100))
|
|
||||||
(:03 (44 100))
|
|
||||||
(:04 (44 100) (40 100))
|
|
||||||
(:06 (44 100))
|
|
||||||
(:07 (44 100) (34 100))
|
|
||||||
(:09 (44 100))
|
|
||||||
(:10 (44 100))
|
|
||||||
(:11 (35 100) (36 100))
|
|
||||||
(:12 (44 100) (40 100))
|
|
||||||
(:14 (44 100)))
|
|
||||||
|
|
||||||
(phrase { :name "Trap Pinging" :beats 8 :steps 96 }
|
|
||||||
(:00 (42 100) (36 100) (34 120) (49 100))
|
|
||||||
(:01 (42 100))
|
|
||||||
(:02 (42 100))
|
|
||||||
(:06 (42 100) (35 80) (36 80) (49 100))
|
|
||||||
(:07 (42 100))
|
|
||||||
(:08 (42 100))
|
|
||||||
(:12 (42 100))
|
|
||||||
(:15 (39 100) (34 100))
|
|
||||||
(:18 (42 100))
|
|
||||||
(:24 (42 100) (38 50) (40 50))
|
|
||||||
(:27 (42 100) (36 50))
|
|
||||||
(:30 (42 100))
|
|
||||||
(:33 (42 100) (36 50) (34 100))
|
|
||||||
(:36 (42 90))
|
|
||||||
(:39 (42 80))
|
|
||||||
(:42 (42 70))
|
|
||||||
(:45 (42 60))
|
|
||||||
|
|
||||||
(:48 (42 100) (36 100) (34 100))
|
|
||||||
(:50 (42 100))
|
|
||||||
(:52 (42 110))
|
|
||||||
(:54 (46 50) (42 120))
|
|
||||||
(:56 (42 90))
|
|
||||||
(:58 (42 100))
|
|
||||||
(:60 (42 100) (35 100))
|
|
||||||
(:64 (39 100))
|
|
||||||
(:66 (42 100) (34 100))
|
|
||||||
|
|
||||||
(:70 (42 100))
|
|
||||||
(:71 (42 100))
|
|
||||||
(:72 (42 100) (38 50) (40 50))
|
|
||||||
(:75 (42 100) (36 50) (34 80))
|
|
||||||
(:78 (42 100))
|
|
||||||
(:81 (42 100) (36 50))
|
|
||||||
(:84 (38 40) (40 50) (34 90))
|
|
||||||
(:87 (42 90) (35 40))
|
|
||||||
(:90 (42 70)))
|
|
||||||
|
|
||||||
(sampler { :name "DrumKit1" :dir "/home/user/Lab/Music/pak" }
|
|
||||||
(sample { :midi 34 :name "808 D" :file "808.wav" })
|
|
||||||
(sample { :midi 35 :name "Kick 1" :file "kik.wav" })
|
|
||||||
(sample { :midi 36 :name "Kick 2" :file "kik2.wav" })
|
|
||||||
(sample { :midi 37 :name "Rim" :file "rim.wav" })
|
|
||||||
(sample { :midi 38 :name "Snare 1" :file "sna.wav" })
|
|
||||||
(sample { :midi 39 :name "Shaker" :file "shk.wav" })
|
|
||||||
(sample { :midi 40 :name "Snare 2" :file "sna2.wav" })
|
|
||||||
(sample { :midi 42 :name "Closed HH 1" :file "chh.wav" })
|
|
||||||
(sample { :midi 44 :name "Closed HH 2" :file "chh2.wav" })
|
|
||||||
(sample { :midi 45 :name "Open HH 0" :file "ohh.wav" })
|
|
||||||
(sample { :midi 46 :name "Open HH 1" :file "ohh1.wav" })
|
|
||||||
(sample { :midi 47 :name "Open HH 2" :file "ohh2.wav" })
|
|
||||||
(sample { :midi 49 :name "Crash" :file "crs.wav" })))
|
|
||||||
|
|
||||||
(track { :name "Bass" :gain +0.0 }
|
|
||||||
(phrase { :name "Bass 1" :beats 4 })
|
|
||||||
(phrase { :name "Bass 2" :beats 4 })
|
|
||||||
(phrase { :name "Bass 3" :beats 4 })
|
|
||||||
(phrase { :name "Bass 4" :beats 4 })
|
|
||||||
(phrase { :name "Bass 5" :beats 4 })
|
|
||||||
(phrase { :name "Bass 6" :beats 4 })
|
|
||||||
(phrase { :name "Bass 7" :beats 4 })
|
|
||||||
(phrase { :name "Bass 8" :beats 4 })
|
|
||||||
(lv2 {
|
|
||||||
:name "Odin2"
|
|
||||||
:path "file:///home/user/.lv2/Odin2.lv2"
|
|
||||||
}))
|
|
||||||
|
|
||||||
(track { :name "Lead" :gain +0.0 }
|
|
||||||
(phrase { :name "Lead 1" :beats 4 })
|
|
||||||
(phrase { :name "Lead 2" :beats 4 })
|
|
||||||
(phrase { :name "Lead 3" :beats 4 })
|
|
||||||
(phrase { :name "Lead 4" :beats 4 })
|
|
||||||
(phrase { :name "Lead 5" :beats 4 })
|
|
||||||
(phrase { :name "Lead 6" :beats 4 })
|
|
||||||
(phrase { :name "Lead 7" :beats 4 })
|
|
||||||
(phrase { :name "Lead 8" :beats 4 })
|
|
||||||
(lv2 {
|
|
||||||
:name "Odin2"
|
|
||||||
:path "file:///home/user/.lv2/Odin2.lv2"
|
|
||||||
}))
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;(:bpm 150)
|
|
||||||
|
|
||||||
;(:track#01 "Drums")
|
|
||||||
;(:track#02 "Bass")
|
|
||||||
;(:track#03 "Lead")
|
|
||||||
|
|
||||||
;(:scene#01 "Intro" (:01 --) (:02 :01) (:03 :01) )
|
|
||||||
;(:scene#02 "Hook" )
|
|
||||||
;(:scene#03 "Verse" )
|
|
||||||
;(:scene#04 "Chorus")
|
|
||||||
;(:scene#05 "Bridge")
|
|
||||||
|
|
||||||
;(midi-in "nanoKEY Studio.*capture.*")
|
|
||||||
;(audio-out ["Komplete.+:playback_FL", "Komplete.+:playback_FR"])
|
|
||||||
|
|
||||||
|
|
||||||
;(sampler { :name "DrumKit1" :dir "/home/user/Lab/Music/pak" }
|
|
||||||
;(sample { :midi 34 :name "808" :file "808.wav" })
|
|
||||||
;(sample { :midi 35 :name "KC1" :file "kik.wav" })
|
|
||||||
;(sample { :midi 36 :name "KC2" :file "kik2.wav" })
|
|
||||||
;(sample { :midi 38 :name "SN1" :file "sna.wav" })
|
|
||||||
;(sample { :midi 40 :name "SN2" :file "sna2.wav" })
|
|
||||||
;(sample { :midi 42 :name "HH1" :file "chh.wav" })
|
|
||||||
;(sample { :midi 44 :name "HH2" :file "chh2.wav" }))
|
|
||||||
|
|
||||||
;(phrase { :name "4 kicks" :beats 4 :steps 16 }
|
|
||||||
;(:00 (36 128))
|
|
||||||
;(:04 (36 128))
|
|
||||||
;(:08 (36 128))
|
|
||||||
;(:12 (36 128))))
|
|
||||||
|
|
||||||
;(phrase {
|
|
||||||
;:name "5 kicks"
|
|
||||||
;:beats 4
|
|
||||||
;} (:00 (36 128))
|
|
||||||
;(:04 (36 128))
|
|
||||||
;(:08 (36 128))
|
|
||||||
;(:12 (36 128))
|
|
||||||
;(:14 (36 128)))
|
|
||||||
|
|
||||||
;(track "Bass"
|
|
||||||
;(lv2-plugin "Odin2")
|
|
||||||
;(phrase { :name "Empty" :beats 4 })
|
|
||||||
;(phrase { :name "Empty" :beats 4 }))
|
|
||||||
|
|
||||||
;(track "Lead"
|
|
||||||
;(lv2-plugin "Odin2")
|
|
||||||
;(phrase { :name "Empty" :beats 4 })
|
|
||||||
;(phrase { :name "Empty" :beats 4 }))
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue