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 aSongclass that you’ll use to represent the information you know about one song (e.g., the artist, title, and path to the corresponding.mp3file.
- 
playlist.py: This file will define aPlaylistclass that you’ll use to represent a collection ofSongobjects 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 yourmainfunction and supporting helper functions. The code in this file will createPlaylistandSongobjects 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.pyon the command line, but it won’t run when youimportfrom 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 .mp3file 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.mp3suffix 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.mp3file 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 isHurtand 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 Songobjects. It should take one parameter (in addition toself): anotherSongobject. It should returnTrueif the twoSongobjects represent the same song (i.e., they have the same.mp3file path) orFalseotherwise.
- 
You will not call this method directly. Instead, python will automatically use it when two Songobjects are compared using==. For this lab, it’s needed so that you can use theinoperator to check if aSongis in a list, which will be helpful when you write thePlaylistclass.
 
- 
| 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 ofSongobjects.
 
- 
- 
add_song(…)- 
This method should take one parameter (in addition to self): theSongobject 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 inoperator to test whether aSongobject is in a list will only work if theSongobject’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 Songobject 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_durationHere are the functions included in the music library:
- 
strip_path(…)- 
This function takes a path to a .mp3file and 1) removes all of the leading directory names, and 2) removes the.mp3suffix. 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 .mp3files (for example,"/home/kwebb/music"). It will return a list containing the paths of all the.mp3files in that directory. For example, if you callread_song_directoryon 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: APlayerwill 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 aPlayerat the start of main and continue to use that onePlayerfor the duration of the program. The constructor forPlayertakes no parameters, so you can create one early inmainwith a line like:
def main():
    player = Player() # create the music player
- 
The player has the following methods defined for you: 
- 
.play(): Takes one parameter, aPlaylistobject. 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 theSongandPlaylistmethods 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.pyandplaylist.py, youimportfromsongandplaylist.  Python adds the.pyautomatically 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.mp3files 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.mp3files 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 aPlayerwill 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 aSongobject, 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 thePlayerobject 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 thePlayerobject 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 Songclass should be in the filesong.pyand its methods should behave as described in section 1.1.
- 
Your implementation of the Playlistclass should be in the fileplaylist.pyand its methods should behave as described in section 1.2.
- 
Your song.pyandplaylist.pyfiles should contain tests of the methods you’ve written in those files.
- 
Your swatify.pyshould contain amainfunction that presents the user with menu choices as described in section 3.
- 
Your implementation of swatify.pyallows the user to list song files, add songs to a playlist, and print the playlist.
- 
Your implementation of swatify.pyallows 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
 or
 ) and choose "log out".
) 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!
 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!