comparison 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
comparison
equal deleted inserted replaced
691:203181f7d804 692:02756c5ca15a
3 // iAudioDB 3 // iAudioDB
4 // 4 //
5 // Created by Mike Jewell on 27/01/2010. 5 // Created by Mike Jewell on 27/01/2010.
6 // Copyright 2010 __MyCompanyName__. All rights reserved. 6 // Copyright 2010 __MyCompanyName__. All rights reserved.
7 // 7 //
8
8 #import "AppController.h" 9 #import "AppController.h"
9
10 10
11 11
12 @implementation AppController 12 @implementation AppController
13 13
14 -(id)init 14 -(id)init
16 [super init]; 16 [super init];
17 17
18 // A max of 100 results. 18 // A max of 100 results.
19 results = [[NSMutableArray alloc] initWithCapacity: 100]; 19 results = [[NSMutableArray alloc] initWithCapacity: 100];
20 20
21
21 return self; 22 return self;
22 } 23 }
23 24
24 - (void)awakeFromNib {
25 [tracksView setTarget:self];
26 [tracksView setDoubleAction:@selector(tableDoubleClick:)];
27 [self updateStatus];
28 }
29
30
31 - (IBAction)tableDoubleClick:(id)sender
32 {
33 [self playResult:Nil];
34 // NSLog(@"Table double clicked");
35 }
36
37 25
38 /** 26 /**
39 * Create a new database, given the selected filename. 27 * Create a new database, given the selected filename.
40 */ 28 */
41 -(IBAction)newDatabase:(id)sender 29 -(IBAction)newDatabase:(id)sender
42 { 30 {
43
44 [NSApp beginSheet:createSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
45 session = [NSApp beginModalSessionForWindow:createSheet];
46 [NSApp runModalSession:session];
47 }
48
49 /**
50 * Cancel the db creation (at configuration time).
51 */
52 -(IBAction)cancelCreate:(id)sender
53 {
54 [NSApp endModalSession:session];
55 [createSheet orderOut:nil];
56 [NSApp endSheet:createSheet];
57 }
58
59 -(IBAction)createDatabase:(id)sender
60 {
61 [self cancelCreate:self];
62
63 NSSavePanel* panel = [NSSavePanel savePanel]; 31 NSSavePanel* panel = [NSSavePanel savePanel];
64 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@""]; 32 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@""];
65 33
66 [results removeAllObjects]; 34 [results removeAllObjects];
67 [tracksView reloadData]; 35 [tracksView reloadData];
68 36
69 if(response == NSFileHandlingPanelOKButton) 37 if(response == NSFileHandlingPanelOKButton)
70 { 38 {
71 // Work out which extractor to use 39 // TODO: Refactor this into a 'tidy' method.
72 NSString* extractor = @"adb_chroma"; 40 // Tidy any existing references up.
73 // TODO: This should be stored with the n3. 41 if(db)
74 int dim; 42 {
75 switch([extractorOptions selectedTag]) 43 audiodb_close(db);
76 { 44 }
77 case 0: 45
78 extractor = @"adb_chroma"; 46 if(dbFilename)
79 dim = 12; 47 {
80 break; 48 [dbFilename release];
81 case 1: 49 [dbName release];
82 extractor = @"adb_cq"; 50 [plistFilename release];
83 dim = 48; 51 }
84 break; 52
85 case 2:
86 extractor = @"qm_chroma";
87 dim = 12;
88 break;
89 case 3:
90 extractor = @"qm_mfcc";
91 dim = 12;
92 break;
93 }
94
95 // Calculate the max DB size
96 int vectors = ceil(([maxLengthField doubleValue] * 60) / ([hopSizeField doubleValue] / 44100));
97 int numtracks = [maxTracksField intValue];
98 int datasize = ceil((numtracks * vectors * dim * 8) / 1024 / 1024); // In MB
99
100 [self reset];
101
102 // Create new db, and set flags. 53 // Create new db, and set flags.
103 db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], datasize, numtracks, dim); 54 db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, 0);
104 audiodb_l2norm(db); 55 audiodb_l2norm(db);
105 56 audiodb_power(db);
57
106 // Store useful paths. 58 // Store useful paths.
107 dbName = [[[panel URL] relativePath] retain]; 59 dbName = [[[panel URL] relativePath] retain];
108 dbFilename = [[panel filename] retain]; 60 dbFilename = [[panel filename] retain];
109 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain]; 61 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
110 62
111 // Create the plist file (contains mapping from filename to key). 63 // Create the plist file (contains mapping from filename to key).
112 dbState = [[NSMutableDictionary alloc] init];
113 trackMap = [[NSMutableDictionary alloc] init]; 64 trackMap = [[NSMutableDictionary alloc] init];
114 [dbState setValue:trackMap forKey:@"tracks"]; 65 [trackMap writeToFile:plistFilename atomically:YES];
115 [dbState setValue:extractor forKey:@"extractor"]; 66
116 [dbState setValue:[hopSizeField stringValue] forKey:@"hopsize"];
117 [dbState setValue:[windowSizeField stringValue] forKey:@"windowsize"];
118 [dbState writeToFile:plistFilename atomically:YES];
119
120 [queryKey setStringValue:@"None Selected"]; 67 [queryKey setStringValue:@"None Selected"];
121 [self updateStatus]; 68 [self updateStatus];
122 } 69 }
123 }
124
125 -(void)reset
126 {
127 // Tidy any existing references up.
128 if(db)
129 {
130 NSLog(@"Close db");
131 audiodb_close(db);
132 }
133
134 if(dbFilename)
135 {
136 NSLog(@"Tidy up filenames");
137 [dbFilename release];
138 [dbName release];
139 [plistFilename release];
140 [trackMap release];
141 [dbState release];
142 }
143
144 if(selectedKey)
145 {
146 NSLog(@"Released selected key: %@", selectedKey);
147 [selectedKey release];
148 selectedKey = Nil;
149 NSLog(@"Is now %@", selectedKey);
150 }
151
152 if(selectedKey)
153 {
154 NSLog(@"Still evals");
155 }
156
157 // Reset query flags
158 [queryPath setStringValue: @"No file selected"];
159 [queryLengthSeconds setDoubleValue:0];
160 [queryLengthVectors setDoubleValue:0];
161 [multipleCheckBox setState:NSOnState];
162 } 70 }
163 71
164 /** 72 /**
165 * Open an existing adb (which must have a plist) 73 * Open an existing adb (which must have a plist)
166 */ 74 */
169 NSArray *fileTypes = [NSArray arrayWithObject:@"adb"]; 77 NSArray *fileTypes = [NSArray arrayWithObject:@"adb"];
170 NSOpenPanel* panel = [NSOpenPanel openPanel]; 78 NSOpenPanel* panel = [NSOpenPanel openPanel];
171 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; 79 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
172 if(response == NSFileHandlingPanelOKButton) 80 if(response == NSFileHandlingPanelOKButton)
173 { 81 {
174 [self reset]; 82 // Tidy any existing references up.
83 if(db)
84 {
85 audiodb_close(db);
86 }
87
88 if(dbFilename)
89 {
90 [dbFilename release];
91 [dbName release];
92 [plistFilename release];
93 }
175 94
176 // Store useful paths. 95 // Store useful paths.
177 NSLog(@"Open"); 96 db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDWR);
178 db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY);
179 dbName = [[[panel URL] relativePath] retain]; 97 dbName = [[[panel URL] relativePath] retain];
180 dbFilename = [[panel filename] retain]; 98 dbFilename = [[panel filename] retain];
181 99
182 // TODO: Verify this exists! 100 // TODO: Verify this exists!
183 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain]; 101 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
185 // Clear out any old results. 103 // Clear out any old results.
186 [results removeAllObjects]; 104 [results removeAllObjects];
187 [tracksView reloadData]; 105 [tracksView reloadData];
188 106
189 [queryKey setStringValue:@"None Selected"]; 107 [queryKey setStringValue:@"None Selected"];
108 [self updateStatus];
190 109
191 adb_liszt_results_t* liszt_results = audiodb_liszt(db); 110 adb_liszt_results_t* liszt_results = audiodb_liszt(db);
192 111
193 for(int k=0; k<liszt_results->nresults; k++) 112 for(int k=0; k<liszt_results->nresults; k++)
194 { 113 {
195 NSMutableString *trackVal = [[NSMutableString alloc] init]; 114 NSMutableString *trackVal = [[NSMutableString alloc] init];
196 [trackVal appendFormat:@"%s", liszt_results->entries[k].key]; 115 [trackVal appendFormat:@"%s", liszt_results->entries[k].key];
197 } 116 }
198 117
199 audiodb_liszt_free_results(db, liszt_results); 118 audiodb_liszt_free_results(db, liszt_results);
200 dbState = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain]; 119 trackMap = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain];
201 trackMap = [[dbState objectForKey:@"tracks"] retain];
202
203 [self updateStatus];
204
205 NSLog(@"Size: %d", [trackMap count]); 120 NSLog(@"Size: %d", [trackMap count]);
206 } 121 }
207 } 122 }
208 123
209 -(IBAction)pathAction:(id)sender
210 {
211 NSLog(@"Path action");
212 }
213
214 /** 124 /**
215 * Update button states and status field based on current state. 125 * Update button states and status field based on current state.
216 */ 126 */
217 -(void)updateStatus 127 -(void)updateStatus
218 { 128 {
219 NSLog(@"Update status");
220 if(db) 129 if(db)
221 { 130 {
222 NSLog(@"Got a db"); 131 adb_status_ptr status = (adb_status_ptr)malloc(sizeof(struct adbstatus));
223 adb_status_t *status = (adb_status_t *)malloc(sizeof(adb_status_t));
224 int flags; 132 int flags;
225 flags = audiodb_status(db, status); 133 flags = audiodb_status(db, status);
226 [statusField setStringValue: [NSString stringWithFormat:@"%@ Dim: %d Files: %d Hop: %@ Win: %@ Ext: %@", 134 [statusField setStringValue: [NSString stringWithFormat:@"Database: %@ Dimensions: %d Files: %d", dbName, status->dim, status->numFiles]];
227 dbName, 135 [chooseButton setEnabled:YES];
228 status->dim,
229 status->numFiles,
230 [dbState objectForKey:@"hopsize"],
231 [dbState objectForKey:@"windowsize"],
232 [dbState objectForKey:@"extractor"]]];
233 [performQueryButton setEnabled:YES];
234 [importAudioButton setEnabled:YES];
235 } 136 }
236 else 137 else
237 { 138 {
238 NSLog(@"No db"); 139 [chooseButton setEnabled:NO];
239 [performQueryButton setEnabled:NO]; 140 [playBothButton setEnabled:FALSE];
240 [importAudioButton setEnabled:NO]; 141 [playResultButton setEnabled:FALSE];
241 [playBothButton setEnabled:NO]; 142 }
242 [playResultButton setEnabled:NO]; 143 }
243 [stopButton setEnabled:NO]; 144
244 } 145 /**
146 * Get user's import choices.
147 */
148 -(IBAction)importAudio:(id)sender
149 {
150 [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
151 session = [NSApp beginModalSessionForWindow: importSheet];
152 [NSApp runModalSession:session];
153 }
154
155 /**
156 * Cancel the import (at configuration time).
157 */
158 -(IBAction)cancelImport:(id)sender;
159 {
160 [NSApp endModalSession:session];
161 [importSheet orderOut:nil];
162 [NSApp endSheet:importSheet];
245 } 163 }
246 164
247 /** 165 /**
248 * Choose the file(s) to be imported. 166 * Choose the file(s) to be imported.
249 * TODO: Currently handles the import process too - split this off. 167 * TODO: Currently handles the import process too - split this off.
250 */ 168 */
251 -(IBAction)importAudio:(id)sender 169 -(IBAction)selectFiles:(id)sender
252 { 170 {
253 [tracksView reloadData]; 171 [tracksView reloadData];
254 172
255 NSArray *fileTypes = [NSArray arrayWithObject:@"wav"]; 173 NSArray *fileTypes = [NSArray arrayWithObject:@"wav"];
256 NSOpenPanel* panel = [NSOpenPanel openPanel]; 174 NSOpenPanel* panel = [NSOpenPanel openPanel];
257 [panel setAllowsMultipleSelection:TRUE]; 175 [panel setAllowsMultipleSelection:TRUE];
258 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; 176 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
259 if(response == NSFileHandlingPanelOKButton) 177 if(response == NSFileHandlingPanelOKButton)
260 { 178 {
179 NSRect newFrame;
180
181 [extractingBox setHidden:FALSE];
182 newFrame.origin.x = [importSheet frame].origin.x;
183 newFrame.origin.y = [importSheet frame].origin.y - [extractingBox frame].size.height;
184 newFrame.size.width = [importSheet frame].size.width;
185 newFrame.size.height = [importSheet frame].size.height + [extractingBox frame].size.height;
186
261 [indicator startAnimation:self]; 187 [indicator startAnimation:self];
262 188 [importSheet setFrame:newFrame display:YES animate:YES];
263 [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
264 session = [NSApp beginModalSessionForWindow: importSheet];
265 [NSApp runModalSession:session];
266 189
267 NSArray *filesToOpen = [panel filenames]; 190 NSArray *filesToOpen = [panel filenames];
268 191
269 NSString* extractor = [dbState objectForKey:@"extractor"]; 192 NSLog(@"Begin import");
270 NSString* extractorPath = [NSString stringWithFormat:@"/Applications/iAudioDB.app/rdf/%@.n3", extractor]; 193
271 194 // Work out which extractor to use
272 // TODO Shift this process into a separate function. 195 NSString* extractor = @"chromagram";
273 // Create the customized extractor config 196 switch([extractorOptions selectedTag])
274 NSString* extractorContent = [NSString stringWithContentsOfFile:extractorPath]; 197 {
275 NSString* hopStr = [dbState objectForKey:@"hopsize"]; 198 case 0:
276 NSString* winStr = [dbState objectForKey:@"windowsize"]; 199 extractor = @"mfcc";
277 NSString* newContent = [[extractorContent stringByReplacingOccurrencesOfString:@"HOP_SIZE" withString:hopStr] 200 break;
278 stringByReplacingOccurrencesOfString:@"WINDOW_SIZE" withString:winStr]; 201 case 1:
279 NSString* n3FileName = [NSTemporaryDirectory() stringByAppendingPathComponent:@"extractor_config.n3"]; 202 extractor = @"chromagram";
280 203 break;
281 NSError* error; 204 }
282 [newContent writeToFile:n3FileName atomically:YES encoding:NSASCIIStringEncoding error:&error];
283 205
284 for(int i=0; i<[filesToOpen count]; i++) 206 for(int i=0; i<[filesToOpen count]; i++)
285 { 207 {
286 audiodb_close(db); 208 // First extract powers
287 NSString* tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"]; 209
288 const char* tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation]; 210 NSString *tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"powers.XXXXXX"];
289 char* tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1); 211 const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
212 char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
290 strcpy(tempFileNameCString, tempFileTemplateCString); 213 strcpy(tempFileNameCString, tempFileTemplateCString);
291 mktemp(tempFileNameCString); 214 mktemp(tempFileNameCString);
292 215
293 NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)]; 216 NSString* powersFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
294 free(tempFileNameCString); 217 free(tempFileNameCString);
295 218
296 NSTask* task = [[NSTask alloc] init]; 219 NSTask *task = [[NSTask alloc] init];
297 220 [task setLaunchPath:@"/usr/local/bin/fftExtract"];
298 [task setLaunchPath:@"/usr/local/bin/sonic-annotator"]; 221 NSArray *args = [NSArray arrayWithObjects:@"-P", @"-s", @"250", [filesToOpen objectAtIndex:i], powersFileName, nil];
299 NSArray* args;
300 args = [NSArray arrayWithObjects:@"-t", n3FileName, @"-w", @"rdf", @"-r", @"--rdf-network", @"--rdf-one-file", featuresFileName, @"--rdf-force", [filesToOpen objectAtIndex:i], nil];
301 [task setArguments:args]; 222 [task setArguments:args];
302 [task launch]; 223 [task launch];
303 [task waitUntilExit]; 224 [task waitUntilExit];
304 [task release]; 225 [task release];
305 226
306 NSTask* importTask = [[NSTask alloc] init]; 227 // Then features
307 [importTask setLaunchPath:@"/usr/local/bin/populate"]; 228
308 args = [NSArray arrayWithObjects:featuresFileName, dbFilename, nil]; 229 tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"];
309 [importTask setArguments:args]; 230 tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
310 [importTask launch]; 231 tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
311 [importTask waitUntilExit]; 232 strcpy(tempFileNameCString, tempFileTemplateCString);
312 [importTask release]; 233 mktemp(tempFileNameCString);
234
235 NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
236 free(tempFileNameCString);
237
238 task = [[NSTask alloc] init];
239
240 [task setLaunchPath:@"/usr/local/bin/fftExtract"];
241
242 NSArray *args2;
243
244 // Choose the args (TODO: This should use sonic annotator eventually)
245 if([extractor isEqualToString:@"chromagram"])
246 {
247 args2 = [NSArray arrayWithObjects:@"-p",@"/Users/mikej/planfile",@"-c", @"12", @"-s", @"250", [filesToOpen objectAtIndex:i], featuresFileName, nil];
248 }
249 else
250 {
251 args2 = [NSArray arrayWithObjects:@"-p",@"/Users/mikej/planfile",@"-m", @"13", @"-s", @"250", [filesToOpen objectAtIndex:i], featuresFileName, nil];
252 }
253 [task setArguments:args2];
254 [task launch];
255 [task waitUntilExit];
256 [task release];
313 257
314 NSString* val = [[filesToOpen objectAtIndex:i] retain]; 258 NSString* val = [[filesToOpen objectAtIndex:i] retain];
315 NSString* key = [[[filesToOpen objectAtIndex:i] lastPathComponent] retain]; 259 NSString* key = [[[filesToOpen objectAtIndex:i] lastPathComponent] retain];
316 260
261 adb_insert_t insert;
262 insert.features = [featuresFileName cStringUsingEncoding:NSUTF8StringEncoding];
263 insert.power = [powersFileName cStringUsingEncoding:NSUTF8StringEncoding];
264 insert.times = NULL;
265 insert.key = [key cStringUsingEncoding:NSUTF8StringEncoding];
266
267 // Insert into db.
268 if(audiodb_insert(db, &insert))
269 {
270 // TODO: Show an error message.
271 NSLog(@"Weep: %@ %@ %@", featuresFileName, powersFileName, key);
272 continue;
273 }
274
317 // Update the plist store. 275 // Update the plist store.
318 [trackMap setValue:val forKey:key]; 276 [trackMap setValue:val forKey:key];
319 [dbState writeToFile:plistFilename atomically: YES]; 277 [trackMap writeToFile:plistFilename atomically: YES];
320 278
321
322 db = audiodb_open([dbFilename cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY);
323 [self updateStatus]; 279 [self updateStatus];
324 } 280 }
281
282 newFrame.origin.x = [importSheet frame].origin.x;
283 newFrame.origin.y = [importSheet frame].origin.y + [extractingBox frame].size.height;
284 newFrame.size.width = [importSheet frame].size.width;
285 newFrame.size.height = [importSheet frame].size.height - [extractingBox frame].size.height;
286
287 [importSheet setFrame:newFrame display:YES animate:YES];
325 288
326 [NSApp endModalSession:session]; 289 [NSApp endModalSession:session];
327 [importSheet orderOut:nil]; 290 [importSheet orderOut:nil];
328 [NSApp endSheet:importSheet]; 291 [NSApp endSheet:importSheet];
329 [indicator stopAnimation:self]; 292 [indicator stopAnimation:self];
293 [extractingBox setHidden:TRUE];
330 } 294 }
331 } 295 }
332 296
333 /** 297 /**
334 * Required table methods begin here. 298 * Required table methods begin here.
344 -(id)tableView:(NSTableView *)v objectValueForTableColumn:(NSTableColumn *)tc row:(NSInteger)row 308 -(id)tableView:(NSTableView *)v objectValueForTableColumn:(NSTableColumn *)tc row:(NSInteger)row
345 { 309 {
346 id result = [results objectAtIndex:row]; 310 id result = [results objectAtIndex:row];
347 id value = [result objectForKey:[tc identifier]]; 311 id value = [result objectForKey:[tc identifier]];
348 312
349 NSLog(@"Result: %s", [tc identifier]);
350 if([[tc identifier] isEqualToString:@"meter"]) 313 if([[tc identifier] isEqualToString:@"meter"])
351 { 314 {
352 NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle]; 315 NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle];
353 [distance setFloatValue:10-[(NSNumber*)value floatValue]*100]; 316 [distance setFloatValue:10-[(NSNumber*)value floatValue]*100];
354 return distance; 317 return distance;
389 */ 352 */
390 -(IBAction)selectedChanged:(id)sender 353 -(IBAction)selectedChanged:(id)sender
391 { 354 {
392 if([tracksView numberOfSelectedRows] == 0) 355 if([tracksView numberOfSelectedRows] == 0)
393 { 356 {
394 [playBothButton setEnabled:NO]; 357 [playBothButton setEnabled:FALSE];
395 [playResultButton setEnabled:NO]; 358 [playResultButton setEnabled:FALSE];
396 } 359 }
397 else 360 else
398 { 361 {
399 [playBothButton setEnabled:YES]; 362 [playBothButton setEnabled:TRUE];
400 [playResultButton setEnabled:YES]; 363 [playResultButton setEnabled:TRUE];
401 } 364 }
402 } 365 }
403 366
404 /** 367 /**
405 * Play just the result track. 368 * Play just the result track.
406 */ 369 */
407 -(IBAction)playResult:(id)sender 370 -(IBAction)playResult:(id)sender
408 { 371 {
409 372
410 if([tracksView selectedRow] == -1)
411 {
412 return;
413 }
414
415 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; 373 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
416 NSString* value = [selectedRow objectForKey:@"key"]; 374 NSString* value = [selectedRow objectForKey:@"key"];
417 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; 375 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
418 NSString* filename = [trackMap objectForKey:value]; 376 NSString* filename = [trackMap objectForKey:value];
419 NSLog(@"Key: %@ Value: %@", value, filename); 377 NSLog(@"Key: %@ Value: %@", value, filename);
453 { 411 {
454 412
455 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]]; 413 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
456 NSString* value = [selectedRow objectForKey:@"key"]; 414 NSString* value = [selectedRow objectForKey:@"key"];
457 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue]; 415 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
416 float qpos = [[selectedRow objectForKey:@"qpos"] floatValue];
458 NSString* filename = [trackMap objectForKey:value]; 417 NSString* filename = [trackMap objectForKey:value];
459 NSLog(@"Key: %@ Value: %@", value, filename); 418 NSLog(@"Key: %@ Value: %@", value, filename);
460 419
461 if(queryTrack) 420 if(queryTrack)
462 { 421 {
478 [resultTrack release]; 437 [resultTrack release];
479 } 438 }
480 439
481 // Get query track and shift to start point 440 // Get query track and shift to start point
482 queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain]; 441 queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain];
442 [queryTrack setCurrentTime:qpos];
483 [queryTrack setDelegate:self]; 443 [queryTrack setDelegate:self];
484 444
485 [queryTrack play]; 445 [queryTrack play];
486 446
487 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain]; 447 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain];
526 /** 486 /**
527 * Select an audio file, determine the key, and fire off a query. 487 * Select an audio file, determine the key, and fire off a query.
528 */ 488 */
529 -(IBAction)chooseQuery:(id)sender 489 -(IBAction)chooseQuery:(id)sender
530 { 490 {
531 [queryButton setEnabled:(selectedKey ? YES : NO)];
532 [NSApp beginSheet:querySheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
533 session = [NSApp beginModalSessionForWindow:querySheet];
534 [NSApp runModalSession:session];
535 }
536
537
538 -(IBAction)selectQueryFile:(id)sender
539 {
540 NSArray* fileTypes = [NSArray arrayWithObject:@"wav"]; 491 NSArray* fileTypes = [NSArray arrayWithObject:@"wav"];
541 NSOpenPanel* panel = [NSOpenPanel openPanel]; 492 NSOpenPanel* panel = [NSOpenPanel openPanel];
542 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes]; 493 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
543 if(response == NSFileHandlingPanelOKButton) 494 if(response == NSFileHandlingPanelOKButton)
544 { 495 {
496 NSLog(@"%@", [panel filename]);
497 // Grab key
545 NSArray* opts = [trackMap allKeysForObject:[panel filename]]; 498 NSArray* opts = [trackMap allKeysForObject:[panel filename]];
546 if([opts count] != 1) 499 if([opts count] != 1)
547 { 500 {
548 // TODO : Needs fixing!
549
550 NSAlert *alert = [[[NSAlert alloc] init] autorelease]; 501 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
551 [alert addButtonWithTitle:@"OK"]; 502 [alert addButtonWithTitle:@"OK"];
552 [alert setMessageText:@"Track not found"]; 503 [alert setMessageText:@"Track not found"];
553 [alert setInformativeText:@"Make sure you have specified a valid track identifier."]; 504 [alert setInformativeText:@"Make sure you have specified a valid track identifier."];
554 [alert setAlertStyle:NSWarningAlertStyle]; 505 [alert setAlertStyle:NSWarningAlertStyle];
556 } 507 }
557 else 508 else
558 { 509 {
559 selectedKey = [opts objectAtIndex:0]; 510 selectedKey = [opts objectAtIndex:0];
560 [queryKey setStringValue:selectedKey]; 511 [queryKey setStringValue:selectedKey];
561 [queryPath setStringValue:selectedKey];
562 selectedFilename = [[panel filename] retain]; 512 selectedFilename = [[panel filename] retain];
563 [queryButton setEnabled:YES]; 513 [self performQuery];
564 514 }
565 [self resetLengths:self]; 515 }
566 }
567 }
568 }
569
570 -(IBAction)resetLengths:(id)sender
571 {
572 queryTrack = [[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES];
573 NSLog(@"%f", [queryTrack duration]);
574 double samples = ([queryTrack duration]*44100);
575 double hopSize = [[dbState objectForKey:@"hopsize"] doubleValue];
576 double winSize = [[dbState objectForKey:@"windowsize"] doubleValue];
577
578 [queryLengthSeconds setDoubleValue:ceil([queryTrack duration])];
579 [queryLengthVectors setDoubleValue:ceil((samples-winSize)/hopSize)];
580
581 }
582
583 - (void)controlTextDidChange:(NSNotification *)nd
584 {
585 NSTextField *ed = [nd object];
586
587 double hopSize = [[dbState objectForKey:@"hopsize"] doubleValue];
588 double winSize = [[dbState objectForKey:@"windowsize"] doubleValue];
589
590 if(!queryTrack)
591 {
592 queryTrack = [[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES];
593 }
594
595 double totalDuration = [queryTrack duration];
596 double samples = totalDuration * 44100;
597 double totalVectors = ((samples-winSize)/hopSize);
598
599 if (ed == queryLengthSeconds)
600 {
601 double secs = [queryLengthSeconds doubleValue];
602 if(secs > totalDuration)
603 {
604 [queryButton setEnabled:NO];
605 }
606 else if(![queryButton isEnabled])
607 {
608 [queryButton setEnabled:YES];
609 }
610
611 if(secs > 0)
612 {
613 // (samples - windowSize) / hopSize
614
615 [queryLengthVectors setDoubleValue:ceil(((secs*44100)-winSize)/hopSize)];
616 }
617 }
618 if (ed == queryLengthVectors)
619 {
620 double vectors = [queryLengthVectors doubleValue];
621
622 if(vectors > totalVectors)
623 {
624 [queryButton setEnabled:NO];
625 }
626 else if(![queryButton isEnabled])
627 {
628 [queryButton setEnabled:YES];
629 }
630
631 if(vectors > 0)
632 {
633 [queryLengthSeconds setDoubleValue:ceil(((hopSize*vectors)+winSize)/44100)];
634 }
635 }
636 };
637
638 -(IBAction)cancelQuery:(id)sender
639 {
640 [NSApp endModalSession:session];
641 [querySheet orderOut:nil];
642 [NSApp endSheet:querySheet];
643 } 516 }
644 517
645 /** 518 /**
646 * Actually perform the query. TODO: Monolithic. 519 * Actually perform the query. TODO: Monolithic.
647 */ 520 */
648 -(IBAction)performQuery:(id)sender 521 -(void)performQuery
649 { 522 {
650 [NSApp endModalSession:session];
651 [querySheet orderOut:nil];
652 [NSApp endSheet:querySheet];
653
654 NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename); 523 NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename);
655 524
656 adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t)); 525 adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t));
657 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t)); 526 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t));
658 527
659 spec->qid.sequence_length = [queryLengthVectors doubleValue]; 528 spec->qid.sequence_length = 20;
660 spec->qid.sequence_start = 0; 529 spec->qid.sequence_start = 0;
661 spec->qid.flags = 0; 530 spec->qid.flags = 0;
531
662 // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE; 532 // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE;
663
664 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK; 533 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK;
665
666 if([multipleCheckBox state] == NSOnState)
667 {
668 spec->params.npoints = 10;
669 }
670 else
671 {
672 spec->params.npoints = 1;
673 }
674
675 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED; 534 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
676 535
536 spec->params.npoints = 1;
677 spec->params.ntracks = 100; 537 spec->params.ntracks = 100;
678 //spec->refine.radius = 5.0; 538 spec->refine.radius = 5.0;
539 spec->refine.hopsize = 1;
679 // spec->refine.absolute_threshold = -6; 540 // spec->refine.absolute_threshold = -6;
680 // spec->refine.relative_threshold = 10; 541 // spec->refine.relative_threshold = 10;
681 // spec->refine.duration_ratio = 0; 542 // spec->refine.duration_ratio = 0;
682 543
683 spec->refine.flags = 0; 544 spec->refine.flags = 0;
684 // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD; 545 // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
685 // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD; 546 // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
686 // spec->refine.flags |= ADB_REFINE_HOP_SIZE; 547 spec->refine.flags |= ADB_REFINE_HOP_SIZE;
687 //spec->refine.flags |= ADB_REFINE_RADIUS; 548 spec->refine.flags |= ADB_REFINE_RADIUS;
688 549
689 adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t)); 550 adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t));
690 spec->qid.datum->data = NULL; 551 spec->qid.datum->data = NULL;
691 spec->qid.datum->power = NULL; 552 spec->qid.datum->power = NULL;
692 spec->qid.datum->times = NULL; 553 spec->qid.datum->times = NULL;
703 564
704 NSLog(@"No results"); 565 NSLog(@"No results");
705 } 566 }
706 else 567 else
707 { 568 {
708 NSLog(@"Populate table: %d", result->nresults);
709 float divisor = (44100/2048);
710 for(int i=0; i<result->nresults; i++) 569 for(int i=0; i<result->nresults; i++)
711 { 570 {
712
713 NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4]; 571 NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4];
714 [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].ikey] forKey:@"key"]; 572 [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].key] forKey:@"key"];
715 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"]; 573 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"];
716 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"]; 574 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"];
717 [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/divisor] forKey:@"ipos"]; 575 [dict setValue:[NSNumber numberWithFloat:result->results[i].qpos/4] forKey:@"qpos"];
576 [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/4] forKey:@"ipos"];
577 NSLog(@"%s qpos %d ipos %d", result->results[i].key, result->results[i].qpos/4, result->results[i].ipos/4);
718 [results addObject: dict]; 578 [results addObject: dict];
719 } 579 }
720 } 580 }
721 581
722 NSSortDescriptor *distSort = [[NSSortDescriptor alloc]initWithKey:@"meter" ascending:YES]; 582 NSSortDescriptor *distSort = [[NSSortDescriptor alloc]initWithKey:@"meter" ascending:YES];