mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
Compare commits
11 commits
1b926b0338
...
cc88743054
| Author | SHA1 | Date | |
|---|---|---|---|
| cc88743054 | |||
| 6f8a677b7a | |||
| 780fd6694b | |||
| 1b48e10d2d | |||
| e3b12a1d36 | |||
| 16d267523b | |||
| ee7f9dcf12 | |||
| a8be2e9dad | |||
| a6100ab1d6 | |||
| 04af945ea0 | |||
| 9f9de3fafb |
20 changed files with 1279 additions and 948 deletions
112
.old/demo.rs.old
Normal file
112
.old/demo.rs.old
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
use tek::*;
|
||||||
|
|
||||||
|
fn main () -> Usually<()> {
|
||||||
|
Tui::run(Arc::new(RwLock::new(Demo::new())))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Demo<E: Engine> {
|
||||||
|
index: usize,
|
||||||
|
items: Vec<Box<dyn Render<Engine = E>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Demo<Tui> {
|
||||||
|
fn new () -> Self {
|
||||||
|
Self {
|
||||||
|
index: 0,
|
||||||
|
items: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Content for Demo<Tui> {
|
||||||
|
type Engine = Tui;
|
||||||
|
fn content (&self) -> dyn Render<Engine = Tui> {
|
||||||
|
let border_style = Style::default().fg(Color::Rgb(0,0,0));
|
||||||
|
Align::Center(Layers::new(move|add|{
|
||||||
|
|
||||||
|
add(&Background(Color::Rgb(0,128,128)))?;
|
||||||
|
|
||||||
|
add(&Margin::XY(1, 1, Stack::down(|add|{
|
||||||
|
|
||||||
|
add(&Layers::new(|add|{
|
||||||
|
add(&Background(Color::Rgb(128,96,0)))?;
|
||||||
|
add(&Border(Square(border_style)))?;
|
||||||
|
add(&Margin::XY(2, 1, "..."))?;
|
||||||
|
Ok(())
|
||||||
|
}).debug())?;
|
||||||
|
|
||||||
|
add(&Layers::new(|add|{
|
||||||
|
add(&Background(Color::Rgb(128,64,0)))?;
|
||||||
|
add(&Border(Lozenge(border_style)))?;
|
||||||
|
add(&Margin::XY(4, 2, "---"))?;
|
||||||
|
Ok(())
|
||||||
|
}).debug())?;
|
||||||
|
|
||||||
|
add(&Layers::new(|add|{
|
||||||
|
add(&Background(Color::Rgb(96,64,0)))?;
|
||||||
|
add(&Border(SquareBold(border_style)))?;
|
||||||
|
add(&Margin::XY(6, 3, "~~~"))?;
|
||||||
|
Ok(())
|
||||||
|
}).debug())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})).debug())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}))
|
||||||
|
//Align::Center(Margin::X(1, Layers::new(|add|{
|
||||||
|
//add(&Background(Color::Rgb(128,0,0)))?;
|
||||||
|
//add(&Stack::down(|add|{
|
||||||
|
//add(&Margin::Y(1, Layers::new(|add|{
|
||||||
|
//add(&Background(Color::Rgb(0,128,0)))?;
|
||||||
|
//add(&Align::Center("12345"))?;
|
||||||
|
//add(&Align::Center("FOO"))
|
||||||
|
//})))?;
|
||||||
|
//add(&Margin::XY(1, 1, Layers::new(|add|{
|
||||||
|
//add(&Align::Center("1234567"))?;
|
||||||
|
//add(&Align::Center("BAR"))?;
|
||||||
|
//add(&Background(Color::Rgb(0,0,128)))
|
||||||
|
//})))
|
||||||
|
//}))
|
||||||
|
//})))
|
||||||
|
|
||||||
|
//Align::Y(Layers::new(|add|{
|
||||||
|
//add(&Background(Color::Rgb(128,0,0)))?;
|
||||||
|
//add(&Margin::X(1, Align::Center(Stack::down(|add|{
|
||||||
|
//add(&Align::X(Margin::Y(1, Layers::new(|add|{
|
||||||
|
//add(&Background(Color::Rgb(0,128,0)))?;
|
||||||
|
//add(&Align::Center("12345"))?;
|
||||||
|
//add(&Align::Center("FOO"))
|
||||||
|
//})))?;
|
||||||
|
//add(&Margin::XY(1, 1, Layers::new(|add|{
|
||||||
|
//add(&Align::Center("1234567"))?;
|
||||||
|
//add(&Align::Center("BAR"))?;
|
||||||
|
//add(&Background(Color::Rgb(0,0,128)))
|
||||||
|
//})))?;
|
||||||
|
//Ok(())
|
||||||
|
//})))))
|
||||||
|
//}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handle<TuiIn> for Demo<Tui> {
|
||||||
|
fn handle (&mut self, from: &TuiIn) -> Perhaps<bool> {
|
||||||
|
use KeyCode::{PageUp, PageDown};
|
||||||
|
match from.event() {
|
||||||
|
kexp!(PageUp) => {
|
||||||
|
self.index = (self.index + 1) % self.items.len();
|
||||||
|
},
|
||||||
|
kexp!(PageDown) => {
|
||||||
|
self.index = if self.index > 1 {
|
||||||
|
self.index - 1
|
||||||
|
} else {
|
||||||
|
self.items.len() - 1
|
||||||
|
};
|
||||||
|
},
|
||||||
|
_ => return Ok(None)
|
||||||
|
}
|
||||||
|
Ok(Some(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
50
Cargo.lock
generated
50
Cargo.lock
generated
|
|
@ -35,15 +35,15 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.11"
|
version = "0.8.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom 0.2.16",
|
"getrandom 0.3.2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
"zerocopy 0.7.35",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -176,9 +176,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.74"
|
version = "0.3.75"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
@ -968,7 +968,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.11",
|
"redox_syscall 0.5.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1466,7 +1466,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.11",
|
"redox_syscall 0.5.12",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
@ -1578,7 +1578,7 @@ version = "0.2.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy 0.8.25",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1790,9 +1790,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.11"
|
version = "0.5.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
]
|
]
|
||||||
|
|
@ -2301,6 +2301,7 @@ dependencies = [
|
||||||
"symphonia",
|
"symphonia",
|
||||||
"tek_engine",
|
"tek_engine",
|
||||||
"tengri",
|
"tengri",
|
||||||
|
"tengri_proc",
|
||||||
"uuid",
|
"uuid",
|
||||||
"wavers",
|
"wavers",
|
||||||
"winit",
|
"winit",
|
||||||
|
|
@ -2367,6 +2368,7 @@ dependencies = [
|
||||||
name = "tengri_proc"
|
name = "tengri_proc"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
|
@ -3132,9 +3134,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.9"
|
version = "0.7.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
|
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
@ -3205,33 +3207,13 @@ 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 = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy"
|
|
||||||
version = "0.7.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy-derive 0.7.35",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.25"
|
version = "0.8.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive 0.8.25",
|
"zerocopy-derive",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy-derive"
|
|
||||||
version = "0.7.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -37,8 +37,8 @@ or [**matrix** `@unspeaker:matrix.org`](https://matrix.to/#/@unspeaker:matrix.or
|
||||||
* [ ] `z`: zoom lock/unlock
|
* [ ] `z`: zoom lock/unlock
|
||||||
* [ ] `del`: delete
|
* [ ] `del`: delete
|
||||||
* Global:
|
* Global:
|
||||||
* [ ] esc: options menu
|
* [x] esc: options menu
|
||||||
* [ ] f1: help/command list
|
* [x] f1: help/command list
|
||||||
* [ ] f2: rename
|
* [ ] f2: rename
|
||||||
* [ ] f6: save
|
* [ ] f6: save
|
||||||
* [ ] f9: load
|
* [ ] f9: load
|
||||||
|
|
@ -68,11 +68,11 @@ paru -S tek
|
||||||
requires docker.
|
requires docker.
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://codeberg.org/unspeaker/tek # obtain source
|
git clone --recursive -b 0.2 https://codeberg.org/unspeaker/tek
|
||||||
cd tek # enter directory
|
cd tek # enter directory
|
||||||
cat bin/release-glibc.sh # preview build script
|
cat bin/release-glibc.sh # preview build script
|
||||||
sudo bin/release-glibc.sh # run build script
|
sudo bin/release-glibc.sh # run build script
|
||||||
sudo cp bin/tek /usr/local/bin/tek # install
|
sudo cp bin/tek /usr/local/bin/tek # install
|
||||||
```
|
```
|
||||||
|
|
||||||
## design goals
|
## design goals
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use tek_midi::*;
|
use tek::*;
|
||||||
use tengri::input::*;
|
use tengri::input::*;
|
||||||
use std::sync::*;
|
use std::sync::*;
|
||||||
struct ExampleClips(Arc<RwLock<Vec<Arc<RwLock<MidiClip>>>>>);
|
struct ExampleClips(Arc<RwLock<Vec<Arc<RwLock<MidiClip>>>>>);
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -53,9 +53,9 @@ impl MidiEditor {
|
||||||
let mut redraw = false;
|
let mut redraw = false;
|
||||||
if let Some(clip) = self.clip() {
|
if let Some(clip) = self.clip() {
|
||||||
let mut clip = clip.write().unwrap();
|
let mut clip = clip.write().unwrap();
|
||||||
let note_start = self.time_pos();
|
let note_start = self.get_time_pos();
|
||||||
let note_pos = self.note_pos();
|
let note_pos = self.get_note_pos();
|
||||||
let note_len = self.note_len();
|
let note_len = self.get_note_len();
|
||||||
let note_end = note_start + (note_len.saturating_sub(1));
|
let note_end = note_start + (note_len.saturating_sub(1));
|
||||||
let key: u7 = u7::from(note_pos as u8);
|
let key: u7 = u7::from(note_pos as u8);
|
||||||
let vel: u7 = 100.into();
|
let vel: u7 = 100.into();
|
||||||
|
|
@ -93,12 +93,13 @@ impl MidiEditor {
|
||||||
let (color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
|
let (color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
|
||||||
(clip.color, clip.length)
|
(clip.color, clip.length)
|
||||||
} else { (ItemTheme::G[64], 0) };
|
} else { (ItemTheme::G[64], 0) };
|
||||||
let time_pos = self.time_pos();
|
let time_pos = self.get_time_pos();
|
||||||
let time_zoom = self.time_zoom().get();
|
let time_zoom = self.get_time_zoom();
|
||||||
let time_lock = if self.time_lock().get() { "[lock]" } else { " " };
|
let time_lock = if self.get_time_lock() { "[lock]" } else { " " };
|
||||||
let note_pos = format!("{:>3}", self.note_pos());
|
let note_pos = self.get_note_pos();
|
||||||
let note_name = format!("{:4}", Note::pitch_to_name(self.note_pos()));
|
let note_name = format!("{:4}", Note::pitch_to_name(note_pos));
|
||||||
let note_len = format!("{:>4}", self.note_len());
|
let note_pos = format!("{:>3}", note_pos);
|
||||||
|
let note_len = format!("{:>4}", self.get_note_len());
|
||||||
Bsp::e(
|
Bsp::e(
|
||||||
FieldH(color, "Time", format!("{length}/{time_zoom}+{time_pos} {time_lock}")),
|
FieldH(color, "Time", format!("{length}/{time_zoom}+{time_pos} {time_lock}")),
|
||||||
FieldH(color, "Note", format!("{note_name} {note_pos} {note_len}")),
|
FieldH(color, "Note", format!("{note_name} {note_pos} {note_len}")),
|
||||||
|
|
@ -120,15 +121,12 @@ impl NoteRange for MidiEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotePoint for MidiEditor {
|
impl NotePoint for MidiEditor {
|
||||||
fn note_len (&self) -> usize { self.mode.note_len() }
|
fn note_len (&self) -> &AtomicUsize { self.mode.note_len() }
|
||||||
fn set_note_len (&self, x: usize) -> usize { self.mode.set_note_len(x) }
|
fn note_pos (&self) -> &AtomicUsize { self.mode.note_pos() }
|
||||||
fn note_pos (&self) -> usize { self.mode.note_pos() }
|
|
||||||
fn set_note_pos (&self, x: usize) -> usize { self.mode.set_note_pos(x) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimePoint for MidiEditor {
|
impl TimePoint for MidiEditor {
|
||||||
fn time_pos (&self) -> usize { self.mode.time_pos() }
|
fn time_pos (&self) -> &AtomicUsize { self.mode.time_pos() }
|
||||||
fn set_time_pos (&self, x: usize) -> usize { self.mode.set_time_pos(x) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MidiViewer for MidiEditor {
|
impl MidiViewer for MidiEditor {
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,9 @@ pub(crate) use ::tengri::tui::ratatui::prelude::Position;
|
||||||
|
|
||||||
#[tengri_proc::view(TuiOut)]
|
#[tengri_proc::view(TuiOut)]
|
||||||
impl Tek {
|
impl Tek {
|
||||||
|
|
||||||
#[tengri::view(":nil")]
|
|
||||||
fn view_nil (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_nil (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
"nil"
|
"nil"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":status")]
|
|
||||||
fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.update_clock();
|
self.update_clock();
|
||||||
let cache = self.view_cache.read().unwrap();
|
let cache = self.view_cache.read().unwrap();
|
||||||
|
|
@ -19,8 +15,6 @@ impl Tek {
|
||||||
cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone(),
|
cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":transport")]
|
|
||||||
fn view_transport (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_transport (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.update_clock();
|
self.update_clock();
|
||||||
let cache = self.view_cache.read().unwrap();
|
let cache = self.view_cache.read().unwrap();
|
||||||
|
|
@ -29,38 +23,24 @@ impl Tek {
|
||||||
cache.bpm.view.clone(), cache.beat.view.clone(), cache.time.view.clone(),
|
cache.bpm.view.clone(), cache.beat.view.clone(), cache.time.view.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":arranger")]
|
|
||||||
fn view_arranger (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_arranger (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
ArrangerView::new(self)
|
ArrangerView::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":pool")]
|
|
||||||
fn view_pool (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_pool (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.pool().map(|p|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), p)))
|
self.pool().map(|p|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), p)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":editor")]
|
|
||||||
fn view_editor (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_editor (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.editor().map(|e|Bsp::n(Bsp::e(e.clip_status(), e.edit_status()), e))
|
self.editor().map(|e|Bsp::n(Bsp::e(e.clip_status(), e.edit_status()), e))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":samples-keys")]
|
|
||||||
fn view_samples_keys (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_samples_keys (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.sampler().map(|s|s.view_list(false, self.editor().unwrap()))
|
self.sampler().map(|s|s.view_list(false, self.editor().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":samples-grid")]
|
|
||||||
fn view_samples_grid (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_samples_grid (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.sampler().map(|s|s.view_grid())
|
self.sampler().map(|s|s.view_grid())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":sample-viewer")]
|
|
||||||
fn view_sample_viewer (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_sample_viewer (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
self.sampler().map(|s|s.view_sample(self.editor().unwrap().note_pos()))
|
self.sampler().map(|s|s.view_sample(self.editor().unwrap().get_note_pos()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tengri::view(":dialog")]
|
|
||||||
fn view_dialog (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_dialog (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
When::new(self.dialog.is_some(), Bsp::b(
|
When::new(self.dialog.is_some(), Bsp::b(
|
||||||
Fill::xy(Tui::fg_bg(Rgb(64,64,64), Rgb(32,32,32), "")),
|
Fill::xy(Tui::fg_bg(Rgb(64,64,64), Rgb(32,32,32), "")),
|
||||||
|
|
@ -76,13 +56,14 @@ impl Tek {
|
||||||
)))
|
)))
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tek {
|
||||||
fn view_dialog_menu (&self) -> impl Content<TuiOut> {
|
fn view_dialog_menu (&self) -> impl Content<TuiOut> {
|
||||||
let options = ||["Projects", "Settings", "Help", "Quit"].iter();
|
let options = ||["Projects", "Settings", "Help", "Quit"].iter();
|
||||||
let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a));
|
let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a));
|
||||||
Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option)))
|
Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_dialog_help (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_dialog_help (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
let bindings = ||self.config.keys.layers.iter()
|
let bindings = ||self.config.keys.layers.iter()
|
||||||
.filter_map(|a|(a.0)(self).then_some(a.1))
|
.filter_map(|a|(a.0)(self).then_some(a.1))
|
||||||
|
|
@ -134,69 +115,6 @@ impl Tek {
|
||||||
/// Default editor height.
|
/// Default editor height.
|
||||||
pub(crate) const H_EDITOR: usize = 15;
|
pub(crate) const H_EDITOR: usize = 15;
|
||||||
|
|
||||||
/// Width of display
|
|
||||||
pub(crate) fn w (&self) -> u16 {
|
|
||||||
self.size.w() as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn w_sidebar (&self) -> u16 {
|
|
||||||
self.w() / if self.is_editing() { 16 } else { 8 } as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Width taken by all tracks.
|
|
||||||
pub(crate) fn w_tracks (&self) -> u16 {
|
|
||||||
self.tracks_with_sizes().last().map(|(_, _, _, x)|x as u16).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Width available to display tracks.
|
|
||||||
pub(crate) fn w_tracks_area (&self) -> u16 {
|
|
||||||
self.w().saturating_sub(2 * self.w_sidebar())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Height of display
|
|
||||||
pub(crate) fn h (&self) -> u16 {
|
|
||||||
self.size.h() as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Height available to display track headers.
|
|
||||||
pub(crate) fn h_tracks_area (&self) -> u16 {
|
|
||||||
5 // FIXME
|
|
||||||
//self.h().saturating_sub(self.h_inputs() + self.h_outputs())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Height available to display tracks.
|
|
||||||
pub(crate) fn h_scenes_area (&self) -> u16 {
|
|
||||||
//15
|
|
||||||
self.h().saturating_sub(
|
|
||||||
self.h_inputs() +
|
|
||||||
self.h_outputs() +
|
|
||||||
self.h_devices() +
|
|
||||||
13 // FIXME
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Height taken by all inputs.
|
|
||||||
pub(crate) fn h_inputs (&self) -> u16 {
|
|
||||||
self.inputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Height taken by all outputs.
|
|
||||||
pub(crate) fn h_outputs (&self) -> u16 {
|
|
||||||
self.outputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Height taken by visible device slots.
|
|
||||||
pub(crate) fn h_devices (&self) -> u16 {
|
|
||||||
2
|
|
||||||
//1 + self.devices_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Height taken by all scenes.
|
|
||||||
pub(crate) fn h_scenes (&self) -> u16 {
|
|
||||||
self.scenes_with_sizes(self.is_editing(), Self::H_SCENE, Self::H_EDITOR).last()
|
|
||||||
.map(|(_, _, _, y)|y as u16).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn inputs_with_sizes (&self) -> impl PortsSizes<'_> {
|
pub(crate) fn inputs_with_sizes (&self) -> impl PortsSizes<'_> {
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
self.midi_ins.iter().enumerate().map(move|(i, input)|{
|
self.midi_ins.iter().enumerate().map(move|(i, input)|{
|
||||||
|
|
@ -1137,9 +1055,9 @@ impl PianoHorizontal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn notes (&self) -> impl Content<TuiOut> {
|
fn notes (&self) -> impl Content<TuiOut> {
|
||||||
let time_start = self.time_start().get();
|
let time_start = self.get_time_start();
|
||||||
let note_lo = self.note_lo().get();
|
let note_lo = self.get_note_lo();
|
||||||
let note_hi = self.note_hi();
|
let note_hi = self.get_note_hi();
|
||||||
let buffer = self.buffer.clone();
|
let buffer = self.buffer.clone();
|
||||||
ThunkRender::new(move|to: &mut TuiOut|{
|
ThunkRender::new(move|to: &mut TuiOut|{
|
||||||
let source = buffer.read().unwrap();
|
let source = buffer.read().unwrap();
|
||||||
|
|
@ -1168,14 +1086,14 @@ impl PianoHorizontal {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn cursor (&self) -> impl Content<TuiOut> {
|
fn cursor (&self) -> impl Content<TuiOut> {
|
||||||
let style = Some(Style::default().fg(self.color.lightest.rgb));
|
let note_hi = self.get_note_hi();
|
||||||
let note_hi = self.note_hi();
|
let note_lo = self.get_note_lo();
|
||||||
let note_lo = self.note_lo().get();
|
let note_pos = self.get_note_pos();
|
||||||
let note_pos = self.note_pos();
|
let note_len = self.get_note_len();
|
||||||
let note_len = self.note_len();
|
let time_pos = self.get_time_pos();
|
||||||
let time_pos = self.time_pos();
|
let time_start = self.get_time_start();
|
||||||
let time_start = self.time_start().get();
|
let time_zoom = self.get_time_zoom();
|
||||||
let time_zoom = self.time_zoom().get();
|
let style = Some(Style::default().fg(self.color.lightest.rgb));
|
||||||
ThunkRender::new(move|to: &mut TuiOut|{
|
ThunkRender::new(move|to: &mut TuiOut|{
|
||||||
let [x0, y0, w, _] = to.area().xywh();
|
let [x0, y0, w, _] = to.area().xywh();
|
||||||
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
|
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
|
||||||
|
|
@ -1201,9 +1119,9 @@ impl PianoHorizontal {
|
||||||
fn keys (&self) -> impl Content<TuiOut> {
|
fn keys (&self) -> impl Content<TuiOut> {
|
||||||
let state = self;
|
let state = self;
|
||||||
let color = state.color;
|
let color = state.color;
|
||||||
let note_lo = state.note_lo().get();
|
let note_lo = state.get_note_lo();
|
||||||
let note_hi = state.note_hi();
|
let note_hi = state.get_note_hi();
|
||||||
let note_pos = state.note_pos();
|
let note_pos = state.get_note_pos();
|
||||||
let key_style = Some(Style::default().fg(Rgb(192, 192, 192)).bg(Rgb(0, 0, 0)));
|
let key_style = Some(Style::default().fg(Rgb(192, 192, 192)).bg(Rgb(0, 0, 0)));
|
||||||
let off_style = Some(Style::default().fg(Tui::g(255)));
|
let off_style = Some(Style::default().fg(Tui::g(255)));
|
||||||
let on_style = Some(Style::default().fg(Rgb(255,0,0)).bg(color.base.rgb).bold());
|
let on_style = Some(Style::default().fg(Rgb(255,0,0)).bg(color.base.rgb).bold());
|
||||||
|
|
@ -1253,15 +1171,12 @@ impl NoteRange for PianoHorizontal {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotePoint for PianoHorizontal {
|
impl NotePoint for PianoHorizontal {
|
||||||
fn note_len (&self) -> usize { self.point.note_len() }
|
fn note_len (&self) -> &AtomicUsize { self.point.note_len() }
|
||||||
fn set_note_len (&self, x: usize) -> usize { self.point.set_note_len(x) }
|
fn note_pos (&self) -> &AtomicUsize { self.point.note_pos() }
|
||||||
fn note_pos (&self) -> usize { self.point.note_pos() }
|
|
||||||
fn set_note_pos (&self, x: usize) -> usize { self.point.set_note_pos(x) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimePoint for PianoHorizontal {
|
impl TimePoint for PianoHorizontal {
|
||||||
fn time_pos (&self) -> usize { self.point.time_pos() }
|
fn time_pos (&self) -> &AtomicUsize { self.point.time_pos() }
|
||||||
fn set_time_pos (&self, x: usize) -> usize { self.point.set_time_pos(x) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MidiViewer for PianoHorizontal {
|
impl MidiViewer for PianoHorizontal {
|
||||||
|
|
@ -1280,8 +1195,8 @@ impl MidiViewer for PianoHorizontal {
|
||||||
let clip = clip.read().unwrap();
|
let clip = clip.read().unwrap();
|
||||||
let buf_size = self.buffer_size(&clip);
|
let buf_size = self.buffer_size(&clip);
|
||||||
let mut buffer = BigBuffer::from(buf_size);
|
let mut buffer = BigBuffer::from(buf_size);
|
||||||
let note_len = self.note_len();
|
let note_len = self.get_note_len();
|
||||||
let time_zoom = self.time_zoom().get();
|
let time_zoom = self.get_time_zoom();
|
||||||
self.time_len().set(clip.length);
|
self.time_len().set(clip.length);
|
||||||
PianoHorizontal::draw_bg(&mut buffer, &clip, time_zoom, note_len);
|
PianoHorizontal::draw_bg(&mut buffer, &clip, time_zoom, note_len);
|
||||||
PianoHorizontal::draw_fg(&mut buffer, &clip, time_zoom);
|
PianoHorizontal::draw_fg(&mut buffer, &clip, time_zoom);
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,16 @@ edition = { workspace = true }
|
||||||
version = { workspace = true }
|
version = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tengri = { workspace = true }
|
tengri = { workspace = true }
|
||||||
|
tengri_proc = { workspace = true }
|
||||||
|
|
||||||
tek_engine = { workspace = true }
|
tek_engine = { workspace = true }
|
||||||
uuid = { workspace = true, optional = true }
|
|
||||||
livi = { workspace = true, optional = true }
|
uuid = { workspace = true, optional = true }
|
||||||
symphonia = { workspace = true, optional = true }
|
livi = { workspace = true, optional = true }
|
||||||
wavers = { workspace = true, optional = true }
|
symphonia = { workspace = true, optional = true }
|
||||||
winit = { workspace = true, optional = true }
|
wavers = { workspace = true, optional = true }
|
||||||
|
winit = { workspace = true, optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "clock", "sequencer", "sampler", "lv2" ]
|
default = [ "clock", "sequencer", "sampler", "lv2" ]
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,61 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[tengri_proc::expose]
|
||||||
pub enum ClockCommand {
|
impl Clock {
|
||||||
Play(Option<u32>),
|
fn _todo_provide_u32 (&self) -> u32 {
|
||||||
Pause(Option<u32>),
|
todo!()
|
||||||
SeekUsec(f64),
|
}
|
||||||
SeekSample(f64),
|
fn _todo_provide_opt_u32 (&self) -> Option<u32> {
|
||||||
SeekPulse(f64),
|
todo!()
|
||||||
SetBpm(f64),
|
}
|
||||||
SetQuant(f64),
|
fn _todo_provide_f64 (&self) -> f64 {
|
||||||
SetSync(f64),
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provide_num!(u32: |self: Clock| {});
|
|
||||||
|
|
||||||
provide!(f64: |self: Clock| {});
|
|
||||||
|
|
||||||
atom_command!(ClockCommand: |state: Clock| {
|
|
||||||
("play" [] Some(Self::Play(None)))
|
|
||||||
("play" [t: u32] Some(Self::Play(t)))
|
|
||||||
("pause" [] Some(Self::Pause(None)))
|
|
||||||
("pause" [t: u32] Some(Self::Pause(t)))
|
|
||||||
("toggle" [] Some(if state.is_rolling() { Self::Pause(None) } else { Self::Play(None) }))
|
|
||||||
("toggle" [t: u32] Some(if state.is_rolling() { Self::Pause(t) } else { Self::Play(t) }))
|
|
||||||
("seek/usec" [t: f64] Some(Self::SeekUsec(t.expect("no usec"))))
|
|
||||||
("seek/pulse" [t: f64] Some(Self::SeekPulse(t.expect("no pulse"))))
|
|
||||||
("seek/sample" [t: f64] Some(Self::SeekSample(t.expect("no sample"))))
|
|
||||||
("set/bpm" [t: f64] Some(Self::SetBpm(t.expect("no bpm"))))
|
|
||||||
("set/sync" [t: f64] Some(Self::SetSync(t.expect("no sync"))))
|
|
||||||
("set/quant" [t: f64] Some(Self::SetQuant(t.expect("no quant"))))
|
|
||||||
});
|
|
||||||
|
|
||||||
impl<T: HasClock> Command<T> for ClockCommand {
|
impl<T: HasClock> Command<T> for ClockCommand {
|
||||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||||
self.execute(state.clock_mut())
|
self.execute(state.clock_mut()) // awesome
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command<Clock> for ClockCommand {
|
#[tengri_proc::command(Clock)]
|
||||||
fn execute (self, state: &mut Clock) -> Perhaps<Self> {
|
impl ClockCommand {
|
||||||
use ClockCommand::*;
|
fn play (state: &mut Clock, position: Option<u32>) -> Perhaps<Self> {
|
||||||
match self {
|
state.play_from(position)?;
|
||||||
Play(start) => state.play_from(start)?,
|
Ok(None) // TODO Some(Pause(previousPosition))
|
||||||
Pause(pause) => state.pause_at(pause)?,
|
}
|
||||||
SeekUsec(usec) => state.playhead.update_from_usec(usec),
|
fn pause (state: &mut Clock, position: Option<u32>) -> Perhaps<Self> {
|
||||||
SeekSample(sample) => state.playhead.update_from_sample(sample),
|
state.pause_at(position)?;
|
||||||
SeekPulse(pulse) => state.playhead.update_from_pulse(pulse),
|
|
||||||
SetBpm(bpm) => return Ok(Some(SetBpm(state.timebase().bpm.set(bpm)))),
|
|
||||||
SetQuant(quant) => return Ok(Some(SetQuant(state.quant.set(quant)))),
|
|
||||||
SetSync(sync) => return Ok(Some(SetSync(state.sync.set(sync)))),
|
|
||||||
};
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
fn toggle_playback (state: &mut Clock, position: Option<u32>) -> Perhaps<Self> {
|
||||||
|
if state.is_rolling() {
|
||||||
|
state.pause_at(position)?;
|
||||||
|
} else {
|
||||||
|
state.play_from(position)?;
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn seek_usec (state: &mut Clock, usec: f64) -> Perhaps<Self> {
|
||||||
|
state.playhead.update_from_usec(usec);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn seek_sample (state: &mut Clock, sample: f64) -> Perhaps<Self> {
|
||||||
|
state.playhead.update_from_sample(sample);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn seek_pulse (state: &mut Clock, pulse: f64) -> Perhaps<Self> {
|
||||||
|
state.playhead.update_from_pulse(pulse);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn set_bpm (state: &mut Clock, bpm: f64) -> Perhaps<Self> {
|
||||||
|
Ok(Some(Self::SetBpm { bpm: state.timebase().bpm.set(bpm) }))
|
||||||
|
}
|
||||||
|
fn set_quant (state: &mut Clock, quant: f64) -> Perhaps<Self> {
|
||||||
|
Ok(Some(Self::SetQuant { quant: state.quant.set(quant) }))
|
||||||
|
}
|
||||||
|
fn set_sync (state: &mut Clock, sync: f64) -> Perhaps<Self> {
|
||||||
|
Ok(Some(Self::SetSync { sync: state.sync.set(sync) }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,165 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
expose!([self: Sampler]
|
|
||||||
([Arc<str>])
|
|
||||||
([MaybeSample])
|
|
||||||
([PathBuf])
|
|
||||||
([f32])
|
|
||||||
([u7]
|
|
||||||
(":pitch" (self.note_pos() as u8).into()) // TODO
|
|
||||||
(":sample" (self.note_pos() as u8).into()))
|
|
||||||
([usize]
|
|
||||||
(":sample-up" self.note_pos().min(119) + 8)
|
|
||||||
(":sample-down" self.note_pos().max(8) - 8)
|
|
||||||
(":sample-left" self.note_pos().min(126) + 1)
|
|
||||||
(":sample-right" self.note_pos().max(1) - 1)));
|
|
||||||
|
|
||||||
impose!([state: Sampler]
|
|
||||||
(FileBrowserCommand:
|
|
||||||
("begin" [] Some(Self::Begin))
|
|
||||||
("cancel" [] Some(Self::Cancel))
|
|
||||||
("confirm" [] Some(Self::Confirm))
|
|
||||||
("select" [i: usize] Some(Self::Select(i.expect("no index"))))
|
|
||||||
("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path"))))
|
|
||||||
("filter" [f: Arc<str>] Some(Self::Filter(f.expect("no filter")))))
|
|
||||||
(SamplerCommand:
|
|
||||||
("import" [,..a]
|
|
||||||
FileBrowserCommand::try_from_expr(state, a).map(Self::Import))
|
|
||||||
("select" [i: usize]
|
|
||||||
Some(Self::Select(i.expect("no index"))))
|
|
||||||
("record/begin" [i: u7]
|
|
||||||
Some(Self::RecordBegin(i.expect("no index"))))
|
|
||||||
("record/cancel" []
|
|
||||||
Some(Self::RecordCancel))
|
|
||||||
("record/finish" []
|
|
||||||
Some(Self::RecordFinish))
|
|
||||||
("set/sample" [i: u7, s: MaybeSample]
|
|
||||||
Some(Self::SetSample(i.expect("no index"), s.expect("no sampler"))))
|
|
||||||
("set/start" [i: u7, s: usize]
|
|
||||||
Some(Self::SetStart(i.expect("no index"), s.expect("no start"))))
|
|
||||||
("set/gain" [i: u7, g: f32]
|
|
||||||
Some(Self::SetGain(i.expect("no index"), g.expect("no gain"))))
|
|
||||||
("note/on" [p: u7, v: u7]
|
|
||||||
Some(Self::NoteOn(p.expect("no pitch"), v.expect("no velocity"))))
|
|
||||||
("note/off" [p: u7]
|
|
||||||
Some(Self::NoteOff(p.expect("no pitch"))))));
|
|
||||||
|
|
||||||
macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; }
|
macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; }
|
||||||
macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; }
|
macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; }
|
||||||
|
|
||||||
defcom!([self, state: Sampler]
|
#[tengri_proc::expose]
|
||||||
(SamplerCommand
|
impl Sampler {
|
||||||
(Select [i: usize] Some(Self::Select(state.set_note_pos(i))))
|
//fn file_browser_filter (&self) -> Arc<str> {
|
||||||
(RecordBegin [p: u7] cmd!(state.begin_recording(p.as_int() as usize)))
|
//todo!()
|
||||||
(RecordCancel [] cmd!(state.cancel_recording()))
|
//}
|
||||||
(RecordFinish [] cmd!(state.finish_recording()))
|
//fn file_browser_path (&self) -> PathBuf {
|
||||||
(SetStart [p: u7, frame: usize] cmd_todo!("\n\rtodo: {self:?}"))
|
//todo!();
|
||||||
(SetGain [p: u7, gain: f32] cmd_todo!("\n\rtodo: {self:?}"))
|
//}
|
||||||
(NoteOn [p: u7, velocity: u7] cmd_todo!("\n\rtodo: {self:?}"))
|
///// Immutable reference to sample at cursor.
|
||||||
(NoteOff [p: u7] cmd_todo!("\n\rtodo: {self:?}"))
|
//fn sample_selected (&self) -> MaybeSample {
|
||||||
(SetSample [p: u7, s: MaybeSample] Some(Self::SetSample(p, state.set_sample(p, s))))
|
//for (i, sample) in self.mapped.iter().enumerate() {
|
||||||
(Import [c: FileBrowserCommand] match c {
|
//if i == self.cursor().0 {
|
||||||
FileBrowserCommand::Begin => {
|
//return sample.as_ref()
|
||||||
//let voices = &state.state.voices;
|
//}
|
||||||
//let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
//}
|
||||||
state.mode = Some(SamplerMode::Import(0, FileBrowser::new(None)?));
|
//for (i, sample) in self.unmapped.iter().enumerate() {
|
||||||
None
|
//if i + self.mapped.len() == self.cursor().0 {
|
||||||
},
|
//return Some(sample)
|
||||||
_ => {
|
//}
|
||||||
println!("\n\rtodo: import: filebrowser: {c:?}");
|
//}
|
||||||
None
|
//None
|
||||||
}
|
//}
|
||||||
})));
|
//fn sample_gain (&self) -> f32 {
|
||||||
|
//todo!()
|
||||||
|
//}
|
||||||
|
//fn sample_above () -> usize {
|
||||||
|
//self.note_pos().min(119) + 8
|
||||||
|
//}
|
||||||
|
//fn sample_below () -> usize {
|
||||||
|
//self.note_pos().max(8) - 8
|
||||||
|
//}
|
||||||
|
//fn sample_to_left () -> usize {
|
||||||
|
//self.note_pos().min(126) + 1
|
||||||
|
//}
|
||||||
|
//fn sample_to_right () -> usize {
|
||||||
|
//self.note_pos().max(1) - 1
|
||||||
|
//}
|
||||||
|
//fn selected_pitch () -> u7 {
|
||||||
|
//(self.note_pos() as u8).into() // TODO
|
||||||
|
//}
|
||||||
|
//fn selected_sample () -> u7 { // TODO
|
||||||
|
//(self.note_pos() as u8).into()
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri_proc::command(Sampler)]
|
||||||
|
impl SamplerCommand {
|
||||||
|
//fn select (&self, state: &mut Sampler, i: usize) -> Option<Self> {
|
||||||
|
//Self::Select(state.set_note_pos(i))
|
||||||
|
//}
|
||||||
|
///// Assign sample to pitch
|
||||||
|
//fn set (&self, pitch: u7, sample: MaybeSample) -> Option<Self> {
|
||||||
|
//let i = pitch.as_int() as usize;
|
||||||
|
//let old = self.mapped[i].clone();
|
||||||
|
//self.mapped[i] = sample;
|
||||||
|
//Some(Self::Set(old))
|
||||||
|
//}
|
||||||
|
//fn record_begin (&self, state: &mut Sampler, pitch: u7) -> Option<Self> {
|
||||||
|
//self.recording = Some((
|
||||||
|
//pitch.as_int() as usize,
|
||||||
|
//Arc::new(RwLock::new(Sample::new("Sample", 0, 0, vec![vec![];self.audio_ins.len()])))
|
||||||
|
//));
|
||||||
|
//None
|
||||||
|
//}
|
||||||
|
//fn record_cancel (&self, state: &mut Sampler) -> Option<Self> {
|
||||||
|
//self.recording = None;
|
||||||
|
//None
|
||||||
|
//}
|
||||||
|
//fn record_finish (&self, state: &mut Sampler) -> Option<Self> {
|
||||||
|
//let recording = self.recording.take();
|
||||||
|
//let _sample = if let Some((index, sample)) = recording {
|
||||||
|
//let old = self.mapped[index].clone();
|
||||||
|
//self.mapped[index] = Some(sample);
|
||||||
|
//old
|
||||||
|
//} else {
|
||||||
|
//None
|
||||||
|
//};
|
||||||
|
//None
|
||||||
|
//}
|
||||||
|
//fn set_start (&self, state: &mut Sampler, pitch: u7, frame: usize) -> Option<Self> {
|
||||||
|
//todo!()
|
||||||
|
//}
|
||||||
|
//fn set_gain (&self, state: &mut Sampler, pitch: u7, g: f32) -> Option<Self> {
|
||||||
|
//todo!()
|
||||||
|
//}
|
||||||
|
//fn note_on (&self, state: &mut Sampler, pitch: u7, v: u7) -> Option<Self> {
|
||||||
|
//todo!()
|
||||||
|
//}
|
||||||
|
//fn note_off (&self, state: &mut Sampler, pitch: u7) -> Option<Self> {
|
||||||
|
//todo!()
|
||||||
|
//}
|
||||||
|
//fn set_sample (&self, state: &mut Sampler, pitch: u7, s: MaybeSample) -> Option<Self> {
|
||||||
|
//Some(Self::SetSample(p, state.set_sample(p, s)))
|
||||||
|
//}
|
||||||
|
//fn import (&self, state: &mut Sampler, c: FileBrowserCommand) -> Option<Self> {
|
||||||
|
//match c {
|
||||||
|
//FileBrowserCommand::Begin => {
|
||||||
|
////let voices = &state.state.voices;
|
||||||
|
////let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
||||||
|
//state.mode = Some(SamplerMode::Import(0, FileBrowser::new(None)?));
|
||||||
|
//None
|
||||||
|
//},
|
||||||
|
//_ => {
|
||||||
|
//println!("\n\rtodo: import: filebrowser: {c:?}");
|
||||||
|
//None
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
////(Select [i: usize] Some(Self::Select(state.set_note_pos(i))))
|
||||||
|
////(RecordBegin [p: u7] cmd!(state.begin_recording(p.as_int() as usize)))
|
||||||
|
////(RecordCancel [] cmd!(state.cancel_recording()))
|
||||||
|
////(RecordFinish [] cmd!(state.finish_recording()))
|
||||||
|
////(SetStart [p: u7, frame: usize] cmd_todo!("\n\rtodo: {self:?}"))
|
||||||
|
////(SetGain [p: u7, gain: f32] cmd_todo!("\n\rtodo: {self:?}"))
|
||||||
|
////(NoteOn [p: u7, velocity: u7] cmd_todo!("\n\rtodo: {self:?}"))
|
||||||
|
////(NoteOff [p: u7] cmd_todo!("\n\rtodo: {self:?}"))
|
||||||
|
////(SetSample [p: u7, s: MaybeSample] Some(Self::SetSample(p, state.set_sample(p, s))))
|
||||||
|
////(Import [c: FileBrowserCommand] match c {
|
||||||
|
////FileBrowserCommand::Begin => {
|
||||||
|
//////let voices = &state.state.voices;
|
||||||
|
//////let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
||||||
|
////state.mode = Some(SamplerMode::Import(0, FileBrowser::new(None)?));
|
||||||
|
////None
|
||||||
|
////},
|
||||||
|
////_ => {
|
||||||
|
////println!("\n\rtodo: import: filebrowser: {c:?}");
|
||||||
|
////None
|
||||||
|
////}
|
||||||
|
////})));
|
||||||
|
////("import" [,..a]
|
||||||
|
////FileBrowserCommand::try_from_expr(state, a).map(Self::Import))
|
||||||
|
////("select" [i: usize]
|
||||||
|
////Some(Self::Select(i.expect("no index"))))
|
||||||
|
////("record/begin" [i: u7]
|
||||||
|
////Some(Self::RecordBegin(i.expect("no index"))))
|
||||||
|
////("record/cancel" []
|
||||||
|
////Some(Self::RecordCancel))
|
||||||
|
////("record/finish" []
|
||||||
|
////Some(Self::RecordFinish))
|
||||||
|
////("set/sample" [i: u7, s: MaybeSample]
|
||||||
|
////Some(Self::SetSample(i.expect("no index"), s.expect("no sampler"))))
|
||||||
|
////("set/start" [i: u7, s: usize]
|
||||||
|
////Some(Self::SetStart(i.expect("no index"), s.expect("no start"))))
|
||||||
|
////("set/gain" [i: u7, g: f32]
|
||||||
|
////Some(Self::SetGain(i.expect("no index"), g.expect("no gain"))))
|
||||||
|
////("note/on" [p: u7, v: u7]
|
||||||
|
////Some(Self::NoteOn(p.expect("no pitch"), v.expect("no velocity"))))
|
||||||
|
////("note/off" [p: u7]
|
||||||
|
////Some(Self::NoteOff(p.expect("no pitch"))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tengri_proc::command(Sampler)]
|
||||||
|
impl FileBrowserCommand {
|
||||||
|
//("begin" [] Some(Self::Begin))
|
||||||
|
//("cancel" [] Some(Self::Cancel))
|
||||||
|
//("confirm" [] Some(Self::Confirm))
|
||||||
|
//("select" [i: usize] Some(Self::Select(i.expect("no index"))))
|
||||||
|
//("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path"))))
|
||||||
|
//("filter" [f: Arc<str>] Some(Self::Filter(f.expect("no filter")))))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,50 +77,10 @@ impl Sampler {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn cancel_recording (&mut self) {
|
|
||||||
self.recording = None;
|
|
||||||
}
|
|
||||||
pub fn begin_recording (&mut self, index: usize) {
|
|
||||||
self.recording = Some((
|
|
||||||
index,
|
|
||||||
Arc::new(RwLock::new(Sample::new("Sample", 0, 0, vec![vec![];self.audio_ins.len()])))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
pub fn finish_recording (&mut self) -> MaybeSample {
|
|
||||||
let recording = self.recording.take();
|
|
||||||
if let Some((index, sample)) = recording {
|
|
||||||
let old = self.mapped[index].clone();
|
|
||||||
self.mapped[index] = Some(sample);
|
|
||||||
old
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Immutable reference to sample at cursor.
|
|
||||||
pub fn sample (&self) -> Option<&Arc<RwLock<Sample>>> {
|
|
||||||
for (i, sample) in self.mapped.iter().enumerate() {
|
|
||||||
if i == self.cursor().0 {
|
|
||||||
return sample.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i, sample) in self.unmapped.iter().enumerate() {
|
|
||||||
if i + self.mapped.len() == self.cursor().0 {
|
|
||||||
return Some(sample)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
/// Value of cursor
|
/// Value of cursor
|
||||||
pub fn cursor (&self) -> (usize, usize) {
|
pub fn cursor (&self) -> (usize, usize) {
|
||||||
(self.cursor.0.load(Relaxed), self.cursor.1.load(Relaxed))
|
(self.cursor.0.load(Relaxed), self.cursor.1.load(Relaxed))
|
||||||
}
|
}
|
||||||
/// Assign sample to pitch
|
|
||||||
pub fn set_sample (&mut self, pitch: u7, sample: MaybeSample) -> MaybeSample {
|
|
||||||
let i = pitch.as_int() as usize;
|
|
||||||
let old = self.mapped[i].clone();
|
|
||||||
self.mapped[i] = sample;
|
|
||||||
old
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoteRange for Sampler {
|
impl NoteRange for Sampler {
|
||||||
|
|
@ -133,13 +93,19 @@ impl NoteRange for Sampler {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotePoint for Sampler {
|
impl NotePoint for Sampler {
|
||||||
fn note_len (&self) -> usize {
|
fn note_len (&self) -> &AtomicUsize {
|
||||||
0 /*TODO?*/
|
unreachable!();
|
||||||
|
}
|
||||||
|
fn get_note_len (&self) -> usize {
|
||||||
|
0
|
||||||
}
|
}
|
||||||
fn set_note_len (&self, x: usize) -> usize {
|
fn set_note_len (&self, x: usize) -> usize {
|
||||||
0 /*TODO?*/
|
0 /*TODO?*/
|
||||||
}
|
}
|
||||||
fn note_pos (&self) -> usize {
|
fn note_pos (&self) -> &AtomicUsize {
|
||||||
|
&self.note_pt
|
||||||
|
}
|
||||||
|
fn get_note_pos (&self) -> usize {
|
||||||
self.note_pt.load(Relaxed)
|
self.note_pt.load(Relaxed)
|
||||||
}
|
}
|
||||||
fn set_note_pos (&self, x: usize) -> usize {
|
fn set_note_pos (&self, x: usize) -> usize {
|
||||||
|
|
@ -189,4 +155,3 @@ pub enum SamplerMode {
|
||||||
// Load sample from path
|
// Load sample from path
|
||||||
Import(usize, FileBrowser),
|
Import(usize, FileBrowser),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,9 @@ impl Sampler {
|
||||||
pub fn view_list <'a, T: NotePoint + NoteRange> (
|
pub fn view_list <'a, T: NotePoint + NoteRange> (
|
||||||
&'a self, compact: bool, editor: &T
|
&'a self, compact: bool, editor: &T
|
||||||
) -> impl Content<TuiOut> + 'a {
|
) -> impl Content<TuiOut> + 'a {
|
||||||
let note_lo = editor.note_lo().load(Relaxed);
|
let note_lo = editor.get_note_lo();
|
||||||
let note_pt = editor.note_pos();
|
let note_pt = editor.get_note_pos();
|
||||||
let note_hi = editor.note_hi();
|
let note_hi = editor.get_note_hi();
|
||||||
Fixed::x(12, Map::south(
|
Fixed::x(12, Map::south(
|
||||||
1,
|
1,
|
||||||
move||(note_lo..=note_hi).rev(),
|
move||(note_lo..=note_hi).rev(),
|
||||||
|
|
@ -80,6 +80,7 @@ impl Sampler {
|
||||||
Tui::fg_bg(fg, bg, format!("{note:3} {}", self.view_list_item(note, compact)))
|
Tui::fg_bg(fg, bg, format!("{note:3} {}", self.view_list_item(note, compact)))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_list_item (&self, note: usize, compact: bool) -> String {
|
pub fn view_list_item (&self, note: usize, compact: bool) -> String {
|
||||||
if compact {
|
if compact {
|
||||||
String::default()
|
String::default()
|
||||||
|
|
@ -87,6 +88,7 @@ impl Sampler {
|
||||||
draw_list_item(&self.mapped[note])
|
draw_list_item(&self.mapped[note])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_sample (&self, note_pt: usize) -> impl Content<TuiOut> + use<'_> {
|
pub fn view_sample (&self, note_pt: usize) -> impl Content<TuiOut> + use<'_> {
|
||||||
Outer(true, Style::default().fg(Tui::g(96))).enclose(draw_viewer(if let Some((_, sample)) = &self.recording {
|
Outer(true, Style::default().fg(Tui::g(96))).enclose(draw_viewer(if let Some((_, sample)) = &self.recording {
|
||||||
Some(sample)
|
Some(sample)
|
||||||
|
|
@ -96,6 +98,7 @@ impl Sampler {
|
||||||
None
|
None
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status (&self, index: usize) -> impl Content<TuiOut> {
|
pub fn status (&self, index: usize) -> impl Content<TuiOut> {
|
||||||
draw_status(self.mapped[index].as_ref())
|
draw_status(self.mapped[index].as_ref())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ pub trait MidiViewer: HasSize<TuiOut> + MidiRange + MidiPoint + Debug + Send + S
|
||||||
}
|
}
|
||||||
/// Make sure cursor is within note range
|
/// Make sure cursor is within note range
|
||||||
fn autoscroll (&self) {
|
fn autoscroll (&self) {
|
||||||
let note_pos = self.note_pos().min(127);
|
let note_pos = self.get_note_pos().min(127);
|
||||||
let note_lo = self.note_lo().get();
|
let note_lo = self.get_note_lo();
|
||||||
let note_hi = self.note_hi();
|
let note_hi = self.get_note_hi();
|
||||||
if note_pos < note_lo {
|
if note_pos < note_lo {
|
||||||
self.note_lo().set(note_pos);
|
self.note_lo().set(note_pos);
|
||||||
} else if note_pos > note_hi {
|
} else if note_pos > note_hi {
|
||||||
|
|
@ -23,9 +23,9 @@ pub trait MidiViewer: HasSize<TuiOut> + MidiRange + MidiPoint + Debug + Send + S
|
||||||
/// Make sure time range is within display
|
/// Make sure time range is within display
|
||||||
fn autozoom (&self) {
|
fn autozoom (&self) {
|
||||||
if self.time_lock().get() {
|
if self.time_lock().get() {
|
||||||
let time_len = self.time_len().get();
|
let time_len = self.get_time_len();
|
||||||
let time_axis = self.time_axis().get();
|
let time_axis = self.get_time_axis();
|
||||||
let time_zoom = self.time_zoom().get();
|
let time_zoom = self.get_time_zoom();
|
||||||
loop {
|
loop {
|
||||||
let time_zoom = self.time_zoom().get();
|
let time_zoom = self.time_zoom().get();
|
||||||
let time_area = time_axis * time_zoom;
|
let time_area = time_axis * time_zoom;
|
||||||
|
|
|
||||||
|
|
@ -20,53 +20,60 @@ impl Default for MidiPointModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait NotePoint {
|
|
||||||
/// Get the current length of the note cursor.
|
|
||||||
fn note_len (&self) -> usize;
|
|
||||||
/// Set the length of the note cursor, returning the previous value.
|
|
||||||
fn set_note_len (&self, x: usize) -> usize;
|
|
||||||
/// Get the current pitch of the note cursor.
|
|
||||||
fn note_pos (&self) -> usize;
|
|
||||||
/// Set the current pitch fo the note cursor, returning the previous value.
|
|
||||||
fn set_note_pos (&self, x: usize) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TimePoint {
|
|
||||||
/// Get the current time position of the note cursor.
|
|
||||||
fn time_pos (&self) -> usize;
|
|
||||||
/// Set the current time position of the note cursor, returning the previous value.
|
|
||||||
fn set_time_pos (&self, x: usize) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MidiPoint: NotePoint + TimePoint {
|
|
||||||
/// Get the current end of the note cursor.
|
|
||||||
fn note_end (&self) -> usize {
|
|
||||||
self.time_pos() + self.note_len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: NotePoint + TimePoint> MidiPoint for T {}
|
|
||||||
|
|
||||||
impl NotePoint for MidiPointModel {
|
impl NotePoint for MidiPointModel {
|
||||||
fn note_len (&self) -> usize {
|
fn note_len (&self) -> &AtomicUsize {
|
||||||
self.note_len.load(Relaxed)
|
&self.note_len
|
||||||
}
|
}
|
||||||
fn set_note_len (&self, x: usize) -> usize {
|
fn note_pos (&self) -> &AtomicUsize {
|
||||||
self.note_len.swap(x, Relaxed)
|
&self.note_pos
|
||||||
}
|
|
||||||
fn note_pos (&self) -> usize {
|
|
||||||
self.note_pos.load(Relaxed).min(127)
|
|
||||||
}
|
|
||||||
fn set_note_pos (&self, x: usize) -> usize {
|
|
||||||
self.note_pos.swap(x.min(127), Relaxed)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimePoint for MidiPointModel {
|
impl TimePoint for MidiPointModel {
|
||||||
fn time_pos (&self) -> usize {
|
fn time_pos (&self) -> &AtomicUsize {
|
||||||
self.time_pos.load(Relaxed)
|
self.time_pos.as_ref()
|
||||||
}
|
|
||||||
fn set_time_pos (&self, x: usize) -> usize {
|
|
||||||
self.time_pos.swap(x, Relaxed)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait NotePoint {
|
||||||
|
fn note_len (&self) -> &AtomicUsize;
|
||||||
|
/// Get the current length of the note cursor.
|
||||||
|
fn get_note_len (&self) -> usize {
|
||||||
|
self.note_len().load(Relaxed)
|
||||||
|
}
|
||||||
|
/// Set the length of the note cursor, returning the previous value.
|
||||||
|
fn set_note_len (&self, x: usize) -> usize {
|
||||||
|
self.note_len().swap(x, Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn note_pos (&self) -> &AtomicUsize;
|
||||||
|
/// Get the current pitch of the note cursor.
|
||||||
|
fn get_note_pos (&self) -> usize {
|
||||||
|
self.note_pos().load(Relaxed).min(127)
|
||||||
|
}
|
||||||
|
/// Set the current pitch fo the note cursor, returning the previous value.
|
||||||
|
fn set_note_pos (&self, x: usize) -> usize {
|
||||||
|
self.note_pos().swap(x.min(127), Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TimePoint {
|
||||||
|
fn time_pos (&self) -> &AtomicUsize;
|
||||||
|
/// Get the current time position of the note cursor.
|
||||||
|
fn get_time_pos (&self) -> usize {
|
||||||
|
self.time_pos().load(Relaxed)
|
||||||
|
}
|
||||||
|
/// Set the current time position of the note cursor, returning the previous value.
|
||||||
|
fn set_time_pos (&self, x: usize) -> usize {
|
||||||
|
self.time_pos().swap(x, Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MidiPoint: NotePoint + TimePoint {
|
||||||
|
/// Get the current end of the note cursor.
|
||||||
|
fn get_note_end (&self) -> usize {
|
||||||
|
self.get_time_pos() + self.get_note_len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NotePoint + TimePoint> MidiPoint for T {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MidiRangeModel {
|
pub struct MidiRangeModel {
|
||||||
|
|
@ -28,20 +29,53 @@ from!(|data:(usize, bool)|MidiRangeModel = Self {
|
||||||
});
|
});
|
||||||
|
|
||||||
pub trait TimeRange {
|
pub trait TimeRange {
|
||||||
fn time_len (&self) -> &AtomicUsize;
|
fn time_len (&self) -> &AtomicUsize;
|
||||||
fn time_zoom (&self) -> &AtomicUsize;
|
fn get_time_len (&self) -> usize {
|
||||||
fn time_lock (&self) -> &AtomicBool;
|
self.time_len().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn time_zoom (&self) -> &AtomicUsize;
|
||||||
|
fn get_time_zoom (&self) -> usize {
|
||||||
|
self.time_zoom().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn set_time_zoom (&self, value: usize) -> usize {
|
||||||
|
self.time_zoom().swap(value, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn time_lock (&self) -> &AtomicBool;
|
||||||
|
fn get_time_lock (&self) -> bool {
|
||||||
|
self.time_lock().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn set_time_lock (&self, value: bool) -> bool {
|
||||||
|
self.time_lock().swap(value, Ordering::Relaxed)
|
||||||
|
}
|
||||||
fn time_start (&self) -> &AtomicUsize;
|
fn time_start (&self) -> &AtomicUsize;
|
||||||
fn time_axis (&self) -> &AtomicUsize;
|
fn get_time_start (&self) -> usize {
|
||||||
fn time_end (&self) -> usize {
|
self.time_start().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn set_time_start (&self, value: usize) -> usize {
|
||||||
|
self.time_start().swap(value, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn time_axis (&self) -> &AtomicUsize;
|
||||||
|
fn get_time_axis (&self) -> usize {
|
||||||
|
self.time_axis().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn get_time_end (&self) -> usize {
|
||||||
self.time_start().get() + self.time_axis().get() * self.time_zoom().get()
|
self.time_start().get() + self.time_axis().get() * self.time_zoom().get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait NoteRange {
|
pub trait NoteRange {
|
||||||
fn note_lo (&self) -> &AtomicUsize;
|
fn note_lo (&self) -> &AtomicUsize;
|
||||||
fn note_axis (&self) -> &AtomicUsize;
|
fn get_note_lo (&self) -> usize {
|
||||||
fn note_hi (&self) -> usize {
|
self.note_lo().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn set_note_lo (&self, x: usize) -> usize {
|
||||||
|
self.note_lo().swap(x, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn note_axis (&self) -> &AtomicUsize;
|
||||||
|
fn get_note_axis (&self) -> usize {
|
||||||
|
self.note_axis().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn get_note_hi (&self) -> usize {
|
||||||
(self.note_lo().get() + self.note_axis().get().saturating_sub(1)).min(127)
|
(self.note_lo().get() + self.note_axis().get().saturating_sub(1)).min(127)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
deps/rust-jack
vendored
2
deps/rust-jack
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit caace9096c9df9c288b14a7c0ea1241d8da2baa1
|
Subproject commit 4cbf155d8ed222c140c11770474832ddfa52bcd7
|
||||||
2
deps/tengri
vendored
2
deps/tengri
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit b543c43e68154f049019da648064f36af1537434
|
Subproject commit 22d63eed9c9cb5bed5016d851f90773e0f60280d
|
||||||
0
tek.rs
0
tek.rs
Loading…
Add table
Add a link
Reference in a new issue