use crate::synthesis::envelope::Envelope;
use crate::synthesis::filter::Filter;
use crate::synthesis::filter_envelope::FilterEnvelope;
use crate::synthesis::fm_synthesis::FMParams;
use crate::synthesis::waveform::Waveform;
use crate::track::NoteEvent; use ahash::AHasher;
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CacheKey(u64);
impl CacheKey {
pub fn new(value: u64) -> Self {
Self(value)
}
pub fn from_note_event(note: &NoteEvent, sample_rate: f32) -> Self {
let mut hasher = AHasher::default();
for i in 0..note.num_freqs {
hash_f32(note.frequencies[i], &mut hasher);
}
note.num_freqs.hash(&mut hasher);
hash_waveform(¬e.waveform, &mut hasher);
hash_envelope(¬e.envelope, &mut hasher);
hash_fm_params(¬e.fm_params, &mut hasher);
hash_filter_envelope(¬e.filter_envelope, &mut hasher);
hash_f32(note.duration, &mut hasher);
hash_f32(note.pitch_bend_semitones, &mut hasher);
hash_f32(sample_rate, &mut hasher);
hash_f32(note.velocity, &mut hasher);
if let Some(ref wavetable) = note.custom_wavetable {
let ptr = wavetable as *const _ as usize;
ptr.hash(&mut hasher);
}
CacheKey(hasher.finish())
}
pub fn from_note_with_filter(note: &NoteEvent, filter: &Filter, sample_rate: f32) -> Self {
let mut hasher = AHasher::default();
let base_key = Self::from_note_event(note, sample_rate);
base_key.0.hash(&mut hasher);
hash_filter(filter, &mut hasher);
CacheKey(hasher.finish())
}
pub fn as_u64(&self) -> u64 {
self.0
}
}
fn hash_f32(value: f32, hasher: &mut AHasher) {
value.to_bits().hash(hasher);
}
fn hash_waveform(waveform: &Waveform, hasher: &mut AHasher) {
std::mem::discriminant(waveform).hash(hasher);
}
fn hash_envelope(envelope: &Envelope, hasher: &mut AHasher) {
hash_f32(envelope.attack, hasher);
hash_f32(envelope.decay, hasher);
hash_f32(envelope.sustain, hasher);
hash_f32(envelope.release, hasher);
std::mem::discriminant(&envelope.curve).hash(hasher);
}
fn hash_fm_params(fm: &FMParams, hasher: &mut AHasher) {
hash_f32(fm.mod_ratio, hasher);
hash_f32(fm.mod_index, hasher);
hash_f32(fm.index_envelope_attack, hasher);
hash_f32(fm.index_envelope_decay, hasher);
hash_f32(fm.index_envelope_sustain, hasher);
hash_f32(fm.index_envelope_release, hasher);
hash_f32(fm.index_env_amount, hasher);
}
fn hash_filter_envelope(filter_env: &FilterEnvelope, hasher: &mut AHasher) {
hash_f32(filter_env.attack, hasher);
hash_f32(filter_env.decay, hasher);
hash_f32(filter_env.sustain, hasher);
hash_f32(filter_env.release, hasher);
hash_f32(filter_env.base_cutoff, hasher);
hash_f32(filter_env.peak_cutoff, hasher);
hash_f32(filter_env.amount, hasher);
}
fn hash_filter(filter: &Filter, hasher: &mut AHasher) {
std::mem::discriminant(&filter.filter_type).hash(hasher);
hash_f32(filter.cutoff, hasher);
hash_f32(filter.resonance, hasher);
std::mem::discriminant(&filter.slope).hash(hasher);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::synthesis::envelope::EnvelopeCurve;
#[test]
fn test_same_parameters_same_key() {
let note1 = NoteEvent {
frequencies: [440.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
num_freqs: 1,
start_time: 0.0,
duration: 1.0,
waveform: Waveform::Sine,
envelope: Envelope::with_curve(0.01, 0.1, 0.7, 0.2, EnvelopeCurve::Linear),
filter_envelope: FilterEnvelope::default(),
fm_params: FMParams::default(),
pitch_bend_semitones: 0.0,
custom_wavetable: None,
velocity: 1.0,
spatial_position: None,
};
let note2 = note1.clone();
let key1 = CacheKey::from_note_event(¬e1, 44100.0);
let key2 = CacheKey::from_note_event(¬e2, 44100.0);
assert_eq!(key1, key2);
}
#[test]
fn test_different_envelope_different_key() {
let note1 = NoteEvent {
frequencies: [440.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
num_freqs: 1,
start_time: 0.0,
duration: 1.0,
waveform: Waveform::Sine,
envelope: Envelope::with_curve(0.01, 0.1, 0.7, 0.2, EnvelopeCurve::Linear),
filter_envelope: FilterEnvelope::default(),
fm_params: FMParams::default(),
pitch_bend_semitones: 0.0,
custom_wavetable: None,
velocity: 1.0,
spatial_position: None,
};
let mut note2 = note1.clone();
note2.envelope = Envelope::with_curve(0.05, 0.1, 0.7, 0.2, EnvelopeCurve::Linear);
let key1 = CacheKey::from_note_event(¬e1, 44100.0);
let key2 = CacheKey::from_note_event(¬e2, 44100.0);
assert_ne!(key1, key2);
}
#[test]
fn test_different_frequency_different_key() {
let note1 = NoteEvent {
frequencies: [440.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
num_freqs: 1,
start_time: 0.0,
duration: 1.0,
waveform: Waveform::Sine,
envelope: Envelope::default(),
filter_envelope: FilterEnvelope::default(),
fm_params: FMParams::default(),
pitch_bend_semitones: 0.0,
custom_wavetable: None,
velocity: 1.0,
spatial_position: None,
};
let mut note2 = note1.clone();
note2.frequencies[0] = 880.0;
let key1 = CacheKey::from_note_event(¬e1, 44100.0);
let key2 = CacheKey::from_note_event(¬e2, 44100.0);
assert_ne!(key1, key2);
}
}