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
38 #include "alfstream.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.
54 std::istream
&mIStream
;
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
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
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)
115 // Source format for the references listed in the data set definition.
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.
128 ET_INT
, // Integer elements.
129 ET_FP
// Floating-point elements.
132 // Source reference state used when loading sources.
134 SourceFormatT mFormat
;
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
,
158 const char *name
= nullptr;
162 const char *slash
= strrchr(filename
, '/');
165 const char *bslash
= strrchr(slash
+1, '\\');
166 if(bslash
) name
= bslash
+1;
171 const char *bslash
= strrchr(filename
, '\\');
172 if(bslash
) name
= bslash
+1;
173 else name
= filename
;
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
};
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();
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
)
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
)
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
, ...)
241 va_start(argPtr
, format
);
242 TrErrorVA(tr
, line
, column
, format
, argPtr
);
246 // Used to display an error at the current line/column.
247 static void TrError(const TokenReaderT
*tr
, const char *format
, ...)
251 va_start(argPtr
, format
);
252 TrErrorVA(tr
, tr
->mLine
, tr
->mColumn
, format
, argPtr
);
256 // Skips to the next line.
257 static void TrSkipLine(TokenReaderT
*tr
)
263 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
275 // Skips to the next token.
276 static int TrSkipWhitespace(TokenReaderT
*tr
)
280 char ch
{tr
->mRing
[tr
->mOut
&TR_RING_MASK
]};
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
))
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
)
327 if(!TrSkipWhitespace(tr
))
331 while(op
[len
] != '\0' && out
< tr
->mIn
)
333 ch
= tr
->mRing
[out
&TR_RING_MASK
];
334 if(ch
!= op
[len
]) break;
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
348 // Reads and validates an identifier token.
349 static int TrReadIdent(TokenReaderT
*tr
, const uint maxLen
, char *ident
)
355 if(TrSkipWhitespace(tr
))
358 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
359 if(ch
== '_' || isalpha(ch
))
369 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
370 } while(ch
== '_' || isdigit(ch
) || isalpha(ch
));
378 TrErrorAt(tr
, tr
->mLine
, col
, "Identifier is too long.\n");
382 TrErrorAt(tr
, tr
->mLine
, col
, "Expected an identifier.\n");
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
;
393 if(TrSkipWhitespace(tr
))
397 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
398 if(ch
== '+' || ch
== '-')
407 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
408 if(!isdigit(ch
)) break;
416 if(digis
> 0 && ch
!= '.' && !isalpha(ch
))
420 TrErrorAt(tr
, tr
->mLine
, col
, "Integer is too long.");
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
);
433 TrErrorAt(tr
, tr
->mLine
, col
, "Expected an integer.\n");
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
;
444 if(TrSkipWhitespace(tr
))
448 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
449 if(ch
== '+' || ch
== '-')
459 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
460 if(!isdigit(ch
)) break;
476 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
477 if(!isdigit(ch
)) break;
486 if(ch
== 'E' || ch
== 'e')
493 if(ch
== '+' || ch
== '-')
502 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
503 if(!isdigit(ch
)) break;
512 if(digis
> 0 && ch
!= '.' && !isalpha(ch
))
516 TrErrorAt(tr
, tr
->mLine
, col
, "Float is too long.");
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
);
532 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a float.\n");
536 // Reads and validates a string token.
537 static int TrReadString(TokenReaderT
*tr
, const uint maxLen
, char *text
)
543 if(TrSkipWhitespace(tr
))
546 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
553 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
559 TrErrorAt(tr
, tr
->mLine
, col
, "Unterminated string at end of line.\n");
568 tr
->mColumn
+= 1 + len
;
569 TrErrorAt(tr
, tr
->mLine
, col
, "Unterminated string at end of input.\n");
572 tr
->mColumn
+= 2 + len
;
575 TrErrorAt(tr
, tr
->mLine
, col
, "String is too long.\n");
582 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a string.\n");
586 // Reads and validates the given operator.
587 static int TrReadOperator(TokenReaderT
*tr
, const char *op
)
593 if(TrSkipWhitespace(tr
))
597 while(op
[len
] != '\0' && TrLoad(tr
))
599 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
600 if(ch
!= op
[len
]) break;
608 TrErrorAt(tr
, tr
->mLine
, col
, "Expected '%s' operator.\n", op
);
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
)
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
);
632 for(uint i
= 0;i
< bytes
;i
++)
633 accum
= (accum
<<8) | in
[bytes
- i
- 1];
636 for(uint i
= 0;i
< bytes
;i
++)
637 accum
= (accum
<<8) | in
[i
];
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
)
654 istream
.read(reinterpret_cast<char*>(in
), 8);
655 if(istream
.gcount() != 8)
657 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
665 accum
= (accum
<<8) | in
[8 - i
- 1];
669 accum
= (accum
<<8) | in
[i
];
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
)
700 if(!ReadBin8(istream
, filename
, order
, &v8
.ui
))
707 if(!ReadBin4(istream
, filename
, order
, bytes
, &v4
.ui
))
714 v4
.ui
>>= (8*bytes
) - (static_cast<uint
>(bits
));
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));
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
, "|");
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
);
754 if(!TrReadInt(tr
, -(1<<(bits
-1)), (1<<(bits
-1))-1, &v
))
756 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
759 *out
= v
/ static_cast<double>((1<<(bits
-1))-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
,
769 uint32_t fourCC
, chunkSize
;
770 uint32_t format
, channels
, rate
, dummy
, block
, size
, bits
;
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
))
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
))
789 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &size
))
797 if(format
== WAVE_FORMAT_EXTENSIBLE
)
799 istream
.seekg(2, std::ios::cur
);
800 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &bits
))
804 istream
.seekg(4, std::ios::cur
);
805 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &format
))
807 istream
.seekg(static_cast<int>(chunkSize
- 26), std::ios::cur
);
813 istream
.seekg(static_cast<int>(chunkSize
- 16), std::ios::cur
);
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
);
822 if(src
->mChannel
>= channels
)
824 fprintf(stderr
, "\nError: Missing source channel in WAVE file '%s'.\n", src
->mPath
);
829 fprintf(stderr
, "\nError: Mismatched source sample rate in WAVE file '%s'.\n", src
->mPath
);
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
);
839 if(bits
< 16 || bits
> (8*size
))
841 fprintf(stderr
, "\nError: Bad significant bits in WAVE file '%s'.\n", src
->mPath
);
848 if(size
!= 4 && size
!= 8)
850 fprintf(stderr
, "\nError: Unsupported sample size in WAVE file '%s'.\n", src
->mPath
);
856 src
->mBits
= static_cast<int>(bits
);
857 src
->mSkip
= channels
;
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
)
868 pre
= static_cast<int>(src
->mSize
* src
->mChannel
);
869 post
= static_cast<int>(src
->mSize
* (src
->mSkip
- src
->mChannel
- 1));
875 istream
.seekg(skip
, std::ios::cur
);
876 if(!ReadBinAsDouble(istream
, src
->mPath
, order
, src
->mType
, src
->mSize
, src
->mBits
, &hrir
[i
]))
881 istream
.seekg(skip
, std::ios::cur
);
885 // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to
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
;
896 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
897 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
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
);
909 istream
.seekg(static_cast<long>(src
->mOffset
* block
), std::ios::cur
);
910 if(!ReadWaveData(istream
, src
, order
, n
, &hrir
[0]))
914 else if(fourCC
== FOURCC_LIST
)
916 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
))
919 if(fourCC
== FOURCC_WAVL
)
923 istream
.seekg(static_cast<long>(chunkSize
), std::ios::cur
);
925 listSize
= chunkSize
;
926 block
= src
->mSize
* src
->mSkip
;
930 while(offset
< n
&& listSize
> 8)
932 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
933 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
935 listSize
-= 8 + chunkSize
;
936 if(fourCC
== FOURCC_DATA
)
938 count
= chunkSize
/ block
;
941 istream
.seekg(static_cast<long>(skip
* block
), std::ios::cur
);
942 chunkSize
-= skip
* block
;
945 if(count
> (n
- offset
))
947 if(!ReadWaveData(istream
, src
, order
, count
, &hrir
[offset
]))
949 chunkSize
-= count
* block
;
951 lastSample
= hrir
[offset
- 1];
959 else if(fourCC
== FOURCC_SLNT
)
961 if(!ReadBin4(istream
, src
->mPath
, order
, 4, &count
))
968 if(count
> (n
- offset
))
970 for(i
= 0; i
< count
; i
++)
971 hrir
[offset
+ i
] = lastSample
;
981 istream
.seekg(static_cast<long>(chunkSize
), std::ios::cur
);
985 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", src
->mPath
);
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
};
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
))
1006 for(i
= 0;i
< n
;i
++)
1008 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &hrir
[i
]))
1010 for(j
= 0;j
< src
->mSkip
;j
++)
1012 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &dummy
))
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
]))
1029 istream
.seekg(static_cast<long>(src
->mSkip
), std::ios::cur
);
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
;
1041 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
1042 || !ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &dummy
))
1044 if(fourCC
== FOURCC_RIFF
)
1046 else if(fourCC
== FOURCC_RIFX
)
1050 fprintf(stderr
, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src
->mPath
);
1054 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
))
1056 if(fourCC
!= FOURCC_WAVE
)
1058 fprintf(stderr
, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src
->mPath
);
1061 if(!ReadWaveFormat(istream
, order
, hrirRate
, src
))
1063 if(!ReadWaveList(istream
, src
, order
, n
, hrir
))
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
)));
1079 fprintf(stderr
, "\nError: Out of memory.\n");
1082 sofa
->lookup
= nullptr;
1083 sofa
->neighborhood
= nullptr;
1086 sofa
->hrtf
= mysofa_load(src
->mPath
, &err
);
1090 fprintf(stderr
, "\nError: Could not load source file '%s'.\n", src
->mPath
);
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
)
1100 fprintf(stderr
, "\nError: Not enough samples in SOFA file '%s'.\n", src
->mPath
);
1103 if(src
->mChannel
>= sofa
->hrtf
->R
)
1106 fprintf(stderr
, "\nError: Missing source receiver in SOFA file '%s'.\n", src
->mPath
);
1109 mysofa_tocartesian(sofa
->hrtf
);
1110 sofa
->lookup
= mysofa_lookup_init(sofa
->hrtf
);
1111 if(sofa
->lookup
== nullptr)
1114 fprintf(stderr
, "\nError: Out of memory.\n");
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)
1129 static int LoadSofaSource(SourceRefT
*src
, const uint hrirRate
, const uint n
, double *hrir
)
1131 struct MYSOFA_EASY
*sofa
;
1136 sofa
= LoadSofaFile(src
, hrirRate
, n
);
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
);
1149 nearest
= mysofa_lookup(sofa
->lookup
, target
);
1152 fprintf(stderr
, "\nError: Lookup failed in source file '%s'.\n", src
->mPath
);
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];
1164 fprintf(stderr
, " Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target
[2], target
[1], target
[0]);
1168 ExtractSofaHrir(sofa
, static_cast<uint
>(nearest
), src
->mChannel
, src
->mOffset
, n
, hrir
);
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
});
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
);
1190 switch(src
->mFormat
)
1193 result
= LoadAsciiSource(*istream
, src
, n
, hrir
);
1196 result
= LoadBinarySource(*istream
, src
, BO_LITTLE
, n
, hrir
);
1199 result
= LoadBinarySource(*istream
, src
, BO_BIG
, n
, hrir
);
1202 result
= LoadWaveSource(*istream
, src
, hrirRate
, n
, hrir
);
1205 result
= LoadSofaSource(src
, hrirRate
, n
, hrir
);
1214 // Match the channel type from a given identifier.
1215 static ChannelTypeT
MatchChannelType(const char *ident
)
1217 if(al::strcasecmp(ident
, "mono") == 0)
1219 if(al::strcasecmp(ident
, "stereo") == 0)
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];
1235 double distances
[MAX_FD_COUNT
];
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
))
1246 if(al::strcasecmp(ident
, "rate") == 0)
1250 TrErrorAt(tr
, line
, col
, "Redefinition of 'rate'.\n");
1253 if(!TrReadOperator(tr
, "="))
1255 if(!TrReadInt(tr
, MIN_RATE
, MAX_RATE
, &intVal
))
1257 hData
->mIrRate
= static_cast<uint
>(intVal
);
1260 else if(al::strcasecmp(ident
, "type") == 0)
1262 char type
[MAX_IDENT_LEN
+1];
1266 TrErrorAt(tr
, line
, col
, "Redefinition of 'type'.\n");
1269 if(!TrReadOperator(tr
, "="))
1272 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1274 hData
->mChannelType
= MatchChannelType(type
);
1275 if(hData
->mChannelType
== CT_NONE
)
1277 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1280 else if(hData
->mChannelType
== CT_STEREO
)
1282 if(chanMode
== CM_ForceMono
)
1283 hData
->mChannelType
= CT_MONO
;
1287 else if(al::strcasecmp(ident
, "points") == 0)
1291 TrErrorAt(tr
, line
, col
, "Redefinition of 'points'.\n");
1294 if(!TrReadOperator(tr
, "="))
1296 TrIndication(tr
, &line
, &col
);
1297 if(!TrReadInt(tr
, MIN_POINTS
, MAX_POINTS
, &intVal
))
1299 points
= static_cast<uint
>(intVal
);
1300 if(fftSize
> 0 && points
> fftSize
)
1302 TrErrorAt(tr
, line
, col
, "Value exceeds the overridden FFT size.\n");
1305 if(points
< truncSize
)
1307 TrErrorAt(tr
, line
, col
, "Value is below the truncation size.\n");
1310 hData
->mIrPoints
= points
;
1311 hData
->mFftSize
= fftSize
;
1312 hData
->mIrSize
= 1 + (fftSize
/ 2);
1313 if(points
> hData
->mIrSize
)
1314 hData
->mIrSize
= points
;
1317 else if(al::strcasecmp(ident
, "radius") == 0)
1321 TrErrorAt(tr
, line
, col
, "Redefinition of 'radius'.\n");
1324 if(!TrReadOperator(tr
, "="))
1326 if(!TrReadFloat(tr
, MIN_RADIUS
, MAX_RADIUS
, &fpVal
))
1328 hData
->mRadius
= fpVal
;
1331 else if(al::strcasecmp(ident
, "distance") == 0)
1337 TrErrorAt(tr
, line
, col
, "Redefinition of 'distance'.\n");
1340 if(!TrReadOperator(tr
, "="))
1345 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1347 if(count
> 0 && fpVal
<= distances
[count
- 1])
1349 TrError(tr
, "Distances are not ascending.\n");
1352 distances
[count
++] = fpVal
;
1353 if(!TrIsOperator(tr
, ","))
1355 if(count
>= MAX_FD_COUNT
)
1357 TrError(tr
, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT
);
1360 TrReadOperator(tr
, ",");
1362 if(fdCount
!= 0 && count
!= fdCount
)
1364 TrError(tr
, "Did not match the specified number of %d fields.\n", fdCount
);
1370 else if(al::strcasecmp(ident
, "azimuths") == 0)
1376 TrErrorAt(tr
, line
, col
, "Redefinition of 'azimuths'.\n");
1379 if(!TrReadOperator(tr
, "="))
1385 if(!TrReadInt(tr
, MIN_AZ_COUNT
, MAX_AZ_COUNT
, &intVal
))
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
);
1395 TrReadOperator(tr
, ",");
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
);
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);
1410 if(!TrIsOperator(tr
, ";"))
1413 if(count
>= MAX_FD_COUNT
)
1415 TrError(tr
, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT
);
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
);
1432 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1435 TrSkipWhitespace(tr
);
1437 if(!(hasRate
&& hasPoints
&& hasRadius
&& hasDistance
&& hasAzimuths
))
1439 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1442 if(distances
[0] < hData
->mRadius
)
1444 TrError(tr
, "Distance cannot start below head radius.\n");
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");
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
)
1462 if(hData
->mFdCount
> 1)
1464 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFdCount
) - 1, &intVal
))
1466 *fi
= static_cast<uint
>(intVal
);
1467 if(!TrReadOperator(tr
, ","))
1474 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvCount
) - 1, &intVal
))
1476 *ei
= static_cast<uint
>(intVal
);
1477 if(!TrReadOperator(tr
, ","))
1479 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvs
[*ei
].mAzCount
) - 1, &intVal
))
1481 *ai
= static_cast<uint
>(intVal
);
1485 // Match the source format from a given identifier.
1486 static SourceFormatT
MatchSourceFormat(const char *ident
)
1488 if(al::strcasecmp(ident
, "ascii") == 0)
1490 if(al::strcasecmp(ident
, "bin_le") == 0)
1492 if(al::strcasecmp(ident
, "bin_be") == 0)
1494 if(al::strcasecmp(ident
, "wave") == 0)
1496 if(al::strcasecmp(ident
, "sofa") == 0)
1501 // Match the source element type from a given identifier.
1502 static ElementTypeT
MatchElementType(const char *ident
)
1504 if(al::strcasecmp(ident
, "int") == 0)
1506 if(al::strcasecmp(ident
, "fp") == 0)
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];
1519 TrIndication(tr
, &line
, &col
);
1520 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1522 src
->mFormat
= MatchSourceFormat(ident
);
1523 if(src
->mFormat
== SF_NONE
)
1525 TrErrorAt(tr
, line
, col
, "Expected a source format.\n");
1528 if(!TrReadOperator(tr
, "("))
1530 if(src
->mFormat
== SF_SOFA
)
1532 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1534 src
->mRadius
= fpVal
;
1535 if(!TrReadOperator(tr
, ","))
1537 if(!TrReadFloat(tr
, -90.0, 90.0, &fpVal
))
1539 src
->mElevation
= fpVal
;
1540 if(!TrReadOperator(tr
, ","))
1542 if(!TrReadFloat(tr
, -360.0, 360.0, &fpVal
))
1544 src
->mAzimuth
= fpVal
;
1545 if(!TrReadOperator(tr
, ":"))
1547 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1549 src
->mType
= ET_NONE
;
1552 src
->mChannel
= static_cast<uint
>(intVal
);
1555 else if(src
->mFormat
== SF_WAVE
)
1557 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1559 src
->mType
= ET_NONE
;
1562 src
->mChannel
= static_cast<uint
>(intVal
);
1567 TrIndication(tr
, &line
, &col
);
1568 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1570 src
->mType
= MatchElementType(ident
);
1571 if(src
->mType
== ET_NONE
)
1573 TrErrorAt(tr
, line
, col
, "Expected a source element type.\n");
1576 if(src
->mFormat
== SF_BIN_LE
|| src
->mFormat
== SF_BIN_BE
)
1578 if(!TrReadOperator(tr
, ","))
1580 if(src
->mType
== ET_INT
)
1582 if(!TrReadInt(tr
, MIN_BIN_SIZE
, MAX_BIN_SIZE
, &intVal
))
1584 src
->mSize
= static_cast<uint
>(intVal
);
1585 if(!TrIsOperator(tr
, ","))
1586 src
->mBits
= static_cast<int>(8*src
->mSize
);
1589 TrReadOperator(tr
, ",");
1590 TrIndication(tr
, &line
, &col
);
1591 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
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
);
1598 src
->mBits
= intVal
;
1603 TrIndication(tr
, &line
, &col
);
1604 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
1606 if(intVal
!= 4 && intVal
!= 8)
1608 TrErrorAt(tr
, line
, col
, "Expected a value of 4 or 8.\n");
1611 src
->mSize
= static_cast<uint
>(intVal
);
1615 else if(src
->mFormat
== SF_ASCII
&& src
->mType
== ET_INT
)
1617 if(!TrReadOperator(tr
, ","))
1619 if(!TrReadInt(tr
, MIN_ASCII_BITS
, MAX_ASCII_BITS
, &intVal
))
1622 src
->mBits
= intVal
;
1630 if(!TrIsOperator(tr
, ";"))
1634 TrReadOperator(tr
, ";");
1635 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1637 src
->mSkip
= static_cast<uint
>(intVal
);
1640 if(!TrReadOperator(tr
, ")"))
1642 if(TrIsOperator(tr
, "@"))
1644 TrReadOperator(tr
, "@");
1645 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1647 src
->mOffset
= static_cast<uint
>(intVal
);
1651 if(!TrReadOperator(tr
, ":"))
1653 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
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];
1665 TrIndication(tr
, &line
, &col
);
1666 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1668 src
->mFormat
= MatchSourceFormat(ident
);
1669 if(src
->mFormat
!= SF_SOFA
)
1671 TrErrorAt(tr
, line
, col
, "Expected the SOFA source format.\n");
1675 src
->mType
= ET_NONE
;
1681 if(TrIsOperator(tr
, "@"))
1683 TrReadOperator(tr
, "@");
1684 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1686 src
->mOffset
= static_cast<uint
>(intVal
);
1690 if(!TrReadOperator(tr
, ":"))
1692 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
1697 // Match the target ear (index) from a given identifier.
1698 static int MatchTargetEar(const char *ident
)
1700 if(al::strcasecmp(ident
, "left") == 0)
1702 if(al::strcasecmp(ident
, "right") == 0)
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
);
1714 ResamplerSetup(&rs
, rate
, 10 * rate
);
1715 ResamplerRun(&rs
, n
, hrir
, 10 * n
, upsampled
.data());
1719 for(uint i
{0u};i
< 10*n
;i
++)
1720 mag
= std::max(std::abs(upsampled
[i
]), mag
);
1726 if(std::abs(upsampled
[i
]) >= mag
)
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};
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
;
1760 printf("Loading sources...");
1763 while(TrIsOperator(tr
, "["))
1765 double factor
[2]{ 1.0, 1.0 };
1767 TrIndication(tr
, &line
, &col
);
1768 TrReadOperator(tr
, "[");
1770 if(TrIsOperator(tr
, "*"))
1773 struct MYSOFA_EASY
*sofa
;
1776 TrReadOperator(tr
, "*");
1777 if(!TrReadOperator(tr
, "]") || !TrReadOperator(tr
, "="))
1780 TrIndication(tr
, &line
, &col
);
1781 if(!ReadSofaRef(tr
, &src
))
1784 if(hData
->mChannelType
== CT_STEREO
)
1786 char type
[MAX_IDENT_LEN
+1];
1787 ChannelTypeT channelType
;
1789 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1792 channelType
= MatchChannelType(type
);
1797 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1809 char type
[MAX_IDENT_LEN
+1];
1810 ChannelTypeT channelType
;
1812 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1815 channelType
= MatchChannelType(type
);
1816 if(channelType
!= CT_MONO
)
1818 TrErrorAt(tr
, line
, col
, "Expected a mono channel type.\n");
1824 sofa
= LoadSofaFile(&src
, hData
->mIrRate
, hData
->mIrPoints
);
1827 for(si
= 0;si
< sofa
->hrtf
->M
;si
++)
1829 printf("\rLoading sources... %d of %d", si
+1, sofa
->hrtf
->M
);
1833 sofa
->hrtf
->SourcePosition
.values
[3*si
],
1834 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 1],
1835 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 2]
1839 if(std::fabs(aer
[1]) >= 89.999f
)
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
)
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)
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)
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
);
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.
1893 if(!ReadIndexTriplet(tr
, hData
, &fi
, &ei
, &ai
))
1895 if(!TrReadOperator(tr
, "]"))
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");
1904 if(!TrReadOperator(tr
, "="))
1911 if(!ReadSourceRef(tr
, &src
))
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.
1918 printf("\rLoading sources... %d file%s", count
, (count
==1)?"":"s");
1921 if(!LoadSource(&src
, hData
->mIrRate
, hData
->mIrPoints
, hrir
.data()))
1925 if(hData
->mChannelType
== CT_STEREO
)
1927 char ident
[MAX_IDENT_LEN
+1];
1929 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1931 ti
= static_cast<uint
>(MatchTargetEar(ident
));
1932 if(static_cast<int>(ti
) < 0)
1934 TrErrorAt(tr
, line
, col
, "Expected a target ear.\n");
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
]);
1942 if(!TrIsOperator(tr
, "+"))
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");
1953 else if(azd
->mIrs
[1] == nullptr)
1955 TrErrorAt(tr
, line
, col
, "Missing right ear source reference(s).\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)
1971 if(ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
)
1974 if(ei
>= hData
->mFds
[fi
].mEvCount
)
1976 TrError(tr
, "Missing source references [ %d, *, * ].\n", fi
);
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
);
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
)];
2011 mysofa_cache_release_all();
2015 TrError(tr
, "Errant data at end of source list.\n");
2016 mysofa_cache_release_all();
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
,
2025 TokenReaderT tr
{istream
};
2027 TrSetup(startbytes
, startbytecount
, filename
, &tr
);
2028 if(!ProcessMetrics(&tr
, fftSize
, truncSize
, chanMode
, hData
)
2029 || !ProcessSources(&tr
, hData
))