Mercurial > hg > audiodb
diff examples/iAudioDB/AppController.m @ 692:02756c5ca15a
* Added interface elements for query start selection
* Added logic for sec/vector conversion.
author | mas01mj |
---|---|
date | Thu, 22 Apr 2010 15:43:26 +0000 |
parents | 203181f7d804 |
children | 9a7d829bc492 |
line wrap: on
line diff
--- a/examples/iAudioDB/AppController.m Fri Mar 12 14:46:22 2010 +0000 +++ b/examples/iAudioDB/AppController.m Thu Apr 22 15:43:26 2010 +0000 @@ -5,10 +5,10 @@ // Created by Mike Jewell on 27/01/2010. // Copyright 2010 __MyCompanyName__. All rights reserved. // + #import "AppController.h" - @implementation AppController -(id)init @@ -18,149 +18,57 @@ // A max of 100 results. results = [[NSMutableArray alloc] initWithCapacity: 100]; + return self; } -- (void)awakeFromNib { - [tracksView setTarget:self]; - [tracksView setDoubleAction:@selector(tableDoubleClick:)]; - [self updateStatus]; -} - - -- (IBAction)tableDoubleClick:(id)sender -{ - [self playResult:Nil]; -// NSLog(@"Table double clicked"); -} - /** * Create a new database, given the selected filename. */ -(IBAction)newDatabase:(id)sender { - - [NSApp beginSheet:createSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; - session = [NSApp beginModalSessionForWindow:createSheet]; - [NSApp runModalSession:session]; -} - -/** - * Cancel the db creation (at configuration time). - */ --(IBAction)cancelCreate:(id)sender -{ - [NSApp endModalSession:session]; - [createSheet orderOut:nil]; - [NSApp endSheet:createSheet]; -} - --(IBAction)createDatabase:(id)sender -{ - [self cancelCreate:self]; - NSSavePanel* panel = [NSSavePanel savePanel]; NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@""]; - + [results removeAllObjects]; [tracksView reloadData]; - + if(response == NSFileHandlingPanelOKButton) { - // Work out which extractor to use - NSString* extractor = @"adb_chroma"; - // TODO: This should be stored with the n3. - int dim; - switch([extractorOptions selectedTag]) + // TODO: Refactor this into a 'tidy' method. + // Tidy any existing references up. + if(db) { - case 0: - extractor = @"adb_chroma"; - dim = 12; - break; - case 1: - extractor = @"adb_cq"; - dim = 48; - break; - case 2: - extractor = @"qm_chroma"; - dim = 12; - break; - case 3: - extractor = @"qm_mfcc"; - dim = 12; - break; + audiodb_close(db); } - // Calculate the max DB size - int vectors = ceil(([maxLengthField doubleValue] * 60) / ([hopSizeField doubleValue] / 44100)); - int numtracks = [maxTracksField intValue]; - int datasize = ceil((numtracks * vectors * dim * 8) / 1024 / 1024); // In MB + if(dbFilename) + { + [dbFilename release]; + [dbName release]; + [plistFilename release]; + } - [self reset]; - // Create new db, and set flags. - db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], datasize, numtracks, dim); + db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, 0); audiodb_l2norm(db); - + audiodb_power(db); + // Store useful paths. dbName = [[[panel URL] relativePath] retain]; dbFilename = [[panel filename] retain]; plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain]; - + // Create the plist file (contains mapping from filename to key). - dbState = [[NSMutableDictionary alloc] init]; trackMap = [[NSMutableDictionary alloc] init]; - [dbState setValue:trackMap forKey:@"tracks"]; - [dbState setValue:extractor forKey:@"extractor"]; - [dbState setValue:[hopSizeField stringValue] forKey:@"hopsize"]; - [dbState setValue:[windowSizeField stringValue] forKey:@"windowsize"]; - [dbState writeToFile:plistFilename atomically:YES]; - + [trackMap writeToFile:plistFilename atomically:YES]; + [queryKey setStringValue:@"None Selected"]; [self updateStatus]; } } --(void)reset -{ - // Tidy any existing references up. - if(db) - { - NSLog(@"Close db"); - audiodb_close(db); - } - - if(dbFilename) - { - NSLog(@"Tidy up filenames"); - [dbFilename release]; - [dbName release]; - [plistFilename release]; - [trackMap release]; - [dbState release]; - } - - if(selectedKey) - { - NSLog(@"Released selected key: %@", selectedKey); - [selectedKey release]; - selectedKey = Nil; - NSLog(@"Is now %@", selectedKey); - } - - if(selectedKey) - { - NSLog(@"Still evals"); - } - - // Reset query flags - [queryPath setStringValue: @"No file selected"]; - [queryLengthSeconds setDoubleValue:0]; - [queryLengthVectors setDoubleValue:0]; - [multipleCheckBox setState:NSOnState]; -} - /** * Open an existing adb (which must have a plist) */ @@ -171,11 +79,21 @@ NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; if(response == NSFileHandlingPanelOKButton) { - [self reset]; + // Tidy any existing references up. + if(db) + { + audiodb_close(db); + } + + if(dbFilename) + { + [dbFilename release]; + [dbName release]; + [plistFilename release]; + } // Store useful paths. - NSLog(@"Open"); - db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY); + db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDWR); dbName = [[[panel URL] relativePath] retain]; dbFilename = [[panel filename] retain]; @@ -187,6 +105,7 @@ [tracksView reloadData]; [queryKey setStringValue:@"None Selected"]; + [self updateStatus]; adb_liszt_results_t* liszt_results = audiodb_liszt(db); @@ -197,58 +116,57 @@ } audiodb_liszt_free_results(db, liszt_results); - dbState = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain]; - trackMap = [[dbState objectForKey:@"tracks"] retain]; - - [self updateStatus]; - + trackMap = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain]; NSLog(@"Size: %d", [trackMap count]); } } --(IBAction)pathAction:(id)sender -{ - NSLog(@"Path action"); -} - /** * Update button states and status field based on current state. */ -(void)updateStatus { - NSLog(@"Update status"); if(db) { - NSLog(@"Got a db"); - adb_status_t *status = (adb_status_t *)malloc(sizeof(adb_status_t)); + adb_status_ptr status = (adb_status_ptr)malloc(sizeof(struct adbstatus)); int flags; flags = audiodb_status(db, status); - [statusField setStringValue: [NSString stringWithFormat:@"%@ Dim: %d Files: %d Hop: %@ Win: %@ Ext: %@", - dbName, - status->dim, - status->numFiles, - [dbState objectForKey:@"hopsize"], - [dbState objectForKey:@"windowsize"], - [dbState objectForKey:@"extractor"]]]; - [performQueryButton setEnabled:YES]; - [importAudioButton setEnabled:YES]; + [statusField setStringValue: [NSString stringWithFormat:@"Database: %@ Dimensions: %d Files: %d", dbName, status->dim, status->numFiles]]; + [chooseButton setEnabled:YES]; } else { - NSLog(@"No db"); - [performQueryButton setEnabled:NO]; - [importAudioButton setEnabled:NO]; - [playBothButton setEnabled:NO]; - [playResultButton setEnabled:NO]; - [stopButton setEnabled:NO]; + [chooseButton setEnabled:NO]; + [playBothButton setEnabled:FALSE]; + [playResultButton setEnabled:FALSE]; } } /** + * Get user's import choices. + */ +-(IBAction)importAudio:(id)sender +{ + [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; + session = [NSApp beginModalSessionForWindow: importSheet]; + [NSApp runModalSession:session]; +} + +/** + * Cancel the import (at configuration time). + */ +-(IBAction)cancelImport:(id)sender; +{ + [NSApp endModalSession:session]; + [importSheet orderOut:nil]; + [NSApp endSheet:importSheet]; +} + +/** * Choose the file(s) to be imported. * TODO: Currently handles the import process too - split this off. */ --(IBAction)importAudio:(id)sender +-(IBAction)selectFiles:(id)sender { [tracksView reloadData]; @@ -258,75 +176,121 @@ NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; if(response == NSFileHandlingPanelOKButton) { + NSRect newFrame; + + [extractingBox setHidden:FALSE]; + newFrame.origin.x = [importSheet frame].origin.x; + newFrame.origin.y = [importSheet frame].origin.y - [extractingBox frame].size.height; + newFrame.size.width = [importSheet frame].size.width; + newFrame.size.height = [importSheet frame].size.height + [extractingBox frame].size.height; + [indicator startAnimation:self]; - - [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; - session = [NSApp beginModalSessionForWindow: importSheet]; - [NSApp runModalSession:session]; + [importSheet setFrame:newFrame display:YES animate:YES]; NSArray *filesToOpen = [panel filenames]; - NSString* extractor = [dbState objectForKey:@"extractor"]; - NSString* extractorPath = [NSString stringWithFormat:@"/Applications/iAudioDB.app/rdf/%@.n3", extractor]; + NSLog(@"Begin import"); - // TODO Shift this process into a separate function. - // Create the customized extractor config - NSString* extractorContent = [NSString stringWithContentsOfFile:extractorPath]; - NSString* hopStr = [dbState objectForKey:@"hopsize"]; - NSString* winStr = [dbState objectForKey:@"windowsize"]; - NSString* newContent = [[extractorContent stringByReplacingOccurrencesOfString:@"HOP_SIZE" withString:hopStr] - stringByReplacingOccurrencesOfString:@"WINDOW_SIZE" withString:winStr]; - NSString* n3FileName = [NSTemporaryDirectory() stringByAppendingPathComponent:@"extractor_config.n3"]; - - NSError* error; - [newContent writeToFile:n3FileName atomically:YES encoding:NSASCIIStringEncoding error:&error]; + // Work out which extractor to use + NSString* extractor = @"chromagram"; + switch([extractorOptions selectedTag]) + { + case 0: + extractor = @"mfcc"; + break; + case 1: + extractor = @"chromagram"; + break; + } for(int i=0; i<[filesToOpen count]; i++) - { - audiodb_close(db); - NSString* tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"]; - const char* tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation]; - char* tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1); + { + // First extract powers + + NSString *tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"powers.XXXXXX"]; + const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation]; + char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1); + strcpy(tempFileNameCString, tempFileTemplateCString); + mktemp(tempFileNameCString); + + NSString* powersFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)]; + free(tempFileNameCString); + + NSTask *task = [[NSTask alloc] init]; + [task setLaunchPath:@"/usr/local/bin/fftExtract"]; + NSArray *args = [NSArray arrayWithObjects:@"-P", @"-s", @"250", [filesToOpen objectAtIndex:i], powersFileName, nil]; + [task setArguments:args]; + [task launch]; + [task waitUntilExit]; + [task release]; + + // Then features + + tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"]; + tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation]; + tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1); strcpy(tempFileNameCString, tempFileTemplateCString); mktemp(tempFileNameCString); NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)]; free(tempFileNameCString); - NSTask* task = [[NSTask alloc] init]; + task = [[NSTask alloc] init]; - [task setLaunchPath:@"/usr/local/bin/sonic-annotator"]; - NSArray* args; - args = [NSArray arrayWithObjects:@"-t", n3FileName, @"-w", @"rdf", @"-r", @"--rdf-network", @"--rdf-one-file", featuresFileName, @"--rdf-force", [filesToOpen objectAtIndex:i], nil]; - [task setArguments:args]; + [task setLaunchPath:@"/usr/local/bin/fftExtract"]; + + NSArray *args2; + + // Choose the args (TODO: This should use sonic annotator eventually) + if([extractor isEqualToString:@"chromagram"]) + { + args2 = [NSArray arrayWithObjects:@"-p",@"/Users/mikej/planfile",@"-c", @"12", @"-s", @"250", [filesToOpen objectAtIndex:i], featuresFileName, nil]; + } + else + { + args2 = [NSArray arrayWithObjects:@"-p",@"/Users/mikej/planfile",@"-m", @"13", @"-s", @"250", [filesToOpen objectAtIndex:i], featuresFileName, nil]; + } + [task setArguments:args2]; [task launch]; [task waitUntilExit]; [task release]; - NSTask* importTask = [[NSTask alloc] init]; - [importTask setLaunchPath:@"/usr/local/bin/populate"]; - args = [NSArray arrayWithObjects:featuresFileName, dbFilename, nil]; - [importTask setArguments:args]; - [importTask launch]; - [importTask waitUntilExit]; - [importTask release]; - NSString* val = [[filesToOpen objectAtIndex:i] retain]; NSString* key = [[[filesToOpen objectAtIndex:i] lastPathComponent] retain]; - + + adb_insert_t insert; + insert.features = [featuresFileName cStringUsingEncoding:NSUTF8StringEncoding]; + insert.power = [powersFileName cStringUsingEncoding:NSUTF8StringEncoding]; + insert.times = NULL; + insert.key = [key cStringUsingEncoding:NSUTF8StringEncoding]; + + // Insert into db. + if(audiodb_insert(db, &insert)) + { + // TODO: Show an error message. + NSLog(@"Weep: %@ %@ %@", featuresFileName, powersFileName, key); + continue; + } + // Update the plist store. [trackMap setValue:val forKey:key]; - [dbState writeToFile:plistFilename atomically: YES]; + [trackMap writeToFile:plistFilename atomically: YES]; - - db = audiodb_open([dbFilename cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY); [self updateStatus]; } + newFrame.origin.x = [importSheet frame].origin.x; + newFrame.origin.y = [importSheet frame].origin.y + [extractingBox frame].size.height; + newFrame.size.width = [importSheet frame].size.width; + newFrame.size.height = [importSheet frame].size.height - [extractingBox frame].size.height; + + [importSheet setFrame:newFrame display:YES animate:YES]; + [NSApp endModalSession:session]; [importSheet orderOut:nil]; [NSApp endSheet:importSheet]; [indicator stopAnimation:self]; + [extractingBox setHidden:TRUE]; } } @@ -346,7 +310,6 @@ id result = [results objectAtIndex:row]; id value = [result objectForKey:[tc identifier]]; - NSLog(@"Result: %s", [tc identifier]); if([[tc identifier] isEqualToString:@"meter"]) { NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle]; @@ -391,13 +354,13 @@ { if([tracksView numberOfSelectedRows] == 0) { - [playBothButton setEnabled:NO]; - [playResultButton setEnabled:NO]; + [playBothButton setEnabled:FALSE]; + [playResultButton setEnabled:FALSE]; } else { - [playBothButton setEnabled:YES]; - [playResultButton setEnabled:YES]; + [playBothButton setEnabled:TRUE]; + [playResultButton setEnabled:TRUE]; } } @@ -407,11 +370,6 @@ -(IBAction)playResult:(id)sender { - if([tracksView selectedRow] == -1) - { - return; - } - NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; NSString* value = [selectedRow objectForKey:@"key"]; float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; @@ -455,6 +413,7 @@ NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; NSString* value = [selectedRow objectForKey:@"key"]; float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; + float qpos = [[selectedRow objectForKey:@"qpos"] floatValue]; NSString* filename = [trackMap objectForKey:value]; NSLog(@"Key: %@ Value: %@", value, filename); @@ -480,6 +439,7 @@ // Get query track and shift to start point queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain]; + [queryTrack setCurrentTime:qpos]; [queryTrack setDelegate:self]; [queryTrack play]; @@ -528,25 +488,16 @@ */ -(IBAction)chooseQuery:(id)sender { - [queryButton setEnabled:(selectedKey ? YES : NO)]; - [NSApp beginSheet:querySheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil]; - session = [NSApp beginModalSessionForWindow:querySheet]; - [NSApp runModalSession:session]; -} - - --(IBAction)selectQueryFile:(id)sender -{ NSArray* fileTypes = [NSArray arrayWithObject:@"wav"]; NSOpenPanel* panel = [NSOpenPanel openPanel]; NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; if(response == NSFileHandlingPanelOKButton) { + NSLog(@"%@", [panel filename]); + // Grab key NSArray* opts = [trackMap allKeysForObject:[panel filename]]; if([opts count] != 1) { - // TODO : Needs fixing! - NSAlert *alert = [[[NSAlert alloc] init] autorelease]; [alert addButtonWithTitle:@"OK"]; [alert setMessageText:@"Track not found"]; @@ -558,124 +509,34 @@ { selectedKey = [opts objectAtIndex:0]; [queryKey setStringValue:selectedKey]; - [queryPath setStringValue:selectedKey]; selectedFilename = [[panel filename] retain]; - [queryButton setEnabled:YES]; - - [self resetLengths:self]; + [self performQuery]; } } } --(IBAction)resetLengths:(id)sender -{ - queryTrack = [[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES]; - NSLog(@"%f", [queryTrack duration]); - double samples = ([queryTrack duration]*44100); - double hopSize = [[dbState objectForKey:@"hopsize"] doubleValue]; - double winSize = [[dbState objectForKey:@"windowsize"] doubleValue]; - - [queryLengthSeconds setDoubleValue:ceil([queryTrack duration])]; - [queryLengthVectors setDoubleValue:ceil((samples-winSize)/hopSize)]; - -} - -- (void)controlTextDidChange:(NSNotification *)nd -{ - NSTextField *ed = [nd object]; - - double hopSize = [[dbState objectForKey:@"hopsize"] doubleValue]; - double winSize = [[dbState objectForKey:@"windowsize"] doubleValue]; - - if(!queryTrack) - { - queryTrack = [[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES]; - } - - double totalDuration = [queryTrack duration]; - double samples = totalDuration * 44100; - double totalVectors = ((samples-winSize)/hopSize); - - if (ed == queryLengthSeconds) - { - double secs = [queryLengthSeconds doubleValue]; - if(secs > totalDuration) - { - [queryButton setEnabled:NO]; - } - else if(![queryButton isEnabled]) - { - [queryButton setEnabled:YES]; - } - - if(secs > 0) - { - // (samples - windowSize) / hopSize - - [queryLengthVectors setDoubleValue:ceil(((secs*44100)-winSize)/hopSize)]; - } - } - if (ed == queryLengthVectors) - { - double vectors = [queryLengthVectors doubleValue]; - - if(vectors > totalVectors) - { - [queryButton setEnabled:NO]; - } - else if(![queryButton isEnabled]) - { - [queryButton setEnabled:YES]; - } - - if(vectors > 0) - { - [queryLengthSeconds setDoubleValue:ceil(((hopSize*vectors)+winSize)/44100)]; - } - } -}; - --(IBAction)cancelQuery:(id)sender -{ - [NSApp endModalSession:session]; - [querySheet orderOut:nil]; - [NSApp endSheet:querySheet]; -} - /** * Actually perform the query. TODO: Monolithic. */ --(IBAction)performQuery:(id)sender +-(void)performQuery { - [NSApp endModalSession:session]; - [querySheet orderOut:nil]; - [NSApp endSheet:querySheet]; - NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename); adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t)); spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t)); - spec->qid.sequence_length = [queryLengthVectors doubleValue]; + spec->qid.sequence_length = 20; spec->qid.sequence_start = 0; - spec->qid.flags = 0; + spec->qid.flags = 0; + // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE; - spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK; - - if([multipleCheckBox state] == NSOnState) - { - spec->params.npoints = 10; - } - else - { - spec->params.npoints = 1; - } - spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED; + spec->params.npoints = 1; spec->params.ntracks = 100; - //spec->refine.radius = 5.0; + spec->refine.radius = 5.0; + spec->refine.hopsize = 1; // spec->refine.absolute_threshold = -6; // spec->refine.relative_threshold = 10; // spec->refine.duration_ratio = 0; @@ -683,8 +544,8 @@ spec->refine.flags = 0; // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD; // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD; -// spec->refine.flags |= ADB_REFINE_HOP_SIZE; - //spec->refine.flags |= ADB_REFINE_RADIUS; + spec->refine.flags |= ADB_REFINE_HOP_SIZE; + spec->refine.flags |= ADB_REFINE_RADIUS; adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t)); spec->qid.datum->data = NULL; @@ -705,16 +566,15 @@ } else { - NSLog(@"Populate table: %d", result->nresults); - float divisor = (44100/2048); for(int i=0; i<result->nresults; i++) { - NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4]; - [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].ikey] forKey:@"key"]; + [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].key] forKey:@"key"]; [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"]; [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"]; - [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/divisor] forKey:@"ipos"]; + [dict setValue:[NSNumber numberWithFloat:result->results[i].qpos/4] forKey:@"qpos"]; + [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/4] forKey:@"ipos"]; + NSLog(@"%s qpos %d ipos %d", result->results[i].key, result->results[i].qpos/4, result->results[i].ipos/4); [results addObject: dict]; } }