Use istream for makemhr input
[openal-soft.git] / utils / makemhr / loaddef.cpp
blob619f5104cdbbd37e22ee4df02da2de68a7855859
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 <cstring>
30 #include <cstdarg>
31 #include <cstdio>
32 #include <cstdlib>
33 #include <iterator>
34 #include <limits>
35 #include <memory>
36 #include <vector>
38 #include "alfstream.h"
39 #include "alstring.h"
40 #include "makemhr.h"
42 #include "mysofa.h"
44 // Constants for accessing the token reader's ring buffer.
45 #define TR_RING_BITS (16)
46 #define TR_RING_SIZE (1 << TR_RING_BITS)
47 #define TR_RING_MASK (TR_RING_SIZE - 1)
49 // The token reader's load interval in bytes.
50 #define TR_LOAD_SIZE (TR_RING_SIZE >> 2)
52 // Token reader state for parsing the data set definition.
53 struct TokenReaderT {
54 std::istream &mIStream;
55 const char *mName{};
56 uint mLine{};
57 uint mColumn{};
58 char mRing[TR_RING_SIZE]{};
59 std::streamsize mIn{};
60 std::streamsize mOut{};
62 TokenReaderT(std::istream &istream) noexcept : mIStream{istream} { }
63 TokenReaderT(const TokenReaderT&) = default;
67 // The maximum identifier length used when processing the data set
68 // definition.
69 #define MAX_IDENT_LEN (16)
71 // The limits for the listener's head 'radius' in the data set definition.
72 #define MIN_RADIUS (0.05)
73 #define MAX_RADIUS (0.15)
75 // The maximum number of channels that can be addressed for a WAVE file
76 // source listed in the data set definition.
77 #define MAX_WAVE_CHANNELS (65535)
79 // The limits to the byte size for a binary source listed in the definition
80 // file.
81 #define MIN_BIN_SIZE (2)
82 #define MAX_BIN_SIZE (4)
84 // The minimum number of significant bits for binary sources listed in the
85 // data set definition. The maximum is calculated from the byte size.
86 #define MIN_BIN_BITS (16)
88 // The limits to the number of significant bits for an ASCII source listed in
89 // the data set definition.
90 #define MIN_ASCII_BITS (16)
91 #define MAX_ASCII_BITS (32)
93 // The four-character-codes for RIFF/RIFX WAVE file chunks.
94 #define FOURCC_RIFF (0x46464952) // 'RIFF'
95 #define FOURCC_RIFX (0x58464952) // 'RIFX'
96 #define FOURCC_WAVE (0x45564157) // 'WAVE'
97 #define FOURCC_FMT (0x20746D66) // 'fmt '
98 #define FOURCC_DATA (0x61746164) // 'data'
99 #define FOURCC_LIST (0x5453494C) // 'LIST'
100 #define FOURCC_WAVL (0x6C766177) // 'wavl'
101 #define FOURCC_SLNT (0x746E6C73) // 'slnt'
103 // The supported wave formats.
104 #define WAVE_FORMAT_PCM (0x0001)
105 #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
106 #define WAVE_FORMAT_EXTENSIBLE (0xFFFE)
109 enum ByteOrderT {
110 BO_NONE,
111 BO_LITTLE,
112 BO_BIG
115 // Source format for the references listed in the data set definition.
116 enum SourceFormatT {
117 SF_NONE,
118 SF_ASCII, // ASCII text file.
119 SF_BIN_LE, // Little-endian binary file.
120 SF_BIN_BE, // Big-endian binary file.
121 SF_WAVE, // RIFF/RIFX WAVE file.
122 SF_SOFA // Spatially Oriented Format for Accoustics (SOFA) file.
125 // Element types for the references listed in the data set definition.
126 enum ElementTypeT {
127 ET_NONE,
128 ET_INT, // Integer elements.
129 ET_FP // Floating-point elements.
132 // Source reference state used when loading sources.
133 struct SourceRefT {
134 SourceFormatT mFormat;
135 ElementTypeT mType;
136 uint mSize;
137 int mBits;
138 uint mChannel;
139 double mAzimuth;
140 double mElevation;
141 double mRadius;
142 uint mSkip;
143 uint mOffset;
144 char mPath[MAX_PATH_LEN+1];
148 /* Whitespace is not significant. It can process tokens as identifiers, numbers
149 * (integer and floating-point), strings, and operators. Strings must be
150 * encapsulated by double-quotes and cannot span multiple lines.
153 // Setup the reader on the given file. The filename can be NULL if no error
154 // output is desired.
155 static void TrSetup(const char *startbytes, std::streamsize startbytecount, const char *filename,
156 TokenReaderT *tr)
158 const char *name = nullptr;
160 if(filename)
162 const char *slash = strrchr(filename, '/');
163 if(slash)
165 const char *bslash = strrchr(slash+1, '\\');
166 if(bslash) name = bslash+1;
167 else name = slash+1;
169 else
171 const char *bslash = strrchr(filename, '\\');
172 if(bslash) name = bslash+1;
173 else name = filename;
177 tr->mName = name;
178 tr->mLine = 1;
179 tr->mColumn = 1;
180 tr->mIn = 0;
181 tr->mOut = 0;
183 if(startbytecount > 0)
185 std::copy_n(startbytes, startbytecount, std::begin(tr->mRing));
186 tr->mIn += startbytecount;
190 // Prime the reader's ring buffer, and return a result indicating that there
191 // is text to process.
192 static int TrLoad(TokenReaderT *tr)
194 std::istream &istream = tr->mIStream;
196 std::streamsize toLoad{TR_RING_SIZE - static_cast<std::streamsize>(tr->mIn - tr->mOut)};
197 if(toLoad >= TR_LOAD_SIZE && istream.good())
199 // Load TR_LOAD_SIZE (or less if at the end of the file) per read.
200 toLoad = TR_LOAD_SIZE;
201 std::streamsize in{tr->mIn&TR_RING_MASK};
202 std::streamsize count{TR_RING_SIZE - in};
203 if(count < toLoad)
205 istream.read(&tr->mRing[in], count);
206 tr->mIn += istream.gcount();
207 istream.read(&tr->mRing[0], toLoad-count);
208 tr->mIn += istream.gcount();
210 else
212 istream.read(&tr->mRing[in], toLoad);
213 tr->mIn += istream.gcount();
216 if(tr->mOut >= TR_RING_SIZE)
218 tr->mOut -= TR_RING_SIZE;
219 tr->mIn -= TR_RING_SIZE;
222 if(tr->mIn > tr->mOut)
223 return 1;
224 return 0;
227 // Error display routine. Only displays when the base name is not NULL.
228 static void TrErrorVA(const TokenReaderT *tr, uint line, uint column, const char *format, va_list argPtr)
230 if(!tr->mName)
231 return;
232 fprintf(stderr, "\nError (%s:%u:%u): ", tr->mName, line, column);
233 vfprintf(stderr, format, argPtr);
236 // Used to display an error at a saved line/column.
237 static void TrErrorAt(const TokenReaderT *tr, uint line, uint column, const char *format, ...)
239 va_list argPtr;
241 va_start(argPtr, format);
242 TrErrorVA(tr, line, column, format, argPtr);
243 va_end(argPtr);
246 // Used to display an error at the current line/column.
247 static void TrError(const TokenReaderT *tr, const char *format, ...)
249 va_list argPtr;
251 va_start(argPtr, format);
252 TrErrorVA(tr, tr->mLine, tr->mColumn, format, argPtr);
253 va_end(argPtr);
256 // Skips to the next line.
257 static void TrSkipLine(TokenReaderT *tr)
259 char ch;
261 while(TrLoad(tr))
263 ch = tr->mRing[tr->mOut&TR_RING_MASK];
264 tr->mOut++;
265 if(ch == '\n')
267 tr->mLine++;
268 tr->mColumn = 1;
269 break;
271 tr->mColumn ++;
275 // Skips to the next token.
276 static int TrSkipWhitespace(TokenReaderT *tr)
278 while(TrLoad(tr))
280 char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
281 if(isspace(ch))
283 tr->mOut++;
284 if(ch == '\n')
286 tr->mLine++;
287 tr->mColumn = 1;
289 else
290 tr->mColumn++;
292 else if(ch == '#')
293 TrSkipLine(tr);
294 else
295 return 1;
297 return 0;
300 // Get the line and/or column of the next token (or the end of input).
301 static void TrIndication(TokenReaderT *tr, uint *line, uint *column)
303 TrSkipWhitespace(tr);
304 if(line) *line = tr->mLine;
305 if(column) *column = tr->mColumn;
308 // Checks to see if a token is (likely to be) an identifier. It does not
309 // display any errors and will not proceed to the next token.
310 static int TrIsIdent(TokenReaderT *tr)
312 if(!TrSkipWhitespace(tr))
313 return 0;
314 char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
315 return ch == '_' || isalpha(ch);
319 // Checks to see if a token is the given operator. It does not display any
320 // errors and will not proceed to the next token.
321 static int TrIsOperator(TokenReaderT *tr, const char *op)
323 std::streamsize out;
324 size_t len;
325 char ch;
327 if(!TrSkipWhitespace(tr))
328 return 0;
329 out = tr->mOut;
330 len = 0;
331 while(op[len] != '\0' && out < tr->mIn)
333 ch = tr->mRing[out&TR_RING_MASK];
334 if(ch != op[len]) break;
335 len++;
336 out++;
338 if(op[len] == '\0')
339 return 1;
340 return 0;
343 /* The TrRead*() routines obtain the value of a matching token type. They
344 * display type, form, and boundary errors and will proceed to the next
345 * token.
348 // Reads and validates an identifier token.
349 static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident)
351 uint col, len;
352 char ch;
354 col = tr->mColumn;
355 if(TrSkipWhitespace(tr))
357 col = tr->mColumn;
358 ch = tr->mRing[tr->mOut&TR_RING_MASK];
359 if(ch == '_' || isalpha(ch))
361 len = 0;
362 do {
363 if(len < maxLen)
364 ident[len] = ch;
365 len++;
366 tr->mOut++;
367 if(!TrLoad(tr))
368 break;
369 ch = tr->mRing[tr->mOut&TR_RING_MASK];
370 } while(ch == '_' || isdigit(ch) || isalpha(ch));
372 tr->mColumn += len;
373 if(len < maxLen)
375 ident[len] = '\0';
376 return 1;
378 TrErrorAt(tr, tr->mLine, col, "Identifier is too long.\n");
379 return 0;
382 TrErrorAt(tr, tr->mLine, col, "Expected an identifier.\n");
383 return 0;
386 // Reads and validates (including bounds) an integer token.
387 static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int *value)
389 uint col, digis, len;
390 char ch, temp[64+1];
392 col = tr->mColumn;
393 if(TrSkipWhitespace(tr))
395 col = tr->mColumn;
396 len = 0;
397 ch = tr->mRing[tr->mOut&TR_RING_MASK];
398 if(ch == '+' || ch == '-')
400 temp[len] = ch;
401 len++;
402 tr->mOut++;
404 digis = 0;
405 while(TrLoad(tr))
407 ch = tr->mRing[tr->mOut&TR_RING_MASK];
408 if(!isdigit(ch)) break;
409 if(len < 64)
410 temp[len] = ch;
411 len++;
412 digis++;
413 tr->mOut++;
415 tr->mColumn += len;
416 if(digis > 0 && ch != '.' && !isalpha(ch))
418 if(len > 64)
420 TrErrorAt(tr, tr->mLine, col, "Integer is too long.");
421 return 0;
423 temp[len] = '\0';
424 *value = static_cast<int>(strtol(temp, nullptr, 10));
425 if(*value < loBound || *value > hiBound)
427 TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound);
428 return 0;
430 return 1;
433 TrErrorAt(tr, tr->mLine, col, "Expected an integer.\n");
434 return 0;
437 // Reads and validates (including bounds) a float token.
438 static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBound, double *value)
440 uint col, digis, len;
441 char ch, temp[64+1];
443 col = tr->mColumn;
444 if(TrSkipWhitespace(tr))
446 col = tr->mColumn;
447 len = 0;
448 ch = tr->mRing[tr->mOut&TR_RING_MASK];
449 if(ch == '+' || ch == '-')
451 temp[len] = ch;
452 len++;
453 tr->mOut++;
456 digis = 0;
457 while(TrLoad(tr))
459 ch = tr->mRing[tr->mOut&TR_RING_MASK];
460 if(!isdigit(ch)) break;
461 if(len < 64)
462 temp[len] = ch;
463 len++;
464 digis++;
465 tr->mOut++;
467 if(ch == '.')
469 if(len < 64)
470 temp[len] = ch;
471 len++;
472 tr->mOut++;
474 while(TrLoad(tr))
476 ch = tr->mRing[tr->mOut&TR_RING_MASK];
477 if(!isdigit(ch)) break;
478 if(len < 64)
479 temp[len] = ch;
480 len++;
481 digis++;
482 tr->mOut++;
484 if(digis > 0)
486 if(ch == 'E' || ch == 'e')
488 if(len < 64)
489 temp[len] = ch;
490 len++;
491 digis = 0;
492 tr->mOut++;
493 if(ch == '+' || ch == '-')
495 if(len < 64)
496 temp[len] = ch;
497 len++;
498 tr->mOut++;
500 while(TrLoad(tr))
502 ch = tr->mRing[tr->mOut&TR_RING_MASK];
503 if(!isdigit(ch)) break;
504 if(len < 64)
505 temp[len] = ch;
506 len++;
507 digis++;
508 tr->mOut++;
511 tr->mColumn += len;
512 if(digis > 0 && ch != '.' && !isalpha(ch))
514 if(len > 64)
516 TrErrorAt(tr, tr->mLine, col, "Float is too long.");
517 return 0;
519 temp[len] = '\0';
520 *value = strtod(temp, nullptr);
521 if(*value < loBound || *value > hiBound)
523 TrErrorAt(tr, tr->mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound);
524 return 0;
526 return 1;
529 else
530 tr->mColumn += len;
532 TrErrorAt(tr, tr->mLine, col, "Expected a float.\n");
533 return 0;
536 // Reads and validates a string token.
537 static int TrReadString(TokenReaderT *tr, const uint maxLen, char *text)
539 uint col, len;
540 char ch;
542 col = tr->mColumn;
543 if(TrSkipWhitespace(tr))
545 col = tr->mColumn;
546 ch = tr->mRing[tr->mOut&TR_RING_MASK];
547 if(ch == '\"')
549 tr->mOut++;
550 len = 0;
551 while(TrLoad(tr))
553 ch = tr->mRing[tr->mOut&TR_RING_MASK];
554 tr->mOut++;
555 if(ch == '\"')
556 break;
557 if(ch == '\n')
559 TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of line.\n");
560 return 0;
562 if(len < maxLen)
563 text[len] = ch;
564 len++;
566 if(ch != '\"')
568 tr->mColumn += 1 + len;
569 TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of input.\n");
570 return 0;
572 tr->mColumn += 2 + len;
573 if(len > maxLen)
575 TrErrorAt(tr, tr->mLine, col, "String is too long.\n");
576 return 0;
578 text[len] = '\0';
579 return 1;
582 TrErrorAt(tr, tr->mLine, col, "Expected a string.\n");
583 return 0;
586 // Reads and validates the given operator.
587 static int TrReadOperator(TokenReaderT *tr, const char *op)
589 uint col, len;
590 char ch;
592 col = tr->mColumn;
593 if(TrSkipWhitespace(tr))
595 col = tr->mColumn;
596 len = 0;
597 while(op[len] != '\0' && TrLoad(tr))
599 ch = tr->mRing[tr->mOut&TR_RING_MASK];
600 if(ch != op[len]) break;
601 len++;
602 tr->mOut++;
604 tr->mColumn += len;
605 if(op[len] == '\0')
606 return 1;
608 TrErrorAt(tr, tr->mLine, col, "Expected '%s' operator.\n", op);
609 return 0;
613 /*************************
614 *** File source input ***
615 *************************/
617 // Read a binary value of the specified byte order and byte size from a file,
618 // storing it as a 32-bit unsigned integer.
619 static int ReadBin4(std::istream &istream, const char *filename, const ByteOrderT order, const uint bytes, uint32_t *out)
621 uint8_t in[4];
622 istream.read(reinterpret_cast<char*>(in), static_cast<int>(bytes));
623 if(istream.gcount() != bytes)
625 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
626 return 0;
628 uint32_t accum{0};
629 switch(order)
631 case BO_LITTLE:
632 for(uint i = 0;i < bytes;i++)
633 accum = (accum<<8) | in[bytes - i - 1];
634 break;
635 case BO_BIG:
636 for(uint i = 0;i < bytes;i++)
637 accum = (accum<<8) | in[i];
638 break;
639 default:
640 break;
642 *out = accum;
643 return 1;
646 // Read a binary value of the specified byte order from a file, storing it as
647 // a 64-bit unsigned integer.
648 static int ReadBin8(std::istream &istream, const char *filename, const ByteOrderT order, uint64_t *out)
650 uint8_t in[8];
651 uint64_t accum;
652 uint i;
654 istream.read(reinterpret_cast<char*>(in), 8);
655 if(istream.gcount() != 8)
657 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
658 return 0;
660 accum = 0;
661 switch(order)
663 case BO_LITTLE:
664 for(i = 0;i < 8;i++)
665 accum = (accum<<8) | in[8 - i - 1];
666 break;
667 case BO_BIG:
668 for(i = 0;i < 8;i++)
669 accum = (accum<<8) | in[i];
670 break;
671 default:
672 break;
674 *out = accum;
675 return 1;
678 /* Read a binary value of the specified type, byte order, and byte size from
679 * a file, converting it to a double. For integer types, the significant
680 * bits are used to normalize the result. The sign of bits determines
681 * whether they are padded toward the MSB (negative) or LSB (positive).
682 * Floating-point types are not normalized.
684 static int ReadBinAsDouble(std::istream &istream, const char *filename, const ByteOrderT order,
685 const ElementTypeT type, const uint bytes, const int bits, double *out)
687 union {
688 uint32_t ui;
689 int32_t i;
690 float f;
691 } v4;
692 union {
693 uint64_t ui;
694 double f;
695 } v8;
697 *out = 0.0;
698 if(bytes > 4)
700 if(!ReadBin8(istream, filename, order, &v8.ui))
701 return 0;
702 if(type == ET_FP)
703 *out = v8.f;
705 else
707 if(!ReadBin4(istream, filename, order, bytes, &v4.ui))
708 return 0;
709 if(type == ET_FP)
710 *out = v4.f;
711 else
713 if(bits > 0)
714 v4.ui >>= (8*bytes) - (static_cast<uint>(bits));
715 else
716 v4.ui &= (0xFFFFFFFF >> (32+bits));
718 if(v4.ui&static_cast<uint>(1<<(std::abs(bits)-1)))
719 v4.ui |= (0xFFFFFFFF << std::abs(bits));
720 *out = v4.i / static_cast<double>(1<<(std::abs(bits)-1));
723 return 1;
726 /* Read an ascii value of the specified type from a file, converting it to a
727 * double. For integer types, the significant bits are used to normalize the
728 * result. The sign of the bits should always be positive. This also skips
729 * up to one separator character before the element itself.
731 static int ReadAsciiAsDouble(TokenReaderT *tr, const char *filename, const ElementTypeT type, const uint bits, double *out)
733 if(TrIsOperator(tr, ","))
734 TrReadOperator(tr, ",");
735 else if(TrIsOperator(tr, ":"))
736 TrReadOperator(tr, ":");
737 else if(TrIsOperator(tr, ";"))
738 TrReadOperator(tr, ";");
739 else if(TrIsOperator(tr, "|"))
740 TrReadOperator(tr, "|");
742 if(type == ET_FP)
744 if(!TrReadFloat(tr, -std::numeric_limits<double>::infinity(),
745 std::numeric_limits<double>::infinity(), out))
747 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
748 return 0;
751 else
753 int v;
754 if(!TrReadInt(tr, -(1<<(bits-1)), (1<<(bits-1))-1, &v))
756 fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
757 return 0;
759 *out = v / static_cast<double>((1<<(bits-1))-1);
761 return 1;
764 // Read the RIFF/RIFX WAVE format chunk from a file, validating it against
765 // the source parameters and data set metrics.
766 static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const uint hrirRate,
767 SourceRefT *src)
769 uint32_t fourCC, chunkSize;
770 uint32_t format, channels, rate, dummy, block, size, bits;
772 chunkSize = 0;
773 do {
774 if(chunkSize > 0)
775 istream.seekg(static_cast<int>(chunkSize), std::ios::cur);
776 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
777 || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
778 return 0;
779 } while(fourCC != FOURCC_FMT);
780 if(!ReadBin4(istream, src->mPath, order, 2, &format)
781 || !ReadBin4(istream, src->mPath, order, 2, &channels)
782 || !ReadBin4(istream, src->mPath, order, 4, &rate)
783 || !ReadBin4(istream, src->mPath, order, 4, &dummy)
784 || !ReadBin4(istream, src->mPath, order, 2, &block))
785 return 0;
786 block /= channels;
787 if(chunkSize > 14)
789 if(!ReadBin4(istream, src->mPath, order, 2, &size))
790 return 0;
791 size /= 8;
792 if(block > size)
793 size = block;
795 else
796 size = block;
797 if(format == WAVE_FORMAT_EXTENSIBLE)
799 istream.seekg(2, std::ios::cur);
800 if(!ReadBin4(istream, src->mPath, order, 2, &bits))
801 return 0;
802 if(bits == 0)
803 bits = 8 * size;
804 istream.seekg(4, std::ios::cur);
805 if(!ReadBin4(istream, src->mPath, order, 2, &format))
806 return 0;
807 istream.seekg(static_cast<int>(chunkSize - 26), std::ios::cur);
809 else
811 bits = 8 * size;
812 if(chunkSize > 14)
813 istream.seekg(static_cast<int>(chunkSize - 16), std::ios::cur);
814 else
815 istream.seekg(static_cast<int>(chunkSize - 14), std::ios::cur);
817 if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT)
819 fprintf(stderr, "\nError: Unsupported WAVE format in file '%s'.\n", src->mPath);
820 return 0;
822 if(src->mChannel >= channels)
824 fprintf(stderr, "\nError: Missing source channel in WAVE file '%s'.\n", src->mPath);
825 return 0;
827 if(rate != hrirRate)
829 fprintf(stderr, "\nError: Mismatched source sample rate in WAVE file '%s'.\n", src->mPath);
830 return 0;
832 if(format == WAVE_FORMAT_PCM)
834 if(size < 2 || size > 4)
836 fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
837 return 0;
839 if(bits < 16 || bits > (8*size))
841 fprintf(stderr, "\nError: Bad significant bits in WAVE file '%s'.\n", src->mPath);
842 return 0;
844 src->mType = ET_INT;
846 else
848 if(size != 4 && size != 8)
850 fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
851 return 0;
853 src->mType = ET_FP;
855 src->mSize = size;
856 src->mBits = static_cast<int>(bits);
857 src->mSkip = channels;
858 return 1;
861 // Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles.
862 static int ReadWaveData(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
863 const uint n, double *hrir)
865 int pre, post, skip;
866 uint i;
868 pre = static_cast<int>(src->mSize * src->mChannel);
869 post = static_cast<int>(src->mSize * (src->mSkip - src->mChannel - 1));
870 skip = 0;
871 for(i = 0;i < n;i++)
873 skip += pre;
874 if(skip > 0)
875 istream.seekg(skip, std::ios::cur);
876 if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
877 return 0;
878 skip = post;
880 if(skip > 0)
881 istream.seekg(skip, std::ios::cur);
882 return 1;
885 // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to
886 // doubles.
887 static int ReadWaveList(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
888 const uint n, double *hrir)
890 uint32_t fourCC, chunkSize, listSize, count;
891 uint block, skip, offset, i;
892 double lastSample;
894 for(;;)
896 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
897 || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
898 return 0;
900 if(fourCC == FOURCC_DATA)
902 block = src->mSize * src->mSkip;
903 count = chunkSize / block;
904 if(count < (src->mOffset + n))
906 fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
907 return 0;
909 istream.seekg(static_cast<long>(src->mOffset * block), std::ios::cur);
910 if(!ReadWaveData(istream, src, order, n, &hrir[0]))
911 return 0;
912 return 1;
914 else if(fourCC == FOURCC_LIST)
916 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
917 return 0;
918 chunkSize -= 4;
919 if(fourCC == FOURCC_WAVL)
920 break;
922 if(chunkSize > 0)
923 istream.seekg(static_cast<long>(chunkSize), std::ios::cur);
925 listSize = chunkSize;
926 block = src->mSize * src->mSkip;
927 skip = src->mOffset;
928 offset = 0;
929 lastSample = 0.0;
930 while(offset < n && listSize > 8)
932 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
933 || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
934 return 0;
935 listSize -= 8 + chunkSize;
936 if(fourCC == FOURCC_DATA)
938 count = chunkSize / block;
939 if(count > skip)
941 istream.seekg(static_cast<long>(skip * block), std::ios::cur);
942 chunkSize -= skip * block;
943 count -= skip;
944 skip = 0;
945 if(count > (n - offset))
946 count = n - offset;
947 if(!ReadWaveData(istream, src, order, count, &hrir[offset]))
948 return 0;
949 chunkSize -= count * block;
950 offset += count;
951 lastSample = hrir[offset - 1];
953 else
955 skip -= count;
956 count = 0;
959 else if(fourCC == FOURCC_SLNT)
961 if(!ReadBin4(istream, src->mPath, order, 4, &count))
962 return 0;
963 chunkSize -= 4;
964 if(count > skip)
966 count -= skip;
967 skip = 0;
968 if(count > (n - offset))
969 count = n - offset;
970 for(i = 0; i < count; i ++)
971 hrir[offset + i] = lastSample;
972 offset += count;
974 else
976 skip -= count;
977 count = 0;
980 if(chunkSize > 0)
981 istream.seekg(static_cast<long>(chunkSize), std::ios::cur);
983 if(offset < n)
985 fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
986 return 0;
988 return 1;
991 // Load a source HRIR from an ASCII text file containing a list of elements
992 // separated by whitespace or common list operators (',', ';', ':', '|').
993 static int LoadAsciiSource(std::istream &istream, const SourceRefT *src,
994 const uint n, double *hrir)
996 TokenReaderT tr{istream};
997 uint i, j;
998 double dummy;
1000 TrSetup(nullptr, 0, nullptr, &tr);
1001 for(i = 0;i < src->mOffset;i++)
1003 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
1004 return 0;
1006 for(i = 0;i < n;i++)
1008 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &hrir[i]))
1009 return 0;
1010 for(j = 0;j < src->mSkip;j++)
1012 if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
1013 return 0;
1016 return 1;
1019 // Load a source HRIR from a binary file.
1020 static int LoadBinarySource(std::istream &istream, const SourceRefT *src, const ByteOrderT order,
1021 const uint n, double *hrir)
1023 istream.seekg(static_cast<long>(src->mOffset), std::ios::beg);
1024 for(uint i{0};i < n;i++)
1026 if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
1027 return 0;
1028 if(src->mSkip > 0)
1029 istream.seekg(static_cast<long>(src->mSkip), std::ios::cur);
1031 return 1;
1034 // Load a source HRIR from a RIFF/RIFX WAVE file.
1035 static int LoadWaveSource(std::istream &istream, SourceRefT *src, const uint hrirRate,
1036 const uint n, double *hrir)
1038 uint32_t fourCC, dummy;
1039 ByteOrderT order;
1041 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
1042 || !ReadBin4(istream, src->mPath, BO_LITTLE, 4, &dummy))
1043 return 0;
1044 if(fourCC == FOURCC_RIFF)
1045 order = BO_LITTLE;
1046 else if(fourCC == FOURCC_RIFX)
1047 order = BO_BIG;
1048 else
1050 fprintf(stderr, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src->mPath);
1051 return 0;
1054 if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
1055 return 0;
1056 if(fourCC != FOURCC_WAVE)
1058 fprintf(stderr, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath);
1059 return 0;
1061 if(!ReadWaveFormat(istream, order, hrirRate, src))
1062 return 0;
1063 if(!ReadWaveList(istream, src, order, n, hrir))
1064 return 0;
1065 return 1;
1070 // Load a Spatially Oriented Format for Accoustics (SOFA) file.
1071 static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uint n)
1073 struct MYSOFA_EASY *sofa{mysofa_cache_lookup(src->mPath, static_cast<float>(hrirRate))};
1074 if(sofa) return sofa;
1076 sofa = static_cast<MYSOFA_EASY*>(calloc(1, sizeof(*sofa)));
1077 if(sofa == nullptr)
1079 fprintf(stderr, "\nError: Out of memory.\n");
1080 return nullptr;
1082 sofa->lookup = nullptr;
1083 sofa->neighborhood = nullptr;
1085 int err;
1086 sofa->hrtf = mysofa_load(src->mPath, &err);
1087 if(!sofa->hrtf)
1089 mysofa_close(sofa);
1090 fprintf(stderr, "\nError: Could not load source file '%s'.\n", src->mPath);
1091 return nullptr;
1093 /* NOTE: Some valid SOFA files are failing this check. */
1094 err = mysofa_check(sofa->hrtf);
1095 if(err != MYSOFA_OK)
1096 fprintf(stderr, "\nWarning: Supposedly malformed source file '%s'.\n", src->mPath);
1097 if((src->mOffset + n) > sofa->hrtf->N)
1099 mysofa_close(sofa);
1100 fprintf(stderr, "\nError: Not enough samples in SOFA file '%s'.\n", src->mPath);
1101 return nullptr;
1103 if(src->mChannel >= sofa->hrtf->R)
1105 mysofa_close(sofa);
1106 fprintf(stderr, "\nError: Missing source receiver in SOFA file '%s'.\n", src->mPath);
1107 return nullptr;
1109 mysofa_tocartesian(sofa->hrtf);
1110 sofa->lookup = mysofa_lookup_init(sofa->hrtf);
1111 if(sofa->lookup == nullptr)
1113 mysofa_close(sofa);
1114 fprintf(stderr, "\nError: Out of memory.\n");
1115 return nullptr;
1117 return mysofa_cache_store(sofa, src->mPath, static_cast<float>(hrirRate));
1120 // Copies the HRIR data from a particular SOFA measurement.
1121 static void ExtractSofaHrir(const MYSOFA_EASY *sofa, const uint index, const uint channel, const uint offset, const uint n, double *hrir)
1123 for(uint i{0u};i < n;i++)
1124 hrir[i] = sofa->hrtf->DataIR.values[(index*sofa->hrtf->R + channel)*sofa->hrtf->N + offset + i];
1127 // Load a source HRIR from a Spatially Oriented Format for Accoustics (SOFA)
1128 // file.
1129 static int LoadSofaSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1131 struct MYSOFA_EASY *sofa;
1132 float target[3];
1133 int nearest;
1134 float *coords;
1136 sofa = LoadSofaFile(src, hrirRate, n);
1137 if(sofa == nullptr)
1138 return 0;
1140 /* NOTE: At some point it may be benficial or necessary to consider the
1141 various coordinate systems, listener/source orientations, and
1142 direciontal vectors defined in the SOFA file.
1144 target[0] = static_cast<float>(src->mAzimuth);
1145 target[1] = static_cast<float>(src->mElevation);
1146 target[2] = static_cast<float>(src->mRadius);
1147 mysofa_s2c(target);
1149 nearest = mysofa_lookup(sofa->lookup, target);
1150 if(nearest < 0)
1152 fprintf(stderr, "\nError: Lookup failed in source file '%s'.\n", src->mPath);
1153 return 0;
1156 coords = &sofa->hrtf->SourcePosition.values[3 * nearest];
1157 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)
1159 fprintf(stderr, "\nError: No impulse response at coordinates (%.3fr, %.1fev, %.1faz) in file '%s'.\n", src->mRadius, src->mElevation, src->mAzimuth, src->mPath);
1160 target[0] = coords[0];
1161 target[1] = coords[1];
1162 target[2] = coords[2];
1163 mysofa_c2s(target);
1164 fprintf(stderr, " Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target[2], target[1], target[0]);
1165 return 0;
1168 ExtractSofaHrir(sofa, static_cast<uint>(nearest), src->mChannel, src->mOffset, n, hrir);
1170 return 1;
1173 // Load a source HRIR from a supported file type.
1174 static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
1176 std::unique_ptr<al::ifstream> istream;
1177 if(src->mFormat != SF_SOFA)
1179 if(src->mFormat == SF_ASCII)
1180 istream.reset(new al::ifstream{src->mPath});
1181 else
1182 istream.reset(new al::ifstream{src->mPath, std::ios::binary});
1183 if(!istream->good())
1185 fprintf(stderr, "\nError: Could not open source file '%s'.\n", src->mPath);
1186 return 0;
1189 int result{0};
1190 switch(src->mFormat)
1192 case SF_ASCII:
1193 result = LoadAsciiSource(*istream, src, n, hrir);
1194 break;
1195 case SF_BIN_LE:
1196 result = LoadBinarySource(*istream, src, BO_LITTLE, n, hrir);
1197 break;
1198 case SF_BIN_BE:
1199 result = LoadBinarySource(*istream, src, BO_BIG, n, hrir);
1200 break;
1201 case SF_WAVE:
1202 result = LoadWaveSource(*istream, src, hrirRate, n, hrir);
1203 break;
1204 case SF_SOFA:
1205 result = LoadSofaSource(src, hrirRate, n, hrir);
1206 break;
1207 case SF_NONE:
1208 break;
1210 return result;
1214 // Match the channel type from a given identifier.
1215 static ChannelTypeT MatchChannelType(const char *ident)
1217 if(al::strcasecmp(ident, "mono") == 0)
1218 return CT_MONO;
1219 if(al::strcasecmp(ident, "stereo") == 0)
1220 return CT_STEREO;
1221 return CT_NONE;
1225 // Process the data set definition to read and validate the data set metrics.
1226 static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint truncSize, const ChannelModeT chanMode, HrirDataT *hData)
1228 int hasRate = 0, hasType = 0, hasPoints = 0, hasRadius = 0;
1229 int hasDistance = 0, hasAzimuths = 0;
1230 char ident[MAX_IDENT_LEN+1];
1231 uint line, col;
1232 double fpVal;
1233 uint points;
1234 int intVal;
1235 double distances[MAX_FD_COUNT];
1236 uint fdCount = 0;
1237 uint evCounts[MAX_FD_COUNT];
1238 std::vector<uint> azCounts(MAX_FD_COUNT * MAX_EV_COUNT);
1240 TrIndication(tr, &line, &col);
1241 while(TrIsIdent(tr))
1243 TrIndication(tr, &line, &col);
1244 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1245 return 0;
1246 if(al::strcasecmp(ident, "rate") == 0)
1248 if(hasRate)
1250 TrErrorAt(tr, line, col, "Redefinition of 'rate'.\n");
1251 return 0;
1253 if(!TrReadOperator(tr, "="))
1254 return 0;
1255 if(!TrReadInt(tr, MIN_RATE, MAX_RATE, &intVal))
1256 return 0;
1257 hData->mIrRate = static_cast<uint>(intVal);
1258 hasRate = 1;
1260 else if(al::strcasecmp(ident, "type") == 0)
1262 char type[MAX_IDENT_LEN+1];
1264 if(hasType)
1266 TrErrorAt(tr, line, col, "Redefinition of 'type'.\n");
1267 return 0;
1269 if(!TrReadOperator(tr, "="))
1270 return 0;
1272 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1273 return 0;
1274 hData->mChannelType = MatchChannelType(type);
1275 if(hData->mChannelType == CT_NONE)
1277 TrErrorAt(tr, line, col, "Expected a channel type.\n");
1278 return 0;
1280 else if(hData->mChannelType == CT_STEREO)
1282 if(chanMode == CM_ForceMono)
1283 hData->mChannelType = CT_MONO;
1285 hasType = 1;
1287 else if(al::strcasecmp(ident, "points") == 0)
1289 if(hasPoints)
1291 TrErrorAt(tr, line, col, "Redefinition of 'points'.\n");
1292 return 0;
1294 if(!TrReadOperator(tr, "="))
1295 return 0;
1296 TrIndication(tr, &line, &col);
1297 if(!TrReadInt(tr, MIN_POINTS, MAX_POINTS, &intVal))
1298 return 0;
1299 points = static_cast<uint>(intVal);
1300 if(fftSize > 0 && points > fftSize)
1302 TrErrorAt(tr, line, col, "Value exceeds the overridden FFT size.\n");
1303 return 0;
1305 if(points < truncSize)
1307 TrErrorAt(tr, line, col, "Value is below the truncation size.\n");
1308 return 0;
1310 hData->mIrPoints = points;
1311 hData->mFftSize = fftSize;
1312 hData->mIrSize = 1 + (fftSize / 2);
1313 if(points > hData->mIrSize)
1314 hData->mIrSize = points;
1315 hasPoints = 1;
1317 else if(al::strcasecmp(ident, "radius") == 0)
1319 if(hasRadius)
1321 TrErrorAt(tr, line, col, "Redefinition of 'radius'.\n");
1322 return 0;
1324 if(!TrReadOperator(tr, "="))
1325 return 0;
1326 if(!TrReadFloat(tr, MIN_RADIUS, MAX_RADIUS, &fpVal))
1327 return 0;
1328 hData->mRadius = fpVal;
1329 hasRadius = 1;
1331 else if(al::strcasecmp(ident, "distance") == 0)
1333 uint count = 0;
1335 if(hasDistance)
1337 TrErrorAt(tr, line, col, "Redefinition of 'distance'.\n");
1338 return 0;
1340 if(!TrReadOperator(tr, "="))
1341 return 0;
1343 for(;;)
1345 if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, &fpVal))
1346 return 0;
1347 if(count > 0 && fpVal <= distances[count - 1])
1349 TrError(tr, "Distances are not ascending.\n");
1350 return 0;
1352 distances[count++] = fpVal;
1353 if(!TrIsOperator(tr, ","))
1354 break;
1355 if(count >= MAX_FD_COUNT)
1357 TrError(tr, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT);
1358 return 0;
1360 TrReadOperator(tr, ",");
1362 if(fdCount != 0 && count != fdCount)
1364 TrError(tr, "Did not match the specified number of %d fields.\n", fdCount);
1365 return 0;
1367 fdCount = count;
1368 hasDistance = 1;
1370 else if(al::strcasecmp(ident, "azimuths") == 0)
1372 uint count = 0;
1374 if(hasAzimuths)
1376 TrErrorAt(tr, line, col, "Redefinition of 'azimuths'.\n");
1377 return 0;
1379 if(!TrReadOperator(tr, "="))
1380 return 0;
1382 evCounts[0] = 0;
1383 for(;;)
1385 if(!TrReadInt(tr, MIN_AZ_COUNT, MAX_AZ_COUNT, &intVal))
1386 return 0;
1387 azCounts[(count * MAX_EV_COUNT) + evCounts[count]++] = static_cast<uint>(intVal);
1388 if(TrIsOperator(tr, ","))
1390 if(evCounts[count] >= MAX_EV_COUNT)
1392 TrError(tr, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT);
1393 return 0;
1395 TrReadOperator(tr, ",");
1397 else
1399 if(evCounts[count] < MIN_EV_COUNT)
1401 TrErrorAt(tr, line, col, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT);
1402 return 0;
1404 if(azCounts[count * MAX_EV_COUNT] != 1 || azCounts[(count * MAX_EV_COUNT) + evCounts[count] - 1] != 1)
1406 TrError(tr, "Poles are not singular for field %d.\n", count - 1);
1407 return 0;
1409 count++;
1410 if(!TrIsOperator(tr, ";"))
1411 break;
1413 if(count >= MAX_FD_COUNT)
1415 TrError(tr, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT);
1416 return 0;
1418 evCounts[count] = 0;
1419 TrReadOperator(tr, ";");
1422 if(fdCount != 0 && count != fdCount)
1424 TrError(tr, "Did not match the specified number of %d fields.\n", fdCount);
1425 return 0;
1427 fdCount = count;
1428 hasAzimuths = 1;
1430 else
1432 TrErrorAt(tr, line, col, "Expected a metric name.\n");
1433 return 0;
1435 TrSkipWhitespace(tr);
1437 if(!(hasRate && hasPoints && hasRadius && hasDistance && hasAzimuths))
1439 TrErrorAt(tr, line, col, "Expected a metric name.\n");
1440 return 0;
1442 if(distances[0] < hData->mRadius)
1444 TrError(tr, "Distance cannot start below head radius.\n");
1445 return 0;
1447 if(hData->mChannelType == CT_NONE)
1448 hData->mChannelType = CT_MONO;
1449 if(!PrepareHrirData(fdCount, distances, evCounts, azCounts.data(), hData))
1451 fprintf(stderr, "Error: Out of memory.\n");
1452 exit(-1);
1454 return 1;
1457 // Parse an index triplet from the data set definition.
1458 static int ReadIndexTriplet(TokenReaderT *tr, const HrirDataT *hData, uint *fi, uint *ei, uint *ai)
1460 int intVal;
1462 if(hData->mFdCount > 1)
1464 if(!TrReadInt(tr, 0, static_cast<int>(hData->mFdCount) - 1, &intVal))
1465 return 0;
1466 *fi = static_cast<uint>(intVal);
1467 if(!TrReadOperator(tr, ","))
1468 return 0;
1470 else
1472 *fi = 0;
1474 if(!TrReadInt(tr, 0, static_cast<int>(hData->mFds[*fi].mEvCount) - 1, &intVal))
1475 return 0;
1476 *ei = static_cast<uint>(intVal);
1477 if(!TrReadOperator(tr, ","))
1478 return 0;
1479 if(!TrReadInt(tr, 0, static_cast<int>(hData->mFds[*fi].mEvs[*ei].mAzCount) - 1, &intVal))
1480 return 0;
1481 *ai = static_cast<uint>(intVal);
1482 return 1;
1485 // Match the source format from a given identifier.
1486 static SourceFormatT MatchSourceFormat(const char *ident)
1488 if(al::strcasecmp(ident, "ascii") == 0)
1489 return SF_ASCII;
1490 if(al::strcasecmp(ident, "bin_le") == 0)
1491 return SF_BIN_LE;
1492 if(al::strcasecmp(ident, "bin_be") == 0)
1493 return SF_BIN_BE;
1494 if(al::strcasecmp(ident, "wave") == 0)
1495 return SF_WAVE;
1496 if(al::strcasecmp(ident, "sofa") == 0)
1497 return SF_SOFA;
1498 return SF_NONE;
1501 // Match the source element type from a given identifier.
1502 static ElementTypeT MatchElementType(const char *ident)
1504 if(al::strcasecmp(ident, "int") == 0)
1505 return ET_INT;
1506 if(al::strcasecmp(ident, "fp") == 0)
1507 return ET_FP;
1508 return ET_NONE;
1511 // Parse and validate a source reference from the data set definition.
1512 static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
1514 char ident[MAX_IDENT_LEN+1];
1515 uint line, col;
1516 double fpVal;
1517 int intVal;
1519 TrIndication(tr, &line, &col);
1520 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1521 return 0;
1522 src->mFormat = MatchSourceFormat(ident);
1523 if(src->mFormat == SF_NONE)
1525 TrErrorAt(tr, line, col, "Expected a source format.\n");
1526 return 0;
1528 if(!TrReadOperator(tr, "("))
1529 return 0;
1530 if(src->mFormat == SF_SOFA)
1532 if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, &fpVal))
1533 return 0;
1534 src->mRadius = fpVal;
1535 if(!TrReadOperator(tr, ","))
1536 return 0;
1537 if(!TrReadFloat(tr, -90.0, 90.0, &fpVal))
1538 return 0;
1539 src->mElevation = fpVal;
1540 if(!TrReadOperator(tr, ","))
1541 return 0;
1542 if(!TrReadFloat(tr, -360.0, 360.0, &fpVal))
1543 return 0;
1544 src->mAzimuth = fpVal;
1545 if(!TrReadOperator(tr, ":"))
1546 return 0;
1547 if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
1548 return 0;
1549 src->mType = ET_NONE;
1550 src->mSize = 0;
1551 src->mBits = 0;
1552 src->mChannel = static_cast<uint>(intVal);
1553 src->mSkip = 0;
1555 else if(src->mFormat == SF_WAVE)
1557 if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
1558 return 0;
1559 src->mType = ET_NONE;
1560 src->mSize = 0;
1561 src->mBits = 0;
1562 src->mChannel = static_cast<uint>(intVal);
1563 src->mSkip = 0;
1565 else
1567 TrIndication(tr, &line, &col);
1568 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1569 return 0;
1570 src->mType = MatchElementType(ident);
1571 if(src->mType == ET_NONE)
1573 TrErrorAt(tr, line, col, "Expected a source element type.\n");
1574 return 0;
1576 if(src->mFormat == SF_BIN_LE || src->mFormat == SF_BIN_BE)
1578 if(!TrReadOperator(tr, ","))
1579 return 0;
1580 if(src->mType == ET_INT)
1582 if(!TrReadInt(tr, MIN_BIN_SIZE, MAX_BIN_SIZE, &intVal))
1583 return 0;
1584 src->mSize = static_cast<uint>(intVal);
1585 if(!TrIsOperator(tr, ","))
1586 src->mBits = static_cast<int>(8*src->mSize);
1587 else
1589 TrReadOperator(tr, ",");
1590 TrIndication(tr, &line, &col);
1591 if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
1592 return 0;
1593 if(std::abs(intVal) < MIN_BIN_BITS || static_cast<uint>(std::abs(intVal)) > (8*src->mSize))
1595 TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8*src->mSize);
1596 return 0;
1598 src->mBits = intVal;
1601 else
1603 TrIndication(tr, &line, &col);
1604 if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
1605 return 0;
1606 if(intVal != 4 && intVal != 8)
1608 TrErrorAt(tr, line, col, "Expected a value of 4 or 8.\n");
1609 return 0;
1611 src->mSize = static_cast<uint>(intVal);
1612 src->mBits = 0;
1615 else if(src->mFormat == SF_ASCII && src->mType == ET_INT)
1617 if(!TrReadOperator(tr, ","))
1618 return 0;
1619 if(!TrReadInt(tr, MIN_ASCII_BITS, MAX_ASCII_BITS, &intVal))
1620 return 0;
1621 src->mSize = 0;
1622 src->mBits = intVal;
1624 else
1626 src->mSize = 0;
1627 src->mBits = 0;
1630 if(!TrIsOperator(tr, ";"))
1631 src->mSkip = 0;
1632 else
1634 TrReadOperator(tr, ";");
1635 if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1636 return 0;
1637 src->mSkip = static_cast<uint>(intVal);
1640 if(!TrReadOperator(tr, ")"))
1641 return 0;
1642 if(TrIsOperator(tr, "@"))
1644 TrReadOperator(tr, "@");
1645 if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1646 return 0;
1647 src->mOffset = static_cast<uint>(intVal);
1649 else
1650 src->mOffset = 0;
1651 if(!TrReadOperator(tr, ":"))
1652 return 0;
1653 if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
1654 return 0;
1655 return 1;
1658 // Parse and validate a SOFA source reference from the data set definition.
1659 static int ReadSofaRef(TokenReaderT *tr, SourceRefT *src)
1661 char ident[MAX_IDENT_LEN+1];
1662 uint line, col;
1663 int intVal;
1665 TrIndication(tr, &line, &col);
1666 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1667 return 0;
1668 src->mFormat = MatchSourceFormat(ident);
1669 if(src->mFormat != SF_SOFA)
1671 TrErrorAt(tr, line, col, "Expected the SOFA source format.\n");
1672 return 0;
1675 src->mType = ET_NONE;
1676 src->mSize = 0;
1677 src->mBits = 0;
1678 src->mChannel = 0;
1679 src->mSkip = 0;
1681 if(TrIsOperator(tr, "@"))
1683 TrReadOperator(tr, "@");
1684 if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal))
1685 return 0;
1686 src->mOffset = static_cast<uint>(intVal);
1688 else
1689 src->mOffset = 0;
1690 if(!TrReadOperator(tr, ":"))
1691 return 0;
1692 if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
1693 return 0;
1694 return 1;
1697 // Match the target ear (index) from a given identifier.
1698 static int MatchTargetEar(const char *ident)
1700 if(al::strcasecmp(ident, "left") == 0)
1701 return 0;
1702 if(al::strcasecmp(ident, "right") == 0)
1703 return 1;
1704 return -1;
1707 // Calculate the onset time of an HRIR and average it with any existing
1708 // timing for its field, elevation, azimuth, and ear.
1709 static double AverageHrirOnset(const uint rate, const uint n, const double *hrir, const double f, const double onset)
1711 std::vector<double> upsampled(10 * n);
1713 ResamplerT rs;
1714 ResamplerSetup(&rs, rate, 10 * rate);
1715 ResamplerRun(&rs, n, hrir, 10 * n, upsampled.data());
1718 double mag{0.0};
1719 for(uint i{0u};i < 10*n;i++)
1720 mag = std::max(std::abs(upsampled[i]), mag);
1722 mag *= 0.15;
1723 uint i{0u};
1724 for(;i < 10*n;i++)
1726 if(std::abs(upsampled[i]) >= mag)
1727 break;
1729 return Lerp(onset, static_cast<double>(i) / (10*rate), f);
1732 // Calculate the magnitude response of an HRIR and average it with any
1733 // existing responses for its field, elevation, azimuth, and ear.
1734 static void AverageHrirMagnitude(const uint points, const uint n, const double *hrir, const double f, double *mag)
1736 uint m = 1 + (n / 2), i;
1737 std::vector<complex_d> h(n);
1738 std::vector<double> r(n);
1740 for(i = 0;i < points;i++)
1741 h[i] = complex_d{hrir[i], 0.0};
1742 for(;i < n;i++)
1743 h[i] = complex_d{0.0, 0.0};
1744 FftForward(n, h.data());
1745 MagnitudeResponse(n, h.data(), r.data());
1746 for(i = 0;i < m;i++)
1747 mag[i] = Lerp(mag[i], r[i], f);
1750 // Process the list of sources in the data set definition.
1751 static int ProcessSources(TokenReaderT *tr, HrirDataT *hData)
1753 uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
1754 hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize);
1755 double *hrirs = hData->mHrirsBase.data();
1756 std::vector<double> hrir(hData->mIrPoints);
1757 uint line, col, fi, ei, ai;
1758 int count;
1760 printf("Loading sources...");
1761 fflush(stdout);
1762 count = 0;
1763 while(TrIsOperator(tr, "["))
1765 double factor[2]{ 1.0, 1.0 };
1767 TrIndication(tr, &line, &col);
1768 TrReadOperator(tr, "[");
1770 if(TrIsOperator(tr, "*"))
1772 SourceRefT src;
1773 struct MYSOFA_EASY *sofa;
1774 uint si;
1776 TrReadOperator(tr, "*");
1777 if(!TrReadOperator(tr, "]") || !TrReadOperator(tr, "="))
1778 return 0;
1780 TrIndication(tr, &line, &col);
1781 if(!ReadSofaRef(tr, &src))
1782 return 0;
1784 if(hData->mChannelType == CT_STEREO)
1786 char type[MAX_IDENT_LEN+1];
1787 ChannelTypeT channelType;
1789 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1790 return 0;
1792 channelType = MatchChannelType(type);
1794 switch(channelType)
1796 case CT_NONE:
1797 TrErrorAt(tr, line, col, "Expected a channel type.\n");
1798 return 0;
1799 case CT_MONO:
1800 src.mChannel = 0;
1801 break;
1802 case CT_STEREO:
1803 src.mChannel = 1;
1804 break;
1807 else
1809 char type[MAX_IDENT_LEN+1];
1810 ChannelTypeT channelType;
1812 if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
1813 return 0;
1815 channelType = MatchChannelType(type);
1816 if(channelType != CT_MONO)
1818 TrErrorAt(tr, line, col, "Expected a mono channel type.\n");
1819 return 0;
1821 src.mChannel = 0;
1824 sofa = LoadSofaFile(&src, hData->mIrRate, hData->mIrPoints);
1825 if(!sofa) return 0;
1827 for(si = 0;si < sofa->hrtf->M;si++)
1829 printf("\rLoading sources... %d of %d", si+1, sofa->hrtf->M);
1830 fflush(stdout);
1832 float aer[3] = {
1833 sofa->hrtf->SourcePosition.values[3*si],
1834 sofa->hrtf->SourcePosition.values[3*si + 1],
1835 sofa->hrtf->SourcePosition.values[3*si + 2]
1837 mysofa_c2s(aer);
1839 if(std::fabs(aer[1]) >= 89.999f)
1840 aer[0] = 0.0f;
1841 else
1842 aer[0] = std::fmod(360.0f - aer[0], 360.0f);
1844 for(fi = 0;fi < hData->mFdCount;fi++)
1846 double delta = aer[2] - hData->mFds[fi].mDistance;
1847 if(std::abs(delta) < 0.001) break;
1849 if(fi >= hData->mFdCount)
1850 continue;
1852 double ef{(90.0 + aer[1]) / 180.0 * (hData->mFds[fi].mEvCount - 1)};
1853 ei = static_cast<uint>(std::round(ef));
1854 ef = (ef - ei) * 180.0 / (hData->mFds[fi].mEvCount - 1);
1855 if(std::abs(ef) >= 0.1)
1856 continue;
1858 double af{aer[0] / 360.0 * hData->mFds[fi].mEvs[ei].mAzCount};
1859 ai = static_cast<uint>(std::round(af));
1860 af = (af - ai) * 360.0 / hData->mFds[fi].mEvs[ei].mAzCount;
1861 ai = ai % hData->mFds[fi].mEvs[ei].mAzCount;
1862 if(std::abs(af) >= 0.1)
1863 continue;
1865 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1866 if(azd->mIrs[0] != nullptr)
1868 TrErrorAt(tr, line, col, "Redefinition of source [ %d, %d, %d ].\n", fi, ei, ai);
1869 return 0;
1872 ExtractSofaHrir(sofa, si, 0, src.mOffset, hData->mIrPoints, hrir.data());
1873 azd->mIrs[0] = &hrirs[hData->mIrSize * azd->mIndex];
1874 azd->mDelays[0] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[0]);
1875 AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0, azd->mIrs[0]);
1877 if(src.mChannel == 1)
1879 ExtractSofaHrir(sofa, si, 1, src.mOffset, hData->mIrPoints, hrir.data());
1880 azd->mIrs[1] = &hrirs[hData->mIrSize * (hData->mIrCount + azd->mIndex)];
1881 azd->mDelays[1] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[1]);
1882 AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0, azd->mIrs[1]);
1885 // TODO: Since some SOFA files contain minimum phase HRIRs,
1886 // it would be beneficial to check for per-measurement delays
1887 // (when available) to reconstruct the HRTDs.
1890 continue;
1893 if(!ReadIndexTriplet(tr, hData, &fi, &ei, &ai))
1894 return 0;
1895 if(!TrReadOperator(tr, "]"))
1896 return 0;
1897 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1899 if(azd->mIrs[0] != nullptr)
1901 TrErrorAt(tr, line, col, "Redefinition of source.\n");
1902 return 0;
1904 if(!TrReadOperator(tr, "="))
1905 return 0;
1907 for(;;)
1909 SourceRefT src;
1911 if(!ReadSourceRef(tr, &src))
1912 return 0;
1914 // TODO: Would be nice to display 'x of y files', but that would
1915 // require preparing the source refs first to get a total count
1916 // before loading them.
1917 ++count;
1918 printf("\rLoading sources... %d file%s", count, (count==1)?"":"s");
1919 fflush(stdout);
1921 if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.data()))
1922 return 0;
1924 uint ti{0};
1925 if(hData->mChannelType == CT_STEREO)
1927 char ident[MAX_IDENT_LEN+1];
1929 if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
1930 return 0;
1931 ti = static_cast<uint>(MatchTargetEar(ident));
1932 if(static_cast<int>(ti) < 0)
1934 TrErrorAt(tr, line, col, "Expected a target ear.\n");
1935 return 0;
1938 azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
1939 azd->mDelays[ti] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0 / factor[ti], azd->mDelays[ti]);
1940 AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir.data(), 1.0 / factor[ti], azd->mIrs[ti]);
1941 factor[ti] += 1.0;
1942 if(!TrIsOperator(tr, "+"))
1943 break;
1944 TrReadOperator(tr, "+");
1946 if(hData->mChannelType == CT_STEREO)
1948 if(azd->mIrs[0] == nullptr)
1950 TrErrorAt(tr, line, col, "Missing left ear source reference(s).\n");
1951 return 0;
1953 else if(azd->mIrs[1] == nullptr)
1955 TrErrorAt(tr, line, col, "Missing right ear source reference(s).\n");
1956 return 0;
1960 printf("\n");
1961 for(fi = 0;fi < hData->mFdCount;fi++)
1963 for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
1965 for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
1967 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1968 if(azd->mIrs[0] != nullptr)
1969 break;
1971 if(ai < hData->mFds[fi].mEvs[ei].mAzCount)
1972 break;
1974 if(ei >= hData->mFds[fi].mEvCount)
1976 TrError(tr, "Missing source references [ %d, *, * ].\n", fi);
1977 return 0;
1979 hData->mFds[fi].mEvStart = ei;
1980 for(;ei < hData->mFds[fi].mEvCount;ei++)
1982 for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
1984 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
1986 if(azd->mIrs[0] == nullptr)
1988 TrError(tr, "Missing source reference [ %d, %d, %d ].\n", fi, ei, ai);
1989 return 0;
1994 for(uint ti{0};ti < channels;ti++)
1996 for(fi = 0;fi < hData->mFdCount;fi++)
1998 for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
2000 for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
2002 HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
2004 azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
2009 if(!TrLoad(tr))
2011 mysofa_cache_release_all();
2012 return 1;
2015 TrError(tr, "Errant data at end of source list.\n");
2016 mysofa_cache_release_all();
2017 return 0;
2021 bool LoadDefInput(std::istream &istream, const char *startbytes, std::streamsize startbytecount,
2022 const char *filename, const uint fftSize, const uint truncSize, const ChannelModeT chanMode,
2023 HrirDataT *hData)
2025 TokenReaderT tr{istream};
2027 TrSetup(startbytes, startbytecount, filename, &tr);
2028 if(!ProcessMetrics(&tr, fftSize, truncSize, chanMode, hData)
2029 || !ProcessSources(&tr, hData))
2030 return false;
2032 return true;