/* * Reads audio data as decimal integers from standard input and outputs * the intervals corresponding to tracks. Tracks are maximal intervals * of samples that contain no long runs of low values. The starting * and ending point of each track is written to standard output. */ #include #include #include "track_list.h" void write_track(int i, int start, int end, int samples[]); /* states for the FSM: * GAP = in the gap between tracks * TRACK = in a track * ZEROS = in a run of zeros (or low values at or below the threshold) */ typedef enum {GAP, TRACK, ZEROS} state; int main(int argc, char **argv) { // the current state of the FSM state curr = GAP; // the maximum value to count as silence const int threshold = 5; // the sample rate of the audio being read const int sample_rate = 44100; // the minimum length of a gap between tracks, in seconds and samples const double min_gap_sec = 0.0001; const int min_gap_samples = (int)(sample_rate * min_gap_sec); // the starting and ending points of the most recent track read or being read int start, end; // the starting and ending points of all the tracks track_list l; track_list_init(&l); const int SAMPLES_INITIAL_SIZE = 4; // make the array int *samples = malloc(sizeof(int) * SAMPLES_INITIAL_SIZE); int samples_capacity = SAMPLES_INITIAL_SIZE; // the index of the currently read sample int count = 0; // the current sample value int value; while (scanf("%d", &value) > 0) { switch (curr) { case GAP: if (abs(value) > threshold) { // end of gap; now reading track so remember start start = count; curr = TRACK; } break; case TRACK: if (abs(value) <= threshold) { // read a low value, start counting consecutive low values // and record possible end of current track end = count - 1; curr = ZEROS; } break; case ZEROS: if (abs(value) > threshold) { // read a high value; just a pause in the track so read some more curr = TRACK; } else if (count - end >= min_gap_samples) { // read enough consecutive low values to consider track over; // output interval for last track and continue to read through gap curr = GAP; track_list_add(&l, start, end); } } if (count == samples_capacity) { int *bigger = malloc(count * 2 * sizeof(int) ); if (bigger == NULL) { fprintf(stderr, "%s: out of memory\n", argv[0]); return 1; } for (int i = 0; i < count; i++) { bigger[i] = samples[i]; } free(samples); samples = bigger; samples_capacity *= 2; } samples[count] = value; count++; } // output interval for last track if input ended in the middle of a track if (curr == TRACK) { end = count - 1; } if (curr == TRACK || curr == ZEROS) { // this section of code has been repeated -- a good candidate // to make into a function! track_list_add(&l, start, end); } for (int i = 0; i < l.count; i++) { write_track(i + 1, l.starts[i], l.ends[i], samples); } // clean up dynamically allocated memory free(samples); track_list_destroy(&l); } /** * Writes the given interval from the given array to standard output. * The interval is given by the indices of the endpoints. The output * format is a header followed by all the values in the interval * on separate lines. * * @param i the index of the track * @param start an inndex into samples * @param end an index into samples >= start * @param samples an array integers */ void write_track(int i, int start, int end, int samples[]) { printf("=== TRACK %d ===\n", i); printf("%d\n", end - start + 1); for (int s = start; s <= end; s++) { printf("%d\n", samples[s]); } }