use super::oscillator_processor::OscillatorProcessor;
use crate::{
commands::Id,
graph::DspNode,
parameter::{ParameterRange, Parameters},
prelude::*,
utility::create_parameters,
};
use itertools::izip;
pub struct Oscillator {
pub node: GraphNode,
params: Parameters,
}
const MIN_GAIN: f64 = f64::NEG_INFINITY;
const MAX_GAIN: f64 = f64::INFINITY;
const MIN_FREQUENCY: f64 = 20.0;
const MAX_FREQUENCY: f64 = 20000.0;
const DEFAULT_GAIN: f64 = 1.0;
fn make_sine_wavetable(length: usize, harmonic: usize) -> Vec<f64> {
let mut values = Vec::with_capacity(length);
for frame in 0..length {
let time = harmonic as f64 * frame as f64 / length as f64;
let value = (std::f64::consts::TAU * time).sin();
values.push(value);
}
values
}
impl DspNode for Oscillator {
fn get_parameters_mut(&mut self) -> &mut Parameters {
&mut self.params
}
}
impl Oscillator {
pub fn sine(context: &dyn Context, frequency: f64, output_count: usize) -> Self {
let table_size = 8192;
let sine_wavetable = make_sine_wavetable(table_size, 1);
Self::new(context, frequency, output_count, sine_wavetable)
}
pub fn with_harmonics(
context: &dyn Context,
frequency: f64,
output_count: usize,
harmonics: &[Level],
) -> Self {
let table_size = 8192;
let mut wavetable = Vec::new();
wavetable.resize(table_size, 0.0);
for (index, level) in harmonics.iter().enumerate() {
let harmonic = index + 1;
let harmonic_wavetable = make_sine_wavetable(table_size, harmonic);
for (harmonic_sample, wavetable_sample) in
izip!(harmonic_wavetable.iter(), wavetable.iter_mut())
{
*wavetable_sample += *harmonic_sample * level.as_linear();
}
}
Self::new(context, frequency, output_count, wavetable)
}
pub fn new(
context: &dyn Context,
frequency: f64,
output_count: usize,
wavetable: Vec<f64>,
) -> Self {
debug_assert!(output_count > 0);
debug_assert!(wavetable.len() > 2);
let id = Id::generate();
let (params, realtime_params) = create_parameters(
id,
context,
[
(
"frequency",
ParameterRange::new(frequency, MIN_FREQUENCY, MAX_FREQUENCY),
),
(
"gain",
ParameterRange::new(DEFAULT_GAIN, MIN_GAIN, MAX_GAIN),
),
],
);
let input_count = 0;
let processor = Box::new(OscillatorProcessor::new(wavetable));
Self {
node: GraphNode::new(
id,
context,
input_count,
output_count,
processor,
realtime_params,
),
params,
}
}
pub fn frequency(&mut self) -> &mut AudioParameter {
self.get_parameter_mut("frequency")
}
pub fn gain(&mut self) -> &mut AudioParameter {
self.get_parameter_mut("gain")
}
}