mas01mj@669: // mas01mj@669: // AppController.m mas01mj@669: // iAudioDB mas01mj@669: // mas01mj@669: // Created by Mike Jewell on 27/01/2010. mas01mj@669: // Copyright 2010 __MyCompanyName__. All rights reserved. mas01mj@669: // mas01mj@669: mas01mj@669: #import "AppController.h" mas01mj@669: mas01mj@669: mas01mj@669: @implementation AppController mas01mj@669: mas01mj@669: -(id)init mas01mj@669: { mas01mj@669: [super init]; mas01mj@669: mas01mj@669: // A max of 100 results. mas01mj@669: results = [[NSMutableArray alloc] initWithCapacity: 100]; mas01mj@669: mas01mj@669: return self; mas01mj@669: } mas01mj@669: mas01mj@684: - (void)awakeFromNib { mas01mj@684: [tracksView setTarget:self]; mas01mj@684: [tracksView setDoubleAction:@selector(tableDoubleClick:)]; mas01mj@684: } mas01mj@684: mas01mj@684: - (IBAction)tableDoubleClick:(id)sender mas01mj@684: { mas01mj@684: [self playResult:Nil]; mas01mj@684: // NSLog(@"Table double clicked"); mas01mj@684: } mas01mj@684: mas01mj@669: mas01mj@669: /** mas01mj@669: * Create a new database, given the selected filename. mas01mj@669: */ mas01mj@669: -(IBAction)newDatabase:(id)sender mas01mj@669: { mas01mj@685: mas01mj@685: [NSApp beginSheet:createSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; mas01mj@685: session = [NSApp beginModalSessionForWindow:createSheet]; mas01mj@685: [NSApp runModalSession:session]; mas01mj@685: } mas01mj@685: mas01mj@685: /** mas01mj@685: * Cancel the db creation (at configuration time). mas01mj@685: */ mas01mj@685: -(IBAction)cancelCreate:(id)sender mas01mj@685: { mas01mj@685: [NSApp endModalSession:session]; mas01mj@685: [createSheet orderOut:nil]; mas01mj@685: [NSApp endSheet:createSheet]; mas01mj@685: } mas01mj@685: mas01mj@685: -(IBAction)createDatabase:(id)sender mas01mj@685: { mas01mj@685: [self cancelCreate:self]; mas01mj@685: mas01mj@669: NSSavePanel* panel = [NSSavePanel savePanel]; mas01mj@669: NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@""]; mas01mj@685: mas01mj@669: [results removeAllObjects]; mas01mj@669: [tracksView reloadData]; mas01mj@685: mas01mj@669: if(response == NSFileHandlingPanelOKButton) mas01mj@669: { mas01mj@685: // Work out which extractor to use mas01mj@685: NSString* extractor = @"adb_chroma"; mas01mj@685: // TODO: This should be stored with the n3. mas01mj@685: int dim; mas01mj@685: switch([extractorOptions selectedTag]) mas01mj@685: { mas01mj@685: case 0: mas01mj@685: extractor = @"adb_chroma"; mas01mj@685: dim = 12; mas01mj@685: break; mas01mj@685: case 1: mas01mj@685: extractor = @"adb_cq"; mas01mj@685: dim = 48; mas01mj@685: break; mas01mj@685: case 2: mas01mj@685: extractor = @"qm_chroma"; mas01mj@685: dim = 12; mas01mj@685: break; mas01mj@685: case 3: mas01mj@685: extractor = @"qm_mfcc"; mas01mj@685: dim = 12; mas01mj@685: break; mas01mj@685: } mas01mj@685: mas01mj@685: // Calculate the max DB size mas01mj@685: int vectors = ceil(([maxLengthField doubleValue] * 60) / ([hopSizeField doubleValue] / 44100)); mas01mj@685: int numtracks = [maxTracksField intValue]; mas01mj@685: int datasize = ceil((numtracks * vectors * dim * 8) / 1024 / 1024); // In MB mas01mj@685: mas01mj@669: // TODO: Refactor this into a 'tidy' method. mas01mj@669: // Tidy any existing references up. mas01mj@669: if(db) mas01mj@669: { mas01mj@669: audiodb_close(db); mas01mj@669: } mas01mj@685: mas01mj@669: if(dbFilename) mas01mj@669: { mas01mj@669: [dbFilename release]; mas01mj@669: [dbName release]; mas01mj@669: [plistFilename release]; mas01mj@669: } mas01mj@685: mas01mj@669: // Create new db, and set flags. mas01mj@685: db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], datasize, numtracks, dim); mas01mj@669: audiodb_l2norm(db); mas01mj@685: mas01mj@669: // Store useful paths. mas01mj@669: dbName = [[[panel URL] relativePath] retain]; mas01mj@669: dbFilename = [[panel filename] retain]; mas01mj@669: plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain]; mas01mj@685: mas01mj@669: // Create the plist file (contains mapping from filename to key). mas01mj@685: dbState = [[NSMutableDictionary alloc] init]; mas01mj@669: trackMap = [[NSMutableDictionary alloc] init]; mas01mj@685: [dbState setValue:trackMap forKey:@"tracks"]; mas01mj@685: [dbState setValue:extractor forKey:@"extractor"]; mas01mj@685: [dbState setValue:[hopSizeField stringValue] forKey:@"hopsize"]; mas01mj@685: [dbState setValue:[windowSizeField stringValue] forKey:@"windowsize"]; mas01mj@685: [dbState writeToFile:plistFilename atomically:YES]; mas01mj@685: mas01mj@669: [queryKey setStringValue:@"None Selected"]; mas01mj@669: [self updateStatus]; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Open an existing adb (which must have a plist) mas01mj@669: */ mas01mj@669: -(IBAction)openDatabase:(id)sender mas01mj@669: { mas01mj@669: NSArray *fileTypes = [NSArray arrayWithObject:@"adb"]; mas01mj@669: NSOpenPanel* panel = [NSOpenPanel openPanel]; mas01mj@669: NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; mas01mj@669: if(response == NSFileHandlingPanelOKButton) mas01mj@669: { mas01mj@669: // Tidy any existing references up. mas01mj@669: if(db) mas01mj@669: { mas01mj@680: NSLog(@"Close db"); mas01mj@669: audiodb_close(db); mas01mj@669: } mas01mj@669: mas01mj@669: if(dbFilename) mas01mj@669: { mas01mj@680: NSLog(@"Tidy up filenames"); mas01mj@669: [dbFilename release]; mas01mj@669: [dbName release]; mas01mj@669: [plistFilename release]; mas01mj@685: [trackMap release]; mas01mj@685: [dbState release]; mas01mj@669: } mas01mj@669: mas01mj@669: // Store useful paths. mas01mj@680: NSLog(@"Open"); mas01mj@680: db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY); mas01mj@669: dbName = [[[panel URL] relativePath] retain]; mas01mj@669: dbFilename = [[panel filename] retain]; mas01mj@669: mas01mj@669: // TODO: Verify this exists! mas01mj@669: plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain]; mas01mj@669: mas01mj@669: // Clear out any old results. mas01mj@669: [results removeAllObjects]; mas01mj@669: [tracksView reloadData]; mas01mj@669: mas01mj@669: [queryKey setStringValue:@"None Selected"]; mas01mj@669: [self updateStatus]; mas01mj@669: mas01mj@669: adb_liszt_results_t* liszt_results = audiodb_liszt(db); mas01mj@669: mas01mj@669: for(int k=0; knresults; k++) mas01mj@669: { mas01mj@669: NSMutableString *trackVal = [[NSMutableString alloc] init]; mas01mj@669: [trackVal appendFormat:@"%s", liszt_results->entries[k].key]; mas01mj@669: } mas01mj@669: mas01mj@669: audiodb_liszt_free_results(db, liszt_results); mas01mj@685: dbState = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain]; mas01mj@685: trackMap = [[dbState objectForKey:@"tracks"] retain]; mas01mj@685: mas01mj@669: NSLog(@"Size: %d", [trackMap count]); mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Update button states and status field based on current state. mas01mj@669: */ mas01mj@669: -(void)updateStatus mas01mj@669: { mas01mj@680: NSLog(@"Update status"); mas01mj@669: if(db) mas01mj@669: { mas01mj@680: NSLog(@"Got a db"); mas01mj@682: adb_status_t *status = (adb_status_t *)malloc(sizeof(adb_status_t)); mas01mj@669: int flags; mas01mj@669: flags = audiodb_status(db, status); mas01mj@669: [statusField setStringValue: [NSString stringWithFormat:@"Database: %@ Dimensions: %d Files: %d", dbName, status->dim, status->numFiles]]; mas01mj@669: [chooseButton setEnabled:YES]; mas01mj@669: } mas01mj@669: else mas01mj@669: { mas01mj@680: NSLog(@"No db"); mas01mj@669: [chooseButton setEnabled:NO]; mas01mj@669: [playBothButton setEnabled:FALSE]; mas01mj@669: [playResultButton setEnabled:FALSE]; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Choose the file(s) to be imported. mas01mj@669: * TODO: Currently handles the import process too - split this off. mas01mj@669: */ mas01mj@685: -(IBAction)importAudio:(id)sender mas01mj@669: { mas01mj@669: [tracksView reloadData]; mas01mj@669: mas01mj@669: NSArray *fileTypes = [NSArray arrayWithObject:@"wav"]; mas01mj@669: NSOpenPanel* panel = [NSOpenPanel openPanel]; mas01mj@669: [panel setAllowsMultipleSelection:TRUE]; mas01mj@669: NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; mas01mj@669: if(response == NSFileHandlingPanelOKButton) mas01mj@669: { mas01mj@685: [indicator startAnimation:self]; mas01mj@669: mas01mj@685: [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; mas01mj@685: session = [NSApp beginModalSessionForWindow: importSheet]; mas01mj@685: [NSApp runModalSession:session]; mas01mj@669: mas01mj@669: NSArray *filesToOpen = [panel filenames]; mas01mj@669: mas01mj@685: NSString* extractor = [dbState objectForKey:@"extractor"]; mas01mj@685: NSString* extractorPath = [NSString stringWithFormat:@"/Users/mikej/Development/audioDB/examples/iAudioDB/rdf/%@.n3", extractor]; mas01mj@669: mas01mj@685: // Create the customized extractor config mas01mj@685: NSString* extractorContent = [NSString stringWithContentsOfFile:extractorPath]; mas01mj@685: NSString* hopStr = [dbState objectForKey:@"hopsize"]; mas01mj@685: NSString* winStr = [dbState objectForKey:@"windowsize"]; mas01mj@685: NSString* newContent = [[extractorContent stringByReplacingOccurrencesOfString:@"HOP_SIZE" withString:hopStr] mas01mj@685: stringByReplacingOccurrencesOfString:@"WINDOW_SIZE" withString:winStr]; mas01mj@685: NSString* n3FileName = [NSTemporaryDirectory() stringByAppendingPathComponent:@"extractor_config.n3"]; mas01mj@680: mas01mj@685: NSError* error; mas01mj@685: [newContent writeToFile:n3FileName atomically:YES encoding:NSASCIIStringEncoding error:&error]; mas01mj@680: mas01mj@669: for(int i=0; i<[filesToOpen count]; i++) mas01mj@680: { mas01mj@680: audiodb_close(db); mas01mj@680: NSString* tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"]; mas01mj@680: const char* tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation]; mas01mj@680: char* tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1); mas01mj@669: strcpy(tempFileNameCString, tempFileTemplateCString); mas01mj@669: mktemp(tempFileNameCString); mas01mj@669: mas01mj@669: NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)]; mas01mj@669: free(tempFileNameCString); mas01mj@669: mas01mj@680: NSTask* task = [[NSTask alloc] init]; mas01mj@669: mas01mj@680: [task setLaunchPath:@"/usr/local/bin/sonic-annotator"]; mas01mj@680: NSArray* args; mas01mj@685: args = [NSArray arrayWithObjects:@"-t", n3FileName, @"-w", @"rdf", @"-r", @"--rdf-network", @"--rdf-one-file", featuresFileName, @"--rdf-force", [filesToOpen objectAtIndex:i], nil]; mas01mj@680: [task setArguments:args]; mas01mj@669: [task launch]; mas01mj@669: [task waitUntilExit]; mas01mj@669: [task release]; mas01mj@669: mas01mj@680: NSTask* importTask = [[NSTask alloc] init]; mas01mj@680: [importTask setLaunchPath:@"/usr/local/bin/populate"]; mas01mj@680: args = [NSArray arrayWithObjects:featuresFileName, dbFilename, nil]; mas01mj@680: [importTask setArguments:args]; mas01mj@680: [importTask launch]; mas01mj@680: [importTask waitUntilExit]; mas01mj@680: [importTask release]; mas01mj@680: mas01mj@669: NSString* val = [[filesToOpen objectAtIndex:i] retain]; mas01mj@669: NSString* key = [[[filesToOpen objectAtIndex:i] lastPathComponent] retain]; mas01mj@685: mas01mj@669: // Update the plist store. mas01mj@669: [trackMap setValue:val forKey:key]; mas01mj@685: [dbState writeToFile:plistFilename atomically: YES]; mas01mj@669: mas01mj@680: mas01mj@680: db = audiodb_open([dbFilename cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY); mas01mj@669: [self updateStatus]; mas01mj@669: } mas01mj@669: mas01mj@669: [NSApp endModalSession:session]; mas01mj@669: [importSheet orderOut:nil]; mas01mj@669: [NSApp endSheet:importSheet]; mas01mj@669: [indicator stopAnimation:self]; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Required table methods begin here. mas01mj@669: */ mas01mj@669: -(int)numberOfRowsInTableView:(NSTableView *)v mas01mj@669: { mas01mj@669: return [results count]; mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Return appropriate values - or the distance indicator if it's the meter column. mas01mj@669: */ mas01mj@669: -(id)tableView:(NSTableView *)v objectValueForTableColumn:(NSTableColumn *)tc row:(NSInteger)row mas01mj@669: { mas01mj@669: id result = [results objectAtIndex:row]; mas01mj@669: id value = [result objectForKey:[tc identifier]]; mas01mj@669: mas01mj@669: if([[tc identifier] isEqualToString:@"meter"]) mas01mj@669: { mas01mj@669: NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle]; mas01mj@669: [distance setFloatValue:10-[(NSNumber*)value floatValue]*100]; mas01mj@669: return distance; mas01mj@669: } mas01mj@669: else mas01mj@669: { mas01mj@669: return value; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Handle column sorting. mas01mj@669: */ mas01mj@669: - (void)tableView:(NSTableView *)v sortDescriptorsDidChange:(NSArray *)oldDescriptors mas01mj@669: { mas01mj@669: [results sortUsingDescriptors:[v sortDescriptors]]; mas01mj@669: [v reloadData]; mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Only enable the import menu option if a database is loaded. mas01mj@669: */ mas01mj@669: - (BOOL)validateUserInterfaceItem:(id )anItem mas01mj@669: { mas01mj@669: SEL theAction = [anItem action]; mas01mj@669: if (theAction == @selector(importAudio:)) mas01mj@669: { mas01mj@669: if(!db) mas01mj@669: { mas01mj@669: return NO; mas01mj@669: } mas01mj@669: } mas01mj@669: return YES; mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Ensure play buttons are only enabled if a track is selected. mas01mj@669: */ mas01mj@669: -(IBAction)selectedChanged:(id)sender mas01mj@669: { mas01mj@669: if([tracksView numberOfSelectedRows] == 0) mas01mj@669: { mas01mj@669: [playBothButton setEnabled:FALSE]; mas01mj@669: [playResultButton setEnabled:FALSE]; mas01mj@669: } mas01mj@669: else mas01mj@669: { mas01mj@669: [playBothButton setEnabled:TRUE]; mas01mj@669: [playResultButton setEnabled:TRUE]; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Play just the result track. mas01mj@669: */ mas01mj@669: -(IBAction)playResult:(id)sender mas01mj@669: { mas01mj@669: mas01mj@684: if([tracksView selectedRow] == -1) mas01mj@684: { mas01mj@684: return; mas01mj@684: } mas01mj@684: mas01mj@669: NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; mas01mj@669: NSString* value = [selectedRow objectForKey:@"key"]; mas01mj@669: float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; mas01mj@669: NSString* filename = [trackMap objectForKey:value]; mas01mj@669: NSLog(@"Key: %@ Value: %@", value, filename); mas01mj@669: mas01mj@669: if(queryTrack) mas01mj@669: { mas01mj@669: if([queryTrack isPlaying]) mas01mj@669: { mas01mj@669: [queryTrack setDelegate:Nil]; mas01mj@669: [queryTrack stop]; mas01mj@669: } mas01mj@669: [queryTrack release]; mas01mj@669: } mas01mj@669: mas01mj@669: if(resultTrack) mas01mj@669: { mas01mj@669: if([resultTrack isPlaying]) mas01mj@669: { mas01mj@669: [resultTrack setDelegate:Nil]; mas01mj@669: [resultTrack stop]; mas01mj@669: } mas01mj@669: [resultTrack release]; mas01mj@669: } mas01mj@669: mas01mj@669: resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain]; mas01mj@669: [resultTrack setCurrentTime:ipos]; mas01mj@669: [resultTrack setDelegate:self]; mas01mj@669: [resultTrack play]; mas01mj@669: mas01mj@669: [stopButton setEnabled:YES]; mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Play the result and query simultaneously. mas01mj@669: */ mas01mj@669: -(IBAction)playBoth:(id)sender mas01mj@669: { mas01mj@669: mas01mj@669: NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; mas01mj@669: NSString* value = [selectedRow objectForKey:@"key"]; mas01mj@669: float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; mas01mj@669: float qpos = [[selectedRow objectForKey:@"qpos"] floatValue]; mas01mj@669: NSString* filename = [trackMap objectForKey:value]; mas01mj@669: NSLog(@"Key: %@ Value: %@", value, filename); mas01mj@669: mas01mj@669: if(queryTrack) mas01mj@669: { mas01mj@669: mas01mj@669: if([queryTrack isPlaying]) mas01mj@669: { mas01mj@669: [queryTrack setDelegate:Nil]; mas01mj@669: [queryTrack stop]; mas01mj@669: } mas01mj@669: [queryTrack release]; mas01mj@669: } mas01mj@669: if(resultTrack) mas01mj@669: { mas01mj@669: if([resultTrack isPlaying]) mas01mj@669: { mas01mj@669: [resultTrack setDelegate:Nil]; mas01mj@669: [resultTrack stop]; mas01mj@669: } mas01mj@669: [resultTrack release]; mas01mj@669: } mas01mj@669: mas01mj@669: // Get query track and shift to start point mas01mj@669: queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain]; mas01mj@669: [queryTrack setCurrentTime:qpos]; mas01mj@669: [queryTrack setDelegate:self]; mas01mj@669: mas01mj@669: [queryTrack play]; mas01mj@669: mas01mj@669: resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain]; mas01mj@669: [resultTrack setCurrentTime:ipos]; mas01mj@669: [resultTrack setDelegate:self]; mas01mj@669: [resultTrack play]; mas01mj@669: mas01mj@669: [stopButton setEnabled:YES]; mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Disable the stop button after playback of both tracks. mas01mj@669: */ mas01mj@669: - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)playbackSuccessful mas01mj@669: { mas01mj@669: mas01mj@669: if((queryTrack && [queryTrack isPlaying]) || (resultTrack && [resultTrack isPlaying])) mas01mj@669: { mas01mj@669: return; mas01mj@669: } mas01mj@669: else mas01mj@669: { mas01mj@669: [stopButton setEnabled:NO]; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Stop playback. mas01mj@669: */ mas01mj@669: -(IBAction)stopPlay:(id)sender mas01mj@669: { mas01mj@669: if(queryTrack) mas01mj@669: { mas01mj@669: [queryTrack stop]; mas01mj@669: } mas01mj@669: if(resultTrack) mas01mj@669: { mas01mj@669: [resultTrack stop]; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Select an audio file, determine the key, and fire off a query. mas01mj@669: */ mas01mj@669: -(IBAction)chooseQuery:(id)sender mas01mj@669: { mas01mj@669: NSArray* fileTypes = [NSArray arrayWithObject:@"wav"]; mas01mj@669: NSOpenPanel* panel = [NSOpenPanel openPanel]; mas01mj@669: NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; mas01mj@669: if(response == NSFileHandlingPanelOKButton) mas01mj@669: { mas01mj@669: NSLog(@"%@", [panel filename]); mas01mj@669: // Grab key mas01mj@669: NSArray* opts = [trackMap allKeysForObject:[panel filename]]; mas01mj@669: if([opts count] != 1) mas01mj@669: { mas01mj@669: NSAlert *alert = [[[NSAlert alloc] init] autorelease]; mas01mj@669: [alert addButtonWithTitle:@"OK"]; mas01mj@669: [alert setMessageText:@"Track not found"]; mas01mj@669: [alert setInformativeText:@"Make sure you have specified a valid track identifier."]; mas01mj@669: [alert setAlertStyle:NSWarningAlertStyle]; mas01mj@669: [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; mas01mj@669: } mas01mj@669: else mas01mj@669: { mas01mj@669: selectedKey = [opts objectAtIndex:0]; mas01mj@669: [queryKey setStringValue:selectedKey]; mas01mj@669: selectedFilename = [[panel filename] retain]; mas01mj@669: [self performQuery]; mas01mj@669: } mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: /** mas01mj@669: * Actually perform the query. TODO: Monolithic. mas01mj@669: */ mas01mj@669: -(void)performQuery mas01mj@669: { mas01mj@669: NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename); mas01mj@669: mas01mj@669: adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t)); mas01mj@669: spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t)); mas01mj@669: mas01mj@669: spec->qid.sequence_length = 20; mas01mj@669: spec->qid.sequence_start = 0; mas01mj@669: spec->qid.flags = 0; mas01mj@669: mas01mj@669: // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE; mas01mj@669: spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK; mas01mj@669: spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED; mas01mj@669: mas01mj@669: spec->params.npoints = 1; mas01mj@669: spec->params.ntracks = 100; mas01mj@669: //spec->refine.radius = 5.0; mas01mj@669: // spec->refine.absolute_threshold = -6; mas01mj@669: // spec->refine.relative_threshold = 10; mas01mj@669: // spec->refine.duration_ratio = 0; mas01mj@669: mas01mj@669: spec->refine.flags = 0; mas01mj@669: // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD; mas01mj@669: // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD; mas01mj@682: // spec->refine.flags |= ADB_REFINE_HOP_SIZE; mas01mj@669: //spec->refine.flags |= ADB_REFINE_RADIUS; mas01mj@669: mas01mj@669: adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t)); mas01mj@669: spec->qid.datum->data = NULL; mas01mj@669: spec->qid.datum->power = NULL; mas01mj@669: spec->qid.datum->times = NULL; mas01mj@669: mas01mj@669: [results removeAllObjects]; mas01mj@669: mas01mj@669: int ok = audiodb_retrieve_datum(db, [selectedKey cStringUsingEncoding:NSUTF8StringEncoding], spec->qid.datum); mas01mj@669: if(ok == 0) mas01mj@669: { mas01mj@669: NSLog(@"Got a datum"); mas01mj@669: result = audiodb_query_spec(db, spec); mas01mj@669: if(result == NULL) mas01mj@669: { mas01mj@669: mas01mj@669: NSLog(@"No results"); mas01mj@669: } mas01mj@669: else mas01mj@669: { mas01mj@680: float divisor = (44100/2048); mas01mj@669: for(int i=0; inresults; i++) mas01mj@669: { mas01mj@682: mas01mj@669: NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4]; mas01mj@682: [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].ikey] forKey:@"key"]; mas01mj@669: [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"]; mas01mj@669: [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"]; mas01mj@680: [dict setValue:[NSNumber numberWithFloat:result->results[i].qpos/divisor] forKey:@"qpos"]; mas01mj@680: [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/divisor] forKey:@"ipos"]; mas01mj@682: NSLog(@"%s qpos %d ipos %d", result->results[i].ikey, result->results[i].qpos/divisor, result->results[i].ipos/divisor); mas01mj@669: [results addObject: dict]; mas01mj@669: } mas01mj@669: } mas01mj@669: mas01mj@669: NSSortDescriptor *distSort = [[NSSortDescriptor alloc]initWithKey:@"meter" ascending:YES]; mas01mj@669: NSArray *distDescs = [NSArray arrayWithObject:distSort]; mas01mj@669: mas01mj@669: [results sortUsingDescriptors:distDescs]; mas01mj@669: [tracksView setSortDescriptors:distDescs]; mas01mj@669: [tracksView reloadData]; mas01mj@669: mas01mj@669: } mas01mj@669: else mas01mj@669: { mas01mj@669: NSAlert *alert = [[[NSAlert alloc] init] autorelease]; mas01mj@669: [alert addButtonWithTitle:@"OK"]; mas01mj@669: [alert setMessageText:@"Track not found"]; mas01mj@669: [alert setInformativeText:@"Make sure you have specified a valid track identifier."]; mas01mj@669: [alert setAlertStyle:NSWarningAlertStyle]; mas01mj@669: [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; mas01mj@669: } mas01mj@669: // audiodb_query_free_results(db, spec, result); mas01mj@669: } mas01mj@669: mas01mj@669: @end