annotate src/midiEventHolder.cpp @ 0:b299a65a3ad0

start project
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Tue, 16 Aug 2011 11:29:59 +0100
parents
children 1a32ce016bb9
rev   line source
andrew@0 1 /*
andrew@0 2 * midiEventHolder.cpp
andrew@0 3 * midiCannamReader3
andrew@0 4 *
andrew@0 5 * Created by Andrew on 19/07/2011.
andrew@0 6 * Copyright 2011 QMUL. All rights reserved.
andrew@0 7 *
andrew@0 8 */
andrew@0 9 //hello
andrew@0 10
andrew@0 11 #include "midiEventHolder.h"
andrew@0 12
andrew@0 13 midiEventHolder::midiEventHolder(){
andrew@0 14 // recordedNoteOnIndex = 0;
andrew@0 15
andrew@0 16 width = ofGetWidth();
andrew@0 17 height = ofGetHeight();
andrew@0 18 screenWidth= &width;
andrew@0 19 screenHeight = &height;
andrew@0 20
andrew@0 21 ticksPerScreen = 4000;
andrew@0 22 tickLocation = 0;
andrew@0 23 pulsesPerQuarternote = 240;
andrew@0 24 noteArrayIndex = 0;
andrew@0 25 noteMinimum = 30;
andrew@0 26 noteMaximum = 96;
andrew@0 27
andrew@0 28 minimumMatchSpeed = 0.5;
andrew@0 29 maximumMatchSpeed = 2.0;
andrew@0 30 likelihoodWidth = 100;
andrew@0 31 likelihoodToNoiseRatio = 50;
andrew@0 32
andrew@0 33 matchWindowWidth = 6000;//window size for matching in ms
andrew@0 34
andrew@0 35 bayesStruct.resetSize(4000);
andrew@0 36 bayesStruct.resetSpeedSize(200);
andrew@0 37 bayesStruct.setRelativeSpeedScalar(0.01);
andrew@0 38 bayesStruct.relativeSpeedPrior.getMaximum();
andrew@0 39 bayesStruct.simpleExample();
andrew@0 40
andrew@0 41 noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum);
andrew@0 42 }
andrew@0 43
andrew@0 44
andrew@0 45
andrew@0 46 void midiEventHolder::reset(){
andrew@0 47 noteArrayIndex = 0;
andrew@0 48 tickLocation = 0;
andrew@0 49 lastPeriodUpdateTime = ofGetElapsedTimeMillis();
andrew@0 50 bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
andrew@0 51 numberOfScreensIn = 0;
andrew@0 52 // recordedNoteOnIndex = 0;
andrew@0 53 bayesStruct.setNewDistributionOffsets(0);
andrew@0 54 bayesStruct.posterior.offset = 0;
andrew@0 55
andrew@0 56 playedEventTimes.clear();
andrew@0 57 playedNoteOnMatrix.clear();
andrew@0 58 matchMatrix.clear();
andrew@0 59
andrew@0 60 bayesStruct.resetSpeedToOne();
andrew@0 61
andrew@0 62 }
andrew@0 63
andrew@0 64 void midiEventHolder::printNotes(){
andrew@0 65 printf("RECORDED MATRIX");
andrew@0 66 for (int i = 0;i < recordedNoteOnMatrix.size();i++){
andrew@0 67 printf("%i :: %i @ %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]);
andrew@0 68 }
andrew@0 69 }
andrew@0 70
andrew@0 71
andrew@0 72 double midiEventHolder::getEventTimeTicks(double millis){
andrew@0 73 return (millis * pulsesPerQuarternote / period);
andrew@0 74 }
andrew@0 75
andrew@0 76 double midiEventHolder::getEventTimeMillis(double ticks){
andrew@0 77 return (period * ticks / (double) pulsesPerQuarternote);
andrew@0 78 }
andrew@0 79
andrew@0 80 void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){
andrew@0 81
andrew@0 82 //MOVE INTO BAYESSTRUCT?? XXX
andrew@0 83 //bayesStruct.copyPriorToPosterior();
andrew@0 84 //why was this here??
andrew@0 85 bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way
andrew@0 86 //bayesStruct.copyPriorToPosterior();
andrew@0 87 //need to get new MAP position and set the offset of the arrays
andrew@0 88 //currently bestEstimate is the approx for the new MAP position
andrew@0 89
andrew@0 90
andrew@0 91 //add the new event to our played information matrix
andrew@0 92 IntVector v;
andrew@0 93 v.push_back(pitch);
andrew@0 94 v.push_back(velocity);
andrew@0 95 playedNoteOnMatrix.push_back(v);
andrew@0 96
andrew@0 97
andrew@0 98 //would update the arrays at this point to show where out current location (phase) and tempo is.
andrew@0 99 double timeNow = ofGetElapsedTimeMillis() - startTime;
andrew@0 100 recentNoteOnTime = timeNow;
andrew@0 101
andrew@0 102 printf("Max time %f OF time %f \n", timePlayed, timeNow);
andrew@0 103
andrew@0 104 playedEventTimes.push_back(timePlayed);
andrew@0 105
andrew@0 106 double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime;
andrew@0 107
andrew@0 108 //addnoise to the tempo distribution
andrew@0 109 bayesStruct.decaySpeedDistribution(timeDifference);
andrew@0 110
andrew@0 111
andrew@0 112 // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate);
andrew@0 113 //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis
andrew@0 114
andrew@0 115 timeString = "Pitch:"+ofToString(pitch);
andrew@0 116 timeString += ", time now:"+ofToString(timeNow, 1);
andrew@0 117 timeString += " TD "+ofToString(timeDifference, 1);
andrew@0 118 timeString += " offset "+ofToString(bayesStruct.posterior.offset , 0);
andrew@0 119 timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0);
andrew@0 120 // timeString += " Previous time" + ofToString(newMAPestimateTime,0);
andrew@0 121 timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.MAPestimate, 2);
andrew@0 122 timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 2);
andrew@0 123
andrew@0 124 // newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate));
andrew@0 125 // timeString += " : Predicted MAP time" + ofToString(newMAPestimateTime,0);
andrew@0 126
andrew@0 127 //then we recalculate the window start based on MAP being central
andrew@0 128 //then we do the matches on these and the likelihood on these.
andrew@0 129
andrew@0 130 bayesStruct.setNewDistributionOffsets(max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)));
andrew@0 131 // bayesStruct.prior.offset = max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
andrew@0 132
andrew@0 133 timeString += " \n : new offset " + ofToString(bayesStruct.prior.offset , 0);
andrew@0 134 timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1);
andrew@0 135 timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.MAPestimate, 1);
andrew@0 136 timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 1);
andrew@0 137
andrew@0 138
andrew@0 139 //be able to draw the prior in correct location relative to the midi notes
andrew@0 140 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference);
andrew@0 141 // bayesStruct.crossUpdateArrays(bayesStruct.prior, bayesStruct.relativeSpeedPosterior, timeDifference);
andrew@0 142
andrew@0 143
andrew@0 144 timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1);
andrew@0 145 timeString += " notearrayindex "+ofToString(noteArrayIndex, 0);
andrew@0 146 //when this is off teh screen there is a problem somehow XXX
andrew@0 147 bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
andrew@0 148 // bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));
andrew@0 149 //trying to switch to prior
andrew@0 150
andrew@0 151 bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
andrew@0 152
andrew@0 153 //do the cross update to find current posterior for location
andrew@0 154 int numberOfMatchesFound = findLocalMatches(pitch);
andrew@0 155 setMatchLikelihoods(numberOfMatchesFound);
andrew@0 156 bayesStruct.calculatePosterior();
andrew@0 157
andrew@0 158 //having found matches we have matches for new note and matches for previous notes
andrew@0 159 findLocalTempoPairs();
andrew@0 160
andrew@0 161
andrew@0 162
andrew@0 163 }
andrew@0 164
andrew@0 165 int midiEventHolder::findLocalMatches(int notePitch){
andrew@0 166
andrew@0 167 //here we find the matches to the new note within appropriate range
andrew@0 168
andrew@0 169 matchString += ", "+ofToString(notePitch);
andrew@0 170
andrew@0 171 windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis
andrew@0 172 int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth);
andrew@0 173
andrew@0 174 return numberOfMatches;
andrew@0 175
andrew@0 176
andrew@0 177 }
andrew@0 178
andrew@0 179
andrew@0 180 void midiEventHolder::setMatchLikelihoods(int numberOfMatches){
andrew@0 181 //reset the offset to match the prior
andrew@0 182 bayesStruct.likelihood.offset = bayesStruct.prior.offset;
andrew@0 183 bayesStruct.likelihood.zero();//set to zero
andrew@0 184
andrew@0 185
andrew@0 186
andrew@0 187 for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){
andrew@0 188 // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset);
andrew@0 189 //this is the vent time since start of file
andrew@0 190 if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){
andrew@0 191 bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, 0.5 * likelihoodToNoiseRatio);
andrew@0 192 }//end if
andrew@0 193 }
andrew@0 194 bayesStruct.likelihood.addConstant(0.01);
andrew@0 195 }
andrew@0 196
andrew@0 197 int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){
andrew@0 198
andrew@0 199 matchesFound.clear();
andrew@0 200 int startIndex = 0;
andrew@0 201
andrew@0 202 if (recordedEventTimes.size() > 0){
andrew@0 203
andrew@0 204 //get to the right range of events to check in
andrew@0 205 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime)
andrew@0 206 startIndex++;
andrew@0 207
andrew@0 208 }
andrew@0 209
andrew@0 210
andrew@0 211 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){
andrew@0 212 if (recordedNoteOnMatrix[startIndex][1] == notePitch){
andrew@0 213 matchesFound.push_back(startIndex);
andrew@0 214 }
andrew@0 215 startIndex++;
andrew@0 216 }
andrew@0 217
andrew@0 218 // printf("%i MATCHES TO Note %i found\n", (int)matchesFound.size(), notePitch);
andrew@0 219 int size = matchesFound.size();
andrew@0 220
andrew@0 221 IntVector v;
andrew@0 222 v.push_back(size);
andrew@0 223 for (int i = 0;i < matchesFound.size();i++)
andrew@0 224 v.push_back(matchesFound[i]);
andrew@0 225
andrew@0 226 matchMatrix.push_back(v);
andrew@0 227
andrew@0 228 return size;
andrew@0 229 }
andrew@0 230
andrew@0 231 bool midiEventHolder::checkIfMatchedNote(const int& tmpIndex){
andrew@0 232 for (int i = 0;i < matchesFound.size();i++){
andrew@0 233 if (matchesFound[i] == tmpIndex)
andrew@0 234 return true;
andrew@0 235 }
andrew@0 236 return false;
andrew@0 237 }
andrew@0 238
andrew@0 239
andrew@0 240
andrew@0 241 void midiEventHolder::findLocalTempoPairs(){
andrew@0 242
andrew@0 243 int currentPlayedIndex = playedNoteOnMatrix.size()-1;
andrew@0 244 // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]);
andrew@0 245 // printMatchesFound();
andrew@0 246 // printMatchMatrix();
andrew@0 247 // printf("possible notes \n");
andrew@0 248
andrew@0 249
andrew@0 250 for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){
andrew@0 251
andrew@0 252 int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1];
andrew@0 253
andrew@0 254 int previousIndex = currentPlayedIndex-1;
andrew@0 255
andrew@0 256 while (previousIndex >= 0 && playedEventTimes[previousIndex] + 2000 > playedEventTimes[currentPlayedIndex]) {
andrew@0 257 double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex];
andrew@0 258
andrew@0 259 for (int k = 0;k < matchMatrix[previousIndex][0];k++){
andrew@0 260 int recordedPreviousIndex = matchMatrix[previousIndex][k+1];
andrew@0 261
andrew@0 262 // printf("(%i)", matchMatrix[currentPlayedIndex][i+1]);
andrew@0 263 // printf("[%i] :: ", recordedPreviousIndex);
andrew@0 264
andrew@0 265 double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex];
andrew@0 266 /// printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference);
andrew@0 267
andrew@0 268 //we want the speed of the recording relative to that of the playing live
andrew@0 269
andrew@0 270 double speedRatio = recordedTimeDifference / playedTimeDifference;
andrew@0 271 if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){
andrew@0 272
andrew@0 273 // printf("update on speed ratio %f", speedRatio);
andrew@0 274 // commented for debug
andrew@0 275 bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match
andrew@0 276
andrew@0 277 }
andrew@0 278 // printf("\n");
andrew@0 279 }
andrew@0 280
andrew@0 281 previousIndex--;
andrew@0 282 }//end while previousindex countdown
andrew@0 283 }//end for loop through possible current matches
andrew@0 284
andrew@0 285
andrew@0 286 }
andrew@0 287
andrew@0 288
andrew@0 289 void midiEventHolder::updatePlayPosition(){
andrew@0 290
andrew@0 291 //in actual fact if we are changing the speed of the play position
andrew@0 292 //we will need to update this via the file
andrew@0 293
andrew@0 294 double timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;
andrew@0 295 //this is time diff in milliseconds
andrew@0 296 //then we have
andrew@0 297 double quarterNoteIntervals = (timeDifference / period);
andrew@0 298 tickLocation = quarterNoteIntervals * pulsesPerQuarternote;
andrew@0 299
andrew@0 300 playPositionInMillis = timeDifference;//based on updating from when we change period
andrew@0 301 //this to be added
andrew@0 302
andrew@0 303 bayesStruct.updateBestEstimate();
andrew@0 304
andrew@0 305 }
andrew@0 306
andrew@0 307
andrew@0 308 void midiEventHolder::drawFile(){
andrew@0 309 //draws midi file on scrolling screen
andrew@0 310 int size = recordedNoteOnMatrix.size();
andrew@0 311 if (size > 0){
andrew@0 312
andrew@0 313 numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in
andrew@0 314
andrew@0 315 // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down
andrew@0 316 timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen);
andrew@0 317
andrew@0 318 while (noteArrayIndex < recordedNoteOnMatrix.size() && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] )
andrew@0 319 noteArrayIndex++;
andrew@0 320
andrew@0 321
andrew@0 322 while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0])
andrew@0 323 noteArrayIndex--;
andrew@0 324
andrew@0 325 //need to start where we currently are in file
andrew@0 326 int maxNoteIndexToPrint = noteArrayIndex;
andrew@0 327 int minNoteIndexToPrint = noteArrayIndex;
andrew@0 328
andrew@0 329 while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen )
andrew@0 330 maxNoteIndexToPrint++;
andrew@0 331
andrew@0 332 while (minNoteIndexToPrint > 0 && minNoteIndexToPrint < size && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)
andrew@0 333 minNoteIndexToPrint--;
andrew@0 334
andrew@0 335 for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){
andrew@0 336
andrew@0 337 if (checkIfMatchedNote(tmpIndex))
andrew@0 338 ofSetColor(0,0,255);
andrew@0 339 else
andrew@0 340 ofSetColor(255,255,255);
andrew@0 341
andrew@0 342 // XXX replace ofgetwidth below
andrew@0 343 //if (tmpIndex >= 0 && tmpIndex < size)
andrew@0 344 int xLocation = (float)(recordedNoteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen;
andrew@0 345 int duration = (float)(recordedNoteOnMatrix[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen;
andrew@0 346
andrew@0 347
andrew@0 348 int yLocation = (*screenHeight) - ((recordedNoteOnMatrix[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));
andrew@0 349 ofRect(xLocation,yLocation, duration, noteHeight);
andrew@0 350
andrew@0 351 }
andrew@0 352
andrew@0 353
andrew@0 354 int xLocation;// = getLocationFromTicks(tickLocation);
andrew@0 355 // ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@0 356
andrew@0 357 //orange line at best estimate
andrew@0 358 xLocation = getLocationFromMillis(bayesStruct.bestEstimate);
andrew@0 359 ofSetColor(250,100,0);
andrew@0 360 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@0 361
andrew@0 362
andrew@0 363 //lines where matching window start and end are
andrew@0 364 ofSetColor(0,100,255);
andrew@0 365 xLocation = getLocationFromMillis(windowStartTime);
andrew@0 366 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@0 367 xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth);
andrew@0 368 ofLine(xLocation, 0, xLocation, (*screenHeight));
andrew@0 369
andrew@0 370
andrew@0 371 }
andrew@0 372
andrew@0 373 ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20);
andrew@0 374
andrew@0 375 ofDrawBitmapString(timeString, 20, 60);
andrew@0 376
andrew@0 377 // bayesStruct.drawArrays();
andrew@0 378
andrew@0 379 // ofSetColor(200,200,0);
andrew@0 380 // bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800);
andrew@0 381
andrew@0 382 //need to draw arrays within correct timescope
andrew@0 383 bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen));
andrew@0 384
andrew@0 385 //bayesStruct.drawTempoArrays();
andrew@0 386
andrew@0 387 ofDrawBitmapString(matchString, 20, ofGetHeight() - 20);
andrew@0 388
andrew@0 389 }
andrew@0 390
andrew@0 391 int midiEventHolder::getLocationFromTicks(double tickPosition){
andrew@0 392 return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen);
andrew@0 393 }
andrew@0 394
andrew@0 395 int midiEventHolder::getLocationFromMillis(double millisPosition){
andrew@0 396 //(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen
andrew@0 397 return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen);
andrew@0 398 }
andrew@0 399
andrew@0 400
andrew@0 401 void midiEventHolder::exampleCrossUpdate(){
andrew@0 402
andrew@0 403 bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200);
andrew@0 404
andrew@0 405 }
andrew@0 406
andrew@0 407
andrew@0 408 void midiEventHolder::setStartPlayingTimes(){
andrew@0 409 lastPeriodUpdateTime = ofGetElapsedTimeMillis();
andrew@0 410 bayesStruct.lastEventTime = ofGetElapsedTimeMillis();
andrew@0 411 startTime = lastPeriodUpdateTime;
andrew@0 412
andrew@0 413 bayesStruct.resetArrays();
andrew@0 414 // bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis();
andrew@0 415 matchString = "";
andrew@0 416 }
andrew@0 417
andrew@0 418
andrew@0 419 void midiEventHolder::printMatchMatrix(){
andrew@0 420 printf("match matrix:\n");
andrew@0 421 for (int i = 0;i < matchMatrix.size();i++){
andrew@0 422 for (int k = 0;k < matchMatrix[i].size();k++){
andrew@0 423 printf("%i , ", matchMatrix[i][k]);
andrew@0 424 }
andrew@0 425 printf("\n");
andrew@0 426 }
andrew@0 427
andrew@0 428
andrew@0 429 }