mod sample;
use core::ops::{Deref, DerefMut};
use core::marker::PhantomData;
use crate::clock::{VFrameTs, VideoTs};
use crate::video::VideoFrame;
pub use sample::{
AudioSample,
FromSample,
IntoSample,
SampleDelta,
MulNorm
};
pub use crate::clock::FTs;
pub trait Blep {
type SampleDelta: SampleDelta;
fn ensure_frame_time(&mut self, sample_rate: u32, ts_rate: f64, frame_ts: FTs, margin_ts: FTs);
fn add_step(&mut self, channel: usize, timestamp: FTs, delta: Self::SampleDelta);
fn end_frame(&mut self, timestamp: FTs) -> usize;
}
pub struct BlepAmpFilter<B: Blep> {
pub filter: B::SampleDelta,
pub blep: B,
}
pub struct BlepStereo<B: Blep> {
pub mono_filter: B::SampleDelta,
pub blep: B,
}
pub trait AmpLevels<T: Copy> {
fn amp_level(level: u32) -> T;
}
pub trait AudioFrame<B: Blep> {
fn ensure_audio_frame_time(&self, blep: &mut B, sample_rate: u32, cpu_hz: f64);
fn get_audio_frame_end_time(&self) -> FTs;
#[inline]
fn end_audio_frame(&self, blep: &mut B) -> usize {
blep.end_frame(self.get_audio_frame_end_time())
}
}
pub trait EarMicOutAudioFrame<B: Blep> {
fn render_earmic_out_audio_frame<V: AmpLevels<B::SampleDelta>>(&self, blep: &mut B, channel: usize);
}
pub trait EarInAudioFrame<B: Blep> {
fn render_ear_in_audio_frame<V: AmpLevels<B::SampleDelta>>(&self, blep: &mut B, channel: usize);
}
pub const AMPS_EAR_MIC: [f32; 4] = [0.34/3.70, 0.66/3.70, 3.56/3.70, 1.0];
pub const AMPS_EAR_OUT: [f32; 4] = [0.34/3.70, 0.34/3.70, 1.0, 1.0];
pub const AMPS_EAR_IN: [f32; 2] = [0.34/3.70, 0.66/3.70];
pub const AMPS_EAR_MIC_I32: [i32; 4] = [0x0bc3_1d10, 0x16d5_1a60, 0x7b28_20ff, 0x7fff_ffff];
pub const AMPS_EAR_OUT_I32: [i32; 4] = [0x0bc3_1d10, 0x0bc3_1d10, 0x7fff_ffff, 0x7fff_ffff];
pub const AMPS_EAR_IN_I32: [i32; 2] = [0x0bc3_1d10, 0x16d5_1a60];
pub const AMPS_EAR_MIC_I16: [i16; 4] = [0x0bc3, 0x16d5, 0x7b27, 0x7fff];
pub const AMPS_EAR_OUT_I16: [i16; 4] = [0x0bc3, 0x0bc3, 0x7fff, 0x7fff];
pub const AMPS_EAR_IN_I16: [i16; 2] = [0x0bc3, 0x16d5];
#[derive(Clone, Default, Debug)]
pub struct EarMicAmps4<T>(PhantomData<T>);
#[derive(Clone, Default, Debug)]
pub struct EarOutAmps4<T>(PhantomData<T>);
#[derive(Clone, Default, Debug)]
pub struct EarInAmps2<T>(PhantomData<T>);
macro_rules! impl_amp_levels {
($([$ty:ty, $ear_mic:ident, $ear_out:ident, $ear_in:ident]),*) => { $(
impl AmpLevels<$ty> for EarMicAmps4<$ty> {
#[inline(always)]
fn amp_level(level: u32) -> $ty {
$ear_mic[(level & 3) as usize]
}
}
impl AmpLevels<$ty> for EarOutAmps4<$ty> {
#[inline(always)]
fn amp_level(level: u32) -> $ty {
$ear_out[(level & 3) as usize]
}
}
impl AmpLevels<$ty> for EarInAmps2<$ty> {
#[inline(always)]
fn amp_level(level: u32) -> $ty {
$ear_in[(level & 1) as usize]
}
}
)* };
}
impl_amp_levels!([f32, AMPS_EAR_MIC, AMPS_EAR_OUT, AMPS_EAR_IN],
[i32, AMPS_EAR_MIC_I32, AMPS_EAR_OUT_I32, AMPS_EAR_IN_I32],
[i16, AMPS_EAR_MIC_I16, AMPS_EAR_OUT_I16, AMPS_EAR_IN_I16]);
impl<B: Blep> BlepAmpFilter<B> {
pub fn build(filter: B::SampleDelta) -> impl FnOnce(B) -> Self
{
move |blep| Self::new(filter, blep)
}
pub fn new(filter: B::SampleDelta, blep: B) -> Self {
BlepAmpFilter { blep, filter }
}
}
impl<B: Blep> BlepStereo<B> {
pub fn build(mono_filter: B::SampleDelta) -> impl FnOnce(B) -> Self {
move |blep| Self::new(mono_filter, blep)
}
pub fn new(mono_filter: B::SampleDelta, blep: B) -> Self {
BlepStereo { blep, mono_filter }
}
}
impl<B: Blep> Deref for BlepAmpFilter<B> {
type Target = B;
fn deref(&self) -> &B {
&self.blep
}
}
impl<B: Blep> DerefMut for BlepAmpFilter<B> {
fn deref_mut(&mut self) -> &mut B {
&mut self.blep
}
}
impl<B: Blep> Deref for BlepStereo<B> {
type Target = B;
fn deref(&self) -> &B {
&self.blep
}
}
impl<B: Blep> DerefMut for BlepStereo<B> {
fn deref_mut(&mut self) -> &mut B {
&mut self.blep
}
}
impl<B> Blep for BlepAmpFilter<B>
where B: Blep, B::SampleDelta: MulNorm + SampleDelta
{
type SampleDelta = B::SampleDelta;
#[inline]
fn ensure_frame_time(&mut self, sample_rate: u32, ts_rate: f64, frame_ts: FTs, margin_ts: FTs) {
self.blep.ensure_frame_time(sample_rate, ts_rate, frame_ts, margin_ts)
}
#[inline]
fn end_frame(&mut self, timestamp: FTs) -> usize {
self.blep.end_frame(timestamp)
}
#[inline]
fn add_step(&mut self, channel: usize, timestamp: FTs, delta: Self::SampleDelta) {
self.blep.add_step(channel, timestamp, delta.mul_norm(self.filter))
}
}
impl<B> Blep for BlepStereo<B>
where B: Blep, B::SampleDelta: MulNorm + SampleDelta
{
type SampleDelta = B::SampleDelta;
#[inline]
fn ensure_frame_time(&mut self, sample_rate: u32, ts_rate: f64, frame_ts: FTs, margin_ts: FTs) {
self.blep.ensure_frame_time(sample_rate, ts_rate, frame_ts, margin_ts)
}
#[inline]
fn end_frame(&mut self, timestamp: FTs) -> usize {
self.blep.end_frame(timestamp)
}
#[inline]
fn add_step(&mut self, channel: usize, timestamp: FTs, delta: B::SampleDelta) {
match channel {
0|1 => self.blep.add_step(channel, timestamp, delta),
_ => {
let delta = delta.mul_norm(self.mono_filter);
self.blep.add_step(0, timestamp, delta);
self.blep.add_step(1, timestamp, delta);
}
}
}
}
pub fn render_audio_frame_vts<VF,VL,L,A,T>(
prev_state: u8,
end_ts: Option<VFrameTs<VF>>,
changes: &[T],
blep: &mut A, channel: usize
)
where VF: VideoFrame,
VL: AmpLevels<L>,
L: SampleDelta,
A: Blep<SampleDelta=L>,
T: Copy, (VideoTs, u8): From<T>,
{
let mut last_vol = VL::amp_level(prev_state.into());
for &tsd in changes.iter() {
let (ts, state) = tsd.into();
let vts: VFrameTs<_> = ts.into();
if let Some(end_ts) = end_ts {
if vts >= end_ts { break
}
}
let next_vol = VL::amp_level(state.into());
if let Some(delta) = last_vol.sample_delta(next_vol) {
let timestamp = vts.into_tstates();
blep.add_step(channel, timestamp, delta);
last_vol = next_vol;
}
}
}
pub fn render_audio_frame_ts<VL,L,A,T>(
prev_state: u8,
end_ts: Option<FTs>,
changes: &[T],
blep: &mut A,
channel: usize
)
where VL: AmpLevels<L>,
L: SampleDelta,
A: Blep<SampleDelta=L>,
T: Copy, (FTs, u8): From<T>,
{
let mut last_vol = VL::amp_level(prev_state.into());
for &tsd in changes.iter() {
let (ts, state) = tsd.into();
if let Some(end_ts) = end_ts {
if ts >= end_ts { break
}
}
let next_vol = VL::amp_level(state.into());
if let Some(delta) = last_vol.sample_delta(next_vol) {
blep.add_step(channel, ts, delta);
last_vol = next_vol;
}
}
}