use std::time::Duration;
use enum_dispatch::enum_dispatch;
use audio_processor_file::AudioFileProcessor;
use audio_processor_traits::AudioContext;
use augmented_adsr_envelope::Envelope;
use augmented_oscillator::Oscillator;
#[enum_dispatch(MetronomeSoundType)]
pub trait MetronomeSound {
fn prepare(&mut self, context: &mut AudioContext);
fn set_accent_beat(&mut self, is_accent: bool);
fn trigger(&mut self);
fn process(&mut self) -> f32;
}
#[enum_dispatch]
pub enum MetronomeSoundType {
Sine(MetronomeSoundSine),
File(MetronomeSoundFile),
}
impl MetronomeSoundType {
pub fn file(file: AudioFileProcessor) -> Self {
Self::File(MetronomeSoundFile {
file_processor: file,
envelope: crate::build_envelope(),
})
}
}
pub struct MetronomeSoundSine {
oscillator: Oscillator<f32>,
envelope: Envelope,
}
impl MetronomeSoundSine {
pub fn new(sample_rate: f32, envelope: Envelope) -> Self {
Self {
oscillator: Oscillator::sine(sample_rate),
envelope,
}
}
}
impl MetronomeSound for MetronomeSoundSine {
fn prepare(&mut self, context: &mut AudioContext) {
self.envelope
.set_sample_rate(context.settings.sample_rate());
self.oscillator
.set_sample_rate(context.settings.sample_rate())
}
fn set_accent_beat(&mut self, is_accent: bool) {
if is_accent {
self.oscillator.set_frequency(880.0);
} else {
self.oscillator.set_frequency(440.0);
}
}
fn trigger(&mut self) {
self.envelope.note_on();
}
fn process(&mut self) -> f32 {
let out = self.envelope.volume() * self.oscillator.get();
self.envelope.tick();
self.oscillator.tick();
out
}
}
pub struct MetronomeSoundFile {
file_processor: AudioFileProcessor,
envelope: Envelope,
}
impl MetronomeSound for MetronomeSoundFile {
fn prepare(&mut self, context: &mut AudioContext) {
audio_processor_traits::AudioProcessor::prepare(&mut self.file_processor, context);
self.envelope
.set_sample_rate(context.settings.sample_rate());
self.envelope.set_decay(Duration::from_millis(50));
self.file_processor.handle().stop();
self.file_processor.handle().set_should_loop(false);
}
fn set_accent_beat(&mut self, _is_accent: bool) {}
fn trigger(&mut self) {
self.envelope.note_on();
self.file_processor.handle().stop();
self.file_processor.handle().play();
}
fn process(&mut self) -> f32 {
let out = self.envelope.volume() * self.file_processor.process_single().sum::<f32>() / 2.0;
self.envelope.tick();
out
}
}