CMSC 246 Systems Programming
Spring 2021
Assignment #7: : Function pointers to Music
In this assignment you will be working with an excerpt from the Million Song Dataset, a freely-available collection of audio features and metadata for a million contemporary popular music tracks.
The file that you will be working with (/home/gtowell/Public/246/a07/musicsampleCSV.csv) contains many records. (There is also a smaller file /home/gtowell/Public/246/a07/musicsampleminiCSV.csv that might be easier to use during development.) Each record in musicsampleCSV.csv contains the following information for a recorded song, in comma-separated fields:
title: song title
artist name: name of artist
duration: duration of the track in seconds
release: album name from which the track was taken
start_of_fade_out: start time of the fade out, in seconds, at the end of the song
tempo: tempo in BPM according to The Echo Nest
terms: terms describing the song genre according to The Echo Nest
year: year recorded
Example:
Never Gonna Give You Up,Rick Astley,211.69587,Big Tunes - Back 2 The 80s,198.536,113.359,dance pop,1987
The data has been "cleaned" so that there are entries of the correct type for each field in each record. There are also no extra commas; the only commas are field separators. However, there may be incorrect data in some fields; sorry.
Use appropriate data types for each field. Note that some of the name, artist, or release string values are very long so in your reader function, you will want something like:
#define LONGLINE 512
FILE* f = ...
char line[LONGLINE];
while (fgets(line, LONGLINE, f))
{ ... }
512 is sufficient to guarantee that every line is read in its entirity.
Requirements
- It is OK -- even expected -- that you will re-use your ArrayList from the previous assignment. However, this version of your ArrayList must be truly generic. This is, it must be able to store any struct, not just the struct you built for holding music. If you really hate your ArrayList implementation, you can start with mine. It is available at /home/gtowell/Public/246/a07/arrayList.[ch]. Note that this implementation is undocumented. If you use my code, you must add documentation. Be sure to also add proper attribution.
- Everything that you store should be dynamically sized and allocated. By everything I mean every char array in the program other that ones for reading from a file (as above) or directly related to user input should be no bigger than it needs to be. Your ArrayList can have some unused space; there should be no other wasted space in your data storage
- The program, on user selection, must be able to present the top N music items according the to the user selected sort order and user specified value of N
- The program must use qsort to sort and be able to sort on at least title, artist, and duration. (More that that just gets really repetitive.)
- The program must, on user selection, be able to search for a match to a search criteria. The match should be an exact match.
- The program must use a binary search function for all searches. That function should take, as an arguement, a comparison function. Hence, there should NOT be a big switch statement inside the binary search function. (You may need a big switch statement in the call to your binary search.) Hence, the prototype for you binary search function should look something like:
/**
* a binary search implementation that takes a passed in comparison function
* @param target -- a pointer to the thing to be found
* @param arrayList -- a pointer to the ArrayList structure that hold the music database
* @param compar -- a pointer to the comparison function to be used in the binary search.
* @return A pointer to a Music struct, or null if a match could not be found.
**/
Music* find(void* target, ArrayList* arrayList, int (*compar)(const void *, const void *)) {
You need not use this exact prototype, but you are certainly allowed to do so.
- The program must interact with the user in a style similar to the one shown below. The program need not exactly match the trace below (my approach could certainly be improved) but you must follow the spirit
- When searching, you need only find one item -- assuming one item exists. There may be more than one item. You are only required to find one.
- The program must be split into multiple files. The split must make sense from an object-oriented viewpoint. That is imagine the program consists of a set of classes and a driver function. .c files implement classes. .h files are the public methods of the classes. Try to achieve standard OO goals; abstraction, encapsulations, modularity, etc. (Private data members are certainly unachievable, you can even write get and set accessors, but other forms of encapsulation can be used.)
- You must include a makefile capable of building your program. In addition, you make file should have a clean rule.
- While finishing, the program must free up all dynamically allocated memory. (use valgrind)
Sample User Interaction
In the sample below, input from the user is indicated by lines starting with "****".
Sort by: 1: Title
: 2: Artist
: 3: Duration
99 -- quit
****2
How many items should do you want to see?
<0 show all:
==0 search for a particular record
****3
2007 ALB:Myth Takes ART:!!! LEN: 144.0
1995 ALB:The Man ART:"Clarence ""Gatemouth"" Brown" LEN: 333.4
1976 ALB:Fill It! - I Love the Fifties ART:"Dave ""Baby"" Cortez" LEN: 125.6
Sort by: 1: Title
: 2: Artist
: 3: Duration
99 -- quit
****2
How many items should do you want to see?
<0 show all:
==0 search for a particular record
****0
Find A record what:
****Devo
1993 ALB:Q: Are We Not Men? A: We Are Devo / Devo Live ART:Devo LEN: 175.3
Sort by: 1: Title
: 2: Artist
: 3: Duration
99 -- quit
****99
What to submit:
- README file. This is a file literally named README. This file should follow the format of https://cs.brynmawr.edu/cs246/README.txt Your readme file should clearly state how to compile and run you program.
- All program files for this task.
- A script showing the use of your code This should illustrate all of the apps functions. It should all illustrate the app on all fields in the dataset. (However, it need not be all functions on all fields.)
- Your makefile
- Include in your README a brief reflection about what went well or poorly
- Do NOT include an executable files or intermediate compilation results (.o files).
How to submit
- Do not use the submit script
- Use tar to create an compressed archive of your submission. Name the tar file something clever like YOURLOGIN_qwe_7.tar.gz where "qwe" is a set of three "secret characters".
- Copy your tar file to /home/gtowell/submissions/spring2021/cmsc246/project7. Only I can get a directory listing of this directory so the three secret characters keeps other students from accidentally overwriting (before you get permission set as below), or reading, your work.
- Set permissions on your submission so that anyone can read but only you can write to the file. That way no one can accidentally overwrite your submission. If you do not allow anyone to read then I will not be able to read. This will result in a poor grade for the assignment (think zero).