# Speaker

Sound out of a Kode Dot: the codec's DAC, the amplifier the C5 switches on, the sample rate that keeps it clean, and the code to play a tone.

## What it is

The speaker is a small 8 Ω, 1 W driver behind the front of the case. It
plays whatever the codec's DAC is fed over I2S: a tone, a notification, a
file. Between the codec and the speaker sits an **NS4150B**, a class-D
amplifier, because the codec's own output is line level and would barely
move the cone.

Two things about this path are decided by hardware and worth knowing before
the first beep. The amplifier is enabled from the C5, not the P4. And the
codec sounds right only at 48 kHz: at the 16 kHz that codec examples
default to, it is a voice codec with audible reconstruction images; at
48 kHz it is flat and clean, and also five times louder, which is why the
volume is capped.

## How it is connected

```mermaid
flowchart LR
  p4["ESP32-P4"] -- "I2S, GPIO38" --> codec["ES8311 DAC"]
  codec -- "line out" --> amp["NS4150B"] --> spk["Speaker, 8 Ω 1 W"]
  c5["ESP32-C5"] -. "PA_CTRL, IO4" .-> amp
```

*Samples over I2S, line level out of the codec, the C5 switches the amplifier on*

The P4 writes samples to the codec on `GPIO38`, clocked by `GPIO33`,
`GPIO34` and `GPIO37`, and configures volume and rate over I2C at `0x18`.
The amplifier's enable, `PA_CTRL`, is `IO4` on the ESP32-C5. Kode's C5
firmware raises it at boot; a C5 running anything else leaves the speaker
off no matter what the P4 does.

## Specifications

| Thing | Value |
| --- | --- |
| Codec | ES8311, mono, at `0x18` on the shared I2C bus. Driver: Espressif's `esp_codec_dev` |
| Amplifier | NS4150B class-D, enable `PA_CTRL` on C5 `IO4`. A codec driver that expects to own that pin is given `-1` |
| Speaker | 8 Ω, 1 W nominal, resonance about 1.3 kHz |
| Sample rate | **48 kHz, always.** Resample material that comes at less. At 16 kHz the codec's filter leaves a 15 kHz image at −3.8 dBc |
| Volume | Cap at about −7 dBFS. Full scale at 48 kHz is 1.9 Vrms out of the codec and the amplifier clips; the cap keeps it clean and keeps the speaker under 0.5 W |
| Kode driver | `kode_audio_init` then `kode_audio_tone(hz, ms)` in the `kode` component: one sine, blocking, 100–8000 Hz |
| Validated | `Kode-Dot-Val/05-AUDIO`: playback and the USB sound-card path on a board, and the gain measured on the bench, August 2026 |

## Gotchas

> **WARNING**
>
> **Everything returns `ESP_OK` and the room stays quiet.** The amplifier's
> enable line is a C5 pin, so the speaker needs firmware on the C5 that
> raises it. Nothing on the P4 side complains while it stays low: the codec
> initialises, the I2S stream runs, and there is no sound. Check what the C5
> is running before you read a line of the audio code.

> **WARNING**
>
> **It sounds harsh, or distorts when loud.** Either the codec is running at
> 16 kHz, which most examples default to, or the volume is above the cap. Set
> 48 kHz and keep the output below about −7 dBFS. Neither is fixable from the
> codec's registers; both are how the board is built.

## Apps that use it

On the marketplace, apps that put this part to work. Install one from
`start/first-app` and see it before you write a line.

- https://apps.kode.diy/app/7b60e571-9826-405f-8af5-3185899dfc74
- https://apps.kode.diy/app/b3c74f9b-6250-459b-835c-5e352546f535
- https://apps.kode.diy/app/de67c852-4d33-47fa-8ea6-9fd10d26fcd2
- https://apps.kode.diy/app/fa5d6a2b-5b29-4ba9-b380-af96b2a31bc0
- https://apps.kode.diy/app/6e2bfa27-4f6a-45ba-beb2-444fa6044044
- https://apps.kode.diy/app/e22664f5-9a5a-4c6f-8fd6-89ef68ab20a3
- https://apps.kode.diy/app/0c3389fc-16a6-4c31-bbf1-396227c34242
- https://apps.kode.diy/app/b20a29cd-7353-4bdb-86a0-6b844cf98e1a

## Example code

Play one note. You hear a short A above middle C, and the call returns
when the speaker is idle again.

```c
/*
 * speaker_tone.c - 2026-09-18 - from Kode with love
 *
 * Plays a 440 Hz tone for 300 ms out of the Kode Dot's speaker, then stops.
 * Brings the board up, opens the codec, and hands the tone to the Kode
 * driver, which fills the I2S stream and returns when it is done. You hear
 * one short beep, provided the C5 has switched the amplifier on.
 */
#include "kode.h"

/* Board, codec, one tone. */
void app_main(void)
{
    ESP_ERROR_CHECK(kode_bsp_init());
    ESP_ERROR_CHECK(kode_audio_init());
    ESP_ERROR_CHECK(kode_audio_tone(440, 300));
}
```

**TBD**: compiled against the `kode` component; a run on a V1 board.

## In the SDK

- [`kdrv_audio`](https://github.com/kodediy/kode-sdk/tree/main/components/kdrv/kdrv_audio): the ES8311 driver, `ktone` for tones and `kwav` for files, in `kode-sdk`.
