compact sampler

This commit is contained in:
🪞👃🪞 2024-06-29 16:22:47 +03:00
parent 2432f27e8c
commit 15f71d0973
4 changed files with 135 additions and 131 deletions

View file

@ -118,13 +118,13 @@ pub fn render (state: &Chain, buf: &mut Buffer, area: Rect)
}
pub fn draw_as_row (
state: &Chain, buf: &mut Buffer, area: Rect, selected: Option<Style>
state: &Chain, buf: &mut Buffer, area: Rect, _: Option<Style>
) -> Usually<(Rect, Vec<Rect>)> {
let Rect { mut x, mut y, width, height } = area;
let Rect { mut x, y, width, height } = area;
x = x + 1;
let mut h = 0u16;
let mut frames = vec![];
for (i, device) in state.items.iter().enumerate() {
for device in state.items.iter() {
let mut x2 = 1u16;
let mut y2 = 1u16;
for port in device.midi_ins()?.iter() {
@ -160,56 +160,43 @@ pub fn draw_as_row (
pub fn draw_as_column (
state: &Chain, buf: &mut Buffer, area: Rect, selected: Option<Style>
) -> Usually<Rect> {
let Rect { mut x, mut y, width, height } = area;
let Rect { x, y, width, height } = area;
//let (area, areas) = Column::draw(buf, area, &state.items, 0)?;
let mut w = 0u16;
let mut y = area.y;
let mut frames = vec![];
for (i, device) in state.items.iter().enumerate() {
let midi_ins = device.midi_ins()?;
let midi_outs = device.midi_outs()?;
let audio_ins = device.audio_ins()?;
let audio_outs = device.audio_outs()?;
for device in state.items.iter() {
let style_midi = Style::default().black().bold().on_green();
let style_audio = Style::default().black().bold().on_red();
let midi_ins = device.midi_ins()?;
let midi_outs = device.midi_outs()?;
let audio_ins = device.audio_ins()?;
let audio_outs = device.audio_outs()?;
y = y + midi_ins.len() as u16;
let frame = device.render(buf, Rect {
x, y, width, height: height.saturating_sub(y)
})?;
frames.push(frame);
w = w.max(frame.width);
y = y - midi_ins.len() as u16;
for port in midi_ins.iter() {
buf.set_string(x + frame.width - 10, y,
&format!(" <i> MIDI {port} "),
Style::default().black().bold().on_green());
buf.set_string(x + frame.width - 10, y, &format!(" <i> MIDI {port} "), style_midi);
y = y + 1;
}
y = y - audio_ins.len() as u16;
for port in audio_ins.iter() {
buf.set_string(x + frame.width - 10, y,
&format!(" <i> MIDI {port} "),
Style::default().black().bold().on_red());
buf.set_string(x + frame.width - 10, y, &format!(" <i> MIDI {port} "), style_audio);
y = y + 1;
}
y = y + frame.height - 1;
y = y + midi_outs.len() as u16;
for port in midi_outs.iter() {
buf.set_string(x + 2, y,
&format!(" <o> MIDI {port} "),
Style::default().black().bold().on_green());
buf.set_string(x + 2, y, &format!(" <o> MIDI {port} "), style_midi);
y = y + 1;
}
y = y + audio_outs.len() as u16;
for port in audio_outs.iter() {
buf.set_string(x + 2, y,
&format!(" <o> Audio {port} "),
Style::default().black().bold().on_red());
buf.set_string(x + 2, y, &format!(" <o> Audio {port} "), style_audio);
y = y + 1;
}
}

View file

@ -1,29 +1,5 @@
use crate::prelude::*;
pub struct Sampler {
name: String,
cursor: (usize, usize),
samples: Vec<Arc<Sample>>,
voices: Vec<Voice>,
midi_in: Port<MidiIn>,
audio_ins: Vec<Port<AudioIn>>,
audio_outs: Vec<Port<AudioOut>>,
}
pub struct Sample {
name: String,
channels: Vec<Vec<f32>>,
start: usize,
}
impl Sample {
fn new (name: &str) -> Arc<Self> {
Arc::new(Self { name: name.to_string(), channels: vec![], start: 0 })
}
fn play (self: &Arc<Self>) -> Voice {
Voice { sample: self.clone(), position: self.start }
}
}
pub struct Voice {
sample: Arc<Sample>,
position: usize,
@ -39,18 +15,76 @@ impl Voice {
}
}
pub struct Sample {
name: String,
start: usize,
end: usize,
channels: Vec<Vec<f32>>,
}
impl Sample {
fn new (name: &str) -> Arc<Self> {
Arc::new(Self { name: name.to_string(), start: 0, end: 0, channels: vec![] })
}
fn play (self: &Arc<Self>) -> Voice {
Voice { sample: self.clone(), position: self.start }
}
}
pub struct Sampler {
name: String,
cursor: (usize, usize),
samples: BTreeMap<u7, Arc<Sample>>,
voices: Vec<Voice>,
midi_in: Port<MidiIn>,
audio_ins: Vec<Port<AudioIn>>,
audio_outs: Vec<Port<AudioOut>>,
}
impl Sampler {
pub fn new (name: &str) -> Result<DynamicDevice<Self>, Box<dyn Error>> {
let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?;
DynamicDevice::new(render, handle, Self::process, Self {
name: name.into(),
cursor: (0, 0),
samples: vec![
Sample::new("Kick"),
Sample::new("Snare"),
],
voices: vec![
],
samples: BTreeMap::from([
(u7::from_int_lossy(35), Sample {
name: "Kick 1".into(),
start: 0,
end: 100000,
channels: vec![],
}.into()),
(u7::from_int_lossy(36).into(), Sample {
name: "Kick 2".into(),
start: 0,
end: 100000,
channels: vec![],
}.into()),
(u7::from_int_lossy(38).into(), Sample {
name: "Snare 1".into(),
start: 0,
end: 100000,
channels: vec![],
}.into()),
(u7::from_int_lossy(40).into(), Sample {
name: "Snare 2".into(),
start: 50000,
end: 100000,
channels: vec![],
}.into()),
(u7::from_int_lossy(42).into(), Sample {
name: "HH Closed".into(),
start: 0,
end: 50000,
channels: vec![],
}.into()),
(u7::from_int_lossy(46).into(), Sample {
name: "HH Open".into(),
start: 0,
end: 25000,
channels: vec![]
}.into()),
]),
voices: vec![],
midi_in: client.register_port("midi", ::jack::MidiIn::default())?,
audio_ins: vec![
client.register_port("recL", ::jack::AudioIn::default())?,
@ -127,27 +161,27 @@ pub fn render (state: &Sampler, buf: &mut Buffer, Rect { x, y, height, .. }: Rec
{
let width = 40;
let style = Style::default().gray();
//draw_box(buf, Rect { x, y: y, width: 40, height: 12 });
let separator = format!("{}", "-".repeat((width - 2).into()));
separator.blit(buf, x, y + 2, Some(style.dim()));
format!(" {}", state.name).blit(buf, x+1, y+1, Some(style.white().bold()));
for (i, (note, name, cut)) in [
("C4", "Sample#000", format!("{:.03}s",
100000.0/44100.0)),
("C#4", "Sample#001", format!("{:.03}-{:.03}s",
50000.0/44100.0, 100000.0/44100.0)),
("D4", "Sample#002", format!("{:.03}-{:.03}/{:.03}s",
0.0, 50000.0/44100.0, 100000.0/44100.0)),
("D#4", "Sample#003", format!("{:.03}-[{:.03}-{:.03}]/{:.03}s ",
10000.0/44100.0, 25000.0/44100.0, 50000.0/44100.0, 100000.0/44100.0)),
].iter().enumerate() {
format!(" {}", state.name).blit(buf, x+1, y, Some(style.white().bold()));
for (i, (note, sample)) in state.samples.iter().enumerate() {
let style = if i == state.cursor.0 {
Style::default().green()
} else {
Style::default()
};
let i = i as u16;
format!("{note:3} {name}")
.blit(buf, x+2, y+3+i*2, Some(style.bold()));
format!(" {cut}")
.blit(buf, x+2, y+4+i*2, Some(style));
let y1 = y+1+i;
if y1 >= y + height {
break
}
if i as usize == state.cursor.0 {
"".blit(buf, x+1, y1, Some(style.bold()));
}
let label1 = format!("{note:3} {:10}", sample.name);
let label2 = format!("{:>7} {:>7}", sample.start, sample.end);
label1.blit(buf, x+2, y1, Some(style.bold()));
label2.blit(buf, x+3+label1.len()as u16, y1, Some(style));
}
Ok(Rect { x, y, width, height: height - 3 })
Ok(Rect { x, y, width, height })
}
//fn render_table (
@ -194,49 +228,26 @@ pub fn render (state: &Sampler, buf: &mut Buffer, Rect { x, y, height, .. }: Rec
//Ok(())
//}
pub fn handle (_: &mut Sampler, _: &AppEvent) -> Usually<bool> {
Ok(false)
//pub const ACTIONS: [(&'static str, &'static str);2] = [
//("Enter", "Play sample"),
//("Ins/Del", "Add/remove sample"),
//];
//if let Event::Input(crossterm::event::Event::Key(event)) = event {
//match event.code {
//KeyCode::Char('c') => {
//if event.modifiers == KeyModifiers::CONTROL {
//state.exit();
//}
//},
//KeyCode::Down => {
//state.selected_sample = (state.selected_sample + 1) % state.samples.lock().unwrap().len();
//println!("{}", state.selected_sample);
//},
//KeyCode::Up => {
//if state.selected_sample == 0 {
//state.selected_sample = state.samples.lock().unwrap().len() - 1;
//} else {
//state.selected_sample = state.selected_sample - 1;
//}
//println!("{}", state.selected_sample);
//},
//KeyCode::Left => {
//if state.selected_column == 0 {
//state.selected_column = 6
//} else {
//state.selected_column = state.selected_column - 1;
//}
//},
//KeyCode::Right => {
//if state.selected_column == 6 {
//state.selected_column = 0
//} else {
//state.selected_column = state.selected_column + 1;
//}
//},
//_ => {
//println!("{event:?}");
//}
//}
//}
pub fn handle (state: &mut Sampler, event: &AppEvent) -> Usually<bool> {
Ok(handle_keymap(state, event, KEYMAP)?)
}
pub const KEYMAP: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
[Up, NONE, "cursor_up", "move cursor up", cursor_up],
[Down, NONE, "cursor_down", "move cursor down", cursor_down],
[Enter, NONE, "enter", "activate", enter],
});
fn cursor_up (state: &mut Sampler) -> Usually<bool> {
state.cursor.0 = if state.cursor.0 == 0 {
state.samples.len() - 1
} else {
state.cursor.0 - 1
};
Ok(true)
}
fn cursor_down (state: &mut Sampler) -> Usually<bool> {
state.cursor.0 = (state.cursor.0 + 1) % state.samples.len();
Ok(true)
}
fn enter (state: &mut Sampler) -> Usually<bool> {
Ok(true)
}

View file

@ -17,7 +17,12 @@ pub fn handle (state: &mut Launcher, event: &AppEvent) -> Usually<bool> {
}
},
LauncherView::Chains => {
true
let i = state.col().saturating_sub(1);
if let Some(track) = state.tracks.get_mut(i) {
crate::device::chain::handle(&mut *track.chain.state(), event)?
} else {
true
}
}
})
}

View file

@ -171,9 +171,10 @@ pub fn process (state: &mut Launcher, _: &Client, _: &ProcessScope) -> Control {
state.position = transport.pos.frame() as usize;
Control::Continue
}
pub fn render (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
pub fn render (state: &Launcher, buf: &mut Buffer, mut area: Rect) -> Usually<Rect> {
area.width = 80;
area.height = 25;
let Rect { x, y, width, height } = area;
let width = 80;
crate::device::sequencer::draw_play_stop(buf, x + 1, y, &state.playing);
crate::device::sequencer::draw_rec(buf, x + 12, y, state.recording);
crate::device::sequencer::draw_mon(buf, x + 19, y, state.monitoring);
@ -287,12 +288,12 @@ fn draw_section_chains (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usual
} else {
vec![]
};
match state.view {
LauncherView::Chains => {
draw_box_styled(buf, Rect { height: 18, ..area }, style);
},
_ => {},
};
//match state.view {
//LauncherView::Chains => {
//draw_box_styled(buf, Rect { height: 18, ..area }, style);
//},
//_ => {},
//};
draw_highlight(buf, &Some(area), match state.view {
LauncherView::Chains => Style::default().green().dim(),
_ => Style::default().dim()