jammable again - and autoconnects!

This commit is contained in:
🪞👃🪞 2024-07-05 01:28:27 +03:00
parent 3ed9ebddd4
commit 768c2337e7
5 changed files with 98 additions and 59 deletions

View file

@ -63,9 +63,32 @@ const KEYMAP: &'static [KeyBinding<App>] = keymap!(App {
} }
}], }],
[F(1), NONE, "toggle_help", "toggle help", |_: &mut App| {Ok(true)}], [F(1), NONE, "toggle_help", "toggle help", |_: &mut App| {Ok(true)}],
[Char('r'), NONE, "toggle_record", "toggle recording", |_: &mut App| {Ok(true)}], [Char('r'), NONE, "toggle_record", "toggle recording", |app: &mut App| {
[Char('d'), NONE, "toggle_overdub", "toggle overdub", |_: &mut App| {Ok(true)}], app.track_mut().map(|t|t.1.toggle_record());
[Char('m'), NONE, "toggle_monitor", "toggle input monitoring", |_: &mut App| {Ok(true)}], Ok(true)
}],
[Char('d'), NONE, "toggle_overdub", "toggle overdub", |app: &mut App| {
app.track_mut().map(|t|t.1.toggle_overdub());
Ok(true)
}],
[Char('m'), NONE, "toggle_monitor", "toggle input monitoring", |app: &mut App| {
app.track_mut().map(|t|t.1.toggle_monitor());
Ok(true)
}],
//fn toggle_record (s: &mut Launcher) -> Usually<bool> {
//s.sequencer_mut().map(|s|s.recording = !s.recording);
//Ok(true)
//}
//fn toggle_overdub (s: &mut Launcher) -> Usually<bool> {
//s.sequencer_mut().map(|s|s.overdub = !s.overdub);
//Ok(true)
//}
//fn toggle_monitor (s: &mut Launcher) -> Usually<bool> {
//s.sequencer_mut().map(|s|s.monitoring = !s.monitoring);
//Ok(true)
//}
[Up, NONE, "cursor_up", "move cursor up", |app: &mut App| { [Up, NONE, "cursor_up", "move cursor up", |app: &mut App| {
if app.entered { if app.entered {
match app.section { match app.section {
@ -152,7 +175,7 @@ const KEYMAP: &'static [KeyBinding<App>] = keymap!(App {
[Char('d'), CONTROL, "duplicate", "duplicate scene or track", duplicate], [Char('d'), CONTROL, "duplicate", "duplicate scene or track", duplicate],
[Enter, NONE, "activate", "activate item at cursor", enter], [Enter, NONE, "activate", "activate item at cursor", enter],
[Esc, NONE, "escape", "unfocus", escape], [Esc, NONE, "escape", "unfocus", escape],
[Char('r'), CONTROL, "rename", "rename current element", rename], //[Char('r'), CONTROL, "rename", "rename current element", rename],
// [Char('='), NONE, "zoom_in", "Zoom in", zoom_in], // [Char('='), NONE, "zoom_in", "Zoom in", zoom_in],
// [Char('-'), NONE, "zoom_out", "Zoom out", zoom_out], // [Char('-'), NONE, "zoom_out", "Zoom out", zoom_out],
// [Char('a'), NONE, "note_add", "Add note", note_add], // [Char('a'), NONE, "note_add", "Add note", note_add],
@ -347,20 +370,6 @@ fn duplicate (_: &mut App) -> Usually<bool> { Ok(true) }
fn rename (_: &mut App) -> Usually<bool> { Ok(true) } fn rename (_: &mut App) -> Usually<bool> { Ok(true) }
//fn toggle_record (s: &mut Launcher) -> Usually<bool> {
//s.sequencer_mut().map(|s|s.recording = !s.recording);
//Ok(true)
//}
//fn toggle_overdub (s: &mut Launcher) -> Usually<bool> {
//s.sequencer_mut().map(|s|s.overdub = !s.overdub);
//Ok(true)
//}
//fn toggle_monitor (s: &mut Launcher) -> Usually<bool> {
//s.sequencer_mut().map(|s|s.monitoring = !s.monitoring);
//Ok(true)
//}
//use crate::{core::*, model::*}; //use crate::{core::*, model::*};
//use super::focus::*; //use super::focus::*;

View file

@ -33,6 +33,20 @@ pub fn main () -> Usually<()> {
state.playing = Some(TransportState::Stopped); state.playing = Some(TransportState::Stopped);
state.midi_in = Some(client.register_port("midi-in", MidiIn)?); state.midi_in = Some(client.register_port("midi-in", MidiIn)?);
let _ = ["nanoKEY Studio.*capture.*"]
.iter()
.map(|name|client
.ports(Some(name), None, PortFlags::empty())
.iter()
.map(|name|{
if let Some(port) = client.port_by_name(name) {
client.connect_ports(&port, &state.midi_in.as_ref().unwrap())?;
}
Ok(())
})
.collect::<Usually<()>>())
.collect::<Usually<()>>()?;
let timebase = &state.timebase; let timebase = &state.timebase;
let ppq = timebase.ppq() as usize; let ppq = timebase.ppq() as usize;
state.track_cursor = 1; state.track_cursor = 1;
@ -54,7 +68,9 @@ pub fn main () -> Usually<()> {
state.add_track_with_cb(Some("Drums"), |_, track|{ state.add_track_with_cb(Some("Drums"), |_, track|{
track.add_device_with_cb(Sampler::new("Sampler", Some(BTreeMap::from([ track.add_device_with_cb(Sampler::new("Sampler", Some(BTreeMap::from([
sample!(36, "Kick", "/home/user/Lab/Music/pak/kik.wav"), sample!(34, "808", "/home/user/Lab/Music/pak/808.wav"),
sample!(35, "Kick1", "/home/user/Lab/Music/pak/kik.wav"),
sample!(36, "Kick2", "/home/user/Lab/Music/pak/kik2.wav"),
sample!(40, "Snare", "/home/user/Lab/Music/pak/sna.wav"), sample!(40, "Snare", "/home/user/Lab/Music/pak/sna.wav"),
sample!(44, "Hihat", "/home/user/Lab/Music/pak/chh.wav"), sample!(44, "Hihat", "/home/user/Lab/Music/pak/chh.wav"),
])))?, |track, device|{ ])))?, |track, device|{
@ -89,13 +105,13 @@ pub fn main () -> Usually<()> {
00 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }, 00 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
04 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() }, 04 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
08 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }, 08 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
10 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }, 10 * ppq/4 => MidiMessage::NoteOn { key: 35.into(), vel: 100.into() },
12 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() }, 12 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
})); }));
track.add_phrase("Garage", ppq * 4, Some(phrase! { track.add_phrase("Garage", ppq * 4, Some(phrase! {
00 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }, 00 * ppq/4 => MidiMessage::NoteOn { key: 35.into(), vel: 100.into() },
04 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() }, 04 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
11 * ppq/4 => MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }, 11 * ppq/4 => MidiMessage::NoteOn { key: 35.into(), vel: 100.into() },
12 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() }, 12 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
})); }));
Ok(()) Ok(())
@ -105,7 +121,8 @@ pub fn main () -> Usually<()> {
track.add_device_with_cb(Plugin::lv2( track.add_device_with_cb(Plugin::lv2(
"Odin2", "Odin2",
"file:///home/user/.lv2/Odin2.lv2" "file:///home/user/.lv2/Odin2.lv2"
)?, |_, device|{ )?, |track, device|{
device.connect_midi_in(0, &track.midi_out.clone_unowned())?;
if let Some(Some(left)) = outputs.get(0) { if let Some(Some(left)) = outputs.get(0) {
device.connect_audio_out(0, left)?; device.connect_audio_out(0, left)?;
} }
@ -208,7 +225,7 @@ process!(App |self, _client, scope| {
&self.timebase, &self.timebase,
self.playing, self.playing,
&scope, &scope,
frame, self.playhead,
frames, frames,
panic, panic,
); );

View file

@ -70,6 +70,7 @@ impl Sampler {
// dropping voices that have reached their ends. // dropping voices that have reached their ends.
let mut voices = vec![]; let mut voices = vec![];
std::mem::swap(&mut voices, &mut self.voices); std::mem::swap(&mut voices, &mut self.voices);
let gain = 0.5;
loop { loop {
if voices.len() < 1 { if voices.len() < 1 {
break break
@ -79,7 +80,7 @@ impl Sampler {
for (i, channel) in chunk.iter().enumerate() { for (i, channel) in chunk.iter().enumerate() {
let buffer = &mut mixed[i % channel_count]; let buffer = &mut mixed[i % channel_count];
for (i, sample) in channel.iter().enumerate() { for (i, sample) in channel.iter().enumerate() {
buffer[i] += sample; buffer[i] += sample * gain;
} }
} }
self.voices.push(voice); self.voices.push(voice);

View file

@ -61,7 +61,7 @@ impl Track {
frames: usize, frames: usize,
panic: bool, panic: bool,
) { ) {
// Need to be borrowed outside the conditional // Need to be borrowed outside the conditionals?
let recording = self.recording; let recording = self.recording;
let monitoring = self.monitoring; let monitoring = self.monitoring;
// Output buffer // Output buffer
@ -82,39 +82,42 @@ impl Track {
} }
} }
// Monitor and record input // Monitor and record input
let phrase = &mut self.phrase_mut(); if self.recording || self.monitoring {
for (time, event, bytes) in parse_midi_input(input) { let phrase = &mut self.phrase_mut();
let pulse = timebase.frames_pulses((frame0 + time) as f64) as usize; for (time, event, bytes) in parse_midi_input(input) {
match event { match event {
LiveEvent::Midi { message, .. } => { LiveEvent::Midi { message, .. } => {
if monitoring { if monitoring {
if let Some(Some(frame)) = output.get_mut(time) { if let Some(Some(frame)) = output.get_mut(time) {
frame.push(bytes.into()) frame.push(bytes.into())
} else {
output[time] = Some(vec![bytes.into()]);
}
}
if recording {
if let Some(phrase) = phrase {
let contains = phrase.notes.contains_key(&pulse);
if contains {
phrase.notes.get_mut(&pulse).unwrap().push(message.clone());
} else { } else {
phrase.notes.insert(pulse, vec![message.clone()]); output[time] = Some(vec![bytes.into()]);
} }
};
}
match message {
MidiMessage::NoteOn { key, .. } => {
notes_on[key.as_int() as usize] = true;
} }
MidiMessage::NoteOff { key, .. } => { if recording {
notes_on[key.as_int() as usize] = false; if let Some(phrase) = phrase {
}, let pulse = timebase.frames_pulses((frame0 + time) as f64) as usize;
_ => {} let pulse = pulse % phrase.length;
} let contains = phrase.notes.contains_key(&pulse);
}, if contains {
_ => {} phrase.notes.get_mut(&pulse).unwrap().push(message.clone());
} else {
phrase.notes.insert(pulse, vec![message.clone()]);
}
};
}
match message {
MidiMessage::NoteOn { key, .. } => {
notes_on[key.as_int() as usize] = true;
}
MidiMessage::NoteOff { key, .. } => {
notes_on[key.as_int() as usize] = false;
},
_ => {}
}
},
_ => {}
}
} }
} }
self.notes_on = notes_on; self.notes_on = notes_on;
@ -171,4 +174,13 @@ impl Track {
let index = self.phrases.len() - 1; let index = self.phrases.len() - 1;
&mut self.phrases[index] &mut self.phrases[index]
} }
pub fn toggle_monitor (&mut self) {
self.monitoring = !self.monitoring;
}
pub fn toggle_record (&mut self) {
self.recording = !self.recording;
}
pub fn toggle_overdub (&mut self) {
self.overdub = !self.overdub;
}
} }

View file

@ -21,9 +21,9 @@ render!(App |self, buf, area| {
y = y + TransportView { y = y + TransportView {
timebase: &self.timebase, timebase: &self.timebase,
playing: *self.playing.as_ref().unwrap_or(&TransportState::Stopped), playing: *self.playing.as_ref().unwrap_or(&TransportState::Stopped),
record: false, monitor: self.track().map(|t|t.1.monitoring).unwrap_or(false),
overdub: false, record: self.track().map(|t|t.1.recording).unwrap_or(false),
monitor: false, overdub: self.track().map(|t|t.1.overdub).unwrap_or(false),
frame: self.playhead, frame: self.playhead,
}.render(buf, area)?.height; }.render(buf, area)?.height;