mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip: playing symphonia-loaded samples
This commit is contained in:
parent
b29d3ecda2
commit
bdd3e31403
5 changed files with 36 additions and 26 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
(bpm 150)
|
(bpm 150)
|
||||||
|
|
||||||
(midi-in "nanoKEY Studio.*capture.*")
|
(midi-in "nanoKEY Studio.*capture.*")
|
||||||
(audio-out "Komplete.+:playback_FL", "Komplete.+:playback_FR")
|
(audio-out "Built-.+:playback_FL", "Built-.+:playback_FR")
|
||||||
|
|
||||||
(scene { :name "Intro" } 0 0 _ _)
|
(scene { :name "Intro" } 0 0 _ _)
|
||||||
(scene { :name "Hook" } 1 1 0 _)
|
(scene { :name "Hook" } 1 1 0 _)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ pub struct Sampler {
|
||||||
pub editing: Option<Arc<RwLock<Sample>>>,
|
pub editing: Option<Arc<RwLock<Sample>>>,
|
||||||
pub mapped: BTreeMap<u7, Arc<RwLock<Sample>>>,
|
pub mapped: BTreeMap<u7, Arc<RwLock<Sample>>>,
|
||||||
pub unmapped: Vec<Arc<RwLock<Sample>>>,
|
pub unmapped: Vec<Arc<RwLock<Sample>>>,
|
||||||
pub voices: Vec<Voice>,
|
pub voices: Arc<RwLock<Vec<Voice>>>,
|
||||||
pub ports: JackPorts,
|
pub ports: JackPorts,
|
||||||
pub buffer: Vec<Vec<f32>>,
|
pub buffer: Vec<Vec<f32>>,
|
||||||
pub output_gain: f32
|
pub output_gain: f32
|
||||||
|
|
@ -20,7 +20,7 @@ pub struct Sampler {
|
||||||
render!(Sampler |self, buf, area| {
|
render!(Sampler |self, buf, area| {
|
||||||
let Rect { x, y, height, .. } = area;
|
let Rect { x, y, height, .. } = area;
|
||||||
let style = Style::default().gray();
|
let style = Style::default().gray();
|
||||||
let title = format!(" {} ({})", self.name, self.voices.len());
|
let title = format!(" {} ({})", self.name, self.voices.read().unwrap().len());
|
||||||
title.blit(buf, x+1, y, Some(style.white().bold().not_dim()))?;
|
title.blit(buf, x+1, y, Some(style.white().bold().not_dim()))?;
|
||||||
let mut width = title.len() + 2;
|
let mut width = title.len() + 2;
|
||||||
let mut y1 = 1;
|
let mut y1 = 1;
|
||||||
|
|
@ -63,7 +63,7 @@ handle!(Sampler |self, event| handle_keymap(self, event, KEYMAP_SAMPLER));
|
||||||
|
|
||||||
/// Key bindings for sampler device.
|
/// Key bindings for sampler device.
|
||||||
pub const KEYMAP_SAMPLER: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
|
pub const KEYMAP_SAMPLER: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
|
||||||
[Up, NONE, "cursor_up", "move cursor up", |state: &mut Sampler| {
|
[Up, NONE, "/sampler/cursor/up", "move cursor up", |state: &mut Sampler| {
|
||||||
state.cursor.0 = if state.cursor.0 == 0 {
|
state.cursor.0 = if state.cursor.0 == 0 {
|
||||||
state.mapped.len() + state.unmapped.len() - 1
|
state.mapped.len() + state.unmapped.len() - 1
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -71,29 +71,29 @@ pub const KEYMAP_SAMPLER: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
|
||||||
};
|
};
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
[Down, NONE, "cursor_down", "move cursor down", |state: &mut Sampler| {
|
[Down, NONE, "/sampler/cursor/down", "move cursor down", |state: &mut Sampler| {
|
||||||
state.cursor.0 = (state.cursor.0 + 1) % (state.mapped.len() + state.unmapped.len());
|
state.cursor.0 = (state.cursor.0 + 1) % (state.mapped.len() + state.unmapped.len());
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
[Char('t'), NONE, "sample_play", "play current sample", |state: &mut Sampler| {
|
[Char('t'), NONE, "/sampler/play", "play current sample", |state: &mut Sampler| {
|
||||||
if let Some(sample) = state.sample() {
|
if let Some(sample) = state.sample() {
|
||||||
state.voices.push(Sample::play(sample, 0, &100.into()))
|
state.voices.write().unwrap().push(Sample::play(sample, 0, &100.into()));
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
[Char('a'), NONE, "sample_add", "add a new sample", |state: &mut Sampler| {
|
[Char('a'), NONE, "/sampler/add", "add a new sample", |state: &mut Sampler| {
|
||||||
let sample = Sample::new("", 0, 0, vec![]);
|
let sample = Arc::new(RwLock::new(Sample::new("", 0, 0, vec![])));
|
||||||
*MODAL.lock().unwrap() = Some(Exit::boxed(AddSampleModal::new(&sample)?));
|
*MODAL.lock().unwrap() = Some(Exit::boxed(AddSampleModal::new(&sample, &state.voices)?));
|
||||||
state.unmapped.push(sample);
|
state.unmapped.push(sample);
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
[Char('r'), NONE, "sample_replace", "replace selected sample", |state: &mut Sampler| {
|
[Char('r'), NONE, "/sampler/replace", "replace selected sample", |state: &mut Sampler| {
|
||||||
if let Some(sample) = state.sample() {
|
if let Some(sample) = state.sample() {
|
||||||
*MODAL.lock().unwrap() = Some(Exit::boxed(AddSampleModal::new(&sample)?));
|
*MODAL.lock().unwrap() = Some(Exit::boxed(AddSampleModal::new(&sample, &state.voices)?));
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
[Enter, NONE, "sample_edit", "edit selected sample", |state: &mut Sampler| {
|
[Enter, NONE, "/sampler/edit", "edit selected sample", |state: &mut Sampler| {
|
||||||
if let Some(sample) = state.sample() {
|
if let Some(sample) = state.sample() {
|
||||||
state.editing = Some(sample.clone());
|
state.editing = Some(sample.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +117,7 @@ impl Sampler {
|
||||||
editing: None,
|
editing: None,
|
||||||
mapped: mapped.unwrap_or_else(||BTreeMap::new()),
|
mapped: mapped.unwrap_or_else(||BTreeMap::new()),
|
||||||
unmapped: vec![],
|
unmapped: vec![],
|
||||||
voices: vec![],
|
voices: Arc::new(RwLock::new(vec![])),
|
||||||
ports,
|
ports,
|
||||||
buffer: vec![vec![0.0;16384];2],
|
buffer: vec![vec![0.0;16384];2],
|
||||||
output_gain: 0.5,
|
output_gain: 0.5,
|
||||||
|
|
@ -153,7 +153,7 @@ impl Sampler {
|
||||||
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
||||||
if let MidiMessage::NoteOn { ref key, ref vel } = message {
|
if let MidiMessage::NoteOn { ref key, ref vel } = message {
|
||||||
if let Some(sample) = self.mapped.get(key) {
|
if let Some(sample) = self.mapped.get(key) {
|
||||||
self.voices.push(Sample::play(sample, time as usize, vel));
|
self.voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -170,7 +170,7 @@ impl Sampler {
|
||||||
/// Mix all currently playing samples into the output.
|
/// Mix all currently playing samples into the output.
|
||||||
fn process_audio_out (&mut self, scope: &ProcessScope) {
|
fn process_audio_out (&mut self, scope: &ProcessScope) {
|
||||||
let channel_count = self.buffer.len();
|
let channel_count = self.buffer.len();
|
||||||
self.voices.retain_mut(|voice|{
|
self.voices.write().unwrap().retain_mut(|voice|{
|
||||||
for index in 0..scope.n_frames() as usize {
|
for index in 0..scope.n_frames() as usize {
|
||||||
if let Some(frame) = voice.next() {
|
if let Some(frame) = voice.next() {
|
||||||
for (channel, sample) in frame.iter().enumerate() {
|
for (channel, sample) in frame.iter().enumerate() {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ pub struct AddSampleModal {
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
sample: Arc<RwLock<Sample>>,
|
sample: Arc<RwLock<Sample>>,
|
||||||
|
voices: Arc<RwLock<Vec<Voice>>>,
|
||||||
_search: Option<String>,
|
_search: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +66,10 @@ handle!(AddSampleModal |self,e|{
|
||||||
});
|
});
|
||||||
|
|
||||||
impl AddSampleModal {
|
impl AddSampleModal {
|
||||||
pub fn new (sample: &Arc<RwLock<Sample>>) -> Usually<Self> {
|
pub fn new (
|
||||||
|
sample: &Arc<RwLock<Sample>>,
|
||||||
|
voices: &Arc<RwLock<Vec<Voice>>>
|
||||||
|
) -> Usually<Self> {
|
||||||
let dir = std::env::current_dir()?;
|
let dir = std::env::current_dir()?;
|
||||||
let (subdirs, files) = scan(&dir)?;
|
let (subdirs, files) = scan(&dir)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
@ -76,6 +80,7 @@ impl AddSampleModal {
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
sample: sample.clone(),
|
sample: sample.clone(),
|
||||||
|
voices: voices.clone(),
|
||||||
_search: None
|
_search: None
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +98,12 @@ impl AddSampleModal {
|
||||||
}
|
}
|
||||||
fn try_preview (&mut self) -> Usually<()> {
|
fn try_preview (&mut self) -> Usually<()> {
|
||||||
if let Some(path) = self.cursor_file() {
|
if let Some(path) = self.cursor_file() {
|
||||||
|
if let Ok(sample) = Sample::from_file(&path) {
|
||||||
|
*self.sample.write().unwrap() = sample;
|
||||||
|
self.voices.write().unwrap().push(
|
||||||
|
Sample::play(&self.sample, 0, &u7::from(100u8))
|
||||||
|
);
|
||||||
|
}
|
||||||
//load_sample(&path)?;
|
//load_sample(&path)?;
|
||||||
//let src = std::fs::File::open(&path)?;
|
//let src = std::fs::File::open(&path)?;
|
||||||
//let mss = MediaSourceStream::new(Box::new(src), Default::default());
|
//let mss = MediaSourceStream::new(Box::new(src), Default::default());
|
||||||
|
|
@ -198,9 +209,9 @@ fn scan (dir: &PathBuf) -> Usually<(Vec<OsString>, Vec<OsString>)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sample {
|
impl Sample {
|
||||||
fn from_file (path: &PathBuf) -> Usually<Arc<RwLock<Self>>> {
|
fn from_file (path: &PathBuf) -> Usually<Self> {
|
||||||
let mut sample = Self::default();
|
let mut sample = Self::default();
|
||||||
sample.name = path.to_string_lossy().into();
|
sample.name = path.file_name().unwrap().to_string_lossy().into();
|
||||||
// Use file extension if present
|
// Use file extension if present
|
||||||
let mut hint = Hint::new();
|
let mut hint = Hint::new();
|
||||||
if let Some(ext) = path.extension() {
|
if let Some(ext) = path.extension() {
|
||||||
|
|
@ -256,6 +267,7 @@ impl Sample {
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
Ok(Arc::new(RwLock::new(sample)))
|
sample.end = sample.channels.iter().fold(0, |l, c|l + c.len());
|
||||||
|
Ok(sample)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::core::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A sound sample.
|
/// A sound sample.
|
||||||
#[derive(Default)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Sample {
|
pub struct Sample {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
|
|
@ -12,10 +12,8 @@ pub struct Sample {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sample {
|
impl Sample {
|
||||||
pub fn new (
|
pub fn new (name: &str, start: usize, end: usize, channels: Vec<Vec<f32>>) -> Self {
|
||||||
name: &str, start: usize, end: usize, channels: Vec<Vec<f32>>
|
Self { name: name.to_string(), start, end, channels, rate: None }
|
||||||
) -> Arc<RwLock<Self>> {
|
|
||||||
Arc::new(RwLock::new(Self { name: name.to_string(), start, end, channels, rate: None }))
|
|
||||||
}
|
}
|
||||||
pub fn play (sample: &Arc<RwLock<Self>>, after: usize, velocity: &u7) -> Voice {
|
pub fn play (sample: &Arc<RwLock<Self>>, after: usize, velocity: &u7) -> Voice {
|
||||||
Voice {
|
Voice {
|
||||||
|
|
|
||||||
|
|
@ -295,7 +295,7 @@ impl Sample {
|
||||||
_ => panic!("unexpected in sample {name}"),
|
_ => panic!("unexpected in sample {name}"),
|
||||||
});
|
});
|
||||||
let (end, data) = read_sample_data(&format!("{dir}/{file}"))?;
|
let (end, data) = read_sample_data(&format!("{dir}/{file}"))?;
|
||||||
Ok((midi, Self::new(&name, start, end, data)))
|
Ok((midi, Arc::new(RwLock::new(Self::new(&name, start, end, data)))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue