diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 72edce2a..b217633a 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -15,6 +15,8 @@ view!(TuiOut: |self: Tek| self.size.of(View(self, self.view)); { ().boxed(),//self.view_sample(self.is_editing()).boxed(), ":sampler" => ().boxed(),//self.view_sampler(self.is_editing(), &self.editor).boxed(), + ":samples-grid" => + self.tracks[0].sampler(0).map(|s|s.view_grid()).boxed(), ":status" => self.view_status().boxed(), ":pool" => self.pool.as_ref() diff --git a/crates/app/src/device.rs b/crates/app/src/device.rs index c9db7a79..c7b7e813 100644 --- a/crates/app/src/device.rs +++ b/crates/app/src/device.rs @@ -1,10 +1 @@ use crate::*; - -pub trait Device: Send + Sync + std::fmt::Debug { - fn boxed <'a> (self) -> Box where Self: Sized + 'a { Box::new(self) } -} - -impl Device for Sampler {} - -#[cfg(feature = "host")] -impl Device for Plugin {} diff --git a/crates/app/src/model.rs b/crates/app/src/model.rs index 6ba1add7..fa0030b0 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -247,60 +247,6 @@ impl HasSelection for Tek { fn selected_mut (&mut self) -> &mut Selection { &mut self.selected } } -pub trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync { - fn midi_ins (&self) -> &Vec; - fn midi_outs (&self) -> &Vec; - fn tracks (&self) -> &Vec; - fn tracks_mut (&mut self) -> &mut Vec; - fn track_longest (&self) -> usize { - self.tracks().iter().map(|s|s.name.len()).fold(0, usize::max) - } - const WIDTH_OFFSET: usize = 1; - fn track_next_name (&self) -> Arc { - format!("Track{:02}", self.tracks().len() + 1).into() - } - fn track (&self) -> Option<&Track> { - self.selected().track().and_then(|s|self.tracks().get(s)) - } - fn track_mut (&mut self) -> Option<&mut Track> { - self.selected().track().and_then(|s|self.tracks_mut().get_mut(s)) - } -} - -#[derive(Debug, Default)] pub struct Track { - /// Name of track - pub name: Arc, - /// Preferred width of track column - pub width: usize, - /// Identifying color of track - pub color: ItemPalette, - /// MIDI player state - pub player: MidiPlayer, - /// Device chain - pub devices: Vec>, - /// Inputs of 1st device - pub audio_ins: Vec, - /// Outputs of last device - pub audio_outs: Vec, -} - -has_clock!(|self: Track|self.player.clock); - -has_player!(|self: Track|self.player); - -impl Track { - const MIN_WIDTH: usize = 9; - fn width_inc (&mut self) { self.width += 1; } - fn width_dec (&mut self) { if self.width > Track::MIN_WIDTH { self.width -= 1; } } -} - -impl HasTracks for Tek { - fn midi_ins (&self) -> &Vec { &self.midi_ins } - fn midi_outs (&self) -> &Vec { &self.midi_outs } - fn tracks (&self) -> &Vec { &self.tracks } - fn tracks_mut (&mut self) -> &mut Vec { &mut self.tracks } -} - pub trait HasScenes: HasSelection + HasEditor + Send + Sync { fn scenes (&self) -> &Vec; fn scenes_mut (&mut self) -> &mut Vec; @@ -361,3 +307,97 @@ impl HasScenes for Tek { fn scenes (&self) -> &Vec { &self.scenes } fn scenes_mut (&mut self) -> &mut Vec { &mut self.scenes } } + +pub trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync { + fn midi_ins (&self) -> &Vec; + fn midi_outs (&self) -> &Vec; + fn tracks (&self) -> &Vec; + fn tracks_mut (&mut self) -> &mut Vec; + fn track_longest (&self) -> usize { + self.tracks().iter().map(|s|s.name.len()).fold(0, usize::max) + } + const WIDTH_OFFSET: usize = 1; + fn track_next_name (&self) -> Arc { + format!("Track{:02}", self.tracks().len() + 1).into() + } + fn track (&self) -> Option<&Track> { + self.selected().track().and_then(|s|self.tracks().get(s)) + } + fn track_mut (&mut self) -> Option<&mut Track> { + self.selected().track().and_then(|s|self.tracks_mut().get_mut(s)) + } +} + +#[derive(Debug, Default)] pub struct Track { + /// Name of track + pub name: Arc, + /// Preferred width of track column + pub width: usize, + /// Identifying color of track + pub color: ItemPalette, + /// MIDI player state + pub player: MidiPlayer, + /// Device chain + pub devices: Vec, + /// Inputs of 1st device + pub audio_ins: Vec, + /// Outputs of last device + pub audio_outs: Vec, +} + +has_clock!(|self: Track|self.player.clock); + +has_player!(|self: Track|self.player); + +impl Track { + pub const MIN_WIDTH: usize = 9; + pub fn width_inc (&mut self) { + self.width += 1; + } + pub fn width_dec (&mut self) { + if self.width > Track::MIN_WIDTH { + self.width -= 1; + } + } + pub fn sequencer (&self, mut nth: usize) -> Option<&MidiPlayer> { + for device in self.devices.iter() { + match device { + Device::Sequencer(s) => if nth == 0 { + return Some(s); + } else { + nth -= 1; + }, + _ => {} + } + } + None + } + pub fn sampler (&self, mut nth: usize) -> Option<&Sampler> { + for device in self.devices.iter() { + match device { + Device::Sampler(s) => if nth == 0 { + return Some(s); + } else { + nth -= 1; + }, + _ => {} + } + } + None + } +} + +impl HasTracks for Tek { + fn midi_ins (&self) -> &Vec { &self.midi_ins } + fn midi_outs (&self) -> &Vec { &self.midi_outs } + fn tracks (&self) -> &Vec { &self.tracks } + fn tracks_mut (&mut self) -> &mut Vec { &mut self.tracks } +} + +#[derive(Debug)] +pub enum Device { + Sequencer(MidiPlayer), + Sampler(Sampler), + #[cfg(feature="host")] + Plugin(Plugin), +} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index b040d826..765cd93f 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -4,7 +4,7 @@ edition = { workspace = true } version = { workspace = true } [dependencies] -tek = { workspace = true } +tek = { workspace = true } clap = { workspace = true } [[bin]] diff --git a/crates/cli/tek.rs b/crates/cli/tek.rs index 3e2a3524..465959f2 100644 --- a/crates/cli/tek.rs +++ b/crates/cli/tek.rs @@ -128,19 +128,51 @@ impl Cli { keys_scene: SourceIter(include_str!("./edn/arranger_keys_scene.edn")), keys_mix: SourceIter(include_str!("./edn/arranger_keys_mix.edn")), tracks: match mode { - Mode::Sequencer => vec![Track::default()], - Mode::Groovebox | Mode::Sampler => vec![Track { - devices: vec![ - Device::boxed(Sampler::new( - jack, - &"sampler", - midi_froms.as_slice(), - audio_froms, - audio_tos - )?) - ], - ..Track::default() - }], + + Mode::Sequencer => vec![ + Track { + devices: vec![ + Device::Sequencer( + MidiPlayer::default() + ), + ], + ..Track::default() + }, + ], + + Mode::Groovebox => vec![ + Track { + devices: vec![ + Device::Sequencer( + MidiPlayer::default() + ), + Device::Sampler(Sampler::new( + jack, + &"sampler", + midi_froms.as_slice(), + audio_froms, + audio_tos + )?) + ], + ..Track::default() + } + ], + + Mode::Sampler => vec![ + Track { + devices: vec![ + Device::Sampler(Sampler::new( + jack, + &"sampler", + midi_froms.as_slice(), + audio_froms, + audio_tos + )?) + ], + ..Track::default() + } + ], + _ => vec![] }, scenes, diff --git a/crates/midi/src/midi_out.rs b/crates/midi/src/midi_out.rs index 913832de..1cdee9cb 100644 --- a/crates/midi/src/midi_out.rs +++ b/crates/midi/src/midi_out.rs @@ -20,7 +20,8 @@ pub trait MidiPlaybackApi: HasPlayClip + HasClock + HasMidiOuts { fn clear ( &mut self, scope: &ProcessScope, out: &mut [Vec>], reset: bool ) { - for frame in &mut out[0..scope.n_frames() as usize] { + let n_frames = (scope.n_frames() as usize).min(out.len()); + for frame in &mut out[0..n_frames] { frame.clear(); } if reset { diff --git a/crates/sampler/src/sampler_api.rs b/crates/sampler/src/sampler_api.rs index e1451cc1..e60b262e 100644 --- a/crates/sampler/src/sampler_api.rs +++ b/crates/sampler/src/sampler_api.rs @@ -6,20 +6,6 @@ provide!(f32: |self: Sampler| {}); provide!(u7: |self: Sampler| {}); provide!(usize: |self: Sampler| {}); -//handle!(TuiIn: |self: Sampler, input|SamplerCommand::execute_with_state(self, input.event())); -//input_to_command!(SamplerCommand: |state: Sampler, input: Event|match state.mode{ - //Some(SamplerMode::Import(..)) => Self::Import( - //FileBrowserCommand::input_to_command(state, input)? - //), - //_ => match input { - //// load sample - //kpat!(Shift-Char('L')) => Self::Import(FileBrowserCommand::Begin), - //kpat!(KeyCode::Up) => Self::Select(state.note_pos().overflowing_add(1).0.min(127)), - //kpat!(KeyCode::Down) => Self::Select(state.note_pos().overflowing_sub(1).0.min(127)), - //_ => return None - //} -//}); - defcom! { |self, state: Sampler| SamplerCommand { diff --git a/crates/sampler/src/sampler_view.rs b/crates/sampler/src/sampler_view.rs index a39c7193..e1411007 100644 --- a/crates/sampler/src/sampler_view.rs +++ b/crates/sampler/src/sampler_view.rs @@ -1,5 +1,11 @@ use crate::*; +impl Sampler { + pub fn view_grid (&self) -> impl Content { + "sampler grid view" + } +} + content!(TuiOut: |self: Sampler| { let keys_width = 5; let keys = move||"";//SamplerKeys(self);