# CircuitPython Audio FX

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/132/982/medium800/circuitpython_PXL_20241009_180328273_2.jpg?1728497185)

I love the Adafruit Audio FX family of boards based on the VS1000 WAV/OGG decoder chip, but let's face it: they're getting a bit long in the tooth.

Inspired by the way the Audio FX made it easy to create interactive sound experiences, I created CircuitPython Audio FX.

Like the VS1000 Audio FX, sounds are triggered by pressing a button or closing a switch; the behavior is controlled by the name of the sound file, so you don't have to write any Python code.

Since the MP3 codec patents have all expired, CircuitPython Audio FX supports MP3 and WAV files, rather than OGG files.

CircuitPython Audio FX also supports polyphony: On the Raspberry Pi Pico 2 with RP2350 microcontroller, you can play 4 simultaneous low-bitrate MP3 files from the internal flash memory!

## Parts
Featured
### Raspberry Pi Pico 2 - RP2350

[Raspberry Pi Pico 2 - RP2350](https://www.adafruit.com/product/6006)
 **Raspberry Pi Pico 2** is Raspberry Pi Foundation's update to their popular RP2040-based Pico board,&nbsp;now built on **RP2350** : their new high-performance, secure microcontroller. With a higher core clock speed, double the on-chip SRAM (512KB), double the...

In Stock
[Buy Now](https://www.adafruit.com/product/6006)
[Related Guides to the Product](https://learn.adafruit.com/products/6006/guides)
![Angled shot of thin, green rectangular microcontroller with castellated pads.](https://cdn-shop.adafruit.com/640x480/6006-02.jpg)

Featured
### Adafruit Feather RP2350 with HSTX Port

[Adafruit Feather RP2350 with HSTX Port](https://www.adafruit.com/product/6000)
RP2350&nbsp;flies high with the&nbsp;Feather&nbsp;format - now you can use any FeatherWings with this battery-powered dev board. It comes with 8MB of flash, 22pin HSTX output port, Stemma QT, debug SWD, and optional PSRAM spot. It's our first RP2350 board and we crammed a ton of goodies...

In Stock
[Buy Now](https://www.adafruit.com/product/6000)
[Related Guides to the Product](https://learn.adafruit.com/products/6000/guides)
![Overhead shot of black, rectangular microcontroller with 22-pin FPC connector.](https://cdn-shop.adafruit.com/640x480/6000-07.jpg)

Featured
### Adafruit I2S Stereo Decoder - UDA1334A Breakout

[Adafruit I2S Stereo Decoder - UDA1334A Breakout](https://www.adafruit.com/product/3678)
This fully-featured UDA1334A I2S Stereo DAC breakout is a perfect match for any I2S-output audio interface. It's affordable but sounds great! The NXP UDA1334A is a jack-of-all-I2S-trades: you can use 3.3V - 5V logic levels (a rarity)&nbsp;and can process multiple different formats by...

In Stock
[Buy Now](https://www.adafruit.com/product/3678)
[Related Guides to the Product](https://learn.adafruit.com/products/3678/guides)
![Angled Shot of the Adafruit I2S Stereo Decoder - UDA1334A Breakout.](https://cdn-shop.adafruit.com/640x480/3678-05.jpg)

### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
![USB cable - USB A to Micro-B - 3 foot long](https://cdn-shop.adafruit.com/640x480/592-01.jpg)

### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

# CircuitPython Audio FX

## Coding CircuitPython Audio FX

Click on the **Download Project Bundle** button in the window below. It will download to your computer as a zipped folder.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/circuitpython-audio-fx/polyphonic/code.py

## Upload the Code, Sound Effects and Libraries to the Raspberry Pi Pico 2

After downloading the Project Bundle, plug your Pico 2 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called **CIRCUITPY**. Open up the zipped file, go to the the appropriate folder inside (e.g., **circuitpython-audio-fx/polyphonic/CircuitPython 9.x** if you are using CircuitPython 9.x) and copy the items in that folder directly onto your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should look like this after copying the sound effects and the **code.py** file.

![Folder](https://adafruit.github.io/Adafruit_Learning_System_Guides/circuitpython-audio-fx_polyphonic.png )

# CircuitPython Audio FX

## Using CircuitPython Audio FX

### Project Wiring

Connect your Pico 2 board to an I2S DAC or I2S Amplifier using the following pins:

- Connect Pico GP16 to I2S Bit Clock (BCLK)
- Connect Pico GP17 to I2S Word Select (WSEL)
- Connect Pico GP18 to I2S Data (DAT)
- Connect Pico GND to GND
- Connect your I2S board to appropriate power & speakers or headphones

![](https://cdn-learn.adafruit.com/assets/assets/000/132/963/medium800/circuitpython-audio-fx_bb.png?1728490029)

Next, connect at least one but up to 16 trigger buttons or switches. All of the pins from GP0 to GP15 are for audio triggers. For each button or switch:

- Connect one side of the switch to one of the GPx pins
- Connect the other side of the switch to GND

The sample project includes sound files for 12 different triggers on pins GP0 through GP11. The diagram only shows a few buttons, but any or all of the first 16 GPIO pins GP0 through GP15 can be used.

## Preparing Audio Files

You can use the software of your choice to prepare audio files for CircuitPython Audio FX. If you don't already have software for recording & saving sound samples, you might want to try the open source [Audacity](https://github.com/audacity/audacity), which runs on Linux, Mac and Windows.

For a given project, all the audio files have to have the same key specifications:

- sample rate (e.g., 8kHz, 11.025kHz, 16kHz)
- number of samples (mono or stereo)
- bit depth (8-bit unsigned or 16-bit signed)

While WAV files are supported, the Pico 2's **CIRCUITPY** drive has a capacity of only about 3 megabytes, so you will probably want to load up with compressed MP3 files instead.

The amount of audio you can load in MP3 format depends on the bit rate. For 128 kbit/second "CD quality" MP3 files (44.1kHz, stereo, 16-bit), you can store about a total of 3 minutes of audio. If you go for a lower quality file such as 32kbit/second (16kHz, mono, 16-bit) you can have over 10 minutes of sound files.

The MP3 **bitrate** is separate from the **sample** rate. A higher **bitrate** means the file takes up more kB per second of audio, but the audio fidelity improves with a higher bitrate. Within a project, MP3 files can have different&nbsp; **bitrates**. For example, your project can include a file with a 16kHz sample rate encoded at 32kbit/s bitrate alongside a file with a 16kHz sample rate and a 64kbit/s bitrate.

A project can mix MP3 files and WAV files but the channel count and sample rate must be the same, and the wave files must be 16-bit signed files.

The included sample files are all 16kHz mono 16-bit MP3s encoded at 32 kbit/s.

### Naming audio files

The name of your audio file controls when and how it will be played.

The name of an audio file is divided into several parts:

- The trigger number, **T00** through **T15**
- The kind of trigger:
  - Empty, for a basic trigger (starts playing once when its trigger is pressed)
  - **HOLDL** for a hold looping trigger (plays in a loop while trigger is pressed)
  - **LATCH** for a toggle looping trigger (starts playing in a loop when trigger is pressed, stops next time trigger is pressed)
  - **NEXT#** for a sequential trigger (plays **NEXT0** , then **NEXT1** , up to **NEXT9** , then back to **NEXT0** &nbsp;each time its trigger is pressed)
  - **RAND#** for random trigger (randomly chooses among **RAND0** , **RAND1** up to **RAND9** , each time its trigger is pressed)

- The file extension, **.WAV** or **.MP3**

Filenames are not case dependent, so you can have **T00RAND9.MP3** or&nbsp; **T00rand9.Mp3** and it will work the same way.

If several kinds of trigger all appear for the same trigger number, only one of them will be used. For example if you have both **T15HOLDL.mp3** and **T15.mp3** (two different trigger types for one trigger number), one or the other will be used, but not both. Similarly, if you have both&nbsp; **T14.mp3** and **T14.wav** , one or the other will be used, but not both (two different file extensions for the same file).

The demonstration files show all the different kinds of triggers, including:

- T00.mp3: A basic trigger on pin GP0
- T01RAND0.mp3 through T01RAND4.mp3: A random trigger on pin GP1
- T04HOLDL.mp3: A hold looping trigger on pin GP4
- T05NEXT0.mp3 through T05NEXT2.mp3: A sequential trigger on pin GP5
- T06LATCH.mp3: A latching looping trigger on pin GP6

### Polyphony & Precedence

In&nbsp; **code.py** there is a configurable number for the maximum&nbsp; **polyphony** , or the maximum number of different sound files that can be played simultaneously. There's a second limit for the number of simultaneous&nbsp; **mp3** files that can be played, because each "MP3 Decoder" object requires a substantial amount of RAM.

When a new sound file is triggered, but the maximum number are already playing, here's what happens: Of the currently playing sounds&nbsp; **the one with the highest trigger number** is stopped, and then the new sound is started.

So imagine that you have polyphony of 2 (the default), and sounds T05 and T06 are playing. When you trigger another channel, whether it's T02 or T15, then the T06 sound is stopped and the new sound file is started.

### Audio file maximums

The maximum audio files that can be played depend on

- format: wav vs mp3
- bit rate & sample rate
- audio volume & clipping when mixing many samples

As a guideline a non-overclocked RP2350 can successfully play 2 320kbit/s MP3 files or 8 32kbit/s MP3 files from internal flash. With overclocking, you can go further.

There's room in the RP2350 RAM for up to 9 MP3 decoder objects, but this has to be reduced somewhat to allow for a complex **code.py** program. The soft maximum of 4 in the **code.py** is probably a bit too restrictive.

# CircuitPython Audio FX

## Code Walkthrough

There's a fair amount of code in this project! Let's look at the highlights.

You can reconfigure the pins used for triggers by updating this block. The number of triggers can be fewer or more than the 16 shown here.

```python
# Configure the pins to use -- earlier in list = higher priority
pads = [
    board.GP0, board.GP1, board.GP2, board.GP3,
    board.GP4, board.GP5, board.GP6, board.GP7,
    board.GP8, board.GP9, board.GP10, board.GP11,
    board.GP12, board.GP13, board.GP14, board.GP15
]
```

You can select a greater number of simultaneous voices (polyphony). Further down there's an additional limit of at most 4 simultaneous MP3s.

```python
# Configure max voices to play at once
# (No matter what, at most 4 MP3 decoders)
# If set this number too high, playback will stutter. use lower bit rates or fewer voices
#   
# when the number of active samples being played back exceeds the number of voices,
# the top numbered playing sample is stopped. There is no logic to restore a sample that
# got stopped in this way.
#
# (this may not be the same as the old FX board logic)
max_simultaneous_voices = 2
```

You can create an I2SOut on different pins, or change to a different kind of audio output altogether (such as `PWMAudioOut`)

```python
audiodev = audiobusio.I2SOut(
    bit_clock=board.GP16, word_select=board.GP17, data=board.GP18
)
```

Each kind of trigger derives from TriggerBase and defines several items:

- The filename fragments associated with this kind of trigger. This is the part of the filename immediately after the **T##** trigger number. It should be a list with at least one string in it. The kind of trigger is chosen based on matching the first stem in the list, so each trigger needs to have a unique stem compared to all the others.
- The action to take when the associated trigger is pressed
- The action to take when the associated trigger is released

Usually one trigger will call **self.play**. If the play is looping, then the other trigger will probably call&nbsp; **self.force\_off**.

If no action is called for in a press or release, provide a method that just says "pass".

Each kind of trigger also needs to be added to the list of **trigger\_classes**.

The basic stem doesn't loop, so it only needs to do something on press:

```auto
class BasicTrigger(TriggerBase):
    """Plays a file each time the button is pressed down"""

    stems = [""]

    def on_press(self):
        self.play(self.filenames[0])

    def on_release(self):
        pass
```

The HoldLoopingTrigger demonstrates that samples can be looped and shows use of **force\_off** in the **on\_release** method:

```auto
class HoldLoopingTrigger(TriggerBase):
    """Plays a file as long as a button is held down"""

    stems = ["HOLDL"]
        
    def on_press(self):
        self.play(self.filenames[0], loop=True)
        
    def on_release(self):
        self.force_off()
```

The **PlayRandomTrigger** class shows how to select one out of a list of different files. Notice how **stems** will be a list of the strings&nbsp; **RAND0** ,&nbsp; **RAND1** , ...,&nbsp; **RAND9**.&nbsp;It uses&nbsp; **random\_choice** , a function that works similar to standard Python's **random.choice** function:

```auto
class PlayRandomTrigger(TriggerBase):
    stems = [f"RAND{i}" for i in range(10)]

    def on_press(self):
        self.play(random_choice(self.filenames))

    def on_release(self):
        pass
```

In the TriggerBase class, the play function starts playing the new sample, after stopping another channel from playing if necessary (inside&nbsp; **ensure\_available\_voice** ; similarly, an MP3 channel is freed if necessary by&nbsp; **ensure\_available\_decoder** ):

```auto
class TriggerBase:
    ...
    def get_sample(self, path):
        if path.endswith(".mp3"):
            self._decoder = ensure_available_decoder()
            self._decoder.open(path)
            return self._decoder
        else:
            return audiocore.WaveFile(path)
    
    def play(self, path, loop=False):
        self.force_off()
        free_stopped_channels()
        sample = self.get_sample(path)
        self.voice = ensure_available_voice()
        self.voice.play(sample, loop=loop)
```

The main loop just checks for key events and calls **on\_press** / **on\_release** as needed (it also spews some debugging information to the serial console):

```auto
while True:
    if e := keys.events.get():
        print("event", e)
        print("available decoders", *(id(i) for i in available_decoders))
        print("available voices", *(id(i) for i in available_voices))
        trigger = triggers[e.key_number]
        if e.pressed:
            trigger.on_press()
        else:
            trigger.on_release()
        print(triggers)
```

# CircuitPython Audio FX

## CircuitPython Audio FX Monophonic

Polyphonic Audio FX is pretty cool, but suppose you have an existing project for the original Audio FX and you want to "port" it to a newer board using CircuitPython instead of VS1000. We got you! Load up your CircuitPython with the monophonic version of the script and you'll get behavior a lot closer to the VS1000-based Audio FX boards. (not working quite right? Please drop us some feedback using the link in the sidebar!)

Wiring is the same as shown under [Using CircuitPython Audio FX](https://learn.adafruit.com/circuitpython-audio-fx/using-circuitpython-audio-fx#using-circuitpython-audio-fx).

## Convert your OGG files to MP3 and save to CIRCUITPY

Using software of your choice, such as the free and open source [Audacity](https://github.com/audacity/audacity) which is available on Linux, Windows & Mac computers. Open each file and then export it as an MP3 file. Keep the first part of the filename (e.g., T01RAND0 or T11LATCH) but choose the right file extension (.mp3)

The RP2350 has approximately 3MB of flash available for the CIRCUITPY drive, so if you were using a VS1000 with a larger capacity you will have to choose a higher compression ratio (lower bit rate) when performing the conversion.

If you still have original wave files with a .WAV extension, it's better to use these files for MP3 conversion, because the WAV file is lossless. Doing repeated lossy audio conversions can reduce the quality of the final audio file, the audio version of those weird crinkly edges and smudgy indistinct areas that JPEG files can get.

Unlike the polyphonic version, your files can have different sample rates, you can mix mono & stereo, etc. For more information about naming and converting files see the headings "Preparing Audio Files" and "Naming Audio Files" under [Using CircuitPython Audio FX](https://learn.adafruit.com/circuitpython-audio-fx/using-circuitpython-audio-fx#using-circuitpython-audio-fx). For information about how each trigger type works, read about it in the [original Audio FX guide](https://learn.adafruit.com/adafruit-audio-fx-sound-board/triggering-audio#trigger-types-and-filenames-2914623).

## Coding CircuitPython Audio FX

Click on the **Download Project Bundle** button in the window below. It will download to your computer as a zipped folder.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/circuitpython-audio-fx/monophonic/code.py

## Upload the Code, Sound Effects and Libraries to the Raspberry Pi Pico 2

After downloading the Project Bundle, plug your Pico 2 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called **CIRCUITPY**. Open up the zipped file, go to the the appropriate folder inside (e.g., **circuitpython-audio-fx/polyphonic/CircuitPython 9.x** if you are using CircuitPython 9.x) and copy the items in that folder directly onto your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should look like this after copying the sound effects and the **code.py** file.

![Folder](https://adafruit.github.io/Adafruit_Learning_System_Guides/circuitpython-audio-fx_polyphonic.png )

At this point, CircuitPython will automatically restart and run the Audio FX code. If you activate the digital inputs (for instance, by pressing a connected button) a sound effect will play. If you run into trouble, you can use the CircuitPython serial connection, sometimes call the REPL, to troubleshoot.


## Guide Products

### Raspberry Pi Pico 2 - RP2350

[Raspberry Pi Pico 2 - RP2350](https://www.adafruit.com/product/6006)
 **Raspberry Pi Pico 2** is Raspberry Pi Foundation's update to their popular RP2040-based Pico board,&nbsp;now built on **RP2350** : their new high-performance, secure microcontroller. With a higher core clock speed, double the on-chip SRAM (512KB), double the...

In Stock
[Buy Now](https://www.adafruit.com/product/6006)
[Related Guides to the Product](https://learn.adafruit.com/products/6006/guides)
### Adafruit Feather RP2350 with HSTX Port

[Adafruit Feather RP2350 with HSTX Port](https://www.adafruit.com/product/6000)
RP2350&nbsp;flies high with the&nbsp;Feather&nbsp;format - now you can use any FeatherWings with this battery-powered dev board. It comes with 8MB of flash, 22pin HSTX output port, Stemma QT, debug SWD, and optional PSRAM spot. It's our first RP2350 board and we crammed a ton of goodies...

In Stock
[Buy Now](https://www.adafruit.com/product/6000)
[Related Guides to the Product](https://learn.adafruit.com/products/6000/guides)
### Adafruit I2S Stereo Decoder - UDA1334A Breakout

[Adafruit I2S Stereo Decoder - UDA1334A Breakout](https://www.adafruit.com/product/3678)
This fully-featured UDA1334A I2S Stereo DAC breakout is a perfect match for any I2S-output audio interface. It's affordable but sounds great! The NXP UDA1334A is a jack-of-all-I2S-trades: you can use 3.3V - 5V logic levels (a rarity)&nbsp;and can process multiple different formats by...

In Stock
[Buy Now](https://www.adafruit.com/product/3678)
[Related Guides to the Product](https://learn.adafruit.com/products/3678/guides)
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)

## Related Guides

- [Adafruit Feather RP2350 with HSTX](https://learn.adafruit.com/adafruit-feather-rp2350.md)
- [LED Matrix FIFA World Cup Scoreboard](https://learn.adafruit.com/led-matrix-fifa-world-cup-scoreboard.md)
- [CircuitScheme - Lisp on CircuitPython](https://learn.adafruit.com/scheme-in-circuitpython.md)
- [Expressive Pixels for Adafruit Matrix Portal](https://learn.adafruit.com/expressive-pixels-for-matrix-portal.md)
- [I2S Microphones with CircuitPython](https://learn.adafruit.com/i2s-microphones-with-circuitpython.md)
- [Clue Coffee Scale](https://learn.adafruit.com/clue-coffee-scale.md)
- [Lucky Cat with Circuit Playground Express](https://learn.adafruit.com/lucky-cat-with-circuit-playground-express.md)
- [Controlling a Classic Nintendo R.O.B. Robot Using Circuit Playground Express](https://learn.adafruit.com/controlling-a-classic-nintendo-r-o-b-robot-using-circuit-playground-express.md)
- [1D Chomper Tabletop Arcade Game](https://learn.adafruit.com/1d-chomper-tabletop-arcade-game.md)
- [Matrix Portal New Guide Scroller](https://learn.adafruit.com/matrix-portal-new-guide-scroller.md)
- [Trash-Built Robotic Fish](https://learn.adafruit.com/trash-robo-fish.md)
- [Adafruit QT Py Activity Timer and Hydration Reminder](https://learn.adafruit.com/qt-py-activity-timer-and-hydration-reminder.md)
- [xLights for Sparkle Motion Board](https://learn.adafruit.com/xlights-for-sparkle-motion-board.md)
- [Bluetooth Cycling Speed & Cadence Sensor Display with Clue](https://learn.adafruit.com/bluetooth-bicycle-speed-cadence-sensor-display-with-clue.md)
- [Upgrading AirLift ESP32 Firmware](https://learn.adafruit.com/upgrading-esp32-firmware.md)
- [Chatty Light-Up Circuit Playground Express Mask](https://learn.adafruit.com/chatty-light-up-cpx-mask.md)
