CSL  5.2
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 
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 
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 
147 
148 // Static Methods
149 
150 // Access the DB, initializing it lazily
151 
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 
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 
461  return mHRTFVector.size();
462 }
463 
464 // The size of the analysis window (in samples).
465 
467  return mWindowSize;
468 }
469 
470 // The length (in samples) of the Transfer Function buffer.
471 
473  return mHRTFLength;
474 }
475 
476 // The length (in samples) of the impulse responses loaded.
477 
479  return mHRIRLength;
480 }
481 
482 // The length (in blocks) of the impulse responses loaded.
483 
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