mas01mj@669
|
1 //
|
mas01mj@669
|
2 // AppController.m
|
mas01mj@706
|
3 // CAMUS
|
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@699
|
8 #import "AppController.h"
|
mas01mj@701
|
9 #import <AudioToolbox/AudioFile.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 return self;
|
mas01mj@669
|
22 }
|
mas01mj@669
|
23
|
mas01mj@699
|
24 - (void)awakeFromNib {
|
mas01mj@699
|
25 [tracksView setTarget:self];
|
mas01mj@699
|
26 [tracksView setDoubleAction:@selector(tableDoubleClick:)];
|
mas01mj@699
|
27 [self updateStatus];
|
mas01mj@699
|
28 }
|
mas01mj@699
|
29
|
mas01mj@699
|
30
|
mas01mj@699
|
31 - (IBAction)tableDoubleClick:(id)sender
|
mas01mj@699
|
32 {
|
mas01mj@699
|
33 [self playResult:Nil];
|
mas01mj@699
|
34 // NSLog(@"Table double clicked");
|
mas01mj@699
|
35 }
|
mas01mj@699
|
36
|
mas01mj@669
|
37
|
mas01mj@669
|
38 /**
|
mas01mj@669
|
39 * Create a new database, given the selected filename.
|
mas01mj@669
|
40 */
|
mas01mj@669
|
41 -(IBAction)newDatabase:(id)sender
|
mas01mj@669
|
42 {
|
mas01mj@699
|
43
|
mas01mj@699
|
44 [NSApp beginSheet:createSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@699
|
45 session = [NSApp beginModalSessionForWindow:createSheet];
|
mas01mj@699
|
46 [NSApp runModalSession:session];
|
mas01mj@699
|
47 }
|
mas01mj@699
|
48
|
mas01mj@699
|
49 /**
|
mas01mj@699
|
50 * Cancel the db creation (at configuration time).
|
mas01mj@699
|
51 */
|
mas01mj@699
|
52 -(IBAction)cancelCreate:(id)sender
|
mas01mj@699
|
53 {
|
mas01mj@699
|
54 [NSApp endModalSession:session];
|
mas01mj@699
|
55 [createSheet orderOut:nil];
|
mas01mj@699
|
56 [NSApp endSheet:createSheet];
|
mas01mj@699
|
57 }
|
mas01mj@699
|
58
|
mas01mj@699
|
59 -(IBAction)createDatabase:(id)sender
|
mas01mj@699
|
60 {
|
mas01mj@699
|
61 [self cancelCreate:self];
|
mas01mj@699
|
62
|
mas01mj@669
|
63 NSSavePanel* panel = [NSSavePanel savePanel];
|
mas01mj@709
|
64 [panel setCanSelectHiddenExtension:YES];
|
mas01mj@739
|
65 [panel setAllowedFileTypes:[NSArray arrayWithObject:@"adb"]];
|
mas01mj@669
|
66 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@""];
|
mas01mj@699
|
67
|
mas01mj@669
|
68 [results removeAllObjects];
|
mas01mj@669
|
69 [tracksView reloadData];
|
mas01mj@699
|
70
|
mas01mj@669
|
71 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
72 {
|
mas01mj@699
|
73 // Work out which extractor to use
|
mas01mj@699
|
74 NSString* extractor = @"adb_chroma";
|
mas01mj@699
|
75 // TODO: This should be stored with the n3.
|
mas01mj@699
|
76 int dim;
|
mas01mj@699
|
77 switch([extractorOptions selectedTag])
|
mas01mj@685
|
78 {
|
mas01mj@699
|
79 case 0:
|
mas01mj@699
|
80 extractor = @"adb_chroma";
|
mas01mj@699
|
81 dim = 12;
|
mas01mj@699
|
82 break;
|
mas01mj@704
|
83 /* case 1:
|
mas01mj@699
|
84 extractor = @"adb_cq";
|
mas01mj@699
|
85 dim = 48;
|
mas01mj@699
|
86 break;
|
mas01mj@699
|
87 case 2:
|
mas01mj@699
|
88 extractor = @"qm_chroma";
|
mas01mj@699
|
89 dim = 12;
|
mas01mj@704
|
90 break;*/
|
mas01mj@704
|
91 case 1:
|
mas01mj@699
|
92 extractor = @"qm_mfcc";
|
mas01mj@699
|
93 dim = 12;
|
mas01mj@699
|
94 break;
|
mas01mj@685
|
95 }
|
mas01mj@685
|
96
|
mas01mj@699
|
97 // Calculate the max DB size
|
mas01mj@709
|
98 NSLog(@"Max length: %f", [maxLengthField doubleValue]);
|
mas01mj@709
|
99 NSLog(@"hop size: %f", [hopSizeField doubleValue]);
|
mas01mj@709
|
100 int vectors = ceil([maxLengthField doubleValue] / (([hopSizeField doubleValue] / 1000.0f)));
|
mas01mj@709
|
101 NSLog(@"Max Vectors: %d", vectors);
|
mas01mj@699
|
102 int numtracks = [maxTracksField intValue];
|
mas01mj@699
|
103 int datasize = ceil((numtracks * vectors * dim * 8.0f) / 1024.0f / 1024.0f); // In MB
|
mas01mj@685
|
104
|
mas01mj@699
|
105 [self reset];
|
mas01mj@699
|
106
|
mas01mj@712
|
107
|
mas01mj@712
|
108
|
mas01mj@669
|
109 // Store useful paths.
|
mas01mj@669
|
110 dbName = [[[panel URL] relativePath] retain];
|
mas01mj@669
|
111 dbFilename = [[panel filename] retain];
|
mas01mj@669
|
112 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
|
mas01mj@712
|
113
|
mas01mj@712
|
114 // Remove any existing files
|
mas01mj@712
|
115 NSFileManager *fileManager = [[NSFileManager alloc] init];
|
mas01mj@712
|
116
|
mas01mj@712
|
117 BOOL overwriteError = NO;
|
mas01mj@712
|
118
|
mas01mj@712
|
119 if([fileManager fileExistsAtPath:[panel filename]])
|
mas01mj@712
|
120 {
|
mas01mj@712
|
121 if(![fileManager removeItemAtPath:[panel filename] error:NULL])
|
mas01mj@712
|
122 {
|
mas01mj@712
|
123 overwriteError = YES;
|
mas01mj@712
|
124 }
|
mas01mj@712
|
125 }
|
mas01mj@712
|
126
|
mas01mj@712
|
127 if(!overwriteError && [fileManager fileExistsAtPath:plistFilename])
|
mas01mj@712
|
128 {
|
mas01mj@712
|
129 if(![fileManager removeItemAtPath:plistFilename error:NULL])
|
mas01mj@712
|
130 {
|
mas01mj@712
|
131 overwriteError = YES;
|
mas01mj@712
|
132 }
|
mas01mj@712
|
133 }
|
mas01mj@712
|
134 [fileManager release];
|
mas01mj@712
|
135
|
mas01mj@712
|
136 if(overwriteError)
|
mas01mj@712
|
137 {
|
mas01mj@712
|
138 NSAlert *alert = [[NSAlert alloc] init];
|
mas01mj@712
|
139 [alert addButtonWithTitle:@"OK"];
|
mas01mj@712
|
140 [alert setMessageText:@"Unable to create database."];
|
mas01mj@712
|
141 [alert setInformativeText:@"A database with this name already exists, and could not be overwritten."];
|
mas01mj@712
|
142 [alert setAlertStyle:NSWarningAlertStyle];
|
mas01mj@712
|
143 [alert runModal];
|
mas01mj@712
|
144 [alert release];
|
mas01mj@712
|
145 return;
|
mas01mj@712
|
146 }
|
mas01mj@712
|
147
|
mas01mj@712
|
148 // Create new db, and set flags.
|
mas01mj@712
|
149 db = audiodb_create([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], datasize, numtracks, dim);
|
mas01mj@712
|
150 audiodb_l2norm(db);
|
mas01mj@699
|
151
|
mas01mj@669
|
152 // Create the plist file (contains mapping from filename to key).
|
mas01mj@699
|
153 dbState = [[NSMutableDictionary alloc] init];
|
mas01mj@669
|
154 trackMap = [[NSMutableDictionary alloc] init];
|
mas01mj@699
|
155 [dbState setValue:trackMap forKey:@"tracks"];
|
mas01mj@699
|
156 [dbState setValue:extractor forKey:@"extractor"];
|
mas01mj@699
|
157 [dbState setValue:[hopSizeField stringValue] forKey:@"hopsize"];
|
mas01mj@699
|
158 [dbState writeToFile:plistFilename atomically:YES];
|
mas01mj@699
|
159
|
mas01mj@669
|
160 [queryKey setStringValue:@"None Selected"];
|
mas01mj@669
|
161 [self updateStatus];
|
mas01mj@669
|
162 }
|
mas01mj@669
|
163 }
|
mas01mj@669
|
164
|
mas01mj@699
|
165 -(void)reset
|
mas01mj@699
|
166 {
|
mas01mj@699
|
167 // Tidy any existing references up.
|
mas01mj@699
|
168 if(db)
|
mas01mj@699
|
169 {
|
mas01mj@699
|
170 NSLog(@"Close db");
|
mas01mj@699
|
171 audiodb_close(db);
|
mas01mj@699
|
172 }
|
mas01mj@699
|
173
|
mas01mj@699
|
174 if(dbFilename)
|
mas01mj@699
|
175 {
|
mas01mj@699
|
176 NSLog(@"Tidy up filenames");
|
mas01mj@699
|
177 [dbFilename release];
|
mas01mj@699
|
178 [dbName release];
|
mas01mj@699
|
179 [plistFilename release];
|
mas01mj@699
|
180 [trackMap release];
|
mas01mj@699
|
181 [dbState release];
|
mas01mj@699
|
182 }
|
mas01mj@699
|
183
|
mas01mj@699
|
184 if(selectedKey)
|
mas01mj@699
|
185 {
|
mas01mj@699
|
186 [selectedKey release];
|
mas01mj@699
|
187 selectedKey = Nil;
|
mas01mj@699
|
188 }
|
mas01mj@699
|
189
|
mas01mj@699
|
190 // Reset query flags
|
mas01mj@699
|
191 [queryPath setStringValue: @"No file selected"];
|
mas01mj@699
|
192 [queryLengthSeconds setDoubleValue:0];
|
mas01mj@699
|
193 [queryLengthVectors setDoubleValue:0];
|
mas01mj@699
|
194 [multipleCheckBox setState:NSOnState];
|
mas01mj@699
|
195 [queryStartSeconds setDoubleValue:0];
|
mas01mj@699
|
196 [queryStartVectors setDoubleValue:0];
|
mas01mj@699
|
197
|
mas01mj@699
|
198 [queryLengthSeconds setEnabled:NO];
|
mas01mj@699
|
199 [queryLengthVectors setEnabled:NO];
|
mas01mj@699
|
200 [queryStartSeconds setEnabled:NO];
|
mas01mj@699
|
201 [queryStartVectors setEnabled:NO];
|
mas01mj@699
|
202 [resetButton setEnabled:NO];
|
mas01mj@699
|
203 [multipleCheckBox setEnabled:NO];
|
mas01mj@739
|
204
|
mas01mj@739
|
205 [playBothButton setEnabled:NO];
|
mas01mj@739
|
206 [playResultButton setEnabled:NO];
|
mas01mj@699
|
207 }
|
mas01mj@699
|
208
|
mas01mj@669
|
209 /**
|
mas01mj@669
|
210 * Open an existing adb (which must have a plist)
|
mas01mj@669
|
211 */
|
mas01mj@669
|
212 -(IBAction)openDatabase:(id)sender
|
mas01mj@669
|
213 {
|
mas01mj@669
|
214 NSArray *fileTypes = [NSArray arrayWithObject:@"adb"];
|
mas01mj@669
|
215 NSOpenPanel* panel = [NSOpenPanel openPanel];
|
mas01mj@669
|
216 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
|
mas01mj@669
|
217 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
218 {
|
mas01mj@699
|
219 [self reset];
|
mas01mj@669
|
220
|
mas01mj@669
|
221 // Store useful paths.
|
mas01mj@699
|
222 NSLog(@"Open");
|
mas01mj@699
|
223 db = audiodb_open([[panel filename] cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY);
|
mas01mj@669
|
224 dbName = [[[panel URL] relativePath] retain];
|
mas01mj@669
|
225 dbFilename = [[panel filename] retain];
|
mas01mj@669
|
226
|
mas01mj@669
|
227 // TODO: Verify this exists!
|
mas01mj@669
|
228 plistFilename = [[NSString stringWithFormat:@"%@.plist", [dbFilename stringByDeletingPathExtension]] retain];
|
mas01mj@669
|
229
|
mas01mj@669
|
230 // Clear out any old results.
|
mas01mj@669
|
231 [results removeAllObjects];
|
mas01mj@669
|
232 [tracksView reloadData];
|
mas01mj@669
|
233
|
mas01mj@669
|
234 [queryKey setStringValue:@"None Selected"];
|
mas01mj@669
|
235
|
mas01mj@669
|
236 adb_liszt_results_t* liszt_results = audiodb_liszt(db);
|
mas01mj@669
|
237
|
mas01mj@669
|
238 for(int k=0; k<liszt_results->nresults; k++)
|
mas01mj@669
|
239 {
|
mas01mj@669
|
240 NSMutableString *trackVal = [[NSMutableString alloc] init];
|
mas01mj@669
|
241 [trackVal appendFormat:@"%s", liszt_results->entries[k].key];
|
mas01mj@669
|
242 }
|
mas01mj@669
|
243
|
mas01mj@669
|
244 audiodb_liszt_free_results(db, liszt_results);
|
mas01mj@699
|
245 dbState = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistFilename] retain];
|
mas01mj@699
|
246 trackMap = [[dbState objectForKey:@"tracks"] retain];
|
mas01mj@699
|
247
|
mas01mj@699
|
248 [self updateStatus];
|
mas01mj@699
|
249
|
mas01mj@669
|
250 NSLog(@"Size: %d", [trackMap count]);
|
mas01mj@669
|
251 }
|
mas01mj@669
|
252 }
|
mas01mj@669
|
253
|
mas01mj@699
|
254 -(IBAction)pathAction:(id)sender
|
mas01mj@699
|
255 {
|
mas01mj@699
|
256 NSLog(@"Path action");
|
mas01mj@699
|
257 }
|
mas01mj@699
|
258
|
mas01mj@669
|
259 /**
|
mas01mj@669
|
260 * Update button states and status field based on current state.
|
mas01mj@669
|
261 */
|
mas01mj@669
|
262 -(void)updateStatus
|
mas01mj@669
|
263 {
|
mas01mj@699
|
264 NSLog(@"Update status");
|
mas01mj@669
|
265 if(db)
|
mas01mj@669
|
266 {
|
mas01mj@699
|
267 NSLog(@"Got a db");
|
mas01mj@699
|
268 adb_status_t *status = (adb_status_t *)malloc(sizeof(adb_status_t));
|
mas01mj@669
|
269 int flags;
|
mas01mj@669
|
270 flags = audiodb_status(db, status);
|
mas01mj@705
|
271 [statusField setStringValue: [NSString stringWithFormat:@"%@ Dim: %d Files: %d Slice: %@ms Ext: %@",
|
mas01mj@699
|
272 dbName,
|
mas01mj@699
|
273 status->dim,
|
mas01mj@699
|
274 status->numFiles,
|
mas01mj@699
|
275 [dbState objectForKey:@"hopsize"],
|
mas01mj@699
|
276 [dbState objectForKey:@"extractor"]]];
|
mas01mj@699
|
277 [performQueryButton setEnabled:YES];
|
mas01mj@699
|
278 [importAudioButton setEnabled:YES];
|
mas01mj@669
|
279 }
|
mas01mj@669
|
280 else
|
mas01mj@669
|
281 {
|
mas01mj@699
|
282 NSLog(@"No db");
|
mas01mj@699
|
283 [performQueryButton setEnabled:NO];
|
mas01mj@699
|
284 [importAudioButton setEnabled:NO];
|
mas01mj@699
|
285 [playBothButton setEnabled:NO];
|
mas01mj@699
|
286 [playResultButton setEnabled:NO];
|
mas01mj@699
|
287 [stopButton setEnabled:NO];
|
mas01mj@669
|
288 }
|
mas01mj@669
|
289 }
|
mas01mj@669
|
290
|
mas01mj@701
|
291 -(UInt64)getSampleRate:(NSString *)filename
|
mas01mj@701
|
292 {
|
mas01mj@701
|
293 AudioFileID audioFile;
|
mas01mj@701
|
294 AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:filename], 0x01, 0, &audioFile);
|
mas01mj@701
|
295
|
mas01mj@701
|
296 UInt32 propertySize;
|
mas01mj@701
|
297 UInt32 propertyIsWritable;
|
mas01mj@701
|
298 AudioFileGetPropertyInfo(audioFile, kAudioFilePropertyDataFormat, &propertySize, &propertyIsWritable);
|
mas01mj@701
|
299
|
mas01mj@701
|
300 AudioStreamBasicDescription dataFormat;
|
mas01mj@701
|
301 AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &propertySize, &dataFormat);
|
mas01mj@701
|
302 Float64 sampleRate = dataFormat.mSampleRate;
|
mas01mj@701
|
303 AudioFileClose(audioFile);
|
mas01mj@701
|
304
|
mas01mj@701
|
305 return sampleRate;
|
mas01mj@701
|
306 }
|
mas01mj@701
|
307
|
mas01mj@702
|
308 -(UInt64)getHopSizeInSamples:(NSString *)filename
|
mas01mj@702
|
309 {
|
mas01mj@702
|
310 NSString* hopStr = [dbState objectForKey:@"hopsize"];
|
mas01mj@702
|
311 return round([self getSampleRate:filename] * ([hopStr doubleValue] / 1000));
|
mas01mj@702
|
312 }
|
mas01mj@702
|
313
|
mas01mj@702
|
314 -(int)nearestPow2:(int)x
|
mas01mj@702
|
315 {
|
mas01mj@702
|
316 if (x < 0)
|
mas01mj@702
|
317 return 0;
|
mas01mj@702
|
318 --x;
|
mas01mj@702
|
319 x |= x >> 1;
|
mas01mj@702
|
320 x |= x >> 2;
|
mas01mj@702
|
321 x |= x >> 4;
|
mas01mj@702
|
322 x |= x >> 8;
|
mas01mj@702
|
323 x |= x >> 16;
|
mas01mj@702
|
324 return x+1;
|
mas01mj@702
|
325 }
|
mas01mj@702
|
326
|
mas01mj@700
|
327 -(void)importFile:(NSString *)filename withExtractorConfig:(NSString *)extractorPath
|
mas01mj@700
|
328 {
|
mas01mj@700
|
329 // Create the extractor configuration
|
mas01mj@702
|
330 int hopSizeSamples = [self getHopSizeInSamples:filename];
|
mas01mj@702
|
331 int windowSizeSamples = [self nearestPow2:(hopSizeSamples*8)];
|
mas01mj@700
|
332
|
mas01mj@700
|
333 NSString* extractorContent = [NSString stringWithContentsOfFile:extractorPath];
|
mas01mj@702
|
334 NSString* newContent = [[extractorContent stringByReplacingOccurrencesOfString:@"HOP_SIZE" withString:[NSString stringWithFormat:@"%d", hopSizeSamples]]
|
mas01mj@702
|
335 stringByReplacingOccurrencesOfString:@"WINDOW_SIZE" withString:[NSString stringWithFormat:@"%d", windowSizeSamples]];
|
mas01mj@700
|
336 NSString* n3FileName = [NSTemporaryDirectory() stringByAppendingPathComponent:@"extractor_config.n3"];
|
mas01mj@702
|
337 NSLog(newContent);
|
mas01mj@700
|
338 NSError* error;
|
mas01mj@700
|
339 [newContent writeToFile:n3FileName atomically:YES encoding:NSASCIIStringEncoding error:&error];
|
mas01mj@700
|
340
|
mas01mj@700
|
341 // Create the temp file for the extracted features
|
mas01mj@700
|
342 NSString* tempFileTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"features.XXXXXX"];
|
mas01mj@700
|
343 const char* tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
|
mas01mj@700
|
344 char* tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
|
mas01mj@700
|
345 strcpy(tempFileNameCString, tempFileTemplateCString);
|
mas01mj@700
|
346 mktemp(tempFileNameCString);
|
mas01mj@700
|
347
|
mas01mj@700
|
348 NSString* featuresFileName = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)];
|
mas01mj@700
|
349 free(tempFileNameCString);
|
mas01mj@700
|
350
|
mas01mj@700
|
351 // Extract features with sonic-annotator
|
mas01mj@700
|
352 NSTask* task = [[NSTask alloc] init];
|
mas01mj@709
|
353 NSLog(@"Resource path: %@", [ [NSBundle mainBundle] resourcePath]);
|
mas01mj@709
|
354 NSString* pluginPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Vamp"];
|
mas01mj@709
|
355 NSString* extractPath = [ [ NSBundle mainBundle ] pathForAuxiliaryExecutable: @"sonic-annotator" ];
|
mas01mj@705
|
356
|
mas01mj@709
|
357 NSLog(@"Plugin path: %@", pluginPath);
|
mas01mj@709
|
358
|
mas01mj@709
|
359 NSDictionary *defaultEnvironment = [[NSProcessInfo processInfo] environment];
|
mas01mj@709
|
360 NSMutableDictionary *environment = [[NSMutableDictionary alloc] initWithDictionary:defaultEnvironment];
|
mas01mj@709
|
361 [environment setValue:pluginPath forKey:@"VAMP_PATH"];
|
mas01mj@709
|
362 NSLog(@"Env: %@", environment);
|
mas01mj@705
|
363 [task setLaunchPath:extractPath];
|
mas01mj@709
|
364 [task setEnvironment:environment];
|
mas01mj@709
|
365
|
mas01mj@705
|
366
|
mas01mj@700
|
367 NSArray* args;
|
mas01mj@700
|
368 args = [NSArray arrayWithObjects:@"-t", n3FileName, @"-w", @"rdf", @"-r", @"--rdf-network", @"--rdf-one-file", featuresFileName, @"--rdf-force", filename, nil];
|
mas01mj@700
|
369 [task setArguments:args];
|
mas01mj@700
|
370 [task launch];
|
mas01mj@700
|
371 [task waitUntilExit];
|
mas01mj@700
|
372 [task release];
|
mas01mj@700
|
373
|
mas01mj@700
|
374 // Populate the audioDB instance
|
mas01mj@700
|
375 NSTask* importTask = [[NSTask alloc] init];
|
mas01mj@705
|
376 NSString* importPath = [ [ NSBundle mainBundle ] pathForAuxiliaryExecutable: @"populate" ];
|
mas01mj@705
|
377 [importTask setLaunchPath:importPath];
|
mas01mj@700
|
378 args = [NSArray arrayWithObjects:featuresFileName, dbFilename, nil];
|
mas01mj@700
|
379 [importTask setArguments:args];
|
mas01mj@700
|
380 [importTask launch];
|
mas01mj@700
|
381 [importTask waitUntilExit];
|
mas01mj@700
|
382 [importTask release];
|
mas01mj@700
|
383
|
mas01mj@700
|
384 NSString* val = [filename retain];
|
mas01mj@700
|
385 NSString* key = [[filename lastPathComponent] retain];
|
mas01mj@700
|
386
|
mas01mj@700
|
387 // Update the plist store.
|
mas01mj@700
|
388 [trackMap setValue:val forKey:key];
|
mas01mj@700
|
389 [dbState writeToFile:plistFilename atomically: YES];
|
mas01mj@700
|
390
|
mas01mj@705
|
391
|
mas01mj@700
|
392 }
|
mas01mj@700
|
393
|
mas01mj@669
|
394 /**
|
mas01mj@669
|
395 * Choose the file(s) to be imported.
|
mas01mj@669
|
396 */
|
mas01mj@699
|
397 -(IBAction)importAudio:(id)sender
|
mas01mj@669
|
398 {
|
mas01mj@669
|
399 [tracksView reloadData];
|
mas01mj@669
|
400
|
mas01mj@739
|
401 NSArray *fileTypes = [NSArray arrayWithObjects:@"wav", @"mp3", @"aif", @"aiff", @"m4a",nil];
|
mas01mj@669
|
402 NSOpenPanel* panel = [NSOpenPanel openPanel];
|
mas01mj@669
|
403 [panel setAllowsMultipleSelection:TRUE];
|
mas01mj@669
|
404 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
|
mas01mj@669
|
405 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
406 {
|
mas01mj@699
|
407 [indicator startAnimation:self];
|
mas01mj@692
|
408
|
mas01mj@699
|
409 [NSApp beginSheet:importSheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@699
|
410 session = [NSApp beginModalSessionForWindow: importSheet];
|
mas01mj@699
|
411 [NSApp runModalSession:session];
|
mas01mj@669
|
412
|
mas01mj@669
|
413 NSArray *filesToOpen = [panel filenames];
|
mas01mj@669
|
414
|
mas01mj@699
|
415 NSString* extractor = [dbState objectForKey:@"extractor"];
|
mas01mj@705
|
416
|
mas01mj@705
|
417 NSLog([NSString stringWithFormat:@"rdf/%@.n3", extractor]);
|
mas01mj@705
|
418 NSString* extractorPath = [ [ NSBundle mainBundle ] pathForResource:extractor ofType:@"n3" inDirectory:@"rdf"];
|
mas01mj@705
|
419 NSLog(@"Extractor path: %@", extractorPath);
|
mas01mj@705
|
420
|
mas01mj@705
|
421 // NSString* extractorPath = [NSString stringWithFormat:@"/Applications/iAudioDB.app/rdf/%@.n3", extractor];
|
mas01mj@669
|
422
|
mas01mj@669
|
423 for(int i=0; i<[filesToOpen count]; i++)
|
mas01mj@699
|
424 {
|
mas01mj@699
|
425 audiodb_close(db);
|
mas01mj@700
|
426
|
mas01mj@700
|
427 // Get the sample rate for the audio file
|
mas01mj@700
|
428
|
mas01mj@700
|
429 [self importFile:[filesToOpen objectAtIndex:i] withExtractorConfig:extractorPath];
|
mas01mj@699
|
430 db = audiodb_open([dbFilename cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY);
|
mas01mj@669
|
431 [self updateStatus];
|
mas01mj@669
|
432 }
|
mas01mj@669
|
433
|
mas01mj@669
|
434 [NSApp endModalSession:session];
|
mas01mj@669
|
435 [importSheet orderOut:nil];
|
mas01mj@669
|
436 [NSApp endSheet:importSheet];
|
mas01mj@669
|
437 [indicator stopAnimation:self];
|
mas01mj@669
|
438 }
|
mas01mj@669
|
439 }
|
mas01mj@669
|
440
|
mas01mj@669
|
441 /**
|
mas01mj@669
|
442 * Required table methods begin here.
|
mas01mj@669
|
443 */
|
mas01mj@669
|
444 -(int)numberOfRowsInTableView:(NSTableView *)v
|
mas01mj@669
|
445 {
|
mas01mj@669
|
446 return [results count];
|
mas01mj@669
|
447 }
|
mas01mj@669
|
448
|
mas01mj@669
|
449 /**
|
mas01mj@669
|
450 * Return appropriate values - or the distance indicator if it's the meter column.
|
mas01mj@669
|
451 */
|
mas01mj@669
|
452 -(id)tableView:(NSTableView *)v objectValueForTableColumn:(NSTableColumn *)tc row:(NSInteger)row
|
mas01mj@669
|
453 {
|
mas01mj@669
|
454 id result = [results objectAtIndex:row];
|
mas01mj@669
|
455 id value = [result objectForKey:[tc identifier]];
|
mas01mj@669
|
456
|
mas01mj@669
|
457 if([[tc identifier] isEqualToString:@"meter"])
|
mas01mj@669
|
458 {
|
mas01mj@669
|
459 NSLevelIndicatorCell *distance = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRelevancyLevelIndicatorStyle];
|
mas01mj@699
|
460 [distance setFloatValue:10.0f-[(NSNumber*)value floatValue]*100.0f];
|
mas01mj@669
|
461 return distance;
|
mas01mj@669
|
462 }
|
mas01mj@669
|
463 else
|
mas01mj@669
|
464 {
|
mas01mj@669
|
465 return value;
|
mas01mj@669
|
466 }
|
mas01mj@669
|
467 }
|
mas01mj@669
|
468
|
mas01mj@669
|
469 /**
|
mas01mj@669
|
470 * Handle column sorting.
|
mas01mj@669
|
471 */
|
mas01mj@669
|
472 - (void)tableView:(NSTableView *)v sortDescriptorsDidChange:(NSArray *)oldDescriptors
|
mas01mj@669
|
473 {
|
mas01mj@669
|
474 [results sortUsingDescriptors:[v sortDescriptors]];
|
mas01mj@669
|
475 [v reloadData];
|
mas01mj@669
|
476 }
|
mas01mj@669
|
477
|
mas01mj@669
|
478 /**
|
mas01mj@669
|
479 * Only enable the import menu option if a database is loaded.
|
mas01mj@669
|
480 */
|
mas01mj@669
|
481 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
|
mas01mj@669
|
482 {
|
mas01mj@669
|
483 SEL theAction = [anItem action];
|
mas01mj@669
|
484 if (theAction == @selector(importAudio:))
|
mas01mj@669
|
485 {
|
mas01mj@669
|
486 if(!db)
|
mas01mj@669
|
487 {
|
mas01mj@669
|
488 return NO;
|
mas01mj@669
|
489 }
|
mas01mj@669
|
490 }
|
mas01mj@739
|
491 else if(theAction == @selector(playBoth:) || theAction == @selector(playResult:))
|
mas01mj@739
|
492 {
|
mas01mj@739
|
493 if([tracksView numberOfSelectedRows] == 0)
|
mas01mj@739
|
494 {
|
mas01mj@739
|
495 return NO;
|
mas01mj@739
|
496 }
|
mas01mj@739
|
497 else
|
mas01mj@739
|
498 {
|
mas01mj@739
|
499 return YES;
|
mas01mj@739
|
500 }
|
mas01mj@739
|
501 }
|
mas01mj@739
|
502 else if(theAction == @selector(stopPlay:))
|
mas01mj@739
|
503 {
|
mas01mj@739
|
504 return NO;
|
mas01mj@739
|
505 }
|
mas01mj@739
|
506
|
mas01mj@739
|
507 NSLog(@"Returning yes for %@", NSStringFromSelector(theAction));
|
mas01mj@739
|
508
|
mas01mj@669
|
509 return YES;
|
mas01mj@669
|
510 }
|
mas01mj@669
|
511
|
mas01mj@669
|
512 /**
|
mas01mj@669
|
513 * Ensure play buttons are only enabled if a track is selected.
|
mas01mj@669
|
514 */
|
mas01mj@669
|
515 -(IBAction)selectedChanged:(id)sender
|
mas01mj@669
|
516 {
|
mas01mj@739
|
517 NSLog(@"Selection changed");
|
mas01mj@669
|
518 if([tracksView numberOfSelectedRows] == 0)
|
mas01mj@669
|
519 {
|
mas01mj@699
|
520 [playBothButton setEnabled:NO];
|
mas01mj@699
|
521 [playResultButton setEnabled:NO];
|
mas01mj@669
|
522 }
|
mas01mj@669
|
523 else
|
mas01mj@669
|
524 {
|
mas01mj@699
|
525 [playBothButton setEnabled:YES];
|
mas01mj@699
|
526 [playResultButton setEnabled:YES];
|
mas01mj@669
|
527 }
|
mas01mj@669
|
528 }
|
mas01mj@669
|
529
|
mas01mj@669
|
530 /**
|
mas01mj@669
|
531 * Play just the result track.
|
mas01mj@669
|
532 */
|
mas01mj@669
|
533 -(IBAction)playResult:(id)sender
|
mas01mj@669
|
534 {
|
mas01mj@669
|
535
|
mas01mj@699
|
536 if([tracksView selectedRow] == -1)
|
mas01mj@699
|
537 {
|
mas01mj@699
|
538 return;
|
mas01mj@699
|
539 }
|
mas01mj@699
|
540
|
mas01mj@669
|
541 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
|
mas01mj@669
|
542 NSString* value = [selectedRow objectForKey:@"key"];
|
mas01mj@669
|
543 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
|
mas01mj@669
|
544 NSString* filename = [trackMap objectForKey:value];
|
mas01mj@669
|
545 NSLog(@"Key: %@ Value: %@", value, filename);
|
mas01mj@669
|
546
|
mas01mj@669
|
547 if(queryTrack)
|
mas01mj@669
|
548 {
|
mas01mj@669
|
549 if([queryTrack isPlaying])
|
mas01mj@669
|
550 {
|
mas01mj@669
|
551 [queryTrack setDelegate:Nil];
|
mas01mj@669
|
552 [queryTrack stop];
|
mas01mj@669
|
553 }
|
mas01mj@669
|
554 [queryTrack release];
|
mas01mj@699
|
555 queryTrack = Nil;
|
mas01mj@669
|
556 }
|
mas01mj@669
|
557
|
mas01mj@669
|
558 if(resultTrack)
|
mas01mj@669
|
559 {
|
mas01mj@669
|
560 if([resultTrack isPlaying])
|
mas01mj@669
|
561 {
|
mas01mj@669
|
562 [resultTrack setDelegate:Nil];
|
mas01mj@669
|
563 [resultTrack stop];
|
mas01mj@669
|
564 }
|
mas01mj@669
|
565 [resultTrack release];
|
mas01mj@699
|
566 resultTrack = Nil;
|
mas01mj@669
|
567 }
|
mas01mj@669
|
568
|
mas01mj@669
|
569 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain];
|
mas01mj@669
|
570 [resultTrack setCurrentTime:ipos];
|
mas01mj@669
|
571 [resultTrack setDelegate:self];
|
mas01mj@669
|
572 [resultTrack play];
|
mas01mj@669
|
573
|
mas01mj@669
|
574 [stopButton setEnabled:YES];
|
mas01mj@669
|
575 }
|
mas01mj@669
|
576
|
mas01mj@669
|
577 /**
|
mas01mj@669
|
578 * Play the result and query simultaneously.
|
mas01mj@669
|
579 */
|
mas01mj@669
|
580 -(IBAction)playBoth:(id)sender
|
mas01mj@669
|
581 {
|
mas01mj@669
|
582
|
mas01mj@669
|
583 NSDictionary* selectedRow = [results objectAtIndex:[tracksView selectedRow]];
|
mas01mj@669
|
584 NSString* value = [selectedRow objectForKey:@"key"];
|
mas01mj@669
|
585 float ipos = [[selectedRow objectForKey:@"ipos"] floatValue];
|
mas01mj@669
|
586 NSString* filename = [trackMap objectForKey:value];
|
mas01mj@669
|
587 NSLog(@"Key: %@ Value: %@", value, filename);
|
mas01mj@669
|
588
|
mas01mj@669
|
589 if(queryTrack)
|
mas01mj@669
|
590 {
|
mas01mj@669
|
591
|
mas01mj@669
|
592 if([queryTrack isPlaying])
|
mas01mj@669
|
593 {
|
mas01mj@669
|
594 [queryTrack setDelegate:Nil];
|
mas01mj@669
|
595 [queryTrack stop];
|
mas01mj@669
|
596 }
|
mas01mj@669
|
597 [queryTrack release];
|
mas01mj@699
|
598 queryTrack = Nil;
|
mas01mj@669
|
599 }
|
mas01mj@669
|
600 if(resultTrack)
|
mas01mj@669
|
601 {
|
mas01mj@669
|
602 if([resultTrack isPlaying])
|
mas01mj@669
|
603 {
|
mas01mj@669
|
604 [resultTrack setDelegate:Nil];
|
mas01mj@669
|
605 [resultTrack stop];
|
mas01mj@669
|
606 }
|
mas01mj@669
|
607 [resultTrack release];
|
mas01mj@699
|
608 resultTrack = Nil;
|
mas01mj@669
|
609 }
|
mas01mj@669
|
610
|
mas01mj@669
|
611 // Get query track and shift to start point
|
mas01mj@669
|
612 queryTrack = [[[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES] retain];
|
mas01mj@669
|
613 [queryTrack setDelegate:self];
|
mas01mj@669
|
614
|
mas01mj@669
|
615 [queryTrack play];
|
mas01mj@669
|
616
|
mas01mj@669
|
617 resultTrack = [[[NSSound alloc] initWithContentsOfFile:filename byReference:YES] retain];
|
mas01mj@669
|
618 [resultTrack setCurrentTime:ipos];
|
mas01mj@669
|
619 [resultTrack setDelegate:self];
|
mas01mj@669
|
620 [resultTrack play];
|
mas01mj@669
|
621
|
mas01mj@669
|
622 [stopButton setEnabled:YES];
|
mas01mj@669
|
623 }
|
mas01mj@669
|
624
|
mas01mj@669
|
625 /**
|
mas01mj@669
|
626 * Disable the stop button after playback of both tracks.
|
mas01mj@669
|
627 */
|
mas01mj@669
|
628 - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)playbackSuccessful
|
mas01mj@669
|
629 {
|
mas01mj@669
|
630
|
mas01mj@669
|
631 if((queryTrack && [queryTrack isPlaying]) || (resultTrack && [resultTrack isPlaying]))
|
mas01mj@669
|
632 {
|
mas01mj@669
|
633 return;
|
mas01mj@669
|
634 }
|
mas01mj@669
|
635 else
|
mas01mj@669
|
636 {
|
mas01mj@669
|
637 [stopButton setEnabled:NO];
|
mas01mj@669
|
638 }
|
mas01mj@669
|
639 }
|
mas01mj@669
|
640
|
mas01mj@669
|
641 /**
|
mas01mj@669
|
642 * Stop playback.
|
mas01mj@669
|
643 */
|
mas01mj@669
|
644 -(IBAction)stopPlay:(id)sender
|
mas01mj@669
|
645 {
|
mas01mj@669
|
646 if(queryTrack)
|
mas01mj@669
|
647 {
|
mas01mj@669
|
648 [queryTrack stop];
|
mas01mj@669
|
649 }
|
mas01mj@669
|
650 if(resultTrack)
|
mas01mj@669
|
651 {
|
mas01mj@669
|
652 [resultTrack stop];
|
mas01mj@669
|
653 }
|
mas01mj@669
|
654 }
|
mas01mj@669
|
655
|
mas01mj@669
|
656 /**
|
mas01mj@669
|
657 * Select an audio file, determine the key, and fire off a query.
|
mas01mj@669
|
658 */
|
mas01mj@669
|
659 -(IBAction)chooseQuery:(id)sender
|
mas01mj@669
|
660 {
|
mas01mj@699
|
661 [queryButton setEnabled:(selectedKey ? YES : NO)];
|
mas01mj@699
|
662 [NSApp beginSheet:querySheet modalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@699
|
663 session = [NSApp beginModalSessionForWindow:querySheet];
|
mas01mj@699
|
664 [NSApp runModalSession:session];
|
mas01mj@699
|
665 }
|
mas01mj@699
|
666
|
mas01mj@699
|
667
|
mas01mj@699
|
668 -(IBAction)selectQueryFile:(id)sender
|
mas01mj@699
|
669 {
|
mas01mj@739
|
670 NSArray* fileTypes = [NSArray arrayWithObjects: @"wav", @"mp3", @"aif", @"aiff", @"m4a", nil];
|
mas01mj@669
|
671 NSOpenPanel* panel = [NSOpenPanel openPanel];
|
mas01mj@669
|
672 NSInteger response = [panel runModalForDirectory:NSHomeDirectory() file:@"" types:fileTypes];
|
mas01mj@669
|
673 if(response == NSFileHandlingPanelOKButton)
|
mas01mj@669
|
674 {
|
mas01mj@669
|
675 NSArray* opts = [trackMap allKeysForObject:[panel filename]];
|
mas01mj@669
|
676 if([opts count] != 1)
|
mas01mj@669
|
677 {
|
mas01mj@699
|
678 // TODO : Needs fixing!
|
mas01mj@699
|
679
|
mas01mj@669
|
680 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
mas01mj@669
|
681 [alert addButtonWithTitle:@"OK"];
|
mas01mj@669
|
682 [alert setMessageText:@"Track not found"];
|
mas01mj@669
|
683 [alert setInformativeText:@"Make sure you have specified a valid track identifier."];
|
mas01mj@669
|
684 [alert setAlertStyle:NSWarningAlertStyle];
|
mas01mj@669
|
685 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@669
|
686 }
|
mas01mj@669
|
687 else
|
mas01mj@669
|
688 {
|
mas01mj@669
|
689 selectedKey = [opts objectAtIndex:0];
|
mas01mj@669
|
690 [queryKey setStringValue:selectedKey];
|
mas01mj@699
|
691 [queryPath setStringValue:selectedKey];
|
mas01mj@669
|
692 selectedFilename = [[panel filename] retain];
|
mas01mj@699
|
693 [queryButton setEnabled:YES];
|
mas01mj@699
|
694
|
mas01mj@699
|
695 [self resetLengths:self];
|
mas01mj@669
|
696 }
|
mas01mj@669
|
697 }
|
mas01mj@669
|
698 }
|
mas01mj@669
|
699
|
mas01mj@699
|
700 -(IBAction)resetLengths:(id)sender
|
mas01mj@699
|
701 {
|
mas01mj@699
|
702 queryTrack = [[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES];
|
mas01mj@699
|
703
|
mas01mj@702
|
704 int sampleRate = [self getSampleRate:selectedFilename];
|
mas01mj@702
|
705 int hopSize = [self getHopSizeInSamples:selectedFilename];
|
mas01mj@702
|
706 int winSize = [self nearestPow2:(hopSize*8)];
|
mas01mj@702
|
707
|
mas01mj@702
|
708 double samples = ([queryTrack duration]*sampleRate);
|
mas01mj@699
|
709
|
mas01mj@699
|
710 [queryLengthSeconds setDoubleValue:[queryTrack duration]];
|
mas01mj@699
|
711 [queryLengthVectors setDoubleValue:ceil((samples-winSize)/hopSize)];
|
mas01mj@699
|
712
|
mas01mj@699
|
713 // For now, go with 0
|
mas01mj@699
|
714 [queryStartSeconds setDoubleValue:0];
|
mas01mj@699
|
715 [queryStartVectors setDoubleValue:0];
|
mas01mj@699
|
716
|
mas01mj@699
|
717 [queryLengthSeconds setEnabled:YES];
|
mas01mj@699
|
718 [queryLengthVectors setEnabled:YES];
|
mas01mj@699
|
719 [queryStartSeconds setEnabled:YES];
|
mas01mj@699
|
720 [queryStartVectors setEnabled:YES];
|
mas01mj@699
|
721 [resetButton setEnabled:YES];
|
mas01mj@699
|
722 [multipleCheckBox setEnabled:YES];
|
mas01mj@702
|
723 [queryButton setEnabled:YES];
|
mas01mj@699
|
724
|
mas01mj@699
|
725 }
|
mas01mj@699
|
726
|
mas01mj@699
|
727 - (void)controlTextDidChange:(NSNotification *)nd
|
mas01mj@699
|
728 {
|
mas01mj@699
|
729 NSTextField *ed = [nd object];
|
mas01mj@699
|
730
|
mas01mj@702
|
731 int sampleRate = [self getSampleRate:selectedFilename];
|
mas01mj@702
|
732 int hopSize = [self getHopSizeInSamples:selectedFilename];
|
mas01mj@702
|
733 int winSize = [self nearestPow2:(hopSize*8)];
|
mas01mj@699
|
734
|
mas01mj@699
|
735 if(!queryTrack)
|
mas01mj@699
|
736 {
|
mas01mj@699
|
737 queryTrack = [[NSSound alloc] initWithContentsOfFile:selectedFilename byReference:YES];
|
mas01mj@699
|
738 }
|
mas01mj@699
|
739
|
mas01mj@699
|
740 double totalDuration = [queryTrack duration];
|
mas01mj@702
|
741 double samples = totalDuration * sampleRate;
|
mas01mj@699
|
742 double totalVectors = ceil((samples-winSize)/hopSize);
|
mas01mj@699
|
743
|
mas01mj@702
|
744
|
mas01mj@699
|
745 double lengthSecs = [queryLengthSeconds doubleValue];
|
mas01mj@699
|
746 double startSecs = [queryStartSeconds doubleValue];
|
mas01mj@699
|
747 double lengthVectors = [queryLengthVectors doubleValue];
|
mas01mj@699
|
748 double startVectors = [queryStartVectors doubleValue];
|
mas01mj@699
|
749
|
mas01mj@699
|
750 // Query Length
|
mas01mj@699
|
751 if (ed == queryLengthSeconds)
|
mas01mj@699
|
752 {
|
mas01mj@699
|
753 if(lengthSecs >= 0)
|
mas01mj@699
|
754 {
|
mas01mj@703
|
755 lengthVectors = ceil((((lengthSecs*sampleRate)-winSize)/hopSize)+1);
|
mas01mj@699
|
756 if(lengthVectors < 0) {lengthVectors = 0; }
|
mas01mj@699
|
757 [queryLengthVectors setDoubleValue:lengthVectors];
|
mas01mj@699
|
758 }
|
mas01mj@699
|
759 }
|
mas01mj@699
|
760
|
mas01mj@699
|
761 if (ed == queryLengthVectors)
|
mas01mj@699
|
762 {
|
mas01mj@699
|
763 if(lengthVectors >= 0)
|
mas01mj@699
|
764 {
|
mas01mj@703
|
765 lengthSecs = ((hopSize*(lengthVectors-1))+winSize)/sampleRate;
|
mas01mj@699
|
766 if(lengthSecs < 0) { lengthSecs = 0; }
|
mas01mj@699
|
767 [queryLengthSeconds setDoubleValue:lengthSecs];
|
mas01mj@699
|
768 }
|
mas01mj@699
|
769 }
|
mas01mj@699
|
770
|
mas01mj@699
|
771 // Query start
|
mas01mj@699
|
772 if (ed == queryStartSeconds)
|
mas01mj@699
|
773 {
|
mas01mj@699
|
774 if(startSecs >= 0)
|
mas01mj@699
|
775 {
|
mas01mj@703
|
776 startVectors = ceil((startSecs*sampleRate)/hopSize);
|
mas01mj@699
|
777 if(startVectors < 0) { startVectors = 0; }
|
mas01mj@699
|
778 [queryStartVectors setDoubleValue:startVectors];
|
mas01mj@699
|
779 }
|
mas01mj@699
|
780 }
|
mas01mj@699
|
781 if (ed == queryStartVectors)
|
mas01mj@699
|
782 {
|
mas01mj@699
|
783 if(startVectors >= 0)
|
mas01mj@699
|
784 {
|
mas01mj@703
|
785 startSecs = (hopSize*startVectors)/sampleRate;
|
mas01mj@699
|
786 if(startSecs < 0) { startSecs = 0; }
|
mas01mj@699
|
787 [queryStartSeconds setDoubleValue:startSecs];
|
mas01mj@699
|
788 }
|
mas01mj@699
|
789 }
|
mas01mj@699
|
790
|
mas01mj@699
|
791 if((lengthSecs + startSecs) > totalDuration || (lengthVectors + startVectors) > totalVectors || lengthVectors == 0)
|
mas01mj@699
|
792 {
|
mas01mj@699
|
793 [queryButton setEnabled:NO];
|
mas01mj@699
|
794 }
|
mas01mj@699
|
795 else if(![queryButton isEnabled])
|
mas01mj@699
|
796 {
|
mas01mj@699
|
797 [queryButton setEnabled:YES];
|
mas01mj@699
|
798 }
|
mas01mj@699
|
799 }
|
mas01mj@699
|
800
|
mas01mj@699
|
801 -(IBAction)cancelQuery:(id)sender
|
mas01mj@699
|
802 {
|
mas01mj@699
|
803 [NSApp endModalSession:session];
|
mas01mj@699
|
804 [querySheet orderOut:nil];
|
mas01mj@699
|
805 [NSApp endSheet:querySheet];
|
mas01mj@699
|
806 }
|
mas01mj@699
|
807
|
mas01mj@669
|
808 /**
|
mas01mj@669
|
809 * Actually perform the query. TODO: Monolithic.
|
mas01mj@669
|
810 */
|
mas01mj@699
|
811 -(IBAction)performQuery:(id)sender
|
mas01mj@669
|
812 {
|
mas01mj@699
|
813 [NSApp endModalSession:session];
|
mas01mj@699
|
814 [querySheet orderOut:nil];
|
mas01mj@699
|
815 [NSApp endSheet:querySheet];
|
mas01mj@699
|
816
|
mas01mj@669
|
817 NSLog(@"Perform query! %@, %@", selectedKey, selectedFilename);
|
mas01mj@669
|
818
|
mas01mj@669
|
819 adb_query_spec_t *spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t));
|
mas01mj@669
|
820 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t));
|
mas01mj@669
|
821
|
mas01mj@699
|
822 spec->qid.sequence_length = [queryLengthVectors doubleValue];
|
mas01mj@699
|
823 spec->qid.sequence_start = [queryStartVectors doubleValue];
|
mas01mj@699
|
824 spec->qid.flags = 0;
|
mas01mj@699
|
825 // spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE;
|
mas01mj@692
|
826
|
mas01mj@669
|
827 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK;
|
mas01mj@699
|
828
|
mas01mj@699
|
829 if([multipleCheckBox state] == NSOnState)
|
mas01mj@699
|
830 {
|
mas01mj@699
|
831 spec->params.npoints = 100;
|
mas01mj@699
|
832 }
|
mas01mj@699
|
833 else
|
mas01mj@699
|
834 {
|
mas01mj@699
|
835 spec->params.npoints = 1;
|
mas01mj@699
|
836 }
|
mas01mj@699
|
837
|
mas01mj@669
|
838 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
|
mas01mj@669
|
839
|
mas01mj@669
|
840 spec->params.ntracks = 100;
|
mas01mj@699
|
841 //spec->refine.radius = 5.0;
|
mas01mj@669
|
842 // spec->refine.absolute_threshold = -6;
|
mas01mj@669
|
843 // spec->refine.relative_threshold = 10;
|
mas01mj@669
|
844 // spec->refine.duration_ratio = 0;
|
mas01mj@669
|
845
|
mas01mj@669
|
846 spec->refine.flags = 0;
|
mas01mj@669
|
847 // spec->refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
|
mas01mj@669
|
848 // spec->refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
|
mas01mj@699
|
849 // spec->refine.flags |= ADB_REFINE_HOP_SIZE;
|
mas01mj@699
|
850 //spec->refine.flags |= ADB_REFINE_RADIUS;
|
mas01mj@669
|
851
|
mas01mj@669
|
852 adb_query_results_t *result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t));
|
mas01mj@669
|
853 spec->qid.datum->data = NULL;
|
mas01mj@669
|
854 spec->qid.datum->power = NULL;
|
mas01mj@669
|
855 spec->qid.datum->times = NULL;
|
mas01mj@669
|
856
|
mas01mj@669
|
857 [results removeAllObjects];
|
mas01mj@669
|
858
|
mas01mj@669
|
859 int ok = audiodb_retrieve_datum(db, [selectedKey cStringUsingEncoding:NSUTF8StringEncoding], spec->qid.datum);
|
mas01mj@669
|
860 if(ok == 0)
|
mas01mj@669
|
861 {
|
mas01mj@699
|
862
|
mas01mj@739
|
863 // float hopSize = [[dbState objectForKey:@"hopsize"] floatValue];
|
mas01mj@669
|
864 NSLog(@"Got a datum");
|
mas01mj@669
|
865 result = audiodb_query_spec(db, spec);
|
mas01mj@669
|
866 if(result == NULL)
|
mas01mj@669
|
867 {
|
mas01mj@669
|
868
|
mas01mj@669
|
869 NSLog(@"No results");
|
mas01mj@669
|
870 }
|
mas01mj@669
|
871 else
|
mas01mj@669
|
872 {
|
mas01mj@702
|
873
|
mas01mj@699
|
874 NSLog(@"Populate table: %d", result->nresults);
|
mas01mj@669
|
875 for(int i=0; i<result->nresults; i++)
|
mas01mj@669
|
876 {
|
mas01mj@699
|
877
|
mas01mj@702
|
878 NSString* filename = [trackMap objectForKey:[NSString stringWithFormat:@"%s", result->results[i].ikey]];
|
mas01mj@702
|
879 int sampleRate = [self getSampleRate:filename];
|
mas01mj@702
|
880 int hopSize = [self getHopSizeInSamples:filename];
|
mas01mj@702
|
881 float divisor = (sampleRate/hopSize);
|
mas01mj@702
|
882
|
mas01mj@669
|
883 NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:4];
|
mas01mj@699
|
884 [dict setValue:[NSString stringWithFormat:@"%s", result->results[i].ikey] forKey:@"key"];
|
mas01mj@669
|
885 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"distance"];
|
mas01mj@669
|
886 [dict setValue:[NSNumber numberWithFloat:result->results[i].dist] forKey:@"meter"];
|
mas01mj@699
|
887 [dict setValue:[NSNumber numberWithFloat:result->results[i].ipos/divisor] forKey:@"ipos"];
|
mas01mj@669
|
888 [results addObject: dict];
|
mas01mj@669
|
889 }
|
mas01mj@669
|
890 }
|
mas01mj@669
|
891
|
mas01mj@669
|
892 NSSortDescriptor *distSort = [[NSSortDescriptor alloc]initWithKey:@"meter" ascending:YES];
|
mas01mj@669
|
893 NSArray *distDescs = [NSArray arrayWithObject:distSort];
|
mas01mj@669
|
894
|
mas01mj@669
|
895 [results sortUsingDescriptors:distDescs];
|
mas01mj@669
|
896 [tracksView setSortDescriptors:distDescs];
|
mas01mj@669
|
897 [tracksView reloadData];
|
mas01mj@669
|
898
|
mas01mj@669
|
899 }
|
mas01mj@669
|
900 else
|
mas01mj@669
|
901 {
|
mas01mj@669
|
902 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
mas01mj@669
|
903 [alert addButtonWithTitle:@"OK"];
|
mas01mj@669
|
904 [alert setMessageText:@"Track not found"];
|
mas01mj@669
|
905 [alert setInformativeText:@"Make sure you have specified a valid track identifier."];
|
mas01mj@669
|
906 [alert setAlertStyle:NSWarningAlertStyle];
|
mas01mj@669
|
907 [alert beginSheetModalForWindow:mainWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
|
mas01mj@669
|
908 }
|
mas01mj@669
|
909 // audiodb_query_free_results(db, spec, result);
|
mas01mj@669
|
910 }
|
mas01mj@669
|
911
|
mas01mj@669
|
912 @end
|