# PyPortal Winamp MP3 Player

## Overview

https://www.youtube.com/watch?v=8sV1sRYdRRY

Bring back the good ol' days of Llama whippin' fun.

This project will turn your PyPortal into an MP3 player to play your favorite tunes with the familiar Winamp look. Create and manage multiple JSON playlists and rock out to whichever one fits the mood.

Take it a step further by choosing a custom [Winamp skin](https://skins.webamp.org/) and convert it for use on your PyPortal.

Warning: 

## Parts
### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
![Front view of a Adafruit PyPortal - CircuitPython Powered Internet Display with a pyportal logo image on the display. ](https://cdn-shop.adafruit.com/640x480/4116-00.jpeg)

### Adafruit PyPortal Titano

[Adafruit PyPortal Titano](https://www.adafruit.com/product/4444)
The **PyPortal Titano** is the big sister to our [popular PyPortal](https://www.adafruit.com/product/4116) now with _twice as many pixels!_ The PyPortal is our easy-to-use IoT device that allows you to create all the things for the “Internet of...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4444)
[Related Guides to the Product](https://learn.adafruit.com/products/4444/guides)
![Hand holding PyPortal Titano development board with SAMD51, ESP32 Wifi, and 3.5" touchscreen TFT display.](https://cdn-shop.adafruit.com/640x480/4444-10.jpg)

### Mini Oval Speaker with Short Wires - 8 Ohm 1 Watt

[Mini Oval Speaker with Short Wires - 8 Ohm 1 Watt](https://www.adafruit.com/product/4227)
Hear the good news! This wee speaker&nbsp;is&nbsp;a&nbsp;great addition to any audio project where you need 8 ohm impedance and 1W or less of power. We particularly like this&nbsp;speaker&nbsp;as it is&nbsp;small and comes with nice skinny wires with a connector on the end. It has a handy...

In Stock
[Buy Now](https://www.adafruit.com/product/4227)
[Related Guides to the Product](https://learn.adafruit.com/products/4227/guides)
![Mini Oval Speaker with Short Wires ](https://cdn-shop.adafruit.com/640x480/4227-06.jpg)

### Mini Oval Speaker - 8 Ohm 1 Watt

[Mini Oval Speaker - 8 Ohm 1 Watt](https://www.adafruit.com/product/3923)
Hear the good news! This wee speaker&nbsp;is&nbsp;a&nbsp;great addition to any audio project where you need 8 ohm impedance and 1W or less of power. We particularly like this&nbsp;speaker&nbsp;as it is&nbsp;small and comes with nice skinny wires with a connector on the end. It has a handy...

In Stock
[Buy Now](https://www.adafruit.com/product/3923)
[Related Guides to the Product](https://learn.adafruit.com/products/3923/guides)
![Small, black, oval speaker with Pico Blade connector.](https://cdn-shop.adafruit.com/640x480/3923-06.jpg)

# PyPortal Winamp MP3 Player

## External Speaker

The PyPortal does have a built-in speaker but it's fairly small. If you want your tunes to play louder you may use a larger speaker.

Luckily the PyPortal contains a plug-in adapter for just that!

If you do want to use the external speaker, you must cut a small jumper connection on the board in order to prevent the built-in speaker from playing in addition to the external one.

![projects_jumper_cut_pyportal_speaker.png](https://cdn-learn.adafruit.com/assets/assets/000/108/792/medium640/projects_jumper_cut_pyportal_speaker.png?1644276820)

![](https://cdn-learn.adafruit.com/assets/assets/000/108/793/medium800/projects_pyportal_speaker.png?1644277004)

# PyPortal Winamp MP3 Player

## Prepare Playlists

## Convert MP3s

CircuitPython works best with **stereo** or **mono** MP3 files from **32kbit/s** to **128kbit/s** , with sample rates from **16kHz** to **44.1kHz**. If your files are different, you can convert them using the free software [Audacity](https://www.audacityteam.org/). See [MP3 Export Options](https://manual.audacityteam.org/man/mp3_export_options.html) in the Audacity docs for more details.

## Copy Music to micro SDCard

Circuitpython supports FAT and FAT32 filesystems. If your micro SDCard is not already formatted with one of those filesystems, then use a PC to format it.

Once formatted, connect it to your PC and copy your MP3 song files onto it. You can sort them into different directories if you want, using any organization that you want. Or you can put them all in the root of the micro SDCard. Just make sure the paths in the **playlist.json** file match the paths to the files on your micro SDcard.

If you want the artist's name to be shown, then you'll need to include it in the filename. For example:

**FavoriteBand - Amazing Song of Awesome.mp3**

## Prepare Playlist JSON

The PyPortal Winamp player reads the playlist from the file **playlist.json** stored on your **CIRCUITPY** drive. If you'd like, you can create extra **playlist\_[something].json** files on your drive and switch between them by renaming the one you want to use to **playlist.json**. This allows you to set up as many playlists as you want so you have appropriate jams for any occasion.

A sample **playlist.json** file is shown below. You can use it as a starting point. Modify the file names and paths to match your songs you copied onto the microSD card in the previous step.

```auto
{
  "playlist": {
    "files": [
      "/sd/FavoriteBand - Advertime.mp3",
      "/sd/FavoriteBand - Beat Thee.mp3",
      "/sd/FavoriteBand - From Page to Practice.mp3",
      "/sd/FavoriteBand - Study and Relax.mp3",
      "/sd/FavoriteBand - The Celebrated Minuet.mp3"
    ]
  }
}
```

Once you've got your song files listed, save a copy as **playlist.json** on your **CIRCUITPY** drive. You can have additional **playlist\_[something].json** files if you'd like, but you must have exactly one named **playlist.json&nbsp;** if your using the default configuration inside of **code.py**.

# PyPortal Winamp MP3 Player

## Project Setup

Warning: 

[Follow these steps to create the /sd directory](https://learn.adafruit.com/adafruit-memento-camera-board/circuitpython-memento-starter-projects)
Are you new to using CircuitPython? No worries,&nbsp;[there is a full getting started guide here](https://learn.adafruit.com/welcome-to-circuitpython "Welcome to CircuitPython").

Plug the PyPortal into your computer with a known good USB cable (not a tint charge only cable). The PyPortal will appear to your computer as a flash drive named&nbsp; **CIRCUITPY**. If the drive does not appear you can [install CircuitPython](https://learn.adafruit.com/adafruit-pyportal/install-circuitpython) on your PyPortal and then return here.

Download the project files with the Download Project Bundle button in the Code section.&nbsp;Unzip the file and copy/paste the&nbsp; **code.py** &nbsp;and other project files to your&nbsp; **CIRCUITPY** &nbsp;drive using File Explorer or Finder (depending on your operating system).

Inside the project bundle you'll find all of the files you need on your PyPortal. There is also a **PyPortal\_Winamp\_Skin\_Converter** directory which does not need to go onto your PyPortal. It's used from your PC if you want to use a [custom skin for your Winamp Player](https://learn.adafruit.com/pyportal-winamp-mp3-player/custom-winamp-skin).

## Drive Structure

After copying the files, your drive should look like the listing below. It can contain other files as well, but must contain these at a minimum:

Warning: 

![Project](https://adafruit.github.io/Adafruit_Learning_System_Guides/PyPortal_PyPortal_Winamp_Player.png )

## Code

The project **code.py** is shown below. The next page [walks through how the code works.](https://learn.adafruit.com/pyportal-winamp-mp3-player/code-walk-through)

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

# PyPortal Winamp MP3 Player

## Code Walk-Through

## Architecture

The project is split into two python code files. **code.py** and **winamp\_helpers.py**. We know that **code.py** is the file that CircuitPython will execute automatically for us. It contains the initialization for the display, touch overlay, and SDCard. It also creates the `WinampApplication` object and reads the input data from the touch overlay to decide what actions should be taken and when.

## code.py

There are a handful of configuration variables that can be used to control different aspects of the player.

- `PLAYLIST_FILE` - The name of the playlist file that should be played. You can leave the default **playlist.json** or change it to your own custom playlist file. I like to create multiple playlist files with descriptive names and then rename the one I am in the mood for to **playlist.json&nbsp;** rather than changing the variable.
- `SKIN_IMAGE` - The name of the BMP image file for the skin that you want to use. The default is **base\_240x320.bmp** , see the [next page](https://learn.adafruit.com/pyportal-winamp-mp3-player/custom-winamp-skin) for instructions on using custom skins.
- `SKIN_CONFIG_FILE` - The name of the JSON configuration file for the chosen skin. Default is **base\_config.json**.
- `TOUCH_COOLDOWN` - Time in seconds to wait before allowing another touch event to be registered. Leave it as the default `0.5` seconds, or lower it if you'd like the app to be able to respond more rapidly to multiple touch events.
- `ORIENTATION` - The rotation value for the display. Must be either `90` or `270` which are the two possible portrait orientations. Default is `90`.

The following occur in **code.py** as setup for various things:

Initializing the touch input based on the `ORIENTATION` setting:

```python
if ORIENTATION == 270:
    # setup touch screen
    ts = adafruit_touchscreen.Touchscreen(
        board.TOUCH_YD,
        board.TOUCH_YU,
        board.TOUCH_XR,
        board.TOUCH_XL,
        calibration=((5200, 59000), (5800, 57000)),
        size=(240, 320),
    )
elif ORIENTATION == 90:
    # setup touch screen
    ts = adafruit_touchscreen.Touchscreen(
        board.TOUCH_YU,
        board.TOUCH_YD,
        board.TOUCH_XL,
        board.TOUCH_XR,
        calibration=((5200, 59000), (5800, 57000)),
        size=(240, 320),
    )
```

Initialize the SDCard so that we can read the song MP3 files from it:

```python
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
sdcard = sdcardio.SDCard(spi, board.SD_CS)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
sys.path.append("/sd")
```

Access the built-in display, and set it's orientation based on our `ORIENTATION` setting.

```auto
# get reference to the display
display = board.DISPLAY

# set rotation
display.rotation = ORIENTATION
```

Create a `WinampApplication` object and set it as the root\_group on the display:

```python
# Initialize WinampApplication helper class
winamp_application = WinampApplication(
    playlist_file=PLAYLIST_FILE,
    skin_image=SKIN_IMAGE,
    skin_config_file=SKIN_CONFIG_FILE,
)

# Add the Group to the Display
display.root_group = winamp_application
```

## Main loop

Inside the main loop there are two main tasks that occur:

- Call `winamp_application.update()` to refresh the UI. This will update the clock display, allow the track title bar to scroll, and update the playlist display based on the current track number. It will open and begin playing the next song when the current one has finished playing.
- Check for touch events coming from the touch overlay and call the appropriate action functions on the `winamp_application` object when touches are detected.

The Winamp skin is decoration only, the controls within it are too tiny for us to use on the PyPortal without a very precise stylus and perfectly calibrated touch overlay.

There are 3 invisible buttons that are used to control the application. The entire top half of the screen is the pause/resume button. The bottom half of the screen is split vertically, the left half is the previous track button, and the right half is the next track button.

![projects_touch_interface.png](https://cdn-learn.adafruit.com/assets/assets/000/109/031/medium640/projects_touch_interface.png?1644973041)

## Helper Classes

There are three helper classes inside of **winamp\_helpers.py** that are used in the project. All of these classes extend `displayio.Group` so they can be added to other groups and shown on the display.

- `WinampApplication` - This is a high level object that manages the player. It initializes the skin graphics, and other displayio widgets used in the UI. It has action functions which get called from the main loop when touch events occur: `pause()`, `resume()`, `next_track()`, and `previous_track()`. The `update()` function must be called once per iteration in the main loop to process all visual updates in the UI and advance to the next track when needed. The `play_current_track()` function is responsible for opening and playing MP3 files.  
  
- `ClockDisplay` - This is a displayio widget that contains the labels needed to show the elapsed time during playback near the top left of the UI. Time showing is updated via the `seconds` property. This custom widget was created because the spacing used for the clock digits in some of the Winamp skins is very specific. A standard Label with the default font would not match the spacing correctly.  
  
- `PlaylistDisplay`- Another displayio widget, this one contains the labels used to show the current track and next two track titles in the bottom part of the UI. It also manages which track is considered the current track for us, which is updated via the `current_track_number` property. `current_track_title` is a convenience property that will format the current track name into a suitable string to be shown in the `ScrollingLabel` near the top right of the UI.

## Further Detail

The source code is thoroughly commented to explain what the statements are doing. You can read through the code and comments to gain a deeper understanding of how it functions, or modify parts of it to suit your needs.

### code.py:
https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/PyPortal/PyPortal_Winamp_Player/code.py

### winamp\_helpers.py:

&nbsp;

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/PyPortal/PyPortal_Winamp_Player/winamp_helpers.py

# PyPortal Winamp MP3 Player

## Custom Winamp Skin

Both [The Winamp Skin Museum](https://skins.webamp.org/) and the [Internet Archive](https://archive.org/details/winampskins) contain many different skins. Take a look through them, find something that suits your style, you can download it and convert it for use on your PyPortal.&nbsp;

Inside the project bundle that you downloaded there is a directory named **PyPortal\_Winamp\_Skin\_Converter**. Inside of there is a Python script that will do the conversion for you.

Warning: 

## Download Skin

Go to the [Skin Museum](https://skins.webamp.org/) or&nbsp;the&nbsp;[Internet Archive](https://archive.org/details/winampskins) and find the perfect skin. Once you find it, right click on its preview image and download the image.

![](https://cdn-learn.adafruit.com/assets/assets/000/109/058/medium800/projects_winamp_skin_download.bmp?1645061132)

Warning: 

By default the filename will be a long string of letters and numbers. You should change it to something shorter and more descriptive, especially if you plan to download multiple skins and swap them out! The skin I chose is a dark theme so I'll choose the name **dark\_theme.png**. You can choose a name that is appropriate for the skin you chose.

Once you've downloaded the skin image copy it into the&nbsp; **PyPortal\_Winamp\_Skin\_Converter&nbsp;** directory on your PC. It should be alongside of **convert\_winamp\_skin.py**. There is a **.circuitpython.skip-screenshot&nbsp;** file there also, but you don't need to use it. That is for our project files screenshot utility.

![projects_convert_files.png](https://cdn-learn.adafruit.com/assets/assets/000/109/059/medium640/projects_convert_files.png?1645061522)

## Convert the skin

The conversion script requires [Python](https://www.python.org/) and the [Pillow](https://python-pillow.org/) library, which is a friendly fork of PIL the Python Imaging Library.

If you don't already have Python on your PC, go to the [Python downloads](https://www.python.org/downloads/) page and follow the instructions there to download Python for your PC.

Once you've got Python on your PC you can use pip to install pillow. Run this command to install it:

```terminal
pip install pillow
```

Once you've got pillow installed you are ready to convert the skin. To convert it run a command like this, substituting in the name of the skin image file that you downloaded.

```terminal
python convert_winamp_skin.py [your_skin_image].png
```

So for my dark theme skin I am running this command:

```terminal
python convert_winamp_skin.py dark_theme.png
```

## Skin files

This will create two files from your skin. These will get loaded onto your&nbsp; **CIRCUITPY** drive. They will be named like these: **[your\_skin]\_240x320.bmp**&nbsp;and&nbsp;**[your\_skin]\_config.json**

![projects_converted_skin_files.png](https://cdn-learn.adafruit.com/assets/assets/000/109/060/medium640/projects_converted_skin_files.png?1645063863)

Copy both of these two files to your PyPortal **CIRCUITPY** drive.

The last thing to do is update the variables near the top of **code.py** on your **CIRCUITPY** drive to reflect your skin filenames. This is how mine look, yours will use the name that you selected previously.

```python
# which skin background to use
SKIN_IMAGE = "/dark_theme_240x320.bmp"

# skin configuration for color values
SKIN_CONFIG_FILE = "dark_theme_config.json"
```

The PyPortal will reset when you save the files and draw the new skin and begin playing your playlist. You can download several skins and swap between them for whatever mood you're in.


## Featured Products

### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
### Adafruit PyPortal Pynt - CircuitPython Powered Internet Display

[Adafruit PyPortal Pynt - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4465)
The **PyPortal Pynt** is the little&nbsp;sister to our [popular PyPortal](https://www.adafruit.com/product/4116) - zapped with a shrink ray to take the design from a 3.2" diagonal down to 2.4" diagonal screen - but otherwise the same! The PyPortal is&nbsp;our...

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

[Adafruit PyPortal Titano](https://www.adafruit.com/product/4444)
The **PyPortal Titano** is the big sister to our [popular PyPortal](https://www.adafruit.com/product/4116) now with _twice as many pixels!_ The PyPortal is our easy-to-use IoT device that allows you to create all the things for the “Internet of...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4444)
[Related Guides to the Product](https://learn.adafruit.com/products/4444/guides)
### Mini Oval Speaker with Short Wires - 8 Ohm 1 Watt

[Mini Oval Speaker with Short Wires - 8 Ohm 1 Watt](https://www.adafruit.com/product/4227)
Hear the good news! This wee speaker&nbsp;is&nbsp;a&nbsp;great addition to any audio project where you need 8 ohm impedance and 1W or less of power. We particularly like this&nbsp;speaker&nbsp;as it is&nbsp;small and comes with nice skinny wires with a connector on the end. It has a handy...

In Stock
[Buy Now](https://www.adafruit.com/product/4227)
[Related Guides to the Product](https://learn.adafruit.com/products/4227/guides)
### Mini Oval Speaker - 8 Ohm 1 Watt

[Mini Oval Speaker - 8 Ohm 1 Watt](https://www.adafruit.com/product/3923)
Hear the good news! This wee speaker&nbsp;is&nbsp;a&nbsp;great addition to any audio project where you need 8 ohm impedance and 1W or less of power. We particularly like this&nbsp;speaker&nbsp;as it is&nbsp;small and comes with nice skinny wires with a connector on the end. It has a handy...

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

## Related Guides

- [Adafruit PyPortal - IoT for CircuitPython](https://learn.adafruit.com/adafruit-pyportal.md)
- [Adafruit PyPortal Titano](https://learn.adafruit.com/adafruit-pyportal-titano.md)
- [ Memory-saving tips for CircuitPython](https://learn.adafruit.com/memory-saving-tips-for-circuitpython.md)
- [TFT Spirit Board](https://learn.adafruit.com/tft-spirit-board.md)
- [PyPortal US Election Calendar](https://learn.adafruit.com/pyportal-electioncal-us.md)
- [Playing Animated GIF Files in CircuitPython](https://learn.adafruit.com/using-animated-gif-files-in-circuitpython.md)
- [PyPortal Trivia Time with the Open Trivia Database](https://learn.adafruit.com/pyportal-trivia-time-open-trivia-database.md)
- [PyPortal Twitter Follows Trophy](https://learn.adafruit.com/pyportal-twitter-follows-trophy.md)
- [CircuitPython Turtle Graphics](https://learn.adafruit.com/circuitpython-turtle-graphics.md)
- [Electronic History of the Day with PyPortal](https://learn.adafruit.com/electronic-history-of-the-day-with-pyportal.md)
- [Making a PyPortal User Interface with DisplayIO](https://learn.adafruit.com/making-a-pyportal-user-interface-displayio.md)
- [Melting Picture Frame for PyPortal IoT images](https://learn.adafruit.com/pyportal-art-display.md)
- [PyPortal Wall Mount](https://learn.adafruit.com/pyportal-wall-mount.md)
- [CircuitPython Display_Text Library](https://learn.adafruit.com/circuitpython-display-text-library.md)
- [PyPortal View Master](https://learn.adafruit.com/pyportal-view-master.md)
- [PyPortal Event Count-Up Clock](https://learn.adafruit.com/pyportal-event-count-up-clock.md)
- [PyPortal Smart Thermometer with Analog Devices ADT7410, Adafruit IO and CircuitPython](https://learn.adafruit.com/pyportal-smart-thermometer-with-analog-devices-adt7410-adafruit-io-and-circuitpython.md)
