view ofxPreciseOnsetDetectorOffline/PreciseOnsetDetectorOffline.cpp @ 6:eb29c6b6dff8

added pointer version of visualiser
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Sun, 19 Jan 2014 23:07:13 +0000
parents 93b9a9471011
children b1c13e8bec26
line wrap: on
line source
/*
 *  PreciseOnsetDetectorOffline.cpp
 *  ofxPreciseOnsetDetectionOffline
 *
 *  Created by Andrew Robertson on 25/12/2013.
 *  Copyright 2013 QMUL. All rights reserved.
 *
 */


//add a retrigger threshold

#include "PreciseOnsetDetectorOffline.h"

const bool printingOn = false;

PreciseOnsetDetectorOffline::PreciseOnsetDetectorOffline(){
	frameSize = 1024;
	hopSize = 512;
	preciseLocator.setup(frameSize);
	writeOutput = true;//write output to txt when loading file - stored at sample location as file
}

PreciseOnsetDetectorOffline::~PreciseOnsetDetectorOffline(){
	//delete infile;
}


int PreciseOnsetDetectorOffline::load(std::string filename){
	
	//name for output file is same dir and filename as aif/wav but with _preciseOnsets.txt added
	//eg 'song.wav' is 'song.wav_preciseOnsets.txt'
	
	return processAudioForBeatTimes(filename);
}



int PreciseOnsetDetectorOffline::processAudioForBeatTimes(std::string audiofile){
	//originally from BeatAnnotationViewer project

	dfValues.clear();
	onsetLocations.clear();
	onsetPositionFrames.clear();
	
	// static double frame[FRAMESIZE]; // to hold a single frame
	double buffer[frameSize];
	double dfval;
	
	for (int i = 0;i < frameSize;i++)
	{
		buffer[i] = 0;
	}
	
	//detfun = new df(1,(FRAMESIZE*2),0);
	
	// initialises with hopsize = 512, framesize = 1024, complex spectral difference DF and hanning window
	detectionFunction = new OnsetDetectionFunction();
	
    SNDFILE      *infile, *outfile ;	// define input and output sound files
	
    SF_INFO		sfinfo ;	// struct to hold info about sound file
    int			readcount ;	// counts number of samples read from sound file
    const char	*infilename =  audiofile.c_str();
	//"/Users/andrew/Music/Station To Station 2/3-03 Panic In Detroit (Live Nassau Coliseum '76).wav";//"ledzep.wav" ;	// input file name
	//   const char	*outfilename = "output.wav" ; // output file name

	
	// Open Input File
    if (! (infile = sf_open (infilename, SFM_READ, &sfinfo)))
    {   // Open failed
        printf ("Not able to open input file %s.\n", infilename) ;
        // Print the error message from libsndfile. 
        puts (sf_strerror (NULL)) ;
        return 1;
	} ;
	
	printf("opened '%s'\n", audiofile.c_str());
	loadedFilename = audiofile;
	//STEREO OKAY
	
	//HERE IS THE CLASSIC LOADING FILE CODE
	//DEALS WITH MORE THAN MONO
	int channels = sfinfo.channels;
	samples = sfinfo.frames;
	printf("Number of channels %i, samples %i\n", channels, samples);
	
	
	int blocksize = hopSize;//FRAMESIZE;	
	float buf [channels * blocksize] ;
	float frame[blocksize];
	
	int k, m;
	readcount = 1;
	int counter = 0;
	
	//DoubleVector d;
	while ((readcount = sf_readf_float (infile, buf, blocksize)) > 0){
		for (k = 0 ; k < readcount ; k++){	
			//d.clear();
			frame[k] = 0;
			
			for (m = 0 ; m < channels ; m++){
				frame[k] += buf[k*channels + 0];//sum the channels together
				//d.push_back(buf [k * channels + m]);
			}
			
			frame[k] /= channels;//average of the channels
		}
		
		//add to our buffer for pocessing
		for (int i = 0; i< frameSize-hopSize;i++)
		{
			buffer[i] = buffer[i+hopSize];
			buffer[i+hopSize] = frame[i];
		}
		
	//	for (int i = 0; i < frameSize; i++)
	//		printf("buffer[%i] %.5f\n", i, buffer[i]);
		
		dfval = detectionFunction->getDFsample(buffer);	// compute detection function sample
		
		dfValues.push_back(dfval);
		
		if (printingOn)
			printf("det val %i: %f\n", counter, dfval);
		
		if (peakProcess.peakProcessing(dfval)){
			
			onsetPositionFrames.push_back(counter);
			int precisesample = preciseLocator.findExactOnset(&buffer[0]);
			//so exact sample is
			int exactsample = (counter-1)*hopSize;//chunks in from beginning
			//as we have just added hopsize samples in, the beginning of the frame is -1 from counter
			exactsample += precisesample;
			//printf("PreciseSample %i, %i\n", precisesample, exactsample);
				
			
			onsetLocations.push_back(exactsample/44100.);
			
			if (printingOn)
				printf("BANG\n");
		}
		
		counter++;
		//printf("read %i samples\n", readcount);
		//was	sf_write_double(outfile, frame, readcount) ;
		
	}//end readcount
	//END STEREO OKAY
	
	// Close input file
    sf_close (infile);
	
	delete detectionFunction;
	detectionFunction = NULL;
	
	printf("Number of samples%i\n", samples);
	
	return 0;
	
}

double PreciseOnsetDetectorOffline::frameIndexToSeconds(const int& frameIndex){
	return ((double)(frameIndex*hopSize) /44100.);//- (detectionFunction.framesize/2)?;
}

double PreciseOnsetDetectorOffline::secondsToFrameIndex(const double& seconds){
	return (seconds*44100./(double)hopSize );//- (detectionFunction.framesize/2)?;
}


void PreciseOnsetDetectorOffline::exportOnsetTimes(){
	exportOnsetTimes(0.0, samples/44100.0);//i.e. the whole file
}


void PreciseOnsetDetectorOffline::exportOnsetTimes(double startTime, double endTime){
	//for writing output
	BeatWriter writer;
	std::string outputFilename = loadedFilename+"_preciseOnsets.txt";
	
	if (writeOutput)
		writer.openFile(outputFilename);
	
	
	int index = 0;
	while (index < onsetLocations.size() && onsetLocations[index] < startTime)
		index++;
	
	while (index < onsetLocations.size() && onsetLocations[index] <= endTime){
		writer.writeBeatTime(onsetLocations[index]);
		index++;
	}
	
	if (writeOutput)	
		writer.closeFile();
}

void PreciseOnsetDetectorOffline::update(){

}


void PreciseOnsetDetectorOffline::draw(){
	//do vizualisation in a specialised class
}

void PreciseOnsetDetectorOffline::printOnsetLocations(){
	for (int i = 0; i < (int)onsetLocations.size(); i++)
		printf("Onset[%i]: %.3f\n", i, onsetLocations[i]);
}

double PreciseOnsetDetectorOffline::closestOnset(double& targetVal){
	int bestIndex = 0;
	double bestDiff = 99999;
	double bestVal = -1;
	
	for (int testIndex = 0; testIndex < (int)onsetLocations.size(); testIndex++){
		double testDiff = (onsetLocations[testIndex] - targetVal);
		if (fabs(testDiff) < bestDiff){
			bestDiff = fabs(testDiff);
			bestVal = onsetLocations[testIndex];
			bestIndex = testIndex;
		}
	}
	return bestVal;
}

void PreciseOnsetDetectorOffline::loadOnsetLocations(DoubleVector& beats){
	//replaces onset locations with new vector
	onsetLocations.clear();
	for (int i = 0; i < beats.size(); i++){
		onsetLocations.push_back(beats[i]);
	}
}