]> git.tdb.fi Git - ext/openal.git/blob - utils/makemhr/loaddef.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / utils / makemhr / loaddef.cpp
1 /*
2  * HRTF utility for producing and demonstrating the process of creating an
3  * OpenAL Soft compatible HRIR data set.
4  *
5  * Copyright (C) 2011-2019  Christopher Fitzgerald
6  *
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.
11  *
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.
16  *
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.
20  *
21  * Or visit:  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  */
23
24 #include "loaddef.h"
25
26 #include <algorithm>
27 #include <cctype>
28 #include <cmath>
29 #include <cstdarg>
30 #include <cstdio>
31 #include <cstdlib>
32 #include <cstring>
33 #include <iterator>
34 #include <limits>
35 #include <memory>
36 #include <cstdarg>
37 #include <vector>
38
39 #include "alfstream.h"
40 #include "aloptional.h"
41 #include "alspan.h"
42 #include "alstring.h"
43 #include "makemhr.h"
44 #include "polyphase_resampler.h"
45
46 #include "mysofa.h"
47
48 // Constants for accessing the token reader's ring buffer.
49 #define TR_RING_BITS                 (16)
50 #define TR_RING_SIZE                 (1 << TR_RING_BITS)
51 #define TR_RING_MASK                 (TR_RING_SIZE - 1)
52
53 // The token reader's load interval in bytes.
54 #define TR_LOAD_SIZE                 (TR_RING_SIZE >> 2)
55
56 // Token reader state for parsing the data set definition.
57 struct TokenReaderT {
58     std::istream &mIStream;
59     const char *mName{};
60     uint        mLine{};
61     uint        mColumn{};
62     char mRing[TR_RING_SIZE]{};
63     std::streamsize mIn{};
64     std::streamsize mOut{};
65
66     TokenReaderT(std::istream &istream) noexcept : mIStream{istream} { }
67     TokenReaderT(const TokenReaderT&) = default;
68 };
69
70
71 // The maximum identifier length used when processing the data set
72 // definition.
73 #define MAX_IDENT_LEN                (16)
74
75 // The limits for the listener's head 'radius' in the data set definition.
76 #define MIN_RADIUS                   (0.05)
77 #define MAX_RADIUS                   (0.15)
78
79 // The maximum number of channels that can be addressed for a WAVE file
80 // source listed in the data set definition.
81 #define MAX_WAVE_CHANNELS            (65535)
82
83 // The limits to the byte size for a binary source listed in the definition
84 // file.
85 #define MIN_BIN_SIZE                 (2)
86 #define MAX_BIN_SIZE                 (4)
87
88 // The minimum number of significant bits for binary sources listed in the
89 // data set definition.  The maximum is calculated from the byte size.
90 #define MIN_BIN_BITS                 (16)
91
92 // The limits to the number of significant bits for an ASCII source listed in
93 // the data set definition.
94 #define MIN_ASCII_BITS               (16)
95 #define MAX_ASCII_BITS               (32)
96
97 // The four-character-codes for RIFF/RIFX WAVE file chunks.
98 #define FOURCC_RIFF                  (0x46464952) // 'RIFF'
99 #define FOURCC_RIFX                  (0x58464952) // 'RIFX'
100 #define FOURCC_WAVE                  (0x45564157) // 'WAVE'
101 #define FOURCC_FMT                   (0x20746D66) // 'fmt '
102 #define FOURCC_DATA                  (0x61746164) // 'data'
103 #define FOURCC_LIST                  (0x5453494C) // 'LIST'
104 #define FOURCC_WAVL                  (0x6C766177) // 'wavl'
105 #define FOURCC_SLNT                  (0x746E6C73) // 'slnt'
106
107 // The supported wave formats.
108 #define WAVE_FORMAT_PCM              (0x0001)
109 #define WAVE_FORMAT_IEEE_FLOAT       (0x0003)
110 #define WAVE_FORMAT_EXTENSIBLE       (0xFFFE)
111
112
113 enum ByteOrderT {
114     BO_NONE,
115     BO_LITTLE,
116     BO_BIG
117 };
118
119 // Source format for the references listed in the data set definition.
120 enum SourceFormatT {
121     SF_NONE,
122     SF_ASCII,  // ASCII text file.
123     SF_BIN_LE, // Little-endian binary file.
124     SF_BIN_BE, // Big-endian binary file.
125     SF_WAVE,   // RIFF/RIFX WAVE file.
126     SF_SOFA    // Spatially Oriented Format for Accoustics (SOFA) file.
127 };
128
129 // Element types for the references listed in the data set definition.
130 enum ElementTypeT {
131     ET_NONE,
132     ET_INT,  // Integer elements.
133     ET_FP    // Floating-point elements.
134 };
135
136 // Source reference state used when loading sources.
137 struct SourceRefT {
138     SourceFormatT mFormat;
139     ElementTypeT  mType;
140     uint mSize;
141     int  mBits;
142     uint mChannel;
143     double mAzimuth;
144     double mElevation;
145     double mRadius;
146     uint mSkip;
147     uint mOffset;
148     char mPath[MAX_PATH_LEN+1];
149 };
150
151
152 /* Whitespace is not significant. It can process tokens as identifiers, numbers
153  * (integer and floating-point), strings, and operators. Strings must be
154  * encapsulated by double-quotes and cannot span multiple lines.
155  */
156
157 // Setup the reader on the given file.  The filename can be NULL if no error
158 // output is desired.
159 static void TrSetup(const char *startbytes, std::streamsize startbytecount, const char *filename,
160     TokenReaderT *tr)
161 {
162     const char *name = nullptr;
163
164     if(filename)
165     {
166         const char *slash = strrchr(filename, '/');
167         if(slash)
168         {
169             const char *bslash = strrchr(slash+1, '\\');
170             if(bslash) name = bslash+1;
171             else name = slash+1;
172         }
173         else
174         {
175             const char *bslash = strrchr(filename, '\\');
176             if(bslash) name = bslash+1;
177             else name = filename;
178         }
179     }
180
181     tr->mName = name;
182     tr->mLine = 1;
183     tr->mColumn = 1;
184     tr->mIn = 0;
185     tr->mOut = 0;
186
187     if(startbytecount > 0)
188     {
189         std::copy_n(startbytes, startbytecount, std::begin(tr->mRing));
190         tr->mIn += startbytecount;
191     }
192 }
193
194 // Prime the reader's ring buffer, and return a result indicating that there
195 // is text to process.
196 static int TrLoad(TokenReaderT *tr)
197 {
198     std::istream &istream = tr->mIStream;
199
200     std::streamsize toLoad{TR_RING_SIZE - static_cast<std::streamsize>(tr->mIn - tr->mOut)};
201     if(toLoad >= TR_LOAD_SIZE && istream.good())
202     {
203         // Load TR_LOAD_SIZE (or less if at the end of the file) per read.
204         toLoad = TR_LOAD_SIZE;
205         std::streamsize in{tr->mIn&TR_RING_MASK};
206         std::streamsize count{TR_RING_SIZE - in};
207         if(count < toLoad)
208         {
209             istream.read(&tr->mRing[in], count);
210             tr->mIn += istream.gcount();
211             istream.read(&tr->mRing[0], toLoad-count);
212             tr->mIn += istream.gcount();
213         }
214         else
215         {
216             istream.read(&tr->mRing[in], toLoad);
217             tr->mIn += istream.gcount();
218         }
219
220         if(tr->mOut >= TR_RING_SIZE)
221         {
222             tr->mOut -= TR_RING_SIZE;
223             tr->mIn -= TR_RING_SIZE;
224         }
225     }
226     if(tr->mIn > tr->mOut)
227         return 1;
228     return 0;
229 }
230
231 // Error display routine.  Only displays when the base name is not NULL.
232 static void TrErrorVA(const TokenReaderT *tr, uint line, uint column, const char *format, va_list argPtr)
233 {
234     if(!tr->mName)
235         return;
236     fprintf(stderr, "\nError (%s:%u:%u): ", tr->mName, line, column);
237     vfprintf(stderr, format, argPtr);
238 }
239
240 // Used to display an error at a saved line/column.
241 static void TrErrorAt(const TokenReaderT *tr, uint line, uint column, const char *format, ...)
242 {
243     va_list argPtr;
244
245     va_start(argPtr, format);
246     TrErrorVA(tr, line, column, format, argPtr);
247     va_end(argPtr);
248 }
249
250 // Used to display an error at the current line/column.
251 static void TrError(const TokenReaderT *tr, const char *format, ...)
252 {
253     va_list argPtr;
254
255     va_start(argPtr, format);
256     TrErrorVA(tr, tr->mLine, tr->mColumn, format, argPtr);
257     va_end(argPtr);
258 }
259
260 // Skips to the next line.
261 static void TrSkipLine(TokenReaderT *tr)
262 {
263     char ch;
264
265     while(TrLoad(tr))
266     {
267         ch = tr->mRing[tr->mOut&TR_RING_MASK];
268         tr->mOut++;
269         if(ch == '\n')
270         {
271             tr->mLine++;
272             tr->mColumn = 1;
273             break;
274         }
275         tr->mColumn ++;
276     }
277 }
278
279 // Skips to the next token.
280 static int TrSkipWhitespace(TokenReaderT *tr)
281 {
282     while(TrLoad(tr))
283     {
284         char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
285         if(isspace(ch))
286         {
287             tr->mOut++;
288             if(ch == '\n')
289             {
290                 tr->mLine++;
291                 tr->mColumn = 1;
292             }
293             else
294                 tr->mColumn++;
295         }
296         else if(ch == '#')
297             TrSkipLine(tr);
298         else
299             return 1;
300     }
301     return 0;
302 }
303
304 // Get the line and/or column of the next token (or the end of input).
305 static void TrIndication(TokenReaderT *tr, uint *line, uint *column)
306 {
307     TrSkipWhitespace(tr);
308     if(line) *line = tr->mLine;
309     if(column) *column = tr->mColumn;
310 }
311
312 // Checks to see if a token is (likely to be) an identifier.  It does not
313 // display any errors and will not proceed to the next token.
314 static int TrIsIdent(TokenReaderT *tr)
315 {
316     if(!TrSkipWhitespace(tr))
317         return 0;
318     char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
319     return ch == '_' || isalpha(ch);
320 }
321
322
323 // Checks to see if a token is the given operator.  It does not display any
324 // errors and will not proceed to the next token.
325 static int TrIsOperator(TokenReaderT *tr, const char *op)
326 {
327     std::streamsize out;
328     size_t len;
329     char ch;
330
331     if(!TrSkipWhitespace(tr))
332         return 0;
333     out = tr->mOut;
334     len = 0;
335     while(op[len] != '\0' && out < tr->mIn)
336     {
337         ch = tr->mRing[out&TR_RING_MASK];
338         if(ch != op[len]) break;
339         len++;
340         out++;
341     }
342     if(op[len] == '\0')
343         return 1;
344     return 0;
345 }
346
347 /* The TrRead*() routines obtain the value of a matching token type.  They
348  * display type, form, and boundary errors and will proceed to the next
349  * token.
350  */
351
352 // Reads and validates an identifier token.
353 static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident)
354 {
355     uint col, len;
356     char ch;
357
358     col = tr->mColumn;
359     if(TrSkipWhitespace(tr))
360     {
361         col = tr->mColumn;
362         ch = tr->mRing[tr->mOut&TR_RING_MASK];
363         if(ch == '_' || isalpha(ch))
364         {
365             len = 0;
366             do {
367                 if(len < maxLen)
368                     ident[len] = ch;
369                 len++;
370                 tr->mOut++;
371                 if(!TrLoad(tr))
372                     break;
373                 ch = tr->mRing[tr->mOut&TR_RING_MASK];
374             } while(ch == '_' || isdigit(ch) || isalpha(ch));
375
376             tr->mColumn += len;
377             if(len < maxLen)
378             {
379                 ident[len] = '\0';
380                 return 1;
381             }
382             TrErrorAt(tr, tr->mLine, col, "Identifier is too long.\n");
383             return 0;
384         }
385     }
386     TrErrorAt(tr, tr->mLine, col, "Expected an identifier.\n");
387     return 0;
388 }
389
390 // Reads and validates (including bounds) an integer token.
391 static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int *value)
392 {
393     uint col, digis, len;
394     char ch, temp[64+1];
395
396     col = tr->mColumn;
397     if(TrSkipWhitespace(tr))
398     {
399         col = tr->mColumn;
400         len = 0;
401         ch = tr->mRing[tr->mOut&TR_RING_MASK];
402         if(ch == '+' || ch == '-')
403         {
404             temp[len] = ch;
405             len++;
406             tr->mOut++;
407         }
408         digis = 0;
409         while(TrLoad(tr))
410         {
411             ch = tr->mRing[tr->mOut&TR_RING_MASK];
412             if(!isdigit(ch)) break;
413             if(len < 64)
414                 temp[len] = ch;
415             len++;
416             digis++;
417             tr->mOut++;
418         }
419         tr->mColumn += len;
420         if(digis > 0 && ch != '.' && !isalpha(ch))
421         {
422             if(len > 64)
423             {
424                 TrErrorAt(tr, tr->mLine, col, "Integer is too long.");
425                 return 0;
426             }
427             temp[len] = '\0';
428             *value = static_cast<int>(strtol(temp, nullptr, 10));
429             if(*value < loBound || *value > hiBound)
430             {
431                 TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound);
432                 return 0;
433             }
434             return 1;
435         }
436     }
437     TrErrorAt(tr, tr->mLine, col, "Expected an integer.\n");
438     return 0;
439 }
440
441 // Reads and validates (including bounds) a float token.
442 static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBound, double *value)
443 {
444     uint col, digis, len;
445     char ch, temp[64+1];
446
447     col = tr->mColumn;
448     if(TrSkipWhitespace(tr))
449     {
450         col = tr->mColumn;
451         len = 0;
452         ch = tr->mRing[tr->mOut&TR_RING_MASK];
453         if(ch == '+' || ch == '-')
454         {
455             temp[len] = ch;
456             len++;
457             tr->mOut++;
458         }
459
460         digis = 0;
461         while(TrLoad(tr))
462         {
463             ch = tr->mRing[tr->mOut&TR_RING_MASK];
464             if(!isdigit(ch)) break;
465             if(len < 64)
466                 temp[len] = ch;
467             len++;
468             digis++;
469             tr->mOut++;
470         }
471         if(ch == '.')
472         {
473             if(len < 64)
474                 temp[len] = ch;
475             len++;
476             tr->mOut++;
477         }
478         while(TrLoad(tr))
479         {
480             ch = tr->mRing[tr->mOut&TR_RING_MASK];
481             if(!isdigit(ch)) break;
482             if(len < 64)
483                 temp[len] = ch;
484             len++;
485             digis++;
486             tr->mOut++;
487         }
488         if(digis > 0)
489         {
490             if(ch == 'E' || ch == 'e')
491             {
492                 if(len < 64)
493                     temp[len] = ch;
494                 len++;
495                 digis = 0;
496                 tr->mOut++;
497                 if(ch == '+' || ch == '-')
498                 {
499                     if(len < 64)
500                         temp[len] = ch;
501                     len++;
502                     tr->mOut++;
503                 }
504                 while(TrLoad(tr))
505                 {
506                     ch = tr->mRing[tr->mOut&TR_RING_MASK];
507                     if(!isdigit(ch)) break;
508                     if(len < 64)
509                         temp[len] = ch;
510                     len++;
511                     digis++;
512                     tr->mOut++;
513                 }
514             }
515             tr->mColumn += len;
516             if(digis > 0 && ch != '.' && !isalpha(ch))
517             {
518                 if(len > 64)
519                 {
520                     TrErrorAt(tr, tr->mLine, col, "Float is too long.");
521                     return 0;
522                 }
523                 temp[len] = '\0';
524                 *value = strtod(temp, nullptr);
525                 if(*value < loBound || *value > hiBound)
526                 {
527                     TrErrorAt(tr, tr->mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound);
528                     return 0;
529                 }
530                 return 1;
531             }
532         }
533         else
534             tr->mColumn += len;
535     }
536     TrErrorAt(tr, tr->mLine, col, "Expected a float.\n");
537     return 0;
538 }
539
540 // Reads and validates a string token.
541 static int TrReadString(TokenReaderT *tr, const uint maxLen, char *text)
542 {
543     uint col, len;
544     char ch;
545
546     col = tr->mColumn;
547     if(TrSkipWhitespace(tr))
548     {
549         col = tr->mColumn;
550         ch = tr->mRing[tr->mOut&TR_RING_MASK];
551         if(ch == '\"')
552         {
553             tr->mOut++;
554             len = 0;
555             while(TrLoad(tr))
556             {
557                 ch = tr->mRing[tr->mOut&TR_RING_MASK];
558                 tr->mOut++;
559                 if(ch == '\"')
560                     break;
561                 if(ch == '\n')
562                 {
563                     TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of line.\n");
564                     return 0;
565                 }
566                 if(len < maxLen)
567                     text[len] = ch;
568                 len++;
569             }
570             if(ch != '\"')
571             {
572                 tr->mColumn += 1 + len;
573                 TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of input.\n");
574                 return 0;
575             }
576             tr->mColumn += 2 + len;
577             if(len > maxLen)
578             {
579                 TrErrorAt(tr, tr->mLine, col, "String is too long.\n");
580                 return 0;
581             }
582             text[len] = '\0';
583             return 1;
584         }
585     }
586     TrErrorAt(tr, tr->mLine, col, "Expected a string.\n");
587     return 0;
588 }
589
590 // Reads and validates the given operator.
591 static int TrReadOperator(TokenReaderT *tr, const char *op)
592 {
593     uint col, len;
594     char ch;
595
596     col = tr->mColumn;
597     if(TrSkipWhitespace(tr))
598     {
599         col = tr->mColumn;
600         len = 0;
601         while(op[len] != '\0' && TrLoad(tr))
602         {
603             ch = tr->mRing[tr->mOut&TR_RING_MASK];
604             if(ch != op[len]) break;
605             len++;
606             tr->mOut++;
607         }
608         tr->mColumn += len;
609         if(op[len] == '\0')
610             return 1;
611     }
612     TrErrorAt(tr, tr->mLine, col, "Expected '%s' operator.\n", op);
613     return 0;
614 }
615
616
617 /*************************
618  *** File source input ***
619  *************************/
620
621 // Read a binary value of the specified byte order and byte size from a file,
622 // storing it as a 32-bit unsigned integer.
623 static int ReadBin4(std::istream &istream, const char *filename, const ByteOrderT order, const uint bytes, uint32_t *out)
624 {
625     uint8_t in[4];
626     istream.read(reinterpret_cast<char*>(in), static_cast<int>(bytes));
627     if(istream.gcount() != bytes)
628     {
629         fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
630         return 0;
631     }
632     uint32_t accum{0};
633     switch(order)
634     {
635         case BO_LITTLE:
636             for(uint i = 0;i < bytes;i++)
637                 accum = (accum<<8) | in[bytes - i - 1];
638             break;
639         case BO_BIG:
640             for(uint i = 0;i < bytes;i++)
641                 accum = (accum<<8) | in[i];
642             break;
643         default:
644             break;
645     }
646     *out = accum;
647     return 1;
648 }
649
650 // Read a binary value of the specified byte order from a file, storing it as
651 // a 64-bit unsigned integer.
652 static int ReadBin8(std::istream &istream, const char *filename, const ByteOrderT order, uint64_t *out)
653 {
654     uint8_t in[8];
655     uint64_t accum;
656     uint i;
657
658     istream.read(reinterpret_cast<char*>(in), 8);
659     if(istream.gcount() != 8)
660     {
661         fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
662         return 0;
663     }
664     accum = 0;
665     switch(order)
666     {
667         case BO_LITTLE:
668             for(i = 0;i < 8;i++)
669                 accum = (accum<<8) | in[8 - i - 1];
670             break;
671         case BO_BIG:
672             for(i = 0;i < 8;i++)
673                 accum = (accum<<8) | in[i];
674             break;
675         default:
676             break;
677     }
678     *out = accum;
679     return 1;
680 }
681
682 /* Read a binary value of the specified type, byte order, and byte size from
683  * a file, converting it to a double.  For integer types, the significant
684  * bits are used to normalize the result.  The sign of bits determines
685  * whether they are padded toward the MSB (negative) or LSB (positive).
686  * Floating-point types are not normalized.
687  */
688 static int ReadBinAsDouble(std::istream &istream, const char *filename, const ByteOrderT order,
689     const ElementTypeT type, const uint bytes, const int bits, double *out)
690 {
691     union {
692         uint32_t ui;
693         int32_t i;
694         float f;
695     } v4;
696     union {
697         uint64_t ui;
698         double f;
699     } v8;
700
701     *out = 0.0;
702     if(bytes > 4)
703     {
704         if(!ReadBin8(istream, filename, order, &v8.ui))
705             return 0;
706         if(type == ET_FP)
707             *out = v8.f;
708     }
709     else
710     {
711         if(!ReadBin4(istream, filename, order, bytes, &v4.ui))
712             return 0;
713         if(type == ET_FP)
714             *out = v4.f;
715         else
716         {
717             if(bits > 0)
718                 v4.ui >>= (8*bytes) - (static_cast<uint>(bits));
719             else
720                 v4.ui &= (0xFFFFFFFF >> (32+bits));
721
722             if(v4.ui&static_cast<uint>(1<<(std::abs(bits)-1)))
723                 v4.ui |= (0xFFFFFFFF << std::abs(bits));
724             *out = v4.i / static_cast<double>(1<<(std::abs(bits)-1));
725         }
726     }
727     return 1;
728 }
729
730 /* Read an ascii value of the specified type from a file, converting it to a
731  * double.  For integer types, the significant bits are used to normalize the
732  * result.  The sign of the bits should always be positive.  This also skips
733  * up to one separator character before the element itself.
734  */
735 static int ReadAsciiAsDouble(TokenReaderT *tr, const char *filename, const ElementTypeT type, const uint bits, double *out)
736 {
737     if(TrIsOperator(tr, ","))
738         TrReadOperator(tr, ",");
739     else if(TrIsOperator(tr, ":"))
740         TrReadOperator(tr, ":");
741     else if(TrIsOperator(tr, ";"))
742         TrReadOperator(tr, ";");
743     else if(TrIsOperator(tr, "|"))
744         TrReadOperator(tr, "|");
745
746     if(type == ET_FP)
747     {
748         if(!TrReadFloat(tr, -std::numeric_limits<double>::infinity(),
749             std::numeric_limits<double>::infinity(), out))
750         {
751             fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
752             return 0;
753         }
754     }
755     else
756     {
757         int v;
758         if(!TrReadInt(tr, -(1<<(bits-1)), (1<<(bits-1))-1, &v))
759         {
760             fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
761             return 0;
762         }
763         *out = v / static_cast<double>((1<<(bits-1))-1);
764     }
765     return 1;
766 }
767
768 // Read the RIFF/RIFX WAVE format chunk from a file, validating it against
769 // the source parameters and data set metrics.
770 static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const uint hrirRate,
771     SourceRefT *src)
772 {
773     uint32_t fourCC, chunkSize;
774     uint32_t format, channels, rate, dummy, block, size, bits;
775
776     chunkSize = 0;
777     do {
778         if(chunkSize > 0)
779             istream.seekg(static_cast<int>(chunkSize), std::ios::cur);
780         if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
781             || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
782             return 0;
783     } while(fourCC != FOURCC_FMT);
784     if(!ReadBin4(istream, src->mPath, order, 2, &format)
785         || !ReadBin4(istream, src->mPath, order, 2, &channels)
786         || !ReadBin4(istream, src->mPath, order, 4, &rate)
787         || !ReadBin4(istream, src->mPath, order, 4, &dummy)
788         || !ReadBin4(istream, src->mPath, order, 2, &block))
789         return 0;
790     block /= channels;
791     if(chunkSize > 14)
792     {
793         if(!ReadBin4(istream, src->mPath, order, 2, &size))
794             return 0;
795         size /= 8;
796         if(block > size)
797             size = block;
798     }
799     else
800         size = block;
801     if(format == WAVE_FORMAT_EXTENSIBLE)
802     {
803         istream.seekg(2, std::ios::cur);
804         if(!ReadBin4(istream, src->mPath, order, 2, &bits))
805             return 0;
806         if(bits == 0)
807             bits = 8 * size;
808         istream.seekg(4, std::ios::cur);
809         if(!ReadBin4(istream, src->mPath, order, 2, &format))
810             return 0;
811         istream.seekg(static_cast<int>(chunkSize - 26), std::ios::cur);
812     }
813     else
814     {
815         bits = 8 * size;
816         if(chunkSize > 14)
817             istream.seekg(static_cast<int>(chunkSize - 16), std::ios::cur);
818         else
819             istream.seekg(static_cast<int>(chunkSize - 14), std::ios::cur);
820     }
821     if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT)
822     {
823         fprintf(stderr, "\nError: Unsupported WAVE format in file '%s'.\n", src->mPath);
824         return 0;
825     }
826     if(src->mChannel >= channels)
827     {
828         fprintf(stderr, "\nError: Missing source channel in WAVE file '%s'.\n", src->mPath);
829         return 0;
830     }
831     if(rate != hrirRate)
832     {
833         fprintf(stderr, "\nError: Mismatched source sample rate in WAVE file '%s'.\n", src->mPath);
834         return 0;
835     }
836     if(format == WAVE_FORMAT_PCM)
837     {
838         if(size < 2 || size > 4)
839         {
840             fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
841             return 0;
842         }
843         if(bits < 16 || bits > (8*size))
844         {
845             fprintf(stderr, "\nError: Bad significant bits in WAVE file '%s'.\n", src->mPath);
846             return 0;
847         }
848         src->mType = ET_INT;
849     }
850     else
851     {
852         if(size != 4 && size != 8)
853         {
854             fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
855             return 0;
856         }
857         src->mType = ET_FP;
858     }
859     src->mSize = size;
860     src->mBits = static_cast<int>(bits);
861     src->mSkip = channels;
862     return 1;
863 }
864
865 // Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles.
866 static int ReadWaveData(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
867     const uint n, double *hrir)
868 {
869     int pre, post, skip;
870     uint i;
871
872     pre = static_cast<int>(src->mSize * src->mChannel);
873     post = static_cast<int>(src->mSize * (src->mSkip - src->mChannel - 1));
874     skip = 0;
875     for(i = 0;i < n;i++)
876     {
877         skip += pre;
878         if(skip > 0)
879             istream.seekg(skip, std::ios::cur);
880         if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
881             return 0;
882         skip = post;
883     }
884     if(skip > 0)
885         istream.seekg(skip, std::ios::cur);
886     return 1;
887 }
888
889 // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to
890 // doubles.
891 static int ReadWaveList(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
892     const uint n, double *hrir)
893 {
894     uint32_t fourCC, chunkSize, listSize, count;
895     uint block, skip, offset, i;
896     double lastSample;
897
898     for(;;)
899     {
900         if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
901             || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
902             return 0;
903
904         if(fourCC == FOURCC_DATA)
905         {
906             block = src->mSize * src->mSkip;
907             count = chunkSize / block;
908             if(count < (src->mOffset + n))
909             {
910                 fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
911                 return 0;
912             }
913             istream.seekg(static_cast<long>(src->mOffset * block), std::ios::cur);
914             if(!ReadWaveData(istream, src, order, n, &hrir[0]))
915                 return 0;
916             return 1;
917         }
918         else if(fourCC == FOURCC_LIST)
919         {
920             if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
921                 return 0;
922             chunkSize -= 4;
923             if(fourCC == FOURCC_WAVL)
924                 break;
925         }
926         if(chunkSize > 0)
927             istream.seekg(static_cast<long>(chunkSize), std::ios::cur);
928     }
929     listSize = chunkSize;
930     block = src->mSize * src->mSkip;
931     skip = src->mOffset;
932     offset = 0;
933     lastSample = 0.0;
934     while(offset < n && listSize > 8)
935     {
936         if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
937             || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
938             return 0;
939         listSize -= 8 + chunkSize;
940         if(fourCC == FOURCC_DATA)
941         {
942             count = chunkSize / block;
943             if(count > skip)
944             {
945                 istream.seekg(static_cast<long>(skip * block), std::ios::cur);
946                 chunkSize -= skip * block;
947                 count -= skip;
948                 skip = 0;
949                 if(count > (n - offset))
950                     count = n - offset;
951                 if(!ReadWaveData(istream, src, order, count, &hrir[offset]))
952                     return 0;
953                 chunkSize -= count * block;
954                 offset += count;
955                 lastSample = hrir[offset - 1];
956             }
957             else
958             {
959                 skip -= count;
960                 count = 0;
961             }
962         }
963         else if(fourCC == FOURCC_SLNT)
964         {
965             if(!ReadBin4(istream, src->mPath, order, 4, &count))
966                 return 0;
967             chunkSize -= 4;
968             if(count > skip)
969             {
970                 count -= skip;
971                 skip = 0;
972                 if(count > (n - offset))
973                     count = n - offset;
974                 for(i = 0; i < count; i ++)
975                     hrir[offset + i] = lastSample;
976                 offset += count;
977             }
978             else
979             {
980                 skip -= count;
981                 count = 0;
982             }
983         }
984         if(chunkSize > 0)
985             istream.seekg(static_cast<long>(chunkSize), std::ios::cur);
986     }
987     if(offset < n)
988     {
989         fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
990         return 0;
991     }
992     return 1;
993 }
994
995 // Load a source HRIR from an ASCII text file containing a list of elements
996 // separated by whitespace or common list operators (',', ';', ':', '|').
997 static int LoadAsciiSource(std::istream &istream, const SourceRefT *src,
998     const uint n, double *hrir)
999 {
1000     TokenReaderT tr{istream};
1001     uint i, j;
1002     double dummy;
1003
1004     TrSetup(nullptr, 0, nullptr, &tr);
1005     for(i = 0;i < src->mOffset;i++)
1006     {
1007         if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
1008             return 0;
1009     }
1010     for(i = 0;i < n;i++)
1011     {
1012         if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &hrir[i]))
1013             return 0;
1014         for(j = 0;j < src->mSkip;j++)
1015         {
1016             if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
1017                 return 0;
1018         }
1019     }
1020     return 1;
1021 }
1022
1023 // Load a source HRIR from a binary file.
1024 static int LoadBinarySource(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
1025     const uint n, double *hrir)
1026 {
1027     istream.seekg(static_cast<long>(src->mOffset), std::ios::beg);
1028     for(uint i{0};i < n;i++)
1029     {
1030         if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
1031             return 0;
1032         if(src->mSkip > 0)
1033             istream.seekg(static_cast<long>(src->mSkip), std::ios::cur);
1034     }
1035     return 1;
1036 }
1037
1038 // Load a source HRIR from a RIFF/RIFX WAVE file.
1039 static int LoadWaveSource(std::istream &istream, SourceRefT *src, const uint hrirRate,
1040     const uint n, double *hrir)
1041 {
1042     uint32_t fourCC, dummy;
1043     ByteOrderT order;
1044
1045     if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
1046         || !ReadBin4(istream, src->mPath, BO_LITTLE, 4, &dummy))
1047         return 0;
1048     if(fourCC == FOURCC_RIFF)
1049         order = BO_LITTLE;
1050     else if(fourCC == FOURCC_RIFX)
1051         order = BO_BIG;
1052     else
1053     {
1054         fprintf(stderr, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src->mPath);
1055         return 0;
1056     }
1057
1058     if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
1059         return 0;
1060     if(fourCC != FOURCC_WAVE)
1061     {
1062         fprintf(stderr, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath);
1063         return 0;
1064     }
1065     if(!ReadWaveFormat(istream, order, hrirRate, src))
1066         return 0;
1067     if(!ReadWaveList(istream, src, order, n, hrir))
1068         return 0;
1069     return 1;
1070 }
1071
1072
1073
1074 // Load a Spatially Oriented Format for Accoustics (SOFA) file.
1075 static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uint n)
1076 {
1077     struct MYSOFA_EASY *sofa{mysofa_cache_lookup(src->mPath, static_cast<float>(hrirRate))};
1078     if(sofa) return sofa;
1079
1080     sofa = static_cast<MYSOFA_EASY*>(calloc(1, sizeof(*sofa)));
1081     if(sofa == nullptr)
1082     {
1083         fprintf(stderr, "\nError:  Out of memory.\n");
1084         return nullptr;
1085     }
1086     sofa->lookup = nullptr;
1087     sofa->neighborhood = nullptr;
1088
1089     int err;
1090     sofa->hrtf = mysofa_load(src->mPath, &err);
1091     if(!sofa->hrtf)
1092     {
1093         mysofa_close(sofa);
1094         fprintf(stderr, "\nError: Could not load source file '%s'.\n", src->mPath);
1095         return nullptr;
1096     }
1097     /* NOTE: Some valid SOFA files are failing this check. */
1098     err = mysofa_check(sofa->hrtf);
1099     if(err != MYSOFA_OK)
1100         fprintf(stderr, "\nWarning: Supposedly malformed source file '%s'.\n", src->mPath);
1101     if((src->mOffset + n) > sofa->hrtf->N)
1102     {
1103         mysofa_close(sofa);
1104         fprintf(stderr, "\nError: Not enough samples in SOFA file '%s'.\n", src->mPath);
1105         return nullptr;
1106     }
1107     if(src->mChannel >= sofa->hrtf->R)
1108     {
1109         mysofa_close(sofa);
1110         fprintf(stderr, "\nError: Missing source receiver in SOFA file '%s'.\n", src->mPath);
1111         return nullptr;
1112     }
1113     mysofa_tocartesian(sofa->hrtf);
1114     sofa->lookup = mysofa_lookup_init(sofa->hrtf);
1115     if(sofa->lookup == nullptr)
1116     {
1117         mysofa_close(sofa);
1118         fprintf(stderr, "\nError:  Out of memory.\n");
1119         return nullptr;
1120     }
1121     return mysofa_cache_store(sofa, src->mPath, static_cast<float>(hrirRate));
1122 }
1123
1124 // Copies the HRIR data from a particular SOFA measurement.
1125 static void ExtractSofaHrir(const MYSOFA_EASY *sofa, const uint index, const uint channel, const uint offset, const uint n, double *hrir)
1126 {
1127     for(uint i{0u};i < n;i++)
1128         hrir[i] = sofa->hrtf->DataIR.values[(index*sofa->hrtf->R + channel)*sofa->hrtf->N + offset + i];
1129 }
1130
1131 // Load a source HRIR from a Spatially Oriented Format for Accoustics (SOFA)
1132 // file.
1133 static int LoadSofaSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1134 {
1135     struct MYSOFA_EASY *sofa;
1136     float target[3];
1137     int nearest;
1138     float *coords;
1139
1140     sofa = LoadSofaFile(src, hrirRate, n);
1141     if(sofa == nullptr)
1142         return 0;
1143
1144     /* NOTE: At some point it may be benficial or necessary to consider the
1145              various coordinate systems, listener/source orientations, and
1146              direciontal vectors defined in the SOFA file.
1147     */
1148     target[0] = static_cast<float>(src->mAzimuth);
1149     target[1] = static_cast<float>(src->mElevation);
1150     target[2] = static_cast<float>(src->mRadius);
1151     mysofa_s2c(target);
1152
1153     nearest = mysofa_lookup(sofa->lookup, target);
1154     if(nearest < 0)
1155     {
1156         fprintf(stderr, "\nError: Lookup failed in source file '%s'.\n", src->mPath);
1157         return 0;
1158     }
1159
1160     coords = &sofa->hrtf->SourcePosition.values[3 * nearest];
1161     if(std::abs(coords[0] - target[0]) > 0.001 || std::abs(coords[1] - target[1]) > 0.001 || std::abs(coords[2] - target[2]) > 0.001)
1162     {
1163         fprintf(stderr, "\nError: No impulse response at coordinates (%.3fr, %.1fev, %.1faz) in file '%s'.\n", src->mRadius, src->mElevation, src->mAzimuth, src->mPath);
1164         target[0] = coords[0];
1165         target[1] = coords[1];
1166         target[2] = coords[2];
1167         mysofa_c2s(target);
1168         fprintf(stderr, "       Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target[2], target[1], target[0]);
1169         return 0;
1170     }
1171
1172     ExtractSofaHrir(sofa, static_cast<uint>(nearest), src->mChannel, src->mOffset, n, hrir);
1173
1174     return 1;
1175 }
1176
1177 // Load a source HRIR from a supported file type.
1178 static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1179 {
1180     std::unique_ptr<al::ifstream> istream;
1181     if(src->mFormat != SF_SOFA)
1182     {
1183         if(src->mFormat == SF_ASCII)
1184             istream.reset(new al::ifstream{src->mPath});
1185         else
1186             istream.reset(new al::ifstream{src->mPath, std::ios::binary});
1187         if(!istream->good())
1188         {
1189             fprintf(stderr, "\nError: Could not open source file '%s'.\n", src->mPath);
1190             return 0;
1191         }
1192     }
1193     int result{0};
1194     switch(src->mFormat)
1195     {
1196         case SF_ASCII:
1197             result = LoadAsciiSource(*istream, src, n, hrir);
1198             break;
1199         case SF_BIN_LE:
1200             result = LoadBinarySource(*istream, src, BO_LITTLE, n, hrir);
1201             break;
1202         case SF_BIN_BE:
1203             result = LoadBinarySource(*istream, src, BO_BIG, n, hrir);
1204             break;
1205         case SF_WAVE:
1206             result = LoadWaveSource(*istream, src, hrirRate, n, hrir);
1207             break;
1208         case SF_SOFA:
1209             result = LoadSofaSource(src, hrirRate, n, hrir);
1210             break;
1211         case SF_NONE:
1212             break;
1213     }
1214     return result;
1215 }
1216
1217
1218 // Match the channel type from a given identifier.
1219 static ChannelTypeT MatchChannelType(const char *ident)
1220 {
1221     if(al::strcasecmp(ident, "mono") == 0)
1222         return CT_MONO;
1223     if(al::strcasecmp(ident, "stereo") == 0)
1224         return CT_STEREO;
1225     return CT_NONE;
1226 }
1227
1228
1229 // Process the data set definition to read and validate the data set metrics.
1230 static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint truncSize, const ChannelModeT chanMode, HrirDataT *hData)
1231 {
1232     int hasRate = 0, hasType = 0, hasPoints = 0, hasRadius = 0;
1233     int hasDistance = 0, hasAzimuths = 0;
1234     char ident[MAX_IDENT_LEN+1];
1235     uint line, col;
1236     double fpVal;
1237     uint points;
1238     int intVal;
1239     double distances[MAX_FD_COUNT];
1240     uint fdCount = 0;
1241     uint evCounts[MAX_FD_COUNT];
1242     auto azCounts = std::vector<std::array<uint,MAX_EV_COUNT>>(MAX_FD_COUNT);
1243     for(auto &azs : azCounts) azs.fill(0u);
1244
1245     TrIndication(tr, &line, &col);
1246     while(TrIsIdent(tr))
1247     {
1248         TrIndication(tr, &line, &col);
1249         if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1250             return 0;
1251         if(al::strcasecmp(ident, "rate") == 0)
1252         {
1253             if(hasRate)
1254             {
1255                 TrErrorAt(tr, line, col, "Redefinition of 'rate'.\n");
1256                 return 0;
1257             }
1258             if(!TrReadOperator(tr, "="))
1259                 return 0;
1260             if(!TrReadInt(tr, MIN_RATE, MAX_RATE, &intVal))
1261                 return 0;
1262             hData->mIrRate = static_cast<uint>(intVal);
1263             hasRate = 1;
1264         }
1265         else if(al::strcasecmp(ident, "type") == 0)
1266         {
1267             char type[MAX_IDENT_LEN+1];
1268
1269             if(hasType)
1270             {
1271                 TrErrorAt(tr, line, col, "Redefinition of 'type'.\n");
1272                 return 0;
1273             }
1274             if(!TrReadOperator(tr, "="))
1275                 return 0;
1276
1277             if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1278                 return 0;
1279             hData->mChannelType = MatchChannelType(type);
1280             if(hData->mChannelType == CT_NONE)
1281             {
1282                 TrErrorAt(tr, line, col, "Expected a channel type.\n");
1283                 return 0;
1284             }
1285             else if(hData->mChannelType == CT_STEREO)
1286             {
1287                 if(chanMode == CM_ForceMono)
1288                     hData->mChannelType = CT_MONO;
1289             }
1290             hasType = 1;
1291         }
1292         else if(al::strcasecmp(ident, "points") == 0)
1293         {
1294             if(hasPoints)
1295             {
1296                 TrErrorAt(tr, line, col, "Redefinition of 'points'.\n");
1297                 return 0;
1298             }
1299             if(!TrReadOperator(tr, "="))
1300                 return 0;
1301             TrIndication(tr, &line, &col);
1302             if(!TrReadInt(tr, MIN_POINTS, MAX_POINTS, &intVal))
1303                 return 0;
1304             points = static_cast<uint>(intVal);
1305             if(fftSize > 0 && points > fftSize)
1306             {
1307                 TrErrorAt(tr, line, col, "Value exceeds the overridden FFT size.\n");
1308                 return 0;
1309             }
1310             if(points < truncSize)
1311             {
1312                 TrErrorAt(tr, line, col, "Value is below the truncation size.\n");
1313                 return 0;
1314             }
1315             hData->mIrPoints = points;
1316             hData->mFftSize = fftSize;
1317             hData->mIrSize = 1 + (fftSize / 2);
1318             if(points > hData->mIrSize)
1319                 hData->mIrSize = points;
1320             hasPoints = 1;
1321         }
1322         else if(al::strcasecmp(ident, "radius") == 0)
1323         {
1324             if(hasRadius)
1325             {
1326                 TrErrorAt(tr, line, col, "Redefinition of 'radius'.\n");
1327                 return 0;
1328             }
1329             if(!TrReadOperator(tr, "="))
1330                 return 0;
1331             if(!TrReadFloat(tr, MIN_RADIUS, MAX_RADIUS, &fpVal))
1332                 return 0;
1333             hData->mRadius = fpVal;
1334             hasRadius = 1;
1335         }
1336         else if(al::strcasecmp(ident, "distance") == 0)
1337         {
1338             uint count = 0;
1339
1340             if(hasDistance)
1341             {
1342                 TrErrorAt(tr, line, col, "Redefinition of 'distance'.\n");
1343                 return 0;
1344             }
1345             if(!TrReadOperator(tr, "="))
1346                 return 0;
1347
1348             for(;;)
1349             {
1350                 if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, &fpVal))
1351                     return 0;
1352                 if(count > 0 && fpVal <= distances[count - 1])
1353                 {
1354                     TrError(tr, "Distances are not ascending.\n");
1355                     return 0;
1356                 }
1357                 distances[count++] = fpVal;
1358                 if(!TrIsOperator(tr, ","))
1359                     break;
1360                 if(count >= MAX_FD_COUNT)
1361                 {
1362                     TrError(tr, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT);
1363                     return 0;
1364                 }
1365                 TrReadOperator(tr, ",");
1366             }
1367             if(fdCount != 0 && count != fdCount)
1368             {
1369                 TrError(tr, "Did not match the specified number of %d fields.\n", fdCount);
1370                 return 0;
1371             }
1372             fdCount = count;
1373             hasDistance = 1;
1374         }
1375         else if(al::strcasecmp(ident, "azimuths") == 0)
1376         {
1377             uint count = 0;
1378
1379             if(hasAzimuths)
1380             {
1381                 TrErrorAt(tr, line, col, "Redefinition of 'azimuths'.\n");
1382                 return 0;
1383             }
1384             if(!TrReadOperator(tr, "="))
1385                 return 0;
1386
1387             evCounts[0] = 0;
1388             for(;;)
1389             {
1390                 if(!TrReadInt(tr, MIN_AZ_COUNT, MAX_AZ_COUNT, &intVal))
1391                     return 0;
1392                 azCounts[count][evCounts[count]++] = static_cast<uint>(intVal);
1393                 if(TrIsOperator(tr, ","))
1394                 {
1395                     if(evCounts[count] >= MAX_EV_COUNT)
1396                     {
1397                         TrError(tr, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT);
1398                         return 0;
1399                     }
1400                     TrReadOperator(tr, ",");
1401                 }
1402                 else
1403                 {
1404                     if(evCounts[count] < MIN_EV_COUNT)
1405                     {
1406                         TrErrorAt(tr, line, col, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT);
1407                         return 0;
1408                     }
1409                     if(azCounts[count][0] != 1 || azCounts[count][evCounts[count] - 1] != 1)
1410                     {
1411                         TrError(tr, "Poles are not singular for field %d.\n", count - 1);
1412                         return 0;
1413                     }
1414                     count++;
1415                     if(!TrIsOperator(tr, ";"))
1416                         break;
1417
1418                     if(count >= MAX_FD_COUNT)
1419                     {
1420                         TrError(tr, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT);
1421                         return 0;
1422                     }
1423                     evCounts[count] = 0;
1424                     TrReadOperator(tr, ";");
1425                 }
1426             }
1427             if(fdCount != 0 && count != fdCount)
1428             {
1429                 TrError(tr, "Did not match the specified number of %d fields.\n", fdCount);
1430                 return 0;
1431             }
1432             fdCount = count;
1433             hasAzimuths = 1;
1434         }
1435         else
1436         {
1437             TrErrorAt(tr, line, col, "Expected a metric name.\n");
1438             return 0;
1439         }
1440         TrSkipWhitespace(tr);
1441     }
1442     if(!(hasRate && hasPoints && hasRadius && hasDistance && hasAzimuths))
1443     {
1444         TrErrorAt(tr, line, col, "Expected a metric name.\n");
1445         return 0;
1446     }
1447     if(distances[0] < hData->mRadius)
1448     {
1449         TrError(tr, "Distance cannot start below head radius.\n");
1450         return 0;
1451     }
1452     if(hData->mChannelType == CT_NONE)
1453         hData->mChannelType = CT_MONO;
1454     const auto azs = al::as_span(azCounts).first<MAX_FD_COUNT>();
1455     if(!PrepareHrirData({distances, fdCount}, evCounts, azs, hData))
1456     {
1457         fprintf(stderr, "Error:  Out of memory.\n");
1458         exit(-1);
1459     }
1460     return 1;
1461 }
1462
1463 // Parse an index triplet from the data set definition.
1464 static int ReadIndexTriplet(TokenReaderT *tr, const HrirDataT *hData, uint *fi, uint *ei, uint *ai)
1465 {
1466     int intVal;
1467
1468     if(hData->mFds.size() > 1)
1469     {
1470         if(!TrReadInt(tr, 0, static_cast<int>(hData->mFds.size()-1), &intVal))
1471             return 0;
1472         *fi = static_cast<uint>(intVal);
1473         if(!TrReadOperator(tr, ","))
1474             return 0;
1475     }
1476     else
1477     {
1478         *fi = 0;
1479     }
1480     if(!TrReadInt(tr, 0, static_cast<int>(hData->mFds[*fi].mEvs.size()-1), &intVal))
1481         return 0;
1482     *ei = static_cast<uint>(intVal);
1483     if(!TrReadOperator(tr, ","))
1484         return 0;
1485     if(!TrReadInt(tr, 0, static_cast<int>(hData->mFds[*fi].mEvs[*ei].mAzs.size()-1), &intVal))
1486         return 0;
1487     *ai = static_cast<uint>(intVal);
1488     return 1;
1489 }
1490
1491 // Match the source format from a given identifier.
1492 static SourceFormatT MatchSourceFormat(const char *ident)
1493 {
1494     if(al::strcasecmp(ident, "ascii") == 0)
1495         return SF_ASCII;
1496     if(al::strcasecmp(ident, "bin_le") == 0)
1497         return SF_BIN_LE;
1498     if(al::strcasecmp(ident, "bin_be") == 0)
1499         return SF_BIN_BE;
1500     if(al::strcasecmp(ident, "wave") == 0)
1501         return SF_WAVE;
1502     if(al::strcasecmp(ident, "sofa") == 0)
1503         return SF_SOFA;
1504     return SF_NONE;
1505 }
1506
1507 // Match the source element type from a given identifier.
1508 static ElementTypeT MatchElementType(const char *ident)
1509 {
1510     if(al::strcasecmp(ident, "int") == 0)
1511         return ET_INT;
1512     if(al::strcasecmp(ident, "fp") == 0)
1513         return ET_FP;
1514     return ET_NONE;
1515 }
1516
1517 // Parse and validate a source reference from the data set definition.
1518 static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
1519 {
1520     char ident[MAX_IDENT_LEN+1];
1521     uint line, col;
1522     double fpVal;
1523     int intVal;
1524
1525     TrIndication(tr, &line, &col);
1526     if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1527         return 0;
1528     src->mFormat = MatchSourceFormat(ident);
1529     if(src->mFormat == SF_NONE)
1530     {
1531         TrErrorAt(tr, line, col, "Expected a source format.\n");
1532         return 0;
1533     }
1534     if(!TrReadOperator(tr, "("))
1535         return 0;
1536     if(src->mFormat == SF_SOFA)
1537     {
1538         if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, &fpVal))
1539             return 0;
1540         src->mRadius = fpVal;
1541         if(!TrReadOperator(tr, ","))
1542             return 0;
1543         if(!TrReadFloat(tr, -90.0, 90.0, &fpVal))
1544             return 0;
1545         src->mElevation = fpVal;
1546         if(!TrReadOperator(tr, ","))
1547             return 0;
1548         if(!TrReadFloat(tr, -360.0, 360.0, &fpVal))
1549             return 0;
1550         src->mAzimuth = fpVal;
1551         if(!TrReadOperator(tr, ":"))
1552             return 0;
1553         if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
1554             return 0;
1555         src->mType = ET_NONE;
1556         src->mSize = 0;
1557         src->mBits = 0;
1558         src->mChannel = static_cast<uint>(intVal);
1559         src->mSkip = 0;
1560     }
1561     else if(src->mFormat == SF_WAVE)
1562     {
1563         if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
1564             return 0;
1565         src->mType = ET_NONE;
1566         src->mSize = 0;
1567         src->mBits = 0;
1568         src->mChannel = static_cast<uint>(intVal);
1569         src->mSkip = 0;
1570     }
1571     else
1572     {
1573         TrIndication(tr, &line, &col);
1574         if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1575             return 0;
1576         src->mType = MatchElementType(ident);
1577         if(src->mType == ET_NONE)
1578         {
1579             TrErrorAt(tr, line, col, "Expected a source element type.\n");
1580             return 0;
1581         }
1582         if(src->mFormat == SF_BIN_LE || src->mFormat == SF_BIN_BE)
1583         {
1584             if(!TrReadOperator(tr, ","))
1585                 return 0;
1586             if(src->mType == ET_INT)
1587             {
1588                 if(!TrReadInt(tr, MIN_BIN_SIZE, MAX_BIN_SIZE, &intVal))
1589                     return 0;
1590                 src->mSize = static_cast<uint>(intVal);
1591                 if(!TrIsOperator(tr, ","))
1592                     src->mBits = static_cast<int>(8*src->mSize);
1593                 else
1594                 {
1595                     TrReadOperator(tr, ",");
1596                     TrIndication(tr, &line, &col);
1597                     if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
1598                         return 0;
1599                     if(std::abs(intVal) < MIN_BIN_BITS || static_cast<uint>(std::abs(intVal)) > (8*src->mSize))
1600                     {
1601                         TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8*src->mSize);
1602                         return 0;
1603                     }
1604                     src->mBits = intVal;
1605                 }
1606             }
1607             else
1608             {
1609                 TrIndication(tr, &line, &col);
1610                 if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
1611                     return 0;
1612                 if(intVal != 4 && intVal != 8)
1613                 {
1614                     TrErrorAt(tr, line, col, "Expected a value of 4 or 8.\n");
1615                     return 0;
1616                 }
1617                 src->mSize = static_cast<uint>(intVal);
1618                 src->mBits = 0;
1619             }
1620         }
1621         else if(src->mFormat == SF_ASCII && src->mType == ET_INT)
1622         {
1623             if(!TrReadOperator(tr, ","))
1624                 return 0;
1625             if(!TrReadInt(tr, MIN_ASCII_BITS, MAX_ASCII_BITS, &intVal))
1626                 return 0;
1627             src->mSize = 0;
1628             src->mBits = intVal;
1629         }
1630         else
1631         {
1632             src->mSize = 0;
1633             src->mBits = 0;
1634         }
1635
1636         if(!TrIsOperator(tr, ";"))
1637             src->mSkip = 0;
1638         else
1639         {
1640             TrReadOperator(tr, ";");
1641             if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1642                 return 0;
1643             src->mSkip = static_cast<uint>(intVal);
1644         }
1645     }
1646     if(!TrReadOperator(tr, ")"))
1647         return 0;
1648     if(TrIsOperator(tr, "@"))
1649     {
1650         TrReadOperator(tr, "@");
1651         if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1652             return 0;
1653         src->mOffset = static_cast<uint>(intVal);
1654     }
1655     else
1656         src->mOffset = 0;
1657     if(!TrReadOperator(tr, ":"))
1658         return 0;
1659     if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
1660         return 0;
1661     return 1;
1662 }
1663
1664 // Parse and validate a SOFA source reference from the data set definition.
1665 static int ReadSofaRef(TokenReaderT *tr, SourceRefT *src)
1666 {
1667     char ident[MAX_IDENT_LEN+1];
1668     uint line, col;
1669     int intVal;
1670
1671     TrIndication(tr, &line, &col);
1672     if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1673         return 0;
1674     src->mFormat = MatchSourceFormat(ident);
1675     if(src->mFormat != SF_SOFA)
1676     {
1677         TrErrorAt(tr, line, col, "Expected the SOFA source format.\n");
1678         return 0;
1679     }
1680
1681     src->mType = ET_NONE;
1682     src->mSize = 0;
1683     src->mBits = 0;
1684     src->mChannel = 0;
1685     src->mSkip = 0;
1686
1687     if(TrIsOperator(tr, "@"))
1688     {
1689         TrReadOperator(tr, "@");
1690         if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1691             return 0;
1692         src->mOffset = static_cast<uint>(intVal);
1693     }
1694     else
1695         src->mOffset = 0;
1696     if(!TrReadOperator(tr, ":"))
1697         return 0;
1698     if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
1699         return 0;
1700     return 1;
1701 }
1702
1703 // Match the target ear (index) from a given identifier.
1704 static int MatchTargetEar(const char *ident)
1705 {
1706     if(al::strcasecmp(ident, "left") == 0)
1707         return 0;
1708     if(al::strcasecmp(ident, "right") == 0)
1709         return 1;
1710     return -1;
1711 }
1712
1713 // Calculate the onset time of an HRIR and average it with any existing
1714 // timing for its field, elevation, azimuth, and ear.
1715 static constexpr int OnsetRateMultiple{10};
1716 static double AverageHrirOnset(PPhaseResampler &rs, al::span<double> upsampled, const uint rate,
1717     const uint n, const double *hrir, const double f, const double onset)
1718 {
1719     rs.process(n, hrir, static_cast<uint>(upsampled.size()), upsampled.data());
1720
1721     auto abs_lt = [](const double &lhs, const double &rhs) -> bool
1722     { return std::abs(lhs) < std::abs(rhs); };
1723     auto iter = std::max_element(upsampled.cbegin(), upsampled.cend(), abs_lt);
1724     return Lerp(onset, static_cast<double>(std::distance(upsampled.cbegin(), iter))/(10*rate), f);
1725 }
1726
1727 // Calculate the magnitude response of an HRIR and average it with any
1728 // existing responses for its field, elevation, azimuth, and ear.
1729 static void AverageHrirMagnitude(const uint points, const uint n, const double *hrir, const double f, double *mag)
1730 {
1731     uint m = 1 + (n / 2), i;
1732     std::vector<complex_d> h(n);
1733     std::vector<double> r(n);
1734
1735     for(i = 0;i < points;i++)
1736         h[i] = hrir[i];
1737     for(;i < n;i++)
1738         h[i] = 0.0;
1739     FftForward(n, h.data());
1740     MagnitudeResponse(n, h.data(), r.data());
1741     for(i = 0;i < m;i++)
1742         mag[i] = Lerp(mag[i], r[i], f);
1743 }
1744
1745 // Process the list of sources in the data set definition.
1746 static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate)
1747 {
1748     const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
1749     hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize);
1750     double *hrirs = hData->mHrirsBase.data();
1751     auto hrir = std::make_unique<double[]>(hData->mIrSize);
1752     uint line, col, fi, ei, ai;
1753
1754     std::vector<double> onsetSamples(OnsetRateMultiple * hData->mIrPoints);
1755     PPhaseResampler onsetResampler;
1756     onsetResampler.init(hData->mIrRate, OnsetRateMultiple*hData->mIrRate);
1757
1758     al::optional<PPhaseResampler> resampler;
1759     if(outRate && outRate != hData->mIrRate)
1760         resampler.emplace().init(hData->mIrRate, outRate);
1761     const double rateScale{outRate ? static_cast<double>(outRate) / hData->mIrRate : 1.0};
1762     const uint irPoints{outRate
1763         ? std::min(static_cast<uint>(std::ceil(hData->mIrPoints*rateScale)), hData->mIrPoints)
1764         : hData->mIrPoints};
1765
1766     printf("Loading sources...");
1767     fflush(stdout);
1768     int count{0};
1769     while(TrIsOperator(tr, "["))
1770     {
1771         double factor[2]{ 1.0, 1.0 };
1772
1773         TrIndication(tr, &line, &col);
1774         TrReadOperator(tr, "[");
1775
1776         if(TrIsOperator(tr, "*"))
1777         {
1778             SourceRefT src;
1779             struct MYSOFA_EASY *sofa;
1780             uint si;
1781
1782             TrReadOperator(tr, "*");
1783             if(!TrReadOperator(tr, "]") || !TrReadOperator(tr, "="))
1784                 return 0;
1785
1786             TrIndication(tr, &line, &col);
1787             if(!ReadSofaRef(tr, &src))
1788                 return 0;
1789
1790             if(hData->mChannelType == CT_STEREO)
1791             {
1792                 char type[MAX_IDENT_LEN+1];
1793                 ChannelTypeT channelType;
1794
1795                 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1796                     return 0;
1797
1798                 channelType = MatchChannelType(type);
1799
1800                 switch(channelType)
1801                 {
1802                     case CT_NONE:
1803                         TrErrorAt(tr, line, col, "Expected a channel type.\n");
1804                         return 0;
1805                     case CT_MONO:
1806                         src.mChannel = 0;
1807                         break;
1808                     case CT_STEREO:
1809                         src.mChannel = 1;
1810                         break;
1811                 }
1812             }
1813             else
1814             {
1815                 char type[MAX_IDENT_LEN+1];
1816                 ChannelTypeT channelType;
1817
1818                 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1819                     return 0;
1820
1821                 channelType = MatchChannelType(type);
1822                 if(channelType != CT_MONO)
1823                 {
1824                     TrErrorAt(tr, line, col, "Expected a mono channel type.\n");
1825                     return 0;
1826                 }
1827                 src.mChannel = 0;
1828             }
1829
1830             sofa = LoadSofaFile(&src, hData->mIrRate, hData->mIrPoints);
1831             if(!sofa) return 0;
1832
1833             for(si = 0;si < sofa->hrtf->M;si++)
1834             {
1835                 printf("\rLoading sources... %d of %d", si+1, sofa->hrtf->M);
1836                 fflush(stdout);
1837
1838                 float aer[3] = {
1839                     sofa->hrtf->SourcePosition.values[3*si],
1840                     sofa->hrtf->SourcePosition.values[3*si + 1],
1841                     sofa->hrtf->SourcePosition.values[3*si + 2]
1842                 };
1843                 mysofa_c2s(aer);
1844
1845                 if(std::fabs(aer[1]) >= 89.999f)
1846                     aer[0] = 0.0f;
1847                 else
1848                     aer[0] = std::fmod(360.0f - aer[0], 360.0f);
1849
1850                 auto field = std::find_if(hData->mFds.cbegin(), hData->mFds.cend(),
1851                     [&aer](const HrirFdT &fld) -> bool
1852                     { return (std::abs(aer[2] - fld.mDistance) < 0.001); });
1853                 if(field == hData->mFds.cend())
1854                     continue;
1855                 fi = static_cast<uint>(std::distance(hData->mFds.cbegin(), field));
1856
1857                 const double evscale{180.0 / static_cast<double>(field->mEvs.size()-1)};
1858                 double ef{(90.0 + aer[1]) / evscale};
1859                 ei = static_cast<uint>(std::round(ef));
1860                 ef = (ef - ei) * evscale;
1861                 if(std::abs(ef) >= 0.1)
1862                     continue;
1863
1864                 const double azscale{360.0 / static_cast<double>(field->mEvs[ei].mAzs.size())};
1865                 double af{aer[0] / azscale};
1866                 ai = static_cast<uint>(std::round(af));
1867                 af = (af - ai) * azscale;
1868                 ai %= static_cast<uint>(field->mEvs[ei].mAzs.size());
1869                 if(std::abs(af) >= 0.1)
1870                     continue;
1871
1872                 HrirAzT *azd = &field->mEvs[ei].mAzs[ai];
1873                 if(azd->mIrs[0] != nullptr)
1874                 {
1875                     TrErrorAt(tr, line, col, "Redefinition of source [ %d, %d, %d ].\n", fi, ei, ai);
1876                     return 0;
1877                 }
1878
1879                 ExtractSofaHrir(sofa, si, 0, src.mOffset, hData->mIrPoints, hrir.get());
1880                 azd->mIrs[0] = &hrirs[hData->mIrSize * azd->mIndex];
1881                 azd->mDelays[0] = AverageHrirOnset(onsetResampler, onsetSamples, hData->mIrRate,
1882                     hData->mIrPoints, hrir.get(), 1.0, azd->mDelays[0]);
1883                 if(resampler)
1884                     resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize, hrir.get());
1885                 AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0, azd->mIrs[0]);
1886
1887                 if(src.mChannel == 1)
1888                 {
1889                     ExtractSofaHrir(sofa, si, 1, src.mOffset, hData->mIrPoints, hrir.get());
1890                     azd->mIrs[1] = &hrirs[hData->mIrSize * (hData->mIrCount + azd->mIndex)];
1891                     azd->mDelays[1] = AverageHrirOnset(onsetResampler, onsetSamples,
1892                         hData->mIrRate, hData->mIrPoints, hrir.get(), 1.0, azd->mDelays[1]);
1893                     if(resampler)
1894                         resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize,
1895                             hrir.get());
1896                     AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0, azd->mIrs[1]);
1897                 }
1898
1899                 // TODO: Since some SOFA files contain minimum phase HRIRs,
1900                 // it would be beneficial to check for per-measurement delays
1901                 // (when available) to reconstruct the HRTDs.
1902             }
1903
1904             continue;
1905         }
1906
1907         if(!ReadIndexTriplet(tr, hData, &fi, &ei, &ai))
1908             return 0;
1909         if(!TrReadOperator(tr, "]"))
1910             return 0;
1911         HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1912
1913         if(azd->mIrs[0] != nullptr)
1914         {
1915             TrErrorAt(tr, line, col, "Redefinition of source.\n");
1916             return 0;
1917         }
1918         if(!TrReadOperator(tr, "="))
1919             return 0;
1920
1921         for(;;)
1922         {
1923             SourceRefT src;
1924
1925             if(!ReadSourceRef(tr, &src))
1926                 return 0;
1927
1928             // TODO: Would be nice to display 'x of y files', but that would
1929             // require preparing the source refs first to get a total count
1930             // before loading them.
1931             ++count;
1932             printf("\rLoading sources... %d file%s", count, (count==1)?"":"s");
1933             fflush(stdout);
1934
1935             if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.get()))
1936                 return 0;
1937
1938             uint ti{0};
1939             if(hData->mChannelType == CT_STEREO)
1940             {
1941                 char ident[MAX_IDENT_LEN+1];
1942
1943                 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1944                     return 0;
1945                 ti = static_cast<uint>(MatchTargetEar(ident));
1946                 if(static_cast<int>(ti) < 0)
1947                 {
1948                     TrErrorAt(tr, line, col, "Expected a target ear.\n");
1949                     return 0;
1950                 }
1951             }
1952             azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
1953             azd->mDelays[ti] = AverageHrirOnset(onsetResampler, onsetSamples, hData->mIrRate,
1954                 hData->mIrPoints, hrir.get(), 1.0 / factor[ti], azd->mDelays[ti]);
1955             if(resampler)
1956                 resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize, hrir.get());
1957             AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0 / factor[ti],
1958                 azd->mIrs[ti]);
1959             factor[ti] += 1.0;
1960             if(!TrIsOperator(tr, "+"))
1961                 break;
1962             TrReadOperator(tr, "+");
1963         }
1964         if(hData->mChannelType == CT_STEREO)
1965         {
1966             if(azd->mIrs[0] == nullptr)
1967             {
1968                 TrErrorAt(tr, line, col, "Missing left ear source reference(s).\n");
1969                 return 0;
1970             }
1971             else if(azd->mIrs[1] == nullptr)
1972             {
1973                 TrErrorAt(tr, line, col, "Missing right ear source reference(s).\n");
1974                 return 0;
1975             }
1976         }
1977     }
1978     printf("\n");
1979     hrir = nullptr;
1980     if(resampler)
1981     {
1982         hData->mIrRate = outRate;
1983         hData->mIrPoints = irPoints;
1984         resampler.reset();
1985     }
1986     for(fi = 0;fi < hData->mFds.size();fi++)
1987     {
1988         for(ei = 0;ei < hData->mFds[fi].mEvs.size();ei++)
1989         {
1990             for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzs.size();ai++)
1991             {
1992                 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1993                 if(azd->mIrs[0] != nullptr)
1994                     break;
1995             }
1996             if(ai < hData->mFds[fi].mEvs[ei].mAzs.size())
1997                 break;
1998         }
1999         if(ei >= hData->mFds[fi].mEvs.size())
2000         {
2001             TrError(tr, "Missing source references [ %d, *, * ].\n", fi);
2002             return 0;
2003         }
2004         hData->mFds[fi].mEvStart = ei;
2005         for(;ei < hData->mFds[fi].mEvs.size();ei++)
2006         {
2007             for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzs.size();ai++)
2008             {
2009                 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
2010
2011                 if(azd->mIrs[0] == nullptr)
2012                 {
2013                     TrError(tr, "Missing source reference [ %d, %d, %d ].\n", fi, ei, ai);
2014                     return 0;
2015                 }
2016             }
2017         }
2018     }
2019     for(uint ti{0};ti < channels;ti++)
2020     {
2021         for(fi = 0;fi < hData->mFds.size();fi++)
2022         {
2023             for(ei = 0;ei < hData->mFds[fi].mEvs.size();ei++)
2024             {
2025                 for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzs.size();ai++)
2026                 {
2027                     HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
2028
2029                     azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
2030                 }
2031             }
2032         }
2033     }
2034     if(!TrLoad(tr))
2035     {
2036         mysofa_cache_release_all();
2037         return 1;
2038     }
2039
2040     TrError(tr, "Errant data at end of source list.\n");
2041     mysofa_cache_release_all();
2042     return 0;
2043 }
2044
2045
2046 bool LoadDefInput(std::istream &istream, const char *startbytes, std::streamsize startbytecount,
2047     const char *filename, const uint fftSize, const uint truncSize, const uint outRate,
2048     const ChannelModeT chanMode, HrirDataT *hData)
2049 {
2050     TokenReaderT tr{istream};
2051
2052     TrSetup(startbytes, startbytecount, filename, &tr);
2053     if(!ProcessMetrics(&tr, fftSize, truncSize, chanMode, hData)
2054         || !ProcessSources(&tr, hData, outRate))
2055         return false;
2056
2057     return true;
2058 }