#[cfg(all(not(feature = "std"), not(feature = "libm"), feature = "micromath"))]
#[allow(unused_imports)]
use micromath::F32Ext;
#[cfg(all(not(feature = "std"), feature = "libm"))]
#[allow(unused_imports)]
use num_traits::float::Float;
use crate::state_instr_default::StateInstrDefault;
use xmrs::prelude::Pitch;
#[derive(Clone)]
pub(crate) struct Voice<'a> {
pub instr: StateInstrDefault<'a>,
pub vol_frozen: f32,
pub channel_volume_frozen: f32,
pub panning_frozen: f32,
pub note: Option<Pitch>,
pub sample_num: Option<usize>,
pub period_at_fork: f32,
#[allow(dead_code)]
pub master_track: Option<usize>,
}
impl<'a> Voice<'a> {
pub fn new_live(instr: StateInstrDefault<'a>, master_track: usize) -> Self {
Self {
instr,
vol_frozen: 1.0,
channel_volume_frozen: 1.0,
panning_frozen: 0.5,
note: None,
sample_num: None,
period_at_fork: 0.0,
master_track: Some(master_track),
}
}
pub fn new_ghost(
instr: StateInstrDefault<'a>,
master_track: usize,
vol_frozen: f32,
channel_volume_frozen: f32,
panning_frozen: f32,
note: Option<Pitch>,
sample_num: Option<usize>,
period_at_fork: f32,
) -> Self {
Self {
instr,
vol_frozen,
channel_volume_frozen,
panning_frozen,
note,
sample_num,
period_at_fork,
master_track: Some(master_track),
}
}
#[inline]
pub fn apply_nna_continue(&mut self) {}
#[inline]
pub fn apply_nna_note_off(&mut self) {
self.instr.key_off();
}
#[inline]
pub fn apply_nna_note_fade_out(&mut self) {
self.instr.key_off();
}
#[inline]
pub fn past_cut(&mut self) {
self.instr.cut_pitch();
}
#[inline]
pub fn past_off(&mut self) {
self.instr.key_off();
}
#[inline]
pub fn past_fade_out(&mut self) {
self.instr.key_off();
}
#[inline]
pub fn tick(&mut self) {
self.instr.tick();
self.instr
.update_frequency(self.period_at_fork, 0.0, 0.0, false);
}
#[inline]
pub fn is_alive(&self) -> bool {
if !self.instr.is_enabled() {
return false;
}
self.instr.get_volume() > 1e-6
}
pub fn next(&mut self) -> Option<(f32, f32)> {
if !self.instr.is_enabled() {
return None;
}
let v = self.vol_frozen * self.instr.get_volume() * self.channel_volume_frozen;
let v = v.clamp(0.0, 1.0);
let l_gain = v * (1.0 - self.panning_frozen);
let r_gain = v * self.panning_frozen;
match self.instr.next() {
Some((l, r)) => Some((l * l_gain, r * r_gain)),
None => None,
}
}
}