Sound: the board's speaker, and HDMI
Two ways to make noise: the small speaker soldered on the board, which plays notes and melodies without blocking the program, and the screen’s speakers, over the HDMI socket, still being tried out.
The board’s speaker
According to the board’s KiCad files (revision A), the speaker is a magnetic transducer (QMB-09B-03), driven by the RP2040’s GPIO20 pin through a transistor. It has no internal oscillator: it must be fed a square wave. It is loudest around 2.7 kHz, its resonant frequency.
The Eliott65 driver produces this signal with one of the RP2040’s PWM units: the frequency is set to within 0.1%, from 20 Hz to 20 kHz, and the volume through the duty cycle (50% at most, the loudest).
The SON service
Service number 6 has three functions:
| Function | What it does |
|---|---|
NOTE | plays a note (frequency, duration, volume) and returns immediately |
ETAT | tells what is left to play, and which note of the melody is playing |
MELODIE | plays a sequence of notes in the background, once or in a loop |
Nothing blocks: the program carries on while the kernel plays. And, as with sprites, the melody is read note by note in the program’s memory, without copying: the program can change it while it plays (generated music, tempo). The sound stops with the process that started it.
The parameters are detailed in the API reference.
Heard on the board (v0.48)
The MUSIQUE.E65 program beeps at 2,700 Hz, then plays the French nursery tune “Au clair de la lune”
in a loop, showing the current note. Checks:
- the PWM, read back by the probe during the melody: 523.0, 659.0 and 587.0 Hz, with the pin at 0 during rests;
- by ear, by the user: “it works”.
In the emulator, the SDL window sends the same square wave to the PC’s sound output.
Sound over the HDMI socket (being tried out)
The other way goes through HDMI data islands (see Video): packets slipped into each line’s sync period, carrying audio samples to the screen’s speakers.
- Step 2 (v0.47): a test tone, an A at exactly 441 Hz, sampled at 44.1 kHz. The emulator’s bench decodes the packets: 735 correct samples out of 735.
- First try on the board: failed. Producing the samples in core 1’s interrupt made about 200 lines per frame late. The fix: core 0 produces the samples, as it already draws the graphics; the interrupt only copies what changes.
- Not yet confirmed by ear. At the user’s request, this avenue is set aside in favour of the board’s speaker; the next step (an API for this sound) is on hold.
- A hidden cost, fixed (v0.48.2). Measuring the graphics again revealed a regression: core 0 was producing the test A all the time, on every line, and two graphics scenarios no longer fitted. The test tone is now off by default: with no sound to play, core 0 produces nothing. Going further, producing the samples will have to cost much less.