annotate examples/iAudioDB/AppController.m @ 688:8bc10774e56b

Disabled query button if no query file selected.
author mas01mj
date Fri, 12 Mar 2010 11:54:02 +0000
parents e2f4924130ef
children 015e361e5baa
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@687 8 #import "AppController.h"
mas01mj@669 9
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@687 98 [self reset];
mas01mj@685 99
mas01mj@669 100 // Create new db, and set flags.
mas01mj@685 101 db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], datasize, numtracks, dim);
mas01mj@669 102 audiodb_l2norm(db);
mas01mj@685 103
mas01mj@669 104 // Store useful paths.
mas01mj@669 105 dbName = [[[panel URL] relativePath] retain];
mas01mj@669 106 dbFilename = [[panel filename] retain];
mas01mj@669 107 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
mas01mj@685 108
mas01mj@669 109 // Create the plist file (contains mapping from filename to key).
mas01mj@685 110 dbState = [[NSMutableDictionary alloc] init];
mas01mj@669 111 trackMap = [[NSMutableDictionary alloc] init];
mas01mj@685 112 [dbState setValue:trackMap forKey:@"tracks"];
mas01mj@685 113 [dbState setValue:extractor forKey:@"extractor"];
mas01mj@685 114 [dbState setValue:[hopSizeField stringValue] forKey:@"hopsize"];
mas01mj@685 115 [dbState setValue:[windowSizeField stringValue] forKey:@"windowsize"];
mas01mj@685 116 [dbState writeToFile:plistFilename atomically:YES];
mas01mj@685 117
mas01mj@669 118 [queryKey setStringValue:@"None Selected"];
mas01mj@669 119 [self updateStatus];
mas01mj@669 120 }
mas01mj@669 121 }
mas01mj@669 122
mas01mj@687 123 -(void)reset
mas01mj@687 124 {
mas01mj@687 125 // Tidy any existing references up.
mas01mj@687 126 if(db)
mas01mj@687 127 {
mas01mj@687 128 NSLog(@"Close db");
mas01mj@687 129 audiodb_close(db);
mas01mj@687 130 }
mas01mj@687 131
mas01mj@687 132 if(dbFilename)
mas01mj@687 133 {
mas01mj@687 134 NSLog(@"Tidy up filenames");
mas01mj@687 135 [dbFilename release];
mas01mj@687 136 [dbName release];
mas01mj@687 137 [plistFilename release];
mas01mj@687 138 [trackMap release];
mas01mj@687 139 [dbState release];
mas01mj@687 140 }
mas01mj@687 141
mas01mj@688 142 if(selectedKey)
mas01mj@688 143 {
mas01mj@688 144 NSLog(@"Released selected key: %@", selectedKey);
mas01mj@688 145 [selectedKey release];
mas01mj@688 146 selectedKey = Nil;
mas01mj@688 147 NSLog(@"Is now %@", selectedKey);
mas01mj@688 148 }
mas01mj@688 149
mas01mj@688 150 if(selectedKey)
mas01mj@688 151 {
mas01mj@688 152 NSLog(@"Still evals");
mas01mj@688 153 }
mas01mj@688 154
mas01mj@687 155 // Reset query flags
mas01mj@687 156 [queryPath setStringValue: @"No file selected"];
mas01mj@687 157 [queryLengthSeconds setDoubleValue:0];
mas01mj@687 158 [queryLengthVectors setDoubleValue:0];
mas01mj@687 159 [multipleCheckBox setState:NSOnState];
mas01mj@687 160 }
mas01mj@687 161
mas01mj@669 162 /**
mas01mj@669 163 * Open an existing adb (which must have a plist)
mas01mj@669 164 */
mas01mj@669 165 -(IBAction)openDatabase:(id)sender
mas01mj@669 166 {
mas01mj@669 167 NSArray *fileTypes = [NSArray arrayWithObject:@"adb"];
mas01mj@669 168 NSOpenPanel* panel = [NSOpenPanel openPanel];
mas01mj@669 169 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
mas01mj@669 170 if(response == NSFileHandlingPanelOKButton)
mas01mj@669 171 {
mas01mj@687 172 [self reset];
mas01mj@669 173
mas01mj@669 174 // Store useful paths.
mas01mj@680 175 NSLog(@"Open");
mas01mj@680 176 db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY);
mas01mj@669 177 dbName = [[[panel URL] relativePath] retain];
mas01mj@669 178 dbFilename = [[panel filename] retain];
mas01mj@669 179
mas01mj@669 180 // TODO: Verify this exists!
mas01mj@669 181 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
mas01mj@669 182
mas01mj@669 183 // Clear out any old results.
mas01mj@669 184 [results removeAllObjects];
mas01mj@669 185 [tracksView reloadData];
mas01mj@669 186
mas01mj@669 187 [queryKey setStringValue:@"None Selected"];
mas01mj@669 188
mas01mj@669 189 adb_liszt_results_t* liszt_results = audiodb_liszt(db);
mas01mj@669 190
mas01mj@669 191 for(int k=0; k<liszt_results->nresults; k++)
mas01mj@669 192 {
mas01mj@669 193 NSMutableString *trackVal = [[NSMutableString alloc] init];
mas01mj@669 194 [trackVal appendFormat:@"%s", liszt_results->entries[k].key];
mas01mj@669 195 }
mas01mj@669 196
mas01mj@669 197 audiodb_liszt_free_results(db, liszt_results);
mas01mj@685 198 dbState = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain];
mas01mj@685 199 trackMap = [[dbState objectForKey:@"tracks"] retain];
mas01mj@685 200
mas01mj@687 201 [self updateStatus];
mas01mj@687 202
mas01mj@669 203 NSLog(@"Size: %d", [trackMap count]);
mas01mj@669 204 }
mas01mj@669 205 }
mas01mj@669 206
mas01mj@687 207 -(IBAction)pathAction:(id)sender
mas01mj@687 208 {
mas01mj@687 209 NSLog(@"Path action");
mas01mj@687 210 }
mas01mj@687 211
mas01mj@669 212 /**
mas01mj@669 213 * Update button states and status field based on current state.
mas01mj@669 214 */
mas01mj@669 215 -(void)updateStatus
mas01mj@669 216 {
mas01mj@680 217 NSLog(@"Update status");
mas01mj@669 218 if(db)
mas01mj@669 219 {
mas01mj@680 220 NSLog(@"Got a db");
mas01mj@682 221 adb_status_t *status = (adb_status_t *)malloc(sizeof(adb_status_t));
mas01mj@669 222 int flags;
mas01mj@669 223 flags = audiodb_status(db, status);
mas01mj@687 224 [statusField setStringValue: [NSString stringWithFormat:@"%@ Dim: %d Files: %d Hop: %@ Win: %@ Ext: %@",
mas01mj@687 225 dbName,
mas01mj@687 226 status->dim,
mas01mj@687 227 status->numFiles,
mas01mj@687 228 [dbState objectForKey:@"hopsize"],
mas01mj@687 229 [dbState objectForKey:@"windowsize"],
mas01mj@687 230 [dbState objectForKey:@"extractor"]]];
mas01mj@687 231 [performQueryButton setEnabled:YES];
mas01mj@669 232 }
mas01mj@669 233 else
mas01mj@669 234 {
mas01mj@680 235 NSLog(@"No db");
mas01mj@687 236 [performQueryButton setEnabled:NO];
mas01mj@688 237 [playBothButton setEnabled:NO];
mas01mj@688 238 [playResultButton setEnabled:NO];
mas01mj@669 239 }
mas01mj@669 240 }
mas01mj@669 241
mas01mj@669 242 /**
mas01mj@669 243 * Choose the file(s) to be imported.
mas01mj@669 244 * TODO: Currently handles the import process too - split this off.
mas01mj@669 245 */
mas01mj@685 246 -(IBAction)importAudio:(id)sender
mas01mj@669 247 {
mas01mj@669 248 [tracksView reloadData];
mas01mj@669 249
mas01mj@669 250 NSArray *fileTypes = [NSArray arrayWithObject:@"wav"];
mas01mj@669 251 NSOpenPanel* panel = [NSOpenPanel openPanel];
mas01mj@669 252 [panel setAllowsMultipleSelection:TRUE];
mas01mj@669 253 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
mas01mj@669 254 if(response == NSFileHandlingPanelOKButton)
mas01mj@669 255 {
mas01mj@685 256 [indicator startAnimation:self];
mas01mj@669 257
mas01mj@685 258 [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
mas01mj@685 259 session = [NSApp beginModalSessionForWindow: importSheet];
mas01mj@685 260 [NSApp runModalSession:session];
mas01mj@669 261
mas01mj@669 262 NSArray *filesToOpen = [panel filenames];
mas01mj@669 263
mas01mj@685 264 NSString* extractor = [dbState objectForKey:@"extractor"];
mas01mj@688 265 NSString* extractorPath = [NSString stringWithFormat:@"/Applications/iAudioDB.app/rdf/%@.n3", extractor];
mas01mj@669 266
mas01mj@687 267 // TODO Shift this process into a separate function.
mas01mj@685 268 // Create the customized extractor config
mas01mj@685 269 NSString* extractorContent = [NSString stringWithContentsOfFile:extractorPath];
mas01mj@685 270 NSString* hopStr = [dbState objectForKey:@"hopsize"];
mas01mj@685 271 NSString* winStr = [dbState objectForKey:@"windowsize"];
mas01mj@685 272 NSString* newContent = [[extractorContent stringByReplacingOccurrencesOfString:@"HOP_SIZE" withString:hopStr]
mas01mj@685 273 stringByReplacingOccurrencesOfString:@"WINDOW_SIZE" withString:winStr];
mas01mj@685 274 NSString* n3FileName = [NSTemporaryDirectory() stringByAppendingPathComponent:@"extractor_config.n3"];
mas01mj@680 275
mas01mj@685 276 NSError* error;
mas01mj@685 277 [newContent writeToFile:n3FileName atomically:YES encoding:NSASCIIStringEncoding error:&error];
mas01mj@680 278
mas01mj@669 279 for(int i=0; i<[filesToOpen count]; i++)
mas01mj@680 280 {
mas01mj@680 281 audiodb_close(db);
mas01mj@680 282 NSString* tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"];
mas01mj@680 283 const char* tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
mas01mj@680 284 char* tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
mas01mj@669 285 strcpy(tempFileNameCString, tempFileTemplateCString);
mas01mj@669 286 mktemp(tempFileNameCString);
mas01mj@669 287
mas01mj@669 288 NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
mas01mj@669 289 free(tempFileNameCString);
mas01mj@669 290
mas01mj@680 291 NSTask* task = [[NSTask alloc] init];
mas01mj@669 292
mas01mj@680 293 [task setLaunchPath:@"/usr/local/bin/sonic-annotator"];
mas01mj@680 294 NSArray* args;
mas01mj@685 295 args = [NSArray arrayWithObjects:@"-t", n3FileName, @"-w", @"rdf", @"-r", @"--rdf-network", @"--rdf-one-file", featuresFileName, @"--rdf-force", [filesToOpen objectAtIndex:i], nil];
mas01mj@680 296 [task setArguments:args];
mas01mj@669 297 [task launch];
mas01mj@669 298 [task waitUntilExit];
mas01mj@669 299 [task release];
mas01mj@669 300
mas01mj@680 301 NSTask* importTask = [[NSTask alloc] init];
mas01mj@680 302 [importTask setLaunchPath:@"/usr/local/bin/populate"];
mas01mj@680 303 args = [NSArray arrayWithObjects:featuresFileName, dbFilename, nil];
mas01mj@680 304 [importTask setArguments:args];
mas01mj@680 305 [importTask launch];
mas01mj@680 306 [importTask waitUntilExit];
mas01mj@680 307 [importTask release];
mas01mj@680 308
mas01mj@669 309 NSString* val = [[filesToOpen objectAtIndex:i] retain];
mas01mj@669 310 NSString* key = [[[filesToOpen objectAtIndex:i] lastPathComponent] retain];
mas01mj@685 311
mas01mj@669 312 // Update the plist store.
mas01mj@669 313 [trackMap setValue:val forKey:key];
mas01mj@685 314 [dbState writeToFile:plistFilename atomically: YES];
mas01mj@669 315
mas01mj@680 316
mas01mj@680 317 db = audiodb_open([dbFilename cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY);
mas01mj@669 318 [self updateStatus];
mas01mj@669 319 }
mas01mj@669 320
mas01mj@669 321 [NSApp endModalSession:session];
mas01mj@669 322 [importSheet orderOut:nil];
mas01mj@669 323 [NSApp endSheet:importSheet];
mas01mj@669 324 [indicator stopAnimation:self];
mas01mj@669 325 }
mas01mj@669 326 }
mas01mj@669 327
mas01mj@669 328 /**
mas01mj@669 329 * Required table methods begin here.
mas01mj@669 330 */
mas01mj@669 331 -(int)numberOfRowsInTableView:(NSTableView *)v
mas01mj@669 332 {
mas01mj@669 333 return [results count];
mas01mj@669 334 }
mas01mj@669 335
mas01mj@669 336 /**
mas01mj@669 337 * Return appropriate values - or the distance indicator if it's the meter column.
mas01mj@669 338 */
mas01mj@669 339 -(id)tableView:(NSTableView *)v objectValueForTableColumn:(NSTableColumn *)tc row:(NSInteger)row
mas01mj@669 340 {
mas01mj@669 341 id result = [results objectAtIndex:row];
mas01mj@669 342 id value = [result objectForKey:[tc identifier]];
mas01mj@669 343
mas01mj@669 344 if([[tc identifier] isEqualToString:@"meter"])
mas01mj@669 345 {
mas01mj@669 346 NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle];
mas01mj@669 347 [distance setFloatValue:10-[(NSNumber*)value floatValue]*100];
mas01mj@669 348 return distance;
mas01mj@669 349 }
mas01mj@669 350 else
mas01mj@669 351 {
mas01mj@669 352 return value;
mas01mj@669 353 }
mas01mj@669 354 }
mas01mj@669 355
mas01mj@669 356 /**
mas01mj@669 357 * Handle column sorting.
mas01mj@669 358 */
mas01mj@669 359 - (void)tableView:(NSTableView *)v sortDescriptorsDidChange:(NSArray *)oldDescriptors
mas01mj@669 360 {
mas01mj@669 361 [results sortUsingDescriptors:[v sortDescriptors]];
mas01mj@669 362 [v reloadData];
mas01mj@669 363 }
mas01mj@669 364
mas01mj@669 365 /**
mas01mj@669 366 * Only enable the import menu option if a database is loaded.
mas01mj@669 367 */
mas01mj@669 368 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
mas01mj@669 369 {
mas01mj@669 370 SEL theAction = [anItem action];
mas01mj@669 371 if (theAction == @selector(importAudio:))
mas01mj@669 372 {
mas01mj@669 373 if(!db)
mas01mj@669 374 {
mas01mj@669 375 return NO;
mas01mj@669 376 }
mas01mj@669 377 }
mas01mj@669 378 return YES;
mas01mj@669 379 }
mas01mj@669 380
mas01mj@669 381 /**
mas01mj@669 382 * Ensure play buttons are only enabled if a track is selected.
mas01mj@669 383 */
mas01mj@669 384 -(IBAction)selectedChanged:(id)sender
mas01mj@669 385 {
mas01mj@669 386 if([tracksView numberOfSelectedRows] == 0)
mas01mj@669 387 {
mas01mj@669 388 [playBothButton setEnabled:FALSE];
mas01mj@669 389 [playResultButton setEnabled:FALSE];
mas01mj@669 390 }
mas01mj@669 391 else
mas01mj@669 392 {
mas01mj@669 393 [playBothButton setEnabled:TRUE];
mas01mj@669 394 [playResultButton setEnabled:TRUE];
mas01mj@669 395 }
mas01mj@669 396 }
mas01mj@669 397
mas01mj@669 398 /**
mas01mj@669 399 * Play just the result track.
mas01mj@669 400 */
mas01mj@669 401 -(IBAction)playResult:(id)sender
mas01mj@669 402 {
mas01mj@669 403
mas01mj@684 404 if([tracksView selectedRow] == -1)
mas01mj@684 405 {
mas01mj@684 406 return;
mas01mj@684 407 }
mas01mj@684 408
mas01mj@669 409 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
mas01mj@669 410 NSString* value = [selectedRow objectForKey:@"key"];
mas01mj@669 411 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
mas01mj@669 412 NSString* filename = [trackMap objectForKey:value];
mas01mj@669 413 NSLog(@"Key: %@ Value: %@", value, filename);
mas01mj@669 414
mas01mj@669 415 if(queryTrack)
mas01mj@669 416 {
mas01mj@669 417 if([queryTrack isPlaying])
mas01mj@669 418 {
mas01mj@669 419 [queryTrack setDelegate:Nil];
mas01mj@669 420 [queryTrack stop];
mas01mj@669 421 }
mas01mj@669 422 [queryTrack release];
mas01mj@669 423 }
mas01mj@669 424
mas01mj@669 425 if(resultTrack)
mas01mj@669 426 {
mas01mj@669 427 if([resultTrack isPlaying])
mas01mj@669 428 {
mas01mj@669 429 [resultTrack setDelegate:Nil];
mas01mj@669 430 [resultTrack stop];
mas01mj@669 431 }
mas01mj@669 432 [resultTrack release];
mas01mj@669 433 }
mas01mj@669 434
mas01mj@669 435 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain];
mas01mj@669 436 [resultTrack setCurrentTime:ipos];
mas01mj@669 437 [resultTrack setDelegate:self];
mas01mj@669 438 [resultTrack play];
mas01mj@669 439
mas01mj@669 440 [stopButton setEnabled:YES];
mas01mj@669 441 }
mas01mj@669 442
mas01mj@669 443 /**
mas01mj@669 444 * Play the result and query simultaneously.
mas01mj@669 445 */
mas01mj@669 446 -(IBAction)playBoth:(id)sender
mas01mj@669 447 {
mas01mj@669 448
mas01mj@669 449 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
mas01mj@669 450 NSString* value = [selectedRow objectForKey:@"key"];
mas01mj@669 451 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
mas01mj@669 452 float qpos = [[selectedRow objectForKey:@"qpos"] floatValue];
mas01mj@669 453 NSString* filename = [trackMap objectForKey:value];
mas01mj@669 454 NSLog(@"Key: %@ Value: %@", value, filename);
mas01mj@669 455
mas01mj@669 456 if(queryTrack)
mas01mj@669 457 {
mas01mj@669 458
mas01mj@669 459 if([queryTrack isPlaying])
mas01mj@669 460 {
mas01mj@669 461 [queryTrack setDelegate:Nil];
mas01mj@669 462 [queryTrack stop];
mas01mj@669 463 }
mas01mj@669 464 [queryTrack release];
mas01mj@669 465 }
mas01mj@669 466 if(resultTrack)
mas01mj@669 467 {
mas01mj@669 468 if([resultTrack isPlaying])
mas01mj@669 469 {
mas01mj@669 470 [resultTrack setDelegate:Nil];
mas01mj@669 471 [resultTrack stop];
mas01mj@669 472 }
mas01mj@669 473 [resultTrack release];
mas01mj@669 474 }
mas01mj@669 475
mas01mj@669 476 // Get query track and shift to start point
mas01mj@669 477 queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain];
mas01mj@669 478 [queryTrack setCurrentTime:qpos];
mas01mj@669 479 [queryTrack setDelegate:self];
mas01mj@669 480
mas01mj@669 481 [queryTrack play];
mas01mj@669 482
mas01mj@669 483 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain];
mas01mj@669 484 [resultTrack setCurrentTime:ipos];
mas01mj@669 485 [resultTrack setDelegate:self];
mas01mj@669 486 [resultTrack play];
mas01mj@669 487
mas01mj@669 488 [stopButton setEnabled:YES];
mas01mj@669 489 }
mas01mj@669 490
mas01mj@669 491 /**
mas01mj@669 492 * Disable the stop button after playback of both tracks.
mas01mj@669 493 */
mas01mj@669 494 - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)playbackSuccessful
mas01mj@669 495 {
mas01mj@669 496
mas01mj@669 497 if((queryTrack && [queryTrack isPlaying]) || (resultTrack && [resultTrack isPlaying]))
mas01mj@669 498 {
mas01mj@669 499 return;
mas01mj@669 500 }
mas01mj@669 501 else
mas01mj@669 502 {
mas01mj@669 503 [stopButton setEnabled:NO];
mas01mj@669 504 }
mas01mj@669 505 }
mas01mj@669 506
mas01mj@669 507 /**
mas01mj@669 508 * Stop playback.
mas01mj@669 509 */
mas01mj@669 510 -(IBAction)stopPlay:(id)sender
mas01mj@669 511 {
mas01mj@669 512 if(queryTrack)
mas01mj@669 513 {
mas01mj@669 514 [queryTrack stop];
mas01mj@669 515 }
mas01mj@669 516 if(resultTrack)
mas01mj@669 517 {
mas01mj@669 518 [resultTrack stop];
mas01mj@669 519 }
mas01mj@669 520 }
mas01mj@669 521
mas01mj@669 522 /**
mas01mj@669 523 * Select an audio file, determine the key, and fire off a query.
mas01mj@669 524 */
mas01mj@669 525 -(IBAction)chooseQuery:(id)sender
mas01mj@669 526 {
mas01mj@688 527 [queryButton setEnabled:(selectedKey ? YES : NO)];
mas01mj@687 528 [NSApp beginSheet:querySheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
mas01mj@687 529 session = [NSApp beginModalSessionForWindow:querySheet];
mas01mj@687 530 [NSApp runModalSession:session];
mas01mj@687 531 }
mas01mj@687 532
mas01mj@687 533
mas01mj@687 534 -(IBAction)selectQueryFile:(id)sender
mas01mj@687 535 {
mas01mj@669 536 NSArray* fileTypes = [NSArray arrayWithObject:@"wav"];
mas01mj@669 537 NSOpenPanel* panel = [NSOpenPanel openPanel];
mas01mj@669 538 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
mas01mj@669 539 if(response == NSFileHandlingPanelOKButton)
mas01mj@669 540 {
mas01mj@669 541 NSArray* opts = [trackMap allKeysForObject:[panel filename]];
mas01mj@669 542 if([opts count] != 1)
mas01mj@669 543 {
mas01mj@687 544 // TODO : Needs fixing!
mas01mj@687 545
mas01mj@669 546 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
mas01mj@669 547 [alert addButtonWithTitle:@"OK"];
mas01mj@669 548 [alert setMessageText:@"Track not found"];
mas01mj@669 549 [alert setInformativeText:@"Make sure you have specified a valid track identifier."];
mas01mj@669 550 [alert setAlertStyle:NSWarningAlertStyle];
mas01mj@669 551 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
mas01mj@669 552 }
mas01mj@669 553 else
mas01mj@669 554 {
mas01mj@669 555 selectedKey = [opts objectAtIndex:0];
mas01mj@669 556 [queryKey setStringValue:selectedKey];
mas01mj@687 557 [queryPath setStringValue:selectedKey];
mas01mj@669 558 selectedFilename = [[panel filename] retain];
mas01mj@688 559 [queryButton setEnabled:YES];
mas01mj@687 560
mas01mj@687 561 [self resetLengths:self];
mas01mj@669 562 }
mas01mj@669 563 }
mas01mj@669 564 }
mas01mj@669 565
mas01mj@687 566 -(IBAction)resetLengths:(id)sender
mas01mj@687 567 {
mas01mj@687 568 queryTrack = [[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES];
mas01mj@687 569 NSLog(@"%f", [queryTrack duration]);
mas01mj@687 570 double samples = ([queryTrack duration]*44100);
mas01mj@687 571 double hopSize = [[dbState objectForKey:@"hopsize"] doubleValue];
mas01mj@687 572 double winSize = [[dbState objectForKey:@"windowsize"] doubleValue];
mas01mj@687 573
mas01mj@687 574 [queryLengthSeconds setDoubleValue:ceil([queryTrack duration])];
mas01mj@687 575 [queryLengthVectors setDoubleValue:ceil((samples-winSize)/hopSize)];
mas01mj@687 576
mas01mj@687 577 }
mas01mj@687 578
mas01mj@687 579 - (void)controlTextDidChange:(NSNotification *)nd
mas01mj@687 580 {
mas01mj@687 581 NSTextField *ed = [nd object];
mas01mj@687 582
mas01mj@687 583 double hopSize = [[dbState objectForKey:@"hopsize"] doubleValue];
mas01mj@687 584 double winSize = [[dbState objectForKey:@"windowsize"] doubleValue];
mas01mj@687 585
mas01mj@687 586 if (ed == queryLengthSeconds)
mas01mj@687 587 {
mas01mj@687 588 double secs = [queryLengthSeconds doubleValue];
mas01mj@687 589 if(secs > 0)
mas01mj@687 590 {
mas01mj@688 591 // (samples - windowSize) / hopSize
mas01mj@688 592
mas01mj@687 593 [queryLengthVectors setDoubleValue:ceil(((secs*44100)-winSize)/hopSize)];
mas01mj@687 594 }
mas01mj@687 595 }
mas01mj@687 596 if (ed == queryLengthVectors)
mas01mj@687 597 {
mas01mj@687 598 double vectors = [queryLengthVectors doubleValue];
mas01mj@687 599 if(vectors > 0)
mas01mj@687 600 {
mas01mj@687 601 [queryLengthSeconds setDoubleValue:ceil(((hopSize*vectors)+winSize)/44100)];
mas01mj@687 602 }
mas01mj@687 603 }
mas01mj@687 604 };
mas01mj@687 605
mas01mj@687 606 -(IBAction)cancelQuery:(id)sender
mas01mj@687 607 {
mas01mj@687 608 [NSApp endModalSession:session];
mas01mj@687 609 [querySheet orderOut:nil];
mas01mj@687 610 [NSApp endSheet:querySheet];
mas01mj@687 611 }
mas01mj@687 612
mas01mj@669 613 /**
mas01mj@669 614 * Actually perform the query. TODO: Monolithic.
mas01mj@669 615 */
mas01mj@687 616 -(IBAction)performQuery:(id)sender
mas01mj@669 617 {
mas01mj@687 618 [NSApp endModalSession:session];
mas01mj@687 619 [querySheet orderOut:nil];
mas01mj@687 620 [NSApp endSheet:querySheet];
mas01mj@687 621
mas01mj@669 622 NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename);
mas01mj@669 623
mas01mj@669 624 adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t));
mas01mj@669 625 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t));
mas01mj@669 626
mas01mj@687 627 spec->qid.sequence_length = [queryLengthVectors doubleValue];
mas01mj@669 628 spec->qid.sequence_start = 0;
mas01mj@687 629 spec->qid.flags = 0;
mas01mj@687 630 // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE;
mas01mj@669 631
mas01mj@669 632 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK;
mas01mj@687 633
mas01mj@687 634 if([multipleCheckBox state] == NSOnState)
mas01mj@687 635 {
mas01mj@687 636 spec->params.npoints = 10;
mas01mj@687 637 }
mas01mj@687 638 else
mas01mj@687 639 {
mas01mj@687 640 spec->params.npoints = 1;
mas01mj@687 641 }
mas01mj@687 642
mas01mj@669 643 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
mas01mj@669 644
mas01mj@669 645 spec->params.ntracks = 100;
mas01mj@669 646 //spec->refine.radius = 5.0;
mas01mj@669 647 // spec->refine.absolute_threshold = -6;
mas01mj@669 648 // spec->refine.relative_threshold = 10;
mas01mj@669 649 // spec->refine.duration_ratio = 0;
mas01mj@669 650
mas01mj@669 651 spec->refine.flags = 0;
mas01mj@669 652 // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
mas01mj@669 653 // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
mas01mj@682 654 // spec->refine.flags |= ADB_REFINE_HOP_SIZE;
mas01mj@669 655 //spec->refine.flags |= ADB_REFINE_RADIUS;
mas01mj@669 656
mas01mj@669 657 adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t));
mas01mj@669 658 spec->qid.datum->data = NULL;
mas01mj@669 659 spec->qid.datum->power = NULL;
mas01mj@669 660 spec->qid.datum->times = NULL;
mas01mj@669 661
mas01mj@669 662 [results removeAllObjects];
mas01mj@669 663
mas01mj@669 664 int ok = audiodb_retrieve_datum(db, [selectedKey cStringUsingEncoding:NSUTF8StringEncoding], spec->qid.datum);
mas01mj@669 665 if(ok == 0)
mas01mj@669 666 {
mas01mj@669 667 NSLog(@"Got a datum");
mas01mj@669 668 result = audiodb_query_spec(db, spec);
mas01mj@669 669 if(result == NULL)
mas01mj@669 670 {
mas01mj@669 671
mas01mj@669 672 NSLog(@"No results");
mas01mj@669 673 }
mas01mj@669 674 else
mas01mj@669 675 {
mas01mj@680 676 float divisor = (44100/2048);
mas01mj@669 677 for(int i=0; i<result->nresults; i++)
mas01mj@669 678 {
mas01mj@682 679
mas01mj@669 680 NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4];
mas01mj@682 681 [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].ikey] forKey:@"key"];
mas01mj@669 682 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"];
mas01mj@669 683 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"];
mas01mj@680 684 [dict setValue:[NSNumber numberWithFloat:result->results[i].qpos/divisor] forKey:@"qpos"];
mas01mj@680 685 [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/divisor] forKey:@"ipos"];
mas01mj@682 686 NSLog(@"%s qpos %d ipos %d", result->results[i].ikey, result->results[i].qpos/divisor, result->results[i].ipos/divisor);
mas01mj@669 687 [results addObject: dict];
mas01mj@669 688 }
mas01mj@669 689 }
mas01mj@669 690
mas01mj@669 691 NSSortDescriptor *distSort = [[NSSortDescriptor alloc]initWithKey:@"meter" ascending:YES];
mas01mj@669 692 NSArray *distDescs = [NSArray arrayWithObject:distSort];
mas01mj@669 693
mas01mj@669 694 [results sortUsingDescriptors:distDescs];
mas01mj@669 695 [tracksView setSortDescriptors:distDescs];
mas01mj@669 696 [tracksView reloadData];
mas01mj@669 697
mas01mj@669 698 }
mas01mj@669 699 else
mas01mj@669 700 {
mas01mj@669 701 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
mas01mj@669 702 [alert addButtonWithTitle:@"OK"];
mas01mj@669 703 [alert setMessageText:@"Track not found"];
mas01mj@669 704 [alert setInformativeText:@"Make sure you have specified a valid track identifier."];
mas01mj@669 705 [alert setAlertStyle:NSWarningAlertStyle];
mas01mj@669 706 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
mas01mj@669 707 }
mas01mj@669 708 // audiodb_query_free_results(db, spec, result);
mas01mj@669 709 }
mas01mj@669 710
mas01mj@669 711 @end