mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 04:36:45 +01:00
wip: ArrangerStandalone
This commit is contained in:
parent
1104093395
commit
3cbb2d2e0b
19 changed files with 165 additions and 231 deletions
|
|
@ -6,7 +6,7 @@ pub mod bound;
|
||||||
pub struct Host(*mut self::bound::SuilHost);
|
pub struct Host(*mut self::bound::SuilHost);
|
||||||
|
|
||||||
impl Drop for Host {
|
impl Drop for Host {
|
||||||
fn drop (&mut self) -> () {
|
fn drop (&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
bound::suil_host_free(self.0)
|
bound::suil_host_free(self.0)
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +75,6 @@ unsafe extern "C" fn write (
|
||||||
unsafe extern "C" fn index (
|
unsafe extern "C" fn index (
|
||||||
_controller: *mut c_void, _: *const i8
|
_controller: *mut c_void, _: *const i8
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
panic!("index");
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,19 +97,19 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
render!(App |self, buf, area| {
|
render!(App |self, buf, area| {
|
||||||
Split::down([
|
Split::down()
|
||||||
&self.transport,
|
.add_ref(&self.transport)
|
||||||
&self.arranger,
|
.add_ref(&self.arranger)
|
||||||
&If(self.arranger.selected.is_clip(), &Split::right([
|
.add(If(self.arranger.selected.is_clip(), &Split::right()
|
||||||
&tek_mixer::TrackView {
|
.add(tek_mixer::TrackView {
|
||||||
direction: Direction::Down,
|
direction: Direction::Down,
|
||||||
entered: self.entered,
|
entered: self.entered,
|
||||||
focused: self.section == AppFocus::Chain,
|
focused: self.section == AppFocus::Chain,
|
||||||
chain: self.mixer.track()
|
chain: self.mixer.track()
|
||||||
},
|
})
|
||||||
&self.arranger.sequencer(),
|
.add_ref(&self.arranger.sequencer())
|
||||||
]))
|
))
|
||||||
]).render(buf, area)?;
|
.render(buf, area)?;
|
||||||
if let Some(ref modal) = *MODAL.lock().unwrap() {
|
if let Some(ref modal) = *MODAL.lock().unwrap() {
|
||||||
modal.render(buf, area)?;
|
modal.render(buf, area)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use crate::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs::{File, create_dir_all};
|
use std::fs::{File, create_dir_all};
|
||||||
|
|
||||||
const CONFIG_FILE_NAME: &'static str = "tek.toml";
|
const CONFIG_FILE_NAME: &str = "tek.toml";
|
||||||
const PROJECT_FILE_NAME: &'static str = "project.toml";
|
const PROJECT_FILE_NAME: &str = "project.toml";
|
||||||
|
|
||||||
/// Filesystem locations of things.
|
/// Filesystem locations of things.
|
||||||
pub struct AppPaths {
|
pub struct AppPaths {
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,8 @@ pub trait Process {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just run thing with JACK. Returns the activated client.
|
/// Just run thing with JACK. Returns the activated client.
|
||||||
pub fn jack_run <T: Sync> (name: &str, app: &Arc<RwLock<T>>) -> Usually<DynamicAsyncClient>
|
pub fn jack_run <T> (name: &str, app: &Arc<RwLock<T>>) -> Usually<DynamicAsyncClient>
|
||||||
where T: Handle + Process + Send + 'static
|
where T: Handle + Process + Send + Sync + 'static
|
||||||
{
|
{
|
||||||
let options = ClientOptions::NO_START_SERVER;
|
let options = ClientOptions::NO_START_SERVER;
|
||||||
let (client, _status) = Client::new(name, options)?;
|
let (client, _status) = Client::new(name, options)?;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{*, jack::*};
|
use crate::jack::*;
|
||||||
|
|
||||||
/// Notification handler used by the [Jack] factory
|
/// Notification handler used by the [Jack] factory
|
||||||
/// when constructing [JackDevice]s.
|
/// when constructing [JackDevice]s.
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,16 @@ impl JackPorts {
|
||||||
|
|
||||||
/// Trait for things that may expose JACK ports.
|
/// Trait for things that may expose JACK ports.
|
||||||
pub trait Ports {
|
pub trait Ports {
|
||||||
fn audio_ins <'a> (&'a self) -> Usually<Vec<&'a Port<Unowned>>> {
|
fn audio_ins (&self) -> Usually<Vec<&Port<Unowned>>> {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
fn audio_outs <'a> (&'a self) -> Usually<Vec<&'a Port<Unowned>>> {
|
fn audio_outs (&self) -> Usually<Vec<&Port<Unowned>>> {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
fn midi_ins <'a> (&'a self) -> Usually<Vec<&'a Port<Unowned>>> {
|
fn midi_ins (&self) -> Usually<Vec<&Port<Unowned>>> {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
fn midi_outs <'a> (&'a self) -> Usually<Vec<&'a Port<Unowned>>> {
|
fn midi_outs (&self) -> Usually<Vec<&Port<Unowned>>> {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ pub(crate) use ratatui::buffer::{Buffer, Cell};
|
||||||
/// Main thread render loop
|
/// Main thread render loop
|
||||||
pub fn render_thread (
|
pub fn render_thread (
|
||||||
exited: &Arc<AtomicBool>,
|
exited: &Arc<AtomicBool>,
|
||||||
device: &Arc<RwLock<impl Render + Send + Sync + 'static>>
|
device: &Arc<RwLock<impl Render + 'static>>
|
||||||
) -> Usually<JoinHandle<()>> {
|
) -> Usually<JoinHandle<()>> {
|
||||||
let exited = exited.clone();
|
let exited = exited.clone();
|
||||||
let device = device.clone();
|
let device = device.clone();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::*;
|
||||||
macro_rules! impl_axis_common { ($A:ident $T:ty) => {
|
macro_rules! impl_axis_common { ($A:ident $T:ty) => {
|
||||||
impl $A<$T> {
|
impl $A<$T> {
|
||||||
pub fn start_inc (&mut self) -> $T {
|
pub fn start_inc (&mut self) -> $T {
|
||||||
self.start = self.start + 1;
|
self.start += 1;
|
||||||
self.start
|
self.start
|
||||||
}
|
}
|
||||||
pub fn start_dec (&mut self) -> $T {
|
pub fn start_dec (&mut self) -> $T {
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,11 @@ impl<'a> Split<'a> {
|
||||||
let result = item.render(buf, Rect { x, y, width, height })?;
|
let result = item.render(buf, Rect { x, y, width, height })?;
|
||||||
match self.1 {
|
match self.1 {
|
||||||
Direction::Down => {
|
Direction::Down => {
|
||||||
y = y + result.height;
|
y += result.height;
|
||||||
height = height.saturating_sub(result.height);
|
height = height.saturating_sub(result.height);
|
||||||
},
|
},
|
||||||
Direction::Right => {
|
Direction::Right => {
|
||||||
x = x + result.width;
|
x += result.width;
|
||||||
width = width.saturating_sub(result.width);
|
width = width.saturating_sub(result.width);
|
||||||
},
|
},
|
||||||
_ => unimplemented!()
|
_ => unimplemented!()
|
||||||
|
|
@ -135,11 +135,11 @@ impl<'a> SplitFocus<'a> {
|
||||||
areas.push(result);
|
areas.push(result);
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Direction::Down => {
|
Direction::Down => {
|
||||||
y = y + result.height;
|
y += result.height;
|
||||||
height = height.saturating_sub(result.height);
|
height = height.saturating_sub(result.height);
|
||||||
},
|
},
|
||||||
Direction::Right => {
|
Direction::Right => {
|
||||||
x = x + result.width;
|
x += result.width;
|
||||||
width = width.saturating_sub(result.width);
|
width = width.saturating_sub(result.width);
|
||||||
},
|
},
|
||||||
_ => unimplemented!()
|
_ => unimplemented!()
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ impl Timebase {
|
||||||
self.rate.load(Ordering::Relaxed)
|
self.rate.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
#[inline] fn usec_per_frame (&self) -> f64 {
|
#[inline] fn usec_per_frame (&self) -> f64 {
|
||||||
1_000_000 as f64 / self.rate() as f64
|
1_000_000f64 / self.rate()
|
||||||
}
|
}
|
||||||
#[inline] pub fn frame_to_usec (&self, frame: f64) -> f64 {
|
#[inline] pub fn frame_to_usec (&self, frame: f64) -> f64 {
|
||||||
frame * self.usec_per_frame()
|
frame * self.usec_per_frame()
|
||||||
|
|
@ -43,10 +43,10 @@ impl Timebase {
|
||||||
self.bpm.store(bpm, Ordering::Relaxed)
|
self.bpm.store(bpm, Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
#[inline] fn usec_per_beat (&self) -> f64 {
|
#[inline] fn usec_per_beat (&self) -> f64 {
|
||||||
60_000_000f64 / self.bpm() as f64
|
60_000_000f64 / self.bpm()
|
||||||
}
|
}
|
||||||
#[inline] fn beat_per_second (&self) -> f64 {
|
#[inline] fn beat_per_second (&self) -> f64 {
|
||||||
self.bpm() as f64 / 60000000.0
|
self.bpm() / 60000000.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pulses per beat
|
/// Pulses per beat
|
||||||
|
|
@ -54,10 +54,10 @@ impl Timebase {
|
||||||
self.ppq.load(Ordering::Relaxed)
|
self.ppq.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
#[inline] pub fn pulse_per_frame (&self) -> f64 {
|
#[inline] pub fn pulse_per_frame (&self) -> f64 {
|
||||||
self.usec_per_pulse() / self.usec_per_frame() as f64
|
self.usec_per_pulse() / self.usec_per_frame()
|
||||||
}
|
}
|
||||||
#[inline] pub fn usec_per_pulse (&self) -> f64 {
|
#[inline] pub fn usec_per_pulse (&self) -> f64 {
|
||||||
self.usec_per_beat() / self.ppq() as f64
|
self.usec_per_beat() / self.ppq()
|
||||||
}
|
}
|
||||||
#[inline] pub fn pulse_to_frame (&self, pulses: f64) -> f64 {
|
#[inline] pub fn pulse_to_frame (&self, pulses: f64) -> f64 {
|
||||||
self.pulse_per_frame() * pulses
|
self.pulse_per_frame() * pulses
|
||||||
|
|
@ -69,10 +69,10 @@ impl Timebase {
|
||||||
4.0 * self.usec_per_beat() * num / den
|
4.0 * self.usec_per_beat() * num / den
|
||||||
}
|
}
|
||||||
#[inline] pub fn frames_per_pulse (&self) -> f64 {
|
#[inline] pub fn frames_per_pulse (&self) -> f64 {
|
||||||
self.rate() as f64 / self.pulses_per_second()
|
self.rate() / self.pulses_per_second()
|
||||||
}
|
}
|
||||||
#[inline] fn pulses_per_second (&self) -> f64 {
|
#[inline] fn pulses_per_second (&self) -> f64 {
|
||||||
self.beat_per_second() * self.ppq() as f64
|
self.beat_per_second() * self.ppq()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline] pub fn note_to_frame (&self, note: (f64, f64)) -> f64 {
|
#[inline] pub fn note_to_frame (&self, note: (f64, f64)) -> f64 {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ pub fn handle_mixer (state: &mut Mixer, event: &AppEvent) -> Usually<bool> {
|
||||||
if state.selected_track == 0 {
|
if state.selected_track == 0 {
|
||||||
state.selected_track = state.tracks.len() - 1;
|
state.selected_track = state.tracks.len() - 1;
|
||||||
} else {
|
} else {
|
||||||
state.selected_track = state.selected_track - 1;
|
state.selected_track -= 1;
|
||||||
}
|
}
|
||||||
println!("{}", state.selected_track);
|
println!("{}", state.selected_track);
|
||||||
return Ok(true)
|
return Ok(true)
|
||||||
|
|
@ -34,7 +34,7 @@ pub fn handle_mixer (state: &mut Mixer, event: &AppEvent) -> Usually<bool> {
|
||||||
if state.selected_column == 0 {
|
if state.selected_column == 0 {
|
||||||
state.selected_column = 6
|
state.selected_column = 6
|
||||||
} else {
|
} else {
|
||||||
state.selected_column = state.selected_column - 1;
|
state.selected_column -= 1;
|
||||||
}
|
}
|
||||||
return Ok(true)
|
return Ok(true)
|
||||||
},
|
},
|
||||||
|
|
@ -42,7 +42,7 @@ pub fn handle_mixer (state: &mut Mixer, event: &AppEvent) -> Usually<bool> {
|
||||||
if state.selected_column == 6 {
|
if state.selected_column == 6 {
|
||||||
state.selected_column = 0
|
state.selected_column = 0
|
||||||
} else {
|
} else {
|
||||||
state.selected_column = state.selected_column + 1;
|
state.selected_column += 1;
|
||||||
}
|
}
|
||||||
return Ok(true)
|
return Ok(true)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use tek_core::edn;
|
use tek_core::edn;
|
||||||
#[cfg(feature = "standalone_devices")]
|
|
||||||
use tek_sampler::*;
|
|
||||||
#[cfg(feature = "standalone_devices")]
|
|
||||||
use tek_plugin::*;
|
|
||||||
|
|
||||||
/// A sequencer track.
|
/// A sequencer track.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -74,9 +70,7 @@ impl Track {
|
||||||
Edn::List(args) => match args.get(0) {
|
Edn::List(args) => match args.get(0) {
|
||||||
// Add a sampler device to the track
|
// Add a sampler device to the track
|
||||||
Some(Edn::Symbol(SYM_SAMPLER)) => {
|
Some(Edn::Symbol(SYM_SAMPLER)) => {
|
||||||
#[cfg(feature = "standalone_devices")]
|
|
||||||
devices.push(Sampler::from_edn(&args[1..])?);
|
devices.push(Sampler::from_edn(&args[1..])?);
|
||||||
#[cfg(not(feature = "standalone_devices"))]
|
|
||||||
panic!(
|
panic!(
|
||||||
"unsupported in track {}: {:?}; tek_mixer not compiled with feature \"sampler\"",
|
"unsupported in track {}: {:?}; tek_mixer not compiled with feature \"sampler\"",
|
||||||
&track.name,
|
&track.name,
|
||||||
|
|
@ -85,9 +79,7 @@ impl Track {
|
||||||
},
|
},
|
||||||
// Add a LV2 plugin to the track.
|
// Add a LV2 plugin to the track.
|
||||||
Some(Edn::Symbol(SYM_LV2)) => {
|
Some(Edn::Symbol(SYM_LV2)) => {
|
||||||
#[cfg(feature = "standalone_devices")]
|
|
||||||
devices.push(LV2Plugin::from_edn(&args[1..])?);
|
devices.push(LV2Plugin::from_edn(&args[1..])?);
|
||||||
#[cfg(not(feature = "standalone_devices"))]
|
|
||||||
panic!(
|
panic!(
|
||||||
"unsupported in track {}: {:?}; tek_mixer not compiled with feature \"plugin\"",
|
"unsupported in track {}: {:?}; tek_mixer not compiled with feature \"plugin\"",
|
||||||
&track.name,
|
&track.name,
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
use tek_core::clap::{self, Parser};
|
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
|
||||||
#[command(version, about, long_about = None)]
|
|
||||||
pub struct ArrangerCli {
|
|
||||||
/// Name of JACK client
|
|
||||||
#[arg(short, long)] name: Option<String>,
|
|
||||||
/// Pulses per quarter note (arruencer resolution; default: 96)
|
|
||||||
#[arg(short, long)] ppq: Option<usize>,
|
|
||||||
/// Whether to include a transport toolbar (default: true)
|
|
||||||
#[arg(short, long)] transport: Option<bool>,
|
|
||||||
/// Number of tracks
|
|
||||||
#[arg(short = 'x', long, default_value_t = 8)] tracks: usize,
|
|
||||||
/// Number of scenes
|
|
||||||
#[arg(short, long, default_value_t = 8)] scenes: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Arranger {
|
|
||||||
pub fn from_args () -> Usually<Self> {
|
|
||||||
let args = ArrangerCli::parse();
|
|
||||||
let mut arr = Self::new("");
|
|
||||||
if let Some(name) = args.name {
|
|
||||||
arr.name = name.clone();
|
|
||||||
}
|
|
||||||
if args.transport == Some(true) {
|
|
||||||
arr.transport = Some(Arc::new(RwLock::new(TransportToolbar::new(None))));
|
|
||||||
}
|
|
||||||
for _ in 0..args.tracks {
|
|
||||||
arr.track_add(None)?;
|
|
||||||
}
|
|
||||||
for _ in 0..args.scenes {
|
|
||||||
arr.scene_add(None)?;
|
|
||||||
}
|
|
||||||
Ok(arr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +1,15 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
handle!(Arranger |self, e| {
|
handle!(Arranger |self, e| {
|
||||||
if let Some(modal) = self.modal.as_mut() {
|
match self.modal.as_mut() {
|
||||||
|
Some(modal) => {
|
||||||
let result = modal.handle(e)?;
|
let result = modal.handle(e)?;
|
||||||
if modal.exited() {
|
if modal.exited() {
|
||||||
self.modal = None;
|
self.modal = None;
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
|
||||||
match e {
|
|
||||||
AppEvent::Input(Event::Key(k)) => {
|
|
||||||
if k.code == KeyCode::Tab {
|
|
||||||
self.focus_sequencer = !self.focus_sequencer;
|
|
||||||
Ok(true)
|
|
||||||
} else if self.focus_sequencer {
|
|
||||||
if let Some(sequencer) = self.sequencer_mut() {
|
|
||||||
handle_keymap(sequencer, e, KEYMAP_SEQUENCER)
|
|
||||||
} else {
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handle_keymap(self, e, KEYMAP_ARRANGER)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => Ok(false),
|
None => handle_keymap(self, e, KEYMAP_ARRANGER)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,97 @@
|
||||||
include!("lib.rs");
|
include!("lib.rs");
|
||||||
|
|
||||||
|
use tek_core::clap::{self, Parser};
|
||||||
|
|
||||||
pub fn main () -> Usually<()> {
|
pub fn main () -> Usually<()> {
|
||||||
tek_core::run(Arc::new(RwLock::new(crate::Arranger::from_args()?)))?;
|
tek_core::run(Arc::new(RwLock::new(crate::ArrangerStandalone::from_args()?)))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ArrangerStandalone {
|
||||||
|
arranger: Arranger,
|
||||||
|
transport: Option<Arc<RwLock<TransportToolbar>>>,
|
||||||
|
show_sequencer: Option<tek_core::Direction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[command(version, about, long_about = None)]
|
||||||
|
pub struct ArrangerCli {
|
||||||
|
/// Name of JACK client
|
||||||
|
#[arg(short, long)] name: Option<String>,
|
||||||
|
/// Pulses per quarter note (arruencer resolution; default: 96)
|
||||||
|
#[arg(short, long)] ppq: Option<usize>,
|
||||||
|
/// Whether to include a transport toolbar (default: true)
|
||||||
|
#[arg(short, long)] transport: Option<bool>,
|
||||||
|
/// Number of tracks
|
||||||
|
#[arg(short = 'x', long, default_value_t = 8)] tracks: usize,
|
||||||
|
/// Number of scenes
|
||||||
|
#[arg(short, long, default_value_t = 8)] scenes: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrangerStandalone {
|
||||||
|
pub fn from_args () -> Usually<Self> {
|
||||||
|
let args = ArrangerCli::parse();
|
||||||
|
let mut app = ArrangerStandalone {
|
||||||
|
arranger: Arranger::new(""),
|
||||||
|
transport: match args.transport {
|
||||||
|
Some(true) => Some(Arc::new(RwLock::new(TransportToolbar::new(None)))),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
show_sequencer: Some(tek_core::Direction::Down),
|
||||||
|
};
|
||||||
|
if let Some(name) = args.name {
|
||||||
|
app.arranger.name = name.clone();
|
||||||
|
}
|
||||||
|
for _ in 0..args.tracks {
|
||||||
|
app.arranger.track_add(None)?;
|
||||||
|
}
|
||||||
|
for _ in 0..args.scenes {
|
||||||
|
app.arranger.scene_add(None)?;
|
||||||
|
}
|
||||||
|
Ok(app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render!(ArrangerStandalone |self, buf, area| {
|
||||||
|
let mut layout = Split::down();
|
||||||
|
if let Some(transport) = &self.transport {
|
||||||
|
layout = layout.add_ref(transport);
|
||||||
|
}
|
||||||
|
let sequencer = self.arranger.sequencer();
|
||||||
|
if let Some(direction) = self.show_sequencer {
|
||||||
|
layout = layout.add(Split::new(direction)
|
||||||
|
.add_ref(&self.arranger)
|
||||||
|
.add(sequencer))
|
||||||
|
} else {
|
||||||
|
layout = layout.add_ref(&self.arranger)
|
||||||
|
}
|
||||||
|
layout.render(buf, area)
|
||||||
|
});
|
||||||
|
|
||||||
|
handle!(ArrangerStandalone |self, e| {
|
||||||
|
if let Some(modal) = self.arranger.modal.as_mut() {
|
||||||
|
let result = modal.handle(e)?;
|
||||||
|
if modal.exited() {
|
||||||
|
self.arranger.modal = None;
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
match e {
|
||||||
|
AppEvent::Input(Event::Key(k)) => {
|
||||||
|
if k.code == KeyCode::Tab {
|
||||||
|
self.arranger.focus_sequencer = !self.arranger.focus_sequencer;
|
||||||
|
Ok(true)
|
||||||
|
} else if self.arranger.focus_sequencer {
|
||||||
|
if let Some(sequencer) = self.arranger.sequencer_mut() {
|
||||||
|
handle_keymap(sequencer, e, KEYMAP_SEQUENCER)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handle_keymap(&mut self.arranger, e, KEYMAP_ARRANGER)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Ok(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use tek_core::Direction;
|
|
||||||
|
|
||||||
/// Display mode of arranger
|
/// Display mode of arranger
|
||||||
pub enum ArrangerViewMode {
|
pub enum ArrangerViewMode {
|
||||||
|
|
@ -21,8 +20,6 @@ impl ArrangerViewMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
render!(Arranger |self, buf, area| {
|
render!(Arranger |self, buf, area| {
|
||||||
|
|
||||||
let arrangement = Box::new(|buf: &mut Buffer, area: Rect| {
|
|
||||||
let area = Rect {
|
let area = Rect {
|
||||||
x: area.x + 1, width: area.width - 2, y: area.y + 1, height: area.height - 2
|
x: area.x + 1, width: area.width - 2, y: area.y + 1, height: area.height - 2
|
||||||
};
|
};
|
||||||
|
|
@ -43,87 +40,4 @@ render!(Arranger |self, buf, area| {
|
||||||
height: area.height + 2,
|
height: area.height + 2,
|
||||||
};
|
};
|
||||||
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, area)
|
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, area)
|
||||||
});
|
|
||||||
|
|
||||||
let mut layout = Split::new(Direction::Down)
|
|
||||||
.add_ref(match &self.transport {
|
|
||||||
Some(transport) => transport as &dyn Render,
|
|
||||||
None => &() as &dyn Render
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(direction) = self.show_sequencer {
|
|
||||||
let sequencer = Box::new(Split::new(direction).add_box(arrangement));
|
|
||||||
layout = layout.add_box(sequencer);
|
|
||||||
} else {
|
|
||||||
layout = layout.add_box(arrangement);
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.render(buf, area)
|
|
||||||
|
|
||||||
//.add(if let Some(direction) = self.show_sequencer {
|
|
||||||
//Box::new(Split::new(direction)
|
|
||||||
//.add(arrangement))
|
|
||||||
////.add_ref(&self.sequencer())) as Box<dyn Render>
|
|
||||||
//} else {
|
|
||||||
//Box::new(arrangement) as Box<dyn Render>
|
|
||||||
//})
|
|
||||||
//.render(buf, area)
|
|
||||||
|
|
||||||
|
|
||||||
//Column([
|
|
||||||
//self.transport,
|
|
||||||
//match self.mode {
|
|
||||||
//ArrangerViewMode::Horizontal =>
|
|
||||||
//super::arranger_view_h::draw(self, buf, area),
|
|
||||||
//ArrangerViewMode::VerticalCompact1 =>
|
|
||||||
//super::arranger_view_v::draw_compact_1(self, buf, area),
|
|
||||||
//ArrangerViewMode::VerticalCompact2 =>
|
|
||||||
//super::arranger_view_v::draw_compact_2(self, buf, area),
|
|
||||||
//ArrangerViewMode::VerticalExpanded =>
|
|
||||||
//super::arranger_view_v::draw_expanded(self, buf, area),
|
|
||||||
//},
|
|
||||||
|
|
||||||
|
|
||||||
//let area = if let Some(direction) = self.show_sequencer {
|
|
||||||
//let arrangement = arrangement(buf, area)?;
|
|
||||||
//match direction {
|
|
||||||
//Direction::Down => {
|
|
||||||
//let sequencer = if let Some(sequencer) = self.sequencer() {
|
|
||||||
//sequencer.render(buf, Rect {
|
|
||||||
//y: area.y + arrangement.height,
|
|
||||||
//height: area.height - arrangement.height,
|
|
||||||
//..area
|
|
||||||
//})?
|
|
||||||
//} else {
|
|
||||||
//Rect::default()
|
|
||||||
//};
|
|
||||||
//match self.focus_sequencer {
|
|
||||||
//true => {
|
|
||||||
//"[Arrows] Move, [A]dd, [D]elete, [R]ecord, [P]lay".blit(
|
|
||||||
//buf, area.x + 1, area.height - 1, Some(Style::default().dim())
|
|
||||||
//)?;
|
|
||||||
//},
|
|
||||||
//false => {
|
|
||||||
//"[Arrows] Move, [P]lay, [R]ecord, [N]ame, [E]dit, [C-T]rack add, [C-A]dd scene".blit(
|
|
||||||
//buf, area.x + 1, area.y + arrangement.height, Some(Style::default().dim())
|
|
||||||
//)?;
|
|
||||||
//},
|
|
||||||
//}
|
|
||||||
//Corners(Style::default().green().not_dim()).draw(buf, match self.focus_sequencer {
|
|
||||||
//true => sequencer,
|
|
||||||
//false => arrangement,
|
|
||||||
//})?;
|
|
||||||
//},
|
|
||||||
//_ => unimplemented!()
|
|
||||||
//}
|
|
||||||
//Ok(area)
|
|
||||||
//} else {
|
|
||||||
//arrangement(buf, area)
|
|
||||||
//}?;
|
|
||||||
//if let Some(ref modal) = self.modal {
|
|
||||||
//fill_bg(buf, area, Nord::bg_lo(false, false));
|
|
||||||
//fill_fg(buf, area, Nord::bg_hi(false, false));
|
|
||||||
//modal.render(buf, area)?;
|
|
||||||
//}
|
|
||||||
//Ok(area)
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ impl<'a> Render for TrackMonitorColumn<'a> {
|
||||||
let Self(tracks) = self;
|
let Self(tracks) = self;
|
||||||
let on = Some(Style::default().not_dim().green().bold());
|
let on = Some(Style::default().not_dim().green().bold());
|
||||||
let off = Some(DIM);
|
let off = Some(DIM);
|
||||||
area.x = area.x + 1;
|
area.x += 1;
|
||||||
for y in 0..area.height {
|
for y in 0..area.height {
|
||||||
if y == 0 {
|
if y == 0 {
|
||||||
//" MON ".blit(buf, area.x, area.y + y, style2)?;
|
//" MON ".blit(buf, area.x, area.y + y, style2)?;
|
||||||
|
|
@ -76,7 +76,7 @@ impl<'a> Render for TrackRecordColumn<'a> {
|
||||||
let Self(tracks) = self;
|
let Self(tracks) = self;
|
||||||
let on = Some(Style::default().not_dim().red().bold());
|
let on = Some(Style::default().not_dim().red().bold());
|
||||||
let off = Some(Style::default().dim());
|
let off = Some(Style::default().dim());
|
||||||
area.x = area.x + 1;
|
area.x += 1;
|
||||||
for y in 0..area.height {
|
for y in 0..area.height {
|
||||||
if y == 0 {
|
if y == 0 {
|
||||||
//" REC ".blit(buf, area.x, area.y + y, style2)?;
|
//" REC ".blit(buf, area.x, area.y + y, style2)?;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ pub(crate) use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
submod! {
|
submod! {
|
||||||
arranger
|
arranger
|
||||||
arranger_cli
|
|
||||||
arranger_focus
|
arranger_focus
|
||||||
arranger_handle
|
arranger_handle
|
||||||
arranger_track
|
arranger_track
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,15 @@ const CORNERS: Corners = Corners(NOT_DIM_GREEN);
|
||||||
render!(TransportToolbar |self, buf, area| {
|
render!(TransportToolbar |self, buf, area| {
|
||||||
let mut area = area;
|
let mut area = area;
|
||||||
area.height = 2;
|
area.height = 2;
|
||||||
let ppq = self.ppq();
|
|
||||||
let bpm = self.bpm();
|
|
||||||
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));
|
||||||
let active = self.focused && self.entered;
|
let active = self.focused && self.entered;
|
||||||
let playing = TransportPlayPauseButton(self.playing);
|
|
||||||
let bpm = TransportBPM(bpm, active && self.selected == TransportFocus::BPM);
|
|
||||||
let quant = TransportQuantize(*quant, active && self.selected == TransportFocus::Quant);
|
|
||||||
let sync = TransportSync(*sync, active && self.selected == TransportFocus::Sync);
|
|
||||||
let clock = TransportClock(pulse, ppq, usecs);
|
|
||||||
Split::right()
|
Split::right()
|
||||||
.add_ref(&playing)
|
.add(TransportPlayPauseButton(self.playing))
|
||||||
.add_ref(&bpm)
|
.add(TransportBPM(self.bpm(), active && self.selected == TransportFocus::BPM))
|
||||||
.add_ref(&quant)
|
.add(TransportQuantize(*quant, active && self.selected == TransportFocus::Quant))
|
||||||
.add_ref(&sync)
|
.add(TransportSync(*sync, active && self.selected == TransportFocus::Sync))
|
||||||
.add_ref(&clock)
|
.add(TransportClock(self.pulse(), self.ppq(), self.usecs()))
|
||||||
.render(buf, area)
|
.render(buf, area)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -31,7 +22,6 @@ struct TransportPlayPauseButton(Option<TransportState>);
|
||||||
|
|
||||||
render!(TransportPlayPauseButton |self, buf, area| {
|
render!(TransportPlayPauseButton |self, buf, area| {
|
||||||
let Rect { x, y, .. } = area;
|
let Rect { x, y, .. } = area;
|
||||||
let gray = Style::default().gray();
|
|
||||||
let style = Some(match self.0 {
|
let style = Some(match self.0 {
|
||||||
Some(TransportState::Stopped) => GRAY_DIM.bold(),
|
Some(TransportState::Stopped) => GRAY_DIM.bold(),
|
||||||
Some(TransportState::Starting) => GRAY_NOT_DIM_BOLD,
|
Some(TransportState::Starting) => GRAY_NOT_DIM_BOLD,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue