Todbot's Audio Tricks
In CircuitPython, there are three different techniques to output audio:
- DAC using
audioio
- PWM using
audiopwmio
- requires an external RC filter (at least) - I2S using
audiobusio
- requires external I2S decoder hardware
CircuitPython support on particular microcontroller may include support for several of these methods (e.g. SAMD51 supports DAC & I2S, just one (e.g. ESP32-S2 supports only I2S) or even none (e.g. Teensy).
Audio out using PWM
This uses the audiopwmio
library, only available for Raspberry Pi Pico (or other RP2040-based boards) and nRF52840-based boards like Adafruit Feather nRF52840 Express. On RP2040-based boards, any pin can be PWM Audio pin. See the audiopwomio Support Matrix for details.
import time,board from audiocore import WaveFile from audiopwmio import PWMAudioOut as AudioOut wave_file = open("laser2.wav", "rb") wave = WaveFile(wave_file) audio = AudioOut(board.TX) # must be PWM-capable pin while True: print("audio is playing:",audio.playing) if not audio.playing: audio.play(wave) wave.sample_rate = int(wave.sample_rate * 0.90) # play 10% slower each time time.sleep(0.1)
Note: Sometimes the audiopwmio
driver gets confused, particularly if there's other USB access, so you may have to reset the board to get PWM audio to work again.
Note: WAV file whould be "16-bit Unsigned PCM" format. Sample rate can be up to 44.1 kHz, and is parsed by audiocore.WaveFile
.
Note: PWM output must be filtered and converted to line-level to be usable. Use an RC circuit to accomplish this, see this twitter thread for details.
Audio out using a DAC
Some CircuitPython boards have one or more built-in Digital to Audio Converters (DACs). These are on specific pins. The code is the the same as above, with just the import line changing.
import time,random,board from audiocore import WaveFile from audioio import AudioOut as AudioOut # only DAC wave_file = open("laser20.wav", "rb") wave = WaveFile(wave_file) audio = AudioOut(board.A0) # must be DAC-capable pin, A0 on QTPy Haxpress while True: print("audio is playing:",audio.playing) if not audio.playing: audio.play(wave) wave.sample_rate = int(wave.sample_rate * 0.90) # play 10% slower each time time.sleep(0.1)
Preparing WAV files for CircuitPython
Convert files to appropriate WAV format (mono, 22050 Hz, 16-bit signed seem best). There are many software sound editing programs. Here are two solutions.
1) See the Adafruit guideĀ Microcontroller Compatible Audio File Conversion
2) Use the command line program sox.
sox loop.mp3 -b 16 -c 1 -r 22050 loop.wav
To get sox
on various platforms:
- Linux:
sudo apt install sox libsox-fmt-mp3
- macOS:
brew install sox
- Windows: Use installer at http://sox.sourceforge.net/
Page last edited March 08, 2024
Text editor powered by tinymce.