mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
This commit is contained in:
parent
2c3bfe4ebb
commit
ef81b085a0
106 changed files with 6866 additions and 7106 deletions
626
device/arranger.rs
Normal file
626
device/arranger.rs
Normal file
|
|
@ -0,0 +1,626 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(Default, Debug)] pub struct Arrangement {
|
||||
/// Project name.
|
||||
pub name: Arc<str>,
|
||||
/// Base color.
|
||||
pub color: ItemTheme,
|
||||
/// JACK client handle.
|
||||
pub jack: Jack<'static>,
|
||||
/// FIXME a render of the project arrangement, redrawn on update.
|
||||
/// TODO rename to "render_cache" or smth
|
||||
pub arranger: Arc<RwLock<Buffer>>,
|
||||
/// Display size
|
||||
pub size: Measure<TuiOut>,
|
||||
/// Display size of clips area
|
||||
pub size_inner: Measure<TuiOut>,
|
||||
/// Source of time
|
||||
#[cfg(feature = "clock")] pub clock: Clock,
|
||||
/// Allows one MIDI clip to be edited
|
||||
#[cfg(feature = "editor")] pub editor: Option<MidiEditor>,
|
||||
/// List of global midi inputs
|
||||
#[cfg(feature = "port")] pub midi_ins: Vec<MidiInput>,
|
||||
/// List of global midi outputs
|
||||
#[cfg(feature = "port")] pub midi_outs: Vec<MidiOutput>,
|
||||
/// List of global audio inputs
|
||||
#[cfg(feature = "port")] pub audio_ins: Vec<AudioInput>,
|
||||
/// List of global audio outputs
|
||||
#[cfg(feature = "port")] pub audio_outs: Vec<AudioOutput>,
|
||||
/// Selected UI element
|
||||
#[cfg(feature = "select")] pub selection: Selection,
|
||||
/// Last track number (to avoid duplicate port names)
|
||||
#[cfg(feature = "track")] pub track_last: usize,
|
||||
/// List of tracks
|
||||
#[cfg(feature = "track")] pub tracks: Vec<Track>,
|
||||
/// Scroll offset of tracks
|
||||
#[cfg(feature = "track")] pub track_scroll: usize,
|
||||
/// List of scenes
|
||||
#[cfg(feature = "scene")] pub scenes: Vec<Scene>,
|
||||
/// Scroll offset of scenes
|
||||
#[cfg(feature = "scene")] pub scene_scroll: usize,
|
||||
}
|
||||
impl HasJack<'static> for Arrangement {
|
||||
fn jack (&self) -> &Jack<'static> {
|
||||
&self.jack
|
||||
}
|
||||
}
|
||||
has!(Jack<'static>: |self: Arrangement|self.jack);
|
||||
has!(Measure<TuiOut>: |self: Arrangement|self.size);
|
||||
#[cfg(feature = "editor")] has!(Option<MidiEditor>: |self: Arrangement|self.editor);
|
||||
#[cfg(feature = "port")] has!(Vec<MidiInput>: |self: Arrangement|self.midi_ins);
|
||||
#[cfg(feature = "port")] has!(Vec<MidiOutput>: |self: Arrangement|self.midi_outs);
|
||||
#[cfg(feature = "clock")] has!(Clock: |self: Arrangement|self.clock);
|
||||
#[cfg(feature = "select")] has!(Selection: |self: Arrangement|self.selection);
|
||||
#[cfg(all(feature = "select", feature = "track"))] has!(Vec<Track>: |self: Arrangement|self.tracks);
|
||||
#[cfg(all(feature = "select", feature = "track"))] maybe_has!(Track: |self: Arrangement|
|
||||
{ Has::<Selection>::get(self).track().map(|index|Has::<Vec<Track>>::get(self).get(index)).flatten() };
|
||||
{ Has::<Selection>::get(self).track().map(|index|Has::<Vec<Track>>::get_mut(self).get_mut(index)).flatten() });
|
||||
#[cfg(all(feature = "select", feature = "scene"))] has!(Vec<Scene>: |self: Arrangement|self.scenes);
|
||||
#[cfg(all(feature = "select", feature = "scene"))] maybe_has!(Scene: |self: Arrangement|
|
||||
{ Has::<Selection>::get(self).track().map(|index|Has::<Vec<Scene>>::get(self).get(index)).flatten() };
|
||||
{ Has::<Selection>::get(self).track().map(|index|Has::<Vec<Scene>>::get_mut(self).get_mut(index)).flatten() });
|
||||
|
||||
#[cfg(feature = "select")]
|
||||
impl Arrangement {
|
||||
#[cfg(feature = "clip")] fn selected_clip (&self) -> Option<MidiClip> { todo!() }
|
||||
#[cfg(feature = "scene")] fn selected_scene (&self) -> Option<Scene> { todo!() }
|
||||
#[cfg(feature = "track")] fn selected_track (&self) -> Option<Track> { todo!() }
|
||||
#[cfg(feature = "port")] fn selected_midi_in (&self) -> Option<MidiInput> { todo!() }
|
||||
#[cfg(feature = "port")] fn selected_midi_out (&self) -> Option<MidiOutput> { todo!() }
|
||||
fn selected_device (&self) -> Option<Device> { todo!() }
|
||||
fn unselect (&self) -> Selection {
|
||||
Selection::Nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl Arrangement {
|
||||
/// Width of display
|
||||
pub fn w (&self) -> u16 {
|
||||
self.size.w() as u16
|
||||
}
|
||||
/// Width allocated for sidebar.
|
||||
pub fn w_sidebar (&self, is_editing: bool) -> u16 {
|
||||
self.w() / if is_editing { 16 } else { 8 } as u16
|
||||
}
|
||||
/// Width available to display tracks.
|
||||
pub fn w_tracks_area (&self, is_editing: bool) -> u16 {
|
||||
self.w().saturating_sub(self.w_sidebar(is_editing))
|
||||
}
|
||||
/// Height of display
|
||||
pub fn h (&self) -> u16 {
|
||||
self.size.h() as u16
|
||||
}
|
||||
/// Height taken by visible device slots.
|
||||
pub fn h_devices (&self) -> u16 {
|
||||
2
|
||||
//1 + self.devices_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "track")]
|
||||
impl TracksView for Arrangement {}
|
||||
|
||||
#[cfg(feature = "track")]
|
||||
impl Arrangement {
|
||||
/// Get the active track
|
||||
pub fn get_track (&self) -> Option<&Track> {
|
||||
let index = self.selection().track()?;
|
||||
Has::<Vec<Track>>::get(self).get(index)
|
||||
}
|
||||
/// Get a mutable reference to the active track
|
||||
pub fn get_track_mut (&mut self) -> Option<&mut Track> {
|
||||
let index = self.selection().track()?;
|
||||
Has::<Vec<Track>>::get_mut(self).get_mut(index)
|
||||
}
|
||||
/// Add multiple tracks
|
||||
pub fn tracks_add (
|
||||
&mut self,
|
||||
count: usize, width: Option<usize>,
|
||||
mins: &[Connect], mouts: &[Connect],
|
||||
) -> Usually<()> {
|
||||
let track_color_1 = ItemColor::random();
|
||||
let track_color_2 = ItemColor::random();
|
||||
for i in 0..count {
|
||||
let color = track_color_1.mix(track_color_2, i as f32 / count as f32).into();
|
||||
let track = self.track_add(None, Some(color), mins, mouts)?.1;
|
||||
if let Some(width) = width {
|
||||
track.width = width;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Add a track
|
||||
pub fn track_add (
|
||||
&mut self,
|
||||
name: Option<&str>, color: Option<ItemTheme>,
|
||||
mins: &[Connect], mouts: &[Connect],
|
||||
) -> Usually<(usize, &mut Track)> {
|
||||
let name: Arc<str> = name.map_or_else(
|
||||
||format!("trk{:02}", self.track_last).into(),
|
||||
|x|x.to_string().into()
|
||||
);
|
||||
self.track_last += 1;
|
||||
let track = Track {
|
||||
width: (name.len() + 2).max(12),
|
||||
color: color.unwrap_or_else(ItemTheme::random),
|
||||
sequencer: Sequencer::new(
|
||||
&format!("{name}"),
|
||||
self.jack(),
|
||||
Some(self.clock()),
|
||||
None,
|
||||
mins,
|
||||
mouts
|
||||
)?,
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
self.tracks_mut().push(track);
|
||||
let len = self.tracks().len();
|
||||
let index = len - 1;
|
||||
for scene in self.scenes_mut().iter_mut() {
|
||||
while scene.clips.len() < len {
|
||||
scene.clips.push(None);
|
||||
}
|
||||
}
|
||||
Ok((index, &mut self.tracks_mut()[index]))
|
||||
}
|
||||
|
||||
pub fn view_inputs (&self, _theme: ItemTheme) -> impl Content<TuiOut> + '_ {
|
||||
Bsp::s(
|
||||
Fixed::Y(1, self.view_inputs_header()),
|
||||
Thunk::new(|to: &mut TuiOut|{
|
||||
for (index, port) in self.midi_ins().iter().enumerate() {
|
||||
to.place(&Push::X(index as u16 * 10, Fixed::Y(1, self.view_inputs_row(port))))
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fn view_inputs_header (&self) -> impl Content<TuiOut> + '_ {
|
||||
Bsp::e(Fixed::X(20, Align::w(button_3("i", "nput ", format!("{}", self.midi_ins.len()), false))),
|
||||
Bsp::w(Fixed::X(4, button_2("I", "+", false)), Thunk::new(move|to: &mut TuiOut|for (_index, track, x1, _x2) in self.tracks_with_sizes() {
|
||||
#[cfg(feature = "track")]
|
||||
to.place(&Push::X(x1 as u16, Tui::bg(track.color.dark.rgb, Align::w(Fixed::X(track.width as u16, row!(
|
||||
Either::new(track.sequencer.monitoring, Tui::fg(Green, "mon "), "mon "),
|
||||
Either::new(track.sequencer.recording, Tui::fg(Red, "rec "), "rec "),
|
||||
Either::new(track.sequencer.overdub, Tui::fg(Yellow, "dub "), "dub "),
|
||||
))))))
|
||||
})))
|
||||
}
|
||||
|
||||
fn view_inputs_row (&self, port: &MidiInput) -> impl Content<TuiOut> {
|
||||
Bsp::e(Fixed::X(20, Align::w(Bsp::e(" ● ", Tui::bold(true, Tui::fg(Rgb(255,255,255), port.port_name()))))),
|
||||
Bsp::w(Fixed::X(4, ()), Thunk::new(move|to: &mut TuiOut|for (_index, track, _x1, _x2) in self.tracks_with_sizes() {
|
||||
#[cfg(feature = "track")]
|
||||
to.place(&Tui::bg(track.color.darker.rgb, Align::w(Fixed::X(track.width as u16, row!(
|
||||
Either::new(track.sequencer.monitoring, Tui::fg(Green, " ● "), " · "),
|
||||
Either::new(track.sequencer.recording, Tui::fg(Red, " ● "), " · "),
|
||||
Either::new(track.sequencer.overdub, Tui::fg(Yellow, " ● "), " · "),
|
||||
)))))
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn view_outputs (&self, theme: ItemTheme) -> impl Content<TuiOut> {
|
||||
let mut h = 1;
|
||||
for output in self.midi_outs().iter() {
|
||||
h += 1 + output.connections.len();
|
||||
}
|
||||
let h = h as u16;
|
||||
let list = Bsp::s(
|
||||
Fixed::Y(1, Fill::X(Align::w(button_3("o", "utput", format!("{}", self.midi_outs.len()), false)))),
|
||||
Fixed::Y(h - 1, Fill::XY(Align::nw(Thunk::new(|to: &mut TuiOut|{
|
||||
for (_index, port) in self.midi_outs().iter().enumerate() {
|
||||
to.place(&Fixed::Y(1,Fill::X(Bsp::e(
|
||||
Align::w(Bsp::e(" ● ", Tui::fg(Rgb(255,255,255),Tui::bold(true, port.port_name())))),
|
||||
Fill::X(Align::e(format!("{}/{} ",
|
||||
port.port().get_connections().len(),
|
||||
port.connections.len())))))));
|
||||
for (index, conn) in port.connections.iter().enumerate() {
|
||||
to.place(&Fixed::Y(1, Fill::X(Align::w(format!(" c{index:02}{}", conn.info())))));
|
||||
}
|
||||
}
|
||||
})))));
|
||||
Fixed::Y(h, view_track_row_section(theme, list, button_2("O", "+", false),
|
||||
Tui::bg(theme.darker.rgb, Align::w(Fill::X(
|
||||
Thunk::new(|to: &mut TuiOut|{
|
||||
for (index, track, _x1, _x2) in self.tracks_with_sizes() {
|
||||
to.place(&Fixed::X(track_width(index, track),
|
||||
Thunk::new(|to: &mut TuiOut|{
|
||||
to.place(&Fixed::Y(1, Align::w(Bsp::e(
|
||||
Either::new(true, Tui::fg(Green, "play "), "play "),
|
||||
Either::new(false, Tui::fg(Yellow, "solo "), "solo "),
|
||||
))));
|
||||
for (_index, port) in self.midi_outs().iter().enumerate() {
|
||||
to.place(&Fixed::Y(1, Align::w(Bsp::e(
|
||||
Either::new(true, Tui::fg(Green, " ● "), " · "),
|
||||
Either::new(false, Tui::fg(Yellow, " ● "), " · "),
|
||||
))));
|
||||
for (_index, _conn) in port.connections.iter().enumerate() {
|
||||
to.place(&Fixed::Y(1, Fill::X("")));
|
||||
}
|
||||
}})))}}))))))
|
||||
}
|
||||
|
||||
pub fn view_track_devices (&self, theme: ItemTheme) -> impl Content<TuiOut> {
|
||||
let mut h = 2u16;
|
||||
for track in self.tracks().iter() {
|
||||
h = h.max(track.devices.len() as u16 * 2);
|
||||
}
|
||||
view_track_row_section(theme,
|
||||
button_3("d", "evice", format!("{}", self.track().map(|t|t.devices.len()).unwrap_or(0)), false),
|
||||
button_2("D", "+", false),
|
||||
Thunk::new(move|to: &mut TuiOut|for (index, track, _x1, _x2) in self.tracks_with_sizes() {
|
||||
to.place(&Fixed::XY(track_width(index, track), h + 1,
|
||||
Tui::bg(track.color.dark.rgb, Align::nw(Map::south(2, move||0..h,
|
||||
|_, _index|Fixed::XY(track.width as u16, 2,
|
||||
Tui::fg_bg(
|
||||
ItemTheme::G[32].lightest.rgb,
|
||||
ItemTheme::G[32].dark.rgb,
|
||||
Align::nw(format!(" · {}", "--")))))))));
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(feature = "track")]
|
||||
pub fn view_track_row_section (
|
||||
_theme: ItemTheme,
|
||||
button: impl Content<TuiOut>,
|
||||
button_add: impl Content<TuiOut>,
|
||||
content: impl Content<TuiOut>,
|
||||
) -> impl Content<TuiOut> {
|
||||
Bsp::w(Fill::Y(Fixed::X(4, Align::nw(button_add))),
|
||||
Bsp::e(Fixed::X(20, Fill::Y(Align::nw(button))), Fill::XY(Align::c(content))))
|
||||
}
|
||||
|
||||
#[cfg(feature = "scene")]
|
||||
impl Arrangement {
|
||||
/// Get the active scene
|
||||
pub fn get_scene (&self) -> Option<&Scene> {
|
||||
let index = self.selection().scene()?;
|
||||
Has::<Vec<Scene>>::get(self).get(index)
|
||||
}
|
||||
/// Get a mutable reference to the active scene
|
||||
pub fn get_scene_mut (&mut self) -> Option<&mut Scene> {
|
||||
let index = self.selection().scene()?;
|
||||
Has::<Vec<Scene>>::get_mut(self).get_mut(index)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "scene")]
|
||||
impl ScenesView for Arrangement {
|
||||
fn h_scenes (&self) -> u16 {
|
||||
(self.height() as u16).saturating_sub(20)
|
||||
}
|
||||
fn w_side (&self) -> u16 {
|
||||
(self.width() as u16 * 2 / 10).max(20)
|
||||
}
|
||||
fn w_mid (&self) -> u16 {
|
||||
(self.width() as u16).saturating_sub(2 * self.w_side()).max(40)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clip")]
|
||||
impl Arrangement {
|
||||
/// Get the active clip
|
||||
pub fn get_clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||
self.get_scene()?.clips.get(self.selection().track()?)?.clone()
|
||||
}
|
||||
/// Put a clip in a slot
|
||||
pub fn clip_put (
|
||||
&mut self, track: usize, scene: usize, clip: Option<Arc<RwLock<MidiClip>>>
|
||||
) -> Option<Arc<RwLock<MidiClip>>> {
|
||||
let old = self.scenes[scene].clips[track].clone();
|
||||
self.scenes[scene].clips[track] = clip;
|
||||
old
|
||||
}
|
||||
/// Change the color of a clip, returning the previous one
|
||||
pub fn clip_set_color (&self, track: usize, scene: usize, color: ItemTheme)
|
||||
-> Option<ItemTheme>
|
||||
{
|
||||
self.scenes[scene].clips[track].as_ref().map(|clip|{
|
||||
let mut clip = clip.write().unwrap();
|
||||
let old = clip.color.clone();
|
||||
clip.color = color.clone();
|
||||
panic!("{color:?} {old:?}");
|
||||
old
|
||||
})
|
||||
}
|
||||
/// Toggle looping for the active clip
|
||||
pub fn toggle_loop (&mut self) {
|
||||
if let Some(clip) = self.get_clip() {
|
||||
clip.write().unwrap().toggle_loop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sampler")]
|
||||
impl Arrangement {
|
||||
/// Get the first sampler of the active track
|
||||
pub fn sampler (&self) -> Option<&Sampler> {
|
||||
self.get_track()?.sampler(0)
|
||||
}
|
||||
/// Get the first sampler of the active track
|
||||
pub fn sampler_mut (&mut self) -> Option<&mut Sampler> {
|
||||
self.get_track_mut()?.sampler_mut(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn wrap (bg: Color, fg: Color, content: impl Content<TuiOut>) -> impl Content<TuiOut> {
|
||||
let left = Tui::fg_bg(bg, Reset, Fixed::X(1, RepeatV("▐")));
|
||||
let right = Tui::fg_bg(bg, Reset, Fixed::X(1, RepeatV("▌")));
|
||||
Bsp::e(left, Bsp::w(right, Tui::fg_bg(fg, bg, content)))
|
||||
}
|
||||
|
||||
pub trait HasClipsSize {
|
||||
fn clips_size (&self) -> &Measure<TuiOut>;
|
||||
}
|
||||
|
||||
impl HasClipsSize for Arrangement {
|
||||
fn clips_size (&self) -> &Measure<TuiOut> { &self.size_inner }
|
||||
}
|
||||
|
||||
pub trait HasWidth {
|
||||
const MIN_WIDTH: usize;
|
||||
/// Increment track width.
|
||||
fn width_inc (&mut self);
|
||||
/// Decrement track width, down to a hardcoded minimum of [Self::MIN_WIDTH].
|
||||
fn width_dec (&mut self);
|
||||
}
|
||||
|
||||
//def_command!(ArrangementCommand: |arranger: Arrangement| {
|
||||
|
||||
//Home => { arranger.editor = None; Ok(None) },
|
||||
|
||||
//Edit => {
|
||||
//let selection = arranger.selection().clone();
|
||||
//arranger.editor = if arranger.editor.is_some() {
|
||||
//None
|
||||
//} else {
|
||||
//match selection {
|
||||
//Selection::TrackClip { track, scene } => {
|
||||
//let clip = &mut arranger.scenes_mut()[scene].clips[track];
|
||||
//if clip.is_none() {
|
||||
////app.clip_auto_create();
|
||||
//*clip = Some(Arc::new(RwLock::new(MidiClip::new(
|
||||
//&format!("t{track:02}s{scene:02}"),
|
||||
//false, 384, None, Some(ItemTheme::random())
|
||||
//))));
|
||||
//}
|
||||
//clip.as_ref().map(|c|c.into())
|
||||
//}
|
||||
//_ => {
|
||||
//None
|
||||
//}
|
||||
//}
|
||||
//};
|
||||
//if let Some(editor) = arranger.editor.as_mut() {
|
||||
//if let Some(clip) = editor.clip() {
|
||||
//let length = clip.read().unwrap().length.max(1);
|
||||
//let width = arranger.size_inner.w().saturating_sub(20).max(1);
|
||||
//editor.set_time_zoom(length / width);
|
||||
//editor.redraw();
|
||||
//}
|
||||
//}
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
////// Set the selection
|
||||
//Select { selection: Selection } => { *arranger.selection_mut() = *selection; Ok(None) },
|
||||
|
||||
////// Launch the selected clip or scene
|
||||
//Launch => {
|
||||
//match *arranger.selection() {
|
||||
//Selection::Track(t) => {
|
||||
//arranger.tracks[t].sequencer.enqueue_next(None)
|
||||
//},
|
||||
//Selection::TrackClip { track, scene } => {
|
||||
//arranger.tracks[track].sequencer.enqueue_next(arranger.scenes[scene].clips[track].as_ref())
|
||||
//},
|
||||
//Selection::Scene(s) => {
|
||||
//for t in 0..arranger.tracks.len() {
|
||||
//arranger.tracks[t].sequencer.enqueue_next(arranger.scenes[s].clips[t].as_ref())
|
||||
//}
|
||||
//},
|
||||
//_ => {}
|
||||
//};
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
////// Set the color of the selected entity
|
||||
//SetColor { palette: Option<ItemTheme> } => {
|
||||
//let mut palette = palette.unwrap_or_else(||ItemTheme::random());
|
||||
//let selection = *arranger.selection();
|
||||
//Ok(Some(Self::SetColor { palette: Some(match selection {
|
||||
//Selection::Mix => {
|
||||
//std::mem::swap(&mut palette, &mut arranger.color);
|
||||
//palette
|
||||
//},
|
||||
//Selection::Scene(s) => {
|
||||
//std::mem::swap(&mut palette, &mut arranger.scenes[s].color);
|
||||
//palette
|
||||
//}
|
||||
//Selection::Track(t) => {
|
||||
//std::mem::swap(&mut palette, &mut arranger.tracks[t].color);
|
||||
//palette
|
||||
//}
|
||||
//Selection::TrackClip { track, scene } => {
|
||||
//if let Some(ref clip) = arranger.scenes[scene].clips[track] {
|
||||
//let mut clip = clip.write().unwrap();
|
||||
//std::mem::swap(&mut palette, &mut clip.color);
|
||||
//palette
|
||||
//} else {
|
||||
//return Ok(None)
|
||||
//}
|
||||
//},
|
||||
//_ => todo!()
|
||||
//}) }))
|
||||
//},
|
||||
|
||||
//Track { track: TrackCommand } => { todo!("delegate") },
|
||||
|
||||
//TrackAdd => {
|
||||
//let index = arranger.track_add(None, None, &[], &[])?.0;
|
||||
//*arranger.selection_mut() = match arranger.selection() {
|
||||
//Selection::Track(_) => Selection::Track(index),
|
||||
//Selection::TrackClip { track: _, scene } => Selection::TrackClip {
|
||||
//track: index, scene: *scene
|
||||
//},
|
||||
//_ => *arranger.selection()
|
||||
//};
|
||||
//Ok(Some(Self::TrackDelete { index }))
|
||||
//},
|
||||
|
||||
//TrackSwap { index: usize, other: usize } => {
|
||||
//let index = *index;
|
||||
//let other = *other;
|
||||
//Ok(Some(Self::TrackSwap { index, other }))
|
||||
//},
|
||||
|
||||
//TrackDelete { index: usize } => {
|
||||
//let index = *index;
|
||||
//let exists = arranger.tracks().get(index).is_some();
|
||||
//if exists {
|
||||
//let track = arranger.tracks_mut().remove(index);
|
||||
//let Track { sequencer: Sequencer { midi_ins, midi_outs, .. }, .. } = track;
|
||||
//for port in midi_ins.into_iter() {
|
||||
//port.close()?;
|
||||
//}
|
||||
//for port in midi_outs.into_iter() {
|
||||
//port.close()?;
|
||||
//}
|
||||
//for scene in arranger.scenes_mut().iter_mut() {
|
||||
//scene.clips.remove(index);
|
||||
//}
|
||||
//}
|
||||
//Ok(None)
|
||||
////TODO:Ok(Some(Self::TrackAdd ( index, track: Some(deleted_track) })
|
||||
//},
|
||||
|
||||
//MidiIn { input: MidiInputCommand } => {
|
||||
//todo!("delegate"); Ok(None)
|
||||
//},
|
||||
|
||||
//MidiInAdd => {
|
||||
//arranger.midi_in_add()?;
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//MidiOut { output: MidiOutputCommand } => {
|
||||
//todo!("delegate");
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//MidiOutAdd => {
|
||||
//arranger.midi_out_add()?;
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//Device { command: DeviceCommand } => {
|
||||
//todo!("delegate");
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//DeviceAdd { index: usize } => {
|
||||
//todo!("delegate");
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//Scene { scene: SceneCommand } => {
|
||||
//todo!("delegate");
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//OutputAdd => {
|
||||
//arranger.midi_outs.push(MidiOutput::new(
|
||||
//arranger.jack(),
|
||||
//&format!("/M{}", arranger.midi_outs.len() + 1),
|
||||
//&[]
|
||||
//)?);
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//InputAdd => {
|
||||
//arranger.midi_ins.push(MidiInput::new(
|
||||
//arranger.jack(),
|
||||
//&format!("M{}/", arranger.midi_ins.len() + 1),
|
||||
//&[]
|
||||
//)?);
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//SceneAdd => {
|
||||
//let index = arranger.scene_add(None, None)?.0;
|
||||
//*arranger.selection_mut() = match arranger.selection() {
|
||||
//Selection::Scene(_) => Selection::Scene(index),
|
||||
//Selection::TrackClip { track, scene } => Selection::TrackClip {
|
||||
//track: *track,
|
||||
//scene: index
|
||||
//},
|
||||
//_ => *arranger.selection()
|
||||
//};
|
||||
//Ok(None) // TODO
|
||||
//},
|
||||
|
||||
//SceneSwap { index: usize, other: usize } => {
|
||||
//let index = *index;
|
||||
//let other = *other;
|
||||
//Ok(Some(Self::SceneSwap { index, other }))
|
||||
//},
|
||||
|
||||
//SceneDelete { index: usize } => {
|
||||
//let index = *index;
|
||||
//let scenes = arranger.scenes_mut();
|
||||
//Ok(if scenes.get(index).is_some() {
|
||||
//let _scene = scenes.remove(index);
|
||||
//None
|
||||
//} else {
|
||||
//None
|
||||
//})
|
||||
//},
|
||||
|
||||
//SceneLaunch { index: usize } => {
|
||||
//let index = *index;
|
||||
//for track in 0..arranger.tracks.len() {
|
||||
//let clip = arranger.scenes[index].clips[track].as_ref();
|
||||
//arranger.tracks[track].sequencer.enqueue_next(clip);
|
||||
//}
|
||||
//Ok(None)
|
||||
//},
|
||||
|
||||
//Clip { scene: ClipCommand } => {
|
||||
//todo!("delegate")
|
||||
//},
|
||||
|
||||
//ClipGet { a: usize, b: usize } => {
|
||||
////(Get [a: usize, b: usize] cmd_todo!("\n\rtodo: clip: get: {a} {b}"))
|
||||
////("get" [a: usize, b: usize] Some(Self::Get(a.unwrap(), b.unwrap())))
|
||||
//todo!()
|
||||
//},
|
||||
|
||||
//ClipPut { a: usize, b: usize } => {
|
||||
////(Put [t: usize, s: usize, c: MaybeClip]
|
||||
////Some(Self::Put(t, s, arranger.clip_put(t, s, c))))
|
||||
////("put" [a: usize, b: usize, c: MaybeClip] Some(Self::Put(a.unwrap(), b.unwrap(), c.unwrap())))
|
||||
//todo!()
|
||||
//},
|
||||
|
||||
//ClipDel { a: usize, b: usize } => {
|
||||
////("delete" [a: usize, b: usize] Some(Self::Put(a.unwrap(), b.unwrap(), None))))
|
||||
//todo!()
|
||||
//},
|
||||
|
||||
//ClipEnqueue { a: usize, b: usize } => {
|
||||
////(Enqueue [t: usize, s: usize]
|
||||
////cmd!(arranger.tracks[t].sequencer.enqueue_next(arranger.scenes[s].clips[t].as_ref())))
|
||||
////("enqueue" [a: usize, b: usize] Some(Self::Enqueue(a.unwrap(), b.unwrap())))
|
||||
//todo!()
|
||||
//},
|
||||
|
||||
//ClipSwap { a: usize, b: usize }=> {
|
||||
////(Edit [clip: MaybeClip] cmd_todo!("\n\rtodo: clip: edit: {clip:?}"))
|
||||
////("edit" [a: MaybeClip] Some(Self::Edit(a.unwrap())))
|
||||
//todo!()
|
||||
//},
|
||||
|
||||
//});
|
||||
Loading…
Add table
Add a link
Reference in a new issue