1pub use self::de::Signal;
2use anyhow::{Ok, Result};
3use bppt::Notes;
4use derive_new::new;
5use serde::Deserialize;
6use std::fmt::Debug;
7use std::num::{NonZeroU16, NonZeroUsize};
8
9mod de;
10mod default;
11
12pub(crate) const SAMPLE_RATE: u32 = 48000;
13
14#[derive(new, PartialEq, Debug, Deserialize)]
15pub struct Track {
16 #[serde(rename = "BPM")]
17 pub bpm: NonZeroU16,
18 pub channels: Vec<Channel>,
19}
20
21impl Channel {
22 pub(crate) fn generator(&self) -> Result<impl Fn(NonZeroUsize, u8, u8, u8) -> Vec<f32>> {
23 let func = self.signal.clone().0.bind2("t", "f")?;
24 let notes = self.notes.set;
25 let tuning = self.tuning;
26 Ok(
27 move |len: NonZeroUsize, n: u8, octave: u8, volume: u8| -> Vec<f32> {
28 let f = (tuning as f64 / 16f64)
29 * 2.0_f64.powf(((notes * octave + n) as f64) / (notes as f64));
30 (1..=usize::from(len))
31 .map(|i| {
32 let t = (i as f64) / (SAMPLE_RATE as f64);
33 (func(t, f) * ((volume as f64) / 100f64)) as f32
34 })
35 .collect()
36 },
37 )
38 }
39}
40
41#[derive(PartialEq, Debug, new, Deserialize)]
42pub struct Channel {
43 pub signal: Signal,
44 #[serde(flatten)]
45 pub notes: Notes,
46 pub tuning: f32,
47}