mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
last small wave of 15 errors?
This commit is contained in:
parent
4fe51b5267
commit
872c2d94d6
11 changed files with 181 additions and 189 deletions
|
|
@ -30,9 +30,9 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
app.toggle_editor(Some(value));
|
||||
Ok(None)
|
||||
}
|
||||
fn color (app: &mut App, theme: ItemTheme) -> Perhaps<Self> {
|
||||
Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme}))
|
||||
}
|
||||
//fn color (app: &mut App, theme: ItemTheme) -> Perhaps<Self> {
|
||||
//Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme}))
|
||||
//}
|
||||
fn enqueue (app: &mut App, clip: Option<Arc<RwLock<MidiClip>>>) -> Perhaps<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
|
@ -42,19 +42,18 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
fn zoom (app: &mut App, zoom: usize) -> Perhaps<Self> {
|
||||
todo!()
|
||||
}
|
||||
fn launch (app: &mut App) -> Perhaps<Self> {
|
||||
app.project.launch();
|
||||
Ok(None)
|
||||
}
|
||||
//fn launch (app: &mut App) -> Perhaps<Self> {
|
||||
//app.project.launch();
|
||||
//Ok(None)
|
||||
//}
|
||||
fn select (app: &mut App, selection: Selection) -> Perhaps<Self> {
|
||||
app.project.select(selection);
|
||||
*app.project.selection_mut() = selection;
|
||||
if let Some(ref mut editor) = app.editor {
|
||||
editor.set_clip(match app.project.selected {
|
||||
Some(Selection::TrackClip { track, scene })
|
||||
if let Some(Some(Some(clip))) = app
|
||||
editor.set_clip(match app.project.selection() {
|
||||
Selection::TrackClip { track, scene } if let Some(Some(Some(clip))) = app
|
||||
.project
|
||||
.scenes.get(scene)
|
||||
.map(|s|s.clips.get(track))
|
||||
.scenes.get(*scene)
|
||||
.map(|s|s.clips.get(*track))
|
||||
=>
|
||||
Some(clip),
|
||||
_ =>
|
||||
|
|
@ -79,14 +78,11 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
.transpose()?
|
||||
.flatten())
|
||||
}
|
||||
fn arrange (app: &mut App, command: ArrangementCommand) -> Perhaps<Self> {
|
||||
Ok(command.delegate(app, |command|Self::Arrange{command})?)
|
||||
fn project (app: &mut App, command: ArrangementCommand) -> Perhaps<Self> {
|
||||
Ok(command.delegate(&mut app.project, |command|Self::Project{command})?)
|
||||
}
|
||||
fn clock (app: &mut App, command: ClockCommand) -> Perhaps<Self> {
|
||||
Ok(command.execute(&mut app.clock())?.map(|command|Self::Clock{command}))
|
||||
}
|
||||
fn device (app: &mut App, command: DeviceCommand) -> Perhaps<Self> {
|
||||
Ok(command.delegate(app, |command|Self::Device{command})?)
|
||||
Ok(command.execute(app.clock_mut())?.map(|command|Self::Clock{command}))
|
||||
}
|
||||
fn message (app: &mut App, command: MessageCommand) -> Perhaps<Self> {
|
||||
Ok(command.delegate(app, |command|Self::Message{command})?)
|
||||
|
|
@ -106,21 +102,20 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
})
|
||||
}
|
||||
fn pool (app: &mut App, command: PoolCommand) -> Perhaps<Self> {
|
||||
Ok(if let Some(pool) = app.project.pool.as_mut() {
|
||||
let undo = command.clone().delegate(pool, |command|AppCommand::Pool{command})?;
|
||||
// update linked editor after pool action
|
||||
app.editor.as_mut().map(|editor|match command {
|
||||
// autoselect: automatically load selected clip in editor
|
||||
PoolCommand::Select { .. } |
|
||||
// autocolor: update color in all places simultaneously
|
||||
PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } =>
|
||||
editor.set_clip(pool.clip().as_ref()),
|
||||
_ => {}
|
||||
});
|
||||
undo
|
||||
} else {
|
||||
None
|
||||
})
|
||||
let undo = command.clone().delegate(
|
||||
&mut app.project.pool,
|
||||
|command|AppCommand::Pool{command}
|
||||
)?;
|
||||
// update linked editor after pool action
|
||||
app.editor.as_mut().map(|editor|match command {
|
||||
// autoselect: automatically load selected clip in editor
|
||||
PoolCommand::Select { .. } |
|
||||
// autocolor: update color in all places simultaneously
|
||||
PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } =>
|
||||
editor.set_clip(app.project.pool.clip().as_ref()),
|
||||
_ => {}
|
||||
});
|
||||
Ok(undo)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +133,7 @@ impl<'state> Context<'state, MidiEditCommand> for App {
|
|||
|
||||
impl<'state> Context<'state, PoolCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<PoolCommand> {
|
||||
self.project.pool.map(|p|Context::get(p, iter)).flatten()
|
||||
Context::get(&self.project.pool, iter)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,9 +143,15 @@ impl<'state> Context<'state, SamplerCommand> for App {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'state> Context<'state, ArrangementCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<ArrangementCommand> {
|
||||
Context::get(&self.project, iter)
|
||||
}
|
||||
}
|
||||
|
||||
#[tengri_proc::command(App)] impl MessageCommand {
|
||||
fn dismiss (app: &mut App) -> Perhaps<Self> {
|
||||
app.message_dismiss();
|
||||
app.dialog = None;
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
use crate::*;
|
||||
|
||||
impl HasJack for App {
|
||||
fn jack (&self) -> &Jack {
|
||||
&self.jack
|
||||
}
|
||||
}
|
||||
|
||||
audio!(
|
||||
|self: App, client, scope|{
|
||||
let t0 = self.perf.get_t0();
|
||||
|
|
|
|||
|
|
@ -28,12 +28,14 @@ pub struct App {
|
|||
pub color: ItemTheme,
|
||||
}
|
||||
|
||||
has!(Option<Selection>: |self: App|self.project.selection);
|
||||
has!(Vec<JackMidiIn>: |self: App|self.project.midi_ins);
|
||||
has!(Vec<JackMidiOut>: |self: App|self.project.midi_outs);
|
||||
has!(Vec<Scene>: |self: App|self.project.scenes);
|
||||
has!(Vec<Track>: |self: App|self.project.tracks);
|
||||
has!(Clock: |self: App|self.project.clock);
|
||||
has!(Jack: |self: App|self.jack);
|
||||
has!(Clock: |self: App|self.project.clock);
|
||||
has!(Selection: |self: App|self.project.selection);
|
||||
has!(Vec<JackMidiIn>: |self: App|self.project.midi_ins);
|
||||
has!(Vec<JackMidiOut>: |self: App|self.project.midi_outs);
|
||||
has!(Vec<Scene>: |self: App|self.project.scenes);
|
||||
has!(Vec<Track>: |self: App|self.project.tracks);
|
||||
|
||||
has_size!(<TuiOut>|self: App|&self.size);
|
||||
has_clips!(|self: App|self.project.pool.clips);
|
||||
has_editor!(|self: App|{
|
||||
|
|
@ -46,24 +48,28 @@ has_editor!(|self: App|{
|
|||
(5 + (time_len / time_zoom)).min(size.saturating_sub(20)).max(16)
|
||||
};
|
||||
editor_h = 15;
|
||||
is_editing = self.editing.load(Relaxed);
|
||||
is_editing = self.editor.is_some();
|
||||
});
|
||||
|
||||
impl App {
|
||||
pub fn toggle_dialog (&mut self, dialog: Option<Dialog>) {
|
||||
self.dialog = if self.dialog == dialog {
|
||||
None
|
||||
} else {
|
||||
dialog
|
||||
}
|
||||
pub fn toggle_dialog (&mut self, mut dialog: Option<Dialog>) -> Option<Dialog> {
|
||||
std::mem::swap(&mut self.dialog, &mut dialog);
|
||||
dialog
|
||||
}
|
||||
pub fn toggle_editor (&mut self, value: Option<bool>) {
|
||||
self.editing.store(value.unwrap_or_else(||!self.is_editing()), Relaxed);
|
||||
self.arranger.map(|arranger|if value {
|
||||
arranger.clip_auto_create();
|
||||
//FIXME: self.editing.store(value.unwrap_or_else(||!self.is_editing()), Relaxed);
|
||||
let value = value.unwrap_or_else(||!self.editor.is_some());
|
||||
if value {
|
||||
self.clip_auto_create();
|
||||
} else {
|
||||
arranger.clip_auto_remove();
|
||||
});
|
||||
self.clip_auto_remove();
|
||||
}
|
||||
}
|
||||
pub fn browser (&self) -> Option<&Browser> {
|
||||
self.dialog.as_ref().and_then(|dialog|match dialog {
|
||||
Dialog::Save(b) | Dialog::Load(b) => Some(b),
|
||||
_ => None
|
||||
})
|
||||
}
|
||||
pub(crate) fn device_pick (&mut self, index: usize) {
|
||||
self.dialog = Some(Dialog::Device(index));
|
||||
|
|
@ -85,15 +91,14 @@ impl App {
|
|||
todo!();
|
||||
Ok(())
|
||||
}
|
||||
fn device_add_sampler (&mut self, jack: &Jack) -> Usually<usize> {
|
||||
let name = jack.with_client(|c|c.name().to_string());
|
||||
let midi = self.track().expect("no active track").sequencer.midi_outs[0].name();
|
||||
fn device_add_sampler (&mut self) -> Usually<()> {
|
||||
let name = self.jack.with_client(|c|c.name().to_string());
|
||||
let midi = self.project.track().expect("no active track").sequencer.midi_outs[0].name();
|
||||
let track = self.track().expect("no active track");
|
||||
let port = format!("{}/Sampler", &track.name);
|
||||
let connect = PortConnect::exact(format!("{name}:{midi}"));
|
||||
let sampler = if let Ok(sampler) = Sampler::new(
|
||||
jack,
|
||||
&format!("{}/Sampler", Has::<Track>::get(self).name),
|
||||
&[PortConnect::exact(format!("{name}:{midi}"))],
|
||||
&[&[], &[]],
|
||||
&[&[], &[]]
|
||||
&self.jack, &port, &[connect], &[&[], &[]], &[&[], &[]]
|
||||
) {
|
||||
self.dialog = None;
|
||||
Device::Sampler(sampler)
|
||||
|
|
@ -101,22 +106,23 @@ impl App {
|
|||
self.dialog = Some(Dialog::Message(Message::FailedToAddDevice));
|
||||
return Err("failed to add device".into())
|
||||
};
|
||||
Has::<Track>::get_mut(self).expect("no active track").devices.push(sampler);
|
||||
let track = self.track_mut().expect("no active track");
|
||||
track.devices.push(sampler);
|
||||
Ok(())
|
||||
}
|
||||
// Create new clip in pool when entering empty cell
|
||||
fn clip_auto_create (&mut self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||
if let Some(Selection::TrackClip { track, scene }) = self.get()
|
||||
&& let Some(scene) = Has::<Vec<Scene>>::get_mut(self).get_mut(scene)
|
||||
if let Selection::TrackClip { track, scene } = *self.selection()
|
||||
&& let Some(scene) = self.project.scenes.get_mut(scene)
|
||||
&& let Some(slot) = scene.clips.get_mut(track)
|
||||
&& slot.is_none()
|
||||
&& let Some(track) = Has::<Vec<Track>>::get_mut(self).get_mut(track)
|
||||
&& let Some(track) = self.project.tracks.get_mut(track)
|
||||
{
|
||||
let (index, mut clip) = self.arranger.pool.add_new_clip();
|
||||
let (index, mut clip) = self.project.pool.add_new_clip();
|
||||
// autocolor: new clip colors from scene and track color
|
||||
let color = track.color.base.mix(scene.color.base, 0.5);
|
||||
clip.write().unwrap().color = ItemColor::random_near(color, 0.2).into();
|
||||
if let Some(ref mut editor) = Has::<Option<MidiEditor>>::get_mut(self) {
|
||||
if let Some(ref mut editor) = self.editor {
|
||||
editor.set_clip(Some(&clip));
|
||||
}
|
||||
*slot = Some(clip.clone());
|
||||
|
|
@ -125,37 +131,24 @@ impl App {
|
|||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "pool", feature = "editor"))]
|
||||
pub trait AutoRemove:
|
||||
Has<Vec<Scene>> +
|
||||
Has<Vec<Track>> +
|
||||
Has<Option<MidiEditor>> +
|
||||
Has<Option<Selection>> +
|
||||
Has<Option<Pool>> +
|
||||
Send + Sync
|
||||
{
|
||||
// Remove clip from arrangement when exiting empty clip editor
|
||||
fn clip_auto_remove (&mut self) {
|
||||
if let Some(ref mut pool) = Has::<Option<Pool>>::get(self)
|
||||
&& let Some(Selection::TrackClip { track, scene }) = self.get()
|
||||
&& let Some(scene) = Has::<Vec<Scene>>::get_mut(self).get_mut(*scene)
|
||||
&& let Some(slot) = scene.clips.get_mut(*track)
|
||||
&& let Some(clip) = slot.as_mut()
|
||||
if let Selection::TrackClip { track, scene } = *self.selection()
|
||||
&& let Some(scene) = self.project.scenes.get_mut(scene)
|
||||
&& let Some(slot) = scene.clips.get_mut(track)
|
||||
&& let Some(clip) = slot.as_mut()
|
||||
{
|
||||
let mut swapped = None;
|
||||
if clip.read().unwrap().count_midi_messages() == 0 {
|
||||
std::mem::swap(&mut swapped, slot);
|
||||
}
|
||||
if let Some(clip) = swapped {
|
||||
pool.delete_clip(&clip.read().unwrap());
|
||||
self.project.pool.delete_clip(&clip.read().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Various possible dialog overlays
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Dialog {
|
||||
|
|
@ -197,7 +190,7 @@ impl App {
|
|||
matches!(self.dialog, Some(Dialog::Device(..)))
|
||||
}
|
||||
fn focus_browser (&self) -> bool {
|
||||
self.browser.is_visible
|
||||
self.browser().is_some()
|
||||
}
|
||||
fn focus_clip (&self) -> bool {
|
||||
!self.is_editing() && self.selection().is_clip()
|
||||
|
|
@ -212,16 +205,16 @@ impl App {
|
|||
!self.is_editing() && self.selection().is_mix()
|
||||
}
|
||||
fn focus_pool_import (&self) -> bool {
|
||||
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Import(..)))
|
||||
matches!(self.project.pool.mode, Some(PoolMode::Import(..)))
|
||||
}
|
||||
fn focus_pool_export (&self) -> bool {
|
||||
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Export(..)))
|
||||
matches!(self.project.pool.mode, Some(PoolMode::Export(..)))
|
||||
}
|
||||
fn focus_pool_rename (&self) -> bool {
|
||||
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Rename(..)))
|
||||
matches!(self.project.pool.mode, Some(PoolMode::Rename(..)))
|
||||
}
|
||||
fn focus_pool_length (&self) -> bool {
|
||||
matches!(self.project.pool.as_ref().map(|p|p.mode.as_ref()).flatten(), Some(PoolMode::Length(..)))
|
||||
matches!(self.project.pool.mode, Some(PoolMode::Length(..)))
|
||||
}
|
||||
fn dialog_device (&self) -> Dialog {
|
||||
Dialog::Device(0) // TODO
|
||||
|
|
@ -239,10 +232,10 @@ impl App {
|
|||
Dialog::Menu
|
||||
}
|
||||
fn dialog_save (&self) -> Dialog {
|
||||
Dialog::Save
|
||||
Dialog::Save(Default::default())
|
||||
}
|
||||
fn dialog_load (&self) -> Dialog {
|
||||
Dialog::Load
|
||||
Dialog::Load(Default::default())
|
||||
}
|
||||
fn dialog_options (&self) -> Dialog {
|
||||
Dialog::Options
|
||||
|
|
@ -251,13 +244,13 @@ impl App {
|
|||
Some((self.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8).into())
|
||||
}
|
||||
fn scene_count (&self) -> usize {
|
||||
self.scenes.len()
|
||||
self.scenes().len()
|
||||
}
|
||||
fn scene_selection (&self) -> Option<usize> {
|
||||
self.selection().scene()
|
||||
}
|
||||
fn track_count (&self) -> usize {
|
||||
self.tracks.len()
|
||||
self.tracks().len()
|
||||
}
|
||||
fn track_selection (&self) -> Option<usize> {
|
||||
self.selection().track()
|
||||
|
|
@ -279,7 +272,7 @@ impl App {
|
|||
}
|
||||
fn clip_selection (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||
match self.selection() {
|
||||
Selection::TrackClip { track, scene } => self.scenes()[scene].clips[track].clone(),
|
||||
Selection::TrackClip { track, scene } => self.scenes()[*scene].clips[*track].clone(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl App {
|
|||
pub fn view_status (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
self.update_clock();
|
||||
let cache = self.view_cache.read().unwrap();
|
||||
view_status(self.project.selected.map(|x|x.describe(self.tracks(), self.scenes())),
|
||||
view_status(Some(self.project.selection.describe(self.tracks(), self.scenes())),
|
||||
cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone())
|
||||
}
|
||||
pub fn view_transport (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue