MP3 Music Player in Python
CSE 120 Final Report
Lincoln May
Table of Contents
1
1. Introduction and Goals
2. Code Explanation
3. Challenges Faced 6
4. What I learned
Appendix A: Source Code
Appendix B: Progress Chart
14
2
Introduction and Goal:
When first reading about the final project for CSE 120, I was extremely
excited with the broadness of the project. It was great to have the ability to
choose to do the project on your own personal interests, which has been
uncommon in my university experience thus far. That being said, there was
an overwhelming number of projects and ideas to choose from. But after
giving it thought, I knew I wanted to do something related to music. An idea
that I had was to recreate a music app similar to Spotify or Apple Music. After
doing a little research on this idea, I saw that you could use pygame, a
library used for developing games in python, to play mp3 files. While
researching I also came across Tkinter, an interface used for developing
graphical user-interfaces. That is when I determined my goal was to build an
mp3 music player application using pygame and Tkinter. I wanted users to
be able to import their own folder of mp3 files and be able to play, pause,
and navigate through their music collection. I wanted the user interface to be
simple and intuitive. It includes buttons to play, pause, next and previous
track functionalities. There is also a list of songs displayed allowing users to
3
see what songs are next up and a volume slider to allow the users to easily
control the volume.
Code Explanation:
The first few lines of code import the necessary libraries for the project.
Pygame is used for the music playback functionalities, while Tkinter is used
to provide tools for creating the graphical user interface. The filedialog
module is used to open a dialog for directory selection, and OS handles file
and directory operations.
The next segment of code initializes pygame mixer which is used for
audio playback. Similarly, I also do some of the initialization for Tkinter. I
create the main window for my application and set the title to “Music
Player”. I then set the dimension of the window and add a menu bar, which
will later be used for file selection.
After most of the setup has been taken care of, I create a load song
function. This Function allows the user to select a directory containing mp3
files. It uses filedialog.askdirectory() to open a directory selection dialog. It
then scans the selected directory for MP3 files, adds them to the songs list,
and populates the song_list window with these songs. The first song in the
list is selected by default.
4
The play song function manages the playback of the selected song. If
the song is not paused, it loads and plays the currently selected song from
the directory using pygame.mixer.music.load() and
pygame.mixer.music.play(). If the song is paused, it simply unpauses the
playback using pygame.mixer.music.unpause().
The pause song function pauses the current song playback. It uses
pygame.mixer.music.pause() to pause the song and sets the paused flag to
true to indicate that the song has been paused.
The next song function moves to the next song in the list and starts
playing it. It calculates the index of the next song, updates the curr_song
variable, and loads and plays the new song using the play song function. It
also updates the selection in the song_list window to reflect the currently
playing song.
The previous song function moves to the previous song in the list and
starts playing it. It also calculates the index of the previous song, updates
the curr_song variable, and loads and plays the new song using the play
song function, updating the selection in the song_list window to reflect the
currently playing song.
The set volume function adjusts the playback volume. It takes a value
from the volume slider, converts it to a range between 0 and 1, and sets the
volume using pygame.mixer.music.set_volume().
5
The next segment sets up the menu and the list box in the main
window. The menu allows the user to select a folder containing MP3 files
using the load_song function. The song_list List box displays the list of songs
and is styled with black background and white text.
The final segment creates and positions the control buttons and the
volume slider. The buttons for previous, play, pause, and next functionalities
are created using tk.Button and they are open-source PNG images from the
internet. They are arranged in a grid within a frame to be more user-friendly.
The volume slider is created using tk.Scale, oriented horizontally, and linked
to the set_volume function. The default volume is set to 70%. Then I call
root.mainloop() to start the main event of the application.
Challenges Faced:
Overall, this project was very fun to develop but there was some
challenges faced along the way. One of the main challenges I faced initially
was that both Tkinter and pygame were completely new to me. I expected to
come across new things while working on this project but it was still
challenging learning how to use pygame and Tkinter. Luckily pygame was
not too complicated, but tkinter was a bit confusing. I have some experience
working with JavaFX, which I found similar to Tkinter. But I seem to have a
hard time understanding both. After a little research and practice I was able
to understand Tkinter to the extent needed for this project.
6
Another challenge I faced while developing this project was using
filedialog and os modules. One significant challenge was ensuring that files
were handled correctly by Tkinter and the os module. Additionally, it was a
challenge to only append mp3 files to the song list, avoiding potential errors
or crashes from unsupported formats. Implementing the directory selection
dialog with filedialog.askdirectory() also introduced difficulties in user
interaction, this is because the user has to be aware that only mp3 files are
supported and it will result in errors if the user tries importing a different
type of file. Lastly, dynamically updating the graphical user interface to
reflect when the previous or next song buttons were selected was also
difficult to work out. I had to make sure that the program would not
unexpectedly crash if the song list was empty.
These challenges were tricky to deal with but ultimately they
strengthened my understanding of pygame, Tkinter, and accessing files. Not
only did they strengthen my understanding of python, but they also worked
to strengthen my ability to write code in general.
What I Learned:
Learning to integrate Tkinter for the graphical user interface and
pygame for music playback was a significant aspect of this project. These
libraries serve different purposes and combining them effectively required a
deep understanding of their functionalities and how they interact. Tkinter
7
provides the tools to build a user-friendly interface, while pygame handles
the audio playback. The challenge was to synchronize these libraries,
ensuring that the user interface responds correctly to audio events and user
inputs. Understanding this integration was crucial for the project's success
and helped in creating a user-friendly interface.
The project also deepened my understanding of event-driven
programming, this is very important for building interactive applications.
Tkinter relies heavily on events and callbacks to interact with the user, such
as button clicks and slider adjustments. This required me to design the
program logic in a way that responds to these events in real-time, ensuring
that user inputs are processed immediately and correctly. Working with
Tkinter enhanced my ability to think in terms of events and handlers, which
are fundamental concepts in GUI development.
Handling file operations in Python, including reading from directories
and managing file paths, was another important learning outcome of this
project. Using the os module, I was able to navigate directories, filter files by
their extensions, and manage file paths efficiently. This skill is crucial for any
application that interacts with the file system, and it ensured that the music
player could dynamically load and manage songs from different directories
without running into errors.
8
.
APPENDIX A: SOURCE CODE
Main.py:
import pygame
import tkinter as tk
from tkinter import filedialog, END, Scale
import os
pygame.mixer.init()
9
root = tk.Tk()
root.title("Music Player")
root.geometry("500x400")
menubar = tk.Menu(root)
root.config(menu=menubar)
def load_song():
global curr_song
root.directory = filedialog.askdirectory()
for song in os.listdir(root.directory):
name, ext = os.path.splitext(song)
if ext == '.mp3':
songs.append(song)
for song in songs:
song_list.insert("end", song)
if songs:
song_list.selection_set(0)
curr_song = songs[song_list.curselection()[0]]
def play_song():
global curr_song, paused
10
if not paused:
pygame.mixer.music.load(os.path.join(root.directory, curr_song))
pygame.mixer.music.play()
else:
pygame.mixer.music.unpause()
paused = False
def pause_song():
global paused
pygame.mixer.music.pause()
paused = True
def next_song():
global curr_song, paused
try:
current_index = songs.index(curr_song)
next_index = (current_index + 1) % len(songs)
curr_song = songs[next_index]
song_list.selection_clear(0, END)
song_list.selection_set(next_index)
song_list.activate(next_index)
pygame.mixer.music.load(os.path.join(root.directory, curr_song))
pygame.mixer.music.play()
11
paused = False
except IndexError:
pass
def prev_song():
global curr_song, paused
try:
current_index = songs.index(curr_song)
prev_index = (current_index - 1) % len(songs)
curr_song = songs[prev_index]
song_list.selection_clear(0, END)
song_list.selection_set(prev_index)
song_list.activate(prev_index)
pygame.mixer.music.load(os.path.join(root.directory, curr_song))
pygame.mixer.music.play()
paused = False
except IndexError:
pass
def set_volume(val):
volume = int(val) / 100
pygame.mixer.music.set_volume(volume)
12
organize_menu = tk.Menu(menubar, tearoff=False)
organize_menu.add_command(label="Select Folder", command=load_song)
menubar.add_cascade(label="Import Music", menu=organize_menu)
song_list = tk.Listbox(root, bg="black", fg="white", width=100, height=15)
song_list.pack()
songs = []
curr_song = ""
paused = False
play_img = tk.PhotoImage(file="play.png")
pause_img = tk.PhotoImage(file="pause.png")
prev_img = tk.PhotoImage(file="previous.png")
next_img = tk.PhotoImage(file="next.png")
control_frame = tk.Frame(root, bg="white")
control_frame.pack()
prev_button = tk.Button(control_frame, image=prev_img,
command=prev_song, borderwidth=0)
play_button = tk.Button(control_frame, image=play_img,
command=play_song, borderwidth=0)
pause_button = tk.Button(control_frame, image=pause_img,
command=pause_song, borderwidth=0)
next_button = tk.Button(control_frame, image=next_img,
command=next_song, borderwidth=0)
13
prev_button.grid(row=0, column=0, padx=10, pady=10)
play_button.grid(row=0, column=1, padx=10, pady=10)
pause_button.grid(row=0, column=2, padx=10, pady=10)
next_button.grid(row=0, column=3, padx=10, pady=10)
volume_slider = Scale(root, from_=0, to=100, orient='horizontal',
command=set_volume)
volume_slider.set(70)
volume_slider.pack(pady=10)
root.mainloop()
APPENDIX B: PROGRESS CHART
Date Progress Made
The goal of my first week of the project was to do develop
an
Week 1, 6/2 Interesting idea for a project that was also feasible in the
scope of a project for this class. I decided on the idea to
make an mp3 player and did slight research to ensure it
would work for my final project.
In the second week of working with the project, my goal
was to do deeper research into what is required for the
Week 2, 6/9 project, such as what libraries and tools would be
necessary to complete the project. I did research on
pygame and tkinter to see what it would be like working
with them as I progress.
14
In the third week of the project, I got familiar with pygame
and tkinter before I was to start building my project. I
Week 3, 6/16 messed around with tkinter in the ide to get more familiar
with the syntax and usage and did the same with pygame
to a lesser extent.
Week 4 is when I started developing my project. I started
building the general layout in tkinter which was not too
Week 4, 6/23 complicated. Then I started developing some of the
functions for playing the music. I worked on the load
music, play, and pause logic.
This week I continued working on logic. I worked on the
logic behind the previous and next song buttons. I was
Week 5, 6/30 closing in on being done with the developing, but I decided
I wanted to add some more features, so I added a volume
slider.
In week seven, I mostly did testing of the project making
some slight changes. I downloaded some mp3 files off the
Week 6, 7/7 internet and added them to a folder so I could test the
mp3 player. Making some slight tweaks to the previous
and next button logic the mp3 player was in good shape.
In the last week of the project, I focused on writing the
Week 7, 7/14 final report.
15