mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
add --bpm flag
This commit is contained in:
parent
42e2ef2a50
commit
94491a323a
11 changed files with 78 additions and 57 deletions
|
|
@ -38,15 +38,6 @@ render!(Tui: (self: TransportView<'a>) => Outer(
|
|||
OutputStats::new(self.compact, self.clock),
|
||||
)));
|
||||
|
||||
struct Field<'a>(ItemPalette, &'a str, &'a str);
|
||||
render!(Tui: (self: Field<'a>) => row!(
|
||||
Tui::bg(self.0.darkest.rgb, Tui::fg(self.0.darker.rgb, "▐")),
|
||||
Tui::bg(self.0.darker.rgb, Tui::fg(self.0.lighter.rgb,
|
||||
Tui::bold(true, format!("{}", self.1)))),
|
||||
Tui::bg(self.0.darkest.rgb, Tui::fg(self.0.darker.rgb, "▌")),
|
||||
Tui::bg(self.0.darkest.rgb, Tui::fg(self.0.lightest.rgb,
|
||||
Tui::bold(true, format!("{} ", self.2))))));
|
||||
|
||||
pub struct PlayPause { pub compact: bool, pub playing: bool }
|
||||
render!(Tui: (self: PlayPause) => Tui::bg(
|
||||
if self.playing{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)},
|
||||
|
|
|
|||
22
src/field.rs
Normal file
22
src/field.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct Field<T, U>(pub ItemPalette, pub T, pub U)
|
||||
where T: AsRef<str> + Send + Sync, U: AsRef<str> + Send + Sync;
|
||||
|
||||
impl<T, U> Content<Tui> for Field<T, U>
|
||||
where T: AsRef<str> + Send + Sync, U: AsRef<str> + Send + Sync
|
||||
{
|
||||
fn content (&self) -> impl Content<Tui> {
|
||||
row!(
|
||||
Tui::bg(self.0.darkest.rgb, Tui::fg(self.0.darker.rgb, "▐")),
|
||||
|
||||
Tui::bg(self.0.darker.rgb, Tui::fg(self.0.lighter.rgb,
|
||||
Tui::bold(true, format!("{}", self.1.as_ref())))),
|
||||
|
||||
Tui::bg(self.0.darkest.rgb, Tui::fg(self.0.darker.rgb, "▌")),
|
||||
|
||||
Tui::bg(self.0.darkest.rgb, Tui::fg(self.0.lightest.rgb,
|
||||
format!("{} ", self.2.as_ref())))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -131,20 +131,16 @@ render!(Tui: (self: Groovebox) => {
|
|||
})),
|
||||
),
|
||||
Bsp::n(
|
||||
Bsp::e(
|
||||
Fixed::y(1, SamplerStatus(&self.sampler, note_pt)),
|
||||
MidiEditStatus(&self.editor),
|
||||
lay!(
|
||||
Align::w(Fixed::y(1, SamplerStatus(&self.sampler, note_pt))),
|
||||
Align::x(Fixed::y(1, MidiEditStatus(&self.editor))),
|
||||
),
|
||||
Bsp::w(
|
||||
Fixed::x(pool_w, Align::e(Fill::y(PoolView(&self.pool)))),
|
||||
Fill::xy(Bsp::e(
|
||||
Fixed::x(sampler_w, sampler),
|
||||
Bsp::s(
|
||||
selector,
|
||||
&self.editor,
|
||||
),
|
||||
),
|
||||
)
|
||||
Fixed::x(sampler_w, Push::y(3, sampler)),
|
||||
Bsp::s(selector, &self.editor),
|
||||
)),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ pub mod border; pub use self::border::*;
|
|||
pub mod clock; pub use self::clock::*;
|
||||
pub mod color; pub use self::color::*;
|
||||
pub mod command; pub use self::command::*;
|
||||
pub mod field; pub use self::field::*;
|
||||
pub mod file; pub use self::file::*;
|
||||
pub mod focus; pub use self::focus::*;
|
||||
pub mod groovebox; pub use self::groovebox::*;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ pub(crate) mod midi_point; pub(crate) use midi_point::*;
|
|||
pub(crate) mod midi_view; pub(crate) use midi_view::*;
|
||||
|
||||
pub(crate) mod midi_editor; pub(crate) use midi_editor::*;
|
||||
pub(crate) mod midi_status; pub(crate) use midi_status::*;
|
||||
|
||||
/// Add "all notes off" to the start of a buffer.
|
||||
pub fn all_notes_off (output: &mut [Vec<Vec<u8>>]) {
|
||||
|
|
|
|||
25
src/midi/midi_status.rs
Normal file
25
src/midi/midi_status.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct MidiEditStatus<'a>(pub &'a MidiEditor);
|
||||
render!(Tui: (self: MidiEditStatus<'a>) => {
|
||||
let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
||||
} else {
|
||||
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false)
|
||||
};
|
||||
let time_point = self.0.time_point();
|
||||
let time_start = self.0.time_start();
|
||||
let time_end = self.0.time_end();
|
||||
let time_axis = self.0.time_axis().get();
|
||||
let time_zoom = self.0.time_zoom().get();
|
||||
let time_lock = if self.0.time_lock().get() { "[lock]" } else { " " };
|
||||
let time_field = Field(color, "Time", format!("{length}/{time_zoom}+{time_point} {time_lock}"));
|
||||
|
||||
Tui::bg(color.darkest.rgb, Fill::x(Tui::fg(color.lightest.rgb, Bsp::e(
|
||||
time_field,
|
||||
Field(color, "Note", format!("{} ({}) {} | {}-{} ({})",
|
||||
self.0.note_point(), Note::pitch_to_name(self.0.note_point()), self.0.note_len(),
|
||||
Note::pitch_to_name(self.0.note_lo().get()), Note::pitch_to_name(self.0.note_hi()),
|
||||
self.0.note_axis().get()))
|
||||
))))
|
||||
});
|
||||
|
|
@ -7,14 +7,8 @@ pub struct PhraseSelector {
|
|||
pub(crate) time: String,
|
||||
}
|
||||
|
||||
// TODO: Display phrases always in order of appearance
|
||||
render!(Tui: (self: PhraseSelector) => Fixed::xy(24, 1, row!(
|
||||
Tui::fg(self.color.lightest.rgb, Tui::bold(true, &self.title)),
|
||||
Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!(
|
||||
format!("{:8}", &self.name[0..8.min(self.name.len())]),
|
||||
Tui::bg(self.color.dark.rgb, &self.time),
|
||||
)),
|
||||
)));
|
||||
render!(Tui: (self: PhraseSelector) =>
|
||||
Field(self.color, self.title, format!("{} {}", self.time, self.name)));
|
||||
|
||||
impl PhraseSelector {
|
||||
|
||||
|
|
@ -31,7 +25,7 @@ impl PhraseSelector {
|
|||
} else {
|
||||
String::from(" ")
|
||||
};
|
||||
Self { title: "Now:|", time, name, color, }
|
||||
Self { title: "Now", time, name, color, }
|
||||
}
|
||||
|
||||
// beats until switchover
|
||||
|
|
@ -59,7 +53,7 @@ impl PhraseSelector {
|
|||
} else {
|
||||
(" ".into(), " ".into(), TuiTheme::g(64).into())
|
||||
};
|
||||
Self { title: " Next|", time, name, color, }
|
||||
Self { title: "Next", time, name, color, }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,6 +181,9 @@ impl Sampler {
|
|||
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||
}
|
||||
},
|
||||
MidiMessage::Controller { controller, value } => {
|
||||
// TODO
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,5 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct MidiEditStatus<'a>(pub &'a MidiEditor);
|
||||
render!(Tui: (self:MidiEditStatus<'a>) => {
|
||||
let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
||||
} else {
|
||||
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false)
|
||||
};
|
||||
let field = move|x, y|row!(
|
||||
Tui::fg_bg(color.lighter.rgb, color.darker.rgb, Tui::bold(true, x)),
|
||||
Tui::fg_bg(color.light.rgb, color.darker.rgb, Tui::bold(true, "│")),
|
||||
Tui::fg_bg(color.lightest.rgb, color.dark.rgb, y),
|
||||
);
|
||||
let bg = color.darkest.rgb;
|
||||
let fg = color.lightest.rgb;
|
||||
Tui::bg(bg, Fill::x(Tui::fg(fg, row!(
|
||||
field(" Time", format!("{}/{}-{} ({}*{}) {}",
|
||||
self.0.time_point(), self.0.time_start().get(), self.0.time_end(),
|
||||
self.0.time_axis().get(), self.0.time_zoom().get(),
|
||||
if self.0.time_lock().get() { "[lock]" } else { " " })),
|
||||
" ",
|
||||
field(" Note", format!("{} ({}) {} | {}-{} ({})",
|
||||
self.0.note_point(), Note::pitch_to_name(self.0.note_point()), self.0.note_len(),
|
||||
Note::pitch_to_name(self.0.note_lo().get()), Note::pitch_to_name(self.0.note_hi()),
|
||||
self.0.note_axis().get()))
|
||||
))))
|
||||
});
|
||||
|
||||
/// Status bar for sequencer app
|
||||
#[derive(Clone)]
|
||||
pub struct SequencerStatus {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue