mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
highlight recorded sample
This commit is contained in:
parent
2feb21bd1f
commit
ae3099847a
3 changed files with 76 additions and 19 deletions
|
|
@ -61,7 +61,6 @@ render!(<Tui>|self:GrooveboxTui|{
|
||||||
let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
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 pool_w = if self.pool.visible { phrase_w } else { 0 };
|
||||||
let sampler_w = 11;
|
let sampler_w = 11;
|
||||||
let note_pt = self.editor.note_point();
|
|
||||||
Fill::wh(lay!([
|
Fill::wh(lay!([
|
||||||
&self.size,
|
&self.size,
|
||||||
Fill::wh(Align::s(Fixed::h(2, GrooveboxStatus::from(self)))),
|
Fill::wh(Align::s(Fixed::h(2, GrooveboxStatus::from(self)))),
|
||||||
|
|
@ -82,18 +81,8 @@ render!(<Tui>|self:GrooveboxTui|{
|
||||||
Tui::split_w(false, pool_w,
|
Tui::split_w(false, pool_w,
|
||||||
Tui::pull_y(1, Fill::h(Align::e(PoolView(&self.pool)))),
|
Tui::pull_y(1, Fill::h(Align::e(PoolView(&self.pool)))),
|
||||||
Tui::split_e(false, sampler_w, Fill::wh(col!([
|
Tui::split_e(false, sampler_w, Fill::wh(col!([
|
||||||
&format!("L/{:>+9.3}", self.sampler.input_meter[0]),
|
Meters(self.sampler.input_meter.as_ref()),
|
||||||
&format!("R/{:>+9.3}", self.sampler.input_meter[1]),
|
GrooveboxSamples(self),
|
||||||
Fill::wh(col!(note in (self.editor.note_lo().load(Relaxed)..=self.editor.note_hi()).rev() => {
|
|
||||||
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))
|
])), Fill::h(&self.editor))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
@ -102,6 +91,34 @@ render!(<Tui>|self:GrooveboxTui|{
|
||||||
]))
|
]))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct Meters<'a>(&'a[f32]);
|
||||||
|
render!(<Tui>|self: Meters<'a>|col!([
|
||||||
|
&format!("L/{:>+9.3}", self.0[0]),
|
||||||
|
&format!("R/{:>+9.3}", self.0[1]),
|
||||||
|
]));
|
||||||
|
|
||||||
|
struct GrooveboxSamples<'a>(&'a GrooveboxTui);
|
||||||
|
render!(<Tui>|self: GrooveboxSamples<'a>|{
|
||||||
|
let note_lo = self.0.editor.note_lo().load(Relaxed);
|
||||||
|
let note_pt = self.0.editor.note_point();
|
||||||
|
let note_hi = self.0.editor.note_hi();
|
||||||
|
Fill::wh(col!(note in (note_lo..=note_hi).rev() => {
|
||||||
|
let mut bg = if note == note_pt { TuiTheme::g(64) } else { Color::Reset };
|
||||||
|
let mut fg = TuiTheme::g(160);
|
||||||
|
if let Some((index, _)) = self.0.sampler.recording {
|
||||||
|
if note == index {
|
||||||
|
bg = Color::Rgb(64,16,0);
|
||||||
|
fg = Color::Rgb(224,64,32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tui::bg(bg, if let Some(sample) = &self.0.sampler.mapped[note] {
|
||||||
|
todo!()
|
||||||
|
} else {
|
||||||
|
Tui::fg(fg, format!("{note:3} (none) "))
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
pub enum GrooveboxCommand {
|
pub enum GrooveboxCommand {
|
||||||
History(isize),
|
History(isize),
|
||||||
Clock(ClockCommand),
|
Clock(ClockCommand),
|
||||||
|
|
@ -137,7 +154,7 @@ input_to_command!(GrooveboxCommand: <Tui>|state: GrooveboxTui, input|match input
|
||||||
key_pat!(Char('0')) => Enqueue(Some(state.pool.phrases()[0].clone())),
|
key_pat!(Char('0')) => Enqueue(Some(state.pool.phrases()[0].clone())),
|
||||||
|
|
||||||
key_pat!(Shift-Char('R')) => Sampler(
|
key_pat!(Shift-Char('R')) => Sampler(
|
||||||
SamplerCommand::Record(u7::from(state.editor.note_point() as u8))
|
SamplerCommand::RecordBegin(u7::from(state.editor.note_point() as u8))
|
||||||
),
|
),
|
||||||
|
|
||||||
// e: Toggle between editing currently playing or other phrase
|
// e: Toggle between editing currently playing or other phrase
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ pub struct Sampler {
|
||||||
pub jack: Arc<RwLock<JackClient>>,
|
pub jack: Arc<RwLock<JackClient>>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub mapped: [Option<Arc<RwLock<Sample>>>;128],
|
pub mapped: [Option<Arc<RwLock<Sample>>>;128],
|
||||||
|
pub recording: Option<(usize, Sample)>,
|
||||||
pub unmapped: Vec<Arc<RwLock<Sample>>>,
|
pub unmapped: Vec<Arc<RwLock<Sample>>>,
|
||||||
pub voices: Arc<RwLock<Vec<Voice>>>,
|
pub voices: Arc<RwLock<Vec<Voice>>>,
|
||||||
pub midi_in: Port<MidiIn>,
|
pub midi_in: Port<MidiIn>,
|
||||||
|
|
@ -68,8 +69,38 @@ impl Sampler {
|
||||||
voices: Arc::new(RwLock::new(vec![])),
|
voices: Arc::new(RwLock::new(vec![])),
|
||||||
buffer: vec![vec![0.0;16384];2],
|
buffer: vec![vec![0.0;16384];2],
|
||||||
output_gain: 0.5,
|
output_gain: 0.5,
|
||||||
|
recording: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
pub fn cancel_recording (&mut self) {
|
||||||
|
self.recording = None;
|
||||||
|
}
|
||||||
|
pub fn begin_recording (&mut self, index: usize) {
|
||||||
|
self.recording = Some(
|
||||||
|
(index, Sample::new("(new)", 0, 0, vec![vec![];self.audio_ins.len()]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn finish_recording (&mut self) -> Option<Arc<RwLock<Sample>>> {
|
||||||
|
let recording = self.recording.take();
|
||||||
|
if let Some((index, sample)) = recording {
|
||||||
|
let old = self.mapped[index].clone();
|
||||||
|
self.mapped[index] = Some(Arc::new(RwLock::new(sample)));
|
||||||
|
old
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn record_chunk (&mut self, chunks: &[&[f32]]) {
|
||||||
|
if let Some((_, sample)) = &mut self.recording {
|
||||||
|
if chunks.len() != sample.channels.len() {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
for (chunk, channel) in chunks.iter().zip(sample.channels.iter_mut()) {
|
||||||
|
channel.extend_from_slice(chunk)
|
||||||
|
}
|
||||||
|
sample.end += chunks[0].len();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub struct SamplerTui {
|
pub struct SamplerTui {
|
||||||
pub state: Sampler,
|
pub state: Sampler,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ pub enum SamplerTuiCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SamplerCommand {
|
pub enum SamplerCommand {
|
||||||
Record(u7),
|
RecordBegin(u7),
|
||||||
|
RecordCancel,
|
||||||
|
RecordFinish,
|
||||||
SetSample(u7, Option<Arc<RwLock<Sample>>>),
|
SetSample(u7, Option<Arc<RwLock<Sample>>>),
|
||||||
SetGain(f32),
|
SetGain(f32),
|
||||||
NoteOn(u7, u7),
|
NoteOn(u7, u7),
|
||||||
|
|
@ -78,10 +80,17 @@ command!(|self: SamplerCommand, state: Sampler|match self {
|
||||||
state.mapped[i] = sample;
|
state.mapped[i] = sample;
|
||||||
Some(Self::SetSample(index, old))
|
Some(Self::SetSample(index, old))
|
||||||
},
|
},
|
||||||
Self::Record(index) => {
|
Self::RecordBegin(index) => {
|
||||||
let i = index.as_int() as usize;
|
state.begin_recording(index.as_int() as usize);
|
||||||
let old = state.mapped[i].clone();
|
None
|
||||||
Some(Self::SetSample(index, old))
|
},
|
||||||
|
Self::RecordCancel => {
|
||||||
|
state.cancel_recording();
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Self::RecordFinish => {
|
||||||
|
state.finish_recording();
|
||||||
|
None
|
||||||
},
|
},
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue