mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
nice (and working) port connect api
This commit is contained in:
parent
f928b026ed
commit
3ed9ebddd4
7 changed files with 209 additions and 190 deletions
|
|
@ -114,7 +114,9 @@ pub fn main_thread (
|
||||||
terminal.draw(|frame|{
|
terminal.draw(|frame|{
|
||||||
let area = frame.size();
|
let area = frame.size();
|
||||||
let buffer = frame.buffer_mut();
|
let buffer = frame.buffer_mut();
|
||||||
device.lock().unwrap().render(buffer, area).expect("Failed to render content");
|
device.lock().unwrap()
|
||||||
|
.render(buffer, area)
|
||||||
|
.expect("Failed to render content");
|
||||||
}).expect("Failed to render frame");
|
}).expect("Failed to render frame");
|
||||||
|
|
||||||
if exited.fetch_and(true, Ordering::Relaxed) {
|
if exited.fetch_and(true, Ordering::Relaxed) {
|
||||||
|
|
|
||||||
|
|
@ -25,4 +25,16 @@ impl JackDevice {
|
||||||
pub fn state (&self) -> MutexGuard<Box<dyn Device>> {
|
pub fn state (&self) -> MutexGuard<Box<dyn Device>> {
|
||||||
self.state.lock().unwrap()
|
self.state.lock().unwrap()
|
||||||
}
|
}
|
||||||
|
pub fn connect_midi_in (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
|
||||||
|
Ok(self.client.as_client().connect_ports(port, self.midi_ins()?[index])?)
|
||||||
|
}
|
||||||
|
pub fn connect_midi_out (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
|
||||||
|
Ok(self.client.as_client().connect_ports(self.midi_outs()?[index], port)?)
|
||||||
|
}
|
||||||
|
pub fn connect_audio_in (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
|
||||||
|
Ok(self.client.as_client().connect_ports(port, self.audio_ins()?[index])?)
|
||||||
|
}
|
||||||
|
pub fn connect_audio_out (&self, index: usize, port: &Port<Unowned>) -> Usually<()> {
|
||||||
|
Ok(self.client.as_client().connect_ports(self.audio_outs()?[index], port)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,44 @@ use super::*;
|
||||||
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
|
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
|
||||||
/// and activation, and encapsulates a `Device` into a `JackDevice`.
|
/// and activation, and encapsulates a `Device` into a `JackDevice`.
|
||||||
pub struct Jack {
|
pub struct Jack {
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub ports: JackPorts,
|
pub midi_ins: Vec<String>,
|
||||||
|
pub audio_ins: Vec<String>,
|
||||||
|
pub midi_outs: Vec<String>,
|
||||||
|
pub audio_outs: Vec<String>,
|
||||||
}
|
}
|
||||||
impl Jack {
|
impl Jack {
|
||||||
pub fn new (name: &str) -> Usually<Self> {
|
pub fn new (name: &str) -> Usually<Self> {
|
||||||
let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?;
|
Ok(Self {
|
||||||
Ok(Self { client, ports: JackPorts::default() })
|
midi_ins: vec![],
|
||||||
|
audio_ins: vec![],
|
||||||
|
midi_outs: vec![],
|
||||||
|
audio_outs: vec![],
|
||||||
|
client: Client::new(
|
||||||
|
name,
|
||||||
|
ClientOptions::NO_START_SERVER
|
||||||
|
)?.0,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn run <T: Device + Process + Sized + 'static> (
|
pub fn run <T: Device + Process + Sized + 'static> (
|
||||||
mut self, state: impl FnOnce(JackPorts)->Box<T>
|
self, state: impl FnOnce(JackPorts)->Box<T>
|
||||||
)
|
)
|
||||||
-> Usually<JackDevice>
|
-> Usually<JackDevice>
|
||||||
{
|
{
|
||||||
let mut owned_ports = JackPorts::default();
|
let owned_ports = JackPorts {
|
||||||
std::mem::swap(&mut self.ports, &mut owned_ports);
|
audio_ins: register_ports(&self.client, self.audio_ins, AudioIn)?,
|
||||||
let unowned_ports = owned_ports.clone_unowned(&self.client);
|
audio_outs: register_ports(&self.client, self.audio_outs, AudioOut)?,
|
||||||
|
midi_ins: register_ports(&self.client, self.midi_ins, MidiIn)?,
|
||||||
|
midi_outs: register_ports(&self.client, self.midi_outs, MidiOut)?,
|
||||||
|
};
|
||||||
|
let midi_outs = owned_ports.midi_outs.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
|
let midi_ins = owned_ports.midi_ins.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
|
let audio_outs = owned_ports.audio_outs.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
|
let audio_ins = owned_ports.audio_ins.values()
|
||||||
|
.map(|p|Ok(p.name()?)).collect::<Usually<Vec<_>>>()?;
|
||||||
let state = Arc::new(Mutex::new(state(owned_ports) as Box<dyn Device>));
|
let state = Arc::new(Mutex::new(state(owned_ports) as Box<dyn Device>));
|
||||||
let client = self.client.activate_async(
|
let client = self.client.activate_async(
|
||||||
Notifications(Box::new({
|
Notifications(Box::new({
|
||||||
|
|
@ -35,44 +57,68 @@ impl Jack {
|
||||||
}
|
}
|
||||||
}) as BoxedProcessHandler)
|
}) as BoxedProcessHandler)
|
||||||
)?;
|
)?;
|
||||||
Ok(JackDevice { client, state, ports: unowned_ports })
|
Ok(JackDevice {
|
||||||
|
ports: UnownedJackPorts {
|
||||||
|
audio_ins: query_ports(&client.as_client(), audio_ins),
|
||||||
|
audio_outs: query_ports(&client.as_client(), audio_outs),
|
||||||
|
midi_ins: query_ports(&client.as_client(), midi_ins),
|
||||||
|
midi_outs: query_ports(&client.as_client(), midi_outs),
|
||||||
|
},
|
||||||
|
client,
|
||||||
|
state,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn ports_from_lv2 (self, plugin: &::livi::Plugin) -> Usually<Self> {
|
pub fn ports_from_lv2 (self, plugin: &::livi::Plugin) -> Self {
|
||||||
let counts = plugin.port_counts();
|
let counts = plugin.port_counts();
|
||||||
let mut jack = self;
|
let mut jack = self;
|
||||||
for i in 0..counts.atom_sequence_inputs {
|
for i in 0..counts.atom_sequence_inputs {
|
||||||
jack = jack.register_midi_in(&format!("midi-in-{i}"))?
|
jack = jack.midi_in(&format!("midi-in-{i}"))
|
||||||
}
|
}
|
||||||
for i in 0..counts.atom_sequence_outputs {
|
for i in 0..counts.atom_sequence_outputs {
|
||||||
jack = jack.register_midi_out(&format!("midi-out-{i}"))?;
|
jack = jack.midi_out(&format!("midi-out-{i}"));
|
||||||
}
|
}
|
||||||
for i in 0..counts.audio_inputs {
|
for i in 0..counts.audio_inputs {
|
||||||
jack = jack.register_audio_in(&format!("audio-in-{i}"))?
|
jack = jack.audio_in(&format!("audio-in-{i}"));
|
||||||
}
|
}
|
||||||
for i in 0..counts.audio_outputs {
|
for i in 0..counts.audio_outputs {
|
||||||
jack = jack.register_audio_out(&format!("audio-out-{i}"))?;
|
jack = jack.audio_out(&format!("audio-out-{i}"));
|
||||||
}
|
}
|
||||||
Ok(jack)
|
jack
|
||||||
}
|
}
|
||||||
pub fn register_midi_out (mut self, name: &str) -> Usually<Self> {
|
pub fn audio_in (mut self, name: &str) -> Self {
|
||||||
let port = self.client.register_port(name, MidiOut::default())?;
|
self.audio_ins.push(name.to_string());
|
||||||
self.ports.midi_outs.insert(name.to_string(), port);
|
self
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
pub fn register_midi_in (mut self, name: &str) -> Usually<Self> {
|
pub fn audio_out (mut self, name: &str) -> Self {
|
||||||
let port = self.client.register_port(name, MidiIn::default())?;
|
self.audio_outs.push(name.to_string());
|
||||||
self.ports.midi_ins.insert(name.to_string(), port);
|
self
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
pub fn register_audio_out (mut self, name: &str) -> Usually<Self> {
|
pub fn midi_in (mut self, name: &str) -> Self {
|
||||||
let port = self.client.register_port(name, AudioOut::default())?;
|
self.midi_ins.push(name.to_string());
|
||||||
self.ports.audio_outs.insert(name.to_string(), port);
|
self
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
pub fn register_audio_in (mut self, name: &str) -> Usually<Self> {
|
pub fn midi_out (mut self, name: &str) -> Self {
|
||||||
let port = self.client.register_port(name, AudioIn::default())?;
|
self.midi_outs.push(name.to_string());
|
||||||
self.ports.audio_ins.insert(name.to_string(), port);
|
self
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_ports <T: PortSpec + Copy> (
|
||||||
|
client: &Client, names: Vec<String>, spec: T
|
||||||
|
) -> Usually<BTreeMap<String, Port<T>>> {
|
||||||
|
names.into_iter().try_fold(BTreeMap::new(), |mut ports, name|{
|
||||||
|
let port = client.register_port(&name, spec)?;
|
||||||
|
ports.insert(name, port);
|
||||||
|
Ok(ports)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_ports (
|
||||||
|
client: &Client, names: Vec<String>
|
||||||
|
) -> BTreeMap<String, Port<Unowned>> {
|
||||||
|
names.into_iter().fold(BTreeMap::new(), |mut ports, name|{
|
||||||
|
let port = client.port_by_name(&name).unwrap();
|
||||||
|
ports.insert(name, port);
|
||||||
|
ports
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use super::*;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct JackPorts {
|
pub struct JackPorts {
|
||||||
lifesaver: Arc<()>,
|
|
||||||
pub audio_ins: BTreeMap<String, Port<AudioIn>>,
|
pub audio_ins: BTreeMap<String, Port<AudioIn>>,
|
||||||
pub midi_ins: BTreeMap<String, Port<MidiIn>>,
|
pub midi_ins: BTreeMap<String, Port<MidiIn>>,
|
||||||
pub audio_outs: BTreeMap<String, Port<AudioOut>>,
|
pub audio_outs: BTreeMap<String, Port<AudioOut>>,
|
||||||
|
|
@ -18,27 +17,19 @@ pub struct UnownedJackPorts {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JackPorts {
|
impl JackPorts {
|
||||||
pub fn clone_unowned (&self, client: &Client) -> UnownedJackPorts {
|
pub fn clone_unowned (&self) -> UnownedJackPorts {
|
||||||
let mut unowned = UnownedJackPorts::default();
|
let mut unowned = UnownedJackPorts::default();
|
||||||
for (name, port) in self.midi_ins.iter() {
|
for (name, port) in self.midi_ins.iter() {
|
||||||
unowned.midi_ins.insert(name.clone(), unsafe {
|
unowned.midi_ins.insert(name.clone(), port.clone_unowned());
|
||||||
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
for (name, port) in self.midi_outs.iter() {
|
for (name, port) in self.midi_outs.iter() {
|
||||||
unowned.midi_outs.insert(name.clone(), unsafe {
|
unowned.midi_outs.insert(name.clone(), port.clone_unowned());
|
||||||
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
for (name, port) in self.audio_ins.iter() {
|
for (name, port) in self.audio_ins.iter() {
|
||||||
unowned.audio_ins.insert(name.clone(), unsafe {
|
unowned.audio_ins.insert(name.clone(), port.clone_unowned());
|
||||||
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
for (name, port) in self.audio_outs.iter() {
|
for (name, port) in self.audio_outs.iter() {
|
||||||
unowned.audio_outs.insert(name.clone(), unsafe {
|
unowned.audio_outs.insert(name.clone(), port.clone_unowned());
|
||||||
Port::from_raw(::jack::Unowned, client.raw(), port.raw(), Arc::downgrade(&self.lifesaver))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
unowned
|
unowned
|
||||||
}
|
}
|
||||||
|
|
|
||||||
140
src/main.rs
140
src/main.rs
|
|
@ -19,67 +19,60 @@ use crate::{core::*, model::*};
|
||||||
pub fn main () -> Usually<()> {
|
pub fn main () -> Usually<()> {
|
||||||
App::default().run(Some(|app: Arc<Mutex<App>>|{
|
App::default().run(Some(|app: Arc<Mutex<App>>|{
|
||||||
let mut state = app.lock().unwrap();
|
let mut state = app.lock().unwrap();
|
||||||
|
|
||||||
let xdg = Arc::new(microxdg::XdgApp::new("tek")?);
|
let xdg = Arc::new(microxdg::XdgApp::new("tek")?);
|
||||||
state.xdg = Some(xdg.clone());
|
state.xdg = Some(xdg.clone());
|
||||||
|
|
||||||
if crate::config::AppPaths::new(&xdg)?.should_create() {
|
if crate::config::AppPaths::new(&xdg)?.should_create() {
|
||||||
state.modal = Some(Box::new(crate::config::SetupModal(Some(xdg.clone()))));
|
state.modal = Some(Box::new(crate::config::SetupModal(Some(xdg.clone()))));
|
||||||
}
|
}
|
||||||
state.scenes = vec![
|
|
||||||
Scene::new("Intro", vec![None, Some(0), None, None]),
|
let jack = jack_run("tek", &app)?;
|
||||||
Scene::new("Hook", vec![Some(0), Some(0), None, None]),
|
let client = jack.as_client();
|
||||||
Scene::new("Verse", vec![Some(1), Some(0), None, None]),
|
state.transport = Some(client.transport());
|
||||||
Scene::new("Chorus", vec![Some(0), Some(0), None, None]),
|
state.playing = Some(TransportState::Stopped);
|
||||||
Scene::new("Bridge", vec![Some(2), Some(0), None, None]),
|
state.midi_in = Some(client.register_port("midi-in", MidiIn)?);
|
||||||
Scene::new("Outro", vec![None, Some(0), None, None]),
|
|
||||||
];
|
let timebase = &state.timebase;
|
||||||
let jack = jack_run("tek", &app)?;
|
let ppq = timebase.ppq() as usize;
|
||||||
let client = jack.as_client();
|
|
||||||
let timebase = &state.timebase;
|
|
||||||
let ppq = timebase.ppq() as usize;
|
|
||||||
state.track_cursor = 1;
|
state.track_cursor = 1;
|
||||||
state.scene_cursor = 1;
|
state.scene_cursor = 1;
|
||||||
state.note_start = 12;
|
state.note_start = 12;
|
||||||
state.time_zoom = 12;
|
state.time_zoom = 12;
|
||||||
state.transport = Some(client.transport());
|
|
||||||
state.playing = Some(TransportState::Stopped);
|
|
||||||
state.midi_in = Some(client.register_port("midi-in", MidiIn)?);
|
|
||||||
state.jack = Some(jack);
|
|
||||||
|
|
||||||
state.add_track_with_cb(Some("Drums"), |client: &Client, track: &mut Track|{
|
let outputs: Vec<_> = ["Komplete.+:playback_FL", "Komplete.+:playback_FR"]
|
||||||
|
.iter()
|
||||||
|
.map(|name|client
|
||||||
|
.ports(Some(name), None, PortFlags::empty())
|
||||||
|
.get(0)
|
||||||
|
.map(|name|client.port_by_name(name)))
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
state.jack = Some(jack);
|
||||||
|
|
||||||
|
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!(36, "Kick", "/home/user/Lab/Music/pak/kik.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: &Track, device: &mut JackDevice|{
|
])))?, |track, device|{
|
||||||
client.connect_ports(
|
device.connect_midi_in(0, &track.midi_out.clone_unowned())?;
|
||||||
&track.midi_out, &device.midi_ins()?[0]
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
track.add_device_with_cb(Plugin::lv2(
|
track.add_device_with_cb(Plugin::lv2(
|
||||||
"Panagement",
|
"Panagement",
|
||||||
"file:///home/user/.lv2/Auburn Sounds Panagement 2.lv2"
|
"file:///home/user/.lv2/Auburn Sounds Panagement 2.lv2"
|
||||||
)?, |track: &Track, device: &mut JackDevice|{
|
)?, |track, device|{
|
||||||
client.connect_ports(
|
device.connect_audio_in(0, &track.devices[0].audio_outs()?[0])?;
|
||||||
&track.devices[0].audio_outs()?[0], &device.audio_ins()?[0]
|
device.connect_audio_in(0, &track.devices[0].audio_outs()?[1])?;
|
||||||
)?;
|
if let Some(Some(left)) = outputs.get(0) {
|
||||||
let output_left = client
|
device.connect_audio_out(0, left)?;
|
||||||
.ports(Some("Komplete.+:playback_FL"), None, PortFlags::empty())
|
|
||||||
.get(0)
|
|
||||||
.map(|name|client.port_by_name(&name))
|
|
||||||
.flatten();
|
|
||||||
if let Some(output_left) = output_left {
|
|
||||||
client.connect_ports(&device.audio_outs()?[0], &output_left)?;
|
|
||||||
}
|
}
|
||||||
let output_right = client
|
if let Some(Some(right)) = outputs.get(0) {
|
||||||
.ports(Some("Komplete.+:playback_FR"), None, PortFlags::empty())
|
device.connect_audio_out(1, right)?;
|
||||||
.get(0)
|
|
||||||
.map(|name|client.port_by_name(&name))
|
|
||||||
.flatten();
|
|
||||||
if let Some(output_right) = output_right {
|
|
||||||
client.connect_ports(&device.audio_outs()?[0], &output_right)?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
@ -108,26 +101,20 @@ pub fn main () -> Usually<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
state.add_track_with_cb(Some("Bass"), |_client: &Client, track: &mut Track|{
|
state.add_track_with_cb(Some("Bass"), |_, track|{
|
||||||
track.add_device(Plugin::lv2("Odin2", "file:///home/user/.lv2/Odin2.lv2")?)?;
|
track.add_device_with_cb(Plugin::lv2(
|
||||||
|
"Odin2",
|
||||||
|
"file:///home/user/.lv2/Odin2.lv2"
|
||||||
|
)?, |_, device|{
|
||||||
|
if let Some(Some(left)) = outputs.get(0) {
|
||||||
|
device.connect_audio_out(0, left)?;
|
||||||
|
}
|
||||||
|
if let Some(Some(right)) = outputs.get(0) {
|
||||||
|
device.connect_audio_out(1, right)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
track.sequence = Some(0); // FIXME
|
track.sequence = Some(0); // FIXME
|
||||||
//client.connect_ports(&track.midi_out, &track.devices[0].midi_ins()?[0])?;
|
|
||||||
//let output_left = client.ports(Some(".+:playback_FL"), None, PortFlags::empty());
|
|
||||||
//if let Some(
|
|
||||||
//output_left
|
|
||||||
//) = output_left.get(0).map(|name|client.port_by_name(&name)).flatten() {
|
|
||||||
//client.connect_ports(
|
|
||||||
//&track.devices[0].audio_outs()?[0], &output_left
|
|
||||||
//)?;
|
|
||||||
//}
|
|
||||||
//let output_right = client.ports(Some(".+:playback_FR"), None, PortFlags::empty());
|
|
||||||
//if let Some(
|
|
||||||
//output_right
|
|
||||||
//) = output_right.get(0).map(|name|client.port_by_name(&name)).flatten() {
|
|
||||||
//client.connect_ports(
|
|
||||||
//&track.devices[0].audio_outs()?[1], &output_right
|
|
||||||
//)?;
|
|
||||||
//}
|
|
||||||
track.add_phrase("Offbeat", ppq * 4, Some(phrase! {
|
track.add_phrase("Offbeat", ppq * 4, Some(phrase! {
|
||||||
00 * ppq/4 => MidiMessage::NoteOff { key: 40.into(), vel: 100.into() },
|
00 * ppq/4 => MidiMessage::NoteOff { key: 40.into(), vel: 100.into() },
|
||||||
02 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
|
02 * ppq/4 => MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
|
||||||
|
|
@ -141,6 +128,15 @@ pub fn main () -> Usually<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
state.scenes = vec![
|
||||||
|
Scene::new("Intro", vec![None, Some(0), None, None]),
|
||||||
|
Scene::new("Hook", vec![Some(0), Some(0), None, None]),
|
||||||
|
Scene::new("Verse", vec![Some(1), Some(0), None, None]),
|
||||||
|
Scene::new("Chorus", vec![Some(0), Some(0), None, None]),
|
||||||
|
Scene::new("Bridge", vec![Some(2), Some(0), None, None]),
|
||||||
|
Scene::new("Outro", vec![None, Some(0), None, None]),
|
||||||
|
];
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
@ -298,32 +294,4 @@ impl App {
|
||||||
let (_, scene) = self.scene()?;
|
let (_, scene) = self.scene()?;
|
||||||
*scene.clips.get(track_id)?
|
*scene.clips.get(track_id)?
|
||||||
}
|
}
|
||||||
pub fn connect_tracks (&self) -> Usually<()> {
|
|
||||||
//let (client, _status) = Client::new(
|
|
||||||
//&format!("{}-init", &self.name), ClientOptions::NO_START_SERVER
|
|
||||||
//)?;
|
|
||||||
//let midi_ins = client.ports(Some(midi_in), None, PortFlags::IS_OUTPUT);
|
|
||||||
//let audio_outs: Vec<Vec<String>> = audio_outs.iter()
|
|
||||||
//.map(|pattern|client.ports(Some(pattern), None, PortFlags::IS_INPUT))
|
|
||||||
//.collect();
|
|
||||||
//for (i, sequencer) in self.tracks.iter().enumerate() {
|
|
||||||
//for sequencer_midi_in in sequencer.midi_ins()?.iter() {
|
|
||||||
//for midi_in in midi_ins.iter() {
|
|
||||||
//client.connect_ports_by_name(&midi_in, &sequencer_midi_in)?;
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//let chain: &Chain = &self.tracks[i].chain;
|
|
||||||
//for port in sequencer.midi_outs()?.iter() {
|
|
||||||
//for midi_in in chain.midi_ins()?.iter() {
|
|
||||||
//client.connect_ports_by_name(&port, &midi_in)?;
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//for (j, port) in chain.audio_outs()?.iter().enumerate() {
|
|
||||||
//for audio_out in audio_outs[j % audio_outs.len()].iter() {
|
|
||||||
//client.connect_ports_by_name(&port, &audio_out)?;
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ impl super::Plugin {
|
||||||
pub fn lv2 (name: &str, path: &str) -> Usually<JackDevice> {
|
pub fn lv2 (name: &str, path: &str) -> Usually<JackDevice> {
|
||||||
let plugin = LV2Plugin::new(path)?;
|
let plugin = LV2Plugin::new(path)?;
|
||||||
Jack::new(name)?
|
Jack::new(name)?
|
||||||
.ports_from_lv2(&plugin.plugin)?
|
.ports_from_lv2(&plugin.plugin)
|
||||||
.run(|ports|Box::new(Self {
|
.run(|ports|Box::new(Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
path: Some(String::from(path)),
|
path: Some(String::from(path)),
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,5 @@
|
||||||
use crate::core::*;
|
use crate::core::*;
|
||||||
|
|
||||||
pub struct Voice {
|
|
||||||
pub sample: Arc<Sample>,
|
|
||||||
pub after: usize,
|
|
||||||
pub position: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Sample {
|
|
||||||
pub name: String,
|
|
||||||
pub start: usize,
|
|
||||||
pub end: usize,
|
|
||||||
pub channels: Vec<Vec<f32>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Voice {
|
|
||||||
pub fn chunk (&mut self, mut frames: usize) -> Option<Vec<Vec<f32>>> {
|
|
||||||
// Create output buffer for each channel
|
|
||||||
let mut chunk = vec![vec![];self.sample.channels.len()];
|
|
||||||
// If it's not time to play yet, count down
|
|
||||||
if self.after >= frames {
|
|
||||||
self.after = self.after - frames;
|
|
||||||
return Some(chunk)
|
|
||||||
}
|
|
||||||
// If the voice will start playing within the current buffer,
|
|
||||||
// subtract the remaining number of wait frames.
|
|
||||||
if self.after > 0 && self.after < frames {
|
|
||||||
chunk = vec![vec![0.0;self.after];self.sample.channels.len()];
|
|
||||||
frames = frames - self.after;
|
|
||||||
self.after = 0;
|
|
||||||
}
|
|
||||||
if self.position < self.sample.end {
|
|
||||||
let start = self.position.min(self.sample.end);
|
|
||||||
let end = (self.position + frames).min(self.sample.end);
|
|
||||||
for (i, channel) in self.sample.channels.iter().enumerate() {
|
|
||||||
chunk[i].extend_from_slice(&channel[start..end]);
|
|
||||||
};
|
|
||||||
self.position = self.position + frames;
|
|
||||||
Some(chunk)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sample {
|
|
||||||
pub fn new (name: &str, start: usize, end: usize, channels: Vec<Vec<f32>>) -> Arc<Self> {
|
|
||||||
Arc::new(Self { name: name.to_string(), start, end, channels })
|
|
||||||
}
|
|
||||||
pub fn play (self: &Arc<Self>, after: usize) -> Voice {
|
|
||||||
Voice { sample: self.clone(), after, position: self.start }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Sampler {
|
pub struct Sampler {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub cursor: (usize, usize),
|
pub cursor: (usize, usize),
|
||||||
|
|
@ -90,11 +38,11 @@ impl Sampler {
|
||||||
name: &str, samples: Option<BTreeMap<u7, Arc<Sample>>>,
|
name: &str, samples: Option<BTreeMap<u7, Arc<Sample>>>,
|
||||||
) -> Usually<JackDevice> {
|
) -> Usually<JackDevice> {
|
||||||
Jack::new(name)?
|
Jack::new(name)?
|
||||||
.register_midi_in("midi")?
|
.midi_in("midi")
|
||||||
.register_audio_in("recL")?
|
.audio_in("recL")
|
||||||
.register_audio_in("recR")?
|
.audio_in("recR")
|
||||||
.register_audio_out("outL")?
|
.audio_out("outL")
|
||||||
.register_audio_out("outR")?
|
.audio_out("outR")
|
||||||
.run(|ports|Box::new(Self {
|
.run(|ports|Box::new(Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
cursor: (0, 0),
|
cursor: (0, 0),
|
||||||
|
|
@ -168,3 +116,55 @@ impl Sampler {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Sample {
|
||||||
|
pub name: String,
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize,
|
||||||
|
pub channels: Vec<Vec<f32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sample {
|
||||||
|
pub fn new (name: &str, start: usize, end: usize, channels: Vec<Vec<f32>>) -> Arc<Self> {
|
||||||
|
Arc::new(Self { name: name.to_string(), start, end, channels })
|
||||||
|
}
|
||||||
|
pub fn play (self: &Arc<Self>, after: usize) -> Voice {
|
||||||
|
Voice { sample: self.clone(), after, position: self.start }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Voice {
|
||||||
|
pub sample: Arc<Sample>,
|
||||||
|
pub after: usize,
|
||||||
|
pub position: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Voice {
|
||||||
|
pub fn chunk (&mut self, mut frames: usize) -> Option<Vec<Vec<f32>>> {
|
||||||
|
// Create output buffer for each channel
|
||||||
|
let mut chunk = vec![vec![];self.sample.channels.len()];
|
||||||
|
// If it's not time to play yet, count down
|
||||||
|
if self.after >= frames {
|
||||||
|
self.after = self.after - frames;
|
||||||
|
return Some(chunk)
|
||||||
|
}
|
||||||
|
// If the voice will start playing within the current buffer,
|
||||||
|
// subtract the remaining number of wait frames.
|
||||||
|
if self.after > 0 && self.after < frames {
|
||||||
|
chunk = vec![vec![0.0;self.after];self.sample.channels.len()];
|
||||||
|
frames = frames - self.after;
|
||||||
|
self.after = 0;
|
||||||
|
}
|
||||||
|
if self.position < self.sample.end {
|
||||||
|
let start = self.position.min(self.sample.end);
|
||||||
|
let end = (self.position + frames).min(self.sample.end);
|
||||||
|
for (i, channel) in self.sample.channels.iter().enumerate() {
|
||||||
|
chunk[i].extend_from_slice(&channel[start..end]);
|
||||||
|
};
|
||||||
|
self.position = self.position + frames;
|
||||||
|
Some(chunk)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue