Dual-core audio engine for Raspberry Pi Pico (RP2040).
PicoSound delivers glitch-free audio for any RP2040 application by dedicating Core1 exclusively to audio processing. While your main program runs on Core0 (handling graphics, I/O, calculations, or game logic), Core1 manages the audio mixer and output independently.
This architecture eliminates audio dropouts caused by blocking operations like SPI transfers, flash writes, or heavy computations. Audio continues uninterrupted regardless of what Core0 is doing.
Supports both synthesized sounds (waveforms, melodies, effects) and streaming from WAV files. Suitable for any project requiring reliable audio output: synthesizers, musical instruments, notification systems, interactive installations, games or educational tools.
Works seamlessly with both Arduino IDE and PlatformIO. The library uses standard C++ structure (.h/.cpp files) ensuring compatibility across development environments.
Simple examples are provided and depending on the development environment (Arduino IDE or PlatformIO), they differ only in the place you can configure your sounds:
* Arduino IDE ----→ into your *.ino file
* PlatformIO ----→ inside a dedicated config.h file
- Non-blocking audio on Core1
- 8-channel mixer
- I2S (MAX98357A) or PWM output
- Synthesized sounds (sine, square, sawtooth, triangle, noise, explosion)
- Melody sequencer
- WAV streaming (LittleFS or PROGMEM)
- Frequency sweeps
- Arduino IDE and PlatformIO compatible
Core0: Program logic Core1: Audio engine
↓ ↓
SendAudioCommand() ----→ PicoSound.loop()
(via PicoSem) (mixer + output)
Audio runs independently. No blocking, no glitches.
| Resource | Used | Pi Pico | % |
|---|---|---|---|
| RAM | 4KB | 264KB | 1.5% |
| Flash | 20KB | 2MB | 1% |
| DMA channels | 1 | 12 | 8% |
| Cores | 1 | 2 | 50% |
- Audio latency: ~35µs
- WAV files: ~32 seconds/MB (e.g. 4 sounds of ~4" and 8 of ~2", for each MB)
Above values refer to a standard configuration: 16Khz - 16 bit/sample - Mono - 8 Channel Mixer
If you need more space for WAV sounds, use a Pi Pico with 16MB Flash avaliable on Amazon or AliExpress
To experiment different sample frequency:
Arduino IDE: edit PicoSound.h and change the value of PICOSOUND_DEFAULT_SAMPLE_RATE
PlatformIO: in your platformio.ini add -D PICOSOUND_DEFAULT_SAMPLE_RATE="your rate"
Download: Code → Download ZIP
Arduino IDE: Sketch → Include Library → Add .ZIP Library
// ========== CONFIGURATION (before includes) ==========
#define USER_SND_OUT OUT_I2S
#define USER_PIN_BCK 14
#define USER_PIN_WS 15
#define USER_PIN_DATA 16
typedef enum {
SND_NONE = 0,
SND_BEEP,
SND_LASER,
} SoundID;
// ========== INCLUDES ==========
#include <PicoSound_AudioCore.h>
#include <PicoSound_DualCore.h>
// ========== SOUND TABLE ==========
const SoundDefinition PICOSOUND_TABLE[] = {
{WAVE_NONE, 0, 0, 0, 0, 100, nullptr, 0, false, nullptr, false},
{WAVE_SQUARE, 440, 0, 100, 12000, 80, nullptr, 0, false, nullptr, false},
{WAVE_SQUARE, 1500, 200, 200, 12000, 70, nullptr, 0, false, nullptr, false},
};
// ============ YOUR PROGRAM ON CORE0 =============
void setup() {
// Your setup here
}
void loop() {
// ...
// Your computing logic, graphics, I/O, etc
// ...
SendAudioCommand(CMD_PLAY_SOUND, SND_BEEP, 80);
delay(1000); // Your program can be "blocking"
}
// ========== AUDIO ENGINE RUNS ON CORE1 ==========
void setup1() {
PicoSound_AudioCore_Setup1();
}
// ======= NON-BLOCKING LOOP TO PLAY AUDIO ========
void loop1() {
PicoSound_AudioCore_Loop1();
} See examples for complete code.
If you already have a platformio.ini into your project, just add:
lib_deps =
https://github.com/IWILZ/PicoSound.git
https://github.com/IWILZ/PicoSem.git
; Memory config to reserve space for WAVs on LittleFS
board_build.filesystem_size = 1m
board_build.filesystem = littlefsotherwise for a full example, see the README in the example/ folder.
The library provides three templates to help you better organize your work by dividing (where appropriate) the definition of your sounds into:
- picosound_user_cfg_template.h --> synthesized sounds and LittleFS files
- picosound_melodies_template.h --> melody definitions
- picosound_samples_template.h --> WAV samples stored in PROGMEM
You can simply use picosound_user_cfg_template.h to create the mandatory picosound_user_cfg.h file, including the other 2 inside it when the number of your sounds increases and you want a better organization for your work.
cp lib/PicoSound/src/templates/picosound_user_cfg_template.h include/picosound_user_cfg.hOr manually copy from lib/PicoSound/src/templates/ to your project's include/ folder.
Edit include/picosound_user_cfg.h:
// Set your hardware pins
#define USER_SND_OUT OUT_I2S
#define USER_PIN_BCK 14
#define USER_PIN_WS 15
#define USER_PIN_DATA 16
// Define your sounds
typedef enum {
SND_NONE = 0,
SND_BEEP,
SND_LASER,
SND_EXPLOSION,
SND_MAX // Always end with SND_MAX
} SoundID;
// Add sounds to table
inline const SoundDefinition PICOSOUND_TABLE[] = {
{WAVE_NONE, 0, 0, 0, 0, 100, nullptr, 0, false, nullptr, false},
{WAVE_SQUARE, 440, 0, 100, 12000, 80, nullptr, 0, false, nullptr, false},
// ... your sounds ...
};#include <Arduino.h>
#include <PicoSound_AudioCore.h>
#include <PicoSound_DualCore.h>
// ============ YOUR PROGRAM ON CORE0 =============
void setup() {
// Your setup here
}
void loop() {
// ...
// Your computing logic, graphics, I/O, etc
// ...
SendAudioCommand(CMD_PLAY_SOUND, SND_BEEP, 80);
delay(1000); // Your program can be "blocking"
}
// ========== AUDIO ENGINE RUNS ON CORE1 ==========
void setup1() {
PicoSound_AudioCore_Setup1();
}
// ======= NON-BLOCKING LOOP TO PLAY AUDIO ========
void loop1() {
PicoSound_AudioCore_Loop1();
}
Configuration is loaded automatically from your include/picosound_user_cfg.h.
pio run --target uploadHigh-level functions (recommended):
PlayTone(frequency, duration, volume);
PlayMelody(melody_array, length, waveform, volume);
SendAudioCommand(CMD_PLAY_SOUND, sound_id, volume);
StopAllSounds();
SetMasterVolume(volume);See docs/API.md for complete reference.
Pico GP14 → BCK
Pico GP15 → WS (LRCLK)
Pico GP16 → DIN
MAX98357A SD → 3.3V (or GPIO for mute control)
Pico GP17 → Speaker (+) via capacitor
GND → Speaker (-)
See docs/HARDWARE.md for detailed description.
| Approach | Best For | Config Location |
|---|---|---|
| Inline | Arduino IDE | In .ino file |
| Separate files | PlatformIO | include/picosound_user_cfg.h |
Advantages:
- ✅ Works perfectly in Arduino IDE
- ✅ Configuration per-project
- ✅ Survives library updates
- ✅ Self-documenting code
Disadvantages:
⚠️ Large sound tables in main file⚠️ Less modular for complex projects
Advantages:
- ✅ Cleaner code organization
- ✅ Reusable config across files
- ✅ Better for large projects
Disadvantages:
- ❌ Arduino IDE doesn't support this well
⚠️ PlatformIO/VSCode only
See example/ folder for both type of development environments.
- Raspberry Pi Pico (RP2040)
- Arduino-Pico core (Earle Philhower)
- PicoSem library
Special thanks to Earle Philhower for his great work!
GPL-3.0
IWILZ (2026)
