mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 03:36:41 +01:00
155 lines
5.4 KiB
Rust
155 lines
5.4 KiB
Rust
use crate::*;
|
|
use KeyCode::Char;
|
|
|
|
pub struct SamplerTui {
|
|
pub state: Sampler,
|
|
pub cursor: (usize, usize),
|
|
pub editing: Option<Arc<RwLock<Sample>>>,
|
|
pub mode: Option<SamplerMode>,
|
|
/// Size of actual notes area
|
|
pub size: Measure<Tui>,
|
|
/// Lowest note displayed
|
|
pub note_lo: AtomicUsize,
|
|
pub note_pt: AtomicUsize,
|
|
pub color: ItemPalette
|
|
}
|
|
|
|
impl SamplerTui {
|
|
/// Immutable reference to sample at cursor.
|
|
pub fn sample (&self) -> Option<&Arc<RwLock<Sample>>> {
|
|
for (i, sample) in self.state.mapped.iter().enumerate() {
|
|
if i == self.cursor.0 {
|
|
return sample.as_ref()
|
|
}
|
|
}
|
|
for (i, sample) in self.state.unmapped.iter().enumerate() {
|
|
if i + self.state.mapped.len() == self.cursor.0 {
|
|
return Some(sample)
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
//from_jack!(|jack|SamplerTui{
|
|
//Self {
|
|
//cursor: (0, 0),
|
|
//editing: None,
|
|
//mode: None,
|
|
//size: Measure::new(),
|
|
//note_lo: 36.into(),
|
|
//note_pt: 36.into(),
|
|
//color: ItemPalette::from(Color::Rgb(64, 128, 32)),
|
|
//state: Sampler::new(jack, &"sampler", &[], &[&[], &[]], &[&[], &[]])?,
|
|
//}
|
|
//});
|
|
|
|
render!(<Tui>|self: SamplerTui|{
|
|
let keys_width = 5;
|
|
let keys = move||"";//SamplerKeys(self);
|
|
let fg = self.color.base.rgb;
|
|
let bg = self.color.darkest.rgb;
|
|
let border = Fill::xy(Outer(Style::default().fg(fg).bg(bg)));
|
|
let with_border = |x|lay!([border, Fill::xy(&x)]);
|
|
let with_size = |x|lay!([self.size, x]);
|
|
Tui::bg(bg, Fill::xy(with_border(Bsp::s(
|
|
Tui::fg(self.color.light.rgb, Tui::bold(true, "Sampler")),
|
|
with_size(Shrink::y(1, Bsp::e(
|
|
Fixed::x(keys_width, keys()),
|
|
Fill::xy(render(|to: &mut TuiOutput|Ok({
|
|
let x = to.area.x();
|
|
let bg_base = self.color.darkest.rgb;
|
|
let bg_selected = self.color.darker.rgb;
|
|
let style_empty = Style::default().fg(self.color.base.rgb);
|
|
let style_full = Style::default().fg(self.color.lighter.rgb);
|
|
let note_hi = self.note_hi();
|
|
let note_pt = self.note_point();
|
|
for y in 0..self.size.h() {
|
|
let note = note_hi - y as usize;
|
|
let bg = if note == note_pt { bg_selected } else { bg_base };
|
|
let style = Some(style_empty.bg(bg));
|
|
to.blit(&" (no sample) ", x, to.area.y() + y as u16, style)
|
|
}
|
|
})))
|
|
))),
|
|
))))
|
|
});
|
|
|
|
impl NoteRange for SamplerTui {
|
|
fn note_lo (&self) -> &AtomicUsize { &self.note_lo }
|
|
fn note_axis (&self) -> &AtomicUsize { &self.size.y }
|
|
}
|
|
|
|
impl NotePoint for SamplerTui {
|
|
fn note_len (&self) -> usize {0/*TODO*/}
|
|
fn set_note_len (&self, x: usize) {}
|
|
fn note_point (&self) -> usize { self.note_pt.load(Relaxed) }
|
|
fn set_note_point (&self, x: usize) { self.note_pt.store(x, Relaxed); }
|
|
}
|
|
|
|
pub enum SamplerMode {
|
|
// Load sample from path
|
|
Import(usize, FileBrowser),
|
|
}
|
|
|
|
handle!(<Tui>|self: SamplerTui, input|SamplerTuiCommand::execute_with_state(self, input));
|
|
|
|
pub enum SamplerTuiCommand {
|
|
Import(FileBrowserCommand),
|
|
SelectNote(usize),
|
|
SelectField(usize),
|
|
Sample(SamplerCommand),
|
|
}
|
|
|
|
input_to_command!(SamplerTuiCommand: <Tui>|state: SamplerTui, input|match state.mode {
|
|
Some(SamplerMode::Import(..)) => Self::Import(
|
|
FileBrowserCommand::input_to_command(state, input)?
|
|
),
|
|
_ => match input.event() {
|
|
// load sample
|
|
key_pat!(Shift-Char('L')) => {
|
|
Self::Import(FileBrowserCommand::Begin)
|
|
},
|
|
key_pat!(KeyCode::Up) => {
|
|
Self::SelectNote(state.note_point().overflowing_add(1).0.min(127))
|
|
},
|
|
key_pat!(KeyCode::Down) => {
|
|
Self::SelectNote(state.note_point().overflowing_sub(1).0.min(127))
|
|
},
|
|
_ => return None
|
|
}
|
|
//key_pat!(KeyCode::Char('p')) => if let Some(sample) = self.sample() {
|
|
//voices.write().unwrap().push(Sample::play(sample, 0, &100.into()));
|
|
//},
|
|
//key_pat!(KeyCode::Char('a')) => {
|
|
//let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
|
//self.mode = None;//Some(Exit::boxed(AddSampleModal::new(&sample, &voices)?));
|
|
//unmapped.push(sample);
|
|
//},
|
|
//key_pat!(KeyCode::Char('r')) => if let Some(sample) = self.sample() {
|
|
//self.mode = None;//Some(Exit::boxed(AddSampleModal::new(&sample, &voices)?));
|
|
//},
|
|
//key_pat!(KeyCode::Enter) => if let Some(sample) = self.sample() {
|
|
//self.editing = Some(sample.clone());
|
|
//},
|
|
//_ => {
|
|
//return Ok(None)
|
|
//}
|
|
//}
|
|
});
|
|
|
|
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![])));
|
|
state.mode = Some(SamplerMode::Import(0, FileBrowser::new(None)?));
|
|
None
|
|
},
|
|
Self::SelectNote(index) => {
|
|
let old = state.note_point();
|
|
state.set_note_point(index);
|
|
Some(Self::SelectNote(old))
|
|
},
|
|
Self::Sample(cmd) => cmd.execute(&mut state.state)?.map(Self::Sample),
|
|
_ => todo!()
|
|
});
|