mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 20:26:42 +01:00
242 lines
7.5 KiB
Rust
242 lines
7.5 KiB
Rust
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::{*, jack::*};
|
|
pub(crate) use tek_api::*;
|
|
|
|
pub(crate) use std::collections::BTreeMap;
|
|
pub(crate) use std::sync::{Arc, Mutex, RwLock};
|
|
pub(crate) use std::path::PathBuf;
|
|
pub(crate) use std::ffi::OsString;
|
|
pub(crate) use std::fs::read_dir;
|
|
|
|
submod! {
|
|
tui_focus
|
|
tui_menu
|
|
tui_status
|
|
|
|
tui_app_arranger
|
|
tui_app_sequencer
|
|
tui_app_transport
|
|
|
|
tui_jack_transport
|
|
tui_jack_sequencer
|
|
tui_jack_arranger
|
|
|
|
tui_control_arranger
|
|
tui_control_file_browser
|
|
tui_control_phrase_editor
|
|
tui_control_phrase_length
|
|
tui_control_phrase_list
|
|
tui_control_phrase_rename
|
|
tui_control_sequencer
|
|
tui_control_transport
|
|
|
|
tui_model_arranger
|
|
tui_model_clock
|
|
tui_model_file_browser
|
|
tui_model_phrase_editor
|
|
tui_model_phrase_length
|
|
tui_model_phrase_list
|
|
tui_model_phrase_player
|
|
|
|
tui_view_arranger
|
|
tui_view_file_browser
|
|
tui_view_phrase_editor
|
|
tui_view_phrase_length
|
|
tui_view_phrase_list
|
|
tui_view_sequencer
|
|
tui_view_transport
|
|
}
|
|
|
|
pub fn to_focus_command (input: &TuiInput) -> Option<FocusCommand> {
|
|
use KeyCode::{Tab, BackTab, Up, Down, Left, Right, Enter, Esc};
|
|
Some(match input.event() {
|
|
key!(Tab) => FocusCommand::Next,
|
|
key!(Shift-Tab) => FocusCommand::Prev,
|
|
key!(BackTab) => FocusCommand::Prev,
|
|
key!(Shift-BackTab) => FocusCommand::Prev,
|
|
key!(Up) => FocusCommand::Up,
|
|
key!(Down) => FocusCommand::Down,
|
|
key!(Left) => FocusCommand::Left,
|
|
key!(Right) => FocusCommand::Right,
|
|
key!(Enter) => FocusCommand::Enter,
|
|
key!(Esc) => FocusCommand::Exit,
|
|
_ => return None
|
|
})
|
|
}
|
|
|
|
pub struct TuiTheme;
|
|
|
|
impl TuiTheme {
|
|
pub fn border_bg () -> Color {
|
|
Color::Rgb(40, 50, 30)
|
|
}
|
|
pub fn border_fg (focused: bool) -> Color {
|
|
if focused { Color::Rgb(100, 110, 40) } else { Color::Rgb(70, 80, 50) }
|
|
}
|
|
pub fn title_fg (focused: bool) -> Color {
|
|
if focused { Color::Rgb(150, 160, 90) } else { Color::Rgb(120, 130, 100) }
|
|
}
|
|
pub fn separator_fg (_: bool) -> Color {
|
|
Color::Rgb(0, 0, 0)
|
|
}
|
|
pub const fn hotkey_fg () -> Color {
|
|
Color::Rgb(255, 255, 0)
|
|
}
|
|
pub fn mode_bg () -> Color {
|
|
Color::Rgb(150, 160, 90)
|
|
}
|
|
pub fn mode_fg () -> Color {
|
|
Color::Rgb(255, 255, 255)
|
|
}
|
|
pub fn status_bar_bg () -> Color {
|
|
Color::Rgb(28, 35, 25)
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_clock_api {
|
|
($Struct:ident $(:: $field:ident)*) => {
|
|
impl ClockApi for $Struct {
|
|
fn quant (&self) -> &Arc<Quantize> {
|
|
&self$(.$field)*.quant
|
|
}
|
|
fn sync (&self) -> &Arc<LaunchSync> {
|
|
&self$(.$field)*.sync
|
|
}
|
|
fn current (&self) -> &Arc<Instant> {
|
|
&self$(.$field)*.current
|
|
}
|
|
fn transport_handle (&self) -> &Arc<Transport> {
|
|
&self$(.$field)*.transport
|
|
}
|
|
fn transport_state (&self) -> &Arc<RwLock<Option<TransportState>>> {
|
|
&self$(.$field)*.playing
|
|
}
|
|
fn transport_offset (&self) -> &Arc<RwLock<Option<(usize, usize)>>> {
|
|
&self$(.$field)*.started
|
|
}
|
|
}
|
|
}
|
|
}
|
|
macro_rules! impl_midi_player {
|
|
($Struct:ident $(:: $field:ident)*) => {
|
|
impl HasPhrase for $Struct {
|
|
fn reset (&self) -> bool {
|
|
self$(.$field)*.reset
|
|
}
|
|
fn reset_mut (&mut self) -> &mut bool {
|
|
&mut self$(.$field)*.reset
|
|
}
|
|
fn play_phrase (&self) -> &Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
|
|
&self$(.$field)*.play_phrase
|
|
}
|
|
fn play_phrase_mut (&mut self) -> &mut Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
|
|
&mut self$(.$field)*.play_phrase
|
|
}
|
|
fn next_phrase (&self) -> &Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
|
|
&self$(.$field)*.next_phrase
|
|
}
|
|
fn next_phrase_mut (&mut self) -> &mut Option<(Instant, Option<Arc<RwLock<Phrase>>>)> {
|
|
&mut self$(.$field)*.next_phrase
|
|
}
|
|
}
|
|
impl MidiInputApi for $Struct {
|
|
fn midi_ins (&self) -> &Vec<Port<jack::MidiIn>> {
|
|
&self$(.$field)*.midi_ins
|
|
}
|
|
fn midi_ins_mut (&mut self) -> &mut Vec<Port<jack::MidiIn>> {
|
|
&mut self$(.$field)*.midi_ins
|
|
}
|
|
fn recording (&self) -> bool {
|
|
self$(.$field)*.recording
|
|
}
|
|
fn recording_mut (&mut self) -> &mut bool {
|
|
&mut self$(.$field)*.recording
|
|
}
|
|
fn monitoring (&self) -> bool {
|
|
self$(.$field)*.monitoring
|
|
}
|
|
fn monitoring_mut (&mut self) -> &mut bool {
|
|
&mut self$(.$field)*.monitoring
|
|
}
|
|
fn overdub (&self) -> bool {
|
|
self$(.$field)*.overdub
|
|
}
|
|
fn overdub_mut (&mut self) -> &mut bool {
|
|
&mut self$(.$field)*.overdub
|
|
}
|
|
fn notes_in (&self) -> &Arc<RwLock<[bool; 128]>> {
|
|
&self$(.$field)*.notes_in
|
|
}
|
|
}
|
|
impl MidiOutputApi for $Struct {
|
|
fn midi_outs (&self) -> &Vec<Port<jack::MidiOut>> {
|
|
&self$(.$field)*.midi_outs
|
|
}
|
|
fn midi_outs_mut (&mut self) -> &mut Vec<Port<jack::MidiOut>> {
|
|
&mut self$(.$field)*.midi_outs
|
|
}
|
|
fn midi_note (&mut self) -> &mut Vec<u8> {
|
|
&mut self$(.$field)*.note_buf
|
|
}
|
|
fn notes_out (&self) -> &Arc<RwLock<[bool; 128]>> {
|
|
&self$(.$field)*.notes_in
|
|
}
|
|
}
|
|
impl MidiPlayerApi for $Struct {}
|
|
}
|
|
}
|
|
|
|
impl_clock_api!(TransportTui::clock);
|
|
impl_clock_api!(SequencerTui::clock);
|
|
impl_clock_api!(ArrangerTui::clock);
|
|
impl_clock_api!(PhrasePlayerModel::clock);
|
|
impl_clock_api!(ArrangerTrack::player::clock);
|
|
|
|
impl_midi_player!(SequencerTui::player);
|
|
impl_midi_player!(ArrangerTrack::player);
|
|
impl_midi_player!(PhrasePlayerModel);
|
|
|
|
use std::fmt::{Debug, Formatter, Error};
|
|
type DebugResult = std::result::Result<(), Error>;
|
|
|
|
impl Debug for ClockModel {
|
|
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
|
|
f.debug_struct("editor")
|
|
.field("playing", &self.playing)
|
|
.field("started", &self.started)
|
|
.field("current", &self.current)
|
|
.field("quant", &self.quant)
|
|
.field("sync", &self.sync)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl Debug for TransportTui {
|
|
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
|
|
f.debug_struct("Measure")
|
|
.field("jack", &self.jack)
|
|
.field("size", &self.size)
|
|
.field("cursor", &self.cursor)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl Debug for PhraseEditorModel {
|
|
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
|
|
f.debug_struct("editor")
|
|
.field("note_axis", &self.time_axis)
|
|
.field("time_axis", &self.note_axis)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl Debug for PhrasePlayerModel {
|
|
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
|
|
f.debug_struct("editor")
|
|
.field("clock", &self.clock)
|
|
.field("play_phrase", &self.play_phrase)
|
|
.field("next_phrase", &self.next_phrase)
|
|
.finish()
|
|
}
|
|
}
|