Skip to content

Audio System

The WolfEngine audio system provides a lightweight, non-blocking sound playback system designed for ESP32.
It is built around simple {frequency, duration} sound clips and uses ESP-IDF’s LEDC hardware PWM for tone generation.

This system supports: - 🎵 Music playback (loopable) - 🔔 Sound effects (with optional callbacks) - ⏱ Non-blocking timing - 🔁 Looping tracks - 🧠 Minimal memory usage


Overview

Audio playback is handled by the SoundManager class and uses two independent channels:

Channel Purpose
Channel 0 Music
Channel 1 Sound Effects

Each channel plays an array of SoundClip.


SoundClip Format

struct SoundClip {
    uint16_t frequency;
    uint16_t duration;
};
Field Description
frequency Note frequency in Hz (0 = silence)
duration Duration in milliseconds

Sounds are terminated using a {0, 0} clip.

Example:

const SoundClip beep[] = {
    { 440, 100 },
    {   0,  50 },
    { 880, 100 },
    {   0,   0 } // terminator
};

SoundManager API

Playback

void playMusic(const SoundClip* sound, bool loop = false);
void playSFX(const SoundClip* sound, void (*onFinish)() = nullptr);
Function Description
playMusic Starts playing a sound as music
loop Restarts when finished
playSFX Plays a one-shot sound effect
onFinish Optional callback when SFX ends

How Playback Works

Internally: - Uses esp_timer_get_time() for millisecond timing - Plays one SoundClip at a time - Automatically advances through the array - Uses {0,0} as end marker - Looping restarts index to 0


Control

You can call these functions to control the flow of music.

void stopMusic();
void stopSFX();
void stopAll();

Wiring

Pins are configured in WE_Settings.hpp:

Settings.hardware.sound.music = 14
Settings.hardware.sound.sfx   = 32

See:
Pin Definitions


Note System (Note_t)

WolfEngine provides a predefined musical note table in WE_Notes.hpp:

enum Note_t : uint16_t {
    REST = 0,
    C4 = 262,
    D4 = 294,
    E4 = 330,
    F4 = 349,
    G4 = 392,
    A4 = 440,
    B4 = 494,
    // ...
};

This allows writing melodies in a musical form:

const SoundClip melody[] = {
    { C4, 200 },
    { D4, 200 },
    { E4, 200 },
    { REST, 100 },
    { G4, 400 },
    { 0, 0 }
};

State Queries

bool isMusicPlaying() const;
bool isSFXPlaying() const;
bool isAnyPlaying() const;
bool isPlaying(const SoundClip* sound) const;

Limitations

  • Square wave only (no PCM audio)
  • Single tone per channel
  • No volume control (yet)
  • No polyphony
  • No ADSR or envelopes