mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-10-08 18:56:42 +02:00
SlotExt::map_inner(_mut); HasClip::clip_mut
This commit is contained in:
parent
ca774cca41
commit
fdee3fbfc8
7 changed files with 214 additions and 168 deletions
|
|
@ -28,7 +28,10 @@ pub trait HasPlayClip: HasClock {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enqueue_next (&mut self, clip: Option<&Arc<RwLock<MidiClip>>>) {
|
fn enqueue_next (&mut self, clip: Option<&Arc<RwLock<MidiClip>>>) {
|
||||||
*self.next_clip_mut() = Some((self.clock().next_launch_instant(), clip.cloned()));
|
*self.next_clip_mut() = Some((
|
||||||
|
self.clock().next_launch_instant(),
|
||||||
|
clip.cloned()
|
||||||
|
));
|
||||||
*self.reset_mut() = true;
|
*self.reset_mut() = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
141
src/proj.rs
141
src/proj.rs
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
impl_as_ref!(Option<Project>: |self: App|todo!());
|
|
||||||
impl_as_mut!(Option<Project>: |self: App|todo!());
|
|
||||||
pub trait HasProject: AsRef<Option<Project>> + AsMut<Option<Project>> {}
|
pub trait HasProject: AsRef<Option<Project>> + AsMut<Option<Project>> {}
|
||||||
impl<T: AsRef<Option<Project>> + AsMut<Option<Project>>> HasProject for T {}
|
impl<T: AsRef<Option<Project>> + AsMut<Option<Project>>> HasProject for T {}
|
||||||
/// Arranger.
|
/// Arranger.
|
||||||
|
|
@ -117,21 +115,18 @@ impl_as_ref_opt!(Scene: |self: Project| self.selected_scene());
|
||||||
impl_as_mut_opt!(Scene: |self: Project| self.selected_scene_mut());
|
impl_as_mut_opt!(Scene: |self: Project| self.selected_scene_mut());
|
||||||
impl_as_ref!(Option<MidiEditor>: |self: Project| &self.editor);
|
impl_as_ref!(Option<MidiEditor>: |self: Project| &self.editor);
|
||||||
impl_as_mut!(Option<MidiEditor>: |self: Project| &mut self.editor);
|
impl_as_mut!(Option<MidiEditor>: |self: Project| &mut self.editor);
|
||||||
//impl HasClip for Project {
|
impl HasClip for Project {
|
||||||
//fn clip (&self) -> Option<RwLockReadGuard<'_, Option<Arc<RwLock<MidiClip>>>>> {
|
fn clip_slot (&self) -> Option<Slot<MidiClip>> {
|
||||||
//match self.selection {
|
match self.selection {
|
||||||
//Selection::Pool(index) =>
|
Selection::Clip(index) =>
|
||||||
//self.clips.read(index),
|
Some(self.clips.slot(index)),
|
||||||
//Selection::TrackClip { track, scene } if let Some(scene) = self.scenes.get(scene) =>
|
Selection::TrackClip { track, scene } if let Some(scene) = self.scenes.get(scene) =>
|
||||||
//scene.clips.read(track),
|
Some(scene.clips.slot(track)),
|
||||||
//_ =>
|
_ =>
|
||||||
//None
|
None
|
||||||
//}
|
}
|
||||||
//}
|
}
|
||||||
//fn clip_mut (&self) -> RwLockWriteGuard<'_, Option<Arc<RwLock<MidiClip>>>> {
|
}
|
||||||
//self.as_ref().0.write()
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
pub fn swap_value <T: Clone + PartialEq, U> (
|
pub fn swap_value <T: Clone + PartialEq, U> (
|
||||||
target: &mut T, value: &T, returned: impl Fn(T)->U
|
target: &mut T, value: &T, returned: impl Fn(T)->U
|
||||||
) -> Perhaps<U> {
|
) -> Perhaps<U> {
|
||||||
|
|
@ -154,118 +149,6 @@ pub fn toggle_bool <U> (
|
||||||
Ok(Some(returned(Some(value))))
|
Ok(Some(returned(Some(value))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Default, Debug)] pub struct Slot<T>(pub Arc<RwLock<Option<Arc<RwLock<T>>>>>);
|
|
||||||
pub type SampleSlot = Slot<Sample>;
|
|
||||||
pub type ClipSlot = Slot<MidiClip>;
|
|
||||||
impl<T> Clone for Slot<T> { fn clone (&self) -> Self { Slot(self.0.clone()) } }
|
|
||||||
impl<T> Slot<T> {
|
|
||||||
pub fn new (value: impl Into<Option<T>>) -> Self {
|
|
||||||
Self(Arc::new(RwLock::new(value.into().map(|value|Arc::new(RwLock::new(value))))))
|
|
||||||
}
|
|
||||||
pub fn read (&self) -> ArcRwLockReadGuard<RawRwLock, Option<Arc<RwLock<T>>>> {
|
|
||||||
self.0.read_arc()
|
|
||||||
}
|
|
||||||
pub fn write (&self) -> ArcRwLockWriteGuard<RawRwLock, Option<Arc<RwLock<T>>>> {
|
|
||||||
self.0.write_arc()
|
|
||||||
}
|
|
||||||
pub fn set_to (&mut self, value: Self) {
|
|
||||||
self.0 = value.0;
|
|
||||||
}
|
|
||||||
pub fn set (&self, value: Option<T>) -> Option<Arc<RwLock<T>>> {
|
|
||||||
let mut value = value.map(|value|Arc::new(RwLock::new(value)));
|
|
||||||
std::mem::swap(&mut*self.0.write(), &mut value);
|
|
||||||
value
|
|
||||||
}
|
|
||||||
pub fn map_inner <U> (&self, cb: impl FnOnce(&T)->U) -> Option<U> {
|
|
||||||
self.read().as_ref().map(|x|cb(&*x.read()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Slot<MidiClip> {
|
|
||||||
pub fn eval <'a> (state: &App, src: impl Language) -> Perhaps<ClipSlot> {
|
|
||||||
eval_word(src, |word|Ok(match word {
|
|
||||||
|
|
||||||
":selected" if let Selection::TrackClip { track, scene } = state.selection() => {
|
|
||||||
state.scenes()[*scene].clips.slot(*track)
|
|
||||||
},
|
|
||||||
|
|
||||||
//":selected-or-create" if let Selection::TrackClip {
|
|
||||||
//track, scene
|
|
||||||
//} = state.selection() => Some(if let Some(Some(clip)) = state.scenes()[*scene].clips.get(*track) {
|
|
||||||
//clip.clone()
|
|
||||||
//} else {
|
|
||||||
//let clip: Arc<RwLock<MidiClip>> = Arc::new(RwLock::new(Default::default()));
|
|
||||||
//state.scenes()[*scene].clips[*track] = Some(clip.clone());
|
|
||||||
//clip
|
|
||||||
//}),
|
|
||||||
|
|
||||||
_ => return err!("not a clip: {word}")
|
|
||||||
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Slot<Sample> {
|
|
||||||
pub fn eval <'a> (_: &App, _: impl Language) -> Perhaps<SampleSlot> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Default, Debug)] pub struct Pool<T>(pub Arc<RwLock<Vec<Slot<T>>>>);
|
|
||||||
impl<T> Clone for Pool<T> { fn clone (&self) -> Self { Pool(self.0.clone()) } }
|
|
||||||
pub type SamplePool = Pool<Sample>;
|
|
||||||
pub type ClipPool = Pool<MidiClip>;
|
|
||||||
impl<T> Pool<T> {
|
|
||||||
pub fn slot (&self, index: usize) -> Slot<T> {
|
|
||||||
let mut state = self.0.write();
|
|
||||||
while index >= state.len() {
|
|
||||||
state.push(Slot::new(None));
|
|
||||||
}
|
|
||||||
state[index].clone()
|
|
||||||
}
|
|
||||||
pub fn delete (&self, index: usize) -> Option<Arc<RwLock<T>>> {
|
|
||||||
let mut none = None;
|
|
||||||
let mut slot = self.slot(index).write();
|
|
||||||
std::mem::swap(&mut none, &mut slot);
|
|
||||||
none
|
|
||||||
}
|
|
||||||
pub fn len (&self) -> usize {
|
|
||||||
self.0.read().len()
|
|
||||||
}
|
|
||||||
pub fn get (&self, index: usize) -> Option<ArcRwLockReadGuard<RawRwLock, Option<Arc<RwLock<T>>>>> {
|
|
||||||
self.0.read_arc().get(index).map(|clip|clip.read())
|
|
||||||
}
|
|
||||||
pub fn set (&self, index: usize, value: Option<T>) {
|
|
||||||
self.write()[index] = Slot::new(value);
|
|
||||||
}
|
|
||||||
pub fn read (&self) -> ArcRwLockReadGuard<RawRwLock, Vec<Slot<T>>> {
|
|
||||||
self.0.read_arc()
|
|
||||||
}
|
|
||||||
pub fn write (&self) -> ArcRwLockWriteGuard<RawRwLock, Vec<Slot<T>>> {
|
|
||||||
self.0.write_arc()
|
|
||||||
}
|
|
||||||
pub fn append (&self, value: Option<T>) -> Slot<T> {
|
|
||||||
let slot = Slot::new(value);
|
|
||||||
self.0.write().push(slot.clone());
|
|
||||||
slot
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Pool<MidiClip> {
|
|
||||||
pub fn eval <'a> (_: &App, _: impl Language) -> Perhaps<ClipPool> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
pub fn remove (&self, filter: &MidiClip) {
|
|
||||||
let iter = self.0.write();
|
|
||||||
iter.retain(|x|if let Some(x) = &*x.0.read() { x!=filter } else { true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Pool<Sample> {
|
|
||||||
pub fn eval <'a> (_: &App, _: impl Language) -> Perhaps<SamplePool> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T> From<Vec<Option<T>>> for Pool<T> {
|
|
||||||
fn from (values: Vec<Option<T>>) -> Self {
|
|
||||||
Self(Arc::new(RwLock::new(values.into_iter().map(Slot::new).collect())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Modes for clip pool
|
/// Modes for clip pool
|
||||||
#[derive(Debug, Clone)] pub enum PoolMode {
|
#[derive(Debug, Clone)] pub enum PoolMode {
|
||||||
/// Renaming a pattern
|
/// Renaming a pattern
|
||||||
|
|
|
||||||
|
|
@ -51,14 +51,14 @@ pub enum Selection {
|
||||||
Input(usize),
|
Input(usize),
|
||||||
/// A MIDI output is selected.
|
/// A MIDI output is selected.
|
||||||
Output(usize),
|
Output(usize),
|
||||||
|
/// A clip is selected.
|
||||||
|
Clip(usize),
|
||||||
|
/// A sample is selected.
|
||||||
|
Sample(usize),
|
||||||
/// A scene is selected.
|
/// A scene is selected.
|
||||||
#[cfg(feature = "scene")] Scene(usize),
|
#[cfg(feature = "scene")] Scene(usize),
|
||||||
/// A track is selected.
|
/// A track is selected.
|
||||||
#[cfg(feature = "track")] Track(usize),
|
#[cfg(feature = "track")] Track(usize),
|
||||||
/// A clip is selected.
|
|
||||||
#[cfg(feature = "track")] Clip(usize),
|
|
||||||
/// A sample is selected.
|
|
||||||
#[cfg(feature = "track")] Sample(usize),
|
|
||||||
/// A clip slot (track × scene) is selected.
|
/// A clip slot (track × scene) is selected.
|
||||||
#[cfg(feature = "track")] TrackClip { track: usize, scene: usize },
|
#[cfg(feature = "track")] TrackClip { track: usize, scene: usize },
|
||||||
/// A track's MIDI input connection is selected.
|
/// A track's MIDI input connection is selected.
|
||||||
|
|
|
||||||
12
src/tek.rs
12
src/tek.rs
|
|
@ -44,9 +44,10 @@ mod proj_track; pub use self::proj_track::*;
|
||||||
|
|
||||||
mod tek_bind; pub use self::tek_bind::*;
|
mod tek_bind; pub use self::tek_bind::*;
|
||||||
mod tek_cli; pub use self::tek_cli::*;
|
mod tek_cli; pub use self::tek_cli::*;
|
||||||
mod tek_config; pub use self::tek_config::*;
|
mod tek_conf; pub use self::tek_conf::*;
|
||||||
mod tek_ctrl; pub use self::tek_ctrl::*;
|
mod tek_ctrl; pub use self::tek_ctrl::*;
|
||||||
mod tek_mode; pub use self::tek_mode::*;
|
mod tek_mode; pub use self::tek_mode::*;
|
||||||
|
mod tek_pool; pub use self::tek_pool::*;
|
||||||
mod tek_view; pub use self::tek_view::*;
|
mod tek_view; pub use self::tek_view::*;
|
||||||
|
|
||||||
#[cfg(feature = "lv2")] mod device_lv2; #[cfg(feature = "lv2")] pub use self::device_lv2::*;
|
#[cfg(feature = "lv2")] mod device_lv2; #[cfg(feature = "lv2")] pub use self::device_lv2::*;
|
||||||
|
|
@ -366,10 +367,15 @@ impl_has!(Clock: |self: App|self.project.clock);
|
||||||
impl_has!(Pool<MidiClip>: |self: App|self.project.clips);
|
impl_has!(Pool<MidiClip>: |self: App|self.project.clips);
|
||||||
impl_has!(Pool<Sample>: |self: App|self.project.samples);
|
impl_has!(Pool<Sample>: |self: App|self.project.samples);
|
||||||
impl_has!(Selection: |self: App|self.project.selection);
|
impl_has!(Selection: |self: App|self.project.selection);
|
||||||
|
impl_as_ref!(Option<Project>: |self: App|todo!());
|
||||||
impl_as_ref!(Slot<MidiClip>: |self: App|todo!());
|
impl_as_mut!(Option<Project>: |self: App|todo!());
|
||||||
impl_as_ref!(Option<MidiEditor>: |self: App|self.project.as_ref());
|
impl_as_ref!(Option<MidiEditor>: |self: App|self.project.as_ref());
|
||||||
impl_as_mut!(Option<MidiEditor>: |self: App|self.project.as_mut());
|
impl_as_mut!(Option<MidiEditor>: |self: App|self.project.as_mut());
|
||||||
|
impl HasClip for App {
|
||||||
|
fn clip_slot (&self) -> Option<Slot<MidiClip>> {
|
||||||
|
self.project.clip_slot()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
primitive!(u8: try_to_u8);
|
primitive!(u8: try_to_u8);
|
||||||
primitive!(u16: try_to_u16);
|
primitive!(u16: try_to_u16);
|
||||||
|
|
|
||||||
|
|
@ -175,17 +175,17 @@ impl<T: HasTracks
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
/// Launch multiple clips
|
/// Launch multiple clips
|
||||||
#[command(Launch = "launch")] fn tracks_launch (&mut self, clips: Option<ClipPool>)
|
#[command(Launch = "launch")] fn tracks_launch (&mut self, clips: ClipPool)
|
||||||
-> Perhaps<TracksCmd>
|
-> Perhaps<TracksCmd>
|
||||||
{
|
{
|
||||||
if let Some(clips) = clips {
|
if clips.len() == 0 {
|
||||||
for (clip, track) in clips.0.read().iter().zip(self.tracks_mut()) {
|
|
||||||
track.sequencer.enqueue_next(clip);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for track in self.tracks_mut().iter_mut() {
|
for track in self.tracks_mut().iter_mut() {
|
||||||
track.sequencer.enqueue_next(None);
|
track.sequencer.enqueue_next(None);
|
||||||
}
|
}
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
for (clip, track) in clips.0.read().iter().zip(self.tracks_mut()) {
|
||||||
|
track.sequencer.enqueue_next(clip.read().as_ref());
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
@ -734,16 +734,13 @@ impl<T> ModeControl for T where T: HasModeStack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HasClip {
|
pub trait HasClip {
|
||||||
fn clip (&self) -> RwLockReadGuard<'_, Option<Arc<RwLock<MidiClip>>>>;
|
fn clip (&self) -> Option<ArcRwLockReadGuard<RawRwLock, Option<Arc<RwLock<MidiClip>>>>> {
|
||||||
fn clip_mut (&self) -> RwLockWriteGuard<'_, Option<Arc<RwLock<MidiClip>>>>;
|
self.clip_slot().map(|slot|slot.read())
|
||||||
}
|
}
|
||||||
impl<T: AsRef<Slot<MidiClip>>> HasClip for T {
|
fn clip_mut (&self) -> Option<ArcRwLockWriteGuard<RawRwLock, Option<Arc<RwLock<MidiClip>>>>> {
|
||||||
fn clip (&self) -> RwLockReadGuard<'_, Option<Arc<RwLock<MidiClip>>>> {
|
self.clip_slot().map(|slot|slot.write())
|
||||||
self.as_ref().0.read()
|
|
||||||
}
|
|
||||||
fn clip_mut (&self) -> RwLockWriteGuard<'_, Option<Arc<RwLock<MidiClip>>>> {
|
|
||||||
self.as_ref().0.write()
|
|
||||||
}
|
}
|
||||||
|
fn clip_slot (&self) -> Option<Slot<MidiClip>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> MidiClipControl for T where T: HasClip
|
impl<T> MidiClipControl for T where T: HasClip
|
||||||
|
|
@ -752,20 +749,30 @@ impl<T> MidiClipControl for T where T: HasClip
|
||||||
+ Namespace<Option<bool>> + Namespace<Option<ItemTheme>>
|
+ Namespace<Option<bool>> + Namespace<Option<ItemTheme>>
|
||||||
{
|
{
|
||||||
/// Create a clip at the current position if it does not already exist.
|
/// Create a clip at the current position if it does not already exist.
|
||||||
#[command(Upsert = "upsert")] fn clip_upsert (&mut self) -> Perhaps<MidiClipCmd> {
|
#[command(Upsert = "upsert")] fn clip_upsert (
|
||||||
if self.clip().is_some() {
|
&mut self
|
||||||
Ok(None)
|
) -> Perhaps<MidiClipCmd> {
|
||||||
|
Ok(self.clip_mut().map(|mut clip|if clip.is_none() {
|
||||||
|
*clip = Some(Default::default());
|
||||||
|
None // TODO undo
|
||||||
} else {
|
} else {
|
||||||
*self.clip_mut() = Some(Default::default());
|
None
|
||||||
Ok(None)
|
}).flatten())
|
||||||
}
|
}
|
||||||
}
|
#[command(SetColor = "color")] fn clip_set_color (
|
||||||
#[command(SetColor = "color")] fn clip_set_color (&mut self, color: Option<ItemTheme>) -> Perhaps<MidiClipCmd> {
|
&mut self, color: Option<ItemTheme>
|
||||||
Ok(self.clip().as_ref().map(|clip|MidiClipCmd::SetColor { color: Some(clip.write().set_color(color)) }))
|
) -> Perhaps<MidiClipCmd> {
|
||||||
|
Ok(self.clip_slot().map_inner_mut(|clip|MidiClipCmd::SetColor {
|
||||||
|
color: Some(clip.set_color(color))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
/// Toggle looping for the active clip
|
/// Toggle looping for the active clip
|
||||||
#[command(SetLoop = "loop")] fn clip_toggle_loop (&mut self, looping: Option<bool>) -> Perhaps<MidiClipCmd> {
|
#[command(SetLoop = "loop")] fn clip_toggle_loop (
|
||||||
Ok(self.clip().as_ref().map(|clip|MidiClipCmd::SetLoop { looping: Some(clip.write().toggle_loop(looping)) }))
|
&mut self, looping: Option<bool>
|
||||||
|
) -> Perhaps<MidiClipCmd> {
|
||||||
|
Ok(self.clip_slot().map_inner_mut(|clip|MidiClipCmd::SetLoop {
|
||||||
|
looping: Some(clip.toggle_loop(looping))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
147
src/tek_pool.rs
Normal file
147
src/tek_pool.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Default, Debug)] pub struct Pool<T>(pub Arc<RwLock<Vec<Slot<T>>>>);
|
||||||
|
pub type SamplePool = Pool<Sample>;
|
||||||
|
pub type ClipPool = Pool<MidiClip>;
|
||||||
|
impl<T> Clone for Pool<T> { fn clone (&self) -> Self { Pool(self.0.clone()) } }
|
||||||
|
impl<T> Pool<T> {
|
||||||
|
pub fn slot (&self, index: usize) -> Slot<T> {
|
||||||
|
let mut state = self.0.write();
|
||||||
|
while index >= state.len() {
|
||||||
|
state.push(Slot::new(None));
|
||||||
|
}
|
||||||
|
state[index].clone()
|
||||||
|
}
|
||||||
|
pub fn delete (&self, index: usize) -> Option<Arc<RwLock<T>>> {
|
||||||
|
let mut none = None;
|
||||||
|
let mut slot = self.slot(index).write();
|
||||||
|
std::mem::swap(&mut none, &mut slot);
|
||||||
|
none
|
||||||
|
}
|
||||||
|
pub fn len (&self) -> usize {
|
||||||
|
self.0.read().len()
|
||||||
|
}
|
||||||
|
pub fn get (&self, index: usize) -> Option<ArcRwLockReadGuard<RawRwLock, Option<Arc<RwLock<T>>>>> {
|
||||||
|
self.0.read_arc().get(index).map(|clip|clip.read())
|
||||||
|
}
|
||||||
|
pub fn set (&self, index: usize, value: Option<T>) {
|
||||||
|
self.write()[index] = Slot::new(value);
|
||||||
|
}
|
||||||
|
pub fn read (&self) -> ArcRwLockReadGuard<RawRwLock, Vec<Slot<T>>> {
|
||||||
|
self.0.read_arc()
|
||||||
|
}
|
||||||
|
pub fn write (&self) -> ArcRwLockWriteGuard<RawRwLock, Vec<Slot<T>>> {
|
||||||
|
self.0.write_arc()
|
||||||
|
}
|
||||||
|
pub fn append (&self, value: Option<T>) -> Slot<T> {
|
||||||
|
let slot = Slot::new(value);
|
||||||
|
self.0.write().push(slot.clone());
|
||||||
|
slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pool<MidiClip> {
|
||||||
|
pub fn eval <'a> (_: &App, _: impl Language) -> Perhaps<ClipPool> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
pub fn remove (&self, filter: &MidiClip) {
|
||||||
|
let mut iter = self.0.write();
|
||||||
|
iter.retain(|x|if let Some(x) = &*x.0.read() {
|
||||||
|
&*x.read() != filter
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pool<Sample> {
|
||||||
|
pub fn eval <'a> (_: &App, _: impl Language) -> Perhaps<SamplePool> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Vec<Option<T>>> for Pool<T> {
|
||||||
|
fn from (values: Vec<Option<T>>) -> Self {
|
||||||
|
Self(Arc::new(RwLock::new(values.into_iter().map(Slot::new).collect())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)] pub struct Slot<T>(pub Arc<RwLock<Option<Arc<RwLock<T>>>>>);
|
||||||
|
pub type SampleSlot = Slot<Sample>;
|
||||||
|
pub type ClipSlot = Slot<MidiClip>;
|
||||||
|
|
||||||
|
impl<T> Clone for Slot<T> {
|
||||||
|
fn clone (&self) -> Self {
|
||||||
|
Slot(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Slot<T> {
|
||||||
|
pub fn new (value: impl Into<Option<T>>) -> Self {
|
||||||
|
Self(Arc::new(RwLock::new(value.into().map(|value|Arc::new(RwLock::new(value))))))
|
||||||
|
}
|
||||||
|
pub fn read (&self) -> ArcRwLockReadGuard<RawRwLock, Option<Arc<RwLock<T>>>> {
|
||||||
|
self.0.read_arc()
|
||||||
|
}
|
||||||
|
pub fn write (&self) -> ArcRwLockWriteGuard<RawRwLock, Option<Arc<RwLock<T>>>> {
|
||||||
|
self.0.write_arc()
|
||||||
|
}
|
||||||
|
pub fn set_to (&mut self, value: Self) {
|
||||||
|
self.0 = value.0;
|
||||||
|
}
|
||||||
|
pub fn set (&self, value: Option<T>) -> Option<Arc<RwLock<T>>> {
|
||||||
|
let mut value = value.map(|value|Arc::new(RwLock::new(value)));
|
||||||
|
std::mem::swap(&mut*self.0.write(), &mut value);
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait SlotExt<T> {
|
||||||
|
fn map_inner <U> (&self, cb: impl FnOnce(&T)->U) -> Option<U>;
|
||||||
|
fn map_inner_mut <U> (&self, cb: impl FnOnce(&mut T)->U) -> Option<U>;
|
||||||
|
}
|
||||||
|
impl<T> SlotExt<T> for Slot<T> {
|
||||||
|
fn map_inner <U> (&self, cb: impl FnOnce(&T)->U) -> Option<U> {
|
||||||
|
self.read().as_ref().map(|x|cb(&*x.read()))
|
||||||
|
}
|
||||||
|
fn map_inner_mut <U> (&self, cb: impl FnOnce(&mut T)->U) -> Option<U> {
|
||||||
|
self.read().as_ref().map(|x|cb(&mut*x.write()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> SlotExt<T> for Option<Slot<T>> {
|
||||||
|
fn map_inner <U> (&self, cb: impl FnOnce(&T)->U) -> Option<U> {
|
||||||
|
self.as_ref().map(|x|x.map_inner(cb))?
|
||||||
|
}
|
||||||
|
fn map_inner_mut <U> (&self, cb: impl FnOnce(&mut T)->U) -> Option<U> {
|
||||||
|
self.as_ref().map(|x|x.map_inner_mut(cb))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Slot<MidiClip> {
|
||||||
|
pub fn eval <'a> (state: &App, src: impl Language) -> Perhaps<ClipSlot> {
|
||||||
|
eval_word(src, |word|Ok(match word {
|
||||||
|
|
||||||
|
":selected" if let Selection::TrackClip { track, scene } = state.selection() => {
|
||||||
|
state.scenes()[*scene].clips.slot(*track)
|
||||||
|
},
|
||||||
|
|
||||||
|
//":selected-or-create" if let Selection::TrackClip {
|
||||||
|
//track, scene
|
||||||
|
//} = state.selection() => Some(if let Some(Some(clip)) = state.scenes()[*scene].clips.get(*track) {
|
||||||
|
//clip.clone()
|
||||||
|
//} else {
|
||||||
|
//let clip: Arc<RwLock<MidiClip>> = Arc::new(RwLock::new(Default::default()));
|
||||||
|
//state.scenes()[*scene].clips[*track] = Some(clip.clone());
|
||||||
|
//clip
|
||||||
|
//}),
|
||||||
|
|
||||||
|
_ => return err!("not a clip: {word}")
|
||||||
|
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Slot<Sample> {
|
||||||
|
pub fn eval <'a> (_: &App, _: impl Language) -> Perhaps<SampleSlot> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue