Use a proper complex number types in makehrtf
[openal-soft.git] / utils / makehrtf.c
blobb51a8bd08a6e669c79bfe3554ea79707d274e31a
1 /*
2 * HRTF utility for producing and demonstrating the process of creating an
3 * OpenAL Soft compatible HRIR data set.
5 * Copyright (C) 2011-2017 Christopher Fitzgerald
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * --------------------------------------------------------------------------
25 * A big thanks goes out to all those whose work done in the field of
26 * binaural sound synthesis using measured HRTFs makes this utility and the
27 * OpenAL Soft implementation possible.
29 * The algorithm for diffuse-field equalization was adapted from the work
30 * done by Rio Emmanuel and Larcher Veronique of IRCAM and Bill Gardner of
31 * MIT Media Laboratory. It operates as follows:
33 * 1. Take the FFT of each HRIR and only keep the magnitude responses.
34 * 2. Calculate the diffuse-field power-average of all HRIRs weighted by
35 * their contribution to the total surface area covered by their
36 * measurement.
37 * 3. Take the diffuse-field average and limit its magnitude range.
38 * 4. Equalize the responses by using the inverse of the diffuse-field
39 * average.
40 * 5. Reconstruct the minimum-phase responses.
41 * 5. Zero the DC component.
42 * 6. IFFT the result and truncate to the desired-length minimum-phase FIR.
44 * The spherical head algorithm for calculating propagation delay was adapted
45 * from the paper:
47 * Modeling Interaural Time Difference Assuming a Spherical Head
48 * Joel David Miller
49 * Music 150, Musical Acoustics, Stanford University
50 * December 2, 2001
52 * The formulae for calculating the Kaiser window metrics are from the
53 * the textbook:
55 * Discrete-Time Signal Processing
56 * Alan V. Oppenheim and Ronald W. Schafer
57 * Prentice-Hall Signal Processing Series
58 * 1999
61 #include "config.h"
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <stdarg.h>
66 #include <string.h>
67 #include <limits.h>
68 #include <ctype.h>
69 #include <math.h>
70 #ifdef HAVE_STRINGS_H
71 #include <strings.h>
72 #endif
74 // Rely (if naively) on OpenAL's header for the types used for serialization.
75 #include "AL/al.h"
76 #include "AL/alext.h"
78 #ifndef M_PI
79 #define M_PI (3.14159265358979323846)
80 #endif
82 #ifndef HUGE_VAL
83 #define HUGE_VAL (1.0 / 0.0)
84 #endif
86 // The epsilon used to maintain signal stability.
87 #define EPSILON (1e-9)
89 // Constants for accessing the token reader's ring buffer.
90 #define TR_RING_BITS (16)
91 #define TR_RING_SIZE (1 << TR_RING_BITS)
92 #define TR_RING_MASK (TR_RING_SIZE - 1)
94 // The token reader's load interval in bytes.
95 #define TR_LOAD_SIZE (TR_RING_SIZE >> 2)
97 // The maximum identifier length used when processing the data set
98 // definition.
99 #define MAX_IDENT_LEN (16)
101 // The maximum path length used when processing filenames.
102 #define MAX_PATH_LEN (256)
104 // The limits for the sample 'rate' metric in the data set definition and for
105 // resampling.
106 #define MIN_RATE (32000)
107 #define MAX_RATE (96000)
109 // The limits for the HRIR 'points' metric in the data set definition.
110 #define MIN_POINTS (16)
111 #define MAX_POINTS (8192)
113 // The limits to the number of 'azimuths' listed in the data set definition.
114 #define MIN_EV_COUNT (5)
115 #define MAX_EV_COUNT (128)
117 // The limits for each of the 'azimuths' listed in the data set definition.
118 #define MIN_AZ_COUNT (1)
119 #define MAX_AZ_COUNT (128)
121 // The limits for the listener's head 'radius' in the data set definition.
122 #define MIN_RADIUS (0.05)
123 #define MAX_RADIUS (0.15)
125 // The limits for the 'distance' from source to listener in the definition
126 // file.
127 #define MIN_DISTANCE (0.5)
128 #define MAX_DISTANCE (2.5)
130 // The maximum number of channels that can be addressed for a WAVE file
131 // source listed in the data set definition.
132 #define MAX_WAVE_CHANNELS (65535)
134 // The limits to the byte size for a binary source listed in the definition
135 // file.
136 #define MIN_BIN_SIZE (2)
137 #define MAX_BIN_SIZE (4)
139 // The minimum number of significant bits for binary sources listed in the
140 // data set definition. The maximum is calculated from the byte size.
141 #define MIN_BIN_BITS (16)
143 // The limits to the number of significant bits for an ASCII source listed in
144 // the data set definition.
145 #define MIN_ASCII_BITS (16)
146 #define MAX_ASCII_BITS (32)
148 // The limits to the FFT window size override on the command line.
149 #define MIN_FFTSIZE (65536)
150 #define MAX_FFTSIZE (131072)
152 // The limits to the equalization range limit on the command line.
153 #define MIN_LIMIT (2.0)
154 #define MAX_LIMIT (120.0)
156 // The limits to the truncation window size on the command line.
157 #define MIN_TRUNCSIZE (16)
158 #define MAX_TRUNCSIZE (512)
160 // The limits to the custom head radius on the command line.
161 #define MIN_CUSTOM_RADIUS (0.05)
162 #define MAX_CUSTOM_RADIUS (0.15)
164 // The truncation window size must be a multiple of the below value to allow
165 // for vectorized convolution.
166 #define MOD_TRUNCSIZE (8)
168 // The defaults for the command line options.
169 #define DEFAULT_FFTSIZE (65536)
170 #define DEFAULT_EQUALIZE (1)
171 #define DEFAULT_SURFACE (1)
172 #define DEFAULT_LIMIT (24.0)
173 #define DEFAULT_TRUNCSIZE (32)
174 #define DEFAULT_HEAD_MODEL (HM_DATASET)
175 #define DEFAULT_CUSTOM_RADIUS (0.0)
177 // The four-character-codes for RIFF/RIFX WAVE file chunks.
178 #define FOURCC_RIFF (0x46464952) // 'RIFF'
179 #define FOURCC_RIFX (0x58464952) // 'RIFX'
180 #define FOURCC_WAVE (0x45564157) // 'WAVE'
181 #define FOURCC_FMT (0x20746D66) // 'fmt '
182 #define FOURCC_DATA (0x61746164) // 'data'
183 #define FOURCC_LIST (0x5453494C) // 'LIST'
184 #define FOURCC_WAVL (0x6C766177) // 'wavl'
185 #define FOURCC_SLNT (0x746E6C73) // 'slnt'
187 // The supported wave formats.
188 #define WAVE_FORMAT_PCM (0x0001)
189 #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
190 #define WAVE_FORMAT_EXTENSIBLE (0xFFFE)
192 // The maximum propagation delay value supported by OpenAL Soft.
193 #define MAX_HRTD (63.0)
195 // The OpenAL Soft HRTF format marker. It stands for minimum-phase head
196 // response protocol 01.
197 #define MHR_FORMAT ("MinPHR01")
199 #define MHR_FORMAT_EXPERIMENTAL ("MinPHRTEMPDONOTUSE")
201 // Sample and channel type enum values
202 typedef enum SampleTypeT {
203 ST_S16 = 0,
204 ST_S24 = 1
205 } SampleTypeT;
207 typedef enum ChannelTypeT {
208 CT_LEFTONLY = 0,
209 CT_LEFTRIGHT = 1
210 } ChannelTypeT;
212 // Byte order for the serialization routines.
213 typedef enum ByteOrderT {
214 BO_NONE,
215 BO_LITTLE,
216 BO_BIG
217 } ByteOrderT;
219 // Source format for the references listed in the data set definition.
220 typedef enum SourceFormatT {
221 SF_NONE,
222 SF_WAVE, // RIFF/RIFX WAVE file.
223 SF_BIN_LE, // Little-endian binary file.
224 SF_BIN_BE, // Big-endian binary file.
225 SF_ASCII // ASCII text file.
226 } SourceFormatT;
228 // Element types for the references listed in the data set definition.
229 typedef enum ElementTypeT {
230 ET_NONE,
231 ET_INT, // Integer elements.
232 ET_FP // Floating-point elements.
233 } ElementTypeT;
235 // Head model used for calculating the impulse delays.
236 typedef enum HeadModelT {
237 HM_NONE,
238 HM_DATASET, // Measure the onset from the dataset.
239 HM_SPHERE // Calculate the onset using a spherical head model.
240 } HeadModelT;
242 // Desired output format from the command line.
243 typedef enum OutputFormatT {
244 OF_NONE,
245 OF_MHR // OpenAL Soft MHR data set file.
246 } OutputFormatT;
248 // Unsigned integer type.
249 typedef unsigned int uint;
251 // Serialization types. The trailing digit indicates the number of bits.
252 typedef ALubyte uint8;
253 typedef ALint int32;
254 typedef ALuint uint32;
255 typedef ALuint64SOFT uint64;
257 // Token reader state for parsing the data set definition.
258 typedef struct TokenReaderT {
259 FILE *mFile;
260 const char *mName;
261 uint mLine;
262 uint mColumn;
263 char mRing[TR_RING_SIZE];
264 size_t mIn;
265 size_t mOut;
266 } TokenReaderT;
268 // Source reference state used when loading sources.
269 typedef struct SourceRefT {
270 SourceFormatT mFormat;
271 ElementTypeT mType;
272 uint mSize;
273 int mBits;
274 uint mChannel;
275 uint mSkip;
276 uint mOffset;
277 char mPath[MAX_PATH_LEN+1];
278 } SourceRefT;
280 // The HRIR metrics and data set used when loading, processing, and storing
281 // the resulting HRTF.
282 typedef struct HrirDataT {
283 uint mIrRate;
284 SampleTypeT mSampleType;
285 ChannelTypeT mChannelType;
286 uint mIrCount;
287 uint mIrSize;
288 uint mIrPoints;
289 uint mFftSize;
290 uint mEvCount;
291 uint mEvStart;
292 uint mAzCount[MAX_EV_COUNT];
293 uint mEvOffset[MAX_EV_COUNT];
294 double mRadius;
295 double mDistance;
296 double *mHrirs;
297 double *mHrtds;
298 double mMaxHrtd;
299 } HrirDataT;
301 // The resampler metrics and FIR filter.
302 typedef struct ResamplerT {
303 uint mP, mQ, mM, mL;
304 double *mF;
305 } ResamplerT;
308 /****************************************
309 *** Complex number type and routines ***
310 ****************************************/
312 typedef struct {
313 double Real, Imag;
314 } Complex;
316 static Complex MakeComplex(double r, double i)
318 Complex c = { r, i };
319 return c;
322 static Complex c_add(Complex a, Complex b)
324 Complex r;
325 r.Real = a.Real + b.Real;
326 r.Imag = a.Imag + b.Imag;
327 return r;
330 static Complex c_sub(Complex a, Complex b)
332 Complex r;
333 r.Real = a.Real - b.Real;
334 r.Imag = a.Imag - b.Imag;
335 return r;
338 static Complex c_mul(Complex a, Complex b)
340 Complex r;
341 r.Real = a.Real*b.Real - a.Imag*b.Imag;
342 r.Imag = a.Imag*b.Real + a.Real*b.Imag;
343 return r;
346 static double c_abs(Complex a)
348 return sqrt(a.Real*a.Real + a.Imag*a.Imag);
351 static Complex c_exp(Complex a)
353 Complex r;
354 double e = exp(a.Real);
355 r.Real = e * cos(a.Imag);
356 r.Imag = e * sin(a.Imag);
357 return r;
360 /*****************************
361 *** Token reader routines ***
362 *****************************/
364 /* Whitespace is not significant. It can process tokens as identifiers, numbers
365 * (integer and floating-point), strings, and operators. Strings must be
366 * encapsulated by double-quotes and cannot span multiple lines.
369 // Setup the reader on the given file. The filename can be NULL if no error
370 // output is desired.
371 static void TrSetup(FILE *fp, const char *filename, TokenReaderT *tr)
373 const char *name = NULL;
375 if(filename)
377 const char *slash = strrchr(filename, '/');
378 if(slash)
380 const char *bslash = strrchr(slash+1, '\\');
381 if(bslash) name = bslash+1;
382 else name = slash+1;
384 else
386 const char *bslash = strrchr(filename, '\\');
387 if(bslash) name = bslash+1;
388 else name = filename;
392 tr->mFile = fp;
393 tr->mName = name;
394 tr->mLine = 1;
395 tr->mColumn = 1;
396 tr->mIn = 0;
397 tr->mOut = 0;
400 // Prime the reader's ring buffer, and return a result indicating that there
401 // is text to process.
402 static int TrLoad(TokenReaderT *tr)
404 size_t toLoad, in, count;
406 toLoad = TR_RING_SIZE - (tr->mIn - tr->mOut);
407 if(toLoad >= TR_LOAD_SIZE && !feof(tr->mFile))
409 // Load TR_LOAD_SIZE (or less if at the end of the file) per read.
410 toLoad = TR_LOAD_SIZE;
411 in = tr->mIn&TR_RING_MASK;
412 count = TR_RING_SIZE - in;
413 if(count < toLoad)
415 tr->mIn += fread(&tr->mRing[in], 1, count, tr->mFile);
416 tr->mIn += fread(&tr->mRing[0], 1, toLoad-count, tr->mFile);
418 else
419 tr->mIn += fread(&tr->mRing[in], 1, toLoad, tr->mFile);
421 if(tr->mOut >= TR_RING_SIZE)
423 tr->mOut -= TR_RING_SIZE;
424 tr->mIn -= TR_RING_SIZE;
427 if(tr->mIn > tr->mOut)
428 return 1;
429 return 0;
432 // Error display routine. Only displays when the base name is not NULL.
433 static void TrErrorVA(const TokenReaderT *tr, uint line, uint column, const char *format, va_list argPtr)
435 if(!tr->mName)
436 return;
437 fprintf(stderr, "Error (%s:%u:%u): ", tr->mName, line, column);
438 vfprintf(stderr, format, argPtr);
441 // Used to display an error at a saved line/column.
442 static void TrErrorAt(const TokenReaderT *tr, uint line, uint column, const char *format, ...)
444 va_list argPtr;
446 va_start(argPtr, format);
447 TrErrorVA(tr, line, column, format, argPtr);
448 va_end(argPtr);
451 // Used to display an error at the current line/column.
452 static void TrError(const TokenReaderT *tr, const char *format, ...)
454 va_list argPtr;
456 va_start(argPtr, format);
457 TrErrorVA(tr, tr->mLine, tr->mColumn, format, argPtr);
458 va_end(argPtr);
461 // Skips to the next line.
462 static void TrSkipLine(TokenReaderT *tr)
464 char ch;
466 while(TrLoad(tr))
468 ch = tr->mRing[tr->mOut&TR_RING_MASK];
469 tr->mOut++;
470 if(ch == '\n')
472 tr->mLine++;
473 tr->mColumn = 1;
474 break;
476 tr->mColumn ++;
480 // Skips to the next token.
481 static int TrSkipWhitespace(TokenReaderT *tr)
483 char ch;
485 while(TrLoad(tr))
487 ch = tr->mRing[tr->mOut&TR_RING_MASK];
488 if(isspace(ch))
490 tr->mOut++;
491 if(ch == '\n')
493 tr->mLine++;
494 tr->mColumn = 1;
496 else
497 tr->mColumn++;
499 else if(ch == '#')
500 TrSkipLine(tr);
501 else
502 return 1;
504 return 0;
507 // Get the line and/or column of the next token (or the end of input).
508 static void TrIndication(TokenReaderT *tr, uint *line, uint *column)
510 TrSkipWhitespace(tr);
511 if(line) *line = tr->mLine;
512 if(column) *column = tr->mColumn;
515 // Checks to see if a token is the given operator. It does not display any
516 // errors and will not proceed to the next token.
517 static int TrIsOperator(TokenReaderT *tr, const char *op)
519 size_t out, len;
520 char ch;
522 if(!TrSkipWhitespace(tr))
523 return 0;
524 out = tr->mOut;
525 len = 0;
526 while(op[len] != '\0' && out < tr->mIn)
528 ch = tr->mRing[out&TR_RING_MASK];
529 if(ch != op[len]) break;
530 len++;
531 out++;
533 if(op[len] == '\0')
534 return 1;
535 return 0;
538 /* The TrRead*() routines obtain the value of a matching token type. They
539 * display type, form, and boundary errors and will proceed to the next
540 * token.
543 // Reads and validates an identifier token.
544 static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident)
546 uint col, len;
547 char ch;
549 col = tr->mColumn;
550 if(TrSkipWhitespace(tr))
552 col = tr->mColumn;
553 ch = tr->mRing[tr->mOut&TR_RING_MASK];
554 if(ch == '_' || isalpha(ch))
556 len = 0;
557 do {
558 if(len < maxLen)
559 ident[len] = ch;
560 len++;
561 tr->mOut++;
562 if(!TrLoad(tr))
563 break;
564 ch = tr->mRing[tr->mOut&TR_RING_MASK];
565 } while(ch == '_' || isdigit(ch) || isalpha(ch));
567 tr->mColumn += len;
568 if(len < maxLen)
570 ident[len] = '\0';
571 return 1;
573 TrErrorAt(tr, tr->mLine, col, "Identifier is too long.\n");
574 return 0;
577 TrErrorAt(tr, tr->mLine, col, "Expected an identifier.\n");
578 return 0;
581 // Reads and validates (including bounds) an integer token.
582 static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int *value)
584 uint col, digis, len;
585 char ch, temp[64+1];
587 col = tr->mColumn;
588 if(TrSkipWhitespace(tr))
590 col = tr->mColumn;
591 len = 0;
592 ch = tr->mRing[tr->mOut&TR_RING_MASK];
593 if(ch == '+' || ch == '-')
595 temp[len] = ch;
596 len++;
597 tr->mOut++;
599 digis = 0;
600 while(TrLoad(tr))
602 ch = tr->mRing[tr->mOut&TR_RING_MASK];
603 if(!isdigit(ch)) break;
604 if(len < 64)
605 temp[len] = ch;
606 len++;
607 digis++;
608 tr->mOut++;
610 tr->mColumn += len;
611 if(digis > 0 && ch != '.' && !isalpha(ch))
613 if(len > 64)
615 TrErrorAt(tr, tr->mLine, col, "Integer is too long.");
616 return 0;
618 temp[len] = '\0';
619 *value = strtol(temp, NULL, 10);
620 if(*value < loBound || *value > hiBound)
622 TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound);
623 return (0);
625 return (1);
628 TrErrorAt(tr, tr->mLine, col, "Expected an integer.\n");
629 return 0;
632 // Reads and validates (including bounds) a float token.
633 static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBound, double *value)
635 uint col, digis, len;
636 char ch, temp[64+1];
638 col = tr->mColumn;
639 if(TrSkipWhitespace(tr))
641 col = tr->mColumn;
642 len = 0;
643 ch = tr->mRing[tr->mOut&TR_RING_MASK];
644 if(ch == '+' || ch == '-')
646 temp[len] = ch;
647 len++;
648 tr->mOut++;
651 digis = 0;
652 while(TrLoad(tr))
654 ch = tr->mRing[tr->mOut&TR_RING_MASK];
655 if(!isdigit(ch)) break;
656 if(len < 64)
657 temp[len] = ch;
658 len++;
659 digis++;
660 tr->mOut++;
662 if(ch == '.')
664 if(len < 64)
665 temp[len] = ch;
666 len++;
667 tr->mOut++;
669 while(TrLoad(tr))
671 ch = tr->mRing[tr->mOut&TR_RING_MASK];
672 if(!isdigit(ch)) break;
673 if(len < 64)
674 temp[len] = ch;
675 len++;
676 digis++;
677 tr->mOut++;
679 if(digis > 0)
681 if(ch == 'E' || ch == 'e')
683 if(len < 64)
684 temp[len] = ch;
685 len++;
686 digis = 0;
687 tr->mOut++;
688 if(ch == '+' || ch == '-')
690 if(len < 64)
691 temp[len] = ch;
692 len++;
693 tr->mOut++;
695 while(TrLoad(tr))
697 ch = tr->mRing[tr->mOut&TR_RING_MASK];
698 if(!isdigit(ch)) break;
699 if(len < 64)
700 temp[len] = ch;
701 len++;
702 digis++;
703 tr->mOut++;
706 tr->mColumn += len;
707 if(digis > 0 && ch != '.' && !isalpha(ch))
709 if(len > 64)
711 TrErrorAt(tr, tr->mLine, col, "Float is too long.");
712 return 0;
714 temp[len] = '\0';
715 *value = strtod(temp, NULL);
716 if(*value < loBound || *value > hiBound)
718 TrErrorAt (tr, tr->mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound);
719 return 0;
721 return 1;
724 else
725 tr->mColumn += len;
727 TrErrorAt(tr, tr->mLine, col, "Expected a float.\n");
728 return 0;
731 // Reads and validates a string token.
732 static int TrReadString(TokenReaderT *tr, const uint maxLen, char *text)
734 uint col, len;
735 char ch;
737 col = tr->mColumn;
738 if(TrSkipWhitespace(tr))
740 col = tr->mColumn;
741 ch = tr->mRing[tr->mOut&TR_RING_MASK];
742 if(ch == '\"')
744 tr->mOut++;
745 len = 0;
746 while(TrLoad(tr))
748 ch = tr->mRing[tr->mOut&TR_RING_MASK];
749 tr->mOut++;
750 if(ch == '\"')
751 break;
752 if(ch == '\n')
754 TrErrorAt (tr, tr->mLine, col, "Unterminated string at end of line.\n");
755 return 0;
757 if(len < maxLen)
758 text[len] = ch;
759 len++;
761 if(ch != '\"')
763 tr->mColumn += 1 + len;
764 TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of input.\n");
765 return 0;
767 tr->mColumn += 2 + len;
768 if(len > maxLen)
770 TrErrorAt (tr, tr->mLine, col, "String is too long.\n");
771 return 0;
773 text[len] = '\0';
774 return 1;
777 TrErrorAt(tr, tr->mLine, col, "Expected a string.\n");
778 return 0;
781 // Reads and validates the given operator.
782 static int TrReadOperator(TokenReaderT *tr, const char *op)
784 uint col, len;
785 char ch;
787 col = tr->mColumn;
788 if(TrSkipWhitespace(tr))
790 col = tr->mColumn;
791 len = 0;
792 while(op[len] != '\0' && TrLoad(tr))
794 ch = tr->mRing[tr->mOut&TR_RING_MASK];
795 if(ch != op[len]) break;
796 len++;
797 tr->mOut++;
799 tr->mColumn += len;
800 if(op[len] == '\0')
801 return 1;
803 TrErrorAt(tr, tr->mLine, col, "Expected '%s' operator.\n", op);
804 return 0;
807 /* Performs a string substitution. Any case-insensitive occurrences of the
808 * pattern string are replaced with the replacement string. The result is
809 * truncated if necessary.
811 static int StrSubst(const char *in, const char *pat, const char *rep, const size_t maxLen, char *out)
813 size_t inLen, patLen, repLen;
814 size_t si, di;
815 int truncated;
817 inLen = strlen(in);
818 patLen = strlen(pat);
819 repLen = strlen(rep);
820 si = 0;
821 di = 0;
822 truncated = 0;
823 while(si < inLen && di < maxLen)
825 if(patLen <= inLen-si)
827 if(strncasecmp(&in[si], pat, patLen) == 0)
829 if(repLen > maxLen-di)
831 repLen = maxLen - di;
832 truncated = 1;
834 strncpy(&out[di], rep, repLen);
835 si += patLen;
836 di += repLen;
839 out[di] = in[si];
840 si++;
841 di++;
843 if(si < inLen)
844 truncated = 1;
845 out[di] = '\0';
846 return !truncated;
850 /*********************
851 *** Math routines ***
852 *********************/
854 // Provide missing math routines for MSVC versions < 1800 (Visual Studio 2013).
855 #if defined(_MSC_VER) && _MSC_VER < 1800
856 static double round(double val)
858 if(val < 0.0)
859 return ceil(val-0.5);
860 return floor(val+0.5);
863 static double fmin(double a, double b)
865 return (a<b) ? a : b;
868 static double fmax(double a, double b)
870 return (a>b) ? a : b;
872 #endif
874 // Simple clamp routine.
875 static double Clamp(const double val, const double lower, const double upper)
877 return fmin(fmax(val, lower), upper);
880 // Performs linear interpolation.
881 static double Lerp(const double a, const double b, const double f)
883 return a + (f * (b - a));
886 static inline uint dither_rng(uint *seed)
888 *seed = (*seed * 96314165) + 907633515;
889 return *seed;
892 // Performs a triangular probability density function dither. It assumes the
893 // input sample is already scaled.
894 static inline double TpdfDither(const double in, uint *seed)
896 static const double PRNG_SCALE = 1.0 / UINT_MAX;
897 uint prn0, prn1;
899 prn0 = dither_rng(seed);
900 prn1 = dither_rng(seed);
901 return round(in + (prn0*PRNG_SCALE - prn1*PRNG_SCALE));
904 // Allocates an array of doubles.
905 static double *CreateArray(size_t n)
907 double *a;
909 if(n == 0) n = 1;
910 a = calloc(n, sizeof(double));
911 if(a == NULL)
913 fprintf(stderr, "Error: Out of memory.\n");
914 exit(-1);
916 return a;
919 // Frees an array of doubles.
920 static void DestroyArray(double *a)
921 { free(a); }
923 /* Fast Fourier transform routines. The number of points must be a power of
924 * two. In-place operation is possible only if both the real and imaginary
925 * parts are in-place together.
928 // Performs bit-reversal ordering.
929 static void FftArrange(const uint n, const Complex *in, Complex *out)
931 uint rk, k, m;
933 if(in == out)
935 // Handle in-place arrangement.
936 rk = 0;
937 for(k = 0;k < n;k++)
939 if(rk > k)
941 Complex temp = in[rk];
942 out[rk] = in[k];
943 out[k] = temp;
945 m = n;
946 while(rk&(m >>= 1))
947 rk &= ~m;
948 rk |= m;
951 else
953 // Handle copy arrangement.
954 rk = 0;
955 for(k = 0;k < n;k++)
957 out[rk] = in[k];
958 m = n;
959 while(rk&(m >>= 1))
960 rk &= ~m;
961 rk |= m;
966 // Performs the summation.
967 static void FftSummation(const int n, const double s, Complex *cplx)
969 double pi;
970 int m, m2;
971 int i, k, mk;
973 pi = s * M_PI;
974 for(m = 1, m2 = 2;m < n; m <<= 1, m2 <<= 1)
976 // v = Complex (-2.0 * sin (0.5 * pi / m) * sin (0.5 * pi / m), -sin (pi / m))
977 double sm = sin(0.5 * pi / m);
978 Complex v = MakeComplex(-2.0*sm*sm, -sin(pi / m));
979 Complex w = MakeComplex(1.0, 0.0);
980 for(i = 0;i < m;i++)
982 for(k = i;k < n;k += m2)
984 Complex t;
985 mk = k + m;
986 t = c_mul(w, cplx[mk]);
987 cplx[mk] = c_sub(cplx[k], t);
988 cplx[k] = c_add(cplx[k], t);
990 w = c_add(w, c_mul(v, w));
995 // Performs a forward FFT.
996 static void FftForward(const uint n, const Complex *in, Complex *out)
998 FftArrange(n, in, out);
999 FftSummation(n, 1.0, out);
1002 // Performs an inverse FFT.
1003 static void FftInverse(const uint n, const Complex *in, Complex *out)
1005 double f;
1006 uint i;
1008 FftArrange(n, in, out);
1009 FftSummation(n, -1.0, out);
1010 f = 1.0 / n;
1011 for(i = 0;i < n;i++)
1013 out[i].Real *= f;
1014 out[i].Imag *= f;
1018 /* Calculate the complex helical sequence (or discrete-time analytical signal)
1019 * of the given input using the Hilbert transform. Given the natural logarithm
1020 * of a signal's magnitude response, the imaginary components can be used as
1021 * the angles for minimum-phase reconstruction.
1023 static void Hilbert(const uint n, const Complex *in, Complex *out)
1025 uint i;
1027 if(in == out)
1029 // Handle in-place operation.
1030 for(i = 0;i < n;i++)
1031 out[i].Imag = 0.0;
1033 else
1035 // Handle copy operation.
1036 for(i = 0;i < n;i++)
1038 out[i].Real = in[i].Real;
1039 out[i].Imag = 0.0;
1042 FftInverse(n, out, out);
1043 for(i = 1;i < (n+1)/2;i++)
1045 out[i].Real *= 2.0;
1046 out[i].Imag *= 2.0;
1048 /* Increment i if n is even. */
1049 i += (n&1)^1;
1050 for(;i < n;i++)
1052 out[i].Real = 0.0;
1053 out[i].Imag = 0.0;
1055 FftForward(n, out, out);
1058 /* Calculate the magnitude response of the given input. This is used in
1059 * place of phase decomposition, since the phase residuals are discarded for
1060 * minimum phase reconstruction. The mirrored half of the response is also
1061 * discarded.
1063 static void MagnitudeResponse(const uint n, const Complex *in, double *out)
1065 const uint m = 1 + (n / 2);
1066 uint i;
1067 for(i = 0;i < m;i++)
1068 out[i] = fmax(c_abs(in[i]), EPSILON);
1071 /* Apply a range limit (in dB) to the given magnitude response. This is used
1072 * to adjust the effects of the diffuse-field average on the equalization
1073 * process.
1075 static void LimitMagnitudeResponse(const uint n, const double limit, const double *in, double *out)
1077 const uint m = 1 + (n / 2);
1078 double halfLim;
1079 uint i, lower, upper;
1080 double ave;
1082 halfLim = limit / 2.0;
1083 // Convert the response to dB.
1084 for(i = 0;i < m;i++)
1085 out[i] = 20.0 * log10(in[i]);
1086 // Use six octaves to calculate the average magnitude of the signal.
1087 lower = ((uint)ceil(n / pow(2.0, 8.0))) - 1;
1088 upper = ((uint)floor(n / pow(2.0, 2.0))) - 1;
1089 ave = 0.0;
1090 for(i = lower;i <= upper;i++)
1091 ave += out[i];
1092 ave /= upper - lower + 1;
1093 // Keep the response within range of the average magnitude.
1094 for(i = 0;i < m;i++)
1095 out[i] = Clamp(out[i], ave - halfLim, ave + halfLim);
1096 // Convert the response back to linear magnitude.
1097 for(i = 0;i < m;i++)
1098 out[i] = pow(10.0, out[i] / 20.0);
1101 /* Reconstructs the minimum-phase component for the given magnitude response
1102 * of a signal. This is equivalent to phase recomposition, sans the missing
1103 * residuals (which were discarded). The mirrored half of the response is
1104 * reconstructed.
1106 static void MinimumPhase(const uint n, const double *in, Complex *out)
1108 const uint m = 1 + (n / 2);
1109 double *mags;
1110 uint i;
1112 mags = CreateArray(n);
1113 for(i = 0;i < m;i++)
1115 mags[i] = fmax(EPSILON, in[i]);
1116 out[i].Real = log(mags[i]);
1117 out[i].Imag = 0.0;
1119 for(;i < n;i++)
1121 mags[i] = mags[n - i];
1122 out[i] = out[n - i];
1124 Hilbert(n, out, out);
1125 // Remove any DC offset the filter has.
1126 mags[0] = EPSILON;
1127 for(i = 0;i < n;i++)
1129 Complex a = c_exp(MakeComplex(0.0, out[i].Imag));
1130 out[i] = c_mul(MakeComplex(mags[i], 0.0), a);
1132 DestroyArray(mags);
1136 /***************************
1137 *** Resampler functions ***
1138 ***************************/
1140 /* This is the normalized cardinal sine (sinc) function.
1142 * sinc(x) = { 1, x = 0
1143 * { sin(pi x) / (pi x), otherwise.
1145 static double Sinc(const double x)
1147 if(fabs(x) < EPSILON)
1148 return 1.0;
1149 return sin(M_PI * x) / (M_PI * x);
1152 /* The zero-order modified Bessel function of the first kind, used for the
1153 * Kaiser window.
1155 * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
1156 * = sum_{k=0}^inf ((x / 2)^k / k!)^2
1158 static double BesselI_0(const double x)
1160 double term, sum, x2, y, last_sum;
1161 int k;
1163 // Start at k=1 since k=0 is trivial.
1164 term = 1.0;
1165 sum = 1.0;
1166 x2 = x/2.0;
1167 k = 1;
1169 // Let the integration converge until the term of the sum is no longer
1170 // significant.
1171 do {
1172 y = x2 / k;
1173 k++;
1174 last_sum = sum;
1175 term *= y * y;
1176 sum += term;
1177 } while(sum != last_sum);
1178 return sum;
1181 /* Calculate a Kaiser window from the given beta value and a normalized k
1182 * [-1, 1].
1184 * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
1185 * { 0, elsewhere.
1187 * Where k can be calculated as:
1189 * k = i / l, where -l <= i <= l.
1191 * or:
1193 * k = 2 i / M - 1, where 0 <= i <= M.
1195 static double Kaiser(const double b, const double k)
1197 if(!(k >= -1.0 && k <= 1.0))
1198 return 0.0;
1199 return BesselI_0(b * sqrt(1.0 - k*k)) / BesselI_0(b);
1202 // Calculates the greatest common divisor of a and b.
1203 static uint Gcd(uint x, uint y)
1205 while(y > 0)
1207 uint z = y;
1208 y = x % y;
1209 x = z;
1211 return x;
1214 /* Calculates the size (order) of the Kaiser window. Rejection is in dB and
1215 * the transition width is normalized frequency (0.5 is nyquist).
1217 * M = { ceil((r - 7.95) / (2.285 2 pi f_t)), r > 21
1218 * { ceil(5.79 / 2 pi f_t), r <= 21.
1221 static uint CalcKaiserOrder(const double rejection, const double transition)
1223 double w_t = 2.0 * M_PI * transition;
1224 if(rejection > 21.0)
1225 return (uint)ceil((rejection - 7.95) / (2.285 * w_t));
1226 return (uint)ceil(5.79 / w_t);
1229 // Calculates the beta value of the Kaiser window. Rejection is in dB.
1230 static double CalcKaiserBeta(const double rejection)
1232 if(rejection > 50.0)
1233 return 0.1102 * (rejection - 8.7);
1234 if(rejection >= 21.0)
1235 return (0.5842 * pow(rejection - 21.0, 0.4)) +
1236 (0.07886 * (rejection - 21.0));
1237 return 0.0;
1240 /* Calculates a point on the Kaiser-windowed sinc filter for the given half-
1241 * width, beta, gain, and cutoff. The point is specified in non-normalized
1242 * samples, from 0 to M, where M = (2 l + 1).
1244 * w(k) 2 p f_t sinc(2 f_t x)
1246 * x -- centered sample index (i - l)
1247 * k -- normalized and centered window index (x / l)
1248 * w(k) -- window function (Kaiser)
1249 * p -- gain compensation factor when sampling
1250 * f_t -- normalized center frequency (or cutoff; 0.5 is nyquist)
1252 static double SincFilter(const int l, const double b, const double gain, const double cutoff, const int i)
1254 return Kaiser(b, (double)(i - l) / l) * 2.0 * gain * cutoff * Sinc(2.0 * cutoff * (i - l));
1257 /* This is a polyphase sinc-filtered resampler.
1259 * Upsample Downsample
1261 * p/q = 3/2 p/q = 3/5
1263 * M-+-+-+-> M-+-+-+->
1264 * -------------------+ ---------------------+
1265 * p s * f f f f|f| | p s * f f f f f |
1266 * | 0 * 0 0 0|0|0 | | 0 * 0 0 0 0|0| |
1267 * v 0 * 0 0|0|0 0 | v 0 * 0 0 0|0|0 |
1268 * s * f|f|f f f | s * f f|f|f f |
1269 * 0 * |0|0 0 0 0 | 0 * 0|0|0 0 0 |
1270 * --------+=+--------+ 0 * |0|0 0 0 0 |
1271 * d . d .|d|. d . d ----------+=+--------+
1272 * d . . . .|d|. . . .
1273 * q->
1274 * q-+-+-+->
1276 * P_f(i,j) = q i mod p + pj
1277 * P_s(i,j) = floor(q i / p) - j
1278 * d[i=0..N-1] = sum_{j=0}^{floor((M - 1) / p)} {
1279 * { f[P_f(i,j)] s[P_s(i,j)], P_f(i,j) < M
1280 * { 0, P_f(i,j) >= M. }
1283 // Calculate the resampling metrics and build the Kaiser-windowed sinc filter
1284 // that's used to cut frequencies above the destination nyquist.
1285 static void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRate)
1287 double cutoff, width, beta;
1288 uint gcd, l;
1289 int i;
1291 gcd = Gcd(srcRate, dstRate);
1292 rs->mP = dstRate / gcd;
1293 rs->mQ = srcRate / gcd;
1294 /* The cutoff is adjusted by half the transition width, so the transition
1295 * ends before the nyquist (0.5). Both are scaled by the downsampling
1296 * factor.
1298 if(rs->mP > rs->mQ)
1300 cutoff = 0.475 / rs->mP;
1301 width = 0.05 / rs->mP;
1303 else
1305 cutoff = 0.475 / rs->mQ;
1306 width = 0.05 / rs->mQ;
1308 // A rejection of -180 dB is used for the stop band. Round up when
1309 // calculating the left offset to avoid increasing the transition width.
1310 l = (CalcKaiserOrder(180.0, width)+1) / 2;
1311 beta = CalcKaiserBeta(180.0);
1312 rs->mM = l*2 + 1;
1313 rs->mL = l;
1314 rs->mF = CreateArray(rs->mM);
1315 for(i = 0;i < ((int)rs->mM);i++)
1316 rs->mF[i] = SincFilter((int)l, beta, rs->mP, cutoff, i);
1319 // Clean up after the resampler.
1320 static void ResamplerClear(ResamplerT *rs)
1322 DestroyArray(rs->mF);
1323 rs->mF = NULL;
1326 // Perform the upsample-filter-downsample resampling operation using a
1327 // polyphase filter implementation.
1328 static void ResamplerRun(ResamplerT *rs, const uint inN, const double *in, const uint outN, double *out)
1330 const uint p = rs->mP, q = rs->mQ, m = rs->mM, l = rs->mL;
1331 const double *f = rs->mF;
1332 uint j_f, j_s;
1333 double *work;
1334 uint i;
1336 if(outN == 0)
1337 return;
1339 // Handle in-place operation.
1340 if(in == out)
1341 work = CreateArray(outN);
1342 else
1343 work = out;
1344 // Resample the input.
1345 for(i = 0;i < outN;i++)
1347 double r = 0.0;
1348 // Input starts at l to compensate for the filter delay. This will
1349 // drop any build-up from the first half of the filter.
1350 j_f = (l + (q * i)) % p;
1351 j_s = (l + (q * i)) / p;
1352 while(j_f < m)
1354 // Only take input when 0 <= j_s < inN. This single unsigned
1355 // comparison catches both cases.
1356 if(j_s < inN)
1357 r += f[j_f] * in[j_s];
1358 j_f += p;
1359 j_s--;
1361 work[i] = r;
1363 // Clean up after in-place operation.
1364 if(in == out)
1366 for(i = 0;i < outN;i++)
1367 out[i] = work[i];
1368 DestroyArray(work);
1372 /*************************
1373 *** File source input ***
1374 *************************/
1376 // Read a binary value of the specified byte order and byte size from a file,
1377 // storing it as a 32-bit unsigned integer.
1378 static int ReadBin4(FILE *fp, const char *filename, const ByteOrderT order, const uint bytes, uint32 *out)
1380 uint8 in[4];
1381 uint32 accum;
1382 uint i;
1384 if(fread(in, 1, bytes, fp) != bytes)
1386 fprintf(stderr, "Error: Bad read from file '%s'.\n", filename);
1387 return 0;
1389 accum = 0;
1390 switch(order)
1392 case BO_LITTLE:
1393 for(i = 0;i < bytes;i++)
1394 accum = (accum<<8) | in[bytes - i - 1];
1395 break;
1396 case BO_BIG:
1397 for(i = 0;i < bytes;i++)
1398 accum = (accum<<8) | in[i];
1399 break;
1400 default:
1401 break;
1403 *out = accum;
1404 return 1;
1407 // Read a binary value of the specified byte order from a file, storing it as
1408 // a 64-bit unsigned integer.
1409 static int ReadBin8(FILE *fp, const char *filename, const ByteOrderT order, uint64 *out)
1411 uint8 in [8];
1412 uint64 accum;
1413 uint i;
1415 if(fread(in, 1, 8, fp) != 8)
1417 fprintf(stderr, "Error: Bad read from file '%s'.\n", filename);
1418 return 0;
1420 accum = 0ULL;
1421 switch(order)
1423 case BO_LITTLE:
1424 for(i = 0;i < 8;i++)
1425 accum = (accum<<8) | in[8 - i - 1];
1426 break;
1427 case BO_BIG:
1428 for(i = 0;i < 8;i++)
1429 accum = (accum<<8) | in[i];
1430 break;
1431 default:
1432 break;
1434 *out = accum;
1435 return 1;
1438 /* Read a binary value of the specified type, byte order, and byte size from
1439 * a file, converting it to a double. For integer types, the significant
1440 * bits are used to normalize the result. The sign of bits determines
1441 * whether they are padded toward the MSB (negative) or LSB (positive).
1442 * Floating-point types are not normalized.
1444 static int ReadBinAsDouble(FILE *fp, const char *filename, const ByteOrderT order, const ElementTypeT type, const uint bytes, const int bits, double *out)
1446 union {
1447 uint32 ui;
1448 int32 i;
1449 float f;
1450 } v4;
1451 union {
1452 uint64 ui;
1453 double f;
1454 } v8;
1456 *out = 0.0;
1457 if(bytes > 4)
1459 if(!ReadBin8(fp, filename, order, &v8.ui))
1460 return 0;
1461 if(type == ET_FP)
1462 *out = v8.f;
1464 else
1466 if(!ReadBin4(fp, filename, order, bytes, &v4.ui))
1467 return 0;
1468 if(type == ET_FP)
1469 *out = v4.f;
1470 else
1472 if(bits > 0)
1473 v4.ui >>= (8*bytes) - ((uint)bits);
1474 else
1475 v4.ui &= (0xFFFFFFFF >> (32+bits));
1477 if(v4.ui&(uint)(1<<(abs(bits)-1)))
1478 v4.ui |= (0xFFFFFFFF << abs (bits));
1479 *out = v4.i / (double)(1<<(abs(bits)-1));
1482 return 1;
1485 /* Read an ascii value of the specified type from a file, converting it to a
1486 * double. For integer types, the significant bits are used to normalize the
1487 * result. The sign of the bits should always be positive. This also skips
1488 * up to one separator character before the element itself.
1490 static int ReadAsciiAsDouble(TokenReaderT *tr, const char *filename, const ElementTypeT type, const uint bits, double *out)
1492 if(TrIsOperator(tr, ","))
1493 TrReadOperator(tr, ",");
1494 else if(TrIsOperator(tr, ":"))
1495 TrReadOperator(tr, ":");
1496 else if(TrIsOperator(tr, ";"))
1497 TrReadOperator(tr, ";");
1498 else if(TrIsOperator(tr, "|"))
1499 TrReadOperator(tr, "|");
1501 if(type == ET_FP)
1503 if(!TrReadFloat(tr, -HUGE_VAL, HUGE_VAL, out))
1505 fprintf(stderr, "Error: Bad read from file '%s'.\n", filename);
1506 return 0;
1509 else
1511 int v;
1512 if(!TrReadInt(tr, -(1<<(bits-1)), (1<<(bits-1))-1, &v))
1514 fprintf(stderr, "Error: Bad read from file '%s'.\n", filename);
1515 return 0;
1517 *out = v / (double)((1<<(bits-1))-1);
1519 return 1;
1522 // Read the RIFF/RIFX WAVE format chunk from a file, validating it against
1523 // the source parameters and data set metrics.
1524 static int ReadWaveFormat(FILE *fp, const ByteOrderT order, const uint hrirRate, SourceRefT *src)
1526 uint32 fourCC, chunkSize;
1527 uint32 format, channels, rate, dummy, block, size, bits;
1529 chunkSize = 0;
1530 do {
1531 if (chunkSize > 0)
1532 fseek (fp, (long) chunkSize, SEEK_CUR);
1533 if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) ||
1534 !ReadBin4(fp, src->mPath, order, 4, &chunkSize))
1535 return 0;
1536 } while(fourCC != FOURCC_FMT);
1537 if(!ReadBin4(fp, src->mPath, order, 2, & format) ||
1538 !ReadBin4(fp, src->mPath, order, 2, & channels) ||
1539 !ReadBin4(fp, src->mPath, order, 4, & rate) ||
1540 !ReadBin4(fp, src->mPath, order, 4, & dummy) ||
1541 !ReadBin4(fp, src->mPath, order, 2, & block))
1542 return (0);
1543 block /= channels;
1544 if(chunkSize > 14)
1546 if(!ReadBin4(fp, src->mPath, order, 2, &size))
1547 return 0;
1548 size /= 8;
1549 if(block > size)
1550 size = block;
1552 else
1553 size = block;
1554 if(format == WAVE_FORMAT_EXTENSIBLE)
1556 fseek(fp, 2, SEEK_CUR);
1557 if(!ReadBin4(fp, src->mPath, order, 2, &bits))
1558 return 0;
1559 if(bits == 0)
1560 bits = 8 * size;
1561 fseek(fp, 4, SEEK_CUR);
1562 if(!ReadBin4(fp, src->mPath, order, 2, &format))
1563 return 0;
1564 fseek(fp, (long)(chunkSize - 26), SEEK_CUR);
1566 else
1568 bits = 8 * size;
1569 if(chunkSize > 14)
1570 fseek(fp, (long)(chunkSize - 16), SEEK_CUR);
1571 else
1572 fseek(fp, (long)(chunkSize - 14), SEEK_CUR);
1574 if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT)
1576 fprintf(stderr, "Error: Unsupported WAVE format in file '%s'.\n", src->mPath);
1577 return 0;
1579 if(src->mChannel >= channels)
1581 fprintf(stderr, "Error: Missing source channel in WAVE file '%s'.\n", src->mPath);
1582 return 0;
1584 if(rate != hrirRate)
1586 fprintf(stderr, "Error: Mismatched source sample rate in WAVE file '%s'.\n", src->mPath);
1587 return 0;
1589 if(format == WAVE_FORMAT_PCM)
1591 if(size < 2 || size > 4)
1593 fprintf(stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
1594 return 0;
1596 if(bits < 16 || bits > (8*size))
1598 fprintf (stderr, "Error: Bad significant bits in WAVE file '%s'.\n", src->mPath);
1599 return 0;
1601 src->mType = ET_INT;
1603 else
1605 if(size != 4 && size != 8)
1607 fprintf(stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
1608 return 0;
1610 src->mType = ET_FP;
1612 src->mSize = size;
1613 src->mBits = (int)bits;
1614 src->mSkip = channels;
1615 return 1;
1618 // Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles.
1619 static int ReadWaveData(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir)
1621 int pre, post, skip;
1622 uint i;
1624 pre = (int)(src->mSize * src->mChannel);
1625 post = (int)(src->mSize * (src->mSkip - src->mChannel - 1));
1626 skip = 0;
1627 for(i = 0;i < n;i++)
1629 skip += pre;
1630 if(skip > 0)
1631 fseek(fp, skip, SEEK_CUR);
1632 if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
1633 return 0;
1634 skip = post;
1636 if(skip > 0)
1637 fseek(fp, skip, SEEK_CUR);
1638 return 1;
1641 // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to
1642 // doubles.
1643 static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir)
1645 uint32 fourCC, chunkSize, listSize, count;
1646 uint block, skip, offset, i;
1647 double lastSample;
1649 for (;;) {
1650 if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, & fourCC) ||
1651 !ReadBin4(fp, src->mPath, order, 4, & chunkSize))
1652 return (0);
1654 if(fourCC == FOURCC_DATA)
1656 block = src->mSize * src->mSkip;
1657 count = chunkSize / block;
1658 if(count < (src->mOffset + n))
1660 fprintf(stderr, "Error: Bad read from file '%s'.\n", src->mPath);
1661 return 0;
1663 fseek(fp, (long)(src->mOffset * block), SEEK_CUR);
1664 if(!ReadWaveData(fp, src, order, n, &hrir[0]))
1665 return 0;
1666 return 1;
1668 else if(fourCC == FOURCC_LIST)
1670 if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC))
1671 return 0;
1672 chunkSize -= 4;
1673 if(fourCC == FOURCC_WAVL)
1674 break;
1676 if(chunkSize > 0)
1677 fseek(fp, (long)chunkSize, SEEK_CUR);
1679 listSize = chunkSize;
1680 block = src->mSize * src->mSkip;
1681 skip = src->mOffset;
1682 offset = 0;
1683 lastSample = 0.0;
1684 while(offset < n && listSize > 8)
1686 if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) ||
1687 !ReadBin4(fp, src->mPath, order, 4, &chunkSize))
1688 return 0;
1689 listSize -= 8 + chunkSize;
1690 if(fourCC == FOURCC_DATA)
1692 count = chunkSize / block;
1693 if(count > skip)
1695 fseek(fp, (long)(skip * block), SEEK_CUR);
1696 chunkSize -= skip * block;
1697 count -= skip;
1698 skip = 0;
1699 if(count > (n - offset))
1700 count = n - offset;
1701 if(!ReadWaveData(fp, src, order, count, &hrir[offset]))
1702 return 0;
1703 chunkSize -= count * block;
1704 offset += count;
1705 lastSample = hrir [offset - 1];
1707 else
1709 skip -= count;
1710 count = 0;
1713 else if(fourCC == FOURCC_SLNT)
1715 if(!ReadBin4(fp, src->mPath, order, 4, &count))
1716 return 0;
1717 chunkSize -= 4;
1718 if(count > skip)
1720 count -= skip;
1721 skip = 0;
1722 if(count > (n - offset))
1723 count = n - offset;
1724 for(i = 0; i < count; i ++)
1725 hrir[offset + i] = lastSample;
1726 offset += count;
1728 else
1730 skip -= count;
1731 count = 0;
1734 if(chunkSize > 0)
1735 fseek(fp, (long)chunkSize, SEEK_CUR);
1737 if(offset < n)
1739 fprintf(stderr, "Error: Bad read from file '%s'.\n", src->mPath);
1740 return 0;
1742 return 1;
1745 // Load a source HRIR from a RIFF/RIFX WAVE file.
1746 static int LoadWaveSource(FILE *fp, SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1748 uint32 fourCC, dummy;
1749 ByteOrderT order;
1751 if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) ||
1752 !ReadBin4(fp, src->mPath, BO_LITTLE, 4, &dummy))
1753 return 0;
1754 if(fourCC == FOURCC_RIFF)
1755 order = BO_LITTLE;
1756 else if(fourCC == FOURCC_RIFX)
1757 order = BO_BIG;
1758 else
1760 fprintf(stderr, "Error: No RIFF/RIFX chunk in file '%s'.\n", src->mPath);
1761 return 0;
1764 if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC))
1765 return 0;
1766 if(fourCC != FOURCC_WAVE)
1768 fprintf(stderr, "Error: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath);
1769 return 0;
1771 if(!ReadWaveFormat(fp, order, hrirRate, src))
1772 return 0;
1773 if(!ReadWaveList(fp, src, order, n, hrir))
1774 return 0;
1775 return 1;
1778 // Load a source HRIR from a binary file.
1779 static int LoadBinarySource(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir)
1781 uint i;
1783 fseek(fp, (long)src->mOffset, SEEK_SET);
1784 for(i = 0;i < n;i++)
1786 if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
1787 return 0;
1788 if(src->mSkip > 0)
1789 fseek(fp, (long)src->mSkip, SEEK_CUR);
1791 return 1;
1794 // Load a source HRIR from an ASCII text file containing a list of elements
1795 // separated by whitespace or common list operators (',', ';', ':', '|').
1796 static int LoadAsciiSource(FILE *fp, const SourceRefT *src, const uint n, double *hrir)
1798 TokenReaderT tr;
1799 uint i, j;
1800 double dummy;
1802 TrSetup(fp, NULL, &tr);
1803 for(i = 0;i < src->mOffset;i++)
1805 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &dummy))
1806 return (0);
1808 for(i = 0;i < n;i++)
1810 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &hrir[i]))
1811 return 0;
1812 for(j = 0;j < src->mSkip;j++)
1814 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &dummy))
1815 return 0;
1818 return 1;
1821 // Load a source HRIR from a supported file type.
1822 static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1824 int result;
1825 FILE *fp;
1827 if (src->mFormat == SF_ASCII)
1828 fp = fopen(src->mPath, "r");
1829 else
1830 fp = fopen(src->mPath, "rb");
1831 if(fp == NULL)
1833 fprintf(stderr, "Error: Could not open source file '%s'.\n", src->mPath);
1834 return 0;
1836 if(src->mFormat == SF_WAVE)
1837 result = LoadWaveSource(fp, src, hrirRate, n, hrir);
1838 else if(src->mFormat == SF_BIN_LE)
1839 result = LoadBinarySource(fp, src, BO_LITTLE, n, hrir);
1840 else if(src->mFormat == SF_BIN_BE)
1841 result = LoadBinarySource(fp, src, BO_BIG, n, hrir);
1842 else
1843 result = LoadAsciiSource(fp, src, n, hrir);
1844 fclose(fp);
1845 return result;
1849 /***************************
1850 *** File storage output ***
1851 ***************************/
1853 // Write an ASCII string to a file.
1854 static int WriteAscii(const char *out, FILE *fp, const char *filename)
1856 size_t len;
1858 len = strlen(out);
1859 if(fwrite(out, 1, len, fp) != len)
1861 fclose(fp);
1862 fprintf(stderr, "Error: Bad write to file '%s'.\n", filename);
1863 return 0;
1865 return 1;
1868 // Write a binary value of the given byte order and byte size to a file,
1869 // loading it from a 32-bit unsigned integer.
1870 static int WriteBin4(const ByteOrderT order, const uint bytes, const uint32 in, FILE *fp, const char *filename)
1872 uint8 out[4];
1873 uint i;
1875 switch(order)
1877 case BO_LITTLE:
1878 for(i = 0;i < bytes;i++)
1879 out[i] = (in>>(i*8)) & 0x000000FF;
1880 break;
1881 case BO_BIG:
1882 for(i = 0;i < bytes;i++)
1883 out[bytes - i - 1] = (in>>(i*8)) & 0x000000FF;
1884 break;
1885 default:
1886 break;
1888 if(fwrite(out, 1, bytes, fp) != bytes)
1890 fprintf(stderr, "Error: Bad write to file '%s'.\n", filename);
1891 return 0;
1893 return 1;
1896 // Store the OpenAL Soft HRTF data set.
1897 static int StoreMhr(const HrirDataT *hData, const int experimental, const char *filename)
1899 uint e, step, end, n, j, i;
1900 uint dither_seed;
1901 FILE *fp;
1902 int v;
1904 if((fp=fopen(filename, "wb")) == NULL)
1906 fprintf(stderr, "Error: Could not open MHR file '%s'.\n", filename);
1907 return 0;
1909 if(!WriteAscii(experimental ? MHR_FORMAT_EXPERIMENTAL : MHR_FORMAT, fp, filename))
1910 return 0;
1911 if(!WriteBin4(BO_LITTLE, 4, (uint32)hData->mIrRate, fp, filename))
1912 return 0;
1913 if(experimental)
1915 if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mSampleType, fp, filename))
1916 return 0;
1917 if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mChannelType, fp, filename))
1918 return 0;
1920 if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mIrPoints, fp, filename))
1921 return 0;
1922 if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mEvCount, fp, filename))
1923 return 0;
1924 for(e = 0;e < hData->mEvCount;e++)
1926 if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mAzCount[e], fp, filename))
1927 return 0;
1929 step = hData->mIrSize;
1930 end = hData->mIrCount * step;
1931 n = hData->mIrPoints;
1932 dither_seed = 22222;
1933 for(j = 0;j < end;j += step)
1935 const double scale = (!experimental || hData->mSampleType == ST_S16) ? 32767.0 :
1936 ((hData->mSampleType == ST_S24) ? 8388607.0 : 0.0);
1937 const int bps = (!experimental || hData->mSampleType == ST_S16) ? 2 :
1938 ((hData->mSampleType == ST_S24) ? 3 : 0);
1939 double out[MAX_TRUNCSIZE];
1940 for(i = 0;i < n;i++)
1941 out[i] = TpdfDither(scale * hData->mHrirs[j+i], &dither_seed);
1942 for(i = 0;i < n;i++)
1944 v = (int)Clamp(out[i], -scale-1.0, scale);
1945 if(!WriteBin4(BO_LITTLE, bps, (uint32)v, fp, filename))
1946 return 0;
1949 for(j = 0;j < hData->mIrCount;j++)
1951 v = (int)fmin(round(hData->mIrRate * hData->mHrtds[j]), MAX_HRTD);
1952 if(!WriteBin4(BO_LITTLE, 1, (uint32)v, fp, filename))
1953 return 0;
1955 fclose(fp);
1956 return 1;
1960 /***********************
1961 *** HRTF processing ***
1962 ***********************/
1964 // Calculate the onset time of an HRIR and average it with any existing
1965 // timing for its elevation and azimuth.
1966 static void AverageHrirOnset(const double *hrir, const double f, const uint ei, const uint ai, const HrirDataT *hData)
1968 double mag;
1969 uint n, i, j;
1971 mag = 0.0;
1972 n = hData->mIrPoints;
1973 for(i = 0;i < n;i++)
1974 mag = fmax(fabs(hrir[i]), mag);
1975 mag *= 0.15;
1976 for(i = 0;i < n;i++)
1978 if(fabs(hrir[i]) >= mag)
1979 break;
1981 j = hData->mEvOffset[ei] + ai;
1982 hData->mHrtds[j] = Lerp(hData->mHrtds[j], ((double)i) / hData->mIrRate, f);
1985 // Calculate the magnitude response of an HRIR and average it with any
1986 // existing responses for its elevation and azimuth.
1987 static void AverageHrirMagnitude(const double *hrir, const double f, const uint ei, const uint ai, const HrirDataT *hData)
1989 uint n, m, i, j;
1990 Complex *cplx;
1991 double *mags;
1993 n = hData->mFftSize;
1994 cplx = calloc(sizeof(*cplx), n);
1995 mags = calloc(sizeof(*mags), n);
1996 for(i = 0;i < hData->mIrPoints;i++)
1997 cplx[i] = MakeComplex(hrir[i], 0.0);
1998 for(;i < n;i++)
1999 cplx[i] = MakeComplex(0.0, 0.0);
2000 FftForward(n, cplx, cplx);
2001 MagnitudeResponse(n, cplx, mags);
2002 m = 1 + (n / 2);
2003 j = (hData->mEvOffset[ei] + ai) * hData->mIrSize;
2004 for(i = 0;i < m;i++)
2005 hData->mHrirs[j+i] = Lerp(hData->mHrirs[j+i], mags[i], f);
2006 free(mags);
2007 free(cplx);
2010 /* Calculate the contribution of each HRIR to the diffuse-field average based
2011 * on the area of its surface patch. All patches are centered at the HRIR
2012 * coordinates on the unit sphere and are measured by solid angle.
2014 static void CalculateDfWeights(const HrirDataT *hData, double *weights)
2016 double evs, sum, ev, up_ev, down_ev, solidAngle;
2017 uint ei;
2019 evs = 90.0 / (hData->mEvCount - 1);
2020 sum = 0.0;
2021 for(ei = hData->mEvStart;ei < hData->mEvCount;ei++)
2023 // For each elevation, calculate the upper and lower limits of the
2024 // patch band.
2025 ev = -90.0 + (ei * 2.0 * evs);
2026 if(ei < (hData->mEvCount - 1))
2027 up_ev = (ev + evs) * M_PI / 180.0;
2028 else
2029 up_ev = M_PI / 2.0;
2030 if(ei > 0)
2031 down_ev = (ev - evs) * M_PI / 180.0;
2032 else
2033 down_ev = -M_PI / 2.0;
2034 // Calculate the area of the patch band.
2035 solidAngle = 2.0 * M_PI * (sin(up_ev) - sin(down_ev));
2036 // Each weight is the area of one patch.
2037 weights[ei] = solidAngle / hData->mAzCount [ei];
2038 // Sum the total surface area covered by the HRIRs.
2039 sum += solidAngle;
2041 // Normalize the weights given the total surface coverage.
2042 for(ei = hData->mEvStart;ei < hData->mEvCount;ei++)
2043 weights[ei] /= sum;
2046 /* Calculate the diffuse-field average from the given magnitude responses of
2047 * the HRIR set. Weighting can be applied to compensate for the varying
2048 * surface area covered by each HRIR. The final average can then be limited
2049 * by the specified magnitude range (in positive dB; 0.0 to skip).
2051 static void CalculateDiffuseFieldAverage(const HrirDataT *hData, const int weighted, const double limit, double *dfa)
2053 uint ei, ai, count, step, start, end, m, j, i;
2054 double *weights;
2056 weights = CreateArray(hData->mEvCount);
2057 if(weighted)
2059 // Use coverage weighting to calculate the average.
2060 CalculateDfWeights(hData, weights);
2062 else
2064 // If coverage weighting is not used, the weights still need to be
2065 // averaged by the number of HRIRs.
2066 count = 0;
2067 for(ei = hData->mEvStart;ei < hData->mEvCount;ei++)
2068 count += hData->mAzCount [ei];
2069 for(ei = hData->mEvStart;ei < hData->mEvCount;ei++)
2070 weights[ei] = 1.0 / count;
2072 ei = hData->mEvStart;
2073 ai = 0;
2074 step = hData->mIrSize;
2075 start = hData->mEvOffset[ei] * step;
2076 end = hData->mIrCount * step;
2077 m = 1 + (hData->mFftSize / 2);
2078 for(i = 0;i < m;i++)
2079 dfa[i] = 0.0;
2080 for(j = start;j < end;j += step)
2082 // Get the weight for this HRIR's contribution.
2083 double weight = weights[ei];
2084 // Add this HRIR's weighted power average to the total.
2085 for(i = 0;i < m;i++)
2086 dfa[i] += weight * hData->mHrirs[j+i] * hData->mHrirs[j+i];
2087 // Determine the next weight to use.
2088 ai++;
2089 if(ai >= hData->mAzCount[ei])
2091 ei++;
2092 ai = 0;
2095 // Finish the average calculation and keep it from being too small.
2096 for(i = 0;i < m;i++)
2097 dfa[i] = fmax(sqrt(dfa[i]), EPSILON);
2098 // Apply a limit to the magnitude range of the diffuse-field average if
2099 // desired.
2100 if(limit > 0.0)
2101 LimitMagnitudeResponse(hData->mFftSize, limit, dfa, dfa);
2102 DestroyArray(weights);
2105 // Perform diffuse-field equalization on the magnitude responses of the HRIR
2106 // set using the given average response.
2107 static void DiffuseFieldEqualize(const double *dfa, const HrirDataT *hData)
2109 uint step, start, end, m, j, i;
2111 step = hData->mIrSize;
2112 start = hData->mEvOffset[hData->mEvStart] * step;
2113 end = hData->mIrCount * step;
2114 m = 1 + (hData->mFftSize / 2);
2115 for(j = start;j < end;j += step)
2117 for(i = 0;i < m;i++)
2118 hData->mHrirs[j+i] /= dfa[i];
2122 // Perform minimum-phase reconstruction using the magnitude responses of the
2123 // HRIR set.
2124 static void ReconstructHrirs(const HrirDataT *hData)
2126 uint step, start, end, n, j, i;
2127 Complex *cplx;
2129 step = hData->mIrSize;
2130 start = hData->mEvOffset[hData->mEvStart] * step;
2131 end = hData->mIrCount * step;
2132 n = hData->mFftSize;
2133 cplx = calloc(sizeof(*cplx), n);
2134 for(j = start;j < end;j += step)
2136 MinimumPhase(n, &hData->mHrirs[j], cplx);
2137 FftInverse(n, cplx, cplx);
2138 for(i = 0;i < hData->mIrPoints;i++)
2139 hData->mHrirs[j+i] = cplx[i].Real;
2141 free(cplx);
2144 // Resamples the HRIRs for use at the given sampling rate.
2145 static void ResampleHrirs(const uint rate, HrirDataT *hData)
2147 uint n, step, start, end, j;
2148 ResamplerT rs;
2150 ResamplerSetup(&rs, hData->mIrRate, rate);
2151 n = hData->mIrPoints;
2152 step = hData->mIrSize;
2153 start = hData->mEvOffset[hData->mEvStart] * step;
2154 end = hData->mIrCount * step;
2155 for(j = start;j < end;j += step)
2156 ResamplerRun(&rs, n, &hData->mHrirs[j], n, &hData->mHrirs[j]);
2157 ResamplerClear(&rs);
2158 hData->mIrRate = rate;
2161 /* Given an elevation index and an azimuth, calculate the indices of the two
2162 * HRIRs that bound the coordinate along with a factor for calculating the
2163 * continous HRIR using interpolation.
2165 static void CalcAzIndices(const HrirDataT *hData, const uint ei, const double az, uint *j0, uint *j1, double *jf)
2167 double af;
2168 uint ai;
2170 af = ((2.0*M_PI) + az) * hData->mAzCount[ei] / (2.0*M_PI);
2171 ai = ((uint)af) % hData->mAzCount[ei];
2172 af -= floor(af);
2174 *j0 = hData->mEvOffset[ei] + ai;
2175 *j1 = hData->mEvOffset[ei] + ((ai+1) % hData->mAzCount [ei]);
2176 *jf = af;
2179 // Synthesize any missing onset timings at the bottom elevations. This just
2180 // blends between slightly exaggerated known onsets. Not an accurate model.
2181 static void SynthesizeOnsets(HrirDataT *hData)
2183 uint oi, e, a, j0, j1;
2184 double t, of, jf;
2186 oi = hData->mEvStart;
2187 t = 0.0;
2188 for(a = 0;a < hData->mAzCount[oi];a++)
2189 t += hData->mHrtds[hData->mEvOffset[oi] + a];
2190 hData->mHrtds[0] = 1.32e-4 + (t / hData->mAzCount[oi]);
2191 for(e = 1;e < hData->mEvStart;e++)
2193 of = ((double)e) / hData->mEvStart;
2194 for(a = 0;a < hData->mAzCount[e];a++)
2196 CalcAzIndices(hData, oi, a * 2.0 * M_PI / hData->mAzCount[e], &j0, &j1, &jf);
2197 hData->mHrtds[hData->mEvOffset[e] + a] = Lerp(hData->mHrtds[0], Lerp(hData->mHrtds[j0], hData->mHrtds[j1], jf), of);
2202 /* Attempt to synthesize any missing HRIRs at the bottom elevations. Right
2203 * now this just blends the lowest elevation HRIRs together and applies some
2204 * attenuation and high frequency damping. It is a simple, if inaccurate
2205 * model.
2207 static void SynthesizeHrirs (HrirDataT *hData)
2209 uint oi, a, e, step, n, i, j;
2210 double lp[4], s0, s1;
2211 double of, b;
2212 uint j0, j1;
2213 double jf;
2215 if(hData->mEvStart <= 0)
2216 return;
2217 step = hData->mIrSize;
2218 oi = hData->mEvStart;
2219 n = hData->mIrPoints;
2220 for(i = 0;i < n;i++)
2221 hData->mHrirs[i] = 0.0;
2222 for(a = 0;a < hData->mAzCount[oi];a++)
2224 j = (hData->mEvOffset[oi] + a) * step;
2225 for(i = 0;i < n;i++)
2226 hData->mHrirs[i] += hData->mHrirs[j+i] / hData->mAzCount[oi];
2228 for(e = 1;e < hData->mEvStart;e++)
2230 of = ((double)e) / hData->mEvStart;
2231 b = (1.0 - of) * (3.5e-6 * hData->mIrRate);
2232 for(a = 0;a < hData->mAzCount[e];a++)
2234 j = (hData->mEvOffset[e] + a) * step;
2235 CalcAzIndices(hData, oi, a * 2.0 * M_PI / hData->mAzCount[e], &j0, &j1, &jf);
2236 j0 *= step;
2237 j1 *= step;
2238 lp[0] = 0.0;
2239 lp[1] = 0.0;
2240 lp[2] = 0.0;
2241 lp[3] = 0.0;
2242 for(i = 0;i < n;i++)
2244 s0 = hData->mHrirs[i];
2245 s1 = Lerp(hData->mHrirs[j0+i], hData->mHrirs[j1+i], jf);
2246 s0 = Lerp(s0, s1, of);
2247 lp[0] = Lerp(s0, lp[0], b);
2248 lp[1] = Lerp(lp[0], lp[1], b);
2249 lp[2] = Lerp(lp[1], lp[2], b);
2250 lp[3] = Lerp(lp[2], lp[3], b);
2251 hData->mHrirs[j+i] = lp[3];
2255 b = 3.5e-6 * hData->mIrRate;
2256 lp[0] = 0.0;
2257 lp[1] = 0.0;
2258 lp[2] = 0.0;
2259 lp[3] = 0.0;
2260 for(i = 0;i < n;i++)
2262 s0 = hData->mHrirs[i];
2263 lp[0] = Lerp(s0, lp[0], b);
2264 lp[1] = Lerp(lp[0], lp[1], b);
2265 lp[2] = Lerp(lp[1], lp[2], b);
2266 lp[3] = Lerp(lp[2], lp[3], b);
2267 hData->mHrirs[i] = lp[3];
2269 hData->mEvStart = 0;
2272 // The following routines assume a full set of HRIRs for all elevations.
2274 // Normalize the HRIR set and slightly attenuate the result.
2275 static void NormalizeHrirs (const HrirDataT *hData)
2277 uint step, end, n, j, i;
2278 double maxLevel;
2280 step = hData->mIrSize;
2281 end = hData->mIrCount * step;
2282 n = hData->mIrPoints;
2283 maxLevel = 0.0;
2284 for(j = 0;j < end;j += step)
2286 for(i = 0;i < n;i++)
2287 maxLevel = fmax(fabs(hData->mHrirs[j+i]), maxLevel);
2289 maxLevel = 1.01 * maxLevel;
2290 for(j = 0;j < end;j += step)
2292 for(i = 0;i < n;i++)
2293 hData->mHrirs[j+i] /= maxLevel;
2297 // Calculate the left-ear time delay using a spherical head model.
2298 static double CalcLTD(const double ev, const double az, const double rad, const double dist)
2300 double azp, dlp, l, al;
2302 azp = asin(cos(ev) * sin(az));
2303 dlp = sqrt((dist*dist) + (rad*rad) + (2.0*dist*rad*sin(azp)));
2304 l = sqrt((dist*dist) - (rad*rad));
2305 al = (0.5 * M_PI) + azp;
2306 if(dlp > l)
2307 dlp = l + (rad * (al - acos(rad / dist)));
2308 return (dlp / 343.3);
2311 // Calculate the effective head-related time delays for each minimum-phase
2312 // HRIR.
2313 static void CalculateHrtds (const HeadModelT model, const double radius, HrirDataT *hData)
2315 double minHrtd, maxHrtd;
2316 uint e, a, j;
2317 double t;
2319 minHrtd = 1000.0;
2320 maxHrtd = -1000.0;
2321 for(e = 0;e < hData->mEvCount;e++)
2323 for(a = 0;a < hData->mAzCount[e];a++)
2325 j = hData->mEvOffset[e] + a;
2326 if(model == HM_DATASET)
2327 t = hData->mHrtds[j] * radius / hData->mRadius;
2328 else
2329 t = CalcLTD((-90.0 + (e * 180.0 / (hData->mEvCount - 1))) * M_PI / 180.0,
2330 (a * 360.0 / hData->mAzCount [e]) * M_PI / 180.0,
2331 radius, hData->mDistance);
2332 hData->mHrtds[j] = t;
2333 maxHrtd = fmax(t, maxHrtd);
2334 minHrtd = fmin(t, minHrtd);
2337 maxHrtd -= minHrtd;
2338 for(j = 0;j < hData->mIrCount;j++)
2339 hData->mHrtds[j] -= minHrtd;
2340 hData->mMaxHrtd = maxHrtd;
2344 // Process the data set definition to read and validate the data set metrics.
2345 static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint truncSize, HrirDataT *hData)
2347 int hasRate = 0, hasPoints = 0, hasAzimuths = 0;
2348 int hasRadius = 0, hasDistance = 0;
2349 char ident[MAX_IDENT_LEN+1];
2350 uint line, col;
2351 double fpVal;
2352 uint points;
2353 int intVal;
2355 while(!(hasRate && hasPoints && hasAzimuths && hasRadius && hasDistance))
2357 TrIndication(tr, & line, & col);
2358 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
2359 return 0;
2360 if(strcasecmp(ident, "rate") == 0)
2362 if(hasRate)
2364 TrErrorAt(tr, line, col, "Redefinition of 'rate'.\n");
2365 return 0;
2367 if(!TrReadOperator(tr, "="))
2368 return 0;
2369 if(!TrReadInt(tr, MIN_RATE, MAX_RATE, &intVal))
2370 return 0;
2371 hData->mIrRate = (uint)intVal;
2372 hasRate = 1;
2374 else if(strcasecmp(ident, "points") == 0)
2376 if (hasPoints) {
2377 TrErrorAt(tr, line, col, "Redefinition of 'points'.\n");
2378 return 0;
2380 if(!TrReadOperator(tr, "="))
2381 return 0;
2382 TrIndication(tr, &line, &col);
2383 if(!TrReadInt(tr, MIN_POINTS, MAX_POINTS, &intVal))
2384 return 0;
2385 points = (uint)intVal;
2386 if(fftSize > 0 && points > fftSize)
2388 TrErrorAt(tr, line, col, "Value exceeds the overridden FFT size.\n");
2389 return 0;
2391 if(points < truncSize)
2393 TrErrorAt(tr, line, col, "Value is below the truncation size.\n");
2394 return 0;
2396 hData->mIrPoints = points;
2397 if(fftSize <= 0)
2399 hData->mFftSize = DEFAULT_FFTSIZE;
2400 hData->mIrSize = 1 + (DEFAULT_FFTSIZE / 2);
2402 else
2404 hData->mFftSize = fftSize;
2405 hData->mIrSize = 1 + (fftSize / 2);
2406 if(points > hData->mIrSize)
2407 hData->mIrSize = points;
2409 hasPoints = 1;
2411 else if(strcasecmp(ident, "azimuths") == 0)
2413 if(hasAzimuths)
2415 TrErrorAt(tr, line, col, "Redefinition of 'azimuths'.\n");
2416 return 0;
2418 if(!TrReadOperator(tr, "="))
2419 return 0;
2420 hData->mIrCount = 0;
2421 hData->mEvCount = 0;
2422 hData->mEvOffset[0] = 0;
2423 for(;;)
2425 if(!TrReadInt(tr, MIN_AZ_COUNT, MAX_AZ_COUNT, &intVal))
2426 return 0;
2427 hData->mAzCount[hData->mEvCount] = (uint)intVal;
2428 hData->mIrCount += (uint)intVal;
2429 hData->mEvCount ++;
2430 if(!TrIsOperator(tr, ","))
2431 break;
2432 if(hData->mEvCount >= MAX_EV_COUNT)
2434 TrError(tr, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT);
2435 return 0;
2437 hData->mEvOffset[hData->mEvCount] = hData->mEvOffset[hData->mEvCount - 1] + ((uint)intVal);
2438 TrReadOperator(tr, ",");
2440 if(hData->mEvCount < MIN_EV_COUNT)
2442 TrErrorAt(tr, line, col, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT);
2443 return 0;
2445 hasAzimuths = 1;
2447 else if(strcasecmp(ident, "radius") == 0)
2449 if(hasRadius)
2451 TrErrorAt(tr, line, col, "Redefinition of 'radius'.\n");
2452 return 0;
2454 if(!TrReadOperator(tr, "="))
2455 return 0;
2456 if(!TrReadFloat(tr, MIN_RADIUS, MAX_RADIUS, &fpVal))
2457 return 0;
2458 hData->mRadius = fpVal;
2459 hasRadius = 1;
2461 else if(strcasecmp(ident, "distance") == 0)
2463 if(hasDistance)
2465 TrErrorAt(tr, line, col, "Redefinition of 'distance'.\n");
2466 return 0;
2468 if(!TrReadOperator(tr, "="))
2469 return 0;
2470 if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, & fpVal))
2471 return 0;
2472 hData->mDistance = fpVal;
2473 hasDistance = 1;
2475 else
2477 TrErrorAt(tr, line, col, "Expected a metric name.\n");
2478 return 0;
2480 TrSkipWhitespace (tr);
2482 return 1;
2485 // Parse an index pair from the data set definition.
2486 static int ReadIndexPair(TokenReaderT *tr, const HrirDataT *hData, uint *ei, uint *ai)
2488 int intVal;
2489 if(!TrReadInt(tr, 0, (int)hData->mEvCount, &intVal))
2490 return 0;
2491 *ei = (uint)intVal;
2492 if(!TrReadOperator(tr, ","))
2493 return 0;
2494 if(!TrReadInt(tr, 0, (int)hData->mAzCount[*ei], &intVal))
2495 return 0;
2496 *ai = (uint)intVal;
2497 return 1;
2500 // Match the source format from a given identifier.
2501 static SourceFormatT MatchSourceFormat(const char *ident)
2503 if(strcasecmp(ident, "wave") == 0)
2504 return SF_WAVE;
2505 if(strcasecmp(ident, "bin_le") == 0)
2506 return SF_BIN_LE;
2507 if(strcasecmp(ident, "bin_be") == 0)
2508 return SF_BIN_BE;
2509 if(strcasecmp(ident, "ascii") == 0)
2510 return SF_ASCII;
2511 return SF_NONE;
2514 // Match the source element type from a given identifier.
2515 static ElementTypeT MatchElementType(const char *ident)
2517 if(strcasecmp(ident, "int") == 0)
2518 return ET_INT;
2519 if(strcasecmp(ident, "fp") == 0)
2520 return ET_FP;
2521 return ET_NONE;
2524 // Parse and validate a source reference from the data set definition.
2525 static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
2527 char ident[MAX_IDENT_LEN+1];
2528 uint line, col;
2529 int intVal;
2531 TrIndication(tr, &line, &col);
2532 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
2533 return 0;
2534 src->mFormat = MatchSourceFormat(ident);
2535 if(src->mFormat == SF_NONE)
2537 TrErrorAt(tr, line, col, "Expected a source format.\n");
2538 return 0;
2540 if(!TrReadOperator(tr, "("))
2541 return 0;
2542 if(src->mFormat == SF_WAVE)
2544 if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
2545 return 0;
2546 src->mType = ET_NONE;
2547 src->mSize = 0;
2548 src->mBits = 0;
2549 src->mChannel = (uint)intVal;
2550 src->mSkip = 0;
2552 else
2554 TrIndication(tr, &line, &col);
2555 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
2556 return 0;
2557 src->mType = MatchElementType(ident);
2558 if(src->mType == ET_NONE)
2560 TrErrorAt(tr, line, col, "Expected a source element type.\n");
2561 return 0;
2563 if(src->mFormat == SF_BIN_LE || src->mFormat == SF_BIN_BE)
2565 if(!TrReadOperator(tr, ","))
2566 return 0;
2567 if(src->mType == ET_INT)
2569 if(!TrReadInt(tr, MIN_BIN_SIZE, MAX_BIN_SIZE, &intVal))
2570 return 0;
2571 src->mSize = (uint)intVal;
2572 if(!TrIsOperator(tr, ","))
2573 src->mBits = (int)(8*src->mSize);
2574 else
2576 TrReadOperator(tr, ",");
2577 TrIndication(tr, &line, &col);
2578 if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
2579 return 0;
2580 if(abs(intVal) < MIN_BIN_BITS || ((uint)abs(intVal)) > (8*src->mSize))
2582 TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8*src->mSize);
2583 return 0;
2585 src->mBits = intVal;
2588 else
2590 TrIndication(tr, &line, &col);
2591 if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
2592 return 0;
2593 if(intVal != 4 && intVal != 8)
2595 TrErrorAt(tr, line, col, "Expected a value of 4 or 8.\n");
2596 return 0;
2598 src->mSize = (uint)intVal;
2599 src->mBits = 0;
2602 else if(src->mFormat == SF_ASCII && src->mType == ET_INT)
2604 if(!TrReadOperator(tr, ","))
2605 return 0;
2606 if(!TrReadInt(tr, MIN_ASCII_BITS, MAX_ASCII_BITS, &intVal))
2607 return 0;
2608 src->mSize = 0;
2609 src->mBits = intVal;
2611 else
2613 src->mSize = 0;
2614 src->mBits = 0;
2617 if(!TrIsOperator(tr, ";"))
2618 src->mSkip = 0;
2619 else
2621 TrReadOperator(tr, ";");
2622 if(!TrReadInt (tr, 0, 0x7FFFFFFF, &intVal))
2623 return 0;
2624 src->mSkip = (uint)intVal;
2627 if(!TrReadOperator(tr, ")"))
2628 return 0;
2629 if(TrIsOperator(tr, "@"))
2631 TrReadOperator(tr, "@");
2632 if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
2633 return 0;
2634 src->mOffset = (uint)intVal;
2636 else
2637 src->mOffset = 0;
2638 if(!TrReadOperator(tr, ":"))
2639 return 0;
2640 if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
2641 return 0;
2642 return 1;
2645 // Process the list of sources in the data set definition.
2646 static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *hData)
2648 uint *setCount, *setFlag;
2649 uint line, col, ei, ai;
2650 SourceRefT src;
2651 double factor;
2652 double *hrir;
2654 setCount = (uint*)calloc(hData->mEvCount, sizeof(uint));
2655 setFlag = (uint*)calloc(hData->mIrCount, sizeof(uint));
2656 hrir = CreateArray(hData->mIrPoints);
2657 while(TrIsOperator(tr, "["))
2659 TrIndication(tr, & line, & col);
2660 TrReadOperator(tr, "[");
2661 if(!ReadIndexPair(tr, hData, &ei, &ai))
2662 goto error;
2663 if(!TrReadOperator(tr, "]"))
2664 goto error;
2665 if(setFlag[hData->mEvOffset[ei] + ai])
2667 TrErrorAt(tr, line, col, "Redefinition of source.\n");
2668 goto error;
2670 if(!TrReadOperator(tr, "="))
2671 goto error;
2673 factor = 1.0;
2674 for(;;)
2676 if(!ReadSourceRef(tr, &src))
2677 goto error;
2678 if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir))
2679 goto error;
2681 if(model == HM_DATASET)
2682 AverageHrirOnset(hrir, 1.0 / factor, ei, ai, hData);
2683 AverageHrirMagnitude(hrir, 1.0 / factor, ei, ai, hData);
2684 factor += 1.0;
2685 if(!TrIsOperator(tr, "+"))
2686 break;
2687 TrReadOperator(tr, "+");
2689 setFlag[hData->mEvOffset[ei] + ai] = 1;
2690 setCount[ei]++;
2693 ei = 0;
2694 while(ei < hData->mEvCount && setCount[ei] < 1)
2695 ei++;
2696 if(ei < hData->mEvCount)
2698 hData->mEvStart = ei;
2699 while(ei < hData->mEvCount && setCount[ei] == hData->mAzCount[ei])
2700 ei++;
2701 if(ei >= hData->mEvCount)
2703 if(!TrLoad(tr))
2705 DestroyArray(hrir);
2706 free(setFlag);
2707 free(setCount);
2708 return 1;
2710 TrError(tr, "Errant data at end of source list.\n");
2712 else
2713 TrError(tr, "Missing sources for elevation index %d.\n", ei);
2715 else
2716 TrError(tr, "Missing source references.\n");
2718 error:
2719 DestroyArray(hrir);
2720 free(setFlag);
2721 free(setCount);
2722 return 0;
2725 /* Parse the data set definition and process the source data, storing the
2726 * resulting data set as desired. If the input name is NULL it will read
2727 * from standard input.
2729 static int ProcessDefinition(const char *inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const OutputFormatT outFormat, const int experimental, const char *outName)
2731 char rateStr[8+1], expName[MAX_PATH_LEN];
2732 TokenReaderT tr;
2733 HrirDataT hData;
2734 double *dfa;
2735 FILE *fp;
2737 hData.mIrRate = 0;
2738 hData.mSampleType = ST_S24;
2739 hData.mChannelType = CT_LEFTONLY;
2740 hData.mIrPoints = 0;
2741 hData.mFftSize = 0;
2742 hData.mIrSize = 0;
2743 hData.mIrCount = 0;
2744 hData.mEvCount = 0;
2745 hData.mRadius = 0;
2746 hData.mDistance = 0;
2747 fprintf(stdout, "Reading HRIR definition...\n");
2748 if(inName != NULL)
2750 fp = fopen(inName, "r");
2751 if(fp == NULL)
2753 fprintf(stderr, "Error: Could not open definition file '%s'\n", inName);
2754 return 0;
2756 TrSetup(fp, inName, &tr);
2758 else
2760 fp = stdin;
2761 TrSetup(fp, "<stdin>", &tr);
2763 if(!ProcessMetrics(&tr, fftSize, truncSize, &hData))
2765 if(inName != NULL)
2766 fclose(fp);
2767 return 0;
2769 hData.mHrirs = CreateArray(hData.mIrCount * hData.mIrSize);
2770 hData.mHrtds = CreateArray(hData.mIrCount);
2771 if(!ProcessSources(model, &tr, &hData))
2773 DestroyArray(hData.mHrtds);
2774 DestroyArray(hData.mHrirs);
2775 if(inName != NULL)
2776 fclose(fp);
2777 return 0;
2779 if(inName != NULL)
2780 fclose(fp);
2781 if(equalize)
2783 dfa = CreateArray(1 + (hData.mFftSize/2));
2784 fprintf(stdout, "Calculating diffuse-field average...\n");
2785 CalculateDiffuseFieldAverage(&hData, surface, limit, dfa);
2786 fprintf(stdout, "Performing diffuse-field equalization...\n");
2787 DiffuseFieldEqualize(dfa, &hData);
2788 DestroyArray(dfa);
2790 fprintf(stdout, "Performing minimum phase reconstruction...\n");
2791 ReconstructHrirs(&hData);
2792 if(outRate != 0 && outRate != hData.mIrRate)
2794 fprintf(stdout, "Resampling HRIRs...\n");
2795 ResampleHrirs(outRate, &hData);
2797 fprintf(stdout, "Truncating minimum-phase HRIRs...\n");
2798 hData.mIrPoints = truncSize;
2799 fprintf(stdout, "Synthesizing missing elevations...\n");
2800 if(model == HM_DATASET)
2801 SynthesizeOnsets(&hData);
2802 SynthesizeHrirs(&hData);
2803 fprintf(stdout, "Normalizing final HRIRs...\n");
2804 NormalizeHrirs(&hData);
2805 fprintf(stdout, "Calculating impulse delays...\n");
2806 CalculateHrtds(model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData.mRadius, &hData);
2807 snprintf(rateStr, 8, "%u", hData.mIrRate);
2808 StrSubst(outName, "%r", rateStr, MAX_PATH_LEN, expName);
2809 switch(outFormat)
2811 case OF_MHR:
2812 fprintf(stdout, "Creating MHR data set file...\n");
2813 if(!StoreMhr(&hData, experimental, expName))
2815 DestroyArray(hData.mHrtds);
2816 DestroyArray(hData.mHrirs);
2817 return 0;
2819 break;
2820 default:
2821 break;
2823 DestroyArray(hData.mHrtds);
2824 DestroyArray(hData.mHrirs);
2825 return 1;
2828 static void PrintHelp(const char *argv0, FILE *ofile)
2830 fprintf(ofile, "Usage: %s <command> [<option>...]\n\n", argv0);
2831 fprintf(ofile, "Commands:\n");
2832 fprintf(ofile, " -m, --make-mhr Makes an OpenAL Soft compatible HRTF data set.\n");
2833 fprintf(ofile, " Defaults output to: ./oalsoft_hrtf_%%r.mhr\n");
2834 fprintf(ofile, " -h, --help Displays this help information.\n\n");
2835 fprintf(ofile, "Options:\n");
2836 fprintf(ofile, " -r=<rate> Change the data set sample rate to the specified value and\n");
2837 fprintf(ofile, " resample the HRIRs accordingly.\n");
2838 fprintf(ofile, " -f=<points> Override the FFT window size (default: %u).\n", DEFAULT_FFTSIZE);
2839 fprintf(ofile, " -e={on|off} Toggle diffuse-field equalization (default: %s).\n", (DEFAULT_EQUALIZE ? "on" : "off"));
2840 fprintf(ofile, " -s={on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DEFAULT_SURFACE ? "on" : "off"));
2841 fprintf(ofile, " -l={<dB>|none} Specify a limit to the magnitude range of the diffuse-field\n");
2842 fprintf(ofile, " average (default: %.2f).\n", DEFAULT_LIMIT);
2843 fprintf(ofile, " -w=<points> Specify the size of the truncation window that's applied\n");
2844 fprintf(ofile, " after minimum-phase reconstruction (default: %u).\n", DEFAULT_TRUNCSIZE);
2845 fprintf(ofile, " -d={dataset| Specify the model used for calculating the head-delay timing\n");
2846 fprintf(ofile, " sphere} values (default: %s).\n", ((DEFAULT_HEAD_MODEL == HM_DATASET) ? "dataset" : "sphere"));
2847 fprintf(ofile, " -c=<size> Use a customized head radius measured ear-to-ear in meters.\n");
2848 fprintf(ofile, " -i=<filename> Specify an HRIR definition file to use (defaults to stdin).\n");
2849 fprintf(ofile, " -o=<filename> Specify an output file. Overrides command-selected default.\n");
2850 fprintf(ofile, " Use of '%%r' will be substituted with the data set sample rate.\n");
2853 // Standard command line dispatch.
2854 int main(const int argc, const char *argv[])
2856 const char *inName = NULL, *outName = NULL;
2857 OutputFormatT outFormat;
2858 uint outRate, fftSize;
2859 int equalize, surface;
2860 int experimental;
2861 char *end = NULL;
2862 HeadModelT model;
2863 uint truncSize;
2864 double radius;
2865 double limit;
2866 int argi;
2868 if(argc < 2 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)
2870 fprintf(stdout, "HRTF Processing and Composition Utility\n\n");
2871 PrintHelp(argv[0], stdout);
2872 return 0;
2875 if(strcmp(argv[1], "--make-mhr") == 0 || strcmp(argv[1], "-m") == 0)
2877 outName = "./oalsoft_hrtf_%r.mhr";
2878 outFormat = OF_MHR;
2880 else
2882 fprintf(stderr, "Error: Invalid command '%s'.\n\n", argv[1]);
2883 PrintHelp(argv[0], stderr);
2884 return -1;
2887 outRate = 0;
2888 fftSize = 0;
2889 equalize = DEFAULT_EQUALIZE;
2890 surface = DEFAULT_SURFACE;
2891 limit = DEFAULT_LIMIT;
2892 truncSize = DEFAULT_TRUNCSIZE;
2893 model = DEFAULT_HEAD_MODEL;
2894 radius = DEFAULT_CUSTOM_RADIUS;
2895 experimental = 0;
2897 argi = 2;
2898 while(argi < argc)
2900 if(strncmp(argv[argi], "-r=", 3) == 0)
2902 outRate = strtoul(&argv[argi][3], &end, 10);
2903 if(end[0] != '\0' || outRate < MIN_RATE || outRate > MAX_RATE)
2905 fprintf(stderr, "Error: Expected a value from %u to %u for '-r'.\n", MIN_RATE, MAX_RATE);
2906 return -1;
2909 else if(strncmp(argv[argi], "-f=", 3) == 0)
2911 fftSize = strtoul(&argv[argi][3], &end, 10);
2912 if(end[0] != '\0' || (fftSize&(fftSize-1)) || fftSize < MIN_FFTSIZE || fftSize > MAX_FFTSIZE)
2914 fprintf(stderr, "Error: Expected a power-of-two value from %u to %u for '-f'.\n", MIN_FFTSIZE, MAX_FFTSIZE);
2915 return -1;
2918 else if(strncmp(argv[argi], "-e=", 3) == 0)
2920 if(strcmp(&argv[argi][3], "on") == 0)
2921 equalize = 1;
2922 else if(strcmp(&argv[argi][3], "off") == 0)
2923 equalize = 0;
2924 else
2926 fprintf(stderr, "Error: Expected 'on' or 'off' for '-e'.\n");
2927 return -1;
2930 else if(strncmp(argv[argi], "-s=", 3) == 0)
2932 if(strcmp(&argv[argi][3], "on") == 0)
2933 surface = 1;
2934 else if(strcmp(&argv[argi][3], "off") == 0)
2935 surface = 0;
2936 else
2938 fprintf(stderr, "Error: Expected 'on' or 'off' for '-s'.\n");
2939 return -1;
2942 else if(strncmp(argv[argi], "-l=", 3) == 0)
2944 if(strcmp(&argv[argi][3], "none") == 0)
2945 limit = 0.0;
2946 else
2948 limit = strtod(&argv[argi] [3], &end);
2949 if(end[0] != '\0' || limit < MIN_LIMIT || limit > MAX_LIMIT)
2951 fprintf(stderr, "Error: Expected 'none' or a value from %.2f to %.2f for '-l'.\n", MIN_LIMIT, MAX_LIMIT);
2952 return -1;
2956 else if(strncmp(argv[argi], "-w=", 3) == 0)
2958 truncSize = strtoul(&argv[argi][3], &end, 10);
2959 if(end[0] != '\0' || truncSize < MIN_TRUNCSIZE || truncSize > MAX_TRUNCSIZE || (truncSize%MOD_TRUNCSIZE))
2961 fprintf(stderr, "Error: Expected a value from %u to %u in multiples of %u for '-w'.\n", MIN_TRUNCSIZE, MAX_TRUNCSIZE, MOD_TRUNCSIZE);
2962 return -1;
2965 else if(strncmp(argv[argi], "-d=", 3) == 0)
2967 if(strcmp(&argv[argi][3], "dataset") == 0)
2968 model = HM_DATASET;
2969 else if(strcmp(&argv[argi][3], "sphere") == 0)
2970 model = HM_SPHERE;
2971 else
2973 fprintf(stderr, "Error: Expected 'dataset' or 'sphere' for '-d'.\n");
2974 return -1;
2977 else if(strncmp(argv[argi], "-c=", 3) == 0)
2979 radius = strtod(&argv[argi][3], &end);
2980 if(end[0] != '\0' || radius < MIN_CUSTOM_RADIUS || radius > MAX_CUSTOM_RADIUS)
2982 fprintf(stderr, "Error: Expected a value from %.2f to %.2f for '-c'.\n", MIN_CUSTOM_RADIUS, MAX_CUSTOM_RADIUS);
2983 return -1;
2986 else if(strncmp(argv[argi], "-i=", 3) == 0)
2987 inName = &argv[argi][3];
2988 else if(strncmp(argv[argi], "-o=", 3) == 0)
2989 outName = &argv[argi][3];
2990 else if(strcmp(argv[argi], "--experimental") == 0)
2991 experimental = 1;
2992 else
2994 fprintf(stderr, "Error: Invalid option '%s'.\n", argv[argi]);
2995 return -1;
2997 argi++;
2999 if(!ProcessDefinition(inName, outRate, fftSize, equalize, surface, limit,
3000 truncSize, model, radius, outFormat, experimental,
3001 outName))
3002 return -1;
3003 fprintf(stdout, "Operation completed.\n");
3004 return 0;