/* syllable.c Simple Mandarin tone recognizer: syllable routines Jim Gilsinan IV gilsinan@post.harvard.edu http://www.fas.harvard.edu/~gilsinan/ Senior Thesis Harvard University 2000-2001 */ #include #include #include "tone.h" #include "syllable.h" // detect the number of syllables in a pitch track file, // given pointer to file, address to store count // returns array of offsets to syllables int * detect_syllables(FILE * in, int * syllable_count) { int count = 0, current_offset = 0, i; double current_pitch = 0; char line[MAXLINE]; int * offsets; rewind(in); // first count syllables while(!feof(in)) { // skip leading zeroes while(!current_pitch) { fgets(line, MAXLINE, in); sscanf(line, "%lf", ¤t_pitch); if (feof(in)) break; } count++; while(current_pitch) { fgets(line, MAXLINE, in); sscanf(line, "%lf", ¤t_pitch); } } // now get offsets count--; rewind(in); offsets = malloc(count * sizeof(int)); for(i = 0; i < count; i++) { // skip leading zeroes while(!current_pitch) { fgets(line, MAXLINE, in); sscanf(line, "%lf", ¤t_pitch); if (feof(in)) break; current_offset++; } offsets[i] = current_offset; while(current_pitch) { fgets(line, MAXLINE, in); sscanf(line, "%lf", ¤t_pitch); current_offset++; } } *syllable_count = count; return offsets; } // jump to the specified line in the pitch track file void syllable_seek (FILE * in, int offset) { int i; char line[MAXLINE]; rewind(in); for (i = 0; i < offset; i++) fgets(line, MAXLINE, in); return; } // get the derivative of a syllable pitch track, // given pitch track array, current length, address to store // derivative syllable void syllable_derivative (double * in, int len, double * out) { int i; for (i = 0; i < len - 1; i++) { out[i] = in[i+1] - in[i]; } out[len-1] = 0; return; } // make the syllable the standard length, // and normalize by dividing by standard deviation // given pitch track array, current length, address to store // standardized syllable void standardize_syllable (double * in, int len, double * out) { int i, int_part; double position, f_part; // standardize in time for (i = 0; i < STANDARD_LEN; i++) { position = ((double)i/STANDARD_LEN)*len; int_part = (int)position; f_part = position - int_part; if (int_part + 1 == len) out[i] = in[int_part]; else out[i] = in[int_part] * (1-f_part) + in[int_part + 1] * (f_part); } /* // normalize in space s = 0; for (i = 0; i < STANDARD_LEN; i++) // first get std deviation s += (fabsf(out[i]) * fabsf(out[i])); s /= STANDARD_LEN; for ( i = 0; i < STANDARD_LEN; i++) // divide by std dev out[i] /= s; */ return; } // normalize a syllable by subtracting the mean // pitch from each sample in the pitch track // arguments: pointer to pitch track array, length of array void normalize_syllable (double * in, int len) { double sample_mean = get_mean_pitch(in, len); int i; for (i = 0; i < len; i++) in[i] -= sample_mean; return; } // get the mean pitch of a syllable // arguments: pointer to pitch track array, length of array double get_mean_pitch ( double * in, int len ) { int i; double mean = 0; for ( i = 0; i < len; i++ ) mean += in[i]; mean /= len; return ( mean ); } // read a syllable from the specified file // arguments: file pointer, pointer in which to store read length, // syllable start offset // returns pitch track array double * get_syllable (FILE * in, int * len, int syllable_offset) { int i, sample_count = 0; double * out; double current_pitch = 1; char line[MAXLINE]; // seek to syllable syllable_seek(in, syllable_offset); // first get number of samples in pitch track while ( current_pitch ) { sample_count++; fgets(line, MAXLINE, in); sscanf(line, "%lf", ¤t_pitch); } sample_count--; // allocate an array for 'em out = malloc(sample_count * sizeof(double)); // go back to the beginning of syllable // and actually read the pitches this time syllable_seek(in, syllable_offset); for (i = 0; i < sample_count; i++) { fgets(line, MAXLINE, in); sscanf(line, "%lf", &out[i]); } *len = sample_count; return (out); }