diff --git a/crates/tek/src/groovebox.rs b/crates/tek/src/groovebox.rs index a9bec7c6..86649d19 100644 --- a/crates/tek/src/groovebox.rs +++ b/crates/tek/src/groovebox.rs @@ -61,6 +61,7 @@ render!(|self:GrooveboxTui|{ let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 }; let pool_w = if self.pool.visible { phrase_w } else { 0 }; let sampler_w = 11; + let note_pt = self.editor.note_point(); Fill::wh(lay!([ &self.size, Fill::wh(Align::s(Fixed::h(2, GrooveboxStatus::from(self)))), @@ -84,11 +85,14 @@ render!(|self:GrooveboxTui|{ &format!("L/{:>+9.3}", self.sampler.input_meter[0]), &format!("R/{:>+9.3}", self.sampler.input_meter[1]), Fill::wh(col!(note in (self.editor.note_lo().load(Relaxed)..=self.editor.note_hi()).rev() => { - if self.sampler.mapped.contains_key(&u7::from(note as u8)) { - todo!() - } else { - Tui::fg(TuiTheme::g(96), format!("{note:3} (none)")) - } + Tui::bg( + if note == note_pt { TuiTheme::g(64) } else { Color::Reset }, + if let Some(sample) = &self.sampler.mapped[note] { + todo!() + } else { + Tui::fg(TuiTheme::g(160), format!("{note:3} (none)")) + } + ) })), ])), Fill::h(&self.editor)) ) @@ -188,6 +192,7 @@ command!(|self:GrooveboxCommand,state:GrooveboxTui|match self { } }, Self::Clock(cmd) => cmd.execute(state)?.map(Clock), + Self::Sampler(cmd) => cmd.execute(&mut state.sampler)?.map(Sampler), Self::Enqueue(phrase) => { state.player.enqueue_next(phrase.as_ref()); None @@ -195,7 +200,4 @@ command!(|self:GrooveboxCommand,state:GrooveboxTui|match self { Self::History(delta) => { todo!("undo/redo") }, - Self::Sampler(command) => { - todo!("sampler") - } }); diff --git a/crates/tek/src/sampler.rs b/crates/tek/src/sampler.rs index 195b3109..d692b955 100644 --- a/crates/tek/src/sampler.rs +++ b/crates/tek/src/sampler.rs @@ -38,7 +38,7 @@ pub(crate) use self::sample_import::*; pub struct Sampler { pub jack: Arc>, pub name: String, - pub mapped: BTreeMap>>, + pub mapped: [Option>>;128], pub unmapped: Vec>>, pub voices: Arc>>, pub midi_in: Port, @@ -63,7 +63,7 @@ impl Sampler { ], jack: jack.clone(), name: name.into(), - mapped: BTreeMap::new(), + mapped: [const { None };128], unmapped: vec![], voices: Arc::new(RwLock::new(vec![])), buffer: vec![vec![0.0;16384];2], @@ -86,9 +86,9 @@ pub struct SamplerTui { impl SamplerTui { /// Immutable reference to sample at cursor. pub fn sample (&self) -> Option<&Arc>> { - for (i, sample) in self.state.mapped.values().enumerate() { + for (i, sample) in self.state.mapped.iter().enumerate() { if i == self.cursor.0 { - return Some(sample) + return sample.as_ref() } } for (i, sample) in self.state.unmapped.iter().enumerate() { diff --git a/crates/tek/src/sampler/sampler_audio.rs b/crates/tek/src/sampler/sampler_audio.rs index fac91ba6..8b9ca5e4 100644 --- a/crates/tek/src/sampler/sampler_audio.rs +++ b/crates/tek/src/sampler/sampler_audio.rs @@ -37,7 +37,7 @@ impl Sampler { if let LiveEvent::Midi { message: MidiMessage::NoteOn { ref key, ref vel }, .. } = LiveEvent::parse(bytes).unwrap() { - if let Some(sample) = mapped.get(key) { + if let Some(ref sample) = mapped[key.as_int() as usize] { voices.write().unwrap().push(Sample::play(sample, time as usize, vel)); } } diff --git a/crates/tek/src/sampler/sampler_control.rs b/crates/tek/src/sampler/sampler_control.rs index 63107481..7963fcad 100644 --- a/crates/tek/src/sampler/sampler_control.rs +++ b/crates/tek/src/sampler/sampler_control.rs @@ -1,21 +1,24 @@ use crate::*; use KeyCode::Char; -handle!(|self:SamplerTui,input|SamplerCommand::execute_with_state(self, input)); +handle!(|self: SamplerTui, input|SamplerTuiCommand::execute_with_state(self, input)); -pub enum SamplerCommand { +pub enum SamplerTuiCommand { Import(FileBrowserCommand), SelectNote(usize), SelectField(usize), - SetName(String), - SetNote(u7, Option>>), + Sample(SamplerCommand), +} + +pub enum SamplerCommand { + Record(u7), + SetSample(u7, Option>>), SetGain(f32), NoteOn(u7, u7), NoteOff(u7), - Record(u7), } -input_to_command!(SamplerCommand: |state: SamplerTui, input|match state.mode { +input_to_command!(SamplerTuiCommand: |state: SamplerTui, input|match state.mode { Some(SamplerMode::Import(..)) => Self::Import( FileBrowserCommand::input_to_command(state, input)? ), @@ -51,7 +54,8 @@ input_to_command!(SamplerCommand: |state: SamplerTui, input|match state.mod //} //} }); -command!(|self:SamplerCommand,state:SamplerTui|match self { + +command!(|self: SamplerTuiCommand, state: SamplerTui|match self { Self::Import(FileBrowserCommand::Begin) => { let voices = &state.state.voices; let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![]))); @@ -63,10 +67,21 @@ command!(|self:SamplerCommand,state:SamplerTui|match self { state.set_note_point(index); Some(Self::SelectNote(old)) }, + Self::Sample(cmd) => cmd.execute(&mut state.state)?.map(Self::Sample), + _ => todo!() +}); + +command!(|self: SamplerCommand, state: Sampler|match self { + Self::SetSample(index, sample) => { + let i = index.as_int() as usize; + let old = state.mapped[i].clone(); + state.mapped[i] = sample; + Some(Self::SetSample(index, old)) + }, Self::Record(index) => { - let old = state.state.mapped.get(&index).cloned(); - - Some(Self::SetNote(index, old)) + let i = index.as_int() as usize; + let old = state.mapped[i].clone(); + Some(Self::SetSample(index, old)) }, _ => todo!() });