Skip to main content

embedded_audio/
source.rs

1use crate::decode::{AdpcmStream, Pcm8Stream};
2use crate::envelope::AdsrSpec;
3use crate::stream::SigmaDeltaBitStream;
4use crate::synth::{FmVoice, ToneParams, ToneVoice, Waveform, WavetableVoice};
5use crate::tier::EffectKind;
6
7/// Active generator for one mixer voice.
8#[derive(Debug, Clone, Copy)]
9pub enum VoiceSource<'a> {
10    Idle,
11    Tone(ToneVoice),
12    Wavetable(WavetableVoice<'a>),
13    Fm(FmVoice),
14    Pcm8(Pcm8Stream<'a>),
15    Adpcm(AdpcmStream<'a>),
16    SigmaDeltaBits(SigmaDeltaBitStream<'a>),
17}
18
19impl<'a> VoiceSource<'a> {
20    pub const fn idle() -> Self {
21        Self::Idle
22    }
23
24    pub fn stop(&mut self) {
25        *self = Self::Idle;
26    }
27
28    pub fn is_active(&self) -> bool {
29        match self {
30            Self::Idle => false,
31            Self::Tone(v) => v.is_active(),
32            Self::Wavetable(v) => v.is_active(),
33            Self::Fm(v) => v.is_active(),
34            Self::Pcm8(v) => !v.is_done(),
35            Self::Adpcm(v) => !v.is_done(),
36            Self::SigmaDeltaBits(v) => !v.is_done(),
37        }
38    }
39
40    /// Dominant carrier for FM hardware (Tier A tone only).
41    pub fn carrier_hz(&self, sample_rate_hz: u32) -> Option<u32> {
42        match self {
43            Self::Tone(v) => {
44                let hz = v.carrier_hz(sample_rate_hz);
45                if hz == 0 { None } else { Some(hz) }
46            }
47            _ => None,
48        }
49    }
50
51    pub fn next_raw_sample(&mut self) -> Option<i8> {
52        match self {
53            Self::Idle => None,
54            Self::Tone(v) => v.next_sample(),
55            Self::Wavetable(v) => v.next_sample(),
56            Self::Fm(v) => v.next_sample(),
57            Self::Pcm8(v) => v.next_sample(),
58            Self::Adpcm(v) => v.next_sample(),
59            Self::SigmaDeltaBits(v) => v.next_sample(),
60        }
61    }
62
63    pub fn start_tone(
64        &mut self,
65        freq_hz: u32,
66        duration_ms: u16,
67        waveform: Waveform,
68        sample_rate_hz: u32,
69    ) {
70        let mut voice = ToneVoice::new();
71        voice.start(
72            ToneParams {
73                freq_hz,
74                duration_ms,
75                waveform,
76                adsr: AdsrSpec::click(),
77            },
78            sample_rate_hz,
79        );
80        *self = Self::Tone(voice);
81    }
82
83    pub fn start_wavetable(&mut self, table: &'a [u8], freq_hz: u32, sample_rate_hz: u32) {
84        let mut voice = WavetableVoice::new(table);
85        voice.start(freq_hz, sample_rate_hz);
86        *self = Self::Wavetable(voice);
87    }
88
89    pub fn start_fm(&mut self, carrier_hz: u32, mod_ratio_cent: u16, sample_rate_hz: u32) {
90        let mut voice = FmVoice::new();
91        voice.start(carrier_hz, mod_ratio_cent, 72, sample_rate_hz);
92        *self = Self::Fm(voice);
93    }
94
95    pub fn start_from_entry(
96        &mut self,
97        kind: EffectKind,
98        flags: u8,
99        param0: u16,
100        param1: u16,
101        payload: &'a [u8],
102        sample_rate_hz: u32,
103    ) -> bool {
104        match kind {
105            EffectKind::Tone => {
106                self.start_tone(param0 as u32, param1, Waveform::Sine, sample_rate_hz);
107                true
108            }
109            EffectKind::Wavetable => {
110                if payload.len() < 256 {
111                    return false;
112                }
113                self.start_wavetable(payload, param0 as u32, sample_rate_hz);
114                true
115            }
116            EffectKind::Fm => {
117                self.start_fm(param0 as u32, param1, sample_rate_hz);
118                true
119            }
120            EffectKind::Pcm8 => {
121                *self = Self::Pcm8(Pcm8Stream::new(payload, flags));
122                true
123            }
124            EffectKind::Adpcm => {
125                if let Some(s) = AdpcmStream::new(payload, flags) {
126                    *self = Self::Adpcm(s);
127                    true
128                } else {
129                    false
130                }
131            }
132            EffectKind::SigmaDeltaBits => {
133                *self = Self::SigmaDeltaBits(SigmaDeltaBitStream::new(payload, flags));
134                true
135            }
136        }
137    }
138}