# MP3 Playback with CircuitPython

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/131/100/medium800/circuitpython_Screenshot_2024-01-22_111822.png?1720452517)

Compressed audio can be a nice alternative to uncompressed WAV files, especially when you have a small filesystem like that on many CircuitPython boards, as WAV files get sizeable quite quickly.

MP3 technology dates to the 1990s and [all the patents have long since expired worldwide](https://en.wikipedia.org/wiki/MP3#Licensing_and_patent_issues), making it an obvious choice for compressed audio. For this reason, many builds of CircuitPython include the `audiomp3` module with its `MP3Decoder` object.

You can listen to a much longer playlist with CircuitPython, using the built in MP3 playback capability!

The MP3 decoder itself supports a wide range of formats, including CBR, ABR and VBR. Across most boards that support MP3Decoder, we've found that **mono and stereo** files from **32kbit** /s to **128kbit** /s work, with sample rates from **16kHz** to **44.1kHz**.

More powerful boards can even **decode and mix two MP3s** and some Espressif boards can **stream MP3s from a web server**.

## MP3 playback projects

Want some ideas about what you can do with MP3 playback? Here are a few of the MP3 projects which are documented on the Adafruit Learning System:

[PyGamer MP3 Player with CircuitPython](https://learn.adafruit.com/pygamer-mp3-player-with-circuitpython)

![circuitpython_projects_IMG_20200518_100307.jpg](https://cdn-learn.adafruit.com/assets/assets/000/131/078/medium640/circuitpython_projects_IMG_20200518_100307.jpg?1720042572)

[MP3 Playback in CircuitPython with Lars the Sloth Puppet](https://learn.adafruit.com/mp3-circuitpython-lars)

![circuitpython_projects_lars-2400.jpg](https://cdn-learn.adafruit.com/assets/assets/000/131/079/medium640/circuitpython_projects_lars-2400.jpg?1720042683)

[PyPortal Winamp MP3 Player](https://learn.adafruit.com/pyportal-winamp-mp3-player)

![circuitpython_base_photo.png](https://cdn-learn.adafruit.com/assets/assets/000/131/080/medium640/circuitpython_base_photo.png?1720042731)

## Parts for the MP3 Streaming Example
### Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM

[Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM](https://www.adafruit.com/product/5500)
What's Metro-shaped and has an ESP32-S3&nbsp;WiFi module? What has a STEMMA QT connector for I2C devices and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - it's the new...

In Stock
[Buy Now](https://www.adafruit.com/product/5500)
[Related Guides to the Product](https://learn.adafruit.com/products/5500/guides)
![Angled shot of black, credit-card-sized dev board.](https://cdn-shop.adafruit.com/640x480/5500-10.jpg)

### Adafruit Metro ESP32-S2

[Adafruit Metro ESP32-S2](https://www.adafruit.com/product/4775)
What's Metro shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices, and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - its the new Adafruit Metro...

In Stock
[Buy Now](https://www.adafruit.com/product/4775)
[Related Guides to the Product](https://learn.adafruit.com/products/4775/guides)
![Angled shot of Adafruit Metro esp32-s2 ](https://cdn-shop.adafruit.com/640x480/4775-06.jpg)

### Adafruit ESP32 Feather V2 w.FL Antenna -  8MB Flash + 2 MB PSRAM

[Adafruit ESP32 Feather V2 w.FL Antenna -  8MB Flash + 2 MB PSRAM](https://www.adafruit.com/product/5438)
One of our star Feathers is the [Adafruit HUZZAH32 ESP32 Feather](https://www.adafruit.com/product/3405) - with the fabulous ESP32 WROOM module on there, it makes quick work of WiFi and Bluetooth® projects that take advantage of Espressifs most popular chipset. Recently we had...

In Stock
[Buy Now](https://www.adafruit.com/product/5438)
[Related Guides to the Product](https://learn.adafruit.com/products/5438/guides)
![Angled shot of rectangular microcontroller.](https://cdn-shop.adafruit.com/640x480/5438-10.jpg)

### Part: I2S Decoder
quantity: 1
PCM5102A I2S AUX Stereo Digital Audio DAC Decoder Board
[I2S Decoder](https://www.amazon.com/dp/B09C5QX228)

# MP3 Playback with CircuitPython

## MP3 Capabilities by Microcontroller

First, check if your board has the audiomp3 module [available for import](https://docs.circuitpython.org/en/latest/shared-bindings/audiomp3/index.html). Then, scan below for the general level of support for that microcontroller family.

### SAMD51 (Metro M4 & Others)

- Play one 128kbit/s file
- Mix two 64kbit/s files
- Plays from the onboard CIRCUITPY drive or SD card with sdcardio
- Streaming not available

### nRF52840 (Circuit Playground Bluefruit & Others)

- Play one 128kbit/s file
- Mix two 64kbit/s files
- Plays from CIRCUITPY or SD card with sdcardio
- Streaming not available

### RP2040 (e.g., Feather RP2040)

- Play one 128kbit/s file
- Mixing streams: not tested
- Plays from CIRCUITPY or SD card with sdcardio
- Streaming on Pico W: not tested

### Espressif ESP32-S3 w/PSRAM (e.g., Metro ESP32-S3)

- Plays one 128kbit/s file
- Mix two 64kbit/s files
- Play from CIRCUITPY or SD card with sdcardio
- Play streams from compatible http & https services using built-in WiFi

### Espressif ESP32-S2 w/PSRAM (e.g., Metro ESP32-S2)

- Play one 128kbit/s stream
- Mixing streams: not tested
- SD cards: not tested
- Play streams from compatible http & https services using built-in WiFi

### Espressif ESP32 w/PSRAM (e.g., Feather ESP32 V2)

- Play one 128kbit/s stream
- Mixing streams: not tested
- SD cards: not tested
- Play streams from compatible http & https services using built-in WiFi

# MP3 Playback with CircuitPython

## MP3 Decoding Tips

Today's microcontrollers are pretty powerful, but without careful coding, you're likely to have glitches in your MP3 playback. Here are some tips for projects that use MP3Decoder in CircuitPython.

## Construct your audio playback object

Depending on your board, this might be:

- [audioio for real DAC based audio conversion inside the microcontroller](https://learn.adafruit.com/circuitpython-essentials/circuitpython-audio-out)
- [audiopwmio for PWM-based audio. Lower fidelity but it gets the job done](https://github.com/todbot/circuitpython-tricks#audio-out-using-pwm)
- [audiobusio for I2S-based audio, the digital audio standard](https://learn.adafruit.com/i2s-amplifier-bff/circuitpython)

## Construct MP3Decoder objects just once

MP3 decoding takes a lot of RAM. To reduce RAM fragmentation, create your&nbsp;`MP3Decoder` object or objects near the start of your program. In order to change the MP3 file that your decoder object plays, use the `open()` method or assign the `file` property.

When creating an MP3Decoder object, you must always specify an MP3 file. This can even be a silent MP3 file that just has a valid MP3 header. This file is used to set the initial properties of the audio stream such as bit rate and channel count.

```python
import audiomp3

mp3_decoder = audiomp3.MP3Decoder("/silence.mp3")
```

## Using a buffer for MP3 streams

Optionally, you can specify a buffer when creating an `MP3Decoder`. This is usually not necessary when playing a stream from the CIRCUITPY drive or SD card, but it can reduce stuttering when playing from a network stream. This buffer is used to store two frames of decoded data (9216 bytes) and not-yet-decoded MP3 data (the remainder).

For a 128kbit/s stream, a total buffer size of 16384 bytes (16KiB) can buffer about 1/2 second of encoded MP3 data. This is a good value to start with.

```python
import audiomp3

mp3_buffer = bytearray(16384)
mp3_decoder = audiomp3.MP3Decoder("/silence.mp3", mp3_buffer)
```

## Tune AudioMixer buffers for MP3 mixing

MP3 data is generally organized in frames of 1152 samples. For stereo 16-bit audio, this means 1 frame is 4\*1152=4608 bytes. The best performance is obtained when the AudioMixer buffer size is a small multiple of the MP3 frame size:

```python
import audiomixer

mixer_buffer_size = (1152 * 4) * 4
mixer = audiomixer.Mixer(
    channel_count=2,
    sample_rate=44100,
    buffer_size=mixer_buffer_size
)
```

## adafruit\_requests settings for MP3 streaming

For MP3 streaming you must make your request with the&nbsp; **Connection: close** header, specify the `stream=True` positional argument, and use the&nbsp;`socket` property of the returned request object. You must also employ the `with ...:` syntax to properly manage the socket resource:

```python
with requests.get("http://ice2.somafm.com/dronezone-128-mp3", headers={"connection": "close", stream=True) as response:
    mp3decoder.file = response
    speaker.play(mp3decoder)
    while speaker.playing:
        time.sleep(.1)
```

It's possible to use this pair of functions to treat local files and remote streams consistently with one another, and do all resource management correctly:

```python
def get_mp3_stream(location):
    if location.startswith("http:") or location.startswith("https:"):
        return requests.get(
            location,
            headers={"connection": "close"},
            stream=True,
        )
    return open(location, "rb")
  
def set_stream(decoder, obj):
    decoder.file = getattr(obj, 'socket', obj)
    
with get_mp3_stream("http://ice2.somafm.com/dronezone-128-mp3") as request:
    set_stream(decoder, request)
```

## Don't call `open()` or assign `file` while an mp3 is playing

This isn't allowed, but due to technical limitations CircuitPython can't currently raise an exception in this case.

## Don't use&nbsp;`play(loop=True)` with a stream

Looping is allowed for files, but not streams. Due to technical limitations CircuitPython can't currently raise an exception in this case.

## Avoid allocating memory during playback

Operations such as creating lists, tuples and dicts allocate memory. Any time memory is allocated, there's a possibility that garbage collection will be required. Garbage collection pauses not only the execution of the CircuitPython code, but also stops the background process that allows more audio data to be generated. Especially on microcontrollers with PSRAM, the length of time taken by garbage collection can be longer than the audio buffer size, leading to gaps or stutters in audio playback.

## Schedule when you update your display

Set your display to manual refresh and call refresh when needed. When a background display update is in progress, the background process that allows more audio data to be generated cannot occur, because only one background task can occur at a time.

Design your user interface so that only a small part of the display updates during playback.

## Use sdcardio or sdioio to access MP3 files on SD cards

`adafruit_sdcard` is not as reliable or fast to access SD cards.

# MP3 Playback with CircuitPython

## MP3 Streaming Example

![](https://cdn-learn.adafruit.com/assets/assets/000/131/082/medium800/circuitpython_feather-i2s_bb.png?1720045973)

Info: The diagram above shows Adafruit's UDA1334 I2S DAC. Your I2S DAC may have different connection names.

Here is a full MP3 streaming example that works on the following boards:

- Adafruit Metro ESP32-S3
- Adafruit Metro ESP32-S2
- Feather ESP32 V2

For this example, [configure your device settings.toml file to automatically connect to WiFi](https://learn.adafruit.com/mp3-playback-with-circuitpython/create-your-settings-toml-file).

Make the connections to the I2S headphone adapter as shown, and plug in headphones.

- BAT to VIN
- GND to GND
- I2S DATA or DIN to D11 or D27 (depending on which CircuitPython board you are using)
- I2S WORD\_SELECT, WSEL, or SCK to D12
- I2S BIT\_CLOCK, BCLK, or BCK to D13

Espressif boards can use any combination of pins for I2S, but if you're adapting this to a different microcontroller, there may be specific pin requirements. Update your **code.py** and wiring accordingly.

Once you have uploaded the example, CircuitPython will restart and stream an MP3 from the streaming site [somafm](https://somafm.com/)'s "[Drone Zone](https://somafm.com/dronezone/)" channel.

Update the `STREAMING_URL` in your **code.py** to change streams. The challenge can be to find the correct MP3 streaming URL.

On somafm, you can find alternate URLs by going to the channel page, looking for the "Non-SSL MP3" line, and selecting the "128k" link. This will download a "[pls](https://en.wikipedia.org/wiki/PLS_(file_format))" (playlist) file to your computer, which is a plain-text file that contains the actual link to the stream. (You can also use the SSL MP3 links on most microcontrollers, but there's little reason to, and it might not work as reliably).

Another source of MP3s is podcasts. You can find MP3 URLs within some podcast "rss feed" documents, such as the [CircuitPython Weekly Discord meeting RSS feed](https://adafruit-podcasts.s3.amazonaws.com/circuitpython_weekly_meeting/audio-podcast.xml).

Different services have different ways to find the streaming URL which are sometimes very obfuscated and are changed by site operators with little or no notice.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_MP3StreamPlayer/code.py

# MP3 Playback with CircuitPython

## Create Your settings.toml File

CircuitPython works with WiFi-capable boards to enable you to make projects that have network connectivity. This means working with various passwords and API keys. As of [CircuitPython 8](https://circuitpython.org/downloads), there is support for a **settings.toml** file. This is a file that is stored on your **CIRCUITPY** drive, that contains all of your secret network information, such as your SSID, SSID password and any API keys for IoT services. It is designed to separate your sensitive information from your **code.py** file so you are able to share your code without sharing your credentials.

CircuitPython previously used a **secrets.py** file for this purpose. The **settings.toml** file is quite similar.

Warning: Your **settings.toml** file should be stored in the main directory of your **CIRCUITPY** drive. It should not be in a folder.

## CircuitPython **settings.toml** File

This section will provide a couple of examples of what your **settings.toml** file should look like, specifically for CircuitPython WiFi projects in general.

The most minimal **settings.toml** file must contain your WiFi SSID and password, as that is the minimum required to connect to WiFi. Copy this example, paste it into your **settings.toml** , and update:

- `your_wifi_ssid`
- `your_wifi_password`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
```

Many CircuitPython network-connected projects on the Adafruit Learn System involve using Adafruit IO. For these projects, you must _also_ include your Adafruit IO username and key. Copy the following example, paste it into your settings.toml file, and update:

- `your_wifi_ssid`
- `your_wifi_password`
- `your_aio_username`
- `your_aio_key`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
ADAFRUIT_AIO_USERNAME = "your_aio_username"
ADAFRUIT_AIO_KEY = "your_aio_key"
```

Some projects use different variable names for the entries in the **settings.toml** file. For example, a project might use `ADAFRUIT_AIO_ID` in the place of `ADAFRUIT_AIO_USERNAME`. **If you run into connectivity issues, one of the first things to check is that the names in the settings.toml file match the names in the code.**

Warning: Not every project uses the same variable name for each entry in the **settings.toml** file! Always verify it matches the code.

## **settings.toml** File Tips
Here is an example **settings.toml** file.

```auto
# Comments are supported
CIRCUITPY_WIFI_SSID = "guest wifi"
CIRCUITPY_WIFI_PASSWORD = "guessable"
CIRCUITPY_WEB_API_PORT = 80
CIRCUITPY_WEB_API_PASSWORD = "passw0rd"
test_variable = "this is a test"
thumbs_up = "\U0001f44d"
```

In a **settings.toml** file, it's important to keep these factors in mind:

- Strings are wrapped in double quotes; ex: `"your-string-here"`
- Integers are _ **not** _ quoted and may be written in decimal with optional sign (`+1`, `-1`, `1000`) or hexadecimal (`0xabcd`).
  - Floats (decimal numbers), octal (`0o567`) and binary (`0b11011`) are not supported.

- Use `\u` escapes for weird characters, `\x` and `\ooo` escapes are not available in **.toml** files
  - Example: `\U0001f44d` for 👍 (thumbs up emoji) and `\u20ac` for € (EUR sign)

- Unicode emoji, and non-ASCII characters, stand for themselves as long as you're careful to save in "UTF-8 without BOM" format

&nbsp;

&nbsp;

When your&nbsp; **settings.toml&nbsp;** file is ready, you can save it in your text editor with the **.toml** &nbsp;extension.

![adafruit_products_dotToml.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/071/medium640/adafruit_products_dotToml.jpg?1671034293)

## Accessing Your **settings.toml** Information in **code.py**
In your **code.py** file, you'll need to `import` the `os` library to access the **settings.toml** file. Your settings are accessed with the `os.getenv()` function. You'll pass your settings entry to the function to import it into the **code.py** file.

```python
import os

print(os.getenv("test_variable"))
```

![](https://cdn-learn.adafruit.com/assets/assets/000/117/072/medium800/adafruit_products_tomlOutput.jpg?1671034496)

In the upcoming CircuitPython WiFi examples, you'll see how the **settings.toml&nbsp;** file is used for connecting to your SSID and accessing your API keys.


## Featured Products

### Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM

[Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM](https://www.adafruit.com/product/5500)
What's Metro-shaped and has an ESP32-S3&nbsp;WiFi module? What has a STEMMA QT connector for I2C devices and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - it's the new...

In Stock
[Buy Now](https://www.adafruit.com/product/5500)
[Related Guides to the Product](https://learn.adafruit.com/products/5500/guides)
### Adafruit Metro ESP32-S2

[Adafruit Metro ESP32-S2](https://www.adafruit.com/product/4775)
What's Metro shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices, and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - its the new Adafruit Metro...

In Stock
[Buy Now](https://www.adafruit.com/product/4775)
[Related Guides to the Product](https://learn.adafruit.com/products/4775/guides)
### Adafruit ESP32 Feather V2 w.FL Antenna -  8MB Flash + 2 MB PSRAM

[Adafruit ESP32 Feather V2 w.FL Antenna -  8MB Flash + 2 MB PSRAM](https://www.adafruit.com/product/5438)
One of our star Feathers is the [Adafruit HUZZAH32 ESP32 Feather](https://www.adafruit.com/product/3405) - with the fabulous ESP32 WROOM module on there, it makes quick work of WiFi and Bluetooth® projects that take advantage of Espressifs most popular chipset. Recently we had...

In Stock
[Buy Now](https://www.adafruit.com/product/5438)
[Related Guides to the Product](https://learn.adafruit.com/products/5438/guides)
### Analog Potentiometer Volume Adjustable TRRS Headset

[Analog Potentiometer Volume Adjustable TRRS Headset](https://www.adafruit.com/product/3959)
Most modern headphone sets are purely digital - with three volume control buttons in-line with the cable. These headphones are interesting in that they have an _analog_ volume control potentiometer. Perfect for use with electronic projects that don't have volume control, or for...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/3959)
[Related Guides to the Product](https://learn.adafruit.com/products/3959/guides)

## Related Guides

- [Adafruit Metro ESP32-S2](https://learn.adafruit.com/adafruit-metro-esp32-s2.md)
- [Adafruit ESP32 Feather V2](https://learn.adafruit.com/adafruit-esp32-feather-v2.md)
- [Adafruit Metro ESP32-S3](https://learn.adafruit.com/adafruit-metro-esp32-s3.md)
- [Introducing Adafruit Feather](https://learn.adafruit.com/adafruit-feather.md)
- [No-Code WipperSnapper Summoning Horn](https://learn.adafruit.com/adafruit-io-wippersnapper-summoning-horn.md)
- [Plotting Offline Data - JSONL to CSV files, filters and graphs](https://learn.adafruit.com/plotting-offline-data-jsonl-to-csv-files-filters-and-graphs.md)
- [Use Docker to Compile Linux for ESP32-S3](https://learn.adafruit.com/docker-esp32-s3-linux.md)
- [Networking in CircuitPython](https://learn.adafruit.com/networking-in-circuitpython.md)
- [CAN Bus with CircuitPython: Using the canio module](https://learn.adafruit.com/using-canio-circuitpython.md)
- [Garden Path Lights with WLED and a Sunset Timer](https://learn.adafruit.com/garden-path-lights-with-sunset-timer.md)
- [WiFi Mailbox Notifier](https://learn.adafruit.com/wifi-mailbox-notifier.md)
- [ESP-NOW in CircuitPython](https://learn.adafruit.com/esp-now-in-circuitpython.md)
- [Animating Animatronics](https://learn.adafruit.com/animating-animatronics.md)
- [Temperature and Humidity Sensing in Home Assistant with CircuitPython](https://learn.adafruit.com/temperature-and-humidity-sensing-in-home-assistant-with-circuitpython.md)
- [Adafruit IoT Button with NeoPixel BFF](https://learn.adafruit.com/adafruit-iot-button-with-neopixel-bff.md)
- [Creative Inspiration Activity Generator](https://learn.adafruit.com/creative-inspiration-activity-generator.md)
