mod effects;
mod envelope;
mod oscillator;
use effects::{distortion::Distortion, Effect};
use envelope::{Envelope, State};
use oscillator::Oscillator;
pub use oscillator::{DutyCycle, OscillatorType};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{cell::RefCell, collections::HashMap};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone)]
pub struct Sample {
volume: Option<f32>,
osc_frequency: usize,
osc_type: OscillatorType,
osc_duty_cycle: DutyCycle,
env_attack: f32,
env_decay: f32,
env_release: f32,
env_sustain: f32,
dis_crunch: Option<f32>,
dis_drive: Option<f32>,
}
impl Default for Sample {
fn default() -> Self {
Self {
volume: None,
osc_frequency: 441,
osc_type: OscillatorType::Sine,
osc_duty_cycle: DutyCycle::default(),
env_attack: 0.01,
env_decay: 0.1,
env_sustain: 0.5,
env_release: 0.5,
dis_crunch: None,
dis_drive: None,
}
}
}
impl Sample {
pub fn volume(&mut self, volume: f32) -> &mut Self {
self.volume = Some(volume);
self
}
pub fn osc_frequency(&mut self, frequency: usize) -> &mut Self {
self.osc_frequency = frequency;
self
}
pub fn osc_type(&mut self, oscillator: OscillatorType) -> &mut Self {
self.osc_type = oscillator;
self
}
pub fn osc_duty_cycle(&mut self, duty_cycle: DutyCycle) -> &mut Self {
self.osc_duty_cycle = duty_cycle;
self
}
pub fn env_attack(&mut self, attack: f32) -> &mut Self {
self.env_attack = attack;
self
}
pub fn env_decay(&mut self, decay: f32) -> &mut Self {
self.env_decay = decay;
self
}
pub fn env_sustain(&mut self, sustain: f32) -> &mut Self {
self.env_sustain = sustain;
self
}
pub fn env_release(&mut self, release: f32) -> &mut Self {
self.env_release = release;
self
}
pub fn dis_crunch(&mut self, crunch: f32) -> &mut Self {
self.dis_crunch = Some(crunch);
self
}
pub fn dis_drive(&mut self, drive: f32) -> &mut Self {
self.dis_drive = Some(drive);
self
}
}
#[derive(Debug)]
struct Generator {
pub(crate) finished: bool,
offset: usize,
volume: Option<f32>,
oscillator: Oscillator,
envelope: Envelope,
distortion: Option<Distortion>,
}
impl Generator {
fn run(&mut self, output: &mut [f32]) {
self.oscillator.generate(output, self.offset);
if self.envelope.apply(output, self.offset) == State::Done {
self.finished = true;
}
if let Some(distortion) = &mut self.distortion {
distortion.apply(output, self.offset);
}
if let Some(volume) = self.volume {
output.iter_mut().for_each(|tone| *tone *= volume);
}
self.offset += output.len();
}
}
#[derive(Debug)]
pub struct Mixer {
generators: Vec<Generator>,
sample_rate: usize,
oscillator_lookup: HashMap<(usize, DutyCycle, OscillatorType), RefCell<Vec<f32>>>,
}
impl Mixer {
pub fn new(sample_rate: usize) -> Self {
Self {
sample_rate,
..Self::default()
}
}
pub fn play(&mut self, sample: Sample) {
let envelope = Envelope::new(
self.sample_rate as f32,
sample.env_attack,
sample.env_decay,
sample.env_sustain,
sample.env_release,
);
let buffer =
self.oscillator_buffer(sample.osc_frequency, sample.osc_duty_cycle, sample.osc_type);
let oscillator = Oscillator::new(buffer, self.sample_rate);
let distortion = match (sample.dis_crunch, sample.dis_drive) {
(Some(crunch), Some(drive)) => Some(Distortion::new(crunch, drive)),
(Some(crunch), None) => Some(Distortion::new(crunch, 1.0)),
(None, Some(drive)) => Some(Distortion::new(0.0, drive)),
(None, None) => None,
};
let generator = Generator {
finished: false,
offset: 0,
volume: sample.volume,
oscillator,
envelope,
distortion,
};
self.generators.push(generator);
}
pub fn generate(&mut self, output: &mut [f32]) {
output.iter_mut().for_each(|tone| *tone = 0.0);
let generators_len = self.generators.len();
if generators_len == 0 {
return;
}
self.generators
.iter_mut()
.for_each(|generator| generator.run(output));
self.generators.retain(|generator| !generator.finished);
let buffer_len_inv = 1.0 / generators_len as f32;
output.iter_mut().for_each(|tone| *tone *= buffer_len_inv);
}
fn oscillator_buffer(
&mut self,
frequency: usize,
duty_cycle: DutyCycle,
oscillator_type: OscillatorType,
) -> RefCell<Vec<f32>> {
match self
.oscillator_lookup
.get(&(frequency, duty_cycle, oscillator_type))
{
Some(buffer) => RefCell::clone(buffer),
None => {
let lut = RefCell::new(oscillator_type.build_lut(
frequency,
duty_cycle,
self.sample_rate,
));
let cloned_ref = RefCell::clone(&lut);
self.oscillator_lookup
.insert((frequency, duty_cycle, oscillator_type), lut);
cloned_ref
}
}
}
}
impl Default for Mixer {
fn default() -> Self {
Self {
sample_rate: 44100,
generators: vec![],
oscillator_lookup: HashMap::new(),
}
}
}