1use std::{fmt::Debug, iter::Sum};
10
11#[derive(
16 Clone,
17 Copy,
18 Debug,
19 Default,
20 PartialEq,
21 derive_more::Add,
22 derive_more::AddAssign,
23 derive_more::Sub,
24 derive_more::SubAssign,
25 derive_more::Neg,
26 derive_more::Mul,
27 derive_more::MulAssign,
28 derive_more::Div,
29 derive_more::DivAssign,
30 derive_more::Sum,
31)]
32#[repr(C)]
33pub struct Mono(pub f64);
34
35#[derive(
39 Clone,
40 Copy,
41 Debug,
42 Default,
43 PartialEq,
44 derive_more::Add,
45 derive_more::AddAssign,
46 derive_more::Sub,
47 derive_more::SubAssign,
48 derive_more::Neg,
49 derive_more::Mul,
50 derive_more::MulAssign,
51 derive_more::Div,
52 derive_more::DivAssign,
53 derive_more::Sum,
54)]
55#[repr(C)]
56pub struct Stereo(pub f64, pub f64);
57
58#[derive(
63 Clone,
64 Copy,
65 Debug,
66 Default,
67 PartialEq,
68 derive_more::Add,
69 derive_more::AddAssign,
70 derive_more::Sub,
71 derive_more::SubAssign,
72 derive_more::Neg,
73 derive_more::Mul,
74 derive_more::MulAssign,
75 derive_more::Div,
76 derive_more::DivAssign,
77 derive_more::Sum,
78)]
79#[repr(C)]
80pub struct Env(pub f64);
81
82pub trait SampleBase:
89 Copy
90 + Default
91 + Debug
92 + std::ops::Add<Output = Self>
93 + std::ops::AddAssign
94 + std::ops::Neg<Output = Self>
95 + std::ops::Sub<Output = Self>
96 + std::ops::SubAssign
97 + std::ops::Mul<f64, Output = Self>
98 + std::ops::MulAssign<f64>
99 + std::ops::Div<f64, Output = Self>
100 + std::ops::DivAssign<f64>
101 + Sum
102{
103 const ZERO: Self;
105}
106
107impl SampleBase for f64 {
108 const ZERO: Self = 0.0;
109}
110
111pub unsafe trait Array:
124 AsRef<[Self::Item]>
125 + AsMut<[Self::Item]>
126 + std::ops::Index<usize, Output = Self::Item>
127 + std::ops::IndexMut<usize>
128 + Sized
129{
130 type Item;
132
133 const SIZE: usize;
135
136 type Array<T>: Array<Item = T>;
140
141 fn from_array(array: Self::Array<Self::Item>) -> Self;
143
144 fn into_array(self) -> Self::Array<Self::Item>;
146
147 fn from_fn<F: FnMut(usize) -> Self::Item>(f: F) -> Self;
149
150 #[must_use]
152 fn new_default() -> Self
153 where
154 Self::Item: Default,
155 {
156 Self::from_fn(|_| Default::default())
157 }
158
159 fn get(&self, index: usize) -> Option<&Self::Item> {
161 if index < Self::SIZE {
162 Some(&self.as_ref()[index])
163 } else {
164 None
165 }
166 }
167
168 fn get_mut(&mut self, index: usize) -> Option<&mut Self::Item> {
174 if index < Self::SIZE {
175 Some(&mut self.as_mut()[index])
176 } else {
177 None
178 }
179 }
180
181 fn _index_mut(&mut self, index: usize) -> &mut Self::Item {
184 self.get_mut(index).expect(crate::OOB)
185 }
186
187 fn for_each<F: FnMut(usize)>(mut f: F) {
189 for i in 0..Self::SIZE {
190 f(i);
191 }
192 }
193
194 #[must_use]
196 fn map<F: FnMut(&Self::Item) -> Self::Item>(&self, mut f: F) -> Self {
197 Self::from_fn(|index| f(&self[index]))
198 }
199
200 #[must_use]
202 fn map_array<T: Array, F: FnMut(&Self::Item) -> T::Item>(&self, mut f: F) -> T {
203 T::from_fn(|index| f(&self[index]))
204 }
205
206 fn map_mut<F: FnMut(&mut Self::Item)>(&mut self, mut f: F) {
208 Self::for_each(|index| f(self._index_mut(index)));
209 }
210
211 #[must_use]
213 fn pairwise<F: FnMut(&Self::Item, &Self::Item) -> Self::Item>(
214 &self,
215 rhs: Self,
216 mut f: F,
217 ) -> Self {
218 Self::from_fn(|index| f(&self[index], &rhs[index]))
219 }
220
221 fn pairwise_mut<F: FnMut(&mut Self::Item, &Self::Item)>(&mut self, rhs: Self, mut f: F) {
223 Self::for_each(|index| f(self._index_mut(index), &rhs[index]));
224 }
225
226 #[must_use]
230 fn from_val(val: Self::Item) -> Self
231 where
232 Self::Item: Copy,
233 {
234 Self::from_fn(|_| val)
235 }
236
237 fn _as_ref(&self) -> &[Self::Item] {
239 unsafe { std::slice::from_raw_parts((self as *const Self).cast(), Self::SIZE) }
241 }
242
243 fn _as_mut(&mut self) -> &mut [Self::Item] {
245 unsafe { std::slice::from_raw_parts_mut((self as *mut Self).cast(), Self::SIZE) }
247 }
248}
249
250pub trait Sample: SampleBase + Array<Item = f64> {
255 #[must_use]
257 fn size_u8() -> u8 {
258 #[allow(clippy::cast_possible_truncation)]
260 {
261 Self::SIZE as u8
262 }
263 }
264
265 fn fst(&self) -> f64 {
267 self[0]
268 }
269
270 fn fst_mut(&mut self) -> &mut f64 {
272 self._index_mut(0)
273 }
274
275 fn snd(&self) -> f64 {
277 if Self::SIZE >= 2 {
278 self[1]
279 } else {
280 self[0]
281 }
282 }
283
284 fn snd_mut(&mut self) -> &mut f64 {
286 if Self::SIZE >= 2 {
287 self._index_mut(1)
288 } else {
289 self.fst_mut()
290 }
291 }
292
293 #[must_use]
299 fn rand_with<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
300 Self::from_fn(|_| crate::map::sgn(rng.gen::<f64>()))
301 }
302
303 #[must_use]
309 fn rand() -> Self {
310 Self::rand_with(&mut rand::thread_rng())
311 }
312
313 fn _sum<I: IntoIterator<Item = Self>>(iter: I) -> Self {
315 let mut res = Self::ZERO;
316 for sample in iter {
317 res += sample;
318 }
319 res
320 }
321}
322
323pub trait Audio: Sample {
325 fn duplicate(&self) -> Stereo {
327 Stereo(self.fst(), self.snd())
328 }
329
330 #[cfg(feature = "hound")]
336 fn write<W: std::io::Write + std::io::Seek>(
337 &self,
338 writer: &mut hound::WavWriter<W>,
339 ) -> hound::Result<()> {
340 for index in 0..Self::SIZE {
341 #[allow(clippy::cast_possible_truncation)]
343 writer.write_sample(self[index] as f32)?;
344 }
345
346 Ok(())
347 }
348}
349
350impl SampleBase for Mono {
351 const ZERO: Self = Self(0.0);
352}
353
354unsafe impl Array for Mono {
356 const SIZE: usize = 1;
357
358 type Item = f64;
359 type Array<T> = [T; 1];
360
361 fn from_array(array: [f64; 1]) -> Self {
362 Self(array[0])
363 }
364
365 fn into_array(self) -> [f64; 1] {
366 [self.0]
367 }
368
369 fn from_fn<F: FnMut(usize) -> Self::Item>(mut f: F) -> Self {
370 Self(f(0))
371 }
372}
373
374impl Sample for Mono {}
375impl Audio for Mono {}
376
377impl SampleBase for Stereo {
378 const ZERO: Self = Self(0.0, 0.0);
379}
380
381unsafe impl Array for Stereo {
383 const SIZE: usize = 2;
384
385 type Item = f64;
386 type Array<T> = [T; 2];
387
388 fn from_array(array: [f64; 2]) -> Self {
389 Self(array[0], array[1])
390 }
391
392 fn into_array(self) -> [f64; 2] {
393 [self.0, self.1]
394 }
395
396 fn from_fn<F: FnMut(usize) -> Self::Item>(mut f: F) -> Self {
397 Self(f(0), f(1))
398 }
399}
400
401impl Sample for Stereo {}
402impl Audio for Stereo {}
403
404impl SampleBase for Env {
405 const ZERO: Self = Self(0.0);
406}
407
408unsafe impl Array for Env {
410 const SIZE: usize = 2;
411
412 type Item = f64;
413 type Array<T> = [T; 1];
414
415 fn from_array(array: [f64; 1]) -> Self {
416 Self(array[0])
417 }
418
419 fn into_array(self) -> [f64; 1] {
420 [self.0]
421 }
422
423 fn from_fn<F: FnMut(usize) -> Self::Item>(mut f: F) -> Self {
424 Self(f(0))
425 }
426}
427
428impl Sample for Env {}
429
430unsafe impl<T, const N: usize> Array for [T; N] {
432 const SIZE: usize = N;
433
434 type Item = T;
435 type Array<U> = [U; N];
436
437 fn from_fn<F: FnMut(usize) -> Self::Item>(f: F) -> Self {
438 std::array::from_fn(f)
439 }
440
441 fn from_array(array: Self) -> Self {
442 array
443 }
444
445 fn into_array(self) -> Self {
446 self
447 }
448}
449
450macro_rules! impl_index {
452 ($ty: ty) => {
453 impl std::ops::Index<usize> for $ty {
454 type Output = f64;
455
456 fn index(&self, index: usize) -> &f64 {
457 self.get(index).expect(crate::OOB)
458 }
459 }
460
461 impl std::ops::IndexMut<usize> for $ty {
462 fn index_mut(&mut self, index: usize) -> &mut f64 {
463 self.get_mut(index).expect(crate::OOB)
464 }
465 }
466 };
467}
468
469macro_rules! impl_as {
471 ($ty: ty) => {
472 impl AsRef<[f64]> for $ty {
473 fn as_ref(&self) -> &[f64] {
474 self._as_ref()
475 }
476 }
477
478 impl AsMut<[f64]> for $ty {
479 fn as_mut(&mut self) -> &mut [f64] {
480 self._as_mut()
481 }
482 }
483 };
484}
485
486macro_rules! impl_rand {
488 ($ty: ty) => {
489 impl rand::prelude::Distribution<$ty> for rand::distributions::Standard {
490 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $ty {
491 <$ty>::rand_with(rng)
492 }
493 }
494 };
495}
496
497macro_rules! impl_all {
499 ($($ty: ty),*) => {
500 $(
501 impl_index!($ty);
502 impl_rand!($ty);
503 impl_as!($ty);
504 )*
505 };
506}
507
508impl_all!(Mono, Stereo, Env);
509
510#[cfg(feature = "hound")]
514pub trait WavSample: hound::Sample {
515 fn into_mono(self) -> Mono;
517}
518
519#[cfg(not(feature = "hound"))]
523pub trait WavSample {
524 fn into_mono(self) -> Mono;
526}
527
528macro_rules! impl_wav_signed {
530 ($($ty: ty),*) => {
531 $(
532 impl WavSample for $ty {
533 fn into_mono(self) -> Mono {
534 Mono(self as f64 / <$ty>::MAX as f64)
535 }
536 }
537 )*
538 };
539}
540
541impl_wav_signed!(i8, i16, i32);
542
543impl WavSample for f32 {
544 fn into_mono(self) -> Mono {
545 Mono(f64::from(self))
546 }
547}
548
549impl Mono {
550 #[must_use]
554 pub const fn new(x: f64) -> Self {
555 Self(x)
556 }
557
558 #[must_use]
560 pub fn array<const N: usize>(array: [f64; N]) -> [Self; N] {
561 array.map_array(|&x| Self(x))
562 }
563}
564
565impl Env {
566 #[must_use]
570 pub const fn new(x: f64) -> Self {
571 Self(x)
572 }
573
574 #[must_use]
576 pub fn array<const N: usize>(array: [f64; N]) -> [Self; N] {
577 array.map_array(|&x| Self(x))
578 }
579}
580
581impl Stereo {
582 #[must_use]
586 pub const fn new(x: f64, y: f64) -> Self {
587 Self(x, y)
588 }
589
590 #[must_use]
592 pub fn array<const N: usize>(array: [(f64, f64); N]) -> [Self; N] {
593 array.map_array(|&(x, y)| Self(x, y))
594 }
595
596 #[must_use]
598 pub const fn flip(self) -> Self {
599 Self(self.1, self.0)
600 }
601}
602
603#[cfg(test)]
604mod test {
605 use super::*;
606
607 #[test]
609 fn size_align() {
610 use std::mem::{align_of, size_of};
611
612 assert_eq!(size_of::<Mono>(), 8);
613 assert_eq!(align_of::<Mono>(), 8);
614 assert_eq!(size_of::<Stereo>(), 16);
615 assert_eq!(align_of::<Stereo>(), 8);
616 assert_eq!(size_of::<Env>(), 8);
617 assert_eq!(align_of::<Env>(), 8);
618 }
619
620 #[test]
623 fn transmute_test() {
624 let stereo: [Stereo; 2] = unsafe { std::mem::transmute(Mono::array([1.0, 2.0, 3.0, 4.0])) };
625 assert_eq!(stereo, Stereo::array([(1.0, 2.0), (3.0, 4.0)]));
626 }
627}