mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
wip: assigning steps to frames
This commit is contained in:
parent
7c1dc9ce9b
commit
faac61180b
6 changed files with 389 additions and 13 deletions
217
Cargo.lock
generated
217
Cargo.lock
generated
|
|
@ -2,6 +2,24 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.8.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "allocator-api2"
|
||||||
|
version = "0.2.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.14"
|
version = "0.6.14"
|
||||||
|
|
@ -76,6 +94,22 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"jack",
|
"jack",
|
||||||
|
"ratatui",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cassowary"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "castaway"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
|
||||||
|
dependencies = [
|
||||||
|
"rustversion",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -130,6 +164,19 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "compact_str"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
|
||||||
|
dependencies = [
|
||||||
|
"castaway",
|
||||||
|
"cfg-if",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossterm"
|
name = "crossterm"
|
||||||
version = "0.27.0"
|
version = "0.27.0"
|
||||||
|
|
@ -155,6 +202,22 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"allocator-api2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|
@ -167,6 +230,21 @@ version = "1.70.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jack"
|
name = "jack"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
|
@ -231,6 +309,15 @@ version = "0.4.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.11"
|
version = "0.8.11"
|
||||||
|
|
@ -243,6 +330,12 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.2"
|
version = "0.12.2"
|
||||||
|
|
@ -266,6 +359,12 @@ dependencies = [
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
|
@ -290,6 +389,26 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ratatui"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"cassowary",
|
||||||
|
"compact_str",
|
||||||
|
"crossterm",
|
||||||
|
"itertools",
|
||||||
|
"lru",
|
||||||
|
"paste",
|
||||||
|
"stability",
|
||||||
|
"strum",
|
||||||
|
"unicode-segmentation",
|
||||||
|
"unicode-truncate",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -299,6 +418,18 @@ dependencies = [
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -341,12 +472,50 @@ version = "1.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stability"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.26.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
||||||
|
dependencies = [
|
||||||
|
"strum_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7993a8e3a9e88a00351486baae9522c91b123a088f76469e5bd5cc17198ea87"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.60"
|
version = "2.0.60"
|
||||||
|
|
@ -364,12 +533,40 @@ version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-truncate"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a5fbabedabe362c618c714dbefda9927b5afc8e2a8102f47f081089a9019226"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
@ -536,3 +733,23 @@ name = "windows_x86_64_msvc"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
||||||
jack = "0.10"
|
jack = "0.10"
|
||||||
clap = { version = "4.5.4", features = [ "derive" ] }
|
clap = { version = "4.5.4", features = [ "derive" ] }
|
||||||
crossterm = "0.27"
|
crossterm = "0.27"
|
||||||
|
ratatui = "0.26.3"
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ fn run_one (command: &cli::Command) -> Result<(), Box<dyn Error>> {
|
||||||
),
|
),
|
||||||
|
|
||||||
cli::Command::Sequencer => engine.run(
|
cli::Command::Sequencer => engine.run(
|
||||||
&mut sequencer::Sequencer::new(engine.jack_client.as_client())?,
|
&mut sequencer::Sequencer::new()?,
|
||||||
|state, stdout, mut offset| {
|
|state, stdout, mut offset| {
|
||||||
let (w, h) = render::render_toolbar_vertical(stdout, offset, &sequencer::ACTIONS)?;
|
let (w, h) = render::render_toolbar_vertical(stdout, offset, &sequencer::ACTIONS)?;
|
||||||
offset.0 = offset.0 + w + 2;
|
offset.0 = offset.0 + w + 2;
|
||||||
|
|
@ -122,7 +122,7 @@ fn run_all () -> Result<(), Box<dyn Error>> {
|
||||||
exited: false,
|
exited: false,
|
||||||
mode: Mode::Sequencer,
|
mode: Mode::Sequencer,
|
||||||
transport: transport::Transport::new(engine.jack_client.as_client())?,
|
transport: transport::Transport::new(engine.jack_client.as_client())?,
|
||||||
sequencer: sequencer::Sequencer::new(engine.jack_client.as_client())?,
|
sequencer: sequencer::Sequencer::new()?,
|
||||||
mixer: mixer::Mixer::new()?,
|
mixer: mixer::Mixer::new()?,
|
||||||
looper: looper::Looper::new()?,
|
looper: looper::Looper::new()?,
|
||||||
sampler: sampler::Sampler::new()?,
|
sampler: sampler::Sampler::new()?,
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,10 @@ pub fn handle (state: &mut Sequencer, event: &Event) -> Result<(), Box<dyn Error
|
||||||
let row = state.cursor.0 as usize;
|
let row = state.cursor.0 as usize;
|
||||||
let step = state.cursor.1 as usize;
|
let step = state.cursor.1 as usize;
|
||||||
let duration = state.cursor.2 as usize;
|
let duration = state.cursor.2 as usize;
|
||||||
state.sequence[row][step] = Some(super::Event::NoteOn(35, 128));
|
let mut sequence = state.sequence.lock().unwrap();
|
||||||
|
sequence[row][step] = Some(super::Event::NoteOn(35, 128));
|
||||||
if state.cursor.2 > 0 {
|
if state.cursor.2 > 0 {
|
||||||
state.sequence[row][step + duration] = Some(super::Event::NoteOff(35));
|
sequence[row][step + duration] = Some(super::Event::NoteOff(35));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,13 @@ pub const ACTIONS: [(&'static str, &'static str);4] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
pub struct Sequencer {
|
pub struct Sequencer {
|
||||||
exited: bool,
|
exited: Arc<AtomicBool>,
|
||||||
cursor: (u16, u16, u16),
|
cursor: (u16, u16, u16),
|
||||||
sequence: Vec<Vec<Option<Event>>>,
|
sequence: Arc<Mutex<Vec<Vec<Option<Event>>>>>,
|
||||||
transport: ::jack::Transport,
|
transport: ::jack::Transport,
|
||||||
bpm: f64,
|
bpm: f64,
|
||||||
timesig: (f32, f32),
|
timesig: (f32, f32),
|
||||||
|
pub jack_client: Jack<self::jack::Notifications>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -29,24 +30,179 @@ pub enum Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sequencer {
|
impl Sequencer {
|
||||||
pub fn new (client: &Client) -> Result<Self, Box<dyn Error>> {
|
|
||||||
|
pub fn new () -> Result<Self, Box<dyn Error>> {
|
||||||
|
let exited = Arc::new(AtomicBool::new(false));
|
||||||
|
let sequence: Arc<Mutex<Vec<Vec<Option<Event>>>>> = Arc::new(Mutex::new(vec![vec![None;64];4]));
|
||||||
|
let (client, _status) = Client::new(
|
||||||
|
"blinkenlive-sequencer",
|
||||||
|
ClientOptions::NO_START_SERVER
|
||||||
|
)?;
|
||||||
let transport = client.transport();
|
let transport = client.transport();
|
||||||
|
let mut port = client.register_port("sequence", ::jack::MidiOut::default())?;
|
||||||
|
let beats = 4;
|
||||||
|
let steps = 16;
|
||||||
|
let bpm = 120;
|
||||||
|
let rate = 44100; // Hz
|
||||||
|
let frame = 1f64 / rate as f64; // msec
|
||||||
|
let buf = 512; // frames
|
||||||
|
let t_beat = 60.0 / bpm as f64; // msec
|
||||||
|
let t_loop = t_beat * beats as f64; // msec
|
||||||
|
let t_step = t_beat / steps as f64; // msec
|
||||||
|
let mut step_frames = vec![];
|
||||||
|
for step in 0..beats*steps {
|
||||||
|
let step_index = (step as f64 * t_step / frame) as usize;
|
||||||
|
step_frames.push(step_index);
|
||||||
|
}
|
||||||
|
let loop_frames = (t_loop*rate as f64) as usize;
|
||||||
|
let mut frame_steps: Vec<Option<usize>> = vec![None;loop_frames];
|
||||||
|
for (index, frame) in step_frames.iter().enumerate() {
|
||||||
|
frame_steps[*frame] = Some(index);
|
||||||
|
}
|
||||||
|
let handler: BoxedProcessHandler = Box::new({
|
||||||
|
let transport = client.transport();
|
||||||
|
let exited = exited.clone();
|
||||||
|
let sequence = sequence.clone();
|
||||||
|
move |client: &Client, scope: &ProcessScope| -> Control {
|
||||||
|
if exited.fetch_and(true, Ordering::Relaxed) {
|
||||||
|
return Control::Quit
|
||||||
|
}
|
||||||
|
if transport.query_state().unwrap() == TransportState::Rolling {
|
||||||
|
let chunk_start = scope.last_frame_time();
|
||||||
|
let chunk_size = scope.n_frames();
|
||||||
|
let chunk_end = chunk_start + chunk_size;
|
||||||
|
let start_looped = chunk_start as usize % loop_frames;
|
||||||
|
let end_looped = chunk_end as usize % loop_frames;
|
||||||
|
let mut writer = port.writer(scope);
|
||||||
|
let sequence = sequence.lock().unwrap();
|
||||||
|
for frame in 0..chunk_size {
|
||||||
|
let value = frame_steps[(start_looped + frame as usize) % loop_frames];
|
||||||
|
if let Some(step) = value {
|
||||||
|
for track in sequence.iter() {
|
||||||
|
for event in track[step].iter() {
|
||||||
|
writer.write(&::jack::RawMidi {
|
||||||
|
time: frame as u32,
|
||||||
|
bytes: &match event {
|
||||||
|
Event::NoteOn(pitch, velocity) => [
|
||||||
|
0b10010000,
|
||||||
|
*pitch,
|
||||||
|
*velocity
|
||||||
|
],
|
||||||
|
Event::NoteOff(pitch) => [
|
||||||
|
0b10000000,
|
||||||
|
*pitch,
|
||||||
|
0b00000000
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Control::Continue
|
||||||
|
}
|
||||||
|
});
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
exited: false,
|
exited,
|
||||||
cursor: (0, 0, 0),
|
cursor: (0, 0, 0),
|
||||||
transport,
|
transport,
|
||||||
sequence: vec![vec![None;64];4],
|
sequence,
|
||||||
bpm: 120.0,
|
bpm: 120.0,
|
||||||
timesig: (4.0, 4.0)
|
timesig: (4.0, 4.0),
|
||||||
|
jack_client: client.activate_async(
|
||||||
|
self::jack::Notifications,
|
||||||
|
ClosureProcessHandler::new(handler)
|
||||||
|
)?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Exitable for Sequencer {
|
impl Exitable for Sequencer {
|
||||||
fn exit (&mut self) {
|
fn exit (&mut self) {
|
||||||
self.exited = true
|
self.exited.store(true, Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
fn exited (&self) -> bool {
|
fn exited (&self) -> bool {
|
||||||
self.exited
|
self.exited.fetch_and(true, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#[test]
|
||||||
|
fn test_midi_frames () {
|
||||||
|
let beats = 4;
|
||||||
|
let steps = 16;
|
||||||
|
let bpm = 120;
|
||||||
|
let rate = 44100; // Hz
|
||||||
|
let frame = 1f64 / rate as f64; // msec
|
||||||
|
let buf = 512; // frames
|
||||||
|
let t_beat = 60.0 / bpm as f64; // msec
|
||||||
|
let t_loop = t_beat * beats as f64; // msec
|
||||||
|
let t_step = t_beat / steps as f64; // msec
|
||||||
|
|
||||||
|
let assign = |chunk: usize| {
|
||||||
|
let start = chunk * buf; // frames
|
||||||
|
let end = (chunk + 1) * buf; // frames
|
||||||
|
println!("{chunk}: {start} .. {end}");
|
||||||
|
let mut steps: Vec<(usize, usize, f64)> = vec![];
|
||||||
|
for frame_index in start..end {
|
||||||
|
let frame_msec = frame_index as f64 * frame;
|
||||||
|
let offset = (frame_msec * 1000.0) % (t_step * 1000.0);
|
||||||
|
if offset < 0.1 {
|
||||||
|
let time = frame_index - start;
|
||||||
|
let step_index = (frame_msec % t_loop / t_step) as usize;
|
||||||
|
println!("{chunk}: {frame_index} ({time}) -> {step_index} ({frame_msec} % {t_step} = {offset})");
|
||||||
|
steps.push((time, step_index, offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps
|
||||||
|
};
|
||||||
|
|
||||||
|
for chunk in 0..10 {
|
||||||
|
let chunk = assign(chunk);
|
||||||
|
//println!("{chunk} {:#?}", assign(chunk));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_midi_frames_2 () {
|
||||||
|
let beats = 4;
|
||||||
|
let steps = 16;
|
||||||
|
let bpm = 120;
|
||||||
|
let rate = 44100; // Hz
|
||||||
|
let frame = 1f64 / rate as f64; // msec
|
||||||
|
let buf = 512; // frames
|
||||||
|
let t_beat = 60.0 / bpm as f64; // msec
|
||||||
|
let t_loop = t_beat * beats as f64; // msec
|
||||||
|
let t_step = t_beat / steps as f64; // msec
|
||||||
|
let mut step_frames = vec![];
|
||||||
|
for step in 0..beats*steps {
|
||||||
|
let step_index = (step as f64 * t_step / frame) as usize;
|
||||||
|
step_frames.push(step_index);
|
||||||
|
}
|
||||||
|
let loop_frames = (t_loop*rate as f64) as usize;
|
||||||
|
let mut frame_steps: Vec<Option<usize>> = vec![None;loop_frames];
|
||||||
|
for (index, frame) in step_frames.iter().enumerate() {
|
||||||
|
println!("{index} {frame}");
|
||||||
|
frame_steps[*frame] = Some(index);
|
||||||
|
}
|
||||||
|
let assign = |chunk: usize| {
|
||||||
|
let (start, end) = (chunk * buf, (chunk + 1) * buf); // frames
|
||||||
|
let (start_looped, end_looped) = (start % loop_frames, end % loop_frames);
|
||||||
|
println!("{chunk}: {start} .. {end} ({start_looped} .. {end_looped})");
|
||||||
|
let mut steps: Vec<Option<usize>> = vec![None;buf];
|
||||||
|
for frame in 0..buf {
|
||||||
|
let value = frame_steps[(start_looped + frame) as usize % loop_frames];
|
||||||
|
if value.is_some() { println!("{frame:03} = {value:?}, ") };
|
||||||
|
steps[frame as usize] = value;
|
||||||
|
}
|
||||||
|
steps
|
||||||
|
};
|
||||||
|
for chunk in 0..1000 {
|
||||||
|
let chunk = assign(chunk);
|
||||||
|
//println!("{chunk} {:#?}", assign(chunk));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ fn render_grid (
|
||||||
.queue(move_to(17, 3))?.queue(Print("1.2"))?
|
.queue(move_to(17, 3))?.queue(Print("1.2"))?
|
||||||
.queue(move_to(33, 3))?.queue(Print("1.3"))?
|
.queue(move_to(33, 3))?.queue(Print("1.3"))?
|
||||||
.queue(move_to(49, 3))?.queue(Print("1.4"))?;
|
.queue(move_to(49, 3))?.queue(Print("1.4"))?;
|
||||||
for (index, row) in state.sequence.iter().enumerate() {
|
let sequence = state.sequence.lock().unwrap();
|
||||||
|
for (index, row) in sequence.iter().enumerate() {
|
||||||
let y = index as u16 + 4;
|
let y = index as u16 + 4;
|
||||||
for x in 0u16..64 {
|
for x in 0u16..64 {
|
||||||
let bg = if x as u32 == (beat - 1) * 16 + (beat_sub * 16.0) as u32 {
|
let bg = if x as u32 == (beat - 1) * 16 + (beat_sub * 16.0) as u32 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue