CS21 Lab 11: Swatify (objects)
Due Wednesday, December 11, before midnight
Please read through the entire lab before starting!
In this lab, you’ll write classes to represent Song
and Playlist
objects
that you’ll use to play .mp3
audio files.
For this lab, you’ll be playing audio. Please be respectful about the noise you may be generating in the lab. Whenever possible, please use headphones to test your audio, and if that’s not possible for some reason, please keep the volume low if others are working nearby. |
Only test audio playback while physically present in the lab, while logged in to the machine you’d be testing on. You will NOT hear anything, and thus will be unable to test correctness, if you’re logged in remotely. |
All of the standard style guidelines from previous labs still apply. Be sure to follow good top-down-design practices.
As you write programs, use good programming practices:
-
Use a comment at the top of the file to describe the purpose of the program (see example).
-
All programs should have a
main()
function (see example). -
Use variable names that describe the contents of the variables.
-
Write your programs incrementally and test them as you go. This is really crucial to success: don’t write lots of code and then test it all at once! Write a little code, make sure it works, then add some more and test it again.
-
Don’t assume that if your program passes the sample tests we provide that it is completely correct. Come up with your own test cases and verify that the program is producing the right output on them.
-
Avoid writing any lines of code that exceed 80 columns.
-
Always work in a terminal window that is 80 characters wide (resize it to be this wide)
-
In
vscode
, at the bottom right in the window, there is an indication of both the line and the column of the cursor.
-
Function Comments
All functions should have a top-level comment! Please see our function example page if you are confused about writing function comments.
Goals
The goals for this lab assignment are:
-
Gain experience writing classes.
-
Gain experience reading and using classes.
1. Writing Classes
For this lab, you’ll be doing your work in three files:
-
song.py
: This file will define aSong
class that you’ll use to represent the information you know about one song (e.g., the artist, title, and path to the corresponding.mp3
file. -
playlist.py
: This file will define aPlaylist
class that you’ll use to represent a collection ofSong
objects that should be played, in order. It will also provide methods for getting information about the collection as a whole (e.g., the total playtime duration of all the songs in the list). -
swatify.py
: The main file that will contain yourmain
function and supporting helper functions. The code in this file will createPlaylist
andSong
objects to "put everything together" and play music according to the specifications below.
1.1. Testing
-
As always, you should test your program as you go.
-
Since you’re working with three files, it’s a good idea to put the tests for your class in the corresponding file.
-
Like we saw in lecture, this can be done by writing a
main()
method, and then calling it at the bottom using:if __name__ == "__main__": main()
This way, your testing code will run when you execute
python3 song.py
on the command line, but it won’t run when youimport
from song inswatify.py
1.2. The Song Class
The song.py
file should contain a class definition for a class named Song
.
The Song
class should have at minimum the following methods:
-
Constructor (
__init(…)__
)-
The constructor should take the path to the corresponding
.mp3
file for this song (a string, for example,"/home/kwebb/music/Johnny Cash-Hurt.mp3"
. -
You should save the file path as-is in an instance variable. The system for playing music that we provide for you will need to refer to the file path later.
-
Based on the file path, you should also store two additional instance variables (strings): an artist and a title. You can determine these values by splitting the file path string. The provided
strip_path()
function will remove the directory names in the path and the.mp3
suffix from the file name for you. After that, you may assume that the artist and song title will always be separated by a dash:"-"
.
-
-
get_filename(…)
-
This method should take no parameters (other than
self
), and it should return the stored full file path to the.mp3
file for this song that was passed in to the constructor.
-
-
get_artist(…)
-
This method should take no parameters (other than
self
), and it should return a string containing just the artist of the song.
-
-
get_title(…)
-
This method should take no parameters (other than
self
), and it should return a string containing just the title of the song.
-
-
get_duration(…)
-
This method should take no parameters (other than
self
), and it should return a float that contains the length of the song, in seconds. -
The provided
lookup_song_duration()
function will help you to determine the length of a song.
-
-
__str__(…)
-
This method should take no parameters (other than
self
), and it should return a string with a short description of the song. For example, if the title isHurt
and the artist isJohnny Cash
, this function should return a description like"Hurt by Johnny Cash"
. -
This method should not print anything, just return a string.
-
-
__eq__(…)
-
This method tests for equality between two
Song
objects. It should take one parameter (in addition toself
): anotherSong
object. It should returnTrue
if the twoSong
objects represent the same song (i.e., they have the same.mp3
file path) orFalse
otherwise. -
You will not call this method directly. Instead, python will automatically use it when two
Song
objects are compared using==
. For this lab, it’s needed so that you can use thein
operator to check if aSong
is in a list, which will be helpful when you write thePlaylist
class.
-
Before moving on to the |
1.3. The Playlist Class
The playlist.py
file should contain a class definition for a class named
Playlist
. The Playlist
class should have at minimum the following
methods:
-
Constructor (
__init(…)__
)-
The constructor should take no parameters (other than
self
), and it should initialize a list instance variable that will later store a list ofSong
objects.
-
-
add_song(…)
-
This method should take one parameter (in addition to
self
): theSong
object to add to the playlist. It does not return any value. -
If the song is not already in the playlist, it should add the song to the playlist. Note that using the
in
operator to test whether aSong
object is in a list will only work if theSong
object’s__eq__()
method is working properly. -
If the song is already in the playlist, it should print a message to inform the user that the song is already in the playlist and not change the contents of the playlist.
-
-
get_song(…)
-
This method should take one parameter (in addition to
self
): the index of the song to retrieve from the playlist (starting from 0, like a python list). -
You can assume this method is provided a valid index.
-
It should return the
Song
object in the playlist at the requested position.
-
-
get_song_count(…)
-
This method should take no parameters (other than
self
), and it should return the number of songs in the playlist (an integer).
-
-
get_duration(…)
-
This method should take no parameters (other than
self
), and it should return a float containing the length of the whole playlist, in seconds.
-
-
__str__()
-
This method should take no parameters (other than
self
), and it should return a string with the contents of the playlist and the total length of the playlist in seconds. -
If the playlist is empty (contains 0 songs), simply return the string
"Playlist is empty"
. -
If the playlist has one or more songs in it, the string this method should generate a string that contains each song on a separate line, followed by the duration in seconds.
-
This method should not print anything, just return a string.
-
Before moving on, add tests cases to a |
Here’s an example of what it would look like to print a Playlist
that has
three Song
objects added to it:
2. Provided Library
This lab provides a music
library that gives you several helpful functions
and a Player
object to make this lab easier. To use the functions described
below, you will import
them from the music
library. For example, to use
the strip_path
and lookup_song_duration
functions, you would say:
from music import strip_path, lookup_song_duration
Here are the functions included in the music
library:
-
strip_path(…)
-
This function takes a path to a
.mp3
file and 1) removes all of the leading directory names, and 2) removes the.mp3
suffix. For example, given the file path:/home/kwebb/music/Johnny Cash-Hurt.mp3
It would produce the string:
"Johnny Cash-Hurt"
-
-
lookup_song_duration(…)
-
This function takes a file path string and returns the length of the song, in seconds, as a float.
-
-
read_song_directory(…)
-
This function takes a path to a directory that contains
.mp3
files (for example,"/home/kwebb/music"
). It will return a list containing the paths of all the.mp3
files in that directory. For example, if you callread_song_directory
on the path"/home/kwebb/music"
, it will generate a list that looks like:['/home/kwebb/music/Aretha Franklin-Respect.mp3', '/home/kwebb/music/Cowboy Junkies-Sweet Jane.mp3', '/home/kwebb/music/David Bowie-Waterloo Sunset.mp3', ..., '/home/kwebb/music/The Animals-House of the Rising Sun.mp3', '/home/kwebb/music/The Blind Boys of Alabama-Way Down in the Hole.mp3']
-
-
Player()
object: APlayer
will help you to manage playing music so that you don’t need to worry about the details of playing audio files. Your program should create aPlayer
at the start of main and continue to use that onePlayer
for the duration of the program. The constructor forPlayer
takes no parameters, so you can create one early inmain
with a line like:
def main(): player = Player() # create the music player
-
The player has the following methods defined for you:
-
.play()
: Takes one parameter, aPlaylist
object. Returns no value. When called, it will begin playing the songs on the playlist, in order. For it to work, you’ll need most of theSong
andPlaylist
methods described above to behave correctly. -
.stop()
: Takes no parameters and returns no value. Stops playback of the playlist if it’s playing. Does nothing if the playlist isn’t playing. -
.next()
: Takes no parameters and returns no value. Skips forward to the next song in the playlist if there is one. Stops the playlist if it’s currently playing the final song. Does nothing if the playlist isn’t playing.
-
.get_current_song()
: returns a string containing information about the current song that is playing (or a string to indicate that nothing is playing if there isn’t one).
3. Putting it all together in swatify.py
The song.py
file should contain a class definition for a class named Song
, and playlist.py
should contain a class definition for a class named Playlist
.
You will need to import these classes into your swatify.py
file by typing:
from song import Song from playlist import Playlist
Even though your files are called song.py and playlist.py , you
import from song and playlist . Python adds the .py automatically when
looking for the file.
|
You will also need to import
some functions from the music
library:
from music import Player, read_song_directory
Like prior labs, this lab will present the user with a menu-based interface to make selections. The menu should look like:
Please select one of the following choices: 1. Show available song files 2. Print current playlist 3. Add song to playlist 4. Start playlist 5. Skip to next song 6. Stop playlist 0. Quit Enter selection:
Depending on what the user selects, you should do one of the following things:
-
Show available song files
: Print a numbered list of available song files for the user to choose from. The providedread_song_directory()
will do much of the work for you here. If you give it a path to a directory, it’ll give you a list of the.mp3
files in that directory. You can use the directory path"/home/kwebb/music"
for example files, or you can make a directory of your own with.mp3
files in it. -
Print current playlist
: Print information about the current playlist, including the contents of the list, the total duration of the playlist in seconds, and the currently playing song, if there is one. The.get_current_song()
method of aPlayer
will tell you what is playing (or that nothing is playing). -
Add song to playlist
: Add a song to the playlist. Prompt the to enter a number for which song they’d like add, create aSong
object, and add it to your playlist. You should validate that the user enters an integer and that it’s a valid choice (i.e., there’s a song file corresponding to that number). -
Start playlist
: Start playing the playlist with the provided.play()
method of aPlayer
. -
Skip to next song
: Tell thePlayer
object to skip to the next song. If nothing is currently playing, this option does nothing. If the playlist is currently playing the final song, this option will stop playback. -
Stop playlist
: Tell thePlayer
object to stop playback. If nothing is currently playing, this option does nothing.
-
Quit
: Exit the program.
4. Requirements
The code you submit for labs is expected to follow good style practices, and to meet one of the course standards, you’ll need to demonstrate good style on six or more of the lab assignments across the semester. To meet the good style expectations, you should:
In addition, you’ll need to demonstrate good top-down design practices on two or more lab assignments across the semester. To meet the top-down design expectations, you should:
|
Your program should meet the following requirements:
-
Your implementation of the
Song
class should be in the filesong.py
and its methods should behave as described in section 1.1. -
Your implementation of the
Playlist
class should be in the fileplaylist.py
and its methods should behave as described in section 1.2. -
Your
song.py
andplaylist.py
files should contain tests of the methods you’ve written in those files. -
Your
swatify.py
should contain amain
function that presents the user with menu choices as described in section 3. -
Your implementation of
swatify.py
allows the user to list song files, add songs to a playlist, and print the playlist. -
Your implementation of
swatify.py
allows the user to play a playlist, skip to the next song, and stop playback.
5. Extra Challenges
Here are some optional extensions! These are not required, but they might be fun and rewarding.
If you implement extensions, please make sure the original menu operations remain the same. That is, you are welcome to add a menu item 7, but don’t change menu item 3 to be menu item 4.
5.1. Optional: Remove song from playlist
Provide the user with an option to remove a song from a playlist. You’ll need to prompt them to tell you which song, and then you’ll need to find it in the list to remove it.
5.2. Optional: Sort the playlist
Sort the playlist based on any criteria you like (artist name, song title, duration, etc.).
5.3. Optional: Print song information
Each .mp3
file in the example directory also has a corresponding text file
with the same name + ".info"
added to the end of it. If the user asks for
information about a file, prompt them to enter a number for which song they’d
like information about, open the corresponding .info
file, and print the
contents of that file to the terminal.
5.4. Optional: Add features based on your own interests!
Do whatever you’d like that we haven’t told you to do! Go crazy!
Answer the Questionnaire
After each lab, please complete the short Google Forms questionnaire. Please select the right lab number (Lab 11) from the dropdown menu on the first question.
Once you’re done with that, you should run handin21
again.
Submitting lab assignments
Remember to run handin21
to turn in your lab files! You may run handin21
as many times as you want. Each time it will turn in any new work. We
recommend running handin21
after you complete each program or after you
complete significant work on any one program.
Logging out
When you’re done working in the lab, you should log out of the computer you’re using.
First quit any applications you are running, including your vscode editor, the browser and the terminal. Then click on the logout icon ( or ) and choose "log out".
If you plan to leave the lab for just a few minutes, you do not need to log out. It is, however, a good idea to lock your machine while you are gone. You can lock your screen by clicking on the lock icon. PLEASE do not leave a session locked for a long period of time. Power may go out, someone might reboot the machine, etc. You don’t want to lose any work!