mas01mj@669
|
1 //
|
mas01mj@669
|
2 // AppController.m
|
mas01mj@669
|
3 // iAudioDB
|
mas01mj@669
|
4 //
|
mas01mj@669
|
5 // Created by Mike Jewell on 27/01/2010.
|
mas01mj@669
|
6 // Copyright 2010 __MyCompanyName__. All rights reserved.
|
mas01mj@669
|
7 //
|
mas01mj@669
|
8
|
mas01mj@669
|
9 #import "AppController.h"
|
mas01mj@669
|
10
|
mas01mj@669
|
11
|
mas01mj@669
|
12 @implementation AppController
|
mas01mj@669
|
13
|
mas01mj@669
|
14 -(id)init
|
mas01mj@669
|
15 {
|
mas01mj@669
|
16 [super init];
|
mas01mj@669
|
17
|
mas01mj@669
|
18 // A max of 100 results.
|
mas01mj@669
|
19 results = [[NSMutableArray alloc] initWithCapacity: 100];
|
mas01mj@669
|
20
|
mas01mj@669
|
21
|
mas01mj@669
|
22 return self;
|
mas01mj@669
|
23 }
|
mas01mj@669
|
24
|
mas01mj@669
|
25
|
mas01mj@669
|
26 /**
|
mas01mj@669
|
27 * Create a new database, given the selected filename.
|
mas01mj@669
|
28 */
|
mas01mj@669
|
29 -(IBAction)newDatabase:(id)sender
|
mas01mj@669
|
30 {
|
mas01mj@669
|
31 NSSavePanel* panel = [NSSavePanel savePanel];
|
mas01mj@669
|
32 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@""];
|
mas01mj@669
|
33
|
mas01mj@669
|
34 [results removeAllObjects];
|
mas01mj@669
|
35 [tracksView reloadData];
|
mas01mj@669
|
36
|
mas01mj@669
|
37 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
38 {
|
mas01mj@669
|
39 // TODO: Refactor this into a 'tidy' method.
|
mas01mj@669
|
40 // Tidy any existing references up.
|
mas01mj@669
|
41 if(db)
|
mas01mj@669
|
42 {
|
mas01mj@669
|
43 audiodb_close(db);
|
mas01mj@669
|
44 }
|
mas01mj@669
|
45
|
mas01mj@669
|
46 if(dbFilename)
|
mas01mj@669
|
47 {
|
mas01mj@669
|
48 [dbFilename release];
|
mas01mj@669
|
49 [dbName release];
|
mas01mj@669
|
50 [plistFilename release];
|
mas01mj@669
|
51 }
|
mas01mj@669
|
52
|
mas01mj@669
|
53 // Create new db, and set flags.
|
mas01mj@669
|
54 db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], 0, 0, 0);
|
mas01mj@669
|
55 audiodb_l2norm(db);
|
mas01mj@669
|
56 audiodb_power(db);
|
mas01mj@669
|
57
|
mas01mj@669
|
58 // Store useful paths.
|
mas01mj@669
|
59 dbName = [[[panel URL] relativePath] retain];
|
mas01mj@669
|
60 dbFilename = [[panel filename] retain];
|
mas01mj@669
|
61 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
|
mas01mj@669
|
62
|
mas01mj@669
|
63 // Create the plist file (contains mapping from filename to key).
|
mas01mj@669
|
64 trackMap = [[NSMutableDictionary alloc] init];
|
mas01mj@669
|
65 [trackMap writeToFile:plistFilename atomically:YES];
|
mas01mj@669
|
66
|
mas01mj@669
|
67 [queryKey setStringValue:@"None Selected"];
|
mas01mj@669
|
68 [self updateStatus];
|
mas01mj@669
|
69 }
|
mas01mj@669
|
70 }
|
mas01mj@669
|
71
|
mas01mj@669
|
72 /**
|
mas01mj@669
|
73 * Open an existing adb (which must have a plist)
|
mas01mj@669
|
74 */
|
mas01mj@669
|
75 -(IBAction)openDatabase:(id)sender
|
mas01mj@669
|
76 {
|
mas01mj@669
|
77 NSArray *fileTypes = [NSArray arrayWithObject:@"adb"];
|
mas01mj@669
|
78 NSOpenPanel* panel = [NSOpenPanel openPanel];
|
mas01mj@669
|
79 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
|
mas01mj@669
|
80 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
81 {
|
mas01mj@669
|
82 // Tidy any existing references up.
|
mas01mj@669
|
83 if(db)
|
mas01mj@669
|
84 {
|
mas01mj@669
|
85 audiodb_close(db);
|
mas01mj@669
|
86 }
|
mas01mj@669
|
87
|
mas01mj@669
|
88 if(dbFilename)
|
mas01mj@669
|
89 {
|
mas01mj@669
|
90 [dbFilename release];
|
mas01mj@669
|
91 [dbName release];
|
mas01mj@669
|
92 [plistFilename release];
|
mas01mj@669
|
93 }
|
mas01mj@669
|
94
|
mas01mj@669
|
95 // Store useful paths.
|
mas01mj@669
|
96 db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDWR);
|
mas01mj@669
|
97 dbName = [[[panel URL] relativePath] retain];
|
mas01mj@669
|
98 dbFilename = [[panel filename] retain];
|
mas01mj@669
|
99
|
mas01mj@669
|
100 // TODO: Verify this exists!
|
mas01mj@669
|
101 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
|
mas01mj@669
|
102
|
mas01mj@669
|
103 // Clear out any old results.
|
mas01mj@669
|
104 [results removeAllObjects];
|
mas01mj@669
|
105 [tracksView reloadData];
|
mas01mj@669
|
106
|
mas01mj@669
|
107 [queryKey setStringValue:@"None Selected"];
|
mas01mj@669
|
108 [self updateStatus];
|
mas01mj@669
|
109
|
mas01mj@669
|
110 adb_liszt_results_t* liszt_results = audiodb_liszt(db);
|
mas01mj@669
|
111
|
mas01mj@669
|
112 for(int k=0; k<liszt_results->nresults; k++)
|
mas01mj@669
|
113 {
|
mas01mj@669
|
114 NSMutableString *trackVal = [[NSMutableString alloc] init];
|
mas01mj@669
|
115 [trackVal appendFormat:@"%s", liszt_results->entries[k].key];
|
mas01mj@669
|
116 }
|
mas01mj@669
|
117
|
mas01mj@669
|
118 audiodb_liszt_free_results(db, liszt_results);
|
mas01mj@669
|
119 trackMap = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain];
|
mas01mj@669
|
120 NSLog(@"Size: %d", [trackMap count]);
|
mas01mj@669
|
121 }
|
mas01mj@669
|
122 }
|
mas01mj@669
|
123
|
mas01mj@669
|
124 /**
|
mas01mj@669
|
125 * Update button states and status field based on current state.
|
mas01mj@669
|
126 */
|
mas01mj@669
|
127 -(void)updateStatus
|
mas01mj@669
|
128 {
|
mas01mj@669
|
129 if(db)
|
mas01mj@669
|
130 {
|
mas01mj@669
|
131 adb_status_ptr status = (adb_status_ptr)malloc(sizeof(struct adbstatus));
|
mas01mj@669
|
132 int flags;
|
mas01mj@669
|
133 flags = audiodb_status(db, status);
|
mas01mj@669
|
134 [statusField setStringValue: [NSString stringWithFormat:@"Database: %@ Dimensions: %d Files: %d", dbName, status->dim, status->numFiles]];
|
mas01mj@669
|
135 [chooseButton setEnabled:YES];
|
mas01mj@669
|
136 }
|
mas01mj@669
|
137 else
|
mas01mj@669
|
138 {
|
mas01mj@669
|
139 [chooseButton setEnabled:NO];
|
mas01mj@669
|
140 [playBothButton setEnabled:FALSE];
|
mas01mj@669
|
141 [playResultButton setEnabled:FALSE];
|
mas01mj@669
|
142 }
|
mas01mj@669
|
143 }
|
mas01mj@669
|
144
|
mas01mj@669
|
145 /**
|
mas01mj@669
|
146 * Get user's import choices.
|
mas01mj@669
|
147 */
|
mas01mj@669
|
148 -(IBAction)importAudio:(id)sender
|
mas01mj@669
|
149 {
|
mas01mj@669
|
150 [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@669
|
151 session = [NSApp beginModalSessionForWindow: importSheet];
|
mas01mj@669
|
152 [NSApp runModalSession:session];
|
mas01mj@669
|
153 }
|
mas01mj@669
|
154
|
mas01mj@669
|
155 /**
|
mas01mj@669
|
156 * Cancel the import (at configuration time).
|
mas01mj@669
|
157 */
|
mas01mj@669
|
158 -(IBAction)cancelImport:(id)sender;
|
mas01mj@669
|
159 {
|
mas01mj@669
|
160 [NSApp endModalSession:session];
|
mas01mj@669
|
161 [importSheet orderOut:nil];
|
mas01mj@669
|
162 [NSApp endSheet:importSheet];
|
mas01mj@669
|
163 }
|
mas01mj@669
|
164
|
mas01mj@669
|
165 /**
|
mas01mj@669
|
166 * Choose the file(s) to be imported.
|
mas01mj@669
|
167 * TODO: Currently handles the import process too - split this off.
|
mas01mj@669
|
168 */
|
mas01mj@669
|
169 -(IBAction)selectFiles:(id)sender
|
mas01mj@669
|
170 {
|
mas01mj@669
|
171 [tracksView reloadData];
|
mas01mj@669
|
172
|
mas01mj@669
|
173 NSArray *fileTypes = [NSArray arrayWithObject:@"wav"];
|
mas01mj@669
|
174 NSOpenPanel* panel = [NSOpenPanel openPanel];
|
mas01mj@669
|
175 [panel setAllowsMultipleSelection:TRUE];
|
mas01mj@669
|
176 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
|
mas01mj@669
|
177 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
178 {
|
mas01mj@669
|
179 NSRect newFrame;
|
mas01mj@669
|
180
|
mas01mj@669
|
181 [extractingBox setHidden:FALSE];
|
mas01mj@669
|
182 newFrame.origin.x = [importSheet frame].origin.x;
|
mas01mj@669
|
183 newFrame.origin.y = [importSheet frame].origin.y - [extractingBox frame].size.height;
|
mas01mj@669
|
184 newFrame.size.width = [importSheet frame].size.width;
|
mas01mj@669
|
185 newFrame.size.height = [importSheet frame].size.height + [extractingBox frame].size.height;
|
mas01mj@669
|
186
|
mas01mj@669
|
187 [indicator startAnimation:self];
|
mas01mj@669
|
188 [importSheet setFrame:newFrame display:YES animate:YES];
|
mas01mj@669
|
189
|
mas01mj@669
|
190 NSArray *filesToOpen = [panel filenames];
|
mas01mj@669
|
191
|
mas01mj@669
|
192 NSLog(@"Begin import");
|
mas01mj@669
|
193
|
mas01mj@669
|
194 // Work out which extractor to use
|
mas01mj@669
|
195 NSString* extractor = @"chromagram";
|
mas01mj@669
|
196 switch([extractorOptions selectedTag])
|
mas01mj@669
|
197 {
|
mas01mj@669
|
198 case 0:
|
mas01mj@669
|
199 extractor = @"mfcc";
|
mas01mj@669
|
200 break;
|
mas01mj@669
|
201 case 1:
|
mas01mj@669
|
202 extractor = @"chromagram";
|
mas01mj@669
|
203 break;
|
mas01mj@669
|
204 }
|
mas01mj@669
|
205
|
mas01mj@669
|
206 for(int i=0; i<[filesToOpen count]; i++)
|
mas01mj@669
|
207 {
|
mas01mj@669
|
208 // First extract powers
|
mas01mj@669
|
209
|
mas01mj@669
|
210 NSString *tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"powers.XXXXXX"];
|
mas01mj@669
|
211 const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
|
mas01mj@669
|
212 char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
|
mas01mj@669
|
213 strcpy(tempFileNameCString, tempFileTemplateCString);
|
mas01mj@669
|
214 mktemp(tempFileNameCString);
|
mas01mj@669
|
215
|
mas01mj@669
|
216 NSString* powersFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
|
mas01mj@669
|
217 free(tempFileNameCString);
|
mas01mj@669
|
218
|
mas01mj@669
|
219 NSTask *task = [[NSTask alloc] init];
|
mas01mj@669
|
220 [task setLaunchPath:@"/usr/local/bin/fftExtract2"];
|
mas01mj@669
|
221 NSArray *args = [NSArray arrayWithObjects:@"-P", @"-h", @"11025", @"-w", @"16384", @"-n", @"32768", @"-i", @"1000", [filesToOpen objectAtIndex:i], powersFileName, nil];
|
mas01mj@669
|
222 [task setArguments:args];
|
mas01mj@669
|
223 [task launch];
|
mas01mj@669
|
224 [task waitUntilExit];
|
mas01mj@669
|
225 [task release];
|
mas01mj@669
|
226
|
mas01mj@669
|
227 // Then features
|
mas01mj@669
|
228
|
mas01mj@669
|
229 tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"];
|
mas01mj@669
|
230 tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
|
mas01mj@669
|
231 tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
|
mas01mj@669
|
232 strcpy(tempFileNameCString, tempFileTemplateCString);
|
mas01mj@669
|
233 mktemp(tempFileNameCString);
|
mas01mj@669
|
234
|
mas01mj@669
|
235 NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
|
mas01mj@669
|
236 free(tempFileNameCString);
|
mas01mj@669
|
237
|
mas01mj@669
|
238 task = [[NSTask alloc] init];
|
mas01mj@669
|
239
|
mas01mj@669
|
240 [task setLaunchPath:@"/usr/local/bin/fftExtract2"];
|
mas01mj@669
|
241
|
mas01mj@669
|
242 NSArray *args2;
|
mas01mj@669
|
243
|
mas01mj@669
|
244 // Choose the args (TODO: This should use sonic annotator eventually)
|
mas01mj@669
|
245 if([extractor isEqualToString:@"chromagram"])
|
mas01mj@669
|
246 {
|
mas01mj@669
|
247 args2 = [NSArray arrayWithObjects:@"-p",@"/Users/moj/planfile",@"-c", @"36", @"-h", @"11025", @"-w", @"16384", @"-n", @"32768", @"-i", @"1000", [filesToOpen objectAtIndex:i], featuresFileName, nil];
|
mas01mj@669
|
248 }
|
mas01mj@669
|
249 else
|
mas01mj@669
|
250 {
|
mas01mj@669
|
251 args2 = [NSArray arrayWithObjects:@"-p",@"/Users/moj/planfile",@"-m", @"13", @"-h", @"11025", @"-w", @"16384", @"-n ", @"32768", @"-i", @"1000", [filesToOpen objectAtIndex:i], featuresFileName, nil];
|
mas01mj@669
|
252 }
|
mas01mj@669
|
253 [task setArguments:args2];
|
mas01mj@669
|
254 [task launch];
|
mas01mj@669
|
255 [task waitUntilExit];
|
mas01mj@669
|
256 [task release];
|
mas01mj@669
|
257
|
mas01mj@669
|
258 NSString* val = [[filesToOpen objectAtIndex:i] retain];
|
mas01mj@669
|
259 NSString* key = [[[filesToOpen objectAtIndex:i] lastPathComponent] retain];
|
mas01mj@669
|
260
|
mas01mj@669
|
261 adb_insert_t insert;
|
mas01mj@669
|
262 insert.features = [featuresFileName cStringUsingEncoding:NSUTF8StringEncoding];
|
mas01mj@669
|
263 insert.power = [powersFileName cStringUsingEncoding:NSUTF8StringEncoding];
|
mas01mj@669
|
264 insert.times = NULL;
|
mas01mj@669
|
265 insert.key = [key cStringUsingEncoding:NSUTF8StringEncoding];
|
mas01mj@669
|
266
|
mas01mj@669
|
267 // Insert into db.
|
mas01mj@669
|
268 if(audiodb_insert(db, &insert))
|
mas01mj@669
|
269 {
|
mas01mj@669
|
270 // TODO: Show an error message.
|
mas01mj@669
|
271 NSLog(@"Weep: %@ %@ %@", featuresFileName, powersFileName, key);
|
mas01mj@669
|
272 continue;
|
mas01mj@669
|
273 }
|
mas01mj@669
|
274
|
mas01mj@669
|
275 // Update the plist store.
|
mas01mj@669
|
276 [trackMap setValue:val forKey:key];
|
mas01mj@669
|
277 [trackMap writeToFile:plistFilename atomically: YES];
|
mas01mj@669
|
278
|
mas01mj@669
|
279 [self updateStatus];
|
mas01mj@669
|
280 }
|
mas01mj@669
|
281
|
mas01mj@669
|
282 newFrame.origin.x = [importSheet frame].origin.x;
|
mas01mj@669
|
283 newFrame.origin.y = [importSheet frame].origin.y + [extractingBox frame].size.height;
|
mas01mj@669
|
284 newFrame.size.width = [importSheet frame].size.width;
|
mas01mj@669
|
285 newFrame.size.height = [importSheet frame].size.height - [extractingBox frame].size.height;
|
mas01mj@669
|
286
|
mas01mj@669
|
287 [importSheet setFrame:newFrame display:YES animate:YES];
|
mas01mj@669
|
288
|
mas01mj@669
|
289 [NSApp endModalSession:session];
|
mas01mj@669
|
290 [importSheet orderOut:nil];
|
mas01mj@669
|
291 [NSApp endSheet:importSheet];
|
mas01mj@669
|
292 [indicator stopAnimation:self];
|
mas01mj@669
|
293 [extractingBox setHidden:TRUE];
|
mas01mj@669
|
294 }
|
mas01mj@669
|
295 }
|
mas01mj@669
|
296
|
mas01mj@669
|
297 /**
|
mas01mj@669
|
298 * Required table methods begin here.
|
mas01mj@669
|
299 */
|
mas01mj@669
|
300 -(int)numberOfRowsInTableView:(NSTableView *)v
|
mas01mj@669
|
301 {
|
mas01mj@669
|
302 return [results count];
|
mas01mj@669
|
303 }
|
mas01mj@669
|
304
|
mas01mj@669
|
305 /**
|
mas01mj@669
|
306 * Return appropriate values - or the distance indicator if it's the meter column.
|
mas01mj@669
|
307 */
|
mas01mj@669
|
308 -(id)tableView:(NSTableView *)v objectValueForTableColumn:(NSTableColumn *)tc row:(NSInteger)row
|
mas01mj@669
|
309 {
|
mas01mj@669
|
310 id result = [results objectAtIndex:row];
|
mas01mj@669
|
311 id value = [result objectForKey:[tc identifier]];
|
mas01mj@669
|
312
|
mas01mj@669
|
313 if([[tc identifier] isEqualToString:@"meter"])
|
mas01mj@669
|
314 {
|
mas01mj@669
|
315 NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle];
|
mas01mj@669
|
316 [distance setFloatValue:10-[(NSNumber*)value floatValue]*100];
|
mas01mj@669
|
317 return distance;
|
mas01mj@669
|
318 }
|
mas01mj@669
|
319 else
|
mas01mj@669
|
320 {
|
mas01mj@669
|
321 return value;
|
mas01mj@669
|
322 }
|
mas01mj@669
|
323 }
|
mas01mj@669
|
324
|
mas01mj@669
|
325 /**
|
mas01mj@669
|
326 * Handle column sorting.
|
mas01mj@669
|
327 */
|
mas01mj@669
|
328 - (void)tableView:(NSTableView *)v sortDescriptorsDidChange:(NSArray *)oldDescriptors
|
mas01mj@669
|
329 {
|
mas01mj@669
|
330 [results sortUsingDescriptors:[v sortDescriptors]];
|
mas01mj@669
|
331 [v reloadData];
|
mas01mj@669
|
332 }
|
mas01mj@669
|
333
|
mas01mj@669
|
334 /**
|
mas01mj@669
|
335 * Only enable the import menu option if a database is loaded.
|
mas01mj@669
|
336 */
|
mas01mj@669
|
337 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
|
mas01mj@669
|
338 {
|
mas01mj@669
|
339 SEL theAction = [anItem action];
|
mas01mj@669
|
340 if (theAction == @selector(importAudio:))
|
mas01mj@669
|
341 {
|
mas01mj@669
|
342 if(!db)
|
mas01mj@669
|
343 {
|
mas01mj@669
|
344 return NO;
|
mas01mj@669
|
345 }
|
mas01mj@669
|
346 }
|
mas01mj@669
|
347 return YES;
|
mas01mj@669
|
348 }
|
mas01mj@669
|
349
|
mas01mj@669
|
350 /**
|
mas01mj@669
|
351 * Ensure play buttons are only enabled if a track is selected.
|
mas01mj@669
|
352 */
|
mas01mj@669
|
353 -(IBAction)selectedChanged:(id)sender
|
mas01mj@669
|
354 {
|
mas01mj@669
|
355 if([tracksView numberOfSelectedRows] == 0)
|
mas01mj@669
|
356 {
|
mas01mj@669
|
357 [playBothButton setEnabled:FALSE];
|
mas01mj@669
|
358 [playResultButton setEnabled:FALSE];
|
mas01mj@669
|
359 }
|
mas01mj@669
|
360 else
|
mas01mj@669
|
361 {
|
mas01mj@669
|
362 [playBothButton setEnabled:TRUE];
|
mas01mj@669
|
363 [playResultButton setEnabled:TRUE];
|
mas01mj@669
|
364 }
|
mas01mj@669
|
365 }
|
mas01mj@669
|
366
|
mas01mj@669
|
367 /**
|
mas01mj@669
|
368 * Play just the result track.
|
mas01mj@669
|
369 */
|
mas01mj@669
|
370 -(IBAction)playResult:(id)sender
|
mas01mj@669
|
371 {
|
mas01mj@669
|
372
|
mas01mj@669
|
373 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
|
mas01mj@669
|
374 NSString* value = [selectedRow objectForKey:@"key"];
|
mas01mj@669
|
375 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
|
mas01mj@669
|
376 NSString* filename = [trackMap objectForKey:value];
|
mas01mj@669
|
377 NSLog(@"Key: %@ Value: %@", value, filename);
|
mas01mj@669
|
378
|
mas01mj@669
|
379 if(queryTrack)
|
mas01mj@669
|
380 {
|
mas01mj@669
|
381 if([queryTrack isPlaying])
|
mas01mj@669
|
382 {
|
mas01mj@669
|
383 [queryTrack setDelegate:Nil];
|
mas01mj@669
|
384 [queryTrack stop];
|
mas01mj@669
|
385 }
|
mas01mj@669
|
386 [queryTrack release];
|
mas01mj@669
|
387 }
|
mas01mj@669
|
388
|
mas01mj@669
|
389 if(resultTrack)
|
mas01mj@669
|
390 {
|
mas01mj@669
|
391 if([resultTrack isPlaying])
|
mas01mj@669
|
392 {
|
mas01mj@669
|
393 [resultTrack setDelegate:Nil];
|
mas01mj@669
|
394 [resultTrack stop];
|
mas01mj@669
|
395 }
|
mas01mj@669
|
396 [resultTrack release];
|
mas01mj@669
|
397 }
|
mas01mj@669
|
398
|
mas01mj@669
|
399 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain];
|
mas01mj@669
|
400 [resultTrack setCurrentTime:ipos];
|
mas01mj@669
|
401 [resultTrack setDelegate:self];
|
mas01mj@669
|
402 [resultTrack play];
|
mas01mj@669
|
403
|
mas01mj@669
|
404 [stopButton setEnabled:YES];
|
mas01mj@669
|
405 }
|
mas01mj@669
|
406
|
mas01mj@669
|
407 /**
|
mas01mj@669
|
408 * Play the result and query simultaneously.
|
mas01mj@669
|
409 */
|
mas01mj@669
|
410 -(IBAction)playBoth:(id)sender
|
mas01mj@669
|
411 {
|
mas01mj@669
|
412
|
mas01mj@669
|
413 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
|
mas01mj@669
|
414 NSString* value = [selectedRow objectForKey:@"key"];
|
mas01mj@669
|
415 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
|
mas01mj@669
|
416 float qpos = [[selectedRow objectForKey:@"qpos"] floatValue];
|
mas01mj@669
|
417 NSString* filename = [trackMap objectForKey:value];
|
mas01mj@669
|
418 NSLog(@"Key: %@ Value: %@", value, filename);
|
mas01mj@669
|
419
|
mas01mj@669
|
420 if(queryTrack)
|
mas01mj@669
|
421 {
|
mas01mj@669
|
422
|
mas01mj@669
|
423 if([queryTrack isPlaying])
|
mas01mj@669
|
424 {
|
mas01mj@669
|
425 [queryTrack setDelegate:Nil];
|
mas01mj@669
|
426 [queryTrack stop];
|
mas01mj@669
|
427 }
|
mas01mj@669
|
428 [queryTrack release];
|
mas01mj@669
|
429 }
|
mas01mj@669
|
430 if(resultTrack)
|
mas01mj@669
|
431 {
|
mas01mj@669
|
432 if([resultTrack isPlaying])
|
mas01mj@669
|
433 {
|
mas01mj@669
|
434 [resultTrack setDelegate:Nil];
|
mas01mj@669
|
435 [resultTrack stop];
|
mas01mj@669
|
436 }
|
mas01mj@669
|
437 [resultTrack release];
|
mas01mj@669
|
438 }
|
mas01mj@669
|
439
|
mas01mj@669
|
440 // Get query track and shift to start point
|
mas01mj@669
|
441 queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain];
|
mas01mj@669
|
442 [queryTrack setCurrentTime:qpos];
|
mas01mj@669
|
443 [queryTrack setDelegate:self];
|
mas01mj@669
|
444
|
mas01mj@669
|
445 [queryTrack play];
|
mas01mj@669
|
446
|
mas01mj@669
|
447 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain];
|
mas01mj@669
|
448 [resultTrack setCurrentTime:ipos];
|
mas01mj@669
|
449 [resultTrack setDelegate:self];
|
mas01mj@669
|
450 [resultTrack play];
|
mas01mj@669
|
451
|
mas01mj@669
|
452 [stopButton setEnabled:YES];
|
mas01mj@669
|
453 }
|
mas01mj@669
|
454
|
mas01mj@669
|
455 /**
|
mas01mj@669
|
456 * Disable the stop button after playback of both tracks.
|
mas01mj@669
|
457 */
|
mas01mj@669
|
458 - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)playbackSuccessful
|
mas01mj@669
|
459 {
|
mas01mj@669
|
460
|
mas01mj@669
|
461 if((queryTrack && [queryTrack isPlaying]) || (resultTrack && [resultTrack isPlaying]))
|
mas01mj@669
|
462 {
|
mas01mj@669
|
463 return;
|
mas01mj@669
|
464 }
|
mas01mj@669
|
465 else
|
mas01mj@669
|
466 {
|
mas01mj@669
|
467 [stopButton setEnabled:NO];
|
mas01mj@669
|
468 }
|
mas01mj@669
|
469 }
|
mas01mj@669
|
470
|
mas01mj@669
|
471 /**
|
mas01mj@669
|
472 * Stop playback.
|
mas01mj@669
|
473 */
|
mas01mj@669
|
474 -(IBAction)stopPlay:(id)sender
|
mas01mj@669
|
475 {
|
mas01mj@669
|
476 if(queryTrack)
|
mas01mj@669
|
477 {
|
mas01mj@669
|
478 [queryTrack stop];
|
mas01mj@669
|
479 }
|
mas01mj@669
|
480 if(resultTrack)
|
mas01mj@669
|
481 {
|
mas01mj@669
|
482 [resultTrack stop];
|
mas01mj@669
|
483 }
|
mas01mj@669
|
484 }
|
mas01mj@669
|
485
|
mas01mj@669
|
486 /**
|
mas01mj@669
|
487 * Select an audio file, determine the key, and fire off a query.
|
mas01mj@669
|
488 */
|
mas01mj@669
|
489 -(IBAction)chooseQuery:(id)sender
|
mas01mj@669
|
490 {
|
mas01mj@669
|
491 NSArray* fileTypes = [NSArray arrayWithObject:@"wav"];
|
mas01mj@669
|
492 NSOpenPanel* panel = [NSOpenPanel openPanel];
|
mas01mj@669
|
493 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
|
mas01mj@669
|
494 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
495 {
|
mas01mj@669
|
496 NSLog(@"%@", [panel filename]);
|
mas01mj@669
|
497 // Grab key
|
mas01mj@669
|
498 NSArray* opts = [trackMap allKeysForObject:[panel filename]];
|
mas01mj@669
|
499 if([opts count] != 1)
|
mas01mj@669
|
500 {
|
mas01mj@669
|
501 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
mas01mj@669
|
502 [alert addButtonWithTitle:@"OK"];
|
mas01mj@669
|
503 [alert setMessageText:@"Track not found"];
|
mas01mj@669
|
504 [alert setInformativeText:@"Make sure you have specified a valid track identifier."];
|
mas01mj@669
|
505 [alert setAlertStyle:NSWarningAlertStyle];
|
mas01mj@669
|
506 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@669
|
507 }
|
mas01mj@669
|
508 else
|
mas01mj@669
|
509 {
|
mas01mj@669
|
510 selectedKey = [opts objectAtIndex:0];
|
mas01mj@669
|
511 [queryKey setStringValue:selectedKey];
|
mas01mj@669
|
512 selectedFilename = [[panel filename] retain];
|
mas01mj@669
|
513 [self performQuery];
|
mas01mj@669
|
514 }
|
mas01mj@669
|
515 }
|
mas01mj@669
|
516 }
|
mas01mj@669
|
517
|
mas01mj@669
|
518 /**
|
mas01mj@669
|
519 * Actually perform the query. TODO: Monolithic.
|
mas01mj@669
|
520 */
|
mas01mj@669
|
521 -(void)performQuery
|
mas01mj@669
|
522 {
|
mas01mj@669
|
523 NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename);
|
mas01mj@669
|
524
|
mas01mj@669
|
525 adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t));
|
mas01mj@669
|
526 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t));
|
mas01mj@669
|
527
|
mas01mj@669
|
528 spec->qid.sequence_length = 20;
|
mas01mj@669
|
529 spec->qid.sequence_start = 0;
|
mas01mj@669
|
530 spec->qid.flags = 0;
|
mas01mj@669
|
531
|
mas01mj@669
|
532 // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE;
|
mas01mj@669
|
533 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK;
|
mas01mj@669
|
534 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
|
mas01mj@669
|
535
|
mas01mj@669
|
536 spec->params.npoints = 1;
|
mas01mj@669
|
537 spec->params.ntracks = 100;
|
mas01mj@669
|
538 //spec->refine.radius = 5.0;
|
mas01mj@669
|
539 spec->refine.hopsize = 1;
|
mas01mj@669
|
540 // spec->refine.absolute_threshold = -6;
|
mas01mj@669
|
541 // spec->refine.relative_threshold = 10;
|
mas01mj@669
|
542 // spec->refine.duration_ratio = 0;
|
mas01mj@669
|
543
|
mas01mj@669
|
544 spec->refine.flags = 0;
|
mas01mj@669
|
545 // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
|
mas01mj@669
|
546 // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
|
mas01mj@669
|
547 spec->refine.flags |= ADB_REFINE_HOP_SIZE;
|
mas01mj@669
|
548 //spec->refine.flags |= ADB_REFINE_RADIUS;
|
mas01mj@669
|
549
|
mas01mj@669
|
550 adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t));
|
mas01mj@669
|
551 spec->qid.datum->data = NULL;
|
mas01mj@669
|
552 spec->qid.datum->power = NULL;
|
mas01mj@669
|
553 spec->qid.datum->times = NULL;
|
mas01mj@669
|
554
|
mas01mj@669
|
555 [results removeAllObjects];
|
mas01mj@669
|
556
|
mas01mj@669
|
557 int ok = audiodb_retrieve_datum(db, [selectedKey cStringUsingEncoding:NSUTF8StringEncoding], spec->qid.datum);
|
mas01mj@669
|
558 if(ok == 0)
|
mas01mj@669
|
559 {
|
mas01mj@669
|
560 NSLog(@"Got a datum");
|
mas01mj@669
|
561 result = audiodb_query_spec(db, spec);
|
mas01mj@669
|
562 if(result == NULL)
|
mas01mj@669
|
563 {
|
mas01mj@669
|
564
|
mas01mj@669
|
565 NSLog(@"No results");
|
mas01mj@669
|
566 }
|
mas01mj@669
|
567 else
|
mas01mj@669
|
568 {
|
mas01mj@669
|
569 for(int i=0; i<result->nresults; i++)
|
mas01mj@669
|
570 {
|
mas01mj@669
|
571 NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4];
|
mas01mj@669
|
572 [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].key] forKey:@"key"];
|
mas01mj@669
|
573 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"];
|
mas01mj@669
|
574 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"];
|
mas01mj@669
|
575 [dict setValue:[NSNumber numberWithFloat:result->results[i].qpos/4] forKey:@"qpos"];
|
mas01mj@669
|
576 [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/4] forKey:@"ipos"];
|
mas01mj@669
|
577 NSLog(@"%s qpos %d ipos %d", result->results[i].key, result->results[i].qpos/4, result->results[i].ipos/4);
|
mas01mj@669
|
578 [results addObject: dict];
|
mas01mj@669
|
579 }
|
mas01mj@669
|
580 }
|
mas01mj@669
|
581
|
mas01mj@669
|
582 NSSortDescriptor *distSort = [[NSSortDescriptor alloc]initWithKey:@"meter" ascending:YES];
|
mas01mj@669
|
583 NSArray *distDescs = [NSArray arrayWithObject:distSort];
|
mas01mj@669
|
584
|
mas01mj@669
|
585 [results sortUsingDescriptors:distDescs];
|
mas01mj@669
|
586 [tracksView setSortDescriptors:distDescs];
|
mas01mj@669
|
587 [tracksView reloadData];
|
mas01mj@669
|
588
|
mas01mj@669
|
589 }
|
mas01mj@669
|
590 else
|
mas01mj@669
|
591 {
|
mas01mj@669
|
592 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
mas01mj@669
|
593 [alert addButtonWithTitle:@"OK"];
|
mas01mj@669
|
594 [alert setMessageText:@"Track not found"];
|
mas01mj@669
|
595 [alert setInformativeText:@"Make sure you have specified a valid track identifier."];
|
mas01mj@669
|
596 [alert setAlertStyle:NSWarningAlertStyle];
|
mas01mj@669
|
597 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@669
|
598 }
|
mas01mj@669
|
599 // audiodb_query_free_results(db, spec, result);
|
mas01mj@669
|
600 }
|
mas01mj@669
|
601
|
mas01mj@669
|
602 @end
|