annotate examples/iAudioDB/AppController.m @ 685:e78e5a80b73d

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