use crate::instruments::drums::DrumType;
use crate::synthesis::envelope::Envelope;
use crate::synthesis::filter_envelope::FilterEnvelope;
use crate::synthesis::fm_synthesis::FMParams;
use crate::synthesis::sample::Sample;
use crate::synthesis::spatial::SpatialPosition;
use crate::synthesis::waveform::Waveform;
use crate::theory::key_signature::KeySignature;
#[derive(Debug, Clone)]
pub enum AudioEvent {
Note(NoteEvent),
Drum(DrumEvent),
Sample(SampleEvent),
TempoChange(TempoChangeEvent),
TimeSignature(TimeSignatureEvent),
KeySignature(KeySignatureEvent),
}
impl AudioEvent {
#[inline]
pub fn start_time(&self) -> f32 {
match self {
AudioEvent::Note(note) => note.start_time,
AudioEvent::Drum(drum) => drum.start_time,
AudioEvent::Sample(sample) => sample.start_time,
AudioEvent::TempoChange(tempo) => tempo.start_time,
AudioEvent::TimeSignature(time_sig) => time_sig.start_time,
AudioEvent::KeySignature(key_sig) => key_sig.start_time,
}
}
#[inline]
pub fn end_time(&self) -> f32 {
match self {
AudioEvent::Note(note) => {
let total_duration = note.envelope.total_duration(note.duration);
note.start_time + total_duration
}
AudioEvent::Drum(drum) => {
let pitch_ratio = 2.0_f32.powf(drum.pitch_offset / 12.0);
drum.start_time + drum.drum_type.duration() / pitch_ratio
}
AudioEvent::Sample(sample) => {
sample.start_time + (sample.sample.duration / sample.playback_rate)
}
AudioEvent::TempoChange(tempo) => tempo.start_time,
AudioEvent::TimeSignature(time_sig) => time_sig.start_time,
AudioEvent::KeySignature(key_sig) => key_sig.start_time,
}
}
}
#[derive(Debug, Clone)]
pub struct NoteEvent {
pub frequencies: [f32; 8], pub num_freqs: usize,
pub start_time: f32, pub duration: f32, pub waveform: Waveform, pub envelope: Envelope, pub filter_envelope: FilterEnvelope, pub fm_params: FMParams, pub pitch_bend_semitones: f32, pub custom_wavetable: Option<crate::synthesis::wavetable::Wavetable>, pub velocity: f32, pub spatial_position: Option<SpatialPosition>, }
#[derive(Debug, Clone, Copy)]
pub struct DrumEvent {
pub drum_type: DrumType,
pub start_time: f32,
pub pitch_offset: f32, pub velocity: f32, pub spatial_position: Option<SpatialPosition>, }
#[derive(Debug, Clone)]
pub struct SampleEvent {
pub sample: Sample,
pub start_time: f32,
pub playback_rate: f32, pub volume: f32, pub spatial_position: Option<SpatialPosition>, }
#[derive(Debug, Clone, Copy)]
pub struct TempoChangeEvent {
pub start_time: f32,
pub bpm: f32,
}
#[derive(Debug, Clone, Copy)]
pub struct TimeSignatureEvent {
pub start_time: f32,
pub numerator: u8, pub denominator: u8, }
#[derive(Debug, Clone, Copy)]
pub struct KeySignatureEvent {
pub start_time: f32,
pub key_signature: KeySignature,
}
impl SampleEvent {
pub fn new(sample: Sample, start_time: f32) -> Self {
Self {
sample,
start_time,
playback_rate: 1.0,
volume: 1.0,
spatial_position: None,
}
}
pub fn with_playback_rate(mut self, rate: f32) -> Self {
self.playback_rate = rate;
self
}
pub fn with_volume(mut self, volume: f32) -> Self {
self.volume = volume.clamp(0.0, 1.0);
self
}
}
impl NoteEvent {
pub fn new(frequencies: &[f32], start_time: f32, duration: f32) -> Self {
Self::with_waveform(frequencies, start_time, duration, Waveform::Sine)
}
pub fn with_waveform(
frequencies: &[f32],
start_time: f32,
duration: f32,
waveform: Waveform,
) -> Self {
Self::with_waveform_and_envelope(
frequencies,
start_time,
duration,
waveform,
Envelope::default(),
)
}
pub fn with_waveform_and_envelope(
frequencies: &[f32],
start_time: f32,
duration: f32,
waveform: Waveform,
envelope: Envelope,
) -> Self {
Self::with_waveform_envelope_and_bend(
frequencies,
start_time,
duration,
waveform,
envelope,
0.0,
)
}
pub fn with_waveform_envelope_and_bend(
frequencies: &[f32],
start_time: f32,
duration: f32,
waveform: Waveform,
envelope: Envelope,
pitch_bend_semitones: f32,
) -> Self {
Self::with_full_params(
frequencies,
start_time,
duration,
waveform,
envelope,
FilterEnvelope::default(),
pitch_bend_semitones,
)
}
pub fn with_full_params(
frequencies: &[f32],
start_time: f32,
duration: f32,
waveform: Waveform,
envelope: Envelope,
filter_envelope: FilterEnvelope,
pitch_bend_semitones: f32,
) -> Self {
Self::with_complete_params(
frequencies,
start_time,
duration,
waveform,
envelope,
filter_envelope,
FMParams::default(),
pitch_bend_semitones,
None,
0.8, )
}
#[allow(clippy::too_many_arguments)]
pub fn with_complete_params(
frequencies: &[f32],
start_time: f32,
duration: f32,
waveform: Waveform,
envelope: Envelope,
filter_envelope: FilterEnvelope,
fm_params: FMParams,
pitch_bend_semitones: f32,
custom_wavetable: Option<crate::synthesis::wavetable::Wavetable>,
velocity: f32,
) -> Self {
let mut freq_array = [0.0; 8];
let num_freqs = frequencies.len().min(8);
if num_freqs > 0 {
freq_array[..num_freqs].copy_from_slice(&frequencies[..num_freqs]);
}
Self {
frequencies: freq_array,
num_freqs,
start_time,
duration,
waveform,
envelope,
filter_envelope,
fm_params,
pitch_bend_semitones,
custom_wavetable,
velocity,
spatial_position: None,
}
}
}