old school music tracker audio backend
at main 136 lines 3.8 kB view raw
1use core::slice; 2use std::{array, ops::IndexMut}; 3 4use dasp::sample::ToSample; 5 6pub(crate) mod instrument; 7pub mod playback; 8pub(crate) mod sample; 9 10#[repr(transparent)] 11#[derive(Clone, Copy, Default, Debug, PartialEq)] 12pub struct Frame([f32; 2]); 13 14impl std::ops::AddAssign for Frame { 15 fn add_assign(&mut self, rhs: Self) { 16 *self = *self + rhs; 17 } 18} 19 20impl std::ops::Add for Frame { 21 type Output = Self; 22 23 fn add(self, rhs: Self) -> Self::Output { 24 Self([self.0[0] + rhs.0[0], self.0[1] + rhs.0[1]]) 25 } 26} 27 28impl std::ops::Sub for Frame { 29 type Output = Self; 30 31 fn sub(self, rhs: Self) -> Self::Output { 32 Self([self.0[0] - rhs.0[0], self.0[1] - rhs.0[1]]) 33 } 34} 35 36impl std::ops::SubAssign for Frame { 37 fn sub_assign(&mut self, rhs: Self) { 38 *self = *self - rhs; 39 } 40} 41 42impl std::ops::MulAssign<f32> for Frame { 43 fn mul_assign(&mut self, rhs: f32) { 44 *self.0.index_mut(0) *= rhs; 45 *self.0.index_mut(1) *= rhs; 46 } 47} 48 49impl std::ops::Mul<f32> for Frame { 50 type Output = Self; 51 52 fn mul(self, rhs: f32) -> Self::Output { 53 Self([self.0[0] * rhs, self.0[1] * rhs]) 54 } 55} 56 57impl std::iter::Sum for Frame { 58 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { 59 iter.reduce(|acc, x| acc + x).unwrap_or_default() 60 } 61} 62 63impl From<[f32; 2]> for Frame { 64 fn from(value: [f32; 2]) -> Self { 65 Self(value) 66 } 67} 68 69impl From<f32> for Frame { 70 fn from(value: f32) -> Self { 71 Self([value, value]) 72 } 73} 74 75impl Frame { 76 // split into left and right. 77 pub fn split_array<const N: usize>(value: [Frame; N]) -> ([f32; N], [f32; N]) { 78 ( 79 array::from_fn(|i| value[i].0[0]), 80 array::from_fn(|i| value[i].0[1]), 81 ) 82 } 83 84 pub fn sum_to_mono(self) -> f32 { 85 self.0[0] + self.0[1] 86 } 87 88 pub fn from_mut<'a>(value: &'a mut [f32; 2]) -> &'a mut Self { 89 // SAFETY: lifetime is specified, both mut, Self is repr(transparent). 90 unsafe { std::mem::transmute::<&'a mut [f32; 2], &'a mut Self>(value) } 91 } 92 93 pub fn from_interleaved(value: &[f32]) -> &[Frame] { 94 debug_assert!(value.len().rem_euclid(2) == 0); 95 let len = value.len() / 2; 96 let ptr = value.as_ptr().cast(); 97 // SAFETY: keeps the same lifetime and mutability. 98 // [f32; 2] is a valid frame 99 unsafe { slice::from_raw_parts(ptr, len) } 100 } 101 102 pub fn from_ref<'a>(value: &'a [f32; 2]) -> &'a Self { 103 // SAFETY: lifetime is specified, both not mut, Self is repr(transparent). 104 unsafe { std::mem::transmute::<&'a [f32; 2], &'a Self>(value) } 105 } 106 107 pub fn to_sample<S: dasp::sample::FromSample<f32>>(self) -> [S; 2] { 108 [self.0[0].to_sample_(), self.0[1].to_sample_()] 109 } 110 111 pub fn to_raw<'a>(into: &mut [Self]) -> &'a mut [[f32; 2]] { 112 unsafe { std::mem::transmute(into) } 113 } 114 115 // pan laws taken from: https://www.cs.cmu.edu/~music/icm-online/readings/panlaws/index.html 116 117 // /// angle in radians between 0 and 90° 118 // pub fn pan_linear(&mut self, angle: f32) { 119 // self.0[0] *= (std::f32::consts::FRAC_PI_2 - angle) * std::f32::consts::FRAC_2_PI; 120 // self.0[1] *= angle * std::f32::consts::FRAC_2_PI; 121 // } 122 123 /// angle in radians between 0 and 90° 124 pub fn pan_constant_power(&mut self, angle: f32) { 125 self.0[0] *= angle.cos(); 126 self.0[1] *= angle.sin(); 127 } 128 129 // /// angle in radians between 0 and 90° 130 // pub fn pan_compromise(&mut self, angle: f32) { 131 // self.0[0] *= f32::sqrt( 132 // (std::f32::consts::FRAC_PI_2 - angle) * std::f32::consts::FRAC_2_PI * angle.cos(), 133 // ); 134 // self.0[1] *= f32::sqrt(angle * std::f32::consts::FRAC_2_PI * angle.sin()); 135 // } 136}