api: compact

This commit is contained in:
🪞👃🪞 2025-04-26 21:20:06 +03:00
parent e4808f8fc1
commit 3ef3d5eb6f
22 changed files with 441 additions and 558 deletions

View file

@ -7,7 +7,7 @@ pub struct Tek {
/// Source of time
pub clock: Clock,
/// Theme
pub color: ItemPalette,
pub color: ItemTheme,
/// Contains all clips in the project
pub pool: Option<MidiPool>,
/// Contains the currently edited MIDI clip
@ -63,15 +63,15 @@ impl Tek {
&mut self,
count: usize,
width: Option<usize>,
midi_from: &[PortConnect],
midi_to: &[PortConnect],
mins: &[PortConnect],
mouts: &[PortConnect],
) -> Usually<()> {
let jack = self.jack().clone();
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 mut track = self.track_add(None, Some(color), midi_from, midi_to)?.1;
let mut track = self.track_add(None, Some(color), mins, mouts)?.1;
if let Some(width) = width {
track.width = width;
}
@ -82,22 +82,17 @@ impl Tek {
/// Add a track
pub fn track_add (
&mut self,
name: Option<&str>,
color: Option<ItemPalette>,
midi_froms: &[PortConnect],
midi_tos: &[PortConnect],
name: Option<&str>,
color: Option<ItemTheme>,
mins: &[PortConnect],
mouts: &[PortConnect],
) -> Usually<(usize, &mut Track)> {
let name = name.map_or_else(||self.track_next_name(), |x|x.to_string().into());
let mut track = Track {
width: (name.len() + 2).max(12),
color: color.unwrap_or_else(ItemPalette::random),
color: color.unwrap_or_else(ItemTheme::random),
player: MidiPlayer::new(
&format!("{name}"),
self.jack(),
Some(self.clock()),
None,
midi_froms,
midi_tos
&format!("{name}"), self.jack(), Some(self.clock()), None, mins, mouts
)?,
name,
..Default::default()
@ -113,6 +108,17 @@ impl Tek {
Ok((index, &mut self.tracks_mut()[index]))
}
/// Add and focus a track
pub(crate) fn track_add_focus (&mut self) -> Usually<usize> {
let index = self.track_add(None, None, &[], &[])?.0;
self.selected = match self.selected {
Selection::Track(t) => Selection::Track(index),
Selection::Clip(t, s) => Selection::Clip(index, s),
_ => self.selected
};
Ok(index)
}
/// Delete a track
pub fn track_del (&mut self, index: usize) {
self.tracks_mut().remove(index);
@ -134,22 +140,46 @@ impl Tek {
}
/// Add a scene
pub fn scene_add (&mut self, name: Option<&str>, color: Option<ItemPalette>)
pub fn scene_add (&mut self, name: Option<&str>, color: Option<ItemTheme>)
-> Usually<(usize, &mut Scene)>
{
let scene = Scene {
name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()),
clips: vec![None;self.tracks().len()],
color: color.unwrap_or_else(ItemPalette::random),
color: color.unwrap_or_else(ItemTheme::random),
};
self.scenes_mut().push(scene);
let index = self.scenes().len() - 1;
Ok((index, &mut self.scenes_mut()[index]))
}
/// Generate the default name for a new scene
pub fn scene_default_name (&self) -> Arc<str> {
format!("Sc{:3>}", self.scenes().len() + 1).into()
/// Add and focus an empty scene
pub fn scene_add_focus (&mut self) -> Usually<usize> {
let index = self.scene_add(None, None)?.0;
self.selected = match self.selected {
Selection::Scene(s) => Selection::Scene(index),
Selection::Clip(t, s) => Selection::Clip(t, index),
_ => self.selected
};
Ok(index)
}
/// Enqueue clips from a scene across all tracks
pub fn scene_enqueue (&mut self, scene: usize) {
for track in 0..self.tracks.len() {
self.tracks[track].player.enqueue_next(self.scenes[scene].clips[track].as_ref());
}
}
pub fn toggle_editor (&mut self, value: Option<bool>) {
let editing = self.is_editing();
let value = value.unwrap_or_else(||!self.is_editing());
self.editing.store(value, Relaxed);
if value {
self.clip_auto_create();
} else {
self.clip_auto_remove();
}
}
// Create new clip in pool when entering empty cell
@ -194,11 +224,43 @@ impl Tek {
}
}
/// Put a clip in a slot
pub(crate) 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(crate) 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
})
}
/// Get the clip pool, if present
pub(crate) fn pool (&self) -> Option<&MidiPool> {
self.pool.as_ref()
}
/// Get the active clip
pub(crate) fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
self.scene()?.clips.get(self.selected().track()?)?.clone()
}
/// Get the active editor
pub(crate) fn editor (&self) -> Option<&MidiEditor> {
self.editor.as_ref()
}
/// Toggle looping for the active clip
pub(crate) fn toggle_loop (&mut self) {
if let Some(clip) = self.clip() {
@ -206,30 +268,88 @@ impl Tek {
}
}
/// Set the selection
pub(crate) fn select (&mut self, s: Selection) {
self.selected = s;
// autoedit: load focused clip in editor.
if let Some(ref mut editor) = self.editor {
editor.set_clip(match self.selected {
Selection::Clip(t, s) if let Some(Some(Some(clip))) = self
.scenes.get(s).map(|s|s.clips.get(t)) => Some(clip),
_ => None
});
}
}
/// Stop all playing clips
pub(crate) fn stop_all (&mut self) {
for track in 0..self.tracks.len() {
self.tracks[track].player.enqueue_next(None);
}
}
/// Launch a clip or scene
pub(crate) fn activate (&mut self) -> Usually<()> {
let selected = self.selected().clone();
match selected {
Selection::Scene(s) => {
let mut clips = vec![];
for (t, _) in self.tracks().iter().enumerate() {
clips.push(self.scenes()[s].clips[t].clone());
}
for (t, track) in self.tracks_mut().iter_mut().enumerate() {
if track.player.play_clip.is_some() || clips[t].is_some() {
track.player.enqueue_next(clips[t].as_ref());
}
}
if self.clock().is_stopped() {
self.clock().play_from(Some(0))?;
}
pub(crate) fn launch (&mut self) {
match self.selected {
Selection::Track(t) => {
self.tracks[t].player.enqueue_next(None)
},
Selection::Clip(t, s) => {
let clip = self.scenes()[s].clips[t].clone();
self.tracks_mut()[t].player.enqueue_next(clip.as_ref());
self.tracks[t].player.enqueue_next(self.scenes[s].clips[t].as_ref())
},
Selection::Scene(s) => {
for t in 0..self.tracks.len() {
self.tracks[t].player.enqueue_next(self.scenes[s].clips[t].as_ref())
}
},
_ => {}
}
};
}
/// Get the first sampler of the active track
pub fn sampler (&self) -> Option<&Sampler> {
self.tracks.get(0).map(|t|t.sampler(0)).flatten()
}
/// Set the color of the selected entity
pub fn set_color (&mut self, palette: Option<ItemTheme>) -> Option<ItemTheme> {
let palette = palette.unwrap_or_else(||ItemTheme::random());
Some(match self.selected {
Selection::Mix => {
let old = self.color;
self.color = palette;
old
},
Selection::Track(t) => {
let old = self.tracks[t].color;
self.tracks[t].color = palette;
old
}
Selection::Scene(s) => {
let old = self.scenes[s].color;
self.scenes[s].color = palette;
old
}
Selection::Clip(t, s) => {
if let Some(ref clip) = self.scenes[s].clips[t] {
let mut clip = clip.write().unwrap();
let old = clip.color;
clip.color = palette;
old
} else {
return None
}
}
})
}
pub(crate) fn add_midi_in (&mut self) -> Usually<()> {
self.midi_ins.push(JackMidiIn::new(&self.jack, &format!("M/{}", self.midi_ins.len()), &[])?);
Ok(())
}
pub(crate) fn add_midi_out (&mut self) -> Usually<()> {
self.midi_outs.push(JackMidiOut::new(&self.jack, &format!("{}/M", self.midi_outs.len()), &[])?);
Ok(())
}
@ -379,6 +499,17 @@ pub trait HasScenes: HasSelection + HasEditor + Send + Sync {
fn scene_del (&mut self, index: usize) {
self.selected().scene().and_then(|s|Some(self.scenes_mut().remove(index)));
}
/// Set the color of a scene, returning the previous one.
fn scene_set_color (&mut self, index: usize, color: ItemTheme) -> ItemTheme {
let scenes = self.scenes_mut();
let old = scenes[index].color;
scenes[index].color = color;
old
}
/// Generate the default name for a new scene
fn scene_default_name (&self) -> Arc<str> {
format!("Sc{:3>}", self.scenes().len() + 1).into()
}
}
#[derive(Debug, Default)] pub struct Scene {
@ -387,7 +518,7 @@ pub trait HasScenes: HasSelection + HasEditor + Send + Sync {
/// Clips in scene, one per track
pub clips: Vec<Option<Arc<RwLock<MidiClip>>>>,
/// Identifying color of scene
pub color: ItemPalette,
pub color: ItemTheme,
}
impl Scene {
@ -443,6 +574,27 @@ pub trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync
fn track_mut (&mut self) -> Option<&mut Track> {
self.selected().track().and_then(|s|self.tracks_mut().get_mut(s))
}
/// Set the color of a track
fn track_set_color (&mut self, index: usize, color: ItemTheme) -> ItemTheme {
let tracks = self.tracks_mut();
let old = tracks[index].color;
tracks[index].color = color;
old
}
/// Toggle track recording
fn track_toggle_record (&mut self) {
if let Some(t) = self.selected().track() {
let tracks = self.tracks_mut();
tracks[t-1].player.recording = !tracks[t-1].player.recording;
}
}
/// Toggle track monitoring
fn track_toggle_monitor (&mut self) {
if let Some(t) = self.selected().track() {
let tracks = self.tracks_mut();
tracks[t-1].player.monitoring = !tracks[t-1].player.monitoring;
}
}
}
#[derive(Debug, Default)] pub struct Track {
@ -451,7 +603,7 @@ pub trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync
/// Preferred width of track column
pub width: usize,
/// Identifying color of track
pub color: ItemPalette,
pub color: ItemTheme,
/// MIDI player state
pub player: MidiPlayer,
/// Device chain