Skip to main content

gb/mmio/
audio.rs

1//! Audio (`NR10`..`NR52`, wave RAM).
2
3use bitfield_struct::{bitenum, bitfield};
4use voladdress::{Safe, VolAddress, VolBlock};
5
6/// Square-wave duty cycle (`NR11` / `NR21` bits 7-6).
7#[bitenum(all = false)]
8#[repr(u8)]
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum Duty {
11    /// 12.5%.
12    Eighth = 0,
13    /// 25%.
14    Quarter = 1,
15    /// 50%.
16    Half = 2,
17    /// 75% (audibly identical to 25%).
18    #[fallback]
19    ThreeQuarters = 3,
20}
21
22/// Wave-channel output level (`NR32` bits 6-5).
23#[bitenum(all = false)]
24#[repr(u8)]
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub enum WaveLevel {
27    /// Muted.
28    Mute = 0,
29    /// 100%, samples used as-is.
30    Full = 1,
31    /// 50%, samples shifted right once.
32    Half = 2,
33    /// 25%, samples shifted right twice.
34    #[fallback]
35    Quarter = 3,
36}
37
38/// Channel 1 frequency sweep (`NR10`).
39///
40/// | Bit | Field | Access | Meaning |
41/// |-----|-------|--------|---------|
42/// | 7   | —          |     | Unused. |
43/// | 6-4 | `pace`     | R/W | An iteration every `pace` 128 Hz ticks; 0 disables the sweep. |
44/// | 3   | `subtract` | R/W | Period direction: clear adds, set subtracts. |
45/// | 2-0 | `step`     | R/W | Shift applied to the period each iteration. |
46#[bitfield(u8)]
47#[derive(PartialEq, Eq)]
48pub struct Sweep {
49    /// Step: shift applied to the period each iteration.
50    #[bits(3)]
51    pub step: u8,
52    /// Direction: `false` adds to the period, `true` subtracts.
53    pub subtract: bool,
54    /// Pace: an iteration every `pace` 128 Hz ticks (0 disables sweep).
55    #[bits(3)]
56    pub pace: u8,
57    #[bits(1)]
58    __: u8,
59}
60
61/// Length timer and duty cycle (`NR11` / `NR21`).
62///
63/// | Bit | Field | Access | Meaning |
64/// |-----|-------|--------|---------|
65/// | 7-6 | `duty`   | R/W | Output waveform duty cycle. |
66/// | 5-0 | `length` | W   | Initial length timer; higher means a shorter time to cut. |
67#[bitfield(u8)]
68#[derive(PartialEq, Eq)]
69pub struct PulseLengthDuty {
70    /// Initial length timer (write-only): higher means a shorter time to cut.
71    #[bits(6, access = WO)]
72    pub length: u8,
73    /// Output waveform duty cycle.
74    #[bits(2)]
75    pub duty: Duty,
76}
77
78/// Volume and envelope (`NR12` / `NR22` / `NR42`).
79///
80/// | Bit | Field | Access | Meaning |
81/// |-----|-------|--------|---------|
82/// | 7-4 | `volume`   | R/W | Initial volume. |
83/// | 3   | `increase` | R/W | Direction: set raises volume over time, clear lowers it. |
84/// | 2-0 | `pace`     | R/W | A step every `pace` 64 Hz ticks; 0 disables the envelope. |
85#[bitfield(u8)]
86#[derive(PartialEq, Eq)]
87pub struct Envelope {
88    /// Envelope pace: a step every `pace` 64 Hz ticks (0 disables the envelope).
89    #[bits(3)]
90    pub pace: u8,
91    /// Direction: `true` increases volume over time, `false` decreases.
92    pub increase: bool,
93    /// Initial volume.
94    #[bits(4)]
95    pub volume: u8,
96}
97
98/// Period high bits and channel control (`NR14` / `NR24` / `NR34`).
99///
100/// | Bit | Field | Access | Meaning |
101/// |-----|-------|--------|---------|
102/// | 7   | `trigger`       | W   | (Re)start the channel. |
103/// | 6   | `length_enable` | R/W | Stop the channel when the length timer expires. |
104/// | 5-3 | —               |     | Unused. |
105/// | 2-0 | `period_high`   | W   | Upper 3 bits of the 11-bit period (low 8 in `NRx3`). |
106#[bitfield(u8)]
107#[derive(PartialEq, Eq)]
108pub struct PeriodCtrl {
109    /// Upper 3 bits of the 11-bit period (low 8 bits live in `NRx3`).
110    #[bits(3, access = WO)]
111    pub period_high: u8,
112    #[bits(3)]
113    __: u8,
114    /// Stop the channel when the length timer expires.
115    pub length_enable: bool,
116    /// Trigger (write-only): (re)start the channel.
117    #[bits(1, access = WO)]
118    pub trigger: bool,
119}
120
121/// Channel 3 DAC power (`NR30`).
122///
123/// | Bit | Field | Access | Meaning |
124/// |-----|-------|--------|---------|
125/// | 7   | `dac_on` | R/W | DAC power; turning it off also turns the channel off. |
126/// | 6-0 | —        |     | Unused. |
127#[bitfield(u8)]
128#[derive(PartialEq, Eq)]
129pub struct WaveDac {
130    #[bits(7)]
131    __: u8,
132    /// DAC power. Turning it off also turns the channel off.
133    pub dac_on: bool,
134}
135
136/// Channel 3 output level (`NR32`).
137///
138/// | Bit | Field | Access | Meaning |
139/// |-----|-------|--------|---------|
140/// | 7   | —       |     | Unused. |
141/// | 6-5 | `level` | R/W | Coarse output volume. |
142/// | 4-0 | —       |     | Unused. |
143#[bitfield(u8)]
144#[derive(PartialEq, Eq)]
145pub struct WaveOutput {
146    #[bits(5)]
147    __: u8,
148    /// Coarse output volume.
149    #[bits(2)]
150    pub level: WaveLevel,
151    #[bits(1)]
152    __: u8,
153}
154
155/// Channel 4 frequency and randomness (`NR43`).
156///
157/// | Bit | Field | Access | Meaning |
158/// |-----|-------|--------|---------|
159/// | 7-4 | `shift`      | R/W | Clock shift. |
160/// | 3   | `short_lfsr` | R/W | LFSR width: set = 7-bit (more tonal), clear = 15-bit. |
161/// | 2-0 | `divider`    | R/W | Clock divider. |
162#[bitfield(u8)]
163#[derive(PartialEq, Eq)]
164pub struct NoiseFreq {
165    /// Clock divider.
166    #[bits(3)]
167    pub divider: u8,
168    /// LFSR width: `false` = 15-bit, `true` = 7-bit (more tonal).
169    pub short_lfsr: bool,
170    /// Clock shift.
171    #[bits(4)]
172    pub shift: u8,
173}
174
175/// Channel 4 control (`NR44`).
176///
177/// | Bit | Field | Access | Meaning |
178/// |-----|-------|--------|---------|
179/// | 7   | `trigger`       | W   | (Re)start the channel. |
180/// | 6   | `length_enable` | R/W | Stop the channel when the length timer expires. |
181/// | 5-0 | —               |     | Unused. |
182#[bitfield(u8)]
183#[derive(PartialEq, Eq)]
184pub struct NoiseCtrl {
185    #[bits(6)]
186    __: u8,
187    /// Stop the channel when the length timer expires.
188    pub length_enable: bool,
189    /// Trigger (write-only): (re)start the channel.
190    #[bits(1, access = WO)]
191    pub trigger: bool,
192}
193
194/// Master volume and VIN panning (`NR50`).
195///
196/// | Bit | Field | Access | Meaning |
197/// |-----|-------|--------|---------|
198/// | 7   | `vin_left`     | R/W | Mix external VIN into the left output. |
199/// | 6-4 | `left_volume`  | R/W | Left output volume (0 treated as 1, 7 as 8). |
200/// | 3   | `vin_right`    | R/W | Mix external VIN into the right output. |
201/// | 2-0 | `right_volume` | R/W | Right output volume (0 treated as 1, 7 as 8). |
202#[bitfield(u8)]
203#[derive(PartialEq, Eq)]
204pub struct MasterVolume {
205    /// Right output volume (0 is treated as 1, 7 as 8).
206    #[bits(3)]
207    pub right_volume: u8,
208    /// Mix external VIN into the right output.
209    pub vin_right: bool,
210    /// Left output volume (0 is treated as 1, 7 as 8).
211    #[bits(3)]
212    pub left_volume: u8,
213    /// Mix external VIN into the left output.
214    pub vin_left: bool,
215}
216
217/// Sound panning (`NR51`): which channels reach each output.
218///
219/// | Bit | Field | Access | Meaning |
220/// |-----|-------|--------|---------|
221/// | 7   | `ch4_left`  | R/W | Channel 4 (noise) reaches the left output. |
222/// | 6   | `ch3_left`  | R/W | Channel 3 (wave) reaches the left output. |
223/// | 5   | `ch2_left`  | R/W | Channel 2 (pulse) reaches the left output. |
224/// | 4   | `ch1_left`  | R/W | Channel 1 (pulse) reaches the left output. |
225/// | 3   | `ch4_right` | R/W | Channel 4 (noise) reaches the right output. |
226/// | 2   | `ch3_right` | R/W | Channel 3 (wave) reaches the right output. |
227/// | 1   | `ch2_right` | R/W | Channel 2 (pulse) reaches the right output. |
228/// | 0   | `ch1_right` | R/W | Channel 1 (pulse) reaches the right output. |
229#[bitfield(u8)]
230#[derive(PartialEq, Eq)]
231pub struct Panning {
232    /// Channel 1 (pulse) reaches the right output.
233    pub ch1_right: bool,
234    /// Channel 2 (pulse) reaches the right output.
235    pub ch2_right: bool,
236    /// Channel 3 (wave) reaches the right output.
237    pub ch3_right: bool,
238    /// Channel 4 (noise) reaches the right output.
239    pub ch4_right: bool,
240    /// Channel 1 (pulse) reaches the left output.
241    pub ch1_left: bool,
242    /// Channel 2 (pulse) reaches the left output.
243    pub ch2_left: bool,
244    /// Channel 3 (wave) reaches the left output.
245    pub ch3_left: bool,
246    /// Channel 4 (noise) reaches the left output.
247    pub ch4_left: bool,
248}
249
250/// Audio master control (`NR52`).
251///
252/// | Bit | Field | Access | Meaning |
253/// |-----|-------|--------|---------|
254/// | 7   | `audio_on` | R/W | Master audio power; off clears and locks the other registers. |
255/// | 6-4 | —          |     | Unused. |
256/// | 3   | `ch4_on`   | RO  | Channel 4 (noise) is running. |
257/// | 2   | `ch3_on`   | RO  | Channel 3 (wave) is running. |
258/// | 1   | `ch2_on`   | RO  | Channel 2 (pulse) is running. |
259/// | 0   | `ch1_on`   | RO  | Channel 1 (pulse) is running. |
260#[bitfield(u8)]
261#[derive(PartialEq, Eq)]
262pub struct AudioCtrl {
263    /// Channel 1 (pulse) is running (read-only status).
264    #[bits(1, access = RO)]
265    pub ch1_on: bool,
266    /// Channel 2 (pulse) is running (read-only status).
267    #[bits(1, access = RO)]
268    pub ch2_on: bool,
269    /// Channel 3 (wave) is running (read-only status).
270    #[bits(1, access = RO)]
271    pub ch3_on: bool,
272    /// Channel 4 (noise) is running (read-only status).
273    #[bits(1, access = RO)]
274    pub ch4_on: bool,
275    #[bits(3)]
276    __: u8,
277    /// Master audio power. Turning it off clears and locks the other registers.
278    pub audio_on: bool,
279}
280
281// ── Channel 1 (square + sweep) ──────────────────────────────────────────────
282
283/// Channel 1 sweep.
284pub const NR10: VolAddress<Sweep, Safe, Safe> = unsafe { VolAddress::new(0xFF10) };
285/// Channel 1 length timer and duty cycle.
286pub const NR11: VolAddress<PulseLengthDuty, Safe, Safe> = unsafe { VolAddress::new(0xFF11) };
287/// Channel 1 volume and envelope.
288pub const NR12: VolAddress<Envelope, Safe, Safe> = unsafe { VolAddress::new(0xFF12) };
289/// Channel 1 period low byte (write-only).
290pub const NR13: VolAddress<u8, (), Safe> = unsafe { VolAddress::new(0xFF13) };
291/// Channel 1 period high byte and control.
292pub const NR14: VolAddress<PeriodCtrl, Safe, Safe> = unsafe { VolAddress::new(0xFF14) };
293
294// ── Channel 2 (square) ──────────────────────────────────────────────────────
295
296/// Channel 2 length timer and duty cycle.
297pub const NR21: VolAddress<PulseLengthDuty, Safe, Safe> = unsafe { VolAddress::new(0xFF16) };
298/// Channel 2 volume and envelope.
299pub const NR22: VolAddress<Envelope, Safe, Safe> = unsafe { VolAddress::new(0xFF17) };
300/// Channel 2 period low byte (write-only).
301pub const NR23: VolAddress<u8, (), Safe> = unsafe { VolAddress::new(0xFF18) };
302/// Channel 2 period high byte and control.
303pub const NR24: VolAddress<PeriodCtrl, Safe, Safe> = unsafe { VolAddress::new(0xFF19) };
304
305// ── Channel 3 (wave) ────────────────────────────────────────────────────────
306
307/// Channel 3 DAC power.
308pub const NR30: VolAddress<WaveDac, Safe, Safe> = unsafe { VolAddress::new(0xFF1A) };
309/// Channel 3 length timer (write-only).
310pub const NR31: VolAddress<u8, (), Safe> = unsafe { VolAddress::new(0xFF1B) };
311/// Channel 3 output level.
312pub const NR32: VolAddress<WaveOutput, Safe, Safe> = unsafe { VolAddress::new(0xFF1C) };
313/// Channel 3 period low byte (write-only).
314pub const NR33: VolAddress<u8, (), Safe> = unsafe { VolAddress::new(0xFF1D) };
315/// Channel 3 period high byte and control.
316pub const NR34: VolAddress<PeriodCtrl, Safe, Safe> = unsafe { VolAddress::new(0xFF1E) };
317
318// ── Channel 4 (noise) ───────────────────────────────────────────────────────
319
320/// Channel 4 length timer (write-only).
321pub const NR41: VolAddress<u8, (), Safe> = unsafe { VolAddress::new(0xFF20) };
322/// Channel 4 volume and envelope.
323pub const NR42: VolAddress<Envelope, Safe, Safe> = unsafe { VolAddress::new(0xFF21) };
324/// Channel 4 frequency and randomness.
325pub const NR43: VolAddress<NoiseFreq, Safe, Safe> = unsafe { VolAddress::new(0xFF22) };
326/// Channel 4 control.
327pub const NR44: VolAddress<NoiseCtrl, Safe, Safe> = unsafe { VolAddress::new(0xFF23) };
328
329// ── Control ─────────────────────────────────────────────────────────────────
330
331/// Master volume and VIN panning.
332pub const NR50: VolAddress<MasterVolume, Safe, Safe> = unsafe { VolAddress::new(0xFF24) };
333/// Sound panning: which channels go to which output.
334pub const NR51: VolAddress<Panning, Safe, Safe> = unsafe { VolAddress::new(0xFF25) };
335/// Audio master control: power and per-channel status.
336pub const NR52: VolAddress<AudioCtrl, Safe, Safe> = unsafe { VolAddress::new(0xFF26) };
337
338/// Wave pattern RAM: 16 bytes of channel 3 sample data at `0xFF30`.
339pub const WAVE_RAM: VolBlock<u8, Safe, Safe, 16> = unsafe { VolBlock::new(0xFF30) };
340
341const _: () = {
342    assert!(Sweep::new().with_pace(0x7).into_bits() == 0b0111_0000);
343    assert!(PulseLengthDuty::new().with_duty(Duty::ThreeQuarters).into_bits() == 0b1100_0000);
344    assert!(Envelope::new().with_volume(0xF).into_bits() == 0b1111_0000);
345    assert!(PeriodCtrl::new().with_trigger(true).into_bits() == 0b1000_0000);
346    assert!(PeriodCtrl::new().with_length_enable(true).into_bits() == 0b0100_0000);
347    assert!(WaveDac::new().with_dac_on(true).into_bits() == 0b1000_0000);
348    assert!(WaveOutput::new().with_level(WaveLevel::Quarter).into_bits() == 0b0110_0000);
349    assert!(NoiseFreq::new().with_shift(0xF).into_bits() == 0b1111_0000);
350    assert!(MasterVolume::new().with_vin_left(true).into_bits() == 0b1000_0000);
351    assert!(Panning::new().with_ch1_right(true).into_bits() == 0b0000_0001);
352    assert!(Panning::new().with_ch4_left(true).into_bits() == 0b1000_0000);
353    assert!(AudioCtrl::new().with_audio_on(true).into_bits() == 0b1000_0000);
354};