Music Playlist – 100 course points
In this assignment, you will create an implementation of a music streaming application. You will practice circular linked list manipulation, referencing objects, reading from CSV files, and the object-oriented programming (OOP) paradigm.
This assignment will take LONGER to complete than the first assignment.
Start your assignment early! You will need time to understand this assignment and the many questions it may present.
Refer to our Programming Assignments FAQ for instructions on how to install VSCode, how to use the command line and how to submit your assignments.
Overview
Apps such as Spotify, Apple Music, and Pandora are applications known as music streaming services. They allow users to stream digitally copyrighted music or on-demand music by joining a subscription. This is done by having songs that are being played point to a reference to a song on the streaming service’s database, which allows for better space efficiency than copying the song into the user’s device. Each song also holds metadata (or “data about data”) for each song, as having proper accreditation is necessary to ensure artists and songwriters receive proper compensation. Read more about what metadata is and why it matters here.
For this assignment, you will assume that the database is centralized in the music folder and that each of the music objects holds a “link” to each song a user may add to their playlist. Therefore, playlists (which are implemented using circular linked lists) can be flexibly created by having a reference to the song object rather than storing the song itself. Once the implementation of the music library is complete, you will even be able to play the playlists you create!
If you would like more songs to play than the songs provided in the folder, please download our full music library here: https://rutgers.box.com/s/i8emeh0nyz21q7hdzjenpky95c7bmse0
The assignment uses:
- an ArrayList to hold all the playlists in a library.
- a Circular Linked List to hold all the songs in a playlist.
Implementation
Overview of files provided
- Song: holds a song’s information.
- PlaylistLibrary: holds all of the methods to be written and that will be tested when running the implementation of the music library. Edit the empty methods with your solution, but DO NOT edit the provided ones or the methods signatures of any method. This is the file you submit.
- Driver: A tool to test your Library implementation interactively. You are free to use this driver to test all of your methods. Feel free to edit this class, as it is provided only to help you test. It is not submitted and/or graded.
- StdRandom: contains the StdRandom.uniformInt(n) method that you will use in the method that shuffles the playlist.
- StdAudio: used to play the songs in the playlist once the implementation of the Library is complete.
- StdIn and StdOut, which are used by the driver. Do not edit these classes.
- Multiple CSV files. Feel free to edit them or even make new ones to help test your code. They are not submitted.
- .wav files contained in the songs folder. These are referenced by the song objects, and will be played when playPlaylists() is called.
- We have currently provided you with the 2010 music files. To access the rest of the music files, download the music library we use for this assignment here: https://rutgers.box.com/s/i8emeh0nyz21q7hdzjenpky95c7bmse0
- Add the provided year folders into the songs folder.
PlaylistLibrary.java
- DO NOT add new import statements.
- DO NOT change any of the method’s signatures.
- You are allowed to create helper methods if needed, but please ensure they are private (encapsulation!).
The class contains:
- songLibrary is an ArrayList of Playlists that holds various playlists.
- provided methods that are used by the driver and empty methods you are expected to write your code in.
Methods to be implemented by you:
1. createPlayList
This method takes the data from an input csv file, and creates a playlist from it.
To complete this method:
- Create a new Playlist object.
- Open the file.
- Declare a SongNode reference that will refer to the last song of the circular linked list.
- While there are still lines in the input file:
- read a song from the file
- Create a Song object with the information read from the file.
- Create a SongNode object that holds the Song object from step 4.2.
- Insert the SongNode from step 4.3 to the END of the circular linked list (use the reference from step 3).
- Increase the count of the number of songs already in the circular linked list
- Return the Playlist object from step 1, that includes both the SongNode object from step 3 and the number of songs.
If the playlist is empty, return a Playlist object with null in the last field, and 0 as its size.
You have been provided some input files to test this method (playlist1.csv, playlist2.csv, playlist3.csv, playlist4.csv). The format is as follows:
- One line for each song containing song name, artist, year, popularity, link (comma separated)
Use the StdIn library to read from a file:
StdIn.setFile(filename)
opens a file to be read
To read one song do:String[] data = StdIn.readLine().split(",");
String name = data[0];
String artist = data[1];
int year = Integer.parseInt(data[2]);
int pop = Integer.parseInt(data[3]);
String link = data[4];
The input file has songs in decreasing popularity order; so the list should also be kept in this order. DO NOT implement a sorting algorithm, there is no need.
- Submit PlaylistLibrary.java with this method completed under Early Submission to receive extra credit.
Use the pre-implemented addPlaylist() method to test this method. Add the playlist at index 0 (to represent this will be the playlist in the first position). This is the expected output for playlist1.csv:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-7.58.07-PM.png)
addPlaylist
This method adds a playlist to the library.
- This method is implemented for you
- Write createPlaylist() to make this method work
removePlaylist
This method removes a playlist from the library.
- This method is implemented for you
2. addAllPlaylists
This method takes an array of filenames, where each file contains information for one playlist, and adds each playlist to the library.
To complete this method:
- Initialize songLibrary to be a new ArrayList of playlists with the default length.
- For each of the playlists in the array of filenames, call addPlaylist() at their respective index.
NOTES
- The playlist will have the same index in songLibrary as it has in the filenames array. For example if the playlist is being created from the filename[i] it will be added to songLibrary[i].
- The first playlist is at index 0, the second playlist is at index 1, and so forth.
This is the expected output for playlist1.csv, playlist2.csv, and playlist3.csv:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-8.06.47-PM.png)
3. insertSong
- The first node of the circular linked list is at position 1, the second node is at position 2 and so forth.
- Inserting at position 1 means the song will come first in the playlist, 2 means it will come second, etc.
- The playlist is specified by playlistIndex. The playlistIndex is the index of the playlist in the songLibrary. The first one is at index 0 (zero).
Return true if the song can be inserted at the given position in the specified playlist (and thus has been added to the playlist), false otherwise (and the song will not be added).
If the song has been added to the playlist, increase the size of the corresponding playlist by one.
NOTES:
- A song cannot be inserted to the playlist if the position is either less than 1
- A song can be inserted to a playlist of n Songs at position n+1, it will be inserted at the end of the playlist.
- REMEMBER: a circular linked list has a reference to the LAST node in the list, and that node points to the front.
This is the expected output from inserting the first song of playlist2.csv to the playlist generated from playlist1.csv, at position 3:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-8.14.25-PM.png)
4. removeSong
- The playlist is specified by playlistIndex. The playlistIndex is the index of the playlist in the songLibrary. The first one is at index 0 (zero).
Return true if the song was found and removed from the specified playlist, or false otherwise (leaving the playlist unmodified).
To find the song in the playlist, make sure to traverse the linked list and use .equals(): (song_to_remove).equals(current_song)
If the song has been removed from the playlist, decrease the size of the corresponding playlist by one.
- REMEMBER: the reference to a circular linked list refers to the LAST node in the list, and that node points to the front.
This is the expected output from removing Bad Romance from the playlist generated from playlist1.csv:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-8.18.41-PM.png)
5. reversePlaylist
This method reverses the specified playlist.
The next
fields of each node in the circular linked list are to be changed so that they point to the SongNode that came before it.
After the list is reversed, the playlist located at playlistIndex will reference the first SongNode in the original playlist (the new last node).
NOTES
- The playlistIndex is the index of the playlist in the songLibrary. The first one is at index 0 (zero).
- REMEMBER: the pointer to a circular linked list points to the LAST item in the list, and that item points to the front.
This is the expected output from reversing the playlist generated from playlist1.csv:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-8.20.26-PM.png)
6. mergePlaylists
This method merges two playlists.
- Both playlists have songs in decreasing popularity order. The resulting playlist will also be in decreasing popularity order.
This is done with the following procedure:
- Identify which playlist has the lower playlistIndex
- Declare a SongNode reference that will point to the last node of the merged playlist.
- While both playlists are not empty, compare the heads of both playlists for the higher popularity index.
- Place this song at the end of the merged playlist, and delete this song from the original playlist.
- Once a playlist is empty, append the non-empty playlist to the end of the merged playlist.
- Assign the merged playlist to library position with the lower playlistIndex, and delete the playlist at the higher playlistIndex.
You may assume both playlists are already in decreasing popularity order. If two songs from different playlists have the same popularity, add the song from the playlist with the lower playlistIndex first.
Once the playlists have been merged, the merged playlist is expected to be stored in the playlist at the lower playlistIndex, and the playlist at the higher playlistIndex is expected to be removed using the removePlaylist() method.
NOTES
- Remember that the lower playlistIndex should hold the new merged playlist, and the higher playlistIndex should be removed. DO NOT assume that playlistIndex1 is necessarily less than playlistIndex2.
- DO NOT implement a sorting algorithm, as both playlists are already in decreasing popularity order.
- Keep in mind that the playlists may be empty.
- REMEMBER: the pointer to a circular linked list points to the LAST item in the list, and that item points to the front.
This is the expected output from merging the playlists generated from playlist1.csv and playlist2.csv:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-8.31.36-PM.png)
7. shufflePlaylist
This method shuffles a specified playlist. It does it using the following procedure:
- Create a new playlist to store the shuffled playlist in.
- While the size of the playlist is not 0 (zero), randomly generate a number using StdRandom.uniformInt(size + 1).
- Remove the corresponding node from the original playlist and insert it into the END of the new playlist (1 being the front of the list, 2 being the second node, etc).
- Update the old playlist with the new shuffled playlist.
NOTES
- Notice that the driver is setting a seed for the random number generator. The seed value is 2023.
This is the expected output from shuffling the playlist generated from playlist1.csv:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-8.36.32-PM.png)
Challenge – sortPlaylist (0 points)
This method DOES NOT count towards this assignment’s grade.
This method sorts a playlist using an O(n log n) sort (such as merge sort). It takes a playlist at the corresponding playlist index and sets it in decreasing popularity order.
If you choose to perform merge sort (which is recommended), we suggest first turning the circular linked list into a singly linked list, performing merge sort on this new linked list, then linking the end of the sorted linked list back to the head to create the circular linked list once again.
NOTES
- Please practice implementing merge sort (or an alternative linearithmic sort)
This is the expected output from sorting the playlist after shuffling playlist1.csv:
![](https://ds.cs.rutgers.edu/wp-content/uploads/sites/131/2023/09/Screenshot-2023-09-29-at-8.38.13-PM.png)
Implementation Notes
- YOU MAY ONLY update the methods with the “WRITE YOUR CODE HERE” comment.
- COMMENT OUT all print statements you have written from PlaylistLibrary.java before submission
- DO NOT add any instance variables to the PlaylistLibrary class.
- DO NOT change any of the method signatures.
- DO NOT add any public methods to the PlaylistLibrary class.
- DO NOT add/rename the project or package statements.
- DO NOT change the class PlaylistLibrary name.
- YOU MAY add private methods to the PlaylistLibrary class.
- DO NOT use System.exit()
VSCode Extensions
You can install VSCode extension packs for Java. Take a look at this tutorial. We suggest:
Importing VSCode Project
- Download MusicPlaylist.zip from Autolab Attachments.
- Unzip the file by double clicking.
- Open VSCode
- Import the folder to a workspace through File > Open
Executing and Debugging
- You can run your program through VSCode or you can use the Terminal to compile and execute. We suggest running through VSCode because it will give you the option to debug.
- How to debug your code
- If you choose the Terminal:
- first navigate to MusicPlaylist directory/folder
- to compile: javac -d bin src/music/*.java
- to execute: java -cp bin music.Driver
- first navigate to MusicPlaylist directory/folder
Before submission
Collaboration policy. Read our collaboration policy here.
Submitting the assignment. Submit PlaylistLibrary.java separately via the web submission system called Autolab. To do this, click the Assignments link from the course website; click the Submit link for that assignment.
Getting help
If anything is unclear, don’t hesitate to drop by office hours or post a question on Piazza.
- Post your questions on Piazza (Canvas -> Piazza)
- Find instructors and head TAs office hours here
- Find tutors office hours on Canvas -> Tutoring -> RU CATS
- In addition to office hours we have the CAVE (Collaborative Academic Versatile Environment), a community space staffed with lab assistants which are undergraduate students further along the CS major to answer questions.
Problem by Jeremy Hui and Vian Miranda.