/* * main.c * Author: Kevin Cooper * Date: 16 Oct 13 * Description: Tests the MyMath functions to simulate the rolling average of several data points */ int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer int i ; avgArray_t test = buildMovingAverage(N_AVG_SAMPLES); int array[10] = {45, 42, 41, 40, 43, 45, 46, 47, 49, 45}; volatile int junk=0; for( i =0;i < 10;i++){ addSample(&test, array[i]); junk = movingAverage(&test); } junk = maxValue(&test); junk = minValue(&test); junk = range(&test); return 0; }
Rhythm::FeatureSet Rhythm::getRemainingFeatures() { FeatureSet output; int frames = intensity.size(); if (frames == 0) return output; // find envelope by convolving each subband with half-hanning window vector<vector<float> > envelope; halfHannConvolve(envelope); // find onset curve by convolving each subband of envelope with canny window vector<float> onset; cannyConvolve(envelope, onset); // normalise onset curve vector<float> onsetNorm; normalise(onset, onsetNorm); // push normalised onset curve Feature f_onset; f_onset.hasTimestamp = true; for (unsigned i = 0; i < onsetNorm.size(); i++) { f_onset.timestamp = Vamp::RealTime::frame2RealTime(i * m_stepSize, m_sampleRate); f_onset.values.clear(); f_onset.values.push_back(onsetNorm.at(i)); output[0].push_back(f_onset); } // find moving average of onset curve and difference vector<float> onsetAverage; vector<float> onsetDiff; movingAverage(onsetNorm, average_window, threshold, onsetAverage, onsetDiff); // push moving average Feature f_avg; f_avg.hasTimestamp = true; for (unsigned i = 0; i < onsetAverage.size(); i++) { f_avg.timestamp = Vamp::RealTime::frame2RealTime(i * m_stepSize, m_sampleRate); f_avg.values.clear(); f_avg.values.push_back(onsetAverage.at(i)); output[1].push_back(f_avg); } // push difference from average Feature f_diff; f_diff.hasTimestamp = true; for (unsigned i = 0; i < onsetDiff.size(); i++) { f_diff.timestamp = Vamp::RealTime::frame2RealTime(i * m_stepSize, m_sampleRate); f_diff.values.clear(); f_diff.values.push_back(onsetDiff.at(i)); output[2].push_back(f_diff); } // choose peaks vector<int> peaks; findOnsetPeaks(onsetDiff, peak_window, peaks); int onsetCount = (int) peaks.size(); // push peaks Feature f_peak; f_peak.hasTimestamp = true; for (unsigned i = 0; i < peaks.size(); i++) { f_peak.timestamp = Vamp::RealTime::frame2RealTime(peaks.at(i) * m_stepSize, m_sampleRate); output[3].push_back(f_peak); } // calculate average onset frequency float averageOnsetFreq = (float) onsetCount / (float) (frames * m_stepSize / m_sampleRate); Feature f_avgOnsetFreq; f_avgOnsetFreq.hasTimestamp = true; f_avgOnsetFreq.timestamp = Vamp::RealTime::fromSeconds(0.0); f_avgOnsetFreq.values.push_back(averageOnsetFreq); output[4].push_back(f_avgOnsetFreq); // calculate rhythm strength float rhythmStrength = findMeanPeak(onset, peaks, 0); Feature f_rhythmStrength; f_rhythmStrength.hasTimestamp = true; f_rhythmStrength.timestamp = Vamp::RealTime::fromSeconds(0.0); f_rhythmStrength.values.push_back(rhythmStrength); output[5].push_back(f_rhythmStrength); // find shift range for autocor float firstShift = (int) round(60.f / max_bpm * m_sampleRate / m_stepSize); float lastShift = (int) round(60.f / min_bpm * m_sampleRate / m_stepSize); // autocorrelation vector<float> autocor; autocorrelation(onsetDiff, firstShift, lastShift, autocor); Feature f_autoCor; f_autoCor.hasTimestamp = true; for (float shift = firstShift; shift < lastShift; shift++) { f_autoCor.timestamp = Vamp::RealTime::frame2RealTime(shift * m_stepSize, m_sampleRate); f_autoCor.values.clear(); f_autoCor.values.push_back(autocor.at(shift - firstShift)); output[6].push_back(f_autoCor); } // find peaks in autocor float percentile = 95; int autocorWindowLength = 3; vector<int> autocorPeaks; vector<int> autocorValleys; findCorrelationPeaks(autocor, percentile, autocorWindowLength, firstShift, autocorPeaks, autocorValleys); // find average corrolation peak float meanCorrelationPeak = findMeanPeak(autocor, autocorPeaks, firstShift); Feature f_meanCorrelationPeak; f_meanCorrelationPeak.hasTimestamp = true; f_meanCorrelationPeak.timestamp = Vamp::RealTime::fromSeconds(0.0); f_meanCorrelationPeak.values.push_back(meanCorrelationPeak); output[7].push_back(f_meanCorrelationPeak); // find peak/valley ratio float meanCorrelationValley = findMeanPeak(autocor, autocorValleys, firstShift) + 0.0001; Feature f_peakValleyRatio; f_peakValleyRatio.hasTimestamp = true; f_peakValleyRatio.timestamp = Vamp::RealTime::fromSeconds(0.0); f_peakValleyRatio.values.push_back( meanCorrelationPeak / meanCorrelationValley); output[8].push_back(f_peakValleyRatio); // find tempo from peaks float tempo = findTempo(autocorPeaks); Feature f_tempo; f_tempo.hasTimestamp = true; f_tempo.timestamp = Vamp::RealTime::fromSeconds(0.0); f_tempo.values.push_back(tempo); output[9].push_back(f_tempo); return output; }
movingAverage::movingAverage() { movingAverage(1,0); }
int *findPossibleBlinks( int *num_blinks, const NUMTYPE *channel, int len_channel, const BlinkParams *params ) { unsigned int i, j, max_level, len_coef, lengths[8]; int cor_length, temp_start, len_template; NUMTYPE *coefs, *chan_a, *chan_d, *chan_r, *thresh, *templ; NUMTYPE min; int above, min_index, num_indices, *indices, steps_1, index, *blinks; NUMTYPE *cors; // Pull out the parameters that we'll be using. NUMTYPE t_1 = params->t_1; NUMTYPE t_cor = params->t_cor; // Make sure that we are capable of taking the 5th, 6th, and 7th level // decompositions. max_level = wavedecMaxLevel( len_channel, COIF3.len_filter ); if (max_level < 7) { fprintf( stderr, "Channel too short for processing!\n" ); (*num_blinks) = 0; return NULL; } ////////////////////////////////////////////////////////////////////////////// // Allocate memory. ////////////////////////////////////////////////////////////////////////////// len_coef = wavedecResultLength( len_channel, COIF3.len_filter, 7 ); coefs = (NUMTYPE*) malloc( sizeof(NUMTYPE) * len_coef ); chan_a = (NUMTYPE*) malloc( sizeof(NUMTYPE) * len_channel ); chan_d = (NUMTYPE*) malloc( sizeof(NUMTYPE) * len_channel ); chan_r = (NUMTYPE*) malloc( sizeof(NUMTYPE) * len_channel ); thresh = (NUMTYPE*) malloc( sizeof(NUMTYPE) * len_channel ); ////////////////////////////////////////////////////////////////////////////// // Extract the appropriate approximation and detail signals. ////////////////////////////////////////////////////////////////////////////// wavedec( coefs, lengths, channel, len_channel, COIF3, 7 ); wrcoef( chan_a, coefs, lengths, 8, RECON_APPROX, COIF3, 3 ); // Sum the enveloped 5th, 6th, and 7th level details. for (i = 0; i < len_channel; i++) { chan_d[i] = 0.0; } for (i = 5; i <= 7; i++) { wrcoef( chan_r, coefs, lengths, 8, RECON_DETAIL, COIF3, i ); envelope( chan_r, len_channel ); for (j = 0; j < len_channel; j++) { chan_d[j] += chan_r[j]; } } ////////////////////////////////////////////////////////////////////////////// // Generate the first guess at eyeblink locations. ////////////////////////////////////////////////////////////////////////////// // Compute the moving average threshold. movingAverage( thresh, chan_d, len_channel ); for (i = 0; i < len_channel; i++) { thresh[i] += t_1; } // Find the minimums of the original channel between rising/falling edge pairs // of the enveloped channel details. above = 0; num_indices = 0; min = INFINITY; min_index = 0; indices = NULL; for (i = 1; i < len_channel; i++) { // Check to see if we crossed the threshold. if (!above && chan_d[i] > thresh[i] && chan_d[i-1] <= thresh[i-1]) { above = 1; // Reset the 'min' value so that we can find a new minimum. min = INFINITY; } else if (above && chan_d[i] < thresh[i] && chan_d[i-1] >= thresh[i-1]) { above = 0; // We just found the falling edge of a pair. Record the index of the // minimum value that we found within the pair. num_indices++; indices = (int*) realloc( indices, sizeof(int) * num_indices ); indices[num_indices-1] = min_index; } // If we're above the threshold, keep track of the minimum value that we // see. if (above) { if (min > chan_a[i]) { min = chan_a[i]; min_index = i; } } } ////////////////////////////////////////////////////////////////////////////// // Refine our first guess, getting our final guess at eyeblink locations. ////////////////////////////////////////////////////////////////////////////// cors = (NUMTYPE*) malloc( sizeof(NUMTYPE) * num_indices ); // Generate the eyeblink template to correlate with the eyeblink locations. templ = getTemplate( &steps_1, &len_template, params ); // Calculate the correlations of the original channel around the minimum // points. (*num_blinks) = num_indices; for (i = 0; i < num_indices; i++) { index = indices[i] - steps_1; temp_start = 0; cor_length = len_template; // Make sure the correlation function will not access beyond the bounds // of our arrays. if (index < 0) { temp_start = -index; cor_length = len_template + index; index = 0; } else if (index + len_template >= len_channel) { cor_length = len_template - (index + len_template - len_channel); } cors[i] = correlate( chan_a + index, templ + temp_start, cor_length ); // Mark for elimination the indices with correlations below the threshold. if (cors[i] < t_cor) { indices[i] = -1; (*num_blinks)--; } } // If we still have blinks after all this, allocate memory for them. if ((*num_blinks) == 0) { blinks = NULL; } else { blinks = (int*) malloc( sizeof(int) * (*num_blinks) ); index = 0; for (i = 0; i < num_indices; i++) { if (indices[i] > 0) { blinks[index] = indices[i]; index++; } } } ////////////////////////////////////////////////////////////////////////////// // Clean up and return. ////////////////////////////////////////////////////////////////////////////// free( indices ); free( cors ); free( coefs ); free( chan_a ); free( chan_d ); free( chan_r ); free( thresh ); free( templ ); return blinks; }