tek/crates/device/src/sampler/sampler_model.rs

157 lines
4.4 KiB
Rust

use crate::*;
pub type MaybeSample = Option<Arc<RwLock<Sample>>>;
/// The sampler device plays sounds in response to MIDI notes.
#[derive(Debug)]
pub struct Sampler {
pub name: String,
pub mapped: [MaybeSample;128],
pub recording: Option<(usize, Arc<RwLock<Sample>>)>,
pub unmapped: Vec<Arc<RwLock<Sample>>>,
pub voices: Arc<RwLock<Vec<Voice>>>,
pub midi_in: Option<JackMidiIn>,
pub audio_ins: Vec<JackAudioIn>,
pub input_meter: Vec<f32>,
pub audio_outs: Vec<JackAudioOut>,
pub buffer: Vec<Vec<f32>>,
pub output_gain: f32,
pub editing: MaybeSample,
pub mode: Option<SamplerMode>,
/// Size of actual notes area
pub size: Measure<TuiOut>,
/// Lowest note displayed
pub note_lo: AtomicUsize,
/// Selected note
pub note_pt: AtomicUsize,
/// Selected note as row/col
pub cursor: (AtomicUsize, AtomicUsize),
pub color: ItemTheme
}
impl Default for Sampler {
fn default () -> Self {
Self {
midi_in: None,
audio_ins: vec![],
input_meter: vec![0.0;2],
audio_outs: vec![],
name: "tek_sampler".to_string(),
mapped: [const { None };128],
unmapped: vec![],
voices: Arc::new(RwLock::new(vec![])),
buffer: vec![vec![0.0;16384];2],
output_gain: 1.,
recording: None,
mode: None,
editing: None,
size: Default::default(),
note_lo: 0.into(),
note_pt: 0.into(),
cursor: (0.into(), 0.into()),
color: Default::default(),
}
}
}
impl Sampler {
pub fn new (
jack: &Jack,
name: impl AsRef<str>,
midi_from: &[PortConnect],
audio_from: &[&[PortConnect];2],
audio_to: &[&[PortConnect];2],
) -> Usually<Self> {
let name = name.as_ref();
Ok(Self {
name: name.into(),
midi_in: Some(JackMidiIn::new(jack, format!("M/{name}"), midi_from)?),
audio_ins: vec![
JackAudioIn::new(jack, &format!("L/{name}"), audio_from[0])?,
JackAudioIn::new(jack, &format!("R/{name}"), audio_from[1])?,
],
audio_outs: vec![
JackAudioOut::new(jack, &format!("{name}/L"), audio_to[0])?,
JackAudioOut::new(jack, &format!("{name}/R"), audio_to[1])?,
],
..Default::default()
})
}
/// Value of cursor
pub fn cursor (&self) -> (usize, usize) {
(self.cursor.0.load(Relaxed), self.cursor.1.load(Relaxed))
}
}
impl NoteRange for Sampler {
fn note_lo (&self) -> &AtomicUsize {
&self.note_lo
}
fn note_axis (&self) -> &AtomicUsize {
&self.size.y
}
}
impl NotePoint for Sampler {
fn note_len (&self) -> &AtomicUsize {
unreachable!();
}
fn get_note_len (&self) -> usize {
0
}
fn set_note_len (&self, x: usize) -> usize {
0 /*TODO?*/
}
fn note_pos (&self) -> &AtomicUsize {
&self.note_pt
}
fn get_note_pos (&self) -> usize {
self.note_pt.load(Relaxed)
}
fn set_note_pos (&self, x: usize) -> usize {
let old = self.note_pt.swap(x, Relaxed);
self.cursor.0.store(x % 8, Relaxed);
self.cursor.1.store(x / 8, Relaxed);
old
}
}
/// A sound sample.
#[derive(Default, Debug)]
pub struct Sample {
pub name: Arc<str>,
pub start: usize,
pub end: usize,
pub channels: Vec<Vec<f32>>,
pub rate: Option<usize>,
pub gain: f32,
}
impl Sample {
pub fn new (name: impl AsRef<str>, start: usize, end: usize, channels: Vec<Vec<f32>>) -> Self {
Self { name: name.as_ref().into(), start, end, channels, rate: None, gain: 1.0 }
}
pub fn play (sample: &Arc<RwLock<Self>>, after: usize, velocity: &u7) -> Voice {
Voice {
sample: sample.clone(),
after,
position: sample.read().unwrap().start,
velocity: velocity.as_int() as f32 / 127.0,
}
}
}
/// A currently playing instance of a sample.
#[derive(Default, Debug, Clone)]
pub struct Voice {
pub sample: Arc<RwLock<Sample>>,
pub after: usize,
pub position: usize,
pub velocity: f32,
}
#[derive(Debug)]
pub enum SamplerMode {
// Load sample from path
Import(usize, FileBrowser),
}