mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +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<()> {
|
fn run (&self) -> Usually<()> {
|
||||||
Tui::run(JackClient::new("tek_groovebox")?.activate_with(|jack|{
|
Tui::run(JackClient::new("tek_groovebox")?.activate_with(|jack|{
|
||||||
let app = tek::GrooveboxTui::try_from(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)?;
|
jack.connect_midi_to(&app.player.midi_outs[0], &self.midi_to)?;
|
||||||
connect_to(&jack, &app.player.midi_outs[0], &self.midi_to)?;
|
|
||||||
|
|
||||||
connect_audio_from(&jack, &app.sampler.audio_ins[0], &self.l_from)?;
|
jack.connect_audio_from(&app.sampler.audio_ins[0], &self.l_from)?;
|
||||||
connect_audio_from(&jack, &app.sampler.audio_ins[1], &self.r_from)?;
|
jack.connect_audio_from(&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_to(&app.sampler.audio_outs[0], &self.l_to)?;
|
||||||
|
jack.connect_audio_to(&app.sampler.audio_outs[1], &self.r_to)?;
|
||||||
|
|
||||||
Ok(app)
|
Ok(app)
|
||||||
})?)?;
|
})?)?;
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,30 @@ audio!(|self: GrooveboxTui, client, scope|{
|
||||||
if Control::Quit == SamplerAudio(&mut self.sampler).process(client, scope) {
|
if Control::Quit == SamplerAudio(&mut self.sampler).process(client, scope) {
|
||||||
return Control::Quit
|
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);
|
self.perf.update(t0, scope);
|
||||||
Control::Continue
|
Control::Continue
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ pub(crate) use self::jack_event::*;
|
||||||
|
|
||||||
pub mod ports;
|
pub mod ports;
|
||||||
pub(crate) use self::ports::*;
|
pub(crate) use self::ports::*;
|
||||||
|
pub use self::ports::RegisterPort;
|
||||||
|
|
||||||
/// Implement [TryFrom<&Arc<RwLock<JackClient>>>]: create app state from wrapped JACK handle.
|
/// Implement [TryFrom<&Arc<RwLock<JackClient>>>]: create app state from wrapped JACK handle.
|
||||||
#[macro_export] macro_rules! from_jack {
|
#[macro_export] macro_rules! from_jack {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,13 @@ pub trait RegisterPort {
|
||||||
fn midi_out (&self, name: &str) -> Usually<Port<MidiOut>>;
|
fn midi_out (&self, name: &str) -> Usually<Port<MidiOut>>;
|
||||||
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>>;
|
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>>;
|
||||||
fn audio_out (&self, name: &str) -> Usually<Port<AudioOut>>;
|
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>> {
|
fn midi_in (&self, name: &str) -> Usually<Port<MidiIn>> {
|
||||||
Ok(self.read().unwrap().client().register_port(name, MidiIn::default())?)
|
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>> {
|
fn audio_in (&self, name: &str) -> Usually<Port<AudioIn>> {
|
||||||
Ok(self.read().unwrap().client().register_port(name, AudioIn::default())?)
|
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.
|
/// Trait for things that may expose JACK ports.
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ impl Sampler {
|
||||||
unmapped: vec![],
|
unmapped: vec![],
|
||||||
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: 1.,
|
||||||
recording: None,
|
recording: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -97,6 +97,7 @@ pub enum SamplerCommand {
|
||||||
RecordCancel,
|
RecordCancel,
|
||||||
RecordFinish,
|
RecordFinish,
|
||||||
SetSample(u7, Option<Arc<RwLock<Sample>>>),
|
SetSample(u7, Option<Arc<RwLock<Sample>>>),
|
||||||
|
SetStart(u7, usize),
|
||||||
SetGain(f32),
|
SetGain(f32),
|
||||||
NoteOn(u7, u7),
|
NoteOn(u7, u7),
|
||||||
NoteOff(u7),
|
NoteOff(u7),
|
||||||
|
|
@ -176,11 +177,14 @@ impl Sampler {
|
||||||
pub fn process_midi_in (&mut self, scope: &ProcessScope) {
|
pub fn process_midi_in (&mut self, scope: &ProcessScope) {
|
||||||
let Sampler { midi_in, mapped, voices, .. } = self;
|
let Sampler { midi_in, mapped, voices, .. } = self;
|
||||||
for RawMidi { time, bytes } in midi_in.iter(scope) {
|
for RawMidi { time, bytes } in midi_in.iter(scope) {
|
||||||
if let LiveEvent::Midi {
|
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
||||||
message: MidiMessage::NoteOn { ref key, ref vel }, ..
|
match message {
|
||||||
} = LiveEvent::parse(bytes).unwrap() {
|
MidiMessage::NoteOn { ref key, ref vel } => {
|
||||||
if let Some(ref sample) = mapped[key.as_int() as usize] {
|
if let Some(ref sample) = mapped[key.as_int() as usize] {
|
||||||
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue