mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-09-18 04:46:43 +02:00
compiled layouts
This commit is contained in:
parent
6771b24f79
commit
ab6959a84f
21 changed files with 534 additions and 263 deletions
|
|
@ -1,33 +1,10 @@
|
|||
use crate::*;
|
||||
|
||||
/// TODO: Preserve the generic passthru syntax;
|
||||
/// remove this macro (only used twice) and potentially the trait.
|
||||
#[macro_export] macro_rules! impl_has_clips {
|
||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasClips for $Struct $(<$($L),*$($T),*>)? {
|
||||
fn clips <'a> (&'a $self) -> std::sync::RwLockReadGuard<'a, ClipPool> {
|
||||
$cb.read().unwrap()
|
||||
}
|
||||
fn clips_mut <'a> (&'a $self) -> std::sync::RwLockWriteGuard<'a, ClipPool> {
|
||||
$cb.write().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has_clip {
|
||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasMidiClip for $Struct $(<$($L),*$($T),*>)? {
|
||||
fn clip (&$self) -> Option<Arc<RwLock<MidiClip>>> { $cb }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arrangement {
|
||||
/// Toggle looping for the active clip
|
||||
pub fn toggle_loop (&mut self) {
|
||||
if let Some(clip) = self.selected_clip() {
|
||||
clip.write().unwrap().toggle_loop()
|
||||
clip.try_write().unwrap().toggle_loop()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +22,7 @@ impl Arrangement {
|
|||
&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 mut clip = clip.try_write().unwrap();
|
||||
let old = clip.color.clone();
|
||||
clip.color = color.clone();
|
||||
panic!("{color:?} {old:?}");
|
||||
|
|
@ -116,7 +93,7 @@ pub trait ClipsView: TracksView + ScenesView {
|
|||
|
||||
fn view_scene_name_theme (scene: &Scene, track_index: usize) -> (Arc<str>, ItemTheme) {
|
||||
if let Some(Some(clip)) = &scene.clips.get(track_index) {
|
||||
let clip = clip.read().unwrap();
|
||||
let clip = clip.try_read().unwrap();
|
||||
(format!(" ⏹ {}", &clip.name).into(), clip.color)
|
||||
} else {
|
||||
(" ⏹ -- ".into(), ItemTheme::G[32])
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl Scene {
|
|||
/// Get pulse length of the longest clip in the scene
|
||||
pub fn pulses (&self) -> usize {
|
||||
self.clips.iter().fold(0, |a, p|{
|
||||
a.max(p.as_ref().map(|q|q.read().unwrap().length).unwrap_or(0))
|
||||
a.max(p.as_ref().map(|q|q.try_read().unwrap().length).unwrap_or(0))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ impl Scene {
|
|||
.get(track_index)
|
||||
.map(|track|{
|
||||
if let Some((_, Some(clip))) = track.sequencer().play_clip() {
|
||||
*clip.read().unwrap() == *c.read().unwrap()
|
||||
*clip.try_read().unwrap() == *c.try_read().unwrap()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl Selection {
|
|||
tracks.get(*t).map(|track|format!("T{t}: {}", &track.name)).unwrap_or_else(||"T??".into()),
|
||||
TrackClip { track, scene } => match (tracks.get(*track), scenes.get(*scene)) {
|
||||
(Some(_), Some(s)) => match s.clip(*track) {
|
||||
Some(clip) => format!("T{track} S{scene} C{}", &clip.read().unwrap().name),
|
||||
Some(clip) => format!("T{track} S{scene} C{}", &clip.try_read().unwrap().name),
|
||||
None => format!("T{track} S{scene}: Empty")
|
||||
},
|
||||
_ => format!("T{track} S{scene}: Empty"),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use crate::*;
|
||||
use ::std::sync::{Arc, RwLock, atomic::AtomicUsize};
|
||||
use ::atomic_float::AtomicF64;
|
||||
|
||||
mod memo; pub use self::memo::*;
|
||||
mod moment; pub use self::moment::*;
|
||||
|
|
@ -328,11 +326,11 @@ impl Clock {
|
|||
}
|
||||
/// Is currently paused?
|
||||
pub fn is_stopped (&self) -> bool {
|
||||
self.started.read().unwrap().is_none()
|
||||
self.started.try_read().unwrap().is_none()
|
||||
}
|
||||
/// Is currently playing?
|
||||
pub fn is_rolling (&self) -> bool {
|
||||
self.started.read().unwrap().is_some()
|
||||
self.started.try_read().unwrap().is_some()
|
||||
}
|
||||
/// Update chunk size
|
||||
pub fn set_chunk (&self, n_frames: usize) {
|
||||
|
|
@ -347,7 +345,7 @@ impl Clock {
|
|||
self.global.sample.set(current_frames as f64);
|
||||
self.global.usec.set(current_usecs as f64);
|
||||
|
||||
let mut started = self.started.write().unwrap();
|
||||
let mut started = self.started.try_write().unwrap();
|
||||
|
||||
// If transport has just started or just stopped,
|
||||
// update starting point:
|
||||
|
|
@ -401,7 +399,7 @@ impl Clock {
|
|||
pub fn get_sample_offset (&self, scope: &ProcessScope, started: &Moment) -> usize{
|
||||
(scope.last_frame_time() as usize).saturating_sub(
|
||||
started.sample.get() as usize +
|
||||
self.started.read().unwrap().as_ref().unwrap().sample.get() as usize
|
||||
self.started.try_read().unwrap().as_ref().unwrap().sample.get() as usize
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl ClockView {
|
|||
let chunk = clock.chunk.load(Relaxed) as f64;
|
||||
let lat = chunk / rate * 1000.;
|
||||
let delta = |start: &Moment|clock.global.usec.get() - start.usec.get();
|
||||
let mut cache = cache.write().unwrap();
|
||||
let mut cache = cache.try_write().unwrap();
|
||||
|
||||
cache.buf.update(
|
||||
Some(chunk), rewrite!(buf, "{chunk}")
|
||||
|
|
@ -59,7 +59,7 @@ impl ClockView {
|
|||
}
|
||||
);
|
||||
|
||||
if let Some(now) = clock.started.read().unwrap().as_ref().map(delta) {
|
||||
if let Some(now) = clock.started.try_read().unwrap().as_ref().map(delta) {
|
||||
let pulse = clock.timebase.usecs_to_pulse(now);
|
||||
let time = now/1000000.;
|
||||
let bpm = clock.timebase.bpm.get();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{*, device::*};
|
||||
|
||||
pub fn draw_dialog <'a> (to: &mut Tui, mut frags: std::str::Split<&str>, state: &App)
|
||||
pub fn draw_dialog <'a, I: Debug + Iterator<Item = &'a str>> (to: &mut Tui, mut frags: I, state: &App)
|
||||
-> Drawn<u16>
|
||||
{
|
||||
match frags.next() {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl App {
|
|||
let (_index, clip) = self.pool.add_new_clip();
|
||||
// autocolor: new clip colors from scene and track color
|
||||
let color = track.color.base.mix(scene.color.base, 0.5);
|
||||
clip.write().unwrap().color = ItemColor::random_near(color, 0.2).into();
|
||||
clip.try_write().unwrap().color = ItemColor::random_near(color, 0.2).into();
|
||||
if let Some(editor) = &mut self.project.editor {
|
||||
editor.set_clip(Some(&clip));
|
||||
}
|
||||
|
|
@ -46,11 +46,11 @@ impl App {
|
|||
{
|
||||
// Remove clip from arrangement when exiting empty clip editor
|
||||
let mut swapped = None;
|
||||
if clip.read().unwrap().count_midi_messages() == 0 {
|
||||
if clip.try_read().unwrap().count_midi_messages() == 0 {
|
||||
std::mem::swap(&mut swapped, slot);
|
||||
}
|
||||
if let Some(clip) = swapped {
|
||||
self.pool.delete_clip(&clip.read().unwrap());
|
||||
self.pool.delete_clip(&clip.try_read().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -210,7 +210,7 @@ impl MidiEditor {
|
|||
pub fn put_note (&mut self, advance: bool) {
|
||||
let mut redraw = false;
|
||||
if let Some(clip) = self.clip() {
|
||||
let mut clip = clip.write().unwrap();
|
||||
let mut clip = clip.try_write().unwrap();
|
||||
let note_start = self.get_time_pos();
|
||||
let note_pos = self.get_note_pos();
|
||||
let note_len = self.get_note_len();
|
||||
|
|
@ -236,7 +236,7 @@ impl MidiEditor {
|
|||
self.mode.redraw();
|
||||
}
|
||||
}
|
||||
fn clip_length (&self) -> usize { self.clip().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1) }
|
||||
fn clip_length (&self) -> usize { self.clip().as_ref().map(|p|p.try_read().unwrap().length).unwrap_or(1) }
|
||||
fn note_length (&self) -> usize { self.get_note_len() }
|
||||
fn note_pos (&self) -> usize { self.get_note_pos() }
|
||||
fn note_pos_next (&self) -> usize { self.get_note_pos() + 1 }
|
||||
|
|
@ -269,7 +269,7 @@ impl MidiEditor {
|
|||
.0.min(self.clip_length().saturating_sub(1))
|
||||
}
|
||||
pub fn clip_status (&self) -> impl Draw<Tui> + '_ {
|
||||
let (_color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
|
||||
let (_color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.try_read().unwrap()) {
|
||||
(clip.color, clip.name.clone(), clip.length, clip.looped)
|
||||
} else { (ItemTheme::G[64], String::new().into(), 0, false) };
|
||||
south!(
|
||||
|
|
@ -282,7 +282,7 @@ impl MidiEditor {
|
|||
).exact_w(20)
|
||||
}
|
||||
pub fn edit_status (&self) -> impl Draw<Tui> + '_ {
|
||||
let (_color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
|
||||
let (_color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.try_read().unwrap()) {
|
||||
(clip.color, clip.length)
|
||||
} else { (ItemTheme::G[64], 0) };
|
||||
let time_pos = self.get_time_pos();
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ impl PianoHorizontal {
|
|||
buffer: RwLock::new(Default::default()).into(),
|
||||
point: MidiCursor::default(),
|
||||
clip: clip.cloned(),
|
||||
color: clip.as_ref().map(|p|p.read().unwrap().color).unwrap_or(ItemTheme::G[64]),
|
||||
color: clip.as_ref().map(|p|p.try_read().unwrap().color).unwrap_or(ItemTheme::G[64]),
|
||||
};
|
||||
piano.redraw();
|
||||
piano
|
||||
|
|
@ -140,7 +140,7 @@ impl PianoHorizontal {
|
|||
draw(move|to: &mut Tui|{
|
||||
let xywh = to.area().into();
|
||||
let XYWH(x0, y0, w, _h) = xywh;
|
||||
let source = buffer.read().unwrap();
|
||||
let source = buffer.try_read().unwrap();
|
||||
//if h as usize != note_axis {
|
||||
//panic!("area height mismatch: {h} <> {note_axis}");
|
||||
//}
|
||||
|
|
@ -234,7 +234,7 @@ impl PianoHorizontal {
|
|||
let xywh = to.area().into();
|
||||
let XYWH(x, y, w, _h) = xywh;
|
||||
let style = Some(Style::default().dim());
|
||||
let length = self.clip.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
|
||||
let length = self.clip.as_ref().map(|p|p.try_read().unwrap().length).unwrap_or(1);
|
||||
for (area_x, screen_x) in (0..w).map(|d|(d, d+x)) {
|
||||
let t = area_x as usize * self.time_zoom().load(Relaxed);
|
||||
if t < length {
|
||||
|
|
@ -276,8 +276,8 @@ impl MidiViewer for PianoHorizontal {
|
|||
(clip.length / self.range.time_zoom().load(Relaxed), 128)
|
||||
}
|
||||
fn redraw (&self) {
|
||||
*self.buffer.write().unwrap() = if let Some(clip) = self.clip.as_ref() {
|
||||
let clip = clip.read().unwrap();
|
||||
*self.buffer.try_write().unwrap() = if let Some(clip) = self.clip.as_ref() {
|
||||
let clip = clip.try_read().unwrap();
|
||||
let buf_size = self.buffer_size(&clip);
|
||||
let mut buffer = BigBuffer::from(buf_size);
|
||||
let time_zoom = self.get_time_zoom();
|
||||
|
|
@ -291,14 +291,14 @@ impl MidiViewer for PianoHorizontal {
|
|||
}
|
||||
fn set_clip (&mut self, clip: Option<&Arc<RwLock<MidiClip>>>) {
|
||||
*self.clip_mut() = clip.cloned();
|
||||
self.color = clip.map(|p|p.read().unwrap().color).unwrap_or(ItemTheme::G[64]);
|
||||
self.color = clip.map(|p|p.try_read().unwrap().color).unwrap_or(ItemTheme::G[64]);
|
||||
self.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PianoHorizontal {
|
||||
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||
let buffer = self.buffer.read().unwrap();
|
||||
let buffer = self.buffer.try_read().unwrap();
|
||||
f.debug_struct("PianoHorizontal")
|
||||
.field("time_zoom", &self.range.time_zoom)
|
||||
.field("buffer", &format!("{}x{}", buffer.width, buffer.height))
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ pub trait PoolController: HasPool
|
|||
/// Delete a clip from the pool
|
||||
#[command(Delete = "delete")]
|
||||
fn delete (&mut self, index: usize) -> Perhaps<PoolCommand> {
|
||||
let clip = self.pool_mut().clips_mut().remove(index).read().unwrap().clone();
|
||||
let clip = self.pool_mut().clips_mut().remove(index).try_read().unwrap().clone();
|
||||
Ok(Some(PoolCommand::Add { index, clip }))
|
||||
}
|
||||
|
||||
|
|
@ -181,8 +181,8 @@ pub trait PoolController: HasPool
|
|||
#[command(SetName = "set-name")]
|
||||
fn clip_set_name (&mut self, index: usize, name: Arc<str>) -> Perhaps<PoolCommand> {
|
||||
let clip = &mut self.pool_mut().clips_mut()[index];
|
||||
let old_name = clip.read().unwrap().name.clone();
|
||||
clip.write().unwrap().name = name.clone();
|
||||
let old_name = clip.try_read().unwrap().name.clone();
|
||||
clip.try_write().unwrap().name = name.clone();
|
||||
Ok(Some(PoolCommand::SetName { index, name: old_name }))
|
||||
}
|
||||
|
||||
|
|
@ -190,8 +190,8 @@ pub trait PoolController: HasPool
|
|||
#[command(SetLength = "set-length")]
|
||||
fn clip_set_length (&mut self, index: usize, length: usize) -> Perhaps<PoolCommand> {
|
||||
let clip = &mut self.pool_mut().clips_mut()[index];
|
||||
let old_len = clip.read().unwrap().length;
|
||||
clip.write().unwrap().length = length;
|
||||
let old_len = clip.try_read().unwrap().length;
|
||||
clip.try_write().unwrap().length = length;
|
||||
Ok(Some(PoolCommand::SetLength { index, length: old_len }))
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +199,7 @@ pub trait PoolController: HasPool
|
|||
#[command(SetColor = "set-color")]
|
||||
fn clip_set_color (&mut self, index: usize, color: ItemColor) -> Perhaps<PoolCommand> {
|
||||
let mut color = ItemTheme::from(color);
|
||||
std::mem::swap(&mut color, &mut self.pool().clips()[index].write().unwrap().color);
|
||||
std::mem::swap(&mut color, &mut self.pool().clips()[index].try_write().unwrap().color);
|
||||
Ok(Some(PoolCommand::SetColor { index, color: color.base }))
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +207,7 @@ pub trait PoolController: HasPool
|
|||
#[command(CropBegin = "crop/begin")]
|
||||
fn crop_begin (&mut self) -> Perhaps<PoolCommand> {
|
||||
let index = self.pool().clip_index();
|
||||
let length = self.pool().clips()[index].read().unwrap().length;
|
||||
let length = self.pool().clips()[index].try_read().unwrap().length;
|
||||
*self.pool_mut().mode_mut() = Some(PoolMode::Length(index, length, ClipLengthFocus::Bar));
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -228,9 +228,9 @@ pub trait PoolController: HasPool
|
|||
{
|
||||
let old_length;
|
||||
{
|
||||
let clip = self.pool().clips()[clip].clone();//.write().unwrap();
|
||||
old_length = Some(clip.read().unwrap().length);
|
||||
clip.write().unwrap().length = *length;
|
||||
let clip = self.pool().clips()[clip].clone();//.try_write().unwrap();
|
||||
old_length = Some(clip.try_read().unwrap().length);
|
||||
clip.try_write().unwrap().length = *length;
|
||||
}
|
||||
*self.pool_mut().mode_mut() = None;
|
||||
return Ok(old_length.map(|l|PoolCommand::CropSet { _length: l }))
|
||||
|
|
@ -290,7 +290,7 @@ pub trait PoolController: HasPool
|
|||
#[command(RenameBegin = "rename/begin")]
|
||||
fn rename_begin (&mut self) -> Perhaps<PoolCommand> {
|
||||
let index = self.pool().clip_index();
|
||||
let name = self.pool().clips()[index].read().unwrap().name.clone();
|
||||
let name = self.pool().clips()[index].try_read().unwrap().name.clone();
|
||||
*self.pool_mut().mode_mut() = Some(PoolMode::Rename(index, name));
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -299,7 +299,7 @@ pub trait PoolController: HasPool
|
|||
#[command(RenameCancel = "rename/cancel")]
|
||||
fn rename_cancel (&mut self) -> Perhaps<PoolCommand> {
|
||||
if let Some(PoolMode::Rename(clip, ref mut old_name)) = self.pool_mut().mode_mut().clone() {
|
||||
self.pool().clips()[clip].write().unwrap().name = old_name.clone().into();
|
||||
self.pool().clips()[clip].try_write().unwrap().name = old_name.clone().into();
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -319,7 +319,7 @@ pub trait PoolController: HasPool
|
|||
#[command(RenameSet = "rename/set")]
|
||||
fn rename_set (&mut self, value: Arc<str>) -> Perhaps<PoolCommand> {
|
||||
if let Some(PoolMode::Rename(clip, ref mut _old_name)) = self.pool_mut().mode_mut().clone() {
|
||||
self.pool().clips()[clip].write().unwrap().name = value.clone();
|
||||
self.pool().clips()[clip].try_write().unwrap().name = value.clone();
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -332,7 +332,7 @@ impl_has_clips!(|self: Pool|self.clips);
|
|||
|
||||
impl_from!(Pool: |clip:&Arc<RwLock<MidiClip>>|{
|
||||
let model = Self::default();
|
||||
model.clips.write().unwrap().push(clip.clone());
|
||||
model.clips.try_write().unwrap().push(clip.clone());
|
||||
model.clip.store(1, Relaxed);
|
||||
model
|
||||
});
|
||||
|
|
@ -378,14 +378,14 @@ impl Pool {
|
|||
}
|
||||
pub fn cloned_clip (&self) -> MidiClip {
|
||||
let index = self.clip_index();
|
||||
let mut clip = self.clips()[index].read().unwrap().duplicate();
|
||||
let mut clip = self.clips()[index].try_read().unwrap().duplicate();
|
||||
clip.color = ItemTheme::random_near(clip.color, 0.25);
|
||||
clip
|
||||
}
|
||||
pub fn add_new_clip (&self) -> (usize, Arc<RwLock<MidiClip>>) {
|
||||
let clip = Arc::new(RwLock::new(self.new_clip()));
|
||||
let index = {
|
||||
let mut clips = self.clips.write().unwrap();
|
||||
let mut clips = self.clips.try_write().unwrap();
|
||||
clips.push(clip.clone());
|
||||
clips.len().saturating_sub(1)
|
||||
};
|
||||
|
|
@ -393,9 +393,9 @@ impl Pool {
|
|||
(index, clip)
|
||||
}
|
||||
pub fn delete_clip (&mut self, clip: &MidiClip) -> bool {
|
||||
let index = self.clips.read().unwrap().iter().position(|x|*x.read().unwrap()==*clip);
|
||||
let index = self.clips.try_read().unwrap().iter().position(|x|*x.try_read().unwrap()==*clip);
|
||||
if let Some(index) = index {
|
||||
self.clips.write().unwrap().remove(index);
|
||||
self.clips.try_write().unwrap().remove(index);
|
||||
return true
|
||||
}
|
||||
false
|
||||
|
|
@ -441,14 +441,14 @@ impl Pool {
|
|||
impl<'a> PoolView<'a> {
|
||||
//fn tui (&self) -> impl Draw<'_, Tui> {
|
||||
//let Self(pool) = self;
|
||||
////let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||g(32).into());
|
||||
////let color = self.1.clip().map(|c|c.try_read().unwrap().color).unwrap_or_else(||g(32).into());
|
||||
////let on_bg = |x|x;//below(Repeat(" "), bg(color.darkest.term, x));
|
||||
////let border = |x|x;//Outer(Style::default().fg(color.dark.term).bg(color.darkest.term)).enclose(x);
|
||||
////let height = pool.clips.read().unwrap().len() as u16;
|
||||
////let height = pool.clips.try_read().unwrap().len() as u16;
|
||||
//iter(
|
||||
//||pool.clips().clone().into_iter(),
|
||||
//move|clip: Arc<RwLock<MidiClip>>, i: usize|{
|
||||
//let MidiClip { ref name, color, length, .. } = *clip.read().unwrap();
|
||||
//let MidiClip { ref name, color, length, .. } = *clip.try_read().unwrap();
|
||||
//let item_height = 1;
|
||||
//let _item_offset = i as u16 * item_height;
|
||||
//let selected = i == pool.clip_index();
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ pub trait SamplerController: HasSampler
|
|||
fn sample_play (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
|
||||
let sampler = self.sampler_mut();
|
||||
if let Some(ref sample) = sampler.samples.0[slot] {
|
||||
sampler.voices.write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
|
||||
sampler.voices.try_write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -244,7 +244,7 @@ impl Sampler {
|
|||
/// Record from inputs to sample
|
||||
fn record_into (&mut self, scope: &ProcessScope) {
|
||||
if let Some(ref sample) = self.recording.as_ref().expect("no recording sample").1 {
|
||||
let mut sample = sample.write().unwrap();
|
||||
let mut sample = sample.try_write().unwrap();
|
||||
if sample.channels.len() != self.audio_ins.len() {
|
||||
panic!("channel count mismatch");
|
||||
}
|
||||
|
|
@ -294,10 +294,10 @@ impl Sampler {
|
|||
let Sampler { buffer, voices, output_gain, mixing_mode, .. } = self;
|
||||
let _channel_count = buffer.len();
|
||||
match mixing_mode {
|
||||
MixingMode::Summing => voices.write().unwrap().retain_mut(|voice|{
|
||||
MixingMode::Summing => voices.try_write().unwrap().retain_mut(|voice|{
|
||||
mix_summing(buffer.as_mut_slice(), *output_gain, frames, ||voice.next())
|
||||
}),
|
||||
MixingMode::Average => voices.write().unwrap().retain_mut(|voice|{
|
||||
MixingMode::Average => voices.try_write().unwrap().retain_mut(|voice|{
|
||||
mix_average(buffer.as_mut_slice(), *output_gain, frames, ||voice.next())
|
||||
}),
|
||||
}
|
||||
|
|
@ -316,7 +316,7 @@ impl Sampler {
|
|||
|
||||
fn draw_list_item (sample: &Option<Arc<RwLock<Sample>>>) -> String {
|
||||
if let Some(sample) = sample {
|
||||
let sample = sample.read().unwrap();
|
||||
let sample = sample.try_read().unwrap();
|
||||
format!("{:8}", sample.name)
|
||||
//format!("{:8} {:3} {:6}-{:6}/{:6}",
|
||||
//sample.name,
|
||||
|
|
@ -337,7 +337,7 @@ fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_
|
|||
let XYWH(x, y, width, height) = xywh;
|
||||
let area = Rect { x, y, width, height };
|
||||
if let Some(sample) = &sample {
|
||||
let sample = sample.read().unwrap();
|
||||
let sample = sample.try_read().unwrap();
|
||||
let start = sample.start as f64;
|
||||
let end = sample.end as f64;
|
||||
let length = end - start;
|
||||
|
|
@ -400,7 +400,7 @@ fn sampler_midi_in (
|
|||
match message {
|
||||
MidiMessage::NoteOn { ref key, ref vel } => {
|
||||
if let Some(sample) = samples.get(key.as_int() as usize) {
|
||||
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||
voices.try_write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||
}
|
||||
},
|
||||
MidiMessage::Controller { controller: _, value: _ } => {
|
||||
|
|
@ -444,7 +444,7 @@ impl Iterator for Voice {
|
|||
self.after -= 1;
|
||||
return Some([0.0, 0.0])
|
||||
}
|
||||
let sample = self.sample.read().unwrap();
|
||||
let sample = self.sample.try_read().unwrap();
|
||||
if self.position < sample.end {
|
||||
let position = self.position;
|
||||
self.position += 1;
|
||||
|
|
@ -514,7 +514,7 @@ impl Sample {
|
|||
Voice {
|
||||
sample: sample.clone(),
|
||||
after,
|
||||
position: sample.read().unwrap().start,
|
||||
position: sample.try_read().unwrap().start,
|
||||
velocity: velocity.as_int() as f32 / 127.0,
|
||||
}
|
||||
}
|
||||
|
|
@ -679,8 +679,8 @@ impl SampleAdd {
|
|||
fn try_preview (&mut self) -> Usually<()> {
|
||||
if let Some(path) = self.cursor_file() {
|
||||
if let Ok(sample) = Sample::from_file(&path) {
|
||||
*self.sample.write().unwrap() = sample;
|
||||
self.voices.write().unwrap().push(
|
||||
*self.sample.try_write().unwrap() = sample;
|
||||
self.voices.try_write().unwrap().push(
|
||||
Sample::play(&self.sample, 0, &u7::from(100u8))
|
||||
);
|
||||
}
|
||||
|
|
@ -736,7 +736,7 @@ impl SampleAdd {
|
|||
}
|
||||
if let Some(path) = self.cursor_file() {
|
||||
let (end, channels) = read_sample_data(&path.to_string_lossy())?;
|
||||
let mut sample = self.sample.write().unwrap();
|
||||
let mut sample = self.sample.try_write().unwrap();
|
||||
sample.name = path.file_name().unwrap().to_string_lossy().into();
|
||||
sample.end = end;
|
||||
sample.channels = channels;
|
||||
|
|
@ -752,7 +752,7 @@ fn read_sample_data (_: &str) -> Usually<(usize, Vec<Vec<f32>>)> {
|
|||
|
||||
pub fn view_sample_info (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> {
|
||||
when(sample.is_some(), draw(move|to: &mut Tui|{
|
||||
let sample = sample.unwrap().read().unwrap();
|
||||
let sample = sample.unwrap().try_read().unwrap();
|
||||
let theme = sample.color;
|
||||
east!(
|
||||
field_h(theme, "Name", format!("{:<10}", sample.name.clone())),
|
||||
|
|
@ -767,7 +767,7 @@ pub fn view_sample_info (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui>
|
|||
|
||||
pub fn view_sample_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> {
|
||||
let a = draw(move|to: &mut Tui|{
|
||||
let sample = sample.unwrap().read().unwrap();
|
||||
let sample = sample.unwrap().try_read().unwrap();
|
||||
let theme = sample.color;
|
||||
south!(
|
||||
field_h(theme, "Name ", format!("{:<10}", sample.name.clone())) .align_w().full_w(),
|
||||
|
|
@ -791,7 +791,7 @@ pub fn view_sample_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tu
|
|||
pub fn view_sample_status (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> {
|
||||
bold(true, fg(g(224), sample
|
||||
.map(|sample|{
|
||||
let sample = sample.read().unwrap();
|
||||
let sample = sample.try_read().unwrap();
|
||||
format!("Sample {}-{}", sample.start, sample.end)
|
||||
})
|
||||
.unwrap_or_else(||"No sample".to_string())))
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ pub trait HasPlayClip: HasClock {
|
|||
fn pulses_since_start_looped (&self) -> Option<(f64, f64)> {
|
||||
if let Some((started, Some(clip))) = self.play_clip().as_ref() {
|
||||
let elapsed = self.clock().playhead.pulse.get() - started.pulse.get();
|
||||
let length = clip.read().unwrap().length.max(1); // prevent div0 on empty clip
|
||||
let length = clip.try_read().unwrap().length.max(1); // prevent div0 on empty clip
|
||||
let times = (elapsed as usize / length) as f64;
|
||||
let elapsed = (elapsed as usize % length) as f64;
|
||||
return Some((times, elapsed))
|
||||
|
|
@ -115,7 +115,7 @@ pub trait HasPlayClip: HasClock {
|
|||
|
||||
fn play_status (&self) -> impl Draw<Tui> {
|
||||
let (name, color): (Arc<str>, ItemTheme) = if let Some((_, Some(clip))) = self.play_clip() {
|
||||
let MidiClip { ref name, color, .. } = *clip.read().unwrap();
|
||||
let MidiClip { ref name, color, .. } = *clip.try_read().unwrap();
|
||||
(name.clone(), color)
|
||||
} else {
|
||||
("".into(), ItemTheme::G[64].into())
|
||||
|
|
@ -136,7 +136,7 @@ pub trait HasPlayClip: HasClock {
|
|||
let mut color = ItemTheme::G[64];
|
||||
let clock = self.clock();
|
||||
if let Some((t, Some(clip))) = self.next_clip() {
|
||||
let clip = clip.read().unwrap();
|
||||
let clip = clip.try_read().unwrap();
|
||||
name = clip.name.clone();
|
||||
color = clip.color.clone();
|
||||
time = {
|
||||
|
|
@ -150,7 +150,7 @@ pub trait HasPlayClip: HasClock {
|
|||
}
|
||||
}.into()
|
||||
} else if let Some((t, Some(clip))) = self.play_clip() {
|
||||
let clip = clip.read().unwrap();
|
||||
let clip = clip.try_read().unwrap();
|
||||
if clip.looped {
|
||||
name = clip.name.clone();
|
||||
color = clip.color.clone();
|
||||
|
|
@ -205,7 +205,7 @@ pub trait MidiRecord: MidiMonitor + HasClock + HasPlayClip {
|
|||
let _recording = self.recording();
|
||||
let timebase = self.clock().timebase().clone();
|
||||
let quant = self.clock().quant.get();
|
||||
let mut clip = clip.write().unwrap();
|
||||
let mut clip = clip.try_write().unwrap();
|
||||
let length = clip.length;
|
||||
for input in self.midi_ins_mut().iter() {
|
||||
for (sample, event, _bytes) in parse_midi_input(input.port().iter(scope)) {
|
||||
|
|
@ -232,8 +232,8 @@ pub type MidiData = Vec<Vec<MidiMessage>>;
|
|||
pub type ClipPool = Vec<Arc<RwLock<MidiClip>>>;
|
||||
|
||||
pub trait HasClips {
|
||||
fn clips <'a> (&'a self) -> std::sync::RwLockReadGuard<'a, ClipPool>;
|
||||
fn clips_mut <'a> (&'a self) -> std::sync::RwLockWriteGuard<'a, ClipPool>;
|
||||
fn clips <'a> (&'a self) -> RwLockReadGuard<'a, ClipPool>;
|
||||
fn clips_mut <'a> (&'a self) -> RwLockWriteGuard<'a, ClipPool>;
|
||||
fn add_clip (&self) -> (usize, Arc<RwLock<MidiClip>>) {
|
||||
let clip = Arc::new(RwLock::new(MidiClip::new("Clip", true, 384, None, None)));
|
||||
self.clips_mut().push(clip.clone());
|
||||
|
|
@ -241,6 +241,29 @@ pub trait HasClips {
|
|||
}
|
||||
}
|
||||
|
||||
/// TODO: Preserve the generic passthru syntax;
|
||||
/// remove this macro (only used twice) and potentially the trait.
|
||||
#[macro_export] macro_rules! impl_has_clips {
|
||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasClips for $Struct $(<$($L),*$($T),*>)? {
|
||||
fn clips <'a> (&'a $self) -> ::tengri::parking_lot::RwLockReadGuard<'a, ClipPool> {
|
||||
$cb.try_read().unwrap()
|
||||
}
|
||||
fn clips_mut <'a> (&'a $self) -> ::tengri::parking_lot::RwLockWriteGuard<'a, ClipPool> {
|
||||
$cb.try_write().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has_clip {
|
||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasMidiClip for $Struct $(<$($L),*$($T),*>)? {
|
||||
fn clip (&$self) -> Option<Arc<RwLock<MidiClip>>> { $cb }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasMidiClip {
|
||||
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>>;
|
||||
}
|
||||
|
|
@ -433,7 +456,7 @@ impl Sequencer {
|
|||
self.midi_buf[sample].push(bytes.to_vec());
|
||||
}
|
||||
// FIXME: don't lock on every event!
|
||||
update_keys(&mut notes_in.write().unwrap(), &message);
|
||||
update_keys(&mut notes_in.try_write().unwrap(), &message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -469,7 +492,7 @@ impl Sequencer {
|
|||
// If no clip is playing, prepare for switchover immediately.
|
||||
if let Some((started, clip)) = &self.play_clip {
|
||||
// Length of clip, to repeat or stop on end.
|
||||
let length = clip.as_ref().map_or(0, |p|p.read().unwrap().length);
|
||||
let length = clip.as_ref().map_or(0, |p|p.try_read().unwrap().length);
|
||||
// Index of first sample to populate.
|
||||
let offset = self.clock().get_sample_offset(scope, &started);
|
||||
// Write MIDI events from clip at sample offsets corresponding to pulses.
|
||||
|
|
@ -484,7 +507,7 @@ impl Sequencer {
|
|||
// If there's a currently playing clip, output notes from it to buffer:
|
||||
if let Some(clip) = clip {
|
||||
// Source clip from which the MIDI events will be taken.
|
||||
let clip = clip.read().unwrap();
|
||||
let clip = clip.try_read().unwrap();
|
||||
// Clip with zero length is not processed
|
||||
if clip.length > 0 {
|
||||
// Current pulse index in source clip
|
||||
|
|
@ -513,7 +536,7 @@ impl Sequencer {
|
|||
//let samples = scope.n_frames() as usize;
|
||||
if let Some((start_at, clip)) = &self.next_clip() {
|
||||
let start = start_at.sample.get() as usize;
|
||||
let sample = self.clock().started.read().unwrap()
|
||||
let sample = self.clock().started.try_read().unwrap()
|
||||
.as_ref().unwrap().sample.get() as usize;
|
||||
// If it's time to switch to the next clip:
|
||||
if start <= sample0.saturating_sub(sample) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue