diff DrumTimingLoader_OF/src/RecordedMultipleAudio.cpp @ 0:82352cfc0b23

Added files from ISMIR groove drum timing work
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 01 Oct 2012 22:24:32 +0100
parents
children 50ba55abea8c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DrumTimingLoader_OF/src/RecordedMultipleAudio.cpp	Mon Oct 01 22:24:32 2012 +0100
@@ -0,0 +1,525 @@
+/*
+ *  RecordedMultipleAudio.cpp
+ *  MultipleAudioMathcher
+ *
+ *  Created by Andrew on 31/01/2012.
+ *  Copyright 2012 QMUL. All rights reserved.
+ *
+ */
+
+#include "RecordedMultipleAudio.h"
+
+RecordedMultipleAudio::RecordedMultipleAudio(){
+	
+	infoFilepath = "../../../data/errorData.txt";
+	//infoFilepath = "/Users/andrew/errorData.txt";
+	
+	timingOffset = 0;
+}
+
+void RecordedMultipleAudio::loadTestAudio(){
+
+
+	numberOfAudioTracks = 2;
+	
+	printf("loaded max val  is %f\n", loadedAudioFiles[0].fileLoader.onsetDetect.onsetDetector.maximumDetectionValue);
+	
+	int multitrackToLoad = 5;
+	setDifferentMultitracks(multitrackToLoad);//command to load this set of audio files - see below
+
+	drumTimingAnalyser.phaseCost = 1000;//v high - i.e. dont do phase 
+	
+	drawWindow = 1;
+	trackScreenHeight = 0.25;
+	
+	
+	
+//	printf("AFTER LOADING: \n");
+//	printInfo();
+	
+}
+#pragma mark -loadingPrerecordedTracks
+void RecordedMultipleAudio::setDifferentMultitracks(const int& setToLoad){
+	const char	*kickfilename ;//= "../../../data/sound/LiveDues/kick_liveDues.wav";	
+	const char	*roomfilename ;//"../../../data/sound/LiveDues/bass_upsideLive.wav";	
+	const char	*snarefilename ;
+	std::string sonicVizBeatsFilename ;
+	
+	switch (setToLoad) {
+		case 0:
+				kickfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/kickFuture.wav";	
+				roomfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/roomFuture.wav";	
+				snarefilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/snareFuture.wav";	
+				sonicVizBeatsFilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/FutureHidesBeats.txt";
+			break;
+			
+			
+		case 1:
+			roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/Mixdown/PennyArcade_StudioMixdown.wav";
+			kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/kick.wav";
+			snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/snare.wav";
+			sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/Mixdown/PennyArcade_StudioMixdown_beats.txt";
+			break;	
+	
+		case 2:
+			roomfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/colesL_bip.wav";
+			kickfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/Kick_bip.wav";
+			snarefilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/Snare_bip.wav";
+			sonicVizBeatsFilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/IngramGreenSectionBeats.txt";
+			break;		
+			
+		case 3:
+			roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/coles_bip.wav";
+			kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/kick d112_bip.wav";
+			snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/snare bottom_bip.wav";
+			sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/TakeOneBeats.txt";
+			break;
+			
+		case 4:
+			roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/neuamnn_bip.wav";
+			kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/kick_bip.wav";
+			snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/snare_bip.wav";
+			sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/PennyArcade_take4_beats.txt";
+			break;	
+			
+		case 5:
+			roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/neuamnn_bip.wav";
+			kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/kick_bip.wav";
+			snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/snare_bip.wav";
+			sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/PennyArcade_take5_beats.txt";
+			break;	
+			
+			
+			
+	}
+	if (kickfilename != NULL){
+		
+		loadAudioTrack(kickfilename, 0);
+	}
+	
+	if (roomfilename != NULL){	
+		printf("roomfilename: %s\n", roomfilename);
+		loadAudioTrack(roomfilename, 1);
+	}
+	
+	if (snarefilename != NULL)
+		loadAudioTrack(snarefilename, 2);
+	
+	if (sonicVizBeatsFilename.c_str() != NULL){
+		readInBeatsFile(sonicVizBeatsFilename);
+		printBeatTimes();
+		checkFileErrors(0);
+		checkFileErrors(2);
+		findBeatOnsets();
+	}
+}
+
+void RecordedMultipleAudio::loadAudioTrack(std::string name, const int& channel){
+	//kick - track type 0
+	//bass - type 1
+	//snare type 2
+	//guitar type 3
+	if (channel >= 0 && channel <= numberOfAudioTracks){
+	loadedAudioPtr = new LoadedAudioHolder;
+	//set tracktype before we do analysis
+	//so we dont do unnecessary chroma and pitch calculations
+		if (channel == 0 || channel == 2){
+			loadedAudioPtr->setTrackType(channel);
+		}
+		else{
+			loadedAudioPtr->setTrackType(0);
+		}
+	loadedAudioPtr->loadAudioFile(name);
+		
+	loadedAudioFiles[channel] = *loadedAudioPtr;
+	loadedAudioFiles[channel].fileLoader.onsetDetect.window.setToRelativeSize(0, trackScreenHeight*channel, 1, trackScreenHeight);
+	//loadedAudioFiles[channel].setTrackType(channel);
+	}
+}
+
+
+
+void RecordedMultipleAudio::readInBeatsFile(std::string& pathName){
+	
+	// "/Users/andrew/Documents/work/MuseScore/RWC/ANNOTATION/RM-C002_annotation+WavPos.csv"
+	beatTimes.clear();
+	
+	printf("- - - - \n\nREAD FILE %s\n", pathName.c_str());
+	ifstream file ( pathName.c_str());
+	string value, tmpLine;
+	stringstream iss;
+	int count = 0;
+	
+	while ( file.good() )
+	{
+		getline(file, tmpLine);
+		iss << tmpLine;
+		int lineCount = 0;
+		//			printf("tmp line %s\n", tmpLine.c_str());
+		while(getline ( iss, value, '\t' )){ // read a string until next comma: http://www.cplusplus.com/reference/string/getline/
+			//	cout << string( value, 1, value.length()-2 ); // display value removing the first and the last character from it
+			//		printf("line:%s\n", value.c_str());
+			string::size_type start = value.find_first_not_of(" ,\t\v\n");
+			
+			string part = value.substr(start, string::npos);
+			
+			//printf("%s\n", firstpart.c_str());
+			if (lineCount == 0){
+				//printf("First part of line found '%s'\n", part.c_str());
+				double newBeatTime = atof(part.c_str());
+				beatTimes.push_back(newBeatTime);
+			}
+			lineCount++;
+			
+		}//end while reading line
+		iss.clear();
+		
+		
+	}//end while
+	
+	//	printBeatTimes();
+	printf("There are %i BEAT annotations\n", (int)beatTimes.size());
+	
+}
+
+void RecordedMultipleAudio::printBeatTimes(){
+	for (int i = 0;i < beatTimes.size();i++){
+		printf("Beat[%i] = %f\n", i, beatTimes[i]);
+	}
+}
+
+
+void RecordedMultipleAudio::checkFileErrors(int channel){
+	int beatIndex = 0;
+	int cutoff = 50;//ms width to check
+	for (int i = 0;i < loadedAudioFiles[channel].onsetTimesMillis.size();i++){
+		while (beatIndex < beatTimes.size() && 1000.0*beatTimes[beatIndex] < loadedAudioFiles[channel].onsetTimesMillis[i] - cutoff) {
+			beatIndex++;
+		}
+		double error = (1000.0*beatTimes[beatIndex] - loadedAudioFiles[channel].onsetTimesMillis[i]);
+		if (fabs(error) < cutoff){
+			if (channel == 0) 
+				printf("Pos: %i Beat Time %f Kick Time %f Error %f\n", beatIndex%4, 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error);
+			else 
+				printf("Pos: %i Beat Time %f Snare Time %f Error %f\n", beatIndex%4, 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error);
+			
+		}else{
+			if (channel == 0) 
+				printf("Out of Beat: Kick Time %f beat error %f\n", 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error);
+			else 
+				printf("Out of Beat: %f Snare Time %f best error %f\n", 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error);
+			
+		}
+	}
+}
+
+
+#pragma mark -labelExactOnsets
+
+void RecordedMultipleAudio::findBeatOnsets(){
+//tries to find kicks on 1, 3; snares on 2,4
+	int beatIndex = 0;
+	int kickIndex = 0;
+	int snareIndex = 0;
+	double kickTime, snareTime;
+	int cutoff = 50;//ms width to check
+	
+	onsetInfo.clear();
+	
+//	kickErrors.clear();
+//	snareErrors.clear();
+	
+	bool beatFound;
+	for (int k = 0;k < beatTimes.size();k++){
+		beatFound = false;
+		double newBeatTime = beatTimes[k]*1000.0;
+		int beatPosition = k % 4;
+		OnsetInformation information;
+		switch (beatPosition) {
+			case 0: case 2://check for kick when it is on the `one' or 'three' (0 or 2 in our metrical position)
+			//	printf("check %i kindex %i\n", beatPosition, kickIndex);
+				while (kickIndex < loadedAudioFiles[0].onsetTimesMillis.size() && loadedAudioFiles[0].onsetTimesMillis[kickIndex] < newBeatTime - cutoff){
+					kickIndex++;
+					kickTime = loadedAudioFiles[0].onsetTimesMillis[kickIndex];
+			//		printf("checking beat[%i] %f kick %f error %f\n", k, beatTimes[k]*1000.0, kickTime, (kickTime - beatTimes[k]*1000.0));
+					if (fabs(kickTime - beatTimes[k]*1000.0) < cutoff){
+						beatFound = true;
+						printf("beat[%i] %f kick %f error %f\n", k, beatTimes[k]*1000.0, kickTime, (kickTime - beatTimes[k]*1000.0));
+
+						information.error = (kickTime - beatTimes[k]*1000.0);//FOR NOW ONLY
+						information.metricalPosition = beatPosition;
+						information.type = 0;	
+						information.exactOnsetTime = kickTime;
+			//			exactBeatPositions.push_back(kickTime);
+					}
+				}
+				
+				break;
+			case 1: case 3://snare
+				while (snareIndex < loadedAudioFiles[1].onsetTimesMillis.size() && loadedAudioFiles[1].onsetTimesMillis[snareIndex] < newBeatTime - cutoff ){
+					snareIndex++;
+					snareTime = loadedAudioFiles[1].onsetTimesMillis[snareIndex];
+					if (fabs(snareTime - beatTimes[k]*1000.0) < cutoff){
+						beatFound = true;
+					//	snareErrors.push_back((beatTimes[k]*1000.0 - snareTime));
+						information.error = (snareTime - beatTimes[k]*1000.0);
+						information.metricalPosition = beatPosition;//.push_back(beatPosition);
+						information.type = 1;
+						information.exactOnsetTime = snareTime;
+						printf("beat[%i] %f snare %f error %f\n", k, beatTimes[k]*1000.0, snareTime, (snareTime - beatTimes[k]*1000.0));
+			//			exactBeatPositions.push_back(snareTime);
+					}
+				}
+				
+				break;
+		}
+		if (!beatFound){
+			information.type = -1;//not a kick or snare
+			information.exactOnsetTime = beatTimes[k]*1000.0;
+			information.metricalPosition = beatPosition;//.push_
+		//	exactBeatPositions.push_back(beatTimes[k]*1000.0);//have to go with the annotated beat instead (no matching kick or snare)
+			
+			printf("beat[%i] %f NOT FOUND, kicktime %f snaretime %f\n", k, beatTimes[k]*1000.0, kickTime, snareTime );
+		}
+		
+		onsetInfo.push_back(information);
+		
+	}//end for all beat annotations
+
+	correctExactBeatTiming();//get rid of the first onset time
+	
+	calculateTimingAnalysis();
+	
+}
+
+#pragma mark -doTimingAnalysis
+void RecordedMultipleAudio::correctExactBeatTiming(){
+	//get rid of firtst onset time
+	if (onsetInfo.size() > 0){
+		timingOffset = onsetInfo[0].exactOnsetTime;//s[0];
+		double tmpPosn;
+		for (int i = 0;i < onsetInfo.size();i++){
+			onsetInfo[i].beatTimeToProcess = onsetInfo[i].exactOnsetTime - timingOffset;
+			printf("exact [%i] type %i %f, corrected %f\n", i, onsetInfo[i].type, onsetInfo[i].exactOnsetTime, onsetInfo[i].beatTimeToProcess );
+		}
+	}
+}
+
+void RecordedMultipleAudio::calculateTimingAnalysis(){
+	
+	for (int i = 0;i < onsetInfo.size();i++){
+		drumTimingAnalyser.updateCostToPoint(onsetInfo[i].beatTimeToProcess, i);
+		//updatecounter is the beat position for this note event - can be used to do other kinds of durations than just simple beats
+		
+		drumTimingAnalyser.beatPosition.push_back(onsetInfo[i].exactOnsetTime);
+	}
+	drumTimingAnalyser.processPathHistory();
+	drumTimingAnalyser.calculateTempoLimits();
+
+	getErrorTimesFromAnalysis();
+	
+	alternativeKickRelativeAnalysis();
+	
+	exportErrorInformation();
+	
+	displayKickRelativeMedianErrors();//NB messes ther order of these
+	
+	//this was how we did it in multimatch program
+//	timer.processPathHistory();
+//	timer.calculateTempoLimits();
+//	timer.exportTimingData();
+//	timer.exportProcessedBeatTimes(firstNoteTime);
+}
+
+void RecordedMultipleAudio::getErrorTimesFromAnalysis(){
+	printf("\nDrumTimingLoader: get error times from analysis!!!\n");
+	setUpErrorsByMetricalPosition();
+	//gets the errors from the drum timing analyser (i.e. ISMIR paper code) and attributes these to the onsets
+	for (int i = 0;i < drumTimingAnalyser.timingData.size();i++){
+		onsetInfo[i].error = drumTimingAnalyser.timingData[i][5];
+		onsetInfo[i].clickTime = drumTimingAnalyser.timingData[i][1] + timingOffset;//this is where teh timing analyser placed the click times
+		errorsByMetricalPosition[onsetInfo[i].metricalPosition].push_back(onsetInfo[i].error);
+		printf("beat %i metrical posn %i exact beat time %f error %i\n", i, onsetInfo[i].metricalPosition, onsetInfo[i].exactOnsetTime, (int)onsetInfo[i].error);
+	}
+	displayMedianErrors();
+}
+
+
+void RecordedMultipleAudio::alternativeKickRelativeAnalysis(){
+	printf("\n\nAnalysis Relative to the Kick Drum on the ONE\n");
+	//this sees kicks as ON the beat, looks at relative error of the three other beats if we chop the bar evenly
+	
+	double recentBeatTime, currentTempo;	
+	kickRelativeErrors.clear();
+	kickRelativeClickTimes.clear();
+	
+	for (int i = 0;i < drumTimingAnalyser.timingData.size();i++){
+		int beatPosition = i%4;
+		if (beatPosition == 0){
+			recentBeatTime = onsetInfo[i].exactOnsetTime;
+			if (i+4 < onsetInfo.size())
+				currentTempo =  (onsetInfo[i+4].exactOnsetTime - onsetInfo[i].exactOnsetTime)/4.0;
+			printf("new beat time %f tempo %f\n", recentBeatTime, currentTempo);
+		}
+		double error = onsetInfo[i].exactOnsetTime - (recentBeatTime + beatPosition*currentTempo);
+		printf("Beat %i KR Predicted Beat %f Actual exact %f KRerror %f DTerror %i\n", beatPosition, (recentBeatTime + beatPosition*currentTempo), onsetInfo[i].exactOnsetTime, error, (int)onsetInfo[i].error); 
+		kickRelativeErrors.push_back(error);
+		kickRelativeClickTimes.push_back(recentBeatTime + beatPosition*currentTempo);
+	}
+}
+
+#pragma label -exportInfo
+void RecordedMultipleAudio::exportErrorInformation(){
+	printf("Export final timing information\n");
+	
+	ofstream ofs(infoFilepath.c_str());
+	for (int i = 0;i < onsetInfo.size() && kickRelativeErrors.size();i++){// drumTimingAnalyser.timingData.size()
+		ofs << i << "," << (i%4) << "," << onsetInfo[i].exactOnsetTime << ",";
+		ofs << onsetInfo[i].clickTime << "," << onsetInfo[i].error << ",";//the error for the ISMIR timing analyser
+		ofs << kickRelativeClickTimes[i] << "," << kickRelativeErrors[i];//the click and error for beats evenly between kicks
+		ofs << endl;
+	}
+	
+}
+
+void RecordedMultipleAudio::printKickRelativeErrors(){
+	for (int i = 0;i < kickRelativeErrors.size();i++){
+	printf("KR error [%i] : %.1f\n", i, kickRelativeErrors[i]);
+	}
+}
+
+void RecordedMultipleAudio::setUpErrorsByMetricalPosition(){
+	//clear this matrix
+	errorsByMetricalPosition.clear();
+	for (int i = 0;i < 4;i++){
+		DoubleVector v;
+		errorsByMetricalPosition.push_back(v);
+	}
+	
+}
+
+void RecordedMultipleAudio::displayMedianErrors(){
+	printf("Medians of the Decoded Tempo variations\n");
+	for (int i = 0;i < 4;i++){
+		//printErrorsForMetricalPosition(i);
+		std::sort(errorsByMetricalPosition[i].begin(), errorsByMetricalPosition[i].end());//sort vector
+		double median = errorsByMetricalPosition[i][(int)(errorsByMetricalPosition[i].size()/2)];
+		printf("median for metrical position %i is %f\n", i, median);
+	}
+}
+
+
+void RecordedMultipleAudio::displayKickRelativeMedianErrors(){
+	printf("Medians of the KR variations\n");
+	
+	DoubleVector tmpKRErrors;
+
+	
+	for (int i = 0;i < 4;i++){
+		
+		tmpKRErrors.clear();
+		int index = 0;
+		
+		while (index+i < kickRelativeErrors.size()) {
+			tmpKRErrors.push_back(kickRelativeErrors[index + i]);
+			index += 4;
+		}
+		
+//		for (int k = 0;k < tmpKRErrors.size();k++)
+//		printf("kr %i [%i] = %f\n", i, k, tmpKRErrors[k]);						  
+								  
+		//printErrorsForMetricalPosition(i);
+		std::sort(tmpKRErrors.begin(), tmpKRErrors.end());//sort vector
+		
+//		for (int k = 0;k < tmpKRErrors.size();k++)
+//			printf("sorted kr %i [%i] = %f\n", i, k, tmpKRErrors[k]);
+		
+		
+		double median = tmpKRErrors[(int)(tmpKRErrors.size()/2)];
+		printf("median for metrical position %i is %f\n", i, median);
+	}
+}
+
+void RecordedMultipleAudio::printErrorsForMetricalPosition(const int& i){
+	for (int k = 0;k < errorsByMetricalPosition[i].size();k++){
+		printf("metrical posn %i, [%i] = %f\n", i, k,  errorsByMetricalPosition[i][k]);
+	}
+}
+
+#pragma mark -drawTracks
+
+void RecordedMultipleAudio::drawTracks(){
+	if (drawWindow == 0){
+		for (int i = 0;i < numberOfAudioTracks;i++){		
+			loadedAudioFiles[i].draw();
+		}
+	} else {
+		drumTimingAnalyser.drawTempoCurve();
+	}
+}
+
+#pragma mark -update 
+void RecordedMultipleAudio::updatePosition(){
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].updateToPlayPosition();
+}
+
+void RecordedMultipleAudio::updatePositionToMillis(const double& millis){
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].updateToMillisPosition(millis);
+}
+
+void RecordedMultipleAudio::updatePlaybackPositionToMillis(const double& millis){
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].updatePlaybackPositionToMillis(millis);
+}
+
+void RecordedMultipleAudio::switchScreens(){
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].switchScreens();
+}
+
+
+void RecordedMultipleAudio::togglePlay(){
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].togglePlay();
+}
+
+void RecordedMultipleAudio::stop(){
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].stop();
+}
+
+
+void RecordedMultipleAudio::printInfo(){
+	loadedAudioFiles[0].fileLoader.onsetDetect.printChromaInfo();
+	loadedAudioFiles[0].printEvents();
+}
+
+void RecordedMultipleAudio::windowResized(const int& w, const int& h){
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].windowResized(w, h);
+}
+
+void RecordedMultipleAudio::zoomIn(){
+	if (drawWindow == 0){
+		printf("zoom in\n");
+		for (int i = 0;i < numberOfAudioTracks;i++)
+			loadedAudioFiles[i].fileLoader.zoomIn();	
+	}
+	
+	if (drawWindow == 1)
+		drumTimingAnalyser.zoomIn();//numberOfPointsPerPage /= 2;
+}
+
+void RecordedMultipleAudio::zoomOut(){
+		printf("zoom out\n");
+	for (int i = 0;i < numberOfAudioTracks;i++)
+		loadedAudioFiles[i].fileLoader.zoomOut();
+	
+	if (drawWindow == 1)
+		drumTimingAnalyser.zoomOut();//numberOfPointsPerPage *= 2;
+	
+}
+
+