Merge pull request #483 from jhasse/silence-nodiscard
[openal-soft.git] / utils / makemhr / loaddef.cpp
blobd325eda1492bf6fbb7971caca01d19ed8964922a
1 /*
2 * HRTF utility for producing and demonstrating the process of creating an
3 * OpenAL Soft compatible HRIR data set.
5 * Copyright (C) 2011-2019 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
24 #include "loaddef.h"
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>
39 #include "alfstream.h"
40 #include "alstring.h"
41 #include "makemhr.h"
43 #include "mysofa.h"
45 // Constants for accessing the token reader's ring buffer.
46 #define TR_RING_BITS (16)
47 #define TR_RING_SIZE (1 << TR_RING_BITS)
48 #define TR_RING_MASK (TR_RING_SIZE - 1)
50 // The token reader's load interval in bytes.
51 #define TR_LOAD_SIZE (TR_RING_SIZE >> 2)
53 // Token reader state for parsing the data set definition.
54 struct TokenReaderT {
55 std::istream &mIStream;
56 const char *mName{};
57 uint mLine{};
58 uint mColumn{};
59 char mRing[TR_RING_SIZE]{};
60 std::streamsize mIn{};
61 std::streamsize mOut{};
63 TokenReaderT(std::istream &istream) noexcept : mIStream{istream} { }
64 TokenReaderT(const TokenReaderT&) = default;
68 // The maximum identifier length used when processing the data set
69 // definition.
70 #define MAX_IDENT_LEN (16)
72 // The limits for the listener's head 'radius' in the data set definition.
73 #define MIN_RADIUS (0.05)
74 #define MAX_RADIUS (0.15)
76 // The maximum number of channels that can be addressed for a WAVE file
77 // source listed in the data set definition.
78 #define MAX_WAVE_CHANNELS (65535)
80 // The limits to the byte size for a binary source listed in the definition
81 // file.
82 #define MIN_BIN_SIZE (2)
83 #define MAX_BIN_SIZE (4)
85 // The minimum number of significant bits for binary sources listed in the
86 // data set definition. The maximum is calculated from the byte size.
87 #define MIN_BIN_BITS (16)
89 // The limits to the number of significant bits for an ASCII source listed in
90 // the data set definition.
91 #define MIN_ASCII_BITS (16)
92 #define MAX_ASCII_BITS (32)
94 // The four-character-codes for RIFF/RIFX WAVE file chunks.
95 #define FOURCC_RIFF (0x46464952) // 'RIFF'
96 #define FOURCC_RIFX (0x58464952) // 'RIFX'
97 #define FOURCC_WAVE (0x45564157) // 'WAVE'
98 #define FOURCC_FMT (0x20746D66) // 'fmt '
99 #define FOURCC_DATA (0x61746164) // 'data'
100 #define FOURCC_LIST (0x5453494C) // 'LIST'
101 #define FOURCC_WAVL (0x6C766177) // 'wavl'
102 #define FOURCC_SLNT (0x746E6C73) // 'slnt'
104 // The supported wave formats.
105 #define WAVE_FORMAT_PCM (0x0001)
106 #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
107 #define WAVE_FORMAT_EXTENSIBLE (0xFFFE)
110 enum ByteOrderT {
111 BO_NONE,
112 BO_LITTLE,
113 BO_BIG
116 // Source format for the references listed in the data set definition.
117 enum SourceFormatT {
118 SF_NONE,
119 SF_ASCII, // ASCII text file.
120 SF_BIN_LE, // Little-endian binary file.
121 SF_BIN_BE, // Big-endian binary file.
122 SF_WAVE, // RIFF/RIFX WAVE file.
123 SF_SOFA // Spatially Oriented Format for Accoustics (SOFA) file.
126 // Element types for the references listed in the data set definition.
127 enum ElementTypeT {
128 ET_NONE,
129 ET_INT, // Integer elements.
130 ET_FP // Floating-point elements.
133 // Source reference state used when loading sources.
134 struct SourceRefT {
135 SourceFormatT mFormat;
136 ElementTypeT mType;
137 uint mSize;
138 int mBits;
139 uint mChannel;
140 double mAzimuth;
141 double mElevation;
142 double mRadius;
143 uint mSkip;
144 uint mOffset;
145 char mPath[MAX_PATH_LEN+1];
149 /* Whitespace is not significant. It can process tokens as identifiers, numbers
150 * (integer and floating-point), strings, and operators. Strings must be
151 * encapsulated by double-quotes and cannot span multiple lines.
154 // Setup the reader on the given file. The filename can be NULL if no error
155 // output is desired.
156 static void TrSetup(const char *startbytes, std::streamsize startbytecount, const char *filename,
157 TokenReaderT *tr)
159 const char *name = nullptr;
161 if(filename)
163 const char *slash = strrchr(filename, '/');
164 if(slash)
166 const char *bslash = strrchr(slash+1, '\\');
167 if(bslash) name = bslash+1;
168 else name = slash+1;
170 else
172 const char *bslash = strrchr(filename, '\\');
173 if(bslash) name = bslash+1;
174 else name = filename;
178 tr->mName = name;
179 tr->mLine = 1;
180 tr->mColumn = 1;
181 tr->mIn = 0;
182 tr->mOut = 0;
184 if(startbytecount > 0)
186 std::copy_n(startbytes, startbytecount, std::begin(tr->mRing));
187 tr->mIn += startbytecount;
191 // Prime the reader's ring buffer, and return a result indicating that there
192 // is text to process.
193 static int TrLoad(TokenReaderT *tr)
195 std::istream &istream = tr->mIStream;
197 std::streamsize toLoad{TR_RING_SIZE - static_cast<std::streamsize>(tr->mIn - tr->mOut)};
198 if(toLoad >= TR_LOAD_SIZE && istream.good())
200 // Load TR_LOAD_SIZE (or less if at the end of the file) per read.
201 toLoad = TR_LOAD_SIZE;
202 std::streamsize in{tr->mIn&TR_RING_MASK};
203 std::streamsize count{TR_RING_SIZE - in};
204 if(count < toLoad)
206 istream.read(&tr->mRing[in], count);
207 tr->mIn += istream.gcount();
208 istream.read(&tr->mRing[0], toLoad-count);
209 tr->mIn += istream.gcount();
211 else
213 istream.read(&tr->mRing[in], toLoad);
214 tr->mIn += istream.gcount();
217 if(tr->mOut >= TR_RING_SIZE)
219 tr->mOut -= TR_RING_SIZE;
220 tr->mIn -= TR_RING_SIZE;
223 if(tr->mIn > tr->mOut)
224 return 1;
225 return 0;
228 // Error display routine. Only displays when the base name is not NULL.
229 static void TrErrorVA(const TokenReaderT *tr, uint line, uint column, const char *format, va_list argPtr)
231 if(!tr->mName)
232 return;
233 fprintf(stderr, "\nError (%s:%u:%u): ", tr->mName, line, column);
234 vfprintf(stderr, format, argPtr);
237 // Used to display an error at a saved line/column.
238 static void TrErrorAt(const TokenReaderT *tr, uint line, uint column, const char *format, ...)
240 va_list argPtr;
242 va_start(argPtr, format);
243 TrErrorVA(tr, line, column, format, argPtr);
244 va_end(argPtr);
247 // Used to display an error at the current line/column.
248 static void TrError(const TokenReaderT *tr, const char *format, ...)
250 va_list argPtr;
252 va_start(argPtr, format);
253 TrErrorVA(tr, tr->mLine, tr->mColumn, format, argPtr);
254 va_end(argPtr);
257 // Skips to the next line.
258 static void TrSkipLine(TokenReaderT *tr)
260 char ch;
262 while(TrLoad(tr))
264 ch = tr->mRing[tr->mOut&TR_RING_MASK];
265 tr->mOut++;
266 if(ch == '\n')
268 tr->mLine++;
269 tr->mColumn = 1;
270 break;
272 tr->mColumn ++;
276 // Skips to the next token.
277 static int TrSkipWhitespace(TokenReaderT *tr)
279 while(TrLoad(tr))
281 char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
282 if(isspace(ch))
284 tr->mOut++;
285 if(ch == '\n')
287 tr->mLine++;
288 tr->mColumn = 1;
290 else
291 tr->mColumn++;
293 else if(ch == '#')
294 TrSkipLine(tr);
295 else
296 return 1;
298 return 0;
301 // Get the line and/or column of the next token (or the end of input).
302 static void TrIndication(TokenReaderT *tr, uint *line, uint *column)
304 TrSkipWhitespace(tr);
305 if(line) *line = tr->mLine;
306 if(column) *column = tr->mColumn;
309 // Checks to see if a token is (likely to be) an identifier. It does not
310 // display any errors and will not proceed to the next token.
311 static int TrIsIdent(TokenReaderT *tr)
313 if(!TrSkipWhitespace(tr))
314 return 0;
315 char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
316 return ch == '_' || isalpha(ch);
320 // Checks to see if a token is the given operator. It does not display any
321 // errors and will not proceed to the next token.
322 static int TrIsOperator(TokenReaderT *tr, const char *op)
324 std::streamsize out;
325 size_t len;
326 char ch;
328 if(!TrSkipWhitespace(tr))
329 return 0;
330 out = tr->mOut;
331 len = 0;
332 while(op[len] != '\0' && out < tr->mIn)
334 ch = tr->mRing[out&TR_RING_MASK];
335 if(ch != op[len]) break;
336 len++;
337 out++;
339 if(op[len] == '\0')
340 return 1;
341 return 0;
344 /* The TrRead*() routines obtain the value of a matching token type. They
345 * display type, form, and boundary errors and will proceed to the next
346 * token.
349 // Reads and validates an identifier token.
350 static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident)
352 uint col, len;
353 char ch;
355 col = tr->mColumn;
356 if(TrSkipWhitespace(tr))
358 col = tr->mColumn;
359 ch = tr->mRing[tr->mOut&TR_RING_MASK];
360 if(ch == '_' || isalpha(ch))
362 len = 0;
363 do {
364 if(len < maxLen)
365 ident[len] = ch;
366 len++;
367 tr->mOut++;
368 if(!TrLoad(tr))
369 break;
370 ch = tr->mRing[tr->mOut&TR_RING_MASK];
371 } while(ch == '_' || isdigit(ch) || isalpha(ch));
373 tr->mColumn += len;
374 if(len < maxLen)
376 ident[len] = '\0';
377 return 1;
379 TrErrorAt(tr, tr->mLine, col, "Identifier is too long.\n");
380 return 0;
383 TrErrorAt(tr, tr->mLine, col, "Expected an identifier.\n");
384 return 0;
387 // Reads and validates (including bounds) an integer token.
388 static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int *value)
390 uint col, digis, len;
391 char ch, temp[64+1];
393 col = tr->mColumn;
394 if(TrSkipWhitespace(tr))
396 col = tr->mColumn;
397 len = 0;
398 ch = tr->mRing[tr->mOut&TR_RING_MASK];
399 if(ch == '+' || ch == '-')
401 temp[len] = ch;
402 len++;
403 tr->mOut++;
405 digis = 0;
406 while(TrLoad(tr))
408 ch = tr->mRing[tr->mOut&TR_RING_MASK];
409 if(!isdigit(ch)) break;
410 if(len < 64)
411 temp[len] = ch;
412 len++;
413 digis++;
414 tr->mOut++;
416 tr->mColumn += len;
417 if(digis > 0 && ch != '.' && !isalpha(ch))
419 if(len > 64)
421 TrErrorAt(tr, tr->mLine, col, "Integer is too long.");
422 return 0;
424 temp[len] = '\0';
425 *value = static_cast<int>(strtol(temp, nullptr, 10));
426 if(*value < loBound || *value > hiBound)
428 TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound);
429 return 0;
431 return 1;
434 TrErrorAt(tr, tr->mLine, col, "Expected an integer.\n");
435 return 0;
438 // Reads and validates (including bounds) a float token.
439 static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBound, double *value)
441 uint col, digis, len;
442 char ch, temp[64+1];
444 col = tr->mColumn;
445 if(TrSkipWhitespace(tr))
447 col = tr->mColumn;
448 len = 0;
449 ch = tr->mRing[tr->mOut&TR_RING_MASK];
450 if(ch == '+' || ch == '-')
452 temp[len] = ch;
453 len++;
454 tr->mOut++;
457 digis = 0;
458 while(TrLoad(tr))
460 ch = tr->mRing[tr->mOut&TR_RING_MASK];
461 if(!isdigit(ch)) break;
462 if(len < 64)
463 temp[len] = ch;
464 len++;
465 digis++;
466 tr->mOut++;
468 if(ch == '.')
470 if(len < 64)
471 temp[len] = ch;
472 len++;
473 tr->mOut++;
475 while(TrLoad(tr))
477 ch = tr->mRing[tr->mOut&TR_RING_MASK];
478 if(!isdigit(ch)) break;
479 if(len < 64)
480 temp[len] = ch;
481 len++;
482 digis++;
483 tr->mOut++;
485 if(digis > 0)
487 if(ch == 'E' || ch == 'e')
489 if(len < 64)
490 temp[len] = ch;
491 len++;
492 digis = 0;
493 tr->mOut++;
494 if(ch == '+' || ch == '-')
496 if(len < 64)
497 temp[len] = ch;
498 len++;
499 tr->mOut++;
501 while(TrLoad(tr))
503 ch = tr->mRing[tr->mOut&TR_RING_MASK];
504 if(!isdigit(ch)) break;
505 if(len < 64)
506 temp[len] = ch;
507 len++;
508 digis++;
509 tr->mOut++;
512 tr->mColumn += len;
513 if(digis > 0 && ch != '.' && !isalpha(ch))
515 if(len > 64)
517 TrErrorAt(tr, tr->mLine, col, "Float is too long.");
518 return 0;
520 temp[len] = '\0';
521 *value = strtod(temp, nullptr);
522 if(*value < loBound || *value > hiBound)
524 TrErrorAt(tr, tr->mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound);
525 return 0;
527 return 1;
530 else
531 tr->mColumn += len;
533 TrErrorAt(tr, tr->mLine, col, "Expected a float.\n");
534 return 0;
537 // Reads and validates a string token.
538 static int TrReadString(TokenReaderT *tr, const uint maxLen, char *text)
540 uint col, len;
541 char ch;
543 col = tr->mColumn;
544 if(TrSkipWhitespace(tr))
546 col = tr->mColumn;
547 ch = tr->mRing[tr->mOut&TR_RING_MASK];
548 if(ch == '\"')
550 tr->mOut++;
551 len = 0;
552 while(TrLoad(tr))
554 ch = tr->mRing[tr->mOut&TR_RING_MASK];
555 tr->mOut++;
556 if(ch == '\"')
557 break;
558 if(ch == '\n')
560 TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of line.\n");
561 return 0;
563 if(len < maxLen)
564 text[len] = ch;
565 len++;
567 if(ch != '\"')
569 tr->mColumn += 1 + len;
570 TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of input.\n");
571 return 0;
573 tr->mColumn += 2 + len;
574 if(len > maxLen)
576 TrErrorAt(tr, tr->mLine, col, "String is too long.\n");
577 return 0;
579 text[len] = '\0';
580 return 1;
583 TrErrorAt(tr, tr->mLine, col, "Expected a string.\n");
584 return 0;
587 // Reads and validates the given operator.
588 static int TrReadOperator(TokenReaderT *tr, const char *op)
590 uint col, len;
591 char ch;
593 col = tr->mColumn;
594 if(TrSkipWhitespace(tr))
596 col = tr->mColumn;
597 len = 0;
598 while(op[len] != '\0' && TrLoad(tr))
600 ch = tr->mRing[tr->mOut&TR_RING_MASK];
601 if(ch != op[len]) break;
602 len++;
603 tr->mOut++;
605 tr->mColumn += len;
606 if(op[len] == '\0')
607 return 1;
609 TrErrorAt(tr, tr->mLine, col, "Expected '%s' operator.\n", op);
610 return 0;
614 /*************************
615 *** File source input ***
616 *************************/
618 // Read a binary value of the specified byte order and byte size from a file,
619 // storing it as a 32-bit unsigned integer.
620 static int ReadBin4(std::istream &istream, const char *filename, const ByteOrderT order, const uint bytes, uint32_t *out)
622 uint8_t in[4];
623 istream.read(reinterpret_cast<char*>(in), static_cast<int>(bytes));
624 if(istream.gcount() != bytes)
626 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
627 return 0;
629 uint32_t accum{0};
630 switch(order)
632 case BO_LITTLE:
633 for(uint i = 0;i < bytes;i++)
634 accum = (accum<<8) | in[bytes - i - 1];
635 break;
636 case BO_BIG:
637 for(uint i = 0;i < bytes;i++)
638 accum = (accum<<8) | in[i];
639 break;
640 default:
641 break;
643 *out = accum;
644 return 1;
647 // Read a binary value of the specified byte order from a file, storing it as
648 // a 64-bit unsigned integer.
649 static int ReadBin8(std::istream &istream, const char *filename, const ByteOrderT order, uint64_t *out)
651 uint8_t in[8];
652 uint64_t accum;
653 uint i;
655 istream.read(reinterpret_cast<char*>(in), 8);
656 if(istream.gcount() != 8)
658 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
659 return 0;
661 accum = 0;
662 switch(order)
664 case BO_LITTLE:
665 for(i = 0;i < 8;i++)
666 accum = (accum<<8) | in[8 - i - 1];
667 break;
668 case BO_BIG:
669 for(i = 0;i < 8;i++)
670 accum = (accum<<8) | in[i];
671 break;
672 default:
673 break;
675 *out = accum;
676 return 1;
679 /* Read a binary value of the specified type, byte order, and byte size from
680 * a file, converting it to a double. For integer types, the significant
681 * bits are used to normalize the result. The sign of bits determines
682 * whether they are padded toward the MSB (negative) or LSB (positive).
683 * Floating-point types are not normalized.
685 static int ReadBinAsDouble(std::istream &istream, const char *filename, const ByteOrderT order,
686 const ElementTypeT type, const uint bytes, const int bits, double *out)
688 union {
689 uint32_t ui;
690 int32_t i;
691 float f;
692 } v4;
693 union {
694 uint64_t ui;
695 double f;
696 } v8;
698 *out = 0.0;
699 if(bytes > 4)
701 if(!ReadBin8(istream, filename, order, &v8.ui))
702 return 0;
703 if(type == ET_FP)
704 *out = v8.f;
706 else
708 if(!ReadBin4(istream, filename, order, bytes, &v4.ui))
709 return 0;
710 if(type == ET_FP)
711 *out = v4.f;
712 else
714 if(bits > 0)
715 v4.ui >>= (8*bytes) - (static_cast<uint>(bits));
716 else
717 v4.ui &= (0xFFFFFFFF >> (32+bits));
719 if(v4.ui&static_cast<uint>(1<<(std::abs(bits)-1)))
720 v4.ui |= (0xFFFFFFFF << std::abs(bits));
721 *out = v4.i / static_cast<double>(1<<(std::abs(bits)-1));
724 return 1;
727 /* Read an ascii value of the specified type from a file, converting it to a
728 * double. For integer types, the significant bits are used to normalize the
729 * result. The sign of the bits should always be positive. This also skips
730 * up to one separator character before the element itself.
732 static int ReadAsciiAsDouble(TokenReaderT *tr, const char *filename, const ElementTypeT type, const uint bits, double *out)
734 if(TrIsOperator(tr, ","))
735 TrReadOperator(tr, ",");
736 else if(TrIsOperator(tr, ":"))
737 TrReadOperator(tr, ":");
738 else if(TrIsOperator(tr, ";"))
739 TrReadOperator(tr, ";");
740 else if(TrIsOperator(tr, "|"))
741 TrReadOperator(tr, "|");
743 if(type == ET_FP)
745 if(!TrReadFloat(tr, -std::numeric_limits<double>::infinity(),
746 std::numeric_limits<double>::infinity(), out))
748 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
749 return 0;
752 else
754 int v;
755 if(!TrReadInt(tr, -(1<<(bits-1)), (1<<(bits-1))-1, &v))
757 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
758 return 0;
760 *out = v / static_cast<double>((1<<(bits-1))-1);
762 return 1;
765 // Read the RIFF/RIFX WAVE format chunk from a file, validating it against
766 // the source parameters and data set metrics.
767 static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const uint hrirRate,
768 SourceRefT *src)
770 uint32_t fourCC, chunkSize;
771 uint32_t format, channels, rate, dummy, block, size, bits;
773 chunkSize = 0;
774 do {
775 if(chunkSize > 0)
776 istream.seekg(static_cast<int>(chunkSize), std::ios::cur);
777 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
778 || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
779 return 0;
780 } while(fourCC != FOURCC_FMT);
781 if(!ReadBin4(istream, src->mPath, order, 2, &format)
782 || !ReadBin4(istream, src->mPath, order, 2, &channels)
783 || !ReadBin4(istream, src->mPath, order, 4, &rate)
784 || !ReadBin4(istream, src->mPath, order, 4, &dummy)
785 || !ReadBin4(istream, src->mPath, order, 2, &block))
786 return 0;
787 block /= channels;
788 if(chunkSize > 14)
790 if(!ReadBin4(istream, src->mPath, order, 2, &size))
791 return 0;
792 size /= 8;
793 if(block > size)
794 size = block;
796 else
797 size = block;
798 if(format == WAVE_FORMAT_EXTENSIBLE)
800 istream.seekg(2, std::ios::cur);
801 if(!ReadBin4(istream, src->mPath, order, 2, &bits))
802 return 0;
803 if(bits == 0)
804 bits = 8 * size;
805 istream.seekg(4, std::ios::cur);
806 if(!ReadBin4(istream, src->mPath, order, 2, &format))
807 return 0;
808 istream.seekg(static_cast<int>(chunkSize - 26), std::ios::cur);
810 else
812 bits = 8 * size;
813 if(chunkSize > 14)
814 istream.seekg(static_cast<int>(chunkSize - 16), std::ios::cur);
815 else
816 istream.seekg(static_cast<int>(chunkSize - 14), std::ios::cur);
818 if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT)
820 fprintf(stderr, "\nError: Unsupported WAVE format in file '%s'.\n", src->mPath);
821 return 0;
823 if(src->mChannel >= channels)
825 fprintf(stderr, "\nError: Missing source channel in WAVE file '%s'.\n", src->mPath);
826 return 0;
828 if(rate != hrirRate)
830 fprintf(stderr, "\nError: Mismatched source sample rate in WAVE file '%s'.\n", src->mPath);
831 return 0;
833 if(format == WAVE_FORMAT_PCM)
835 if(size < 2 || size > 4)
837 fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
838 return 0;
840 if(bits < 16 || bits > (8*size))
842 fprintf(stderr, "\nError: Bad significant bits in WAVE file '%s'.\n", src->mPath);
843 return 0;
845 src->mType = ET_INT;
847 else
849 if(size != 4 && size != 8)
851 fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
852 return 0;
854 src->mType = ET_FP;
856 src->mSize = size;
857 src->mBits = static_cast<int>(bits);
858 src->mSkip = channels;
859 return 1;
862 // Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles.
863 static int ReadWaveData(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
864 const uint n, double *hrir)
866 int pre, post, skip;
867 uint i;
869 pre = static_cast<int>(src->mSize * src->mChannel);
870 post = static_cast<int>(src->mSize * (src->mSkip - src->mChannel - 1));
871 skip = 0;
872 for(i = 0;i < n;i++)
874 skip += pre;
875 if(skip > 0)
876 istream.seekg(skip, std::ios::cur);
877 if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
878 return 0;
879 skip = post;
881 if(skip > 0)
882 istream.seekg(skip, std::ios::cur);
883 return 1;
886 // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to
887 // doubles.
888 static int ReadWaveList(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
889 const uint n, double *hrir)
891 uint32_t fourCC, chunkSize, listSize, count;
892 uint block, skip, offset, i;
893 double lastSample;
895 for(;;)
897 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
898 || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
899 return 0;
901 if(fourCC == FOURCC_DATA)
903 block = src->mSize * src->mSkip;
904 count = chunkSize / block;
905 if(count < (src->mOffset + n))
907 fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
908 return 0;
910 istream.seekg(static_cast<long>(src->mOffset * block), std::ios::cur);
911 if(!ReadWaveData(istream, src, order, n, &hrir[0]))
912 return 0;
913 return 1;
915 else if(fourCC == FOURCC_LIST)
917 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
918 return 0;
919 chunkSize -= 4;
920 if(fourCC == FOURCC_WAVL)
921 break;
923 if(chunkSize > 0)
924 istream.seekg(static_cast<long>(chunkSize), std::ios::cur);
926 listSize = chunkSize;
927 block = src->mSize * src->mSkip;
928 skip = src->mOffset;
929 offset = 0;
930 lastSample = 0.0;
931 while(offset < n && listSize > 8)
933 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
934 || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
935 return 0;
936 listSize -= 8 + chunkSize;
937 if(fourCC == FOURCC_DATA)
939 count = chunkSize / block;
940 if(count > skip)
942 istream.seekg(static_cast<long>(skip * block), std::ios::cur);
943 chunkSize -= skip * block;
944 count -= skip;
945 skip = 0;
946 if(count > (n - offset))
947 count = n - offset;
948 if(!ReadWaveData(istream, src, order, count, &hrir[offset]))
949 return 0;
950 chunkSize -= count * block;
951 offset += count;
952 lastSample = hrir[offset - 1];
954 else
956 skip -= count;
957 count = 0;
960 else if(fourCC == FOURCC_SLNT)
962 if(!ReadBin4(istream, src->mPath, order, 4, &count))
963 return 0;
964 chunkSize -= 4;
965 if(count > skip)
967 count -= skip;
968 skip = 0;
969 if(count > (n - offset))
970 count = n - offset;
971 for(i = 0; i < count; i ++)
972 hrir[offset + i] = lastSample;
973 offset += count;
975 else
977 skip -= count;
978 count = 0;
981 if(chunkSize > 0)
982 istream.seekg(static_cast<long>(chunkSize), std::ios::cur);
984 if(offset < n)
986 fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
987 return 0;
989 return 1;
992 // Load a source HRIR from an ASCII text file containing a list of elements
993 // separated by whitespace or common list operators (',', ';', ':', '|').
994 static int LoadAsciiSource(std::istream &istream, const SourceRefT *src,
995 const uint n, double *hrir)
997 TokenReaderT tr{istream};
998 uint i, j;
999 double dummy;
1001 TrSetup(nullptr, 0, nullptr, &tr);
1002 for(i = 0;i < src->mOffset;i++)
1004 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
1005 return 0;
1007 for(i = 0;i < n;i++)
1009 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &hrir[i]))
1010 return 0;
1011 for(j = 0;j < src->mSkip;j++)
1013 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
1014 return 0;
1017 return 1;
1020 // Load a source HRIR from a binary file.
1021 static int LoadBinarySource(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
1022 const uint n, double *hrir)
1024 istream.seekg(static_cast<long>(src->mOffset), std::ios::beg);
1025 for(uint i{0};i < n;i++)
1027 if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
1028 return 0;
1029 if(src->mSkip > 0)
1030 istream.seekg(static_cast<long>(src->mSkip), std::ios::cur);
1032 return 1;
1035 // Load a source HRIR from a RIFF/RIFX WAVE file.
1036 static int LoadWaveSource(std::istream &istream, SourceRefT *src, const uint hrirRate,
1037 const uint n, double *hrir)
1039 uint32_t fourCC, dummy;
1040 ByteOrderT order;
1042 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
1043 || !ReadBin4(istream, src->mPath, BO_LITTLE, 4, &dummy))
1044 return 0;
1045 if(fourCC == FOURCC_RIFF)
1046 order = BO_LITTLE;
1047 else if(fourCC == FOURCC_RIFX)
1048 order = BO_BIG;
1049 else
1051 fprintf(stderr, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src->mPath);
1052 return 0;
1055 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
1056 return 0;
1057 if(fourCC != FOURCC_WAVE)
1059 fprintf(stderr, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath);
1060 return 0;
1062 if(!ReadWaveFormat(istream, order, hrirRate, src))
1063 return 0;
1064 if(!ReadWaveList(istream, src, order, n, hrir))
1065 return 0;
1066 return 1;
1071 // Load a Spatially Oriented Format for Accoustics (SOFA) file.
1072 static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uint n)
1074 struct MYSOFA_EASY *sofa{mysofa_cache_lookup(src->mPath, static_cast<float>(hrirRate))};
1075 if(sofa) return sofa;
1077 sofa = static_cast<MYSOFA_EASY*>(calloc(1, sizeof(*sofa)));
1078 if(sofa == nullptr)
1080 fprintf(stderr, "\nError: Out of memory.\n");
1081 return nullptr;
1083 sofa->lookup = nullptr;
1084 sofa->neighborhood = nullptr;
1086 int err;
1087 sofa->hrtf = mysofa_load(src->mPath, &err);
1088 if(!sofa->hrtf)
1090 mysofa_close(sofa);
1091 fprintf(stderr, "\nError: Could not load source file '%s'.\n", src->mPath);
1092 return nullptr;
1094 /* NOTE: Some valid SOFA files are failing this check. */
1095 err = mysofa_check(sofa->hrtf);
1096 if(err != MYSOFA_OK)
1097 fprintf(stderr, "\nWarning: Supposedly malformed source file '%s'.\n", src->mPath);
1098 if((src->mOffset + n) > sofa->hrtf->N)
1100 mysofa_close(sofa);
1101 fprintf(stderr, "\nError: Not enough samples in SOFA file '%s'.\n", src->mPath);
1102 return nullptr;
1104 if(src->mChannel >= sofa->hrtf->R)
1106 mysofa_close(sofa);
1107 fprintf(stderr, "\nError: Missing source receiver in SOFA file '%s'.\n", src->mPath);
1108 return nullptr;
1110 mysofa_tocartesian(sofa->hrtf);
1111 sofa->lookup = mysofa_lookup_init(sofa->hrtf);
1112 if(sofa->lookup == nullptr)
1114 mysofa_close(sofa);
1115 fprintf(stderr, "\nError: Out of memory.\n");
1116 return nullptr;
1118 return mysofa_cache_store(sofa, src->mPath, static_cast<float>(hrirRate));
1121 // Copies the HRIR data from a particular SOFA measurement.
1122 static void ExtractSofaHrir(const MYSOFA_EASY *sofa, const uint index, const uint channel, const uint offset, const uint n, double *hrir)
1124 for(uint i{0u};i < n;i++)
1125 hrir[i] = sofa->hrtf->DataIR.values[(index*sofa->hrtf->R + channel)*sofa->hrtf->N + offset + i];
1128 // Load a source HRIR from a Spatially Oriented Format for Accoustics (SOFA)
1129 // file.
1130 static int LoadSofaSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1132 struct MYSOFA_EASY *sofa;
1133 float target[3];
1134 int nearest;
1135 float *coords;
1137 sofa = LoadSofaFile(src, hrirRate, n);
1138 if(sofa == nullptr)
1139 return 0;
1141 /* NOTE: At some point it may be benficial or necessary to consider the
1142 various coordinate systems, listener/source orientations, and
1143 direciontal vectors defined in the SOFA file.
1145 target[0] = static_cast<float>(src->mAzimuth);
1146 target[1] = static_cast<float>(src->mElevation);
1147 target[2] = static_cast<float>(src->mRadius);
1148 mysofa_s2c(target);
1150 nearest = mysofa_lookup(sofa->lookup, target);
1151 if(nearest < 0)
1153 fprintf(stderr, "\nError: Lookup failed in source file '%s'.\n", src->mPath);
1154 return 0;
1157 coords = &sofa->hrtf->SourcePosition.values[3 * nearest];
1158 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)
1160 fprintf(stderr, "\nError: No impulse response at coordinates (%.3fr, %.1fev, %.1faz) in file '%s'.\n", src->mRadius, src->mElevation, src->mAzimuth, src->mPath);
1161 target[0] = coords[0];
1162 target[1] = coords[1];
1163 target[2] = coords[2];
1164 mysofa_c2s(target);
1165 fprintf(stderr, " Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target[2], target[1], target[0]);
1166 return 0;
1169 ExtractSofaHrir(sofa, static_cast<uint>(nearest), src->mChannel, src->mOffset, n, hrir);
1171 return 1;
1174 // Load a source HRIR from a supported file type.
1175 static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1177 std::unique_ptr<al::ifstream> istream;
1178 if(src->mFormat != SF_SOFA)
1180 if(src->mFormat == SF_ASCII)
1181 istream.reset(new al::ifstream{src->mPath});
1182 else
1183 istream.reset(new al::ifstream{src->mPath, std::ios::binary});
1184 if(!istream->good())
1186 fprintf(stderr, "\nError: Could not open source file '%s'.\n", src->mPath);
1187 return 0;
1190 int result{0};
1191 switch(src->mFormat)
1193 case SF_ASCII:
1194 result = LoadAsciiSource(*istream, src, n, hrir);
1195 break;
1196 case SF_BIN_LE:
1197 result = LoadBinarySource(*istream, src, BO_LITTLE, n, hrir);
1198 break;
1199 case SF_BIN_BE:
1200 result = LoadBinarySource(*istream, src, BO_BIG, n, hrir);
1201 break;
1202 case SF_WAVE:
1203 result = LoadWaveSource(*istream, src, hrirRate, n, hrir);
1204 break;
1205 case SF_SOFA:
1206 result = LoadSofaSource(src, hrirRate, n, hrir);
1207 break;
1208 case SF_NONE:
1209 break;
1211 return result;
1215 // Match the channel type from a given identifier.
1216 static ChannelTypeT MatchChannelType(const char *ident)
1218 if(al::strcasecmp(ident, "mono") == 0)
1219 return CT_MONO;
1220 if(al::strcasecmp(ident, "stereo") == 0)
1221 return CT_STEREO;
1222 return CT_NONE;
1226 // Process the data set definition to read and validate the data set metrics.
1227 static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint truncSize, const ChannelModeT chanMode, HrirDataT *hData)
1229 int hasRate = 0, hasType = 0, hasPoints = 0, hasRadius = 0;
1230 int hasDistance = 0, hasAzimuths = 0;
1231 char ident[MAX_IDENT_LEN+1];
1232 uint line, col;
1233 double fpVal;
1234 uint points;
1235 int intVal;
1236 double distances[MAX_FD_COUNT];
1237 uint fdCount = 0;
1238 uint evCounts[MAX_FD_COUNT];
1239 std::vector<uint> azCounts(MAX_FD_COUNT * MAX_EV_COUNT);
1241 TrIndication(tr, &line, &col);
1242 while(TrIsIdent(tr))
1244 TrIndication(tr, &line, &col);
1245 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1246 return 0;
1247 if(al::strcasecmp(ident, "rate") == 0)
1249 if(hasRate)
1251 TrErrorAt(tr, line, col, "Redefinition of 'rate'.\n");
1252 return 0;
1254 if(!TrReadOperator(tr, "="))
1255 return 0;
1256 if(!TrReadInt(tr, MIN_RATE, MAX_RATE, &intVal))
1257 return 0;
1258 hData->mIrRate = static_cast<uint>(intVal);
1259 hasRate = 1;
1261 else if(al::strcasecmp(ident, "type") == 0)
1263 char type[MAX_IDENT_LEN+1];
1265 if(hasType)
1267 TrErrorAt(tr, line, col, "Redefinition of 'type'.\n");
1268 return 0;
1270 if(!TrReadOperator(tr, "="))
1271 return 0;
1273 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1274 return 0;
1275 hData->mChannelType = MatchChannelType(type);
1276 if(hData->mChannelType == CT_NONE)
1278 TrErrorAt(tr, line, col, "Expected a channel type.\n");
1279 return 0;
1281 else if(hData->mChannelType == CT_STEREO)
1283 if(chanMode == CM_ForceMono)
1284 hData->mChannelType = CT_MONO;
1286 hasType = 1;
1288 else if(al::strcasecmp(ident, "points") == 0)
1290 if(hasPoints)
1292 TrErrorAt(tr, line, col, "Redefinition of 'points'.\n");
1293 return 0;
1295 if(!TrReadOperator(tr, "="))
1296 return 0;
1297 TrIndication(tr, &line, &col);
1298 if(!TrReadInt(tr, MIN_POINTS, MAX_POINTS, &intVal))
1299 return 0;
1300 points = static_cast<uint>(intVal);
1301 if(fftSize > 0 && points > fftSize)
1303 TrErrorAt(tr, line, col, "Value exceeds the overridden FFT size.\n");
1304 return 0;
1306 if(points < truncSize)
1308 TrErrorAt(tr, line, col, "Value is below the truncation size.\n");
1309 return 0;
1311 hData->mIrPoints = points;
1312 hData->mFftSize = fftSize;
1313 hData->mIrSize = 1 + (fftSize / 2);
1314 if(points > hData->mIrSize)
1315 hData->mIrSize = points;
1316 hasPoints = 1;
1318 else if(al::strcasecmp(ident, "radius") == 0)
1320 if(hasRadius)
1322 TrErrorAt(tr, line, col, "Redefinition of 'radius'.\n");
1323 return 0;
1325 if(!TrReadOperator(tr, "="))
1326 return 0;
1327 if(!TrReadFloat(tr, MIN_RADIUS, MAX_RADIUS, &fpVal))
1328 return 0;
1329 hData->mRadius = fpVal;
1330 hasRadius = 1;
1332 else if(al::strcasecmp(ident, "distance") == 0)
1334 uint count = 0;
1336 if(hasDistance)
1338 TrErrorAt(tr, line, col, "Redefinition of 'distance'.\n");
1339 return 0;
1341 if(!TrReadOperator(tr, "="))
1342 return 0;
1344 for(;;)
1346 if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, &fpVal))
1347 return 0;
1348 if(count > 0 && fpVal <= distances[count - 1])
1350 TrError(tr, "Distances are not ascending.\n");
1351 return 0;
1353 distances[count++] = fpVal;
1354 if(!TrIsOperator(tr, ","))
1355 break;
1356 if(count >= MAX_FD_COUNT)
1358 TrError(tr, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT);
1359 return 0;
1361 TrReadOperator(tr, ",");
1363 if(fdCount != 0 && count != fdCount)
1365 TrError(tr, "Did not match the specified number of %d fields.\n", fdCount);
1366 return 0;
1368 fdCount = count;
1369 hasDistance = 1;
1371 else if(al::strcasecmp(ident, "azimuths") == 0)
1373 uint count = 0;
1375 if(hasAzimuths)
1377 TrErrorAt(tr, line, col, "Redefinition of 'azimuths'.\n");
1378 return 0;
1380 if(!TrReadOperator(tr, "="))
1381 return 0;
1383 evCounts[0] = 0;
1384 for(;;)
1386 if(!TrReadInt(tr, MIN_AZ_COUNT, MAX_AZ_COUNT, &intVal))
1387 return 0;
1388 azCounts[(count * MAX_EV_COUNT) + evCounts[count]++] = static_cast<uint>(intVal);
1389 if(TrIsOperator(tr, ","))
1391 if(evCounts[count] >= MAX_EV_COUNT)
1393 TrError(tr, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT);
1394 return 0;
1396 TrReadOperator(tr, ",");
1398 else
1400 if(evCounts[count] < MIN_EV_COUNT)
1402 TrErrorAt(tr, line, col, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT);
1403 return 0;
1405 if(azCounts[count * MAX_EV_COUNT] != 1 || azCounts[(count * MAX_EV_COUNT) + evCounts[count] - 1] != 1)
1407 TrError(tr, "Poles are not singular for field %d.\n", count - 1);
1408 return 0;
1410 count++;
1411 if(!TrIsOperator(tr, ";"))
1412 break;
1414 if(count >= MAX_FD_COUNT)
1416 TrError(tr, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT);
1417 return 0;
1419 evCounts[count] = 0;
1420 TrReadOperator(tr, ";");
1423 if(fdCount != 0 && count != fdCount)
1425 TrError(tr, "Did not match the specified number of %d fields.\n", fdCount);
1426 return 0;
1428 fdCount = count;
1429 hasAzimuths = 1;
1431 else
1433 TrErrorAt(tr, line, col, "Expected a metric name.\n");
1434 return 0;
1436 TrSkipWhitespace(tr);
1438 if(!(hasRate && hasPoints && hasRadius && hasDistance && hasAzimuths))
1440 TrErrorAt(tr, line, col, "Expected a metric name.\n");
1441 return 0;
1443 if(distances[0] < hData->mRadius)
1445 TrError(tr, "Distance cannot start below head radius.\n");
1446 return 0;
1448 if(hData->mChannelType == CT_NONE)
1449 hData->mChannelType = CT_MONO;
1450 if(!PrepareHrirData(fdCount, distances, evCounts, azCounts.data(), hData))
1452 fprintf(stderr, "Error: Out of memory.\n");
1453 exit(-1);
1455 return 1;
1458 // Parse an index triplet from the data set definition.
1459 static int ReadIndexTriplet(TokenReaderT *tr, const HrirDataT *hData, uint *fi, uint *ei, uint *ai)
1461 int intVal;
1463 if(hData->mFdCount > 1)
1465 if(!TrReadInt(tr, 0, static_cast<int>(hData->mFdCount) - 1, &intVal))
1466 return 0;
1467 *fi = static_cast<uint>(intVal);
1468 if(!TrReadOperator(tr, ","))
1469 return 0;
1471 else
1473 *fi = 0;
1475 if(!TrReadInt(tr, 0, static_cast<int>(hData->mFds[*fi].mEvCount) - 1, &intVal))
1476 return 0;
1477 *ei = static_cast<uint>(intVal);
1478 if(!TrReadOperator(tr, ","))
1479 return 0;
1480 if(!TrReadInt(tr, 0, static_cast<int>(hData->mFds[*fi].mEvs[*ei].mAzCount) - 1, &intVal))
1481 return 0;
1482 *ai = static_cast<uint>(intVal);
1483 return 1;
1486 // Match the source format from a given identifier.
1487 static SourceFormatT MatchSourceFormat(const char *ident)
1489 if(al::strcasecmp(ident, "ascii") == 0)
1490 return SF_ASCII;
1491 if(al::strcasecmp(ident, "bin_le") == 0)
1492 return SF_BIN_LE;
1493 if(al::strcasecmp(ident, "bin_be") == 0)
1494 return SF_BIN_BE;
1495 if(al::strcasecmp(ident, "wave") == 0)
1496 return SF_WAVE;
1497 if(al::strcasecmp(ident, "sofa") == 0)
1498 return SF_SOFA;
1499 return SF_NONE;
1502 // Match the source element type from a given identifier.
1503 static ElementTypeT MatchElementType(const char *ident)
1505 if(al::strcasecmp(ident, "int") == 0)
1506 return ET_INT;
1507 if(al::strcasecmp(ident, "fp") == 0)
1508 return ET_FP;
1509 return ET_NONE;
1512 // Parse and validate a source reference from the data set definition.
1513 static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
1515 char ident[MAX_IDENT_LEN+1];
1516 uint line, col;
1517 double fpVal;
1518 int intVal;
1520 TrIndication(tr, &line, &col);
1521 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1522 return 0;
1523 src->mFormat = MatchSourceFormat(ident);
1524 if(src->mFormat == SF_NONE)
1526 TrErrorAt(tr, line, col, "Expected a source format.\n");
1527 return 0;
1529 if(!TrReadOperator(tr, "("))
1530 return 0;
1531 if(src->mFormat == SF_SOFA)
1533 if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, &fpVal))
1534 return 0;
1535 src->mRadius = fpVal;
1536 if(!TrReadOperator(tr, ","))
1537 return 0;
1538 if(!TrReadFloat(tr, -90.0, 90.0, &fpVal))
1539 return 0;
1540 src->mElevation = fpVal;
1541 if(!TrReadOperator(tr, ","))
1542 return 0;
1543 if(!TrReadFloat(tr, -360.0, 360.0, &fpVal))
1544 return 0;
1545 src->mAzimuth = fpVal;
1546 if(!TrReadOperator(tr, ":"))
1547 return 0;
1548 if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
1549 return 0;
1550 src->mType = ET_NONE;
1551 src->mSize = 0;
1552 src->mBits = 0;
1553 src->mChannel = static_cast<uint>(intVal);
1554 src->mSkip = 0;
1556 else if(src->mFormat == SF_WAVE)
1558 if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
1559 return 0;
1560 src->mType = ET_NONE;
1561 src->mSize = 0;
1562 src->mBits = 0;
1563 src->mChannel = static_cast<uint>(intVal);
1564 src->mSkip = 0;
1566 else
1568 TrIndication(tr, &line, &col);
1569 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1570 return 0;
1571 src->mType = MatchElementType(ident);
1572 if(src->mType == ET_NONE)
1574 TrErrorAt(tr, line, col, "Expected a source element type.\n");
1575 return 0;
1577 if(src->mFormat == SF_BIN_LE || src->mFormat == SF_BIN_BE)
1579 if(!TrReadOperator(tr, ","))
1580 return 0;
1581 if(src->mType == ET_INT)
1583 if(!TrReadInt(tr, MIN_BIN_SIZE, MAX_BIN_SIZE, &intVal))
1584 return 0;
1585 src->mSize = static_cast<uint>(intVal);
1586 if(!TrIsOperator(tr, ","))
1587 src->mBits = static_cast<int>(8*src->mSize);
1588 else
1590 TrReadOperator(tr, ",");
1591 TrIndication(tr, &line, &col);
1592 if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
1593 return 0;
1594 if(std::abs(intVal) < MIN_BIN_BITS || static_cast<uint>(std::abs(intVal)) > (8*src->mSize))
1596 TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8*src->mSize);
1597 return 0;
1599 src->mBits = intVal;
1602 else
1604 TrIndication(tr, &line, &col);
1605 if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
1606 return 0;
1607 if(intVal != 4 && intVal != 8)
1609 TrErrorAt(tr, line, col, "Expected a value of 4 or 8.\n");
1610 return 0;
1612 src->mSize = static_cast<uint>(intVal);
1613 src->mBits = 0;
1616 else if(src->mFormat == SF_ASCII && src->mType == ET_INT)
1618 if(!TrReadOperator(tr, ","))
1619 return 0;
1620 if(!TrReadInt(tr, MIN_ASCII_BITS, MAX_ASCII_BITS, &intVal))
1621 return 0;
1622 src->mSize = 0;
1623 src->mBits = intVal;
1625 else
1627 src->mSize = 0;
1628 src->mBits = 0;
1631 if(!TrIsOperator(tr, ";"))
1632 src->mSkip = 0;
1633 else
1635 TrReadOperator(tr, ";");
1636 if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1637 return 0;
1638 src->mSkip = static_cast<uint>(intVal);
1641 if(!TrReadOperator(tr, ")"))
1642 return 0;
1643 if(TrIsOperator(tr, "@"))
1645 TrReadOperator(tr, "@");
1646 if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1647 return 0;
1648 src->mOffset = static_cast<uint>(intVal);
1650 else
1651 src->mOffset = 0;
1652 if(!TrReadOperator(tr, ":"))
1653 return 0;
1654 if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
1655 return 0;
1656 return 1;
1659 // Parse and validate a SOFA source reference from the data set definition.
1660 static int ReadSofaRef(TokenReaderT *tr, SourceRefT *src)
1662 char ident[MAX_IDENT_LEN+1];
1663 uint line, col;
1664 int intVal;
1666 TrIndication(tr, &line, &col);
1667 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1668 return 0;
1669 src->mFormat = MatchSourceFormat(ident);
1670 if(src->mFormat != SF_SOFA)
1672 TrErrorAt(tr, line, col, "Expected the SOFA source format.\n");
1673 return 0;
1676 src->mType = ET_NONE;
1677 src->mSize = 0;
1678 src->mBits = 0;
1679 src->mChannel = 0;
1680 src->mSkip = 0;
1682 if(TrIsOperator(tr, "@"))
1684 TrReadOperator(tr, "@");
1685 if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1686 return 0;
1687 src->mOffset = static_cast<uint>(intVal);
1689 else
1690 src->mOffset = 0;
1691 if(!TrReadOperator(tr, ":"))
1692 return 0;
1693 if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
1694 return 0;
1695 return 1;
1698 // Match the target ear (index) from a given identifier.
1699 static int MatchTargetEar(const char *ident)
1701 if(al::strcasecmp(ident, "left") == 0)
1702 return 0;
1703 if(al::strcasecmp(ident, "right") == 0)
1704 return 1;
1705 return -1;
1708 // Calculate the onset time of an HRIR and average it with any existing
1709 // timing for its field, elevation, azimuth, and ear.
1710 static double AverageHrirOnset(const uint rate, const uint n, const double *hrir, const double f, const double onset)
1712 std::vector<double> upsampled(10 * n);
1714 PPhaseResampler rs;
1715 rs.init(rate, 10 * rate);
1716 rs.process(n, hrir, 10 * n, upsampled.data());
1719 auto abs_lt = [](const double &lhs, const double &rhs) -> bool
1720 { return std::abs(lhs) < std::abs(rhs); };
1721 auto iter = std::max_element(upsampled.cbegin(), upsampled.cend(), abs_lt);
1722 return Lerp(onset, static_cast<double>(std::distance(upsampled.cbegin(), iter))/(10*rate), f);
1725 // Calculate the magnitude response of an HRIR and average it with any
1726 // existing responses for its field, elevation, azimuth, and ear.
1727 static void AverageHrirMagnitude(const uint points, const uint n, const double *hrir, const double f, double *mag)
1729 uint m = 1 + (n / 2), i;
1730 std::vector<complex_d> h(n);
1731 std::vector<double> r(n);
1733 for(i = 0;i < points;i++)
1734 h[i] = complex_d{hrir[i], 0.0};
1735 for(;i < n;i++)
1736 h[i] = complex_d{0.0, 0.0};
1737 FftForward(n, h.data());
1738 MagnitudeResponse(n, h.data(), r.data());
1739 for(i = 0;i < m;i++)
1740 mag[i] = Lerp(mag[i], r[i], f);
1743 // Process the list of sources in the data set definition.
1744 static int ProcessSources(TokenReaderT *tr, HrirDataT *hData)
1746 uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
1747 hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize);
1748 double *hrirs = hData->mHrirsBase.data();
1749 std::vector<double> hrir(hData->mIrPoints);
1750 uint line, col, fi, ei, ai;
1751 int count;
1753 printf("Loading sources...");
1754 fflush(stdout);
1755 count = 0;
1756 while(TrIsOperator(tr, "["))
1758 double factor[2]{ 1.0, 1.0 };
1760 TrIndication(tr, &line, &col);
1761 TrReadOperator(tr, "[");
1763 if(TrIsOperator(tr, "*"))
1765 SourceRefT src;
1766 struct MYSOFA_EASY *sofa;
1767 uint si;
1769 TrReadOperator(tr, "*");
1770 if(!TrReadOperator(tr, "]") || !TrReadOperator(tr, "="))
1771 return 0;
1773 TrIndication(tr, &line, &col);
1774 if(!ReadSofaRef(tr, &src))
1775 return 0;
1777 if(hData->mChannelType == CT_STEREO)
1779 char type[MAX_IDENT_LEN+1];
1780 ChannelTypeT channelType;
1782 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1783 return 0;
1785 channelType = MatchChannelType(type);
1787 switch(channelType)
1789 case CT_NONE:
1790 TrErrorAt(tr, line, col, "Expected a channel type.\n");
1791 return 0;
1792 case CT_MONO:
1793 src.mChannel = 0;
1794 break;
1795 case CT_STEREO:
1796 src.mChannel = 1;
1797 break;
1800 else
1802 char type[MAX_IDENT_LEN+1];
1803 ChannelTypeT channelType;
1805 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1806 return 0;
1808 channelType = MatchChannelType(type);
1809 if(channelType != CT_MONO)
1811 TrErrorAt(tr, line, col, "Expected a mono channel type.\n");
1812 return 0;
1814 src.mChannel = 0;
1817 sofa = LoadSofaFile(&src, hData->mIrRate, hData->mIrPoints);
1818 if(!sofa) return 0;
1820 for(si = 0;si < sofa->hrtf->M;si++)
1822 printf("\rLoading sources... %d of %d", si+1, sofa->hrtf->M);
1823 fflush(stdout);
1825 float aer[3] = {
1826 sofa->hrtf->SourcePosition.values[3*si],
1827 sofa->hrtf->SourcePosition.values[3*si + 1],
1828 sofa->hrtf->SourcePosition.values[3*si + 2]
1830 mysofa_c2s(aer);
1832 if(std::fabs(aer[1]) >= 89.999f)
1833 aer[0] = 0.0f;
1834 else
1835 aer[0] = std::fmod(360.0f - aer[0], 360.0f);
1837 for(fi = 0;fi < hData->mFdCount;fi++)
1839 double delta = aer[2] - hData->mFds[fi].mDistance;
1840 if(std::abs(delta) < 0.001) break;
1842 if(fi >= hData->mFdCount)
1843 continue;
1845 double ef{(90.0 + aer[1]) / 180.0 * (hData->mFds[fi].mEvCount - 1)};
1846 ei = static_cast<uint>(std::round(ef));
1847 ef = (ef - ei) * 180.0 / (hData->mFds[fi].mEvCount - 1);
1848 if(std::abs(ef) >= 0.1)
1849 continue;
1851 double af{aer[0] / 360.0 * hData->mFds[fi].mEvs[ei].mAzCount};
1852 ai = static_cast<uint>(std::round(af));
1853 af = (af - ai) * 360.0 / hData->mFds[fi].mEvs[ei].mAzCount;
1854 ai = ai % hData->mFds[fi].mEvs[ei].mAzCount;
1855 if(std::abs(af) >= 0.1)
1856 continue;
1858 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1859 if(azd->mIrs[0] != nullptr)
1861 TrErrorAt(tr, line, col, "Redefinition of source [ %d, %d, %d ].\n", fi, ei, ai);
1862 return 0;
1865 ExtractSofaHrir(sofa, si, 0, src.mOffset, hData->mIrPoints, hrir.data());
1866 azd->mIrs[0] = &hrirs[hData->mIrSize * azd->mIndex];
1867 azd->mDelays[0] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[0]);
1868 AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0, azd->mIrs[0]);
1870 if(src.mChannel == 1)
1872 ExtractSofaHrir(sofa, si, 1, src.mOffset, hData->mIrPoints, hrir.data());
1873 azd->mIrs[1] = &hrirs[hData->mIrSize * (hData->mIrCount + azd->mIndex)];
1874 azd->mDelays[1] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[1]);
1875 AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0, azd->mIrs[1]);
1878 // TODO: Since some SOFA files contain minimum phase HRIRs,
1879 // it would be beneficial to check for per-measurement delays
1880 // (when available) to reconstruct the HRTDs.
1883 continue;
1886 if(!ReadIndexTriplet(tr, hData, &fi, &ei, &ai))
1887 return 0;
1888 if(!TrReadOperator(tr, "]"))
1889 return 0;
1890 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1892 if(azd->mIrs[0] != nullptr)
1894 TrErrorAt(tr, line, col, "Redefinition of source.\n");
1895 return 0;
1897 if(!TrReadOperator(tr, "="))
1898 return 0;
1900 for(;;)
1902 SourceRefT src;
1904 if(!ReadSourceRef(tr, &src))
1905 return 0;
1907 // TODO: Would be nice to display 'x of y files', but that would
1908 // require preparing the source refs first to get a total count
1909 // before loading them.
1910 ++count;
1911 printf("\rLoading sources... %d file%s", count, (count==1)?"":"s");
1912 fflush(stdout);
1914 if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.data()))
1915 return 0;
1917 uint ti{0};
1918 if(hData->mChannelType == CT_STEREO)
1920 char ident[MAX_IDENT_LEN+1];
1922 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1923 return 0;
1924 ti = static_cast<uint>(MatchTargetEar(ident));
1925 if(static_cast<int>(ti) < 0)
1927 TrErrorAt(tr, line, col, "Expected a target ear.\n");
1928 return 0;
1931 azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
1932 azd->mDelays[ti] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0 / factor[ti], azd->mDelays[ti]);
1933 AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0 / factor[ti], azd->mIrs[ti]);
1934 factor[ti] += 1.0;
1935 if(!TrIsOperator(tr, "+"))
1936 break;
1937 TrReadOperator(tr, "+");
1939 if(hData->mChannelType == CT_STEREO)
1941 if(azd->mIrs[0] == nullptr)
1943 TrErrorAt(tr, line, col, "Missing left ear source reference(s).\n");
1944 return 0;
1946 else if(azd->mIrs[1] == nullptr)
1948 TrErrorAt(tr, line, col, "Missing right ear source reference(s).\n");
1949 return 0;
1953 printf("\n");
1954 for(fi = 0;fi < hData->mFdCount;fi++)
1956 for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
1958 for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
1960 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1961 if(azd->mIrs[0] != nullptr)
1962 break;
1964 if(ai < hData->mFds[fi].mEvs[ei].mAzCount)
1965 break;
1967 if(ei >= hData->mFds[fi].mEvCount)
1969 TrError(tr, "Missing source references [ %d, *, * ].\n", fi);
1970 return 0;
1972 hData->mFds[fi].mEvStart = ei;
1973 for(;ei < hData->mFds[fi].mEvCount;ei++)
1975 for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
1977 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1979 if(azd->mIrs[0] == nullptr)
1981 TrError(tr, "Missing source reference [ %d, %d, %d ].\n", fi, ei, ai);
1982 return 0;
1987 for(uint ti{0};ti < channels;ti++)
1989 for(fi = 0;fi < hData->mFdCount;fi++)
1991 for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
1993 for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
1995 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1997 azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
2002 if(!TrLoad(tr))
2004 mysofa_cache_release_all();
2005 return 1;
2008 TrError(tr, "Errant data at end of source list.\n");
2009 mysofa_cache_release_all();
2010 return 0;
2014 bool LoadDefInput(std::istream &istream, const char *startbytes, std::streamsize startbytecount,
2015 const char *filename, const uint fftSize, const uint truncSize, const ChannelModeT chanMode,
2016 HrirDataT *hData)
2018 TokenReaderT tr{istream};
2020 TrSetup(startbytes, startbytecount, filename, &tr);
2021 if(!ProcessMetrics(&tr, fftSize, truncSize, chanMode, hData)
2022 || !ProcessSources(&tr, hData))
2023 return false;
2025 return true;