use aether_core::{node::DspNode, param::ParamBlock, BUFFER_SIZE, MAX_INPUTS};
use crate::{analysis::TimbreProfile, transfer::TimbreTransfer};
use std::sync::{Arc, Mutex};
pub struct TimbreTransferNode {
transfer: TimbreTransfer,
profile: Arc<Mutex<Option<TimbreProfile>>>,
current_note: u8,
profile_loaded: bool,
}
impl TimbreTransferNode {
pub fn new() -> Self {
Self {
transfer: TimbreTransfer::new(2048),
profile: Arc::new(Mutex::new(None)),
current_note: 60,
profile_loaded: false,
}
}
pub fn profile_slot(&self) -> Arc<Mutex<Option<TimbreProfile>>> {
Arc::clone(&self.profile)
}
pub fn set_note(&mut self, note: u8) {
if note != self.current_note {
self.current_note = note;
self.profile_loaded = false; }
}
fn maybe_reload_profile(&mut self) {
if self.profile_loaded {
return;
}
if let Ok(guard) = self.profile.try_lock() {
if let Some(profile) = guard.as_ref() {
if let Some(envelope) = profile.envelope_for_note(self.current_note) {
self.transfer.set_target(envelope.clone());
self.profile_loaded = true;
}
}
}
}
}
impl Default for TimbreTransferNode {
fn default() -> Self {
Self::new()
}
}
impl DspNode for TimbreTransferNode {
fn process(
&mut self,
inputs: &[Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS],
output: &mut [f32; BUFFER_SIZE],
params: &mut ParamBlock,
_sample_rate: f32,
) {
let amount = if params.count > 0 {
params.params[0].current.clamp(0.0, 1.0)
} else {
1.0
};
self.transfer.amount = amount;
self.maybe_reload_profile();
let input = match inputs[0] {
Some(buf) => buf,
None => {
output.fill(0.0);
return;
}
};
if amount < 0.001 {
output.copy_from_slice(input);
return;
}
let processed = self.transfer.process_block(input);
for (i, s) in processed.iter().enumerate().take(BUFFER_SIZE) {
output[i] = *s;
}
}
fn type_name(&self) -> &'static str {
"TimbreTransferNode"
}
}