mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-10-08 18:56:42 +02:00
tek_has
This commit is contained in:
parent
0a89fab28a
commit
9e3cc1139d
18 changed files with 450 additions and 414 deletions
204
src/tek_ctrl.rs
204
src/tek_ctrl.rs
|
|
@ -4,8 +4,6 @@ impl_from!(AppCmd: |x: AxisCmd| AppCmd::Axis { command: x });
|
|||
impl_from!(AppCmd: |x: BrowseCmd| AppCmd::Browse { command: x });
|
||||
impl_from!(AppCmd: |x: MidiClipCmd| AppCmd::MidiClip { command: x });
|
||||
impl_from!(AppCmd: |x: MidiEditCmd| AppCmd::MidiEdit { command: x });
|
||||
impl_from!(AppCmd: |x: ModeCmd| AppCmd::Mode { command: x });
|
||||
//impl_from!(AppCmd: |x: PoolCmd| AppCmd::Pool { command: x });
|
||||
impl_from!(AppCmd: |x: ProjectCmd| AppCmd::Project { command: x });
|
||||
impl_from!(AppCmd: |x: SceneCmd| AppCmd::Scene { command: x });
|
||||
impl_from!(AppCmd: |x: ScenesCmd| AppCmd::Scenes { command: x });
|
||||
|
|
@ -18,6 +16,25 @@ impl_from!(AppCmd: |x: TracksCmd| AppCmd::Tracks { command: x });
|
|||
self.exit.exit();
|
||||
Ok(None)
|
||||
}
|
||||
/// Switch to another set of contextual modes.
|
||||
#[command(Mode = "mode")] pub fn cmd_mode (&mut self, modes: Vec<Arc<str>>) -> Perhaps<AppCmd> {
|
||||
*self.modes_mut() = modes.into();
|
||||
Ok(None)
|
||||
}
|
||||
/// Enter a contextual mode.
|
||||
#[command(Enter = "enter")] pub fn cmd_mode_enter (&mut self, mode: Arc<str>) -> Perhaps<AppCmd> {
|
||||
self.modes_mut().push(mode);
|
||||
Ok(Some(AppCmd::Leave))
|
||||
}
|
||||
/// Leave a contextual mode.
|
||||
#[command(Leave = "leave")] fn cmd_mode_leave (&mut self) -> Perhaps<AppCmd> {
|
||||
let mode = self.modes_mut().pop();
|
||||
Ok(mode.map(|mode|AppCmd::Enter { mode }))
|
||||
}
|
||||
/// Navigate along a contextual axis.
|
||||
#[command(Axis = "axis")] pub fn cmd_axis (&mut self, command: AxisCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
/// Cancel current selection.
|
||||
#[command(Cancel = "cancel")] pub fn cmd_cancel (&mut self) -> Perhaps<AppCmd> {
|
||||
todo!("cancel")
|
||||
|
|
@ -44,27 +61,22 @@ impl_from!(AppCmd: |x: TracksCmd| AppCmd::Tracks { command: x });
|
|||
std::mem::swap(&mut self.dialog, &mut dialog);
|
||||
Ok(Some(AppCmd::Dialog { dialog }))
|
||||
}
|
||||
#[command(Mode = "mode")] pub fn cmd_mode (&mut self, command: ModeCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
#[command(Project = "session")] pub fn cmd_session (&mut self, command: ProjectCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
#[command(Axis = "axis")] pub fn cmd_axis (&mut self, command: AxisCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
/// Command the file browser.
|
||||
#[command(Browse = "browse")] pub fn cmd_browse (&mut self, command: BrowseCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
/// Commands that alter the current session.
|
||||
#[command(Project = "session")] pub fn cmd_session (&mut self, command: ProjectCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
/// Commands pertaining to MIDI clips.
|
||||
#[command(MidiClip = "clip")] pub fn cmd_midi_clip (&mut self, command: MidiClipCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
/// Commands pertaining to the MIDI clip editor.
|
||||
#[command(MidiEdit = "edit")] pub fn cmd_midi_edit (&mut self, command: MidiEditCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
//#[command(Pool = "pool")] pub fn cmd_pool (&mut self, command: PoolCmd) -> Perhaps<AppCmd> {
|
||||
//Ok(command.dispatch(self)?.map(Into::into))
|
||||
//}
|
||||
#[command(Scene = "scene")] pub fn cmd_scene (&mut self, command: SceneCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
|
|
@ -77,6 +89,9 @@ impl_from!(AppCmd: |x: TracksCmd| AppCmd::Tracks { command: x });
|
|||
#[command(Tracks = "tracks")] pub fn cmd_tracks (&mut self, command: TracksCmd) -> Perhaps<AppCmd> {
|
||||
Ok(command.dispatch(self)?.map(Into::into))
|
||||
}
|
||||
//#[command(Pool = "pool")] pub fn cmd_pool (&mut self, command: PoolCmd) -> Perhaps<AppCmd> {
|
||||
//Ok(command.dispatch(self)?.map(Into::into))
|
||||
//}
|
||||
}
|
||||
|
||||
impl<T: HasProject> ProjectControl for T {}
|
||||
|
|
@ -142,29 +157,17 @@ impl<T> ClockControl for T where T: HasClock
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: HasTracks
|
||||
impl<T> TracksControl for T where T: HasTracks
|
||||
+ HasScenes
|
||||
+ HasSelection
|
||||
+ HasJack<'static>
|
||||
+ Namespace<usize>
|
||||
+ Namespace<Arc<[Connect]>>
|
||||
+ Namespace<Option<usize>>
|
||||
+ Namespace<Option<Arc<str>>>
|
||||
+ Namespace<Option<ItemTheme>>
|
||||
+ Namespace<Option<Arc<[Connect]>>>
|
||||
+ Namespace<ClipPool>
|
||||
> TracksControl for T {}
|
||||
{}
|
||||
|
||||
#[tek_proc::commands(TracksCmd)] pub trait TracksControl: HasTracks
|
||||
+ HasScenes
|
||||
+ HasSelection
|
||||
+ HasJack<'static>
|
||||
+ Namespace<usize>
|
||||
+ Namespace<Arc<[Connect]>>
|
||||
+ Namespace<Option<usize>>
|
||||
+ Namespace<Option<Arc<str>>>
|
||||
+ Namespace<Option<ItemTheme>>
|
||||
+ Namespace<Option<Arc<[Connect]>>>
|
||||
+ Namespace<ClipPool>
|
||||
{
|
||||
/// Stop all playing clips
|
||||
|
|
@ -190,7 +193,7 @@ impl<T: HasTracks
|
|||
Ok(None)
|
||||
}
|
||||
#[command(Add = "add")] fn tracks_add (&mut self) -> Perhaps<TracksCmd>
|
||||
where Self: HasScenes + HasJack<'static>
|
||||
where Self: HasScenes + HasJack<'static> + Sized
|
||||
{
|
||||
let (_index, _) = self.tracks_add_one(None, None, [].into(), [].into())?;
|
||||
Ok(None)
|
||||
|
|
@ -212,6 +215,76 @@ impl<T: HasTracks
|
|||
*self.selection_mut() = select;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Run audio callbacks for every track and every device
|
||||
fn tracks_jack_process (&mut self, client: &Client, scope: &ProcessScope) -> Control
|
||||
where Self: HasJack<'static>
|
||||
{
|
||||
for track in self.tracks_mut().iter_mut() {
|
||||
if Control::Quit == Audio::process(&mut track.sequencer, client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
for device in track.devices.iter_mut() {
|
||||
if Control::Quit == DeviceAudio(device).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
}
|
||||
}
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
/// Add multiple tracks
|
||||
fn tracks_add_many (
|
||||
&mut self,
|
||||
count: usize,
|
||||
width: Option<usize>,
|
||||
mins: Arc<[Connect]>,
|
||||
mouts: Arc<[Connect]>,
|
||||
) -> Usually<()>
|
||||
where Self: HasJack<'static> + HasScenes
|
||||
{
|
||||
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.tracks_add_one(None, Some(color), mins.clone(), mouts.clone())?.1;
|
||||
if let Some(width) = width {
|
||||
track.width = width;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a track
|
||||
fn tracks_add_one (
|
||||
&mut self,
|
||||
name: Option<Arc<str>>,
|
||||
color: Option<ItemTheme>,
|
||||
mins: Arc<[Connect]>,
|
||||
mouts: Arc<[Connect]>,
|
||||
) -> Usually<(usize, &mut Track)>
|
||||
where Self: HasJack<'static> + HasScenes
|
||||
{
|
||||
let name: Arc<str> = name.map_or_else(
|
||||
||format!("trk{}", self.tracks_last()).into(),
|
||||
|x|x.to_string().into()
|
||||
);
|
||||
*self.tracks_last_mut() += 1;
|
||||
let track = Track::new_added(self.jack(), Some(self.clock()), &name, color, None, mins, mouts)?;
|
||||
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.append(None);
|
||||
}
|
||||
}
|
||||
Ok((index, &mut self.tracks_mut()[index]))
|
||||
}
|
||||
|
||||
fn track_longest_name (&self) -> usize {
|
||||
self.tracks().iter().map(|s|s.name.len()).fold(0, usize::max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HasTrack
|
||||
|
|
@ -283,9 +356,6 @@ impl<T: HasScenes
|
|||
+ HasTrackScroll
|
||||
+ HasSelection
|
||||
+ HasJack<'static>
|
||||
+ Namespace<usize>
|
||||
+ Namespace<Option<ItemTheme>>
|
||||
+ Namespace<Option<Arc<str>>>
|
||||
> ScenesControl for T {}
|
||||
|
||||
#[tek_proc::commands(ScenesCmd)] pub trait ScenesControl: HasScenes
|
||||
|
|
@ -293,11 +363,8 @@ impl<T: HasScenes
|
|||
+ HasTrackScroll
|
||||
+ HasSelection
|
||||
+ HasJack<'static>
|
||||
+ Namespace<usize>
|
||||
+ Namespace<Option<ItemTheme>>
|
||||
+ Namespace<Option<Arc<str>>>
|
||||
{
|
||||
#[command(Add = "add")] fn scenes_add (&mut self) -> Perhaps<ScenesCmd> {
|
||||
#[command(Add = "add")] fn scenes_add (&mut self) -> Perhaps<ScenesCmd> where Self: Sized {
|
||||
let (_index, _) = self.scenes_add_one(None, None)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -318,6 +385,41 @@ impl<T: HasScenes
|
|||
*self.selection_mut() = select;
|
||||
Ok(None)
|
||||
}
|
||||
/// Generate the default name for a new scene
|
||||
fn scenes_default_name (&self) -> Arc<str> {
|
||||
format!("s{:3>}", self.scenes().len() + 1).into()
|
||||
}
|
||||
fn scenes_longest_name (&self) -> usize {
|
||||
self.scenes().iter().map(|s|s.name.len()).fold(0, usize::max)
|
||||
}
|
||||
/// Add multiple scenes
|
||||
fn scenes_add_many (&mut self, n: usize)
|
||||
-> Usually<()> where Self: HasTracks
|
||||
{
|
||||
let scene_color_1 = ItemColor::random();
|
||||
let scene_color_2 = ItemColor::random();
|
||||
for i in 0..n {
|
||||
let _ = self.scenes_add_one(None, Some(
|
||||
scene_color_1.mix(scene_color_2, i as f32 / n as f32).into()
|
||||
))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Add a scene
|
||||
fn scenes_add_one (&mut self, name: Option<Arc<str>>, color: Option<ItemTheme>)
|
||||
-> Usually<(usize, &mut Scene)>
|
||||
where
|
||||
Self: HasTracks
|
||||
{
|
||||
let scene = Scene {
|
||||
name: name.map_or_else(||self.scenes_default_name(), |x|x.to_string().into()),
|
||||
clips: Pool::from(vec![None;self.tracks().len()]),
|
||||
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]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HasScene
|
||||
|
|
@ -721,36 +823,6 @@ impl<T: HasClip + HasEditor
|
|||
////}
|
||||
//}
|
||||
|
||||
impl<T> ModeControl for T where T: HasModeStack
|
||||
+ Namespace<Vec<Arc<str>>> + Namespace<Arc<str>> + Namespace<usize>
|
||||
{}
|
||||
#[tek_proc::commands(ModeCmd)] pub trait ModeControl: HasModeStack
|
||||
+ Namespace<Vec<Arc<str>>> + Namespace<Arc<str>> + Namespace<usize>
|
||||
{
|
||||
#[command(Reset = "reset")] fn mode_reset (&mut self, modes: Vec<Arc<str>>) -> Perhaps<ModeCmd> {
|
||||
*self.modes_mut() = modes.into();
|
||||
Ok(None)
|
||||
}
|
||||
#[command(Push = "push")] fn mode_push (&mut self, mode: Arc<str>) -> Perhaps<ModeCmd> {
|
||||
self.modes_mut().push(mode);
|
||||
Ok(Some(ModeCmd::Pop))
|
||||
}
|
||||
#[command(Pop = "pop")] fn mode_pop (&mut self) -> Perhaps<ModeCmd> {
|
||||
let mode = self.modes_mut().pop();
|
||||
Ok(mode.map(|mode|ModeCmd::Push { mode }))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasClip {
|
||||
fn clip (&self) -> Option<ArcRwLockReadGuard<RawRwLock, Option<Arc<RwLock<MidiClip>>>>> {
|
||||
self.clip_slot().map(|slot|slot.read())
|
||||
}
|
||||
fn clip_mut (&self) -> Option<ArcRwLockWriteGuard<RawRwLock, Option<Arc<RwLock<MidiClip>>>>> {
|
||||
self.clip_slot().map(|slot|slot.write())
|
||||
}
|
||||
fn clip_slot (&self) -> Option<Slot<MidiClip>>;
|
||||
}
|
||||
|
||||
impl<T> MidiClipControl for T where T: HasClip
|
||||
+ Namespace<Option<bool>> + Namespace<Option<ItemTheme>> {}
|
||||
#[tek_proc::commands(MidiClipCmd)] pub trait MidiClipControl: HasClip
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue