diff options
Diffstat (limited to 'comp1511/cs_beats/beats.c')
| -rw-r--r-- | comp1511/cs_beats/beats.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/comp1511/cs_beats/beats.c b/comp1511/cs_beats/beats.c new file mode 100644 index 0000000..2f26898 --- /dev/null +++ b/comp1511/cs_beats/beats.c @@ -0,0 +1,412 @@ +// Assignment 2 20T1 COMP1511: CS bEats +// beats.c +// +// The purpose of this program is to categorise music input. +// +// Version 1.0.0: Assignment released. +// Version 1.0.1: Fix default return value of add_musical_note_to_beat. + +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#include "beats.h" + +struct track { + struct beat *head; + struct beat *cur; +}; + +struct beat { + struct note *notes; + struct beat *next; +}; + +struct note { + int oct; + int key; + struct note *next; +}; + +//////////////////////////////////////////////////////////////////////// +// User Defined Functions // +//////////////////////////////////////////////////////////////////////// + +// Returns a value representing the pitch. +static int get_pitch(const int octave, const int key) { + return (octave * 12) + (key); +} + +// Return a malloced beat with fields initialised. +struct beat *create_beat() { + Beat new_beat = malloc(sizeof(struct beat)); + assert(new_beat != NULL); + + new_beat->next = NULL; + new_beat->notes = NULL; + + return new_beat; +} + +// Returns the tail of a note linked list. +static struct note *get_note_tail(struct note *nhead) { + if (nhead == NULL) { + return NULL; + } + struct note *ret = nhead; + while (ret->next != NULL) { + ret = ret->next; + } + return ret; +} + +// Returns the tail of a beat linked list. +static struct beat *get_beat_tail(struct beat *bhead) { + if (bhead == NULL) { + return NULL; + } + struct beat *ret = bhead; + while (ret->next != NULL) { + ret = ret->next; + } + return ret; +} + +// Returns a malloced Note with fields initialised. +static struct note *create_note() { + struct note *ret = malloc(sizeof(struct note)); + assert(ret != NULL); + + ret->oct = 0; + ret->key = 0; + ret->next = NULL; + return ret; +} + +// Inserts a note into a linked list of notes before the target note. +static void insert_note_before(struct beat *beat, struct note *note, + struct note *target) { + if (beat->notes == target) { + beat->notes = note; + note->next = target; + return; + } + for (struct note *i = beat->notes; i != NULL; i = i->next) { + if (i->next == target) { + i->next = note; + note->next = target; + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// Stage 1 Functions // +//////////////////////////////////////////////////////////////////////// + +// Add a note to the end of a beat. +int add_note_to_beat(struct beat *const beat, const int oct, const int key) { + if (oct < 0 || oct >= 10) { + return INVALID_OCTAVE; + } + if (key < 0 || key >= 12) { + return INVALID_KEY; + } + + struct note *ntail = get_note_tail(beat->notes); + if (ntail != NULL) { + if (get_pitch(oct, key) <= get_pitch(ntail->oct, ntail->key)) { + return NOT_HIGHEST_NOTE; + } + } + struct note *new_note = create_note(); + new_note->oct = oct; + new_note->key = key; + new_note->next = NULL; + + if (ntail == NULL) { + beat->notes = new_note; + } else { + ntail->next = new_note; + } + return VALID_NOTE; +} + +// Print the contents of a beat. +void print_beat(struct beat *const beat) { + if (beat == NULL) { + return; + } + if (beat->notes == NULL) { + printf("\n"); + return; + } + for (struct note *i = beat->notes; i != NULL; i = i->next) { + printf("%d ", i->oct); + if (i->key >= 10) { + printf("%d", i->key % 12); + } else { + printf("%d%d", i->key / 12, i->key % 12); + } + if (i->next) { + printf(" | "); + } + } + printf("\n"); +} + +// Count the number of notes in a beat that are in a given octave. +int count_notes_in_octave(struct beat *const beat, int oct) { + if (beat->notes == NULL) { + return 0; + } + int notes = 0; + for (struct note *i = beat->notes; i != NULL; i = i->next) { + if (i->oct == oct) { + ++notes; + } + } + return notes; +} + +//////////////////////////////////////////////////////////////////////// +// Stage 2 Functions // +//////////////////////////////////////////////////////////////////////// + +// Return a malloced track with fields initialized. +struct track *create_track(void) { + struct track *ret = malloc(sizeof(struct track)); + ret->head = NULL; + ret->cur = NULL; + return ret; +} + +// Add a beat after the current beat in a track. +void add_beat_to_track(struct track *track, struct beat *beat) { + if (track->cur != NULL) { // this behaviour may be unwanted + if (track->cur->next != NULL) { + beat->next = track->cur->next; + track->cur->next = beat; + } else { + track->cur->next = beat; + } + } else { + if (track->head == NULL) { + track->head = beat; + } else { + beat->next = track->head; + track->head = beat; + } + } +} + +// Set a track's current beat to the next beat. +int select_next_beat(struct track *track) { + if (track->cur == NULL) { + if (track->head == NULL) { + return TRACK_STOPPED; + } else { + track->cur = track->head; + return TRACK_PLAYING; + } + } else { + if (track->cur->next == NULL) { + track->cur = NULL; + return TRACK_STOPPED; + } else { + track->cur = track->cur->next; + return TRACK_PLAYING; + } + } +} + +// Print the contents of a track. +void print_track(struct track *track) { + if (track->head == NULL) { + return; + } + int count = 1; + for (struct beat *i = track->head; i != NULL; i = i->next) { + if (i == track->cur) { + printf(">"); + } else { + printf(" "); + } + printf("[%d] ", count); + print_beat(i); + ++count; + } +} + +// Count beats after the current beat in a track. +int count_beats_left_in_track(struct track *track) { + int count = 0; + if (track == NULL || track->head == NULL) { + return count; + } + struct beat *i = track->cur; + if (i == NULL) { + i = track->head; + } + for (; i != NULL; i = i->next) { + ++count; + } + if (track->cur) { + --count; + } + return count; +} + +//////////////////////////////////////////////////////////////////////// +// Stage 3 Functions // +//////////////////////////////////////////////////////////////////////// + +// Free the memory of a beat, and any memory it points to. +void free_beat(struct beat *beat) { + if (beat == NULL) { + return; + } + if (beat->notes != NULL) { + struct note *i = beat->notes; + struct note *forwards = i->next; + while (i != NULL) { + forwards = i->next; + free(i); + i = forwards; + } + } + free(beat); +} + +// Free the memory of a track, and any memory it points to. +void free_track(struct track *track) { + if (track == NULL) { + return; + } + if (track->head != NULL) { + struct beat *i = track->head; + struct beat *forwards = i->next; + while (i != NULL) { + forwards = i->next; + free_beat(i); + i = forwards; + } + } + free(track); +} + +// Remove the currently selected beat from a track. +int remove_selected_beat(struct track *track) { + if (track->cur == NULL) { + return TRACK_STOPPED; + } + struct beat *backwards = NULL; + struct beat *forwards = NULL; + for (struct beat *i = track->head; i != NULL; i = i->next) { + if (i == track->cur) { + track->head = i->next; + forwards = i->next; + free_beat(track->cur); + break; + } else if (i->next == track->cur) { + backwards = i; + forwards = i->next->next; + free_beat(track->cur); + backwards->next = forwards; + break; + } + } + if (forwards == NULL) { + track->cur = NULL; + return TRACK_STOPPED; + } else { + track->cur = forwards; + return TRACK_PLAYING; + } +} + +//////////////////////////////////////////////////////////////////////// +// Stage 4 Functions // +//////////////////////////////////////////////////////////////////////// + +// Add note to beat, given its 'musical notation'. +int add_musical_note_to_beat(Beat beat, char *string) { + int oct = string[0] - '0'; + if (oct < 0 || oct > 9) { + return INVALID_MUSICAL_NOTE; + } + int key = 0; + switch (string[1]) { + case 'A': + key = 0; + break; + case 'B': + key = 2; + break; + case 'C': + key = 3; + break; + case 'D': + key = 5; + break; + case 'E': + key = 7; + break; + case 'F': + key = 8; + break; + case 'G': + key = 10; + break; + default: + return INVALID_MUSICAL_NOTE; + } + for (char *c = string + 2; *c != '\0'; ++c) { + if (*c == '#') { + ++key; + } else { + return INVALID_MUSICAL_NOTE; + } + } + int pitch = get_pitch(oct, key); + oct = pitch / 12; + key = pitch % 12; + struct note *tail = get_note_tail(beat->notes); + if (tail == NULL || get_pitch(tail->oct, tail->key) < pitch) { + add_note_to_beat(beat, oct, key); + return VALID_NOTE; + } + struct note *higher = NULL; + for (struct note *i = beat->notes; i != NULL; i = i->next) { + int iter_pitch = get_pitch(i->oct, i->key); + if (iter_pitch == pitch) { + return INVALID_MUSICAL_NOTE; + } else if (iter_pitch > pitch) { + higher = i; + break; + } + } + struct note *note = create_note(); + note->oct = oct; + note->key = key; + insert_note_before(beat, note, higher); + return VALID_NOTE; +} + +//////////////////////////////////////////////////////////////////////// +// Stage 5 Functions // +//////////////////////////////////////////////////////////////////////// + +// Cut a range of beats to the end of a track. +void cut_range_to_end(Track track, int range_length) { + printf("cut_range_to_end not implemented yet."); + return; +} + +// Reverse a list of beats within a range of a track. +int reverse_range(Track track, int range_length) { + printf("reverse_range not implemented yet."); + return 0; +} |
