annotate examples/iAudioDB/AppController.m @ 687:e2f4924130ef

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