use crate::envelope::Envelope;
use oscy::Oscillator;
use pitchy::Pitch;
pub struct Voice<O: Oscillator, E: Envelope> {
osc: O,
amp_env: E,
velocity: f32,
note: Option<u8>,
}
impl<O: Oscillator, E: Envelope> Voice<O, E> {
pub fn new(osc: O, amp_env: E) -> Self {
Self {
osc,
amp_env,
velocity: 0.0,
note: None,
}
}
pub fn note_on(&mut self, midi_note: u8, velocity: f32) {
let _ = self.try_note_on(midi_note, velocity);
}
pub fn try_note_on(&mut self, midi_note: u8, velocity: f32) -> Result<(), pitchy::PitchyError> {
let pitch = Pitch::try_from_midi_number(midi_note)?;
self.note = Some(midi_note);
self.velocity = velocity.clamp(0.0, 1.0);
self.osc.set_frequency(pitch.frequency() as f32);
self.amp_env.gate_on();
Ok(())
}
pub fn note_off(&mut self) {
self.amp_env.gate_off();
self.note = None;
}
pub fn next_sample(&mut self) -> f32 {
let osc_out = self.osc.next_sample();
let env_out = self.amp_env.next_sample();
osc_out * env_out * self.velocity
}
pub fn is_active(&self) -> bool {
self.amp_env.is_active()
}
pub fn reset(&mut self) {
self.amp_env.reset();
self.osc.reset();
self.velocity = 0.0;
self.note = None;
}
pub fn note(&self) -> Option<u8> {
self.note
}
pub fn velocity(&self) -> f32 {
self.velocity
}
pub fn osc(&self) -> &O {
&self.osc
}
pub fn osc_mut(&mut self) -> &mut O {
&mut self.osc
}
pub fn amp_env(&self) -> &E {
&self.amp_env
}
pub fn amp_env_mut(&mut self) -> &mut E {
&mut self.amp_env
}
}