use alloc::boxed::Box;
use alloc::collections::VecDeque;
use alloc::vec::Vec;
use crate::consumer::Consume;
use crate::plugin::Plugin;
use crate::synth::{envelope, midi_to_hz, square, triangle};
use crate::{BassNote, MelodyNote, Note};
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct StemSample {
pub value: f32,
pub byte_index: u64,
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct StemsSample {
pub voice: StemSample,
pub square: StemSample,
pub triangle: StemSample,
pub noise: f32,
pub sfx: StemSample,
}
pub trait SampleStem {
fn sample_square(&self, sample_rate: u32) -> Vec<StemSample>;
fn sample_triangle(&self, sample_rate: u32) -> Vec<StemSample>;
}
pub trait DescribeNote {
fn midi(&self) -> f64;
fn duration(&self) -> f64;
fn byte_index(&self) -> u64;
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct SquareNote {
pub midi: f64,
pub duration: f64,
pub amp: f32,
pub duty: f64,
pub byte_index: u64,
}
impl DescribeNote for SquareNote {
fn midi(&self) -> f64 {
self.midi
}
fn duration(&self) -> f64 {
self.duration
}
fn byte_index(&self) -> u64 {
self.byte_index
}
}
impl SampleStem for SquareNote {
fn sample_square(&self, sample_rate: u32) -> Vec<StemSample> {
let sample_rate = sample_rate as f64;
let total_samples = (sample_rate * self.duration).floor() as usize;
if total_samples == 0 {
return Vec::new();
}
let dur_sec = total_samples as f64 / sample_rate;
let chunk = square(
sample_rate,
midi_to_hz(self.midi),
dur_sec,
self.amp,
self.duty,
);
let chunk = envelope(sample_rate, &chunk, 0.005, 0.05, 0.7, 0.05);
let mut samples = Vec::new();
for (i, &s) in chunk.iter().enumerate() {
if i >= total_samples {
break;
}
samples.push(StemSample {
value: s,
byte_index: self.byte_index,
});
}
samples
}
fn sample_triangle(&self, _sample_rate: u32) -> Vec<StemSample> {
Default::default()
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct TriangleNote {
pub midi: f64,
pub duration: f64,
pub byte_index: u64,
}
impl DescribeNote for TriangleNote {
fn midi(&self) -> f64 {
self.midi
}
fn duration(&self) -> f64 {
self.duration
}
fn byte_index(&self) -> u64 {
self.byte_index
}
}
impl SampleStem for TriangleNote {
fn sample_square(&self, _sample_rate: u32) -> Vec<StemSample> {
Default::default()
}
fn sample_triangle(&self, sample_rate: u32) -> Vec<StemSample> {
let sample_rate = sample_rate as f64;
let total_beats = (sample_rate as f64 * self.duration).floor() as usize;
if total_beats == 0 {
return Vec::new();
}
let dur_sec = total_beats as f64 / sample_rate;
let chunk = triangle(sample_rate, midi_to_hz(self.midi), dur_sec, 0.25);
let chunk = envelope(sample_rate, &chunk, 0.005, 0.05, 0.7, 0.05);
let mut samples = Vec::new();
for (i, &s) in chunk.iter().enumerate() {
if i >= total_beats {
break;
}
samples.push(StemSample {
value: s,
byte_index: self.byte_index,
});
}
samples
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Sampler {
melody_notes: VecDeque<MelodyNote>,
bass_notes: VecDeque<BassNote>,
voice_samples: VecDeque<StemSample>,
sfx_samples: VecDeque<StemSample>,
square_samples: VecDeque<StemSample>,
triangle_samples: VecDeque<StemSample>,
}
impl Consume for Sampler {
type Item = Note;
fn push(&mut self, note: Note) {
match note {
Note::Melody(n) => self.melody_notes.push_back(n),
Note::Bass(n) => self.bass_notes.push_back(n),
}
}
fn extend(&mut self, notes: &[Note]) {
for note in notes {
self.push(*note);
}
}
fn capacity(&self) -> usize {
self.melody_notes.capacity().min(self.bass_notes.capacity())
}
fn len(&self) -> usize {
self.melody_notes.len().min(self.bass_notes.len())
}
fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl Sampler {
pub fn sample(&mut self, plugin: &Box<dyn Plugin>, sample_rate: u32) -> Option<StemsSample> {
loop {
if self.square_samples.len() > 0 && self.triangle_samples.len() > 0 {
let Some(square) = self.square_samples.pop_front() else {
return None;
};
let Some(triangle) = self.triangle_samples.pop_front() else {
return None;
};
let voice = self.voice_samples.pop_front().unwrap_or_default();
let sfx = self.sfx_samples.pop_front().unwrap_or_default();
return Some(StemsSample {
voice,
square,
triangle,
noise: 0.0,
sfx,
});
}
while self.triangle_samples.len() > self.square_samples.len() {
let Some(note) = self.melody_notes.pop_front() else {
return None;
};
self.square_samples
.extend(plugin.sample_melody_note(note, sample_rate));
self.voice_samples
.extend(plugin.sample_voice_note(note, sample_rate));
self.sfx_samples
.extend(plugin.sample_sfx_note(note, sample_rate));
}
if let Some(note) = self.bass_notes.pop_front() {
self.triangle_samples
.extend(plugin.sample_bass_note(note, sample_rate));
}
if self.triangle_samples.is_empty() {
return None;
}
}
}
pub fn samples(&mut self, plugin: &Box<dyn Plugin>, sample_rate: u32) -> Vec<StemsSample> {
let mut samples = Vec::new();
while let Some(sample) = self.sample(plugin, sample_rate) {
samples.push(sample);
}
samples
}
}