mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
add Justfile and tweak things
This commit is contained in:
parent
a017d2ca51
commit
f347ca838b
5 changed files with 95 additions and 86 deletions
6
Justfile
Normal file
6
Justfile
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
default:
|
||||||
|
just -l
|
||||||
|
status:
|
||||||
|
cargo c
|
||||||
|
cloc --by-file src/
|
||||||
|
git status
|
||||||
63
src/main.rs
63
src/main.rs
|
|
@ -17,40 +17,37 @@ use crate::{core::*, model::*};
|
||||||
|
|
||||||
/// Application entrypoint.
|
/// Application entrypoint.
|
||||||
pub fn main () -> Usually<()> {
|
pub fn main () -> Usually<()> {
|
||||||
run(App::from_edn(include_str!("../demos/project.edn"))?.activate(Some(|app: &Arc<RwLock<App>>| {
|
run(App::from_edn(include_str!("../demos/project.edn"))?
|
||||||
|
.activate(Some(|app: &Arc<RwLock<App>>|Ok({
|
||||||
let (midi_in, mut midi_outs) = {
|
let (midi_in, mut midi_outs) = {
|
||||||
let app = app.read().unwrap();
|
let app = app.read().unwrap();
|
||||||
let jack = app.jack.as_ref().unwrap();
|
let jack = app.jack.as_ref().unwrap();
|
||||||
let midi_in = jack.register_port("midi-in", MidiIn)?;
|
let midi_in = jack.register_port("midi-in", MidiIn)?;
|
||||||
let midi_outs = app.arranger.tracks.iter()
|
let midi_outs = app.arranger.tracks.iter()
|
||||||
.map(|t|Some(jack.register_port(&t.name, MidiOut).unwrap()))
|
.map(|t|Some(jack.register_port(&t.name, MidiOut).unwrap()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
(midi_in, midi_outs)
|
(midi_in, midi_outs)
|
||||||
};
|
};
|
||||||
|
{
|
||||||
{
|
let mut app = app.write().unwrap();
|
||||||
let mut app = app.write().unwrap();
|
let jack = app.jack.as_ref().unwrap();
|
||||||
let jack = app.jack.as_ref().unwrap();
|
for name in app.midi_ins.iter() {
|
||||||
for name in app.midi_ins.iter() {
|
let ports = jack.client().ports(Some(name), None, PortFlags::empty());
|
||||||
for port in jack.client().ports(Some(name), None, PortFlags::empty()).iter() {
|
for port in ports.iter() {
|
||||||
if let Some(port) = jack.client().port_by_name(port) {
|
if let Some(port) = jack.client().port_by_name(port) {
|
||||||
jack.client().connect_ports(&port, &midi_in)?;
|
jack.client().connect_ports(&port, &midi_in)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
app.midi_in = Some(Arc::new(midi_in));
|
||||||
app.midi_in = Some(Arc::new(midi_in));
|
for (index, track) in app.arranger.tracks.iter_mut().enumerate() {
|
||||||
for (index, track) in app.arranger.tracks.iter_mut().enumerate() {
|
track.midi_out = midi_outs[index].take();
|
||||||
track.midi_out = midi_outs[index].take();
|
}
|
||||||
}
|
for track in app.arranger.tracks.iter() {
|
||||||
for track in app.arranger.tracks.iter() {
|
track.connect_first_device()?;
|
||||||
track.connect_first_device()?;
|
track.connect_last_device(&app)?;
|
||||||
track.connect_last_device(&app)?;
|
}
|
||||||
}
|
};
|
||||||
}
|
})))?)?;
|
||||||
|
|
||||||
Ok(())
|
|
||||||
|
|
||||||
}))?)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
89
src/model.rs
89
src/model.rs
|
|
@ -6,41 +6,42 @@ use crate::{core::*, view::*};
|
||||||
|
|
||||||
/// Root of application state.
|
/// Root of application state.
|
||||||
pub struct App {
|
pub struct App {
|
||||||
|
/// Optional modal dialog
|
||||||
|
pub modal: Option<Box<dyn Exit>>,
|
||||||
|
/// Whether the currently focused section has input priority
|
||||||
|
pub entered: bool,
|
||||||
|
/// Currently focused section
|
||||||
|
pub section: AppFocus,
|
||||||
|
/// Transport model and view.
|
||||||
|
pub transport: TransportToolbar,
|
||||||
|
/// Arraneger model and view.
|
||||||
|
pub arranger: Arranger,
|
||||||
/// Main JACK client.
|
/// Main JACK client.
|
||||||
pub jack: Option<JackClient>,
|
pub jack: Option<JackClient>,
|
||||||
/// Map of external MIDI outs in the jack graph
|
/// Map of external MIDI outs in the jack graph
|
||||||
/// to internal MIDI ins of this app.
|
/// to internal MIDI ins of this app.
|
||||||
pub midi_in: Option<Arc<Port<MidiIn>>>,
|
pub midi_in: Option<Arc<Port<MidiIn>>>,
|
||||||
/// Names of ports to connect to main MIDI IN.
|
/// Names of ports to connect to main MIDI IN.
|
||||||
pub midi_ins: Vec<String>,
|
pub midi_ins: Vec<String>,
|
||||||
/// Display mode of chain section
|
/// Display mode of chain section
|
||||||
pub chain_mode: bool,
|
pub chain_mode: bool,
|
||||||
/// Display mode of sequencer seciton
|
|
||||||
pub seq_mode: bool,
|
|
||||||
/// Display buffer for sequencer
|
|
||||||
pub seq_buf: BufferedSequencerView,
|
|
||||||
/// Optional modal dialog
|
|
||||||
pub modal: Option<Box<dyn Exit>>,
|
|
||||||
/// Display position of cursor within note range
|
|
||||||
pub note_cursor: usize,
|
|
||||||
/// Range of notes to display
|
|
||||||
pub note_start: usize,
|
|
||||||
/// Display position of cursor within time range
|
|
||||||
pub time_cursor: usize,
|
|
||||||
/// Paths to user directories
|
/// Paths to user directories
|
||||||
xdg: Option<Arc<XdgApp>>,
|
xdg: Option<Arc<XdgApp>>,
|
||||||
/// Main audio outputs.
|
/// Main audio outputs.
|
||||||
pub audio_outs: Vec<Arc<Port<Unowned>>>,
|
pub audio_outs: Vec<Arc<Port<Unowned>>>,
|
||||||
/// Number of frames requested by process callback
|
/// Number of frames requested by process callback
|
||||||
chunk_size: usize,
|
chunk_size: usize,
|
||||||
/// Transport model and view.
|
|
||||||
pub transport: TransportToolbar,
|
/// Display mode of sequencer seciton
|
||||||
/// Arraneger model and view.
|
pub seq_mode: bool,
|
||||||
pub arranger: Arranger,
|
/// Display buffer for sequencer
|
||||||
/// Currently focused section
|
pub seq_buf: BufferedSequencerView,
|
||||||
pub section: AppFocus,
|
/// Display position of cursor within note range
|
||||||
/// Whether the current focus section has input priority
|
pub note_cursor: usize,
|
||||||
pub entered: bool,
|
/// Range of notes to display
|
||||||
|
pub note_start: usize,
|
||||||
|
/// Display position of cursor within time range
|
||||||
|
pub time_cursor: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
|
@ -49,25 +50,27 @@ impl App {
|
||||||
let first_run = crate::config::AppPaths::new(&xdg)?.should_create();
|
let first_run = crate::config::AppPaths::new(&xdg)?.should_create();
|
||||||
let jack = JackClient::Inactive(Client::new("tek", ClientOptions::NO_START_SERVER)?.0);
|
let jack = JackClient::Inactive(Client::new("tek", ClientOptions::NO_START_SERVER)?.0);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
transport: TransportToolbar::new(Some(jack.transport())),
|
modal: first_run.then(||{
|
||||||
arranger: Arranger::new(),
|
Exit::boxed(crate::config::SetupModal(Some(xdg.clone()), false))
|
||||||
|
}),
|
||||||
|
|
||||||
|
entered: true,
|
||||||
|
section: AppFocus::default(),
|
||||||
|
transport: TransportToolbar::new(Some(jack.transport())),
|
||||||
|
arranger: Arranger::new(),
|
||||||
|
jack: Some(jack),
|
||||||
audio_outs: vec![],
|
audio_outs: vec![],
|
||||||
chain_mode: false,
|
chain_mode: false,
|
||||||
chunk_size: 0,
|
chunk_size: 0,
|
||||||
entered: true,
|
midi_in: None,
|
||||||
jack: Some(jack),
|
midi_ins: vec![],
|
||||||
midi_in: None,
|
xdg: Some(xdg),
|
||||||
midi_ins: vec![],
|
|
||||||
|
seq_mode: false,
|
||||||
|
seq_buf: BufferedSequencerView::new(96, 16384),
|
||||||
note_cursor: 0,
|
note_cursor: 0,
|
||||||
note_start: 2,
|
note_start: 2,
|
||||||
section: AppFocus::default(),
|
|
||||||
seq_mode: false,
|
|
||||||
seq_buf: BufferedSequencerView::new(96, 16384),
|
|
||||||
time_cursor: 0,
|
time_cursor: 0,
|
||||||
modal: first_run.then(
|
|
||||||
||Exit::boxed(crate::config::SetupModal(Some(xdg.clone()), false))
|
|
||||||
),
|
|
||||||
xdg: Some(xdg),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,9 +136,13 @@ impl App {
|
||||||
/// Different sections of the UI that may be focused.
|
/// Different sections of the UI that may be focused.
|
||||||
#[derive(PartialEq, Clone, Copy)]
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
pub enum AppFocus {
|
pub enum AppFocus {
|
||||||
|
/// The transport is selected.
|
||||||
Transport,
|
Transport,
|
||||||
|
/// The arranger is selected.
|
||||||
Arranger,
|
Arranger,
|
||||||
|
/// The sequencer is selected.
|
||||||
Sequencer,
|
Sequencer,
|
||||||
|
/// The device chain is selected.
|
||||||
Chain,
|
Chain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@ pub struct Track {
|
||||||
/// Device selector
|
/// Device selector
|
||||||
pub device: usize,
|
pub device: usize,
|
||||||
/// Send all notes off
|
/// Send all notes off
|
||||||
/// FIXME: Some(nframes)?
|
pub reset: bool, // TODO?: after Some(nframes)
|
||||||
pub reset: bool,
|
|
||||||
/// Highlight keys on piano roll.
|
/// Highlight keys on piano roll.
|
||||||
pub notes_in: [bool;128],
|
pub notes_in: [bool;128],
|
||||||
/// Highlight keys on piano roll.
|
/// Highlight keys on piano roll.
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::{core::*,view::*,model::*};
|
use crate::{core::*,view::*,model::*};
|
||||||
|
|
||||||
render!(TransportToolbar |self, buf, area| {
|
render!(TransportToolbar |self, buf, area| {
|
||||||
|
let mut area = area;
|
||||||
|
area.height = 2;
|
||||||
let gray = Style::default().gray();
|
let gray = Style::default().gray();
|
||||||
let not_dim = Style::default().not_dim();
|
let not_dim = Style::default().not_dim();
|
||||||
let not_dim_bold = not_dim.bold();
|
let not_dim_bold = not_dim.bold();
|
||||||
|
let corners = Corners(Style::default().green().not_dim());
|
||||||
let mut area = area;
|
let ppq = self.ppq();
|
||||||
area.height = 2;
|
let bpm = self.bpm();
|
||||||
let ppq = self.ppq();
|
let pulse = self.pulse();
|
||||||
let bpm = self.bpm();
|
let usecs = self.usecs();
|
||||||
let pulse = self.pulse();
|
|
||||||
let usecs = self.usecs();
|
|
||||||
let Self { quant, sync, focused, entered, .. } = self;
|
let Self { quant, sync, focused, entered, .. } = self;
|
||||||
fill_bg(buf, area, Nord::bg_lo(*focused, *entered));
|
fill_bg(buf, area, Nord::bg_lo(*focused, *entered));
|
||||||
Split::right([
|
Split::right([
|
||||||
|
|
@ -40,7 +40,7 @@ render!(TransportToolbar |self, buf, area| {
|
||||||
let width = format!("{}.{:03}", bpm, bpm % 1).blit(buf, x, y + 1, Some(not_dim_bold))?.width;
|
let width = format!("{}.{:03}", bpm, bpm % 1).blit(buf, x, y + 1, Some(not_dim_bold))?.width;
|
||||||
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
||||||
if self.focused && self.entered && self.selected == TransportFocus::BPM {
|
if self.focused && self.entered && self.selected == TransportFocus::BPM {
|
||||||
Corners(Style::default().green().not_dim()).draw(buf, Rect { x: area.x - 1, ..area })?;
|
corners.draw(buf, Rect { x: area.x - 1, ..area })?;
|
||||||
}
|
}
|
||||||
Ok(area)
|
Ok(area)
|
||||||
},
|
},
|
||||||
|
|
@ -51,7 +51,7 @@ render!(TransportToolbar |self, buf, area| {
|
||||||
let width = ppq_to_name(*quant).blit(buf, x, y + 1, Some(not_dim_bold))?.width;
|
let width = ppq_to_name(*quant).blit(buf, x, y + 1, Some(not_dim_bold))?.width;
|
||||||
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
||||||
if self.focused && self.entered && self.selected == TransportFocus::Quant {
|
if self.focused && self.entered && self.selected == TransportFocus::Quant {
|
||||||
Corners(Style::default().green().not_dim()).draw(buf, Rect { x: area.x - 1, ..area })?;
|
corners.draw(buf, Rect { x: area.x - 1, ..area })?;
|
||||||
}
|
}
|
||||||
Ok(area)
|
Ok(area)
|
||||||
},
|
},
|
||||||
|
|
@ -62,7 +62,7 @@ render!(TransportToolbar |self, buf, area| {
|
||||||
let width = ppq_to_name(*sync).blit(buf, x, y + 1, Some(not_dim_bold))?.width;
|
let width = ppq_to_name(*sync).blit(buf, x, y + 1, Some(not_dim_bold))?.width;
|
||||||
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
||||||
if self.focused && self.entered && self.selected == TransportFocus::Sync {
|
if self.focused && self.entered && self.selected == TransportFocus::Sync {
|
||||||
Corners(Style::default().green().not_dim()).draw(buf, Rect { x: area.x - 1, ..area })?;
|
corners.draw(buf, Rect { x: area.x - 1, ..area })?;
|
||||||
}
|
}
|
||||||
Ok(area)
|
Ok(area)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue