Mercurial > hg > audiodb
comparison examples/iAudioDB/AppController.m @ 669:780ebab29268
Added initial increment of OSX audioDB interface
| author | mas01mj |
|---|---|
| date | Wed, 03 Mar 2010 17:17:08 +0000 |
| parents | |
| children | 15e71890b584 |
comparison
equal
deleted
inserted
replaced
| 668:ce5ff00168e1 | 669:780ebab29268 |
|---|---|
| 1 // | |
| 2 // AppController.m | |
| 3 // iAudioDB | |
| 4 // | |
| 5 // Created by Mike Jewell on 27/01/2010. | |
| 6 // Copyright 2010 __MyCompanyName__. All rights reserved. | |
| 7 // | |
| 8 | |
| 9 #import "AppController.h" | |
| 10 | |
| 11 | |
| 12 @implementation AppController | |
| 13 | |
| 14 -(id)init | |
| 15 { | |
| 16 [super init]; | |
| 17 | |
| 18 // A max of 100 results. | |
| 19 results = [[NSMutableArray alloc] initWithCapacity: 100]; | |
| 20 | |
| 21 | |
| 22 return self; | |
| 23 } | |
| 24 | |
| 25 | |
| 26 /** | |
| 27 * Create a new database, given the selected filename. | |
| 28 */ | |
| 29 -(IBAction)newDatabase:(id)sender | |
| 30 { | |
| 31 NSSavePanel* panel = [NSSavePanel savePanel]; | |
| 32 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@""]; | |
| 33 | |
| 34 [results removeAllObjects]; | |
| 35 [tracksView reloadData]; | |
| 36 | |
| 37 if(response == NSFileHandlingPanelOKButton) | |
| 38 { | |
| 39 // TODO: Refactor this into a 'tidy' method. | |
| 40 // Tidy any existing references up. | |
| 41 if(db) | |
| 42 { | |
| 43 audiodb_close(db); | |
| 44 } | |
| 45 | |
| 46 if(dbFilename) | |
| 47 { | |
| 48 [dbFilename release]; | |
| 49 [dbName release]; | |
| 50 [plistFilename release]; | |
| 51 } | |
| 52 | |
| 53 // Create new db, and set flags. | |
| 54 db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, 0); | |
| 55 audiodb_l2norm(db); | |
| 56 audiodb_power(db); | |
| 57 | |
| 58 // Store useful paths. | |
| 59 dbName = [[[panel URL] relativePath] retain]; | |
| 60 dbFilename = [[panel filename] retain]; | |
| 61 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain]; | |
| 62 | |
| 63 // Create the plist file (contains mapping from filename to key). | |
| 64 trackMap = [[NSMutableDictionary alloc] init]; | |
| 65 [trackMap writeToFile:plistFilename atomically:YES]; | |
| 66 | |
| 67 [queryKey setStringValue:@"None Selected"]; | |
| 68 [self updateStatus]; | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 /** | |
| 73 * Open an existing adb (which must have a plist) | |
| 74 */ | |
| 75 -(IBAction)openDatabase:(id)sender | |
| 76 { | |
| 77 NSArray *fileTypes = [NSArray arrayWithObject:@"adb"]; | |
| 78 NSOpenPanel* panel = [NSOpenPanel openPanel]; | |
| 79 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; | |
| 80 if(response == NSFileHandlingPanelOKButton) | |
| 81 { | |
| 82 // Tidy any existing references up. | |
| 83 if(db) | |
| 84 { | |
| 85 audiodb_close(db); | |
| 86 } | |
| 87 | |
| 88 if(dbFilename) | |
| 89 { | |
| 90 [dbFilename release]; | |
| 91 [dbName release]; | |
| 92 [plistFilename release]; | |
| 93 } | |
| 94 | |
| 95 // Store useful paths. | |
| 96 db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDWR); | |
| 97 dbName = [[[panel URL] relativePath] retain]; | |
| 98 dbFilename = [[panel filename] retain]; | |
| 99 | |
| 100 // TODO: Verify this exists! | |
| 101 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain]; | |
| 102 | |
| 103 // Clear out any old results. | |
| 104 [results removeAllObjects]; | |
| 105 [tracksView reloadData]; | |
| 106 | |
| 107 [queryKey setStringValue:@"None Selected"]; | |
| 108 [self updateStatus]; | |
| 109 | |
| 110 adb_liszt_results_t* liszt_results = audiodb_liszt(db); | |
| 111 | |
| 112 for(int k=0; k<liszt_results->nresults; k++) | |
| 113 { | |
| 114 NSMutableString *trackVal = [[NSMutableString alloc] init]; | |
| 115 [trackVal appendFormat:@"%s", liszt_results->entries[k].key]; | |
| 116 } | |
| 117 | |
| 118 audiodb_liszt_free_results(db, liszt_results); | |
| 119 trackMap = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain]; | |
| 120 NSLog(@"Size: %d", [trackMap count]); | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 /** | |
| 125 * Update button states and status field based on current state. | |
| 126 */ | |
| 127 -(void)updateStatus | |
| 128 { | |
| 129 if(db) | |
| 130 { | |
| 131 adb_status_ptr status = (adb_status_ptr)malloc(sizeof(struct adbstatus)); | |
| 132 int flags; | |
| 133 flags = audiodb_status(db, status); | |
| 134 [statusField setStringValue: [NSString stringWithFormat:@"Database: %@ Dimensions: %d Files: %d", dbName, status->dim, status->numFiles]]; | |
| 135 [chooseButton setEnabled:YES]; | |
| 136 } | |
| 137 else | |
| 138 { | |
| 139 [chooseButton setEnabled:NO]; | |
| 140 [playBothButton setEnabled:FALSE]; | |
| 141 [playResultButton setEnabled:FALSE]; | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 /** | |
| 146 * Get user's import choices. | |
| 147 */ | |
| 148 -(IBAction)importAudio:(id)sender | |
| 149 { | |
| 150 [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; | |
| 151 session = [NSApp beginModalSessionForWindow: importSheet]; | |
| 152 [NSApp runModalSession:session]; | |
| 153 } | |
| 154 | |
| 155 /** | |
| 156 * Cancel the import (at configuration time). | |
| 157 */ | |
| 158 -(IBAction)cancelImport:(id)sender; | |
| 159 { | |
| 160 [NSApp endModalSession:session]; | |
| 161 [importSheet orderOut:nil]; | |
| 162 [NSApp endSheet:importSheet]; | |
| 163 } | |
| 164 | |
| 165 /** | |
| 166 * Choose the file(s) to be imported. | |
| 167 * TODO: Currently handles the import process too - split this off. | |
| 168 */ | |
| 169 -(IBAction)selectFiles:(id)sender | |
| 170 { | |
| 171 [tracksView reloadData]; | |
| 172 | |
| 173 NSArray *fileTypes = [NSArray arrayWithObject:@"wav"]; | |
| 174 NSOpenPanel* panel = [NSOpenPanel openPanel]; | |
| 175 [panel setAllowsMultipleSelection:TRUE]; | |
| 176 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; | |
| 177 if(response == NSFileHandlingPanelOKButton) | |
| 178 { | |
| 179 NSRect newFrame; | |
| 180 | |
| 181 [extractingBox setHidden:FALSE]; | |
| 182 newFrame.origin.x = [importSheet frame].origin.x; | |
| 183 newFrame.origin.y = [importSheet frame].origin.y - [extractingBox frame].size.height; | |
| 184 newFrame.size.width = [importSheet frame].size.width; | |
| 185 newFrame.size.height = [importSheet frame].size.height + [extractingBox frame].size.height; | |
| 186 | |
| 187 [indicator startAnimation:self]; | |
| 188 [importSheet setFrame:newFrame display:YES animate:YES]; | |
| 189 | |
| 190 NSArray *filesToOpen = [panel filenames]; | |
| 191 | |
| 192 NSLog(@"Begin import"); | |
| 193 | |
| 194 // Work out which extractor to use | |
| 195 NSString* extractor = @"chromagram"; | |
| 196 switch([extractorOptions selectedTag]) | |
| 197 { | |
| 198 case 0: | |
| 199 extractor = @"mfcc"; | |
| 200 break; | |
| 201 case 1: | |
| 202 extractor = @"chromagram"; | |
| 203 break; | |
| 204 } | |
| 205 | |
| 206 for(int i=0; i<[filesToOpen count]; i++) | |
| 207 { | |
| 208 // First extract powers | |
| 209 | |
| 210 NSString *tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"powers.XXXXXX"]; | |
| 211 const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation]; | |
| 212 char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1); | |
| 213 strcpy(tempFileNameCString, tempFileTemplateCString); | |
| 214 mktemp(tempFileNameCString); | |
| 215 | |
| 216 NSString* powersFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)]; | |
| 217 free(tempFileNameCString); | |
| 218 | |
| 219 NSTask *task = [[NSTask alloc] init]; | |
| 220 [task setLaunchPath:@"/usr/local/bin/fftExtract2"]; | |
| 221 NSArray *args = [NSArray arrayWithObjects:@"-P", @"-h", @"11025", @"-w", @"16384", @"-n", @"32768", @"-i", @"1000", [filesToOpen objectAtIndex:i], powersFileName, nil]; | |
| 222 [task setArguments:args]; | |
| 223 [task launch]; | |
| 224 [task waitUntilExit]; | |
| 225 [task release]; | |
| 226 | |
| 227 // Then features | |
| 228 | |
| 229 tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"]; | |
| 230 tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation]; | |
| 231 tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1); | |
| 232 strcpy(tempFileNameCString, tempFileTemplateCString); | |
| 233 mktemp(tempFileNameCString); | |
| 234 | |
| 235 NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)]; | |
| 236 free(tempFileNameCString); | |
| 237 | |
| 238 task = [[NSTask alloc] init]; | |
| 239 | |
| 240 [task setLaunchPath:@"/usr/local/bin/fftExtract2"]; | |
| 241 | |
| 242 NSArray *args2; | |
| 243 | |
| 244 // Choose the args (TODO: This should use sonic annotator eventually) | |
| 245 if([extractor isEqualToString:@"chromagram"]) | |
| 246 { | |
| 247 args2 = [NSArray arrayWithObjects:@"-p",@"/Users/moj/planfile",@"-c", @"36", @"-h", @"11025", @"-w", @"16384", @"-n", @"32768", @"-i", @"1000", [filesToOpen objectAtIndex:i], featuresFileName, nil]; | |
| 248 } | |
| 249 else | |
| 250 { | |
| 251 args2 = [NSArray arrayWithObjects:@"-p",@"/Users/moj/planfile",@"-m", @"13", @"-h", @"11025", @"-w", @"16384", @"-n ", @"32768", @"-i", @"1000", [filesToOpen objectAtIndex:i], featuresFileName, nil]; | |
| 252 } | |
| 253 [task setArguments:args2]; | |
| 254 [task launch]; | |
| 255 [task waitUntilExit]; | |
| 256 [task release]; | |
| 257 | |
| 258 NSString* val = [[filesToOpen objectAtIndex:i] retain]; | |
| 259 NSString* key = [[[filesToOpen objectAtIndex:i] lastPathComponent] retain]; | |
| 260 | |
| 261 adb_insert_t insert; | |
| 262 insert.features = [featuresFileName cStringUsingEncoding:NSUTF8StringEncoding]; | |
| 263 insert.power = [powersFileName cStringUsingEncoding:NSUTF8StringEncoding]; | |
| 264 insert.times = NULL; | |
| 265 insert.key = [key cStringUsingEncoding:NSUTF8StringEncoding]; | |
| 266 | |
| 267 // Insert into db. | |
| 268 if(audiodb_insert(db, &insert)) | |
| 269 { | |
| 270 // TODO: Show an error message. | |
| 271 NSLog(@"Weep: %@ %@ %@", featuresFileName, powersFileName, key); | |
| 272 continue; | |
| 273 } | |
| 274 | |
| 275 // Update the plist store. | |
| 276 [trackMap setValue:val forKey:key]; | |
| 277 [trackMap writeToFile:plistFilename atomically: YES]; | |
| 278 | |
| 279 [self updateStatus]; | |
| 280 } | |
| 281 | |
| 282 newFrame.origin.x = [importSheet frame].origin.x; | |
| 283 newFrame.origin.y = [importSheet frame].origin.y + [extractingBox frame].size.height; | |
| 284 newFrame.size.width = [importSheet frame].size.width; | |
| 285 newFrame.size.height = [importSheet frame].size.height - [extractingBox frame].size.height; | |
| 286 | |
| 287 [importSheet setFrame:newFrame display:YES animate:YES]; | |
| 288 | |
| 289 [NSApp endModalSession:session]; | |
| 290 [importSheet orderOut:nil]; | |
| 291 [NSApp endSheet:importSheet]; | |
| 292 [indicator stopAnimation:self]; | |
| 293 [extractingBox setHidden:TRUE]; | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 /** | |
| 298 * Required table methods begin here. | |
| 299 */ | |
| 300 -(int)numberOfRowsInTableView:(NSTableView *)v | |
| 301 { | |
| 302 return [results count]; | |
| 303 } | |
| 304 | |
| 305 /** | |
| 306 * Return appropriate values - or the distance indicator if it's the meter column. | |
| 307 */ | |
| 308 -(id)tableView:(NSTableView *)v objectValueForTableColumn:(NSTableColumn *)tc row:(NSInteger)row | |
| 309 { | |
| 310 id result = [results objectAtIndex:row]; | |
| 311 id value = [result objectForKey:[tc identifier]]; | |
| 312 | |
| 313 if([[tc identifier] isEqualToString:@"meter"]) | |
| 314 { | |
| 315 NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle]; | |
| 316 [distance setFloatValue:10-[(NSNumber*)value floatValue]*100]; | |
| 317 return distance; | |
| 318 } | |
| 319 else | |
| 320 { | |
| 321 return value; | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 /** | |
| 326 * Handle column sorting. | |
| 327 */ | |
| 328 - (void)tableView:(NSTableView *)v sortDescriptorsDidChange:(NSArray *)oldDescriptors | |
| 329 { | |
| 330 [results sortUsingDescriptors:[v sortDescriptors]]; | |
| 331 [v reloadData]; | |
| 332 } | |
| 333 | |
| 334 /** | |
| 335 * Only enable the import menu option if a database is loaded. | |
| 336 */ | |
| 337 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem | |
| 338 { | |
| 339 SEL theAction = [anItem action]; | |
| 340 if (theAction == @selector(importAudio:)) | |
| 341 { | |
| 342 if(!db) | |
| 343 { | |
| 344 return NO; | |
| 345 } | |
| 346 } | |
| 347 return YES; | |
| 348 } | |
| 349 | |
| 350 /** | |
| 351 * Ensure play buttons are only enabled if a track is selected. | |
| 352 */ | |
| 353 -(IBAction)selectedChanged:(id)sender | |
| 354 { | |
| 355 if([tracksView numberOfSelectedRows] == 0) | |
| 356 { | |
| 357 [playBothButton setEnabled:FALSE]; | |
| 358 [playResultButton setEnabled:FALSE]; | |
| 359 } | |
| 360 else | |
| 361 { | |
| 362 [playBothButton setEnabled:TRUE]; | |
| 363 [playResultButton setEnabled:TRUE]; | |
| 364 } | |
| 365 } | |
| 366 | |
| 367 /** | |
| 368 * Play just the result track. | |
| 369 */ | |
| 370 -(IBAction)playResult:(id)sender | |
| 371 { | |
| 372 | |
| 373 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; | |
| 374 NSString* value = [selectedRow objectForKey:@"key"]; | |
| 375 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; | |
| 376 NSString* filename = [trackMap objectForKey:value]; | |
| 377 NSLog(@"Key: %@ Value: %@", value, filename); | |
| 378 | |
| 379 if(queryTrack) | |
| 380 { | |
| 381 if([queryTrack isPlaying]) | |
| 382 { | |
| 383 [queryTrack setDelegate:Nil]; | |
| 384 [queryTrack stop]; | |
| 385 } | |
| 386 [queryTrack release]; | |
| 387 } | |
| 388 | |
| 389 if(resultTrack) | |
| 390 { | |
| 391 if([resultTrack isPlaying]) | |
| 392 { | |
| 393 [resultTrack setDelegate:Nil]; | |
| 394 [resultTrack stop]; | |
| 395 } | |
| 396 [resultTrack release]; | |
| 397 } | |
| 398 | |
| 399 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain]; | |
| 400 [resultTrack setCurrentTime:ipos]; | |
| 401 [resultTrack setDelegate:self]; | |
| 402 [resultTrack play]; | |
| 403 | |
| 404 [stopButton setEnabled:YES]; | |
| 405 } | |
| 406 | |
| 407 /** | |
| 408 * Play the result and query simultaneously. | |
| 409 */ | |
| 410 -(IBAction)playBoth:(id)sender | |
| 411 { | |
| 412 | |
| 413 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; | |
| 414 NSString* value = [selectedRow objectForKey:@"key"]; | |
| 415 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; | |
| 416 float qpos = [[selectedRow objectForKey:@"qpos"] floatValue]; | |
| 417 NSString* filename = [trackMap objectForKey:value]; | |
| 418 NSLog(@"Key: %@ Value: %@", value, filename); | |
| 419 | |
| 420 if(queryTrack) | |
| 421 { | |
| 422 | |
| 423 if([queryTrack isPlaying]) | |
| 424 { | |
| 425 [queryTrack setDelegate:Nil]; | |
| 426 [queryTrack stop]; | |
| 427 } | |
| 428 [queryTrack release]; | |
| 429 } | |
| 430 if(resultTrack) | |
| 431 { | |
| 432 if([resultTrack isPlaying]) | |
| 433 { | |
| 434 [resultTrack setDelegate:Nil]; | |
| 435 [resultTrack stop]; | |
| 436 } | |
| 437 [resultTrack release]; | |
| 438 } | |
| 439 | |
| 440 // Get query track and shift to start point | |
| 441 queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain]; | |
| 442 [queryTrack setCurrentTime:qpos]; | |
| 443 [queryTrack setDelegate:self]; | |
| 444 | |
| 445 [queryTrack play]; | |
| 446 | |
| 447 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain]; | |
| 448 [resultTrack setCurrentTime:ipos]; | |
| 449 [resultTrack setDelegate:self]; | |
| 450 [resultTrack play]; | |
| 451 | |
| 452 [stopButton setEnabled:YES]; | |
| 453 } | |
| 454 | |
| 455 /** | |
| 456 * Disable the stop button after playback of both tracks. | |
| 457 */ | |
| 458 - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)playbackSuccessful | |
| 459 { | |
| 460 | |
| 461 if((queryTrack && [queryTrack isPlaying]) || (resultTrack && [resultTrack isPlaying])) | |
| 462 { | |
| 463 return; | |
| 464 } | |
| 465 else | |
| 466 { | |
| 467 [stopButton setEnabled:NO]; | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 /** | |
| 472 * Stop playback. | |
| 473 */ | |
| 474 -(IBAction)stopPlay:(id)sender | |
| 475 { | |
| 476 if(queryTrack) | |
| 477 { | |
| 478 [queryTrack stop]; | |
| 479 } | |
| 480 if(resultTrack) | |
| 481 { | |
| 482 [resultTrack stop]; | |
| 483 } | |
| 484 } | |
| 485 | |
| 486 /** | |
| 487 * Select an audio file, determine the key, and fire off a query. | |
| 488 */ | |
| 489 -(IBAction)chooseQuery:(id)sender | |
| 490 { | |
| 491 NSArray* fileTypes = [NSArray arrayWithObject:@"wav"]; | |
| 492 NSOpenPanel* panel = [NSOpenPanel openPanel]; | |
| 493 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; | |
| 494 if(response == NSFileHandlingPanelOKButton) | |
| 495 { | |
| 496 NSLog(@"%@", [panel filename]); | |
| 497 // Grab key | |
| 498 NSArray* opts = [trackMap allKeysForObject:[panel filename]]; | |
| 499 if([opts count] != 1) | |
| 500 { | |
| 501 NSAlert *alert = [[[NSAlert alloc] init] autorelease]; | |
| 502 [alert addButtonWithTitle:@"OK"]; | |
| 503 [alert setMessageText:@"Track not found"]; | |
| 504 [alert setInformativeText:@"Make sure you have specified a valid track identifier."]; | |
| 505 [alert setAlertStyle:NSWarningAlertStyle]; | |
| 506 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; | |
| 507 } | |
| 508 else | |
| 509 { | |
| 510 selectedKey = [opts objectAtIndex:0]; | |
| 511 [queryKey setStringValue:selectedKey]; | |
| 512 selectedFilename = [[panel filename] retain]; | |
| 513 [self performQuery]; | |
| 514 } | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 /** | |
| 519 * Actually perform the query. TODO: Monolithic. | |
| 520 */ | |
| 521 -(void)performQuery | |
| 522 { | |
| 523 NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename); | |
| 524 | |
| 525 adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t)); | |
| 526 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t)); | |
| 527 | |
| 528 spec->qid.sequence_length = 20; | |
| 529 spec->qid.sequence_start = 0; | |
| 530 spec->qid.flags = 0; | |
| 531 | |
| 532 // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE; | |
| 533 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK; | |
| 534 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED; | |
| 535 | |
| 536 spec->params.npoints = 1; | |
| 537 spec->params.ntracks = 100; | |
| 538 //spec->refine.radius = 5.0; | |
| 539 spec->refine.hopsize = 1; | |
| 540 // spec->refine.absolute_threshold = -6; | |
| 541 // spec->refine.relative_threshold = 10; | |
| 542 // spec->refine.duration_ratio = 0; | |
| 543 | |
| 544 spec->refine.flags = 0; | |
| 545 // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD; | |
| 546 // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD; | |
| 547 spec->refine.flags |= ADB_REFINE_HOP_SIZE; | |
| 548 //spec->refine.flags |= ADB_REFINE_RADIUS; | |
| 549 | |
| 550 adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t)); | |
| 551 spec->qid.datum->data = NULL; | |
| 552 spec->qid.datum->power = NULL; | |
| 553 spec->qid.datum->times = NULL; | |
| 554 | |
| 555 [results removeAllObjects]; | |
| 556 | |
| 557 int ok = audiodb_retrieve_datum(db, [selectedKey cStringUsingEncoding:NSUTF8StringEncoding], spec->qid.datum); | |
| 558 if(ok == 0) | |
| 559 { | |
| 560 NSLog(@"Got a datum"); | |
| 561 result = audiodb_query_spec(db, spec); | |
| 562 if(result == NULL) | |
| 563 { | |
| 564 | |
| 565 NSLog(@"No results"); | |
| 566 } | |
| 567 else | |
| 568 { | |
| 569 for(int i=0; i<result->nresults; i++) | |
| 570 { | |
| 571 NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4]; | |
| 572 [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].key] forKey:@"key"]; | |
| 573 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"]; | |
| 574 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"]; | |
| 575 [dict setValue:[NSNumber numberWithFloat:result->results[i].qpos/4] forKey:@"qpos"]; | |
| 576 [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/4] forKey:@"ipos"]; | |
| 577 NSLog(@"%s qpos %d ipos %d", result->results[i].key, result->results[i].qpos/4, result->results[i].ipos/4); | |
| 578 [results addObject: dict]; | |
| 579 } | |
| 580 } | |
| 581 | |
| 582 NSSortDescriptor *distSort = [[NSSortDescriptor alloc]initWithKey:@"meter" ascending:YES]; | |
| 583 NSArray *distDescs = [NSArray arrayWithObject:distSort]; | |
| 584 | |
| 585 [results sortUsingDescriptors:distDescs]; | |
| 586 [tracksView setSortDescriptors:distDescs]; | |
| 587 [tracksView reloadData]; | |
| 588 | |
| 589 } | |
| 590 else | |
| 591 { | |
| 592 NSAlert *alert = [[[NSAlert alloc] init] autorelease]; | |
| 593 [alert addButtonWithTitle:@"OK"]; | |
| 594 [alert setMessageText:@"Track not found"]; | |
| 595 [alert setInformativeText:@"Make sure you have specified a valid track identifier."]; | |
| 596 [alert setAlertStyle:NSWarningAlertStyle]; | |
| 597 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; | |
| 598 } | |
| 599 // audiodb_query_free_results(db, spec, result); | |
| 600 } | |
| 601 | |
| 602 @end |
