CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

BinauralDB.cpp
Go to the documentation of this file.
1 ///
2 /// BinauralDB.cpp -- HRTF-based binaural panner/spatializers
3 ///
4 /// Classes
5 /// HRTF: holds the data that corresponds to an HRTF for a single position.
6 /// HRTFDatabase: vector of HRTFs; implemented as a Singleton because it's large.
7 /// BinauralPanner: place sources in 3D using block-wise convolution with an HRTF.
8 /// BinauralSourceCache: used for caching previous state of spatial sources.
9 ///
10 /// See the copyright notice and acknowledgment of authors in the file COPYRIGHT
11 /// Created by Jorge Castellanos on 7/19/06.
12 /// Rewritten for FFT wrappers and pluggable sound file APIs in 8/09 by STP.
13 /// Inspired by and partially based on the VST HRTF Plug-in written by Ryan Avery.
14 ///
15
16 #include "BinauralDB.h"
17
18 //#include <iostream>
19
20 using namespace csl;
21 using namespace std;
22
23 // HRTF Constructor allocates memory for the HRTF data
24
25 HRTF::HRTF() {
26 unsigned hrirLength = HRIR_SIZE;
27 unsigned framesPerBlock = HRTF_BLOCK_SIZE;
28 unsigned mWindowSize = 2 * framesPerBlock;
29 mNumFFTBlocks = hrirLength / framesPerBlock;
30 unsigned hrtfLength = framesPerBlock + 1;
31 // allocate HRTF: L/R vectors of complex buffers
32 SAFE_MALLOC(mHrtfL, SampleComplexVector, mNumFFTBlocks);
33 for (unsigned i = 0; i < mNumFFTBlocks; i++) {
34 SAFE_MALLOC(mHrtfL[i], SampleComplex, hrtfLength);
35 }
36 SAFE_MALLOC(mHrtfR, SampleComplexVector, mNumFFTBlocks);
37 for (unsigned i = 0; i < mNumFFTBlocks; i++) {
38 SAFE_MALLOC(mHrtfR[i], SampleComplex, hrtfLength);
39 }
40 }
41
42 // HRTF Constructor allocates memory for the HRTF data and then reads the HRIR file
43 // and performs the block-wise FFT into the complex arrays mHrtfL[i] and mHrtfR[i]
44
45 HRTF::HRTF(char * filename, FFTWrapper & fft) {
46 unsigned hrirLength = HRIR_SIZE;
47 unsigned framesPerBlock = HRTF_BLOCK_SIZE;
48 unsigned mWindowSize = 2 * framesPerBlock;
49 mNumFFTBlocks = hrirLength / framesPerBlock;
50 unsigned hrtfLength = framesPerBlock + 1;
51 float theta, phi;
52 // allocate HRTF data storage
53 SAFE_MALLOC(mHrtfL, SampleComplexVector, mNumFFTBlocks);
54 for (unsigned i = 0; i < mNumFFTBlocks; i++) {
55 SAFE_MALLOC(mHrtfL[i], SampleComplex, hrtfLength);
56 }
57 SAFE_MALLOC(mHrtfR, SampleComplexVector, mNumFFTBlocks);
58 for (unsigned i = 0; i < mNumFFTBlocks; i++) {
59 SAFE_MALLOC(mHrtfR[i], SampleComplex, hrtfLength);
60 }
61 // I/O buffers
62 Buffer mInBuf(1, mWindowSize), mOutBuf(1, mWindowSize);
63 mInBuf.allocateBuffers(); // mInBuf has actual storage
64
65 char *cursor = strstr(filename, "_T"); // parse the name to get theta and phi
66 if (cursor == NULL) { // e.g., IRC_1012_R_R0195_T000_P330.wav
67 logMsg(kLogError, "Cannot parse HRIR file name for theta: \"%s\"\n", filename);
68 throw IOError("Cannot parse HRIR filename");
69 }
70 theta = strtof((cursor + 2), (char **)NULL); // Read the number (degree) for theta, in filename.
71
72 cursor = strstr(filename, "_P");
73 if (cursor == NULL) {
74 logMsg(kLogError, "Cannot parse HRIR file namefor phi: \"%s\"\n", filename);
75 throw IOError("Cannot parse HRIR filename");
76 }
77 phi = strtof((cursor + 2), (char **)NULL); // Read the number (degree) for phi, in filename.
78 mPosition.set('s', 1.0f, theta / CSL_DEGS_PER_RAD, phi / CSL_DEGS_PER_RAD);
79 // logMsg("HRTF reading %g @ %g", theta, phi);
80
81 SoundFile hrirFile(filename); // open the HRIR file
82 hrirFile.openForRead(); // load HRIR file
83
84 if ( ! hrirFile.isValid()) { // check validity
85 logMsg("Cannot open sound file \"%s\"", filename);
86 throw IOError("Sound file open error");
87 } // Check file's #channels and #frames
88 if ((hrirFile.channels() != 2) || (hrirFile.duration() < HRIR_SIZE)) {
89 logMsg("Sound file \"%s\" is wrong format: %d ch, %d frames",
90 filename, hrirFile.channels(), hrirFile.duration());
91 throw IOError("Sound file open error");
92 }
93 // Load in HRIR file and convert it to HRTF buffers
94 for (unsigned i = 0; i < mNumFFTBlocks; i++) {
95 mInBuf.zeroBuffers(); // clear buffer (no zero-padding needed this way)
96 memcpy(mInBuf.buffer(0), // copy samples from file to buffer
97 (hrirFile.mWavetable.monoBuffer(0)) + (i * framesPerBlock),
98 (framesPerBlock * sizeof(sample)));
99 mOutBuf.setBuffer(0, (SampleBuffer) mHrtfL[i]);
100
101 fft.nextBuffer(mInBuf, mOutBuf); // execute Left FFT
102
103 mInBuf.zeroBuffers();
104 memcpy(mInBuf.buffer(0),
105 (hrirFile.mWavetable.monoBuffer(1)) + (i * framesPerBlock),
106 (framesPerBlock * sizeof(sample)));
107 mOutBuf.setBuffer(0, (SampleBuffer) mHrtfR[i]);
108
109 fft.nextBuffer(mInBuf, mOutBuf); // execute Right FFT
110 }
111 hrirFile.close(); // Close the file.
112 }
113
114 // destructor clears memory
115
116 HRTF::~HRTF() {
117 for (unsigned i = 0; i < mNumFFTBlocks; i++) {
118 SAFE_FREE(mHrtfL[i]);
119 SAFE_FREE(mHrtfR[i]);
120 }
121 SAFE_FREE(mHrtfR);
122 SAFE_FREE(mHrtfR);
123 }
124
125 // pretty print
126
127 void HRTF::dump() {
128 logMsg("HRTF with Azimuth: %f \t Elevation: %f",
129 mPosition.theta() * CSL_DEGS_PER_RAD,
130 mPosition.ele() * CSL_DEGS_PER_RAD);
131 }
132
133 // Answer the HRTF's storage size in Bytes
134
135 unsigned HRTF::size() {
136 return ((mNumFFTBlocks * 2 * (HRTF_BLOCK_SIZE + 1) * sizeof(SampleComplex))
137 + (mNumFFTBlocks * 2 * sizeof(SampleComplexVector)));
138 }
139
140 //////////////////////////////////////////////////////////////////////////////////////
141 /// HRTFDatabase
142 ///
143
144 // Static "Singleton" HRTF Database
145
146 HRTFDatabase * HRTFDatabase::mDatabase = 0;
147
148 // Static Methods
149
150 // Access the DB, initializing it lazily
151
152 HRTFDatabase* HRTFDatabase::Database() {
153 if (mDatabase == NULL) {
154 string folder(CGestalt::dataFolder());
155 folder += DEFAULT_HRTF_FOLDER;
156 mDatabase = new HRTFDatabase(folder.c_str());
157 }
158 return mDatabase;
159 }
160
161 // Flush the DB
162
163 void HRTFDatabase::Destroy() {
164 if (mDatabase) {
165 delete mDatabase;
166 mDatabase = NULL;
167 }
168 }
169
170 // constructor that takes an HRTF vector
171
172 //void HRTFDatabase::Reload(vector <HRTF *> hrtfs) {
173 // // create new DB
174 // HRTFDatabase * newDB = new HRTFDatabase(hrtfs);
175 // // be careful to avoid race conditions
176 // HRTFDatabase * oldDB = mDatabase;
177 // mDatabase = newDB; // set new DB
178 // if (oldDB)
179 // delete oldDB; // free old one
180 //}
181
182 // load a new folder into the DB
183
184 void HRTFDatabase::Reload(char * folder) {
185 // create new DB
186 HRTFDatabase * newDB = new HRTFDatabase(folder);
187 // be careful to avoid race conditions
188 HRTFDatabase * oldDB = mDatabase;
189 mDatabase = newDB; // set new DB
190 if (oldDB)
191 delete oldDB; // free old one
192 }
193
194 // HRTFDatabase Constructor (is private)
195
196 HRTFDatabase::HRTFDatabase(const char * folder) {
197 mWindowSize = 2 * HRTF_BLOCK_SIZE;
198 mHRTFLength = HRTF_BLOCK_SIZE ; // + 1;
199 mHRIRLength = HRIR_SIZE;
200
201 if (strcasestr(folder, ".dat") != NULL) { // if the name looks like a DB name
202 try {
203 loadFromDB(folder);
204 } catch (CException ex) { // handler: log error and exit the program.
205 logMsg(kLogError, "Loading the HRTFDatabase: %s\n", ex.mMessage.c_str());
206 exit(0);
207 }
208
209 } else if (folder[strlen(folder) - 1] == '/') { // if the name looks like a folder name
210 try {
211 char realFolder[CSL_NAME_LEN] = "";
212 if (folder[0] == '~') { // handle paths relative to "~"
213 strcpy(realFolder, getenv("HOME"));
214 if (strlen(folder) > 1)
215 strcat(realFolder, &folder[1]);
216 } else
217 strcpy(realFolder, folder);
218 // logMsg("Loading HRTF data from %s", realFolder);
219
220 this->loadFromFolder(realFolder); // load the folder
221
222 } catch (CException ex) { // handler: log error and exit the program.
223 logMsg(kLogError, "Loading the HRTFDatabase: %s\n", ex.mMessage.c_str());
224 exit(0);
225 }
226
227 } else { // if the name looks like the list file name
228 try {
229 // logMsg("Loading HRTF files from %s", folder);
230 loadFromFile(folder); // load the folder
231 } catch (CException ex) { // handler: log error and exit the program.
232 logMsg(kLogError, "Loading the HRTFDatabase: %s\n", ex.mMessage.c_str());
233 exit(0);
234 }
235 }
236 }
237
238 // HRTFDatabase::loadFromFolder: load an IRCAM-format HRTF database folder.
239 // This assumes there's a file named "files.txt" in the folder with a list of files.
240 // Create this with "ls IRC* > files"
241 // ToDo: use directory enumeration or popen("ls IRC*") for this
242
243 void HRTFDatabase::loadFromFolder (const char *folder) throw (CException) {
244 char filename[CSL_NAME_LEN];
245 strcpy(filename, folder); // Copy the path to the folder into the "filename" string
246 strcat(filename, FLIST_NAME); // Append the name of the file containing the list of hrtf files
247 this->loadFromFile(filename);
248 }
249
250 // Load HRTF data from the given file list
251
252 void HRTFDatabase::loadFromFile (const char *listname) throw (CException) {
253 char lineBuffer[CSL_NAME_LEN];
254 char dirname[CSL_NAME_LEN];
255 char filename[CSL_NAME_LEN];
256 FILE * listFile; // text file with the list of HRTF files in the directory
257 FFTWrapper fft(mWindowSize, CSL_FFT_COMPLEX); // create a raw-format forward FFT
258
259 listFile = fopen(listname, "r"); // Open the file that contains the list.
260 if ( ! listFile) {
261 logMsg("Cannot open list file %s for reading.\n", listname);
262 return;
263 }
264 strcpy(dirname, listname); // copy list file name to get directory name
265 char * ext = rindex(dirname, '/');
266 ext++;
267 *ext = 0;
268 while ( ! feof(listFile)) { // Go thru the file list
269 fgets(lineBuffer, 1024, listFile); // Read one full line
270 // logMsg("Read HRTF file %s", lineBuffer);
271 int len = strlen(lineBuffer) - 1;
272 if (len < 2)
273 continue;
274 if (lineBuffer[len] == '\n') // remove EOL from line
275 lineBuffer[len] = '\0';
276 strcpy(filename, dirname); // Copy the path to the files directory into filename
277 strcat(filename, lineBuffer); // Copy the name from the line in
278 // cout << " Read HRTF file " << filename << endl;
279
280 HRTF * tHRTF = new HRTF(filename, fft); // Create the HRTF from the file
281 mHRTFVector.push_back(tHRTF); // Add the HRTF to the vector.
282 }
283 fclose(listFile); // Close the list file.
284 //#endif
285 #ifdef CSL_DEBUG
286 dump();
287 #endif
288 }
289
290 // byte-swap the buffer
291
292 #ifdef IPHONE // byte-swap floats
293 void swapBuffer(float * buf, unsigned numFloats) {
294 float * ptr = buf;
295 for (unsigned b = 0; b < numFloats; b++) {
296 unsigned int val = (unsigned int) *ptr;
297 val = CFSwapInt32LittleToHost(val);
298 *ptr++ = (float) val;
299 }
300 }
301 #endif
302
303 // Load HRTF data from the given file list
304
305 void HRTFDatabase::loadFromDB (const char *dbName) throw (CException) {
306 char lineBuffer[CSL_NAME_LEN];
307 char tok[8];
308 char nam[16];
309 int nHRTFs, nBlocks, hrirLen, fftLen;
310 FILE * dbFile; // text file with the list of HRTF files in the directory
311 PointVector hrtfPoints;
312 int azim, elev;
313
314 dbFile = fopen(dbName, "r"); // Open the file that contains the list.
315 if ( ! dbFile) {
316 logMsg("Cannot open DB file %s for reading.\n", dbName);
317 return;
318 }
319 fgets(lineBuffer, 1024, dbFile); // Read magic # = "HRTF"
320 if (strncmp(lineBuffer, "HRTF", 4) != 0) {
321 logMsg("DB file %s wrong format.\n", dbName);
322 fclose(dbFile);
323 return;
324 } // read header line
325 int numFound = sscanf(lineBuffer, "%s\t%s\t%d\t%d\t%d\t%d",
326 tok, nam, & nHRTFs, & hrirLen, & fftLen, & nBlocks);
327 if (numFound != 6) {
328 logMsg("Line format: %s\n", lineBuffer);
329 fclose(dbFile);
330 return;
331 }
332 mWindowSize = 2 * fftLen; // set receiver's members from line
333 mHRTFLength = fftLen;
334 mHRIRLength = hrirLen;
335 if (nBlocks != numBlocks()) {
336 logMsg("Line format: %s\n", lineBuffer);
337 fclose(dbFile);
338 return;
339 }
340 fgets(lineBuffer, CSL_LINE_LEN, dbFile); // read the first geometry line
341 while(strlen(lineBuffer) > 1) { // loop through file to an empty line
342 // Read 2 ints from a line
343 if(sscanf(lineBuffer, "%d\t%d", & azim, & elev) != 2) {
344 logMsg("Line format: %s\n", lineBuffer);
345 fclose(dbFile);
346 return;
347 } // create a point
348 CPoint * cpt = new CPoint(kPolar, 1.0f, azim / CSL_DEGS_PER_RAD, elev / CSL_DEGS_PER_RAD);
349 // cpt->dumpPol(); // verbose list of points
350 hrtfPoints.push_back(cpt); // add pt to list
351 fgets(lineBuffer, CSL_LINE_LEN, dbFile); // read next line
352 } // end of loop; empty line read
353 // logMsg("Found %d positions (%d)", hrtfPoints.size(), nHRTFs);
354
355 if (hrtfPoints.size() != nHRTFs) {
356 logMsg("Found %d positions ( ! = %d)", hrtfPoints.size(), nHRTFs);
357 fclose(dbFile);
358 return;
359 }
360
361 int hdrSize = (int) ftell(dbFile); // start of data section
362 for (unsigned i = 0; i < nHRTFs; i++) { // loop over 180 HRTFs
363 HRTF * hrtf = new HRTF(); // Create an empty HRTF
364 hrtf->mPosition.set('s', 1.0f, // set its pos
365 hrtfPoints[i]->theta(),
366 hrtfPoints[i]->ele());
367 for (unsigned b = 0; b < nBlocks; b++) { // loop over 16 blocks
368 // read 2 complex buffers from file
369 size_t nRead = fread(hrtf->mHrtfL[b], sizeof(SampleComplex), mHRTFLength, dbFile);
370 if (nRead != mHRTFLength) {
371 logMsg(kLogError, "HRTF load read error %d\n", nRead);
372 perror("Error reading HRTF ");
373 throw IOError("Error reading HRTF");
374 }
375 nRead = fread(hrtf->mHrtfR[b], sizeof(SampleComplex), mHRTFLength, dbFile);
376 if (nRead != mHRTFLength) {
377 logMsg(kLogError, "HRTF load read error %d\n", nRead);
378 perror("Error reading HRTF ");
379 throw IOError("Error reading HRTF");
380 }
381 }
382 mHRTFVector.push_back(hrtf); // Add the HRTF to the vector.
383 }
384 int dataSize = (int) ftell(dbFile) - hdrSize; // end of file
385 fgets(lineBuffer, 1024, dbFile); // Read "HRTF" trailer from the file
386 if (strncmp(lineBuffer, "HRTF", 4) != 0)
387 logMsg("Error: Trailer format: %s\n", lineBuffer);
388 fclose(dbFile);
389 // printf("\nLoad HRTF DB \"%s\"\n\t%d HRTFs of %d blocks of %d-len complex arrays;\n\thdr = %d data = %5.2f\n",
390 // dbName, nHRTFs, nBlocks, fftLen, hdrSize, ((float) dataSize / 1000000.0f));
391 }
392
393 // copy constructor
394
395 //HRTFDatabase::HRTFDatabase(HRTFVector hrtfs) {
396 // mWindowSize = 2 * HRTF_BLOCK_SIZE;
397 // mHRTFLength = mWindowSize / 2 + 1;
398 // mHRIRLength = HRIR_SIZE;
399 // for (HRTFVector::iterator it = hrtfs.begin(); it != hrtfs.end(); it++)
400 // mHRTFVector.push_back(*it);
401 //}
402
403 // Prints the number of HRTFs in the database, and then calls dump() an each of them, printing their position.
404 // :: HRTF: 188 files = 24.7 MB (w: 1024 i: 8192 f: 511 b: 16)
405
406 void HRTFDatabase::dump(bool verbose) {
407 logMsg("HRTF: %d files = %4.1f MB (w: %d i: %d f: %d b: %d)",
408 numHRTFs(), ((float) size() / 1000000.0f),
409 windowSize(), hrirLength(), hrtfLength(), numBlocks());
410 if (verbose)
411 for (unsigned i = 0; i < numHRTFs(); i++)
412 mHRTFVector[i]->dump();
413 }
414
415 // Answer the HRTFDatabase's storage size in Bytes
416
417 unsigned HRTFDatabase::size() {
418 unsigned siz = 0;
419 for (unsigned i = 0; i < this->numHRTFs(); i++)
420 siz += mHRTFVector[i]->size();
421 return siz;
422 }
423
424 // the main HRTFDatabase accessor by index
425
426 HRTF * HRTFDatabase::hrtfAt(unsigned index) {
427 unsigned numHRTFs = this->numHRTFs();
428 if ( ! numHRTFs) { // empty HRTF
429 logMsg(kLogError, "HRTFDatabase::hrtfAt - empty data");
430 return 0;
431 }
432 return mHRTFVector[index];
433 }
434
435 // answer the index of the HRTF closest to the given source position by linear search
436
437 unsigned HRTFDatabase::hrtfAt(CPoint sourcePos) {
438 double tmpVal = 0;
439 double lowVal = 10000; // > than the largest reasonable distance
440 unsigned localHRTF = 0;
441 unsigned numHRTFs = this->numHRTFs();
442 if ( ! numHRTFs) { // empty HRTF
443 logMsg(kLogError, "HRTFDatabase::hrtfAt - empty data");
444 return 0;
445 }
446 CPoint sPt = sourcePos;
447 sPt.normalize(); // Make it a unit vector, so its at the same distance as the hrtfs
448 for (unsigned j = 0; j < numHRTFs - 1; j++) {
449 tmpVal = sPt.distance2(mHRTFVector[j]->mPosition); // Get the distance from one point to the other.
450 if (tmpVal < lowVal) {
451 lowVal = tmpVal;
452 localHRTF = j;
453 }
454 }
455 return localHRTF;
456 }
457
458 // Total number of HRTFs loaded into the database.
459
460 unsigned HRTFDatabase::numHRTFs() {
461 return mHRTFVector.size();
462 }
463
464 // The size of the analysis window (in samples).
465
466 unsigned HRTFDatabase::windowSize() {
467 return mWindowSize;
468 }
469
470 // The length (in samples) of the Transfer Function buffer.
471
472 unsigned HRTFDatabase::hrtfLength() {
473 return mHRTFLength;
474 }
475
476 // The length (in samples) of the impulse responses loaded.
477
478 unsigned HRTFDatabase::hrirLength() {
479 return mHRIRLength;
480 }
481
482 // The length (in blocks) of the impulse responses loaded.
483
484 unsigned HRTFDatabase::numBlocks() {
485 return mHRIRLength / (windowSize() / 2);
486 }
487
488 // dump the DB as a single binary file
489 // format is:
490 // a nul-term string with the label and geometry list,
491 // label is name #-hrtfs #-blocks blk-size
492 // e.g., HRTF 1047 188 16 513
493 // name list is in the same format as the files.txt list,
494 // followed by the blocks of complex, blocked HRTFs
495 // 16 blocks/set, each has 513 complex values for L and R
496 // = 8 * 2 * 513 * 16 = 131 kB / HRTF * 188 = 24.6 MB / DB
497
498 void HRTFDatabase::storeToDB(const char *filename, const char *sname) throw (CException) {
499 unsigned numBlocks = hrirLength() / (windowSize() / 2);
500 unsigned num2Store = numHRTFs(); // store all by default
501
502 FILE * store = fopen(filename, "w");
503 if ( ! store) {
504 printf("Error saving HRTF DB - cannot open file\n");
505 return;
506 }
507 fprintf(store, "HRTF %s\t%d\t%d\t%d\t%d\n", // write store header
508 sname, num2Store, hrirLength(), hrtfLength(), numBlocks);
509 // write store HRTF position list
510 for (unsigned j = 0; j < num2Store; j++) {
511 // for (unsigned j = 0; j < numHRTFs() /* num2Store */; j++) {
512 // if (mHRTFVector[j]->mPosition.ele() == 0)
513 fprintf(store, "%g\t%g\n",
514 mHRTFVector[j]->mPosition.theta() * CSL_DEGS_PER_RAD,
515 mHRTFVector[j]->mPosition.ele() * CSL_DEGS_PER_RAD);
516 }
517 fprintf(store, "\n"); // write a blank line to end list
518 int hdrSize = (int) ftell(store);
519 // write HRTF data
520 for (unsigned i = 0; i < num2Store; i++) { // loop over 180 HRTFs
521 // for (unsigned i = 0; i < numHRTFs() /* num2Store */; i++) { // loop over 180 HRTFs
522 // if (mHRTFVector[i]->mPosition.ele() == 0) { // store only elev = 0
523 HRTF * hrtf = mHRTFVector[i];
524 for (unsigned b = 0; b < numBlocks; b++) { // loop over 16 blocks
525 // write 2 complex buffers
526 fwrite(hrtf->mHrtfL[b], sizeof(SampleComplex), mHRTFLength, store);
527 fwrite(hrtf->mHrtfR[b], sizeof(SampleComplex), mHRTFLength, store);
528 }
529 fflush(store);
530 // }
531 }
532 int dataSize = (int) ftell(store) - hdrSize;
533 fprintf(store, "HRTF\n"); // write footer
534 fclose(store);
535 printf("Saved HRTF DB %s with %d HRTFs %d blocks of %d-len arrays;\n\thdr = %d B, data = %5.2f MB\n\n",
536 sname, num2Store, numBlocks, hrtfLength(), hdrSize, ((float) dataSize / 1000000.0f));
537 }
538
539 // bulk translation of IRCAM HRTFs to CSL-format block data files
540
541 void HRTFDatabase::convertDB(const char *listname) throw (CException) {
542 char lineBuffer[CSL_NAME_LEN];
543 char filename[CSL_NAME_LEN];
544 char tok[8];
545 FILE * listFile; // text file with the list of HRTF files in the directory
546
547 listFile = fopen(listname, "r"); // Open the file that contains the list.
548 if ( ! listFile) {
549 logMsg("Cannot open list file %s for reading.\n", listname);
550 return;
551 }
552 while ( ! feof(listFile)) { // Go thru the file list
553 fgets(lineBuffer, 1024, listFile); // Read one full line
554 int len = strlen(lineBuffer) - 1;
555 if (lineBuffer[len] == '\n') // remove EOL from line
556 lineBuffer[len] = '\0';
557 logMsg("Read HRTF folder %s", lineBuffer);
558 sprintf(filename, "%sIRCAM_HRTF/%s/",
559 CGestalt::dataFolder().c_str(), lineBuffer);
560
561 HRTFDatabase::Reload(filename); // Load the new data
562 logMsg("Loaded %d HRTF files = %4.1f MB",
563 HRTFDatabase::Database()->numHRTFs(),
564 ((float) HRTFDatabase::Database()->size() / 1000000.0f));
565
566 char * cpos = strstr(filename, "IRC_");
567 if (cpos) {
568 int index = atoi(cpos + 4);
569 sprintf(filename, "%sIRCAM_HRTF/HRTF_%d.dat",
570 CGestalt::dataFolder().c_str(), index); // CSL data folder location
571 sprintf(tok, "%d", index);
572 HRTFDatabase::Database()->storeToDB(filename, tok);
573 }
574 }
575 }
576
577 // Stale
578 //
579 //#ifdef IPHONE
580 // NSBundle * bundle = [NSBundle mainBundle];
581 // CFURLRef fileURL = (CFURLRef)[[NSURL fileURLWithPath:
582 // [bundle pathForResource: @"IRC_1047_R" ofType: @""]]
583 // retain];
584 // CFStringRef namestring = CFURLGetString (fileURL);
585 // char theName[CSL_NAME_LEN];
586 // Boolean aok = CFStringGetCString (namestring, theName, CSL_NAME_LEN, kCFStringEncodingMacRoman);
587 // logMsg("Loading HRTF files from %s", theName);
588 // NSArray * pathsArray =[[NSBundle mainBundle]
589 // pathsForResourcesOfType: @"wav"
590 // inDirectory: [NSString stringWithCString: HRTF_RESOURCE]];
591 // int pathCount = [pathsArray count];
592 // int i;
593 // NSString* presetPath = NULL;
594 // for(i = 0; i < pathCount; i++) {
595 // presetPath = [pathsArray objectAtIndex:i];
596 // aok = CFStringGetCString (presetPath, theName, CSL_NAME_LEN, kCFStringEncodingMacRoman);
597 // mHRTFVector.push_back(new HRTF(theName, fft)); //// Add the HRTF to the vector.
598 // }
599 //#else