mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 20:26:42 +01:00
add from_jack!
This commit is contained in:
parent
8cf42aff0b
commit
0496ed6251
4 changed files with 97 additions and 91 deletions
|
|
@ -24,6 +24,17 @@ pub trait Audio: Send + Sync {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export] macro_rules! from_jack {
|
||||||
|
(|$jack:ident|$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)? $cb:expr) => {
|
||||||
|
impl $(<$($L),*$($T $(: $U)?),*>)? TryFrom<&Arc<RwLock<JackClient>>> for $Struct $(<$($L),*$($T),*>)? {
|
||||||
|
type Error = Box<dyn std::error::Error>;
|
||||||
|
fn try_from ($jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
|
||||||
|
Ok($cb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub trait HasMidiIns {
|
pub trait HasMidiIns {
|
||||||
fn midi_ins (&self) -> &Vec<Port<MidiIn>>;
|
fn midi_ins (&self) -> &Vec<Port<MidiIn>>;
|
||||||
fn midi_ins_mut (&mut self) -> &mut Vec<Port<MidiIn>>;
|
fn midi_ins_mut (&mut self) -> &mut Vec<Port<MidiIn>>;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
pub enum Cond<E: Engine, A: Render<E>, B: Render<E>> {
|
||||||
|
_Unused(E),
|
||||||
|
When(bool, A),
|
||||||
|
Either(bool, A, B)
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: Engine, R: Render<E>> LayoutCond<E> for R {}
|
impl<E: Engine, R: Render<E>> LayoutCond<E> for R {}
|
||||||
|
|
||||||
pub trait LayoutCond<E: Engine>: Render<E> + Sized {
|
pub trait LayoutCond<E: Engine>: Render<E> + Sized {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for GrooveboxTui {
|
||||||
sequencer,
|
sequencer,
|
||||||
sampler: SamplerTui::try_from(jack)?,
|
sampler: SamplerTui::try_from(jack)?,
|
||||||
split: 16,
|
split: 16,
|
||||||
focus: GrooveboxFocus::Sequencer,
|
focus: GrooveboxFocus::Sampler,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,44 @@ use symphonia::core::probe::Hint;
|
||||||
use symphonia::core::audio::SampleBuffer;
|
use symphonia::core::audio::SampleBuffer;
|
||||||
use symphonia::default::get_codecs;
|
use symphonia::default::get_codecs;
|
||||||
|
|
||||||
|
pub struct SamplerTui {
|
||||||
|
pub state: Sampler,
|
||||||
|
pub cursor: (usize, usize),
|
||||||
|
pub editing: Option<Arc<RwLock<Sample>>>,
|
||||||
|
pub mode: Option<SamplerMode>,
|
||||||
|
}
|
||||||
|
pub enum SamplerMode {
|
||||||
|
// Load sample from path
|
||||||
|
Import(usize, FileBrowser),
|
||||||
|
}
|
||||||
|
from_jack!(|jack|SamplerTui{
|
||||||
|
let midi_in = jack.read().unwrap().client().register_port("in", MidiIn::default())?;
|
||||||
|
let audio_outs = vec![
|
||||||
|
jack.read().unwrap().client().register_port("outL", AudioOut::default())?,
|
||||||
|
jack.read().unwrap().client().register_port("outR", AudioOut::default())?,
|
||||||
|
];
|
||||||
|
Self {
|
||||||
|
cursor: (0, 0),
|
||||||
|
editing: None,
|
||||||
|
mode: None,
|
||||||
|
state: Sampler {
|
||||||
|
jack: jack.clone(),
|
||||||
|
name: "Sampler".into(),
|
||||||
|
mapped: BTreeMap::new(),
|
||||||
|
unmapped: vec![],
|
||||||
|
voices: Arc::new(RwLock::new(vec![])),
|
||||||
|
buffer: vec![vec![0.0;16384];2],
|
||||||
|
output_gain: 0.5,
|
||||||
|
midi_in,
|
||||||
|
audio_outs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
handle!(<Tui>|self:SamplerTui,input|SamplerCommand::execute_with_state(self, input));
|
||||||
pub enum SamplerCommand {
|
pub enum SamplerCommand {
|
||||||
Import(FileBrowserCommand),
|
Import(FileBrowserCommand),
|
||||||
|
SelectNote(usize),
|
||||||
|
SelectField(usize),
|
||||||
SetName(String),
|
SetName(String),
|
||||||
SetNote(u7, Arc<RwLock<Sample>>),
|
SetNote(u7, Arc<RwLock<Sample>>),
|
||||||
SetGain(f32),
|
SetGain(f32),
|
||||||
|
|
@ -18,7 +54,34 @@ pub enum SamplerCommand {
|
||||||
}
|
}
|
||||||
input_to_command!(SamplerCommand:<Tui>|state:SamplerTui,input|match state.mode {
|
input_to_command!(SamplerCommand:<Tui>|state:SamplerTui,input|match state.mode {
|
||||||
Some(SamplerMode::Import(..)) => Self::Import(FileBrowserCommand::input_to_command(state, input)?),
|
Some(SamplerMode::Import(..)) => Self::Import(FileBrowserCommand::input_to_command(state, input)?),
|
||||||
_ => return None
|
_ => todo!()
|
||||||
|
//_ => match input.event() {
|
||||||
|
//key_pat!(KeyCode::Up) => state.cursor.0 = if state.cursor.0 == 0 {
|
||||||
|
//mapped.len() + unmapped.len() - 1
|
||||||
|
//} else {
|
||||||
|
//state.cursor.0 - 1
|
||||||
|
//},
|
||||||
|
//key_pat!(KeyCode::Down) => {
|
||||||
|
//state.cursor.0 = (state.cursor.0 + 1) % (mapped.len() + unmapped.len());
|
||||||
|
//},
|
||||||
|
//key_pat!(KeyCode::Char('p')) => if let Some(sample) = self.sample() {
|
||||||
|
//voices.write().unwrap().push(Sample::play(sample, 0, &100.into()));
|
||||||
|
//},
|
||||||
|
//key_pat!(KeyCode::Char('a')) => {
|
||||||
|
//let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
||||||
|
//self.mode = None;//Some(Exit::boxed(AddSampleModal::new(&sample, &voices)?));
|
||||||
|
//unmapped.push(sample);
|
||||||
|
//},
|
||||||
|
//key_pat!(KeyCode::Char('r')) => if let Some(sample) = self.sample() {
|
||||||
|
//self.mode = None;//Some(Exit::boxed(AddSampleModal::new(&sample, &voices)?));
|
||||||
|
//},
|
||||||
|
//key_pat!(KeyCode::Enter) => if let Some(sample) = self.sample() {
|
||||||
|
//self.editing = Some(sample.clone());
|
||||||
|
//},
|
||||||
|
//_ => {
|
||||||
|
//return Ok(None)
|
||||||
|
//}
|
||||||
|
//}
|
||||||
});
|
});
|
||||||
input_to_command!(FileBrowserCommand:<Tui>|state:SamplerTui,input|match input {
|
input_to_command!(FileBrowserCommand:<Tui>|state:SamplerTui,input|match input {
|
||||||
_ => return None
|
_ => return None
|
||||||
|
|
@ -35,44 +98,21 @@ command!(|self:SamplerCommand,state:SamplerTui|match self {
|
||||||
command!(|self:FileBrowserCommand,state:SamplerTui|match self {
|
command!(|self:FileBrowserCommand,state:SamplerTui|match self {
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
});
|
});
|
||||||
|
impl SamplerTui {
|
||||||
impl TryFrom<&Arc<RwLock<JackClient>>> for SamplerTui {
|
/// Immutable reference to sample at cursor.
|
||||||
type Error = Box<dyn std::error::Error>;
|
pub fn sample (&self) -> Option<&Arc<RwLock<Sample>>> {
|
||||||
fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
|
for (i, sample) in self.state.mapped.values().enumerate() {
|
||||||
let midi_in = jack.read().unwrap().client().register_port("in", MidiIn::default())?;
|
if i == self.cursor.0 {
|
||||||
let audio_outs = vec![
|
return Some(sample)
|
||||||
jack.read().unwrap().client().register_port("outL", AudioOut::default())?,
|
|
||||||
jack.read().unwrap().client().register_port("outR", AudioOut::default())?,
|
|
||||||
];
|
|
||||||
Ok(Self {
|
|
||||||
cursor: (0, 0),
|
|
||||||
editing: None,
|
|
||||||
mode: None,
|
|
||||||
state: Sampler {
|
|
||||||
jack: jack.clone(),
|
|
||||||
name: "Sampler".into(),
|
|
||||||
mapped: BTreeMap::new(),
|
|
||||||
unmapped: vec![],
|
|
||||||
voices: Arc::new(RwLock::new(vec![])),
|
|
||||||
buffer: vec![vec![0.0;16384];2],
|
|
||||||
output_gain: 0.5,
|
|
||||||
midi_in,
|
|
||||||
audio_outs,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i, sample) in self.state.unmapped.iter().enumerate() {
|
||||||
pub struct SamplerTui {
|
if i + self.state.mapped.len() == self.cursor.0 {
|
||||||
pub state: Sampler,
|
return Some(sample)
|
||||||
pub cursor: (usize, usize),
|
}
|
||||||
pub editing: Option<Arc<RwLock<Sample>>>,
|
}
|
||||||
pub mode: Option<SamplerMode>,
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SamplerMode {
|
|
||||||
// Load sample from path
|
|
||||||
Import(usize, FileBrowser),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
audio!(|self: SamplerTui, _client, scope|{
|
audio!(|self: SamplerTui, _client, scope|{
|
||||||
|
|
@ -82,6 +122,7 @@ audio!(|self: SamplerTui, _client, scope|{
|
||||||
self.state.write_output_buffer(scope);
|
self.state.write_output_buffer(scope);
|
||||||
Control::Continue
|
Control::Continue
|
||||||
});
|
});
|
||||||
|
|
||||||
render!(<Tui>|self: SamplerTui|Tui::min_y(10, Fill::wh(lay!([
|
render!(<Tui>|self: SamplerTui|Tui::min_y(10, Fill::wh(lay!([
|
||||||
|
|
||||||
Fill::wh(render(|to|{ // border
|
Fill::wh(render(|to|{ // border
|
||||||
|
|
@ -113,58 +154,6 @@ render!(<Tui>|self: SamplerTui|Tui::min_y(10, Fill::wh(lay!([
|
||||||
|
|
||||||
]))));
|
]))));
|
||||||
|
|
||||||
handle!(<Tui>|self:SamplerTui,from|{
|
|
||||||
let cursor = &mut self.cursor;
|
|
||||||
let unmapped = &mut self.state.unmapped;
|
|
||||||
let mapped = &self.state.mapped;
|
|
||||||
let voices = &self.state.voices;
|
|
||||||
match from.event() {
|
|
||||||
key_pat!(KeyCode::Up) => cursor.0 = if cursor.0 == 0 {
|
|
||||||
mapped.len() + unmapped.len() - 1
|
|
||||||
} else {
|
|
||||||
cursor.0 - 1
|
|
||||||
},
|
|
||||||
key_pat!(KeyCode::Down) => {
|
|
||||||
cursor.0 = (cursor.0 + 1) % (mapped.len() + unmapped.len());
|
|
||||||
},
|
|
||||||
key_pat!(KeyCode::Char('p')) => if let Some(sample) = self.sample() {
|
|
||||||
voices.write().unwrap().push(Sample::play(sample, 0, &100.into()));
|
|
||||||
},
|
|
||||||
key_pat!(KeyCode::Char('a')) => {
|
|
||||||
let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
|
||||||
self.mode = None;//Some(Exit::boxed(AddSampleModal::new(&sample, &voices)?));
|
|
||||||
unmapped.push(sample);
|
|
||||||
},
|
|
||||||
key_pat!(KeyCode::Char('r')) => if let Some(sample) = self.sample() {
|
|
||||||
self.mode = None;//Some(Exit::boxed(AddSampleModal::new(&sample, &voices)?));
|
|
||||||
},
|
|
||||||
key_pat!(KeyCode::Enter) => if let Some(sample) = self.sample() {
|
|
||||||
self.editing = Some(sample.clone());
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Some(true))
|
|
||||||
});
|
|
||||||
|
|
||||||
impl SamplerTui {
|
|
||||||
/// Immutable reference to sample at cursor.
|
|
||||||
pub fn sample (&self) -> Option<&Arc<RwLock<Sample>>> {
|
|
||||||
for (i, sample) in self.state.mapped.values().enumerate() {
|
|
||||||
if i == self.cursor.0 {
|
|
||||||
return Some(sample)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i, sample) in self.state.unmapped.iter().enumerate() {
|
|
||||||
if i + self.state.mapped.len() == self.cursor.0 {
|
|
||||||
return Some(sample)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AddSampleModal {
|
pub struct AddSampleModal {
|
||||||
exited: bool,
|
exited: bool,
|
||||||
dir: PathBuf,
|
dir: PathBuf,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue