Mercurial > hg > audiodb
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]; |