mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
api: compact
This commit is contained in:
parent
e4808f8fc1
commit
3ef3d5eb6f
22 changed files with 441 additions and 558 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue