mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 04:36:45 +01:00
use iterator in sampler
This commit is contained in:
parent
81717f17b8
commit
c5369328f4
9 changed files with 175 additions and 120 deletions
|
|
@ -55,22 +55,23 @@ impl Phrase {
|
|||
timebase: &Arc<Timebase>,
|
||||
(frame0, frames, _): (usize, usize, f64),
|
||||
) {
|
||||
let mut buf = Vec::with_capacity(8);
|
||||
for (time, tick) in Ticks(timebase.pulse_per_frame()).between_frames(
|
||||
frame0, frame0 + frames
|
||||
) {
|
||||
let tick = tick % self.length;
|
||||
if let Some(events) = self.notes.get(&(tick as usize)) {
|
||||
for message in events.iter() {
|
||||
let mut buf = vec![];
|
||||
buf.clear();
|
||||
let channel = 0.into();
|
||||
let message = *message;
|
||||
LiveEvent::Midi { channel, message }.write(&mut buf).unwrap();
|
||||
output[time as usize].push(buf.clone());
|
||||
match message {
|
||||
MidiMessage::NoteOn { key, .. } => notes_on[key.as_int() as usize] = true,
|
||||
MidiMessage::NoteOff { key, .. } => notes_on[key.as_int() as usize] = false,
|
||||
_ => {}
|
||||
}
|
||||
LiveEvent::Midi { channel, message }.write(&mut buf).unwrap();
|
||||
output[time as usize].push(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ pub struct Sampler {
|
|||
pub samples: BTreeMap<u7, Arc<Sample>>,
|
||||
pub voices: Vec<Voice>,
|
||||
pub ports: JackPorts,
|
||||
pub buffer: Vec<Vec<f32>>,
|
||||
pub output_gain: f32
|
||||
}
|
||||
|
||||
render!(Sampler = crate::view::sampler::render);
|
||||
|
|
@ -48,15 +50,21 @@ impl Sampler {
|
|||
cursor: (0, 0),
|
||||
samples: samples.unwrap_or(BTreeMap::new()),
|
||||
voices: vec![],
|
||||
ports
|
||||
ports,
|
||||
buffer: vec![vec![0.0;16384];2],
|
||||
output_gain: 0.5,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
|
||||
// Output buffer: this will be copied to the audio outs.
|
||||
let channel_count = self.ports.audio_outs.len();
|
||||
let mut mixed = vec![vec![0.0;scope.n_frames() as usize];channel_count];
|
||||
// Process MIDI input to add new voices.
|
||||
self.process_midi_in(scope);
|
||||
self.clear_output_buffer();
|
||||
self.process_audio_out(scope);
|
||||
self.write_output_buffer(scope);
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
fn process_midi_in (&mut self, scope: &ProcessScope) {
|
||||
for RawMidi { time, bytes } in self.ports.midi_ins.get("midi").unwrap().iter(scope) {
|
||||
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
||||
if let MidiMessage::NoteOn { ref key, .. } = message {
|
||||
|
|
@ -66,33 +74,39 @@ impl Sampler {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Emit next chunk of each currently playing voice,
|
||||
// dropping voices that have reached their ends.
|
||||
let gain = 0.5;
|
||||
}
|
||||
|
||||
fn clear_output_buffer (&mut self) {
|
||||
for buffer in self.buffer.iter_mut() {
|
||||
buffer.fill(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_audio_out (&mut self, scope: &ProcessScope) {
|
||||
let channel_count = self.buffer.len();
|
||||
self.voices.retain_mut(|voice|{
|
||||
if let Some(chunk) = voice.chunk(scope.n_frames() as usize) {
|
||||
for (i, channel) in chunk.iter().enumerate() {
|
||||
let buffer = &mut mixed[i % channel_count];
|
||||
for (i, sample) in channel.iter().enumerate() {
|
||||
buffer[i] += sample * gain;
|
||||
for index in 0..scope.n_frames() as usize {
|
||||
if let Some(frame) = voice.next() {
|
||||
for (channel, sample) in frame.iter().enumerate() {
|
||||
self.buffer[channel % channel_count][index] += sample * self.output_gain;
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
return true
|
||||
});
|
||||
// Write output buffer to output ports.
|
||||
}
|
||||
|
||||
/// Write output buffer to output ports.
|
||||
fn write_output_buffer (&mut self, scope: &ProcessScope) {
|
||||
for (i, port) in self.ports.audio_outs.values_mut().enumerate() {
|
||||
let buffer = &mixed[i];
|
||||
let buffer = &self.buffer[i];
|
||||
for (i, value) in port.as_mut_slice(scope).iter_mut().enumerate() {
|
||||
*value = *buffer.get(i).unwrap_or(&0.0);
|
||||
}
|
||||
}
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
fn load_sample (&mut self, _path: &str) {}
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! sample {
|
||||
|
|
@ -126,7 +140,11 @@ impl Sample {
|
|||
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 }
|
||||
Voice {
|
||||
sample: self.clone(),
|
||||
after,
|
||||
position: self.start
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,32 +154,23 @@ pub struct Voice {
|
|||
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;
|
||||
const BUFFER: [f32;64] = [0.0f32;64];
|
||||
|
||||
impl Iterator for Voice {
|
||||
type Item = [f32;2];
|
||||
fn next (&mut self) -> Option<Self::Item> {
|
||||
if self.after > 0 {
|
||||
self.after = self.after - 1;
|
||||
return Some([0.0, 0.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
|
||||
let position = self.position;
|
||||
self.position = self.position + 1;
|
||||
return Some([
|
||||
self.sample.channels[0][position],
|
||||
self.sample.channels[0][position],
|
||||
])
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ impl Track {
|
|||
Ok(Self {
|
||||
name: name.to_string(),
|
||||
midi_out: jack.register_port(name, MidiOut)?,
|
||||
midi_out_buf: vec![vec![];1024],
|
||||
midi_out_buf: vec![vec![];16384],
|
||||
notes_on: vec![false;128],
|
||||
monitoring: false,
|
||||
recording: false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue