mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
control sample start/end with cc20/21
This commit is contained in:
parent
1859f378ea
commit
b992843e1c
5 changed files with 93 additions and 15 deletions
|
|
@ -32,17 +32,18 @@ impl GrooveboxCli {
|
|||
fn run (&self) -> Usually<()> {
|
||||
Tui::run(JackClient::new("tek_groovebox")?.activate_with(|jack|{
|
||||
let app = tek::GrooveboxTui::try_from(jack)?;
|
||||
let jack = jack.read().unwrap();
|
||||
jack.read().unwrap().client().connect_ports(&app.player.midi_outs[0], &app.sampler.midi_in)?;
|
||||
|
||||
jack.client().connect_ports(&app.player.midi_outs[0], &app.sampler.midi_in)?;
|
||||
jack.connect_midi_from(&app.player.midi_ins[0], &self.midi_from)?;
|
||||
jack.connect_midi_from(&app.sampler.midi_in, &self.midi_from)?;
|
||||
|
||||
connect_from(&jack, &app.player.midi_ins[0], &self.midi_from)?;
|
||||
connect_to(&jack, &app.player.midi_outs[0], &self.midi_to)?;
|
||||
jack.connect_midi_to(&app.player.midi_outs[0], &self.midi_to)?;
|
||||
|
||||
connect_audio_from(&jack, &app.sampler.audio_ins[0], &self.l_from)?;
|
||||
connect_audio_from(&jack, &app.sampler.audio_ins[1], &self.r_from)?;
|
||||
connect_audio_to(&jack, &app.sampler.audio_outs[0], &self.l_to)?;
|
||||
connect_audio_to(&jack, &app.sampler.audio_outs[1], &self.r_to)?;
|
||||
jack.connect_audio_from(&app.sampler.audio_ins[0], &self.l_from)?;
|
||||
jack.connect_audio_from(&app.sampler.audio_ins[1], &self.r_from)?;
|
||||
|
||||
jack.connect_audio_to(&app.sampler.audio_outs[0], &self.l_to)?;
|
||||
jack.connect_audio_to(&app.sampler.audio_outs[1], &self.r_to)?;
|
||||
|
||||
Ok(app)
|
||||
})?)?;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,30 @@ audio!(|self: GrooveboxTui, client, scope|{
|
|||
if Control::Quit == SamplerAudio(&mut self.sampler).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
for RawMidi { time, bytes } in self.sampler.midi_in.iter(scope) {
|
||||
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
||||
match message {
|
||||
MidiMessage::Controller { controller, value } => {
|
||||
if controller == u7::from(20) {
|
||||
if let Some(sample) = &self.sampler.mapped[self.editor.note_point()] {
|
||||
let mut sample = sample.write().unwrap();
|
||||
let percentage = value.as_int() as f64 / 127.;
|
||||
sample.start = (percentage * sample.end as f64) as usize;
|
||||
}
|
||||
} else if controller == u7::from(21) {
|
||||
if let Some(sample) = &self.sampler.mapped[self.editor.note_point()] {
|
||||
let mut sample = sample.write().unwrap();
|
||||
let percentage = value.as_int() as f64 / 127.;
|
||||
let length = sample.channels[0].len();
|
||||
sample.end = sample.start + (percentage * (length as f64 - sample.start as f64)) as usize;
|
||||
sample.end = sample.end.min(length);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.perf.update(t0, scope);
|
||||
Control::Continue
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ pub(crate) use self::jack_event::*;
|
|||
|
||||
pub mod ports;
|
||||
pub(crate) use self::ports::*;
|
||||
pub use self::ports::RegisterPort;
|
||||
|
||||
/// Implement [TryFrom<&Arc<RwLock<JackClient>>>]: create app state from wrapped JACK handle.
|
||||
#[macro_export] macro_rules! from_jack {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@ pub trait RegisterPort {
|
|||
fn midi_out (&self, name: &str) -> Usually<Port<MidiOut>>;
|
||||
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>>;
|
||||
fn audio_out (&self, name: &str) -> Usually<Port<AudioOut>>;
|
||||
fn connect_midi_from (&self, my_input: &Port<MidiIn>, ports: &[String]) -> Usually<()>;
|
||||
fn connect_midi_to (&self, my_output: &Port<MidiOut>, ports: &[String]) -> Usually<()>;
|
||||
fn connect_audio_from (&self, my_input: &Port<AudioIn>, ports: &[String]) -> Usually<()>;
|
||||
fn connect_audio_to (&self, my_output: &Port<AudioOut>, ports: &[String]) -> Usually<()>;
|
||||
}
|
||||
|
||||
impl RegisterPort for &Arc<RwLock<JackClient>> {
|
||||
impl RegisterPort for Arc<RwLock<JackClient>> {
|
||||
fn midi_in (&self, name: &str) -> Usually<Port<MidiIn>> {
|
||||
Ok(self.read().unwrap().client().register_port(name, MidiIn::default())?)
|
||||
}
|
||||
|
|
@ -20,6 +24,50 @@ impl RegisterPort for &Arc<RwLock<JackClient>> {
|
|||
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>> {
|
||||
Ok(self.read().unwrap().client().register_port(name, AudioIn::default())?)
|
||||
}
|
||||
fn connect_midi_from (&self, input: &Port<MidiIn>, ports: &[String]) -> Usually<()> {
|
||||
let jack = self.read().unwrap();
|
||||
for port in ports.iter() {
|
||||
if let Some(port) = jack.port_by_name(port).as_ref() {
|
||||
jack.client().connect_ports(port, input)?;
|
||||
} else {
|
||||
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn connect_midi_to (&self, output: &Port<MidiOut>, ports: &[String]) -> Usually<()> {
|
||||
let jack = self.read().unwrap();
|
||||
for port in ports.iter() {
|
||||
if let Some(port) = jack.port_by_name(port).as_ref() {
|
||||
jack.client().connect_ports(output, port)?;
|
||||
} else {
|
||||
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn connect_audio_from (&self, input: &Port<AudioIn>, ports: &[String]) -> Usually<()> {
|
||||
let jack = self.read().unwrap();
|
||||
for port in ports.iter() {
|
||||
if let Some(port) = jack.port_by_name(port).as_ref() {
|
||||
jack.client().connect_ports(port, input)?;
|
||||
} else {
|
||||
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn connect_audio_to (&self, output: &Port<AudioOut>, ports: &[String]) -> Usually<()> {
|
||||
let jack = self.read().unwrap();
|
||||
for port in ports.iter() {
|
||||
if let Some(port) = jack.port_by_name(port).as_ref() {
|
||||
jack.client().connect_ports(output, port)?;
|
||||
} else {
|
||||
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for things that may expose JACK ports.
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ impl Sampler {
|
|||
unmapped: vec![],
|
||||
voices: Arc::new(RwLock::new(vec![])),
|
||||
buffer: vec![vec![0.0;16384];2],
|
||||
output_gain: 0.5,
|
||||
output_gain: 1.,
|
||||
recording: None,
|
||||
})
|
||||
}
|
||||
|
|
@ -97,6 +97,7 @@ pub enum SamplerCommand {
|
|||
RecordCancel,
|
||||
RecordFinish,
|
||||
SetSample(u7, Option<Arc<RwLock<Sample>>>),
|
||||
SetStart(u7, usize),
|
||||
SetGain(f32),
|
||||
NoteOn(u7, u7),
|
||||
NoteOff(u7),
|
||||
|
|
@ -176,11 +177,14 @@ impl Sampler {
|
|||
pub fn process_midi_in (&mut self, scope: &ProcessScope) {
|
||||
let Sampler { midi_in, mapped, voices, .. } = self;
|
||||
for RawMidi { time, bytes } in midi_in.iter(scope) {
|
||||
if let LiveEvent::Midi {
|
||||
message: MidiMessage::NoteOn { ref key, ref vel }, ..
|
||||
} = LiveEvent::parse(bytes).unwrap() {
|
||||
if let Some(ref sample) = mapped[key.as_int() as usize] {
|
||||
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
||||
match message {
|
||||
MidiMessage::NoteOn { ref key, ref vel } => {
|
||||
if let Some(ref sample) = mapped[key.as_int() as usize] {
|
||||
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue