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
39 #include "alfstream.h"
45 // Constants for accessing the token reader's ring buffer.
46 #define TR_RING_BITS (16)
47 #define TR_RING_SIZE (1 << TR_RING_BITS)
48 #define TR_RING_MASK (TR_RING_SIZE - 1)
50 // The token reader's load interval in bytes.
51 #define TR_LOAD_SIZE (TR_RING_SIZE >> 2)
53 // Token reader state for parsing the data set definition.
55 std::istream
&mIStream
;
59 char mRing
[TR_RING_SIZE
]{};
60 std::streamsize mIn
{};
61 std::streamsize mOut
{};
63 TokenReaderT(std::istream
&istream
) noexcept
: mIStream
{istream
} { }
64 TokenReaderT(const TokenReaderT
&) = default;
68 // The maximum identifier length used when processing the data set
70 #define MAX_IDENT_LEN (16)
72 // The limits for the listener's head 'radius' in the data set definition.
73 #define MIN_RADIUS (0.05)
74 #define MAX_RADIUS (0.15)
76 // The maximum number of channels that can be addressed for a WAVE file
77 // source listed in the data set definition.
78 #define MAX_WAVE_CHANNELS (65535)
80 // The limits to the byte size for a binary source listed in the definition
82 #define MIN_BIN_SIZE (2)
83 #define MAX_BIN_SIZE (4)
85 // The minimum number of significant bits for binary sources listed in the
86 // data set definition. The maximum is calculated from the byte size.
87 #define MIN_BIN_BITS (16)
89 // The limits to the number of significant bits for an ASCII source listed in
90 // the data set definition.
91 #define MIN_ASCII_BITS (16)
92 #define MAX_ASCII_BITS (32)
94 // The four-character-codes for RIFF/RIFX WAVE file chunks.
95 #define FOURCC_RIFF (0x46464952) // 'RIFF'
96 #define FOURCC_RIFX (0x58464952) // 'RIFX'
97 #define FOURCC_WAVE (0x45564157) // 'WAVE'
98 #define FOURCC_FMT (0x20746D66) // 'fmt '
99 #define FOURCC_DATA (0x61746164) // 'data'
100 #define FOURCC_LIST (0x5453494C) // 'LIST'
101 #define FOURCC_WAVL (0x6C766177) // 'wavl'
102 #define FOURCC_SLNT (0x746E6C73) // 'slnt'
104 // The supported wave formats.
105 #define WAVE_FORMAT_PCM (0x0001)
106 #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
107 #define WAVE_FORMAT_EXTENSIBLE (0xFFFE)
116 // Source format for the references listed in the data set definition.
119 SF_ASCII
, // ASCII text file.
120 SF_BIN_LE
, // Little-endian binary file.
121 SF_BIN_BE
, // Big-endian binary file.
122 SF_WAVE
, // RIFF/RIFX WAVE file.
123 SF_SOFA
// Spatially Oriented Format for Accoustics (SOFA) file.
126 // Element types for the references listed in the data set definition.
129 ET_INT
, // Integer elements.
130 ET_FP
// Floating-point elements.
133 // Source reference state used when loading sources.
135 SourceFormatT mFormat
;
145 char mPath
[MAX_PATH_LEN
+1];
149 /* Whitespace is not significant. It can process tokens as identifiers, numbers
150 * (integer and floating-point), strings, and operators. Strings must be
151 * encapsulated by double-quotes and cannot span multiple lines.
154 // Setup the reader on the given file. The filename can be NULL if no error
155 // output is desired.
156 static void TrSetup(const char *startbytes
, std::streamsize startbytecount
, const char *filename
,
159 const char *name
= nullptr;
163 const char *slash
= strrchr(filename
, '/');
166 const char *bslash
= strrchr(slash
+1, '\\');
167 if(bslash
) name
= bslash
+1;
172 const char *bslash
= strrchr(filename
, '\\');
173 if(bslash
) name
= bslash
+1;
174 else name
= filename
;
184 if(startbytecount
> 0)
186 std::copy_n(startbytes
, startbytecount
, std::begin(tr
->mRing
));
187 tr
->mIn
+= startbytecount
;
191 // Prime the reader's ring buffer, and return a result indicating that there
192 // is text to process.
193 static int TrLoad(TokenReaderT
*tr
)
195 std::istream
&istream
= tr
->mIStream
;
197 std::streamsize toLoad
{TR_RING_SIZE
- static_cast<std::streamsize
>(tr
->mIn
- tr
->mOut
)};
198 if(toLoad
>= TR_LOAD_SIZE
&& istream
.good())
200 // Load TR_LOAD_SIZE (or less if at the end of the file) per read.
201 toLoad
= TR_LOAD_SIZE
;
202 std::streamsize in
{tr
->mIn
&TR_RING_MASK
};
203 std::streamsize count
{TR_RING_SIZE
- in
};
206 istream
.read(&tr
->mRing
[in
], count
);
207 tr
->mIn
+= istream
.gcount();
208 istream
.read(&tr
->mRing
[0], toLoad
-count
);
209 tr
->mIn
+= istream
.gcount();
213 istream
.read(&tr
->mRing
[in
], toLoad
);
214 tr
->mIn
+= istream
.gcount();
217 if(tr
->mOut
>= TR_RING_SIZE
)
219 tr
->mOut
-= TR_RING_SIZE
;
220 tr
->mIn
-= TR_RING_SIZE
;
223 if(tr
->mIn
> tr
->mOut
)
228 // Error display routine. Only displays when the base name is not NULL.
229 static void TrErrorVA(const TokenReaderT
*tr
, uint line
, uint column
, const char *format
, va_list argPtr
)
233 fprintf(stderr
, "\nError (%s:%u:%u): ", tr
->mName
, line
, column
);
234 vfprintf(stderr
, format
, argPtr
);
237 // Used to display an error at a saved line/column.
238 static void TrErrorAt(const TokenReaderT
*tr
, uint line
, uint column
, const char *format
, ...)
242 va_start(argPtr
, format
);
243 TrErrorVA(tr
, line
, column
, format
, argPtr
);
247 // Used to display an error at the current line/column.
248 static void TrError(const TokenReaderT
*tr
, const char *format
, ...)
252 va_start(argPtr
, format
);
253 TrErrorVA(tr
, tr
->mLine
, tr
->mColumn
, format
, argPtr
);
257 // Skips to the next line.
258 static void TrSkipLine(TokenReaderT
*tr
)
264 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
276 // Skips to the next token.
277 static int TrSkipWhitespace(TokenReaderT
*tr
)
281 char ch
{tr
->mRing
[tr
->mOut
&TR_RING_MASK
]};
301 // Get the line and/or column of the next token (or the end of input).
302 static void TrIndication(TokenReaderT
*tr
, uint
*line
, uint
*column
)
304 TrSkipWhitespace(tr
);
305 if(line
) *line
= tr
->mLine
;
306 if(column
) *column
= tr
->mColumn
;
309 // Checks to see if a token is (likely to be) an identifier. It does not
310 // display any errors and will not proceed to the next token.
311 static int TrIsIdent(TokenReaderT
*tr
)
313 if(!TrSkipWhitespace(tr
))
315 char ch
{tr
->mRing
[tr
->mOut
&TR_RING_MASK
]};
316 return ch
== '_' || isalpha(ch
);
320 // Checks to see if a token is the given operator. It does not display any
321 // errors and will not proceed to the next token.
322 static int TrIsOperator(TokenReaderT
*tr
, const char *op
)
328 if(!TrSkipWhitespace(tr
))
332 while(op
[len
] != '\0' && out
< tr
->mIn
)
334 ch
= tr
->mRing
[out
&TR_RING_MASK
];
335 if(ch
!= op
[len
]) break;
344 /* The TrRead*() routines obtain the value of a matching token type. They
345 * display type, form, and boundary errors and will proceed to the next
349 // Reads and validates an identifier token.
350 static int TrReadIdent(TokenReaderT
*tr
, const uint maxLen
, char *ident
)
356 if(TrSkipWhitespace(tr
))
359 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
360 if(ch
== '_' || isalpha(ch
))
370 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
371 } while(ch
== '_' || isdigit(ch
) || isalpha(ch
));
379 TrErrorAt(tr
, tr
->mLine
, col
, "Identifier is too long.\n");
383 TrErrorAt(tr
, tr
->mLine
, col
, "Expected an identifier.\n");
387 // Reads and validates (including bounds) an integer token.
388 static int TrReadInt(TokenReaderT
*tr
, const int loBound
, const int hiBound
, int *value
)
390 uint col
, digis
, len
;
394 if(TrSkipWhitespace(tr
))
398 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
399 if(ch
== '+' || ch
== '-')
408 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
409 if(!isdigit(ch
)) break;
417 if(digis
> 0 && ch
!= '.' && !isalpha(ch
))
421 TrErrorAt(tr
, tr
->mLine
, col
, "Integer is too long.");
425 *value
= static_cast<int>(strtol(temp
, nullptr, 10));
426 if(*value
< loBound
|| *value
> hiBound
)
428 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a value from %d to %d.\n", loBound
, hiBound
);
434 TrErrorAt(tr
, tr
->mLine
, col
, "Expected an integer.\n");
438 // Reads and validates (including bounds) a float token.
439 static int TrReadFloat(TokenReaderT
*tr
, const double loBound
, const double hiBound
, double *value
)
441 uint col
, digis
, len
;
445 if(TrSkipWhitespace(tr
))
449 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
450 if(ch
== '+' || ch
== '-')
460 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
461 if(!isdigit(ch
)) break;
477 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
478 if(!isdigit(ch
)) break;
487 if(ch
== 'E' || ch
== 'e')
494 if(ch
== '+' || ch
== '-')
503 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
504 if(!isdigit(ch
)) break;
513 if(digis
> 0 && ch
!= '.' && !isalpha(ch
))
517 TrErrorAt(tr
, tr
->mLine
, col
, "Float is too long.");
521 *value
= strtod(temp
, nullptr);
522 if(*value
< loBound
|| *value
> hiBound
)
524 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a value from %f to %f.\n", loBound
, hiBound
);
533 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a float.\n");
537 // Reads and validates a string token.
538 static int TrReadString(TokenReaderT
*tr
, const uint maxLen
, char *text
)
544 if(TrSkipWhitespace(tr
))
547 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
554 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
560 TrErrorAt(tr
, tr
->mLine
, col
, "Unterminated string at end of line.\n");
569 tr
->mColumn
+= 1 + len
;
570 TrErrorAt(tr
, tr
->mLine
, col
, "Unterminated string at end of input.\n");
573 tr
->mColumn
+= 2 + len
;
576 TrErrorAt(tr
, tr
->mLine
, col
, "String is too long.\n");
583 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a string.\n");
587 // Reads and validates the given operator.
588 static int TrReadOperator(TokenReaderT
*tr
, const char *op
)
594 if(TrSkipWhitespace(tr
))
598 while(op
[len
] != '\0' && TrLoad(tr
))
600 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
601 if(ch
!= op
[len
]) break;
609 TrErrorAt(tr
, tr
->mLine
, col
, "Expected '%s' operator.\n", op
);
614 /*************************
615 *** File source input ***
616 *************************/
618 // Read a binary value of the specified byte order and byte size from a file,
619 // storing it as a 32-bit unsigned integer.
620 static int ReadBin4(std::istream
&istream
, const char *filename
, const ByteOrderT order
, const uint bytes
, uint32_t *out
)
623 istream
.read(reinterpret_cast<char*>(in
), static_cast<int>(bytes
));
624 if(istream
.gcount() != bytes
)
626 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
633 for(uint i
= 0;i
< bytes
;i
++)
634 accum
= (accum
<<8) | in
[bytes
- i
- 1];
637 for(uint i
= 0;i
< bytes
;i
++)
638 accum
= (accum
<<8) | in
[i
];
647 // Read a binary value of the specified byte order from a file, storing it as
648 // a 64-bit unsigned integer.
649 static int ReadBin8(std::istream
&istream
, const char *filename
, const ByteOrderT order
, uint64_t *out
)
655 istream
.read(reinterpret_cast<char*>(in
), 8);
656 if(istream
.gcount() != 8)
658 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
666 accum
= (accum
<<8) | in
[8 - i
- 1];
670 accum
= (accum
<<8) | in
[i
];
679 /* Read a binary value of the specified type, byte order, and byte size from
680 * a file, converting it to a double. For integer types, the significant
681 * bits are used to normalize the result. The sign of bits determines
682 * whether they are padded toward the MSB (negative) or LSB (positive).
683 * Floating-point types are not normalized.
685 static int ReadBinAsDouble(std::istream
&istream
, const char *filename
, const ByteOrderT order
,
686 const ElementTypeT type
, const uint bytes
, const int bits
, double *out
)
701 if(!ReadBin8(istream
, filename
, order
, &v8
.ui
))
708 if(!ReadBin4(istream
, filename
, order
, bytes
, &v4
.ui
))
715 v4
.ui
>>= (8*bytes
) - (static_cast<uint
>(bits
));
717 v4
.ui
&= (0xFFFFFFFF >> (32+bits
));
719 if(v4
.ui
&static_cast<uint
>(1<<(std::abs(bits
)-1)))
720 v4
.ui
|= (0xFFFFFFFF << std::abs(bits
));
721 *out
= v4
.i
/ static_cast<double>(1<<(std::abs(bits
)-1));
727 /* Read an ascii value of the specified type from a file, converting it to a
728 * double. For integer types, the significant bits are used to normalize the
729 * result. The sign of the bits should always be positive. This also skips
730 * up to one separator character before the element itself.
732 static int ReadAsciiAsDouble(TokenReaderT
*tr
, const char *filename
, const ElementTypeT type
, const uint bits
, double *out
)
734 if(TrIsOperator(tr
, ","))
735 TrReadOperator(tr
, ",");
736 else if(TrIsOperator(tr
, ":"))
737 TrReadOperator(tr
, ":");
738 else if(TrIsOperator(tr
, ";"))
739 TrReadOperator(tr
, ";");
740 else if(TrIsOperator(tr
, "|"))
741 TrReadOperator(tr
, "|");
745 if(!TrReadFloat(tr
, -std::numeric_limits
<double>::infinity(),
746 std::numeric_limits
<double>::infinity(), out
))
748 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
755 if(!TrReadInt(tr
, -(1<<(bits
-1)), (1<<(bits
-1))-1, &v
))
757 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
760 *out
= v
/ static_cast<double>((1<<(bits
-1))-1);
765 // Read the RIFF/RIFX WAVE format chunk from a file, validating it against
766 // the source parameters and data set metrics.
767 static int ReadWaveFormat(std::istream
&istream
, const ByteOrderT order
, const uint hrirRate
,
770 uint32_t fourCC
, chunkSize
;
771 uint32_t format
, channels
, rate
, dummy
, block
, size
, bits
;
776 istream
.seekg(static_cast<int>(chunkSize
), std::ios::cur
);
777 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
778 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
780 } while(fourCC
!= FOURCC_FMT
);
781 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &format
)
782 || !ReadBin4(istream
, src
->mPath
, order
, 2, &channels
)
783 || !ReadBin4(istream
, src
->mPath
, order
, 4, &rate
)
784 || !ReadBin4(istream
, src
->mPath
, order
, 4, &dummy
)
785 || !ReadBin4(istream
, src
->mPath
, order
, 2, &block
))
790 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &size
))
798 if(format
== WAVE_FORMAT_EXTENSIBLE
)
800 istream
.seekg(2, std::ios::cur
);
801 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &bits
))
805 istream
.seekg(4, std::ios::cur
);
806 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &format
))
808 istream
.seekg(static_cast<int>(chunkSize
- 26), std::ios::cur
);
814 istream
.seekg(static_cast<int>(chunkSize
- 16), std::ios::cur
);
816 istream
.seekg(static_cast<int>(chunkSize
- 14), std::ios::cur
);
818 if(format
!= WAVE_FORMAT_PCM
&& format
!= WAVE_FORMAT_IEEE_FLOAT
)
820 fprintf(stderr
, "\nError: Unsupported WAVE format in file '%s'.\n", src
->mPath
);
823 if(src
->mChannel
>= channels
)
825 fprintf(stderr
, "\nError: Missing source channel in WAVE file '%s'.\n", src
->mPath
);
830 fprintf(stderr
, "\nError: Mismatched source sample rate in WAVE file '%s'.\n", src
->mPath
);
833 if(format
== WAVE_FORMAT_PCM
)
835 if(size
< 2 || size
> 4)
837 fprintf(stderr
, "\nError: Unsupported sample size in WAVE file '%s'.\n", src
->mPath
);
840 if(bits
< 16 || bits
> (8*size
))
842 fprintf(stderr
, "\nError: Bad significant bits in WAVE file '%s'.\n", src
->mPath
);
849 if(size
!= 4 && size
!= 8)
851 fprintf(stderr
, "\nError: Unsupported sample size in WAVE file '%s'.\n", src
->mPath
);
857 src
->mBits
= static_cast<int>(bits
);
858 src
->mSkip
= channels
;
862 // Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles.
863 static int ReadWaveData(std::istream
&istream
, const SourceRefT
*src
, const ByteOrderT order
,
864 const uint n
, double *hrir
)
869 pre
= static_cast<int>(src
->mSize
* src
->mChannel
);
870 post
= static_cast<int>(src
->mSize
* (src
->mSkip
- src
->mChannel
- 1));
876 istream
.seekg(skip
, std::ios::cur
);
877 if(!ReadBinAsDouble(istream
, src
->mPath
, order
, src
->mType
, src
->mSize
, src
->mBits
, &hrir
[i
]))
882 istream
.seekg(skip
, std::ios::cur
);
886 // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to
888 static int ReadWaveList(std::istream
&istream
, const SourceRefT
*src
, const ByteOrderT order
,
889 const uint n
, double *hrir
)
891 uint32_t fourCC
, chunkSize
, listSize
, count
;
892 uint block
, skip
, offset
, i
;
897 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
898 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
901 if(fourCC
== FOURCC_DATA
)
903 block
= src
->mSize
* src
->mSkip
;
904 count
= chunkSize
/ block
;
905 if(count
< (src
->mOffset
+ n
))
907 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", src
->mPath
);
910 istream
.seekg(static_cast<long>(src
->mOffset
* block
), std::ios::cur
);
911 if(!ReadWaveData(istream
, src
, order
, n
, &hrir
[0]))
915 else if(fourCC
== FOURCC_LIST
)
917 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
))
920 if(fourCC
== FOURCC_WAVL
)
924 istream
.seekg(static_cast<long>(chunkSize
), std::ios::cur
);
926 listSize
= chunkSize
;
927 block
= src
->mSize
* src
->mSkip
;
931 while(offset
< n
&& listSize
> 8)
933 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
934 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
936 listSize
-= 8 + chunkSize
;
937 if(fourCC
== FOURCC_DATA
)
939 count
= chunkSize
/ block
;
942 istream
.seekg(static_cast<long>(skip
* block
), std::ios::cur
);
943 chunkSize
-= skip
* block
;
946 if(count
> (n
- offset
))
948 if(!ReadWaveData(istream
, src
, order
, count
, &hrir
[offset
]))
950 chunkSize
-= count
* block
;
952 lastSample
= hrir
[offset
- 1];
960 else if(fourCC
== FOURCC_SLNT
)
962 if(!ReadBin4(istream
, src
->mPath
, order
, 4, &count
))
969 if(count
> (n
- offset
))
971 for(i
= 0; i
< count
; i
++)
972 hrir
[offset
+ i
] = lastSample
;
982 istream
.seekg(static_cast<long>(chunkSize
), std::ios::cur
);
986 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", src
->mPath
);
992 // Load a source HRIR from an ASCII text file containing a list of elements
993 // separated by whitespace or common list operators (',', ';', ':', '|').
994 static int LoadAsciiSource(std::istream
&istream
, const SourceRefT
*src
,
995 const uint n
, double *hrir
)
997 TokenReaderT tr
{istream
};
1001 TrSetup(nullptr, 0, nullptr, &tr
);
1002 for(i
= 0;i
< src
->mOffset
;i
++)
1004 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &dummy
))
1007 for(i
= 0;i
< n
;i
++)
1009 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &hrir
[i
]))
1011 for(j
= 0;j
< src
->mSkip
;j
++)
1013 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &dummy
))
1020 // Load a source HRIR from a binary file.
1021 static int LoadBinarySource(std::istream
&istream
, const SourceRefT
*src
, const ByteOrderT order
,
1022 const uint n
, double *hrir
)
1024 istream
.seekg(static_cast<long>(src
->mOffset
), std::ios::beg
);
1025 for(uint i
{0};i
< n
;i
++)
1027 if(!ReadBinAsDouble(istream
, src
->mPath
, order
, src
->mType
, src
->mSize
, src
->mBits
, &hrir
[i
]))
1030 istream
.seekg(static_cast<long>(src
->mSkip
), std::ios::cur
);
1035 // Load a source HRIR from a RIFF/RIFX WAVE file.
1036 static int LoadWaveSource(std::istream
&istream
, SourceRefT
*src
, const uint hrirRate
,
1037 const uint n
, double *hrir
)
1039 uint32_t fourCC
, dummy
;
1042 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
1043 || !ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &dummy
))
1045 if(fourCC
== FOURCC_RIFF
)
1047 else if(fourCC
== FOURCC_RIFX
)
1051 fprintf(stderr
, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src
->mPath
);
1055 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
))
1057 if(fourCC
!= FOURCC_WAVE
)
1059 fprintf(stderr
, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src
->mPath
);
1062 if(!ReadWaveFormat(istream
, order
, hrirRate
, src
))
1064 if(!ReadWaveList(istream
, src
, order
, n
, hrir
))
1071 // Load a Spatially Oriented Format for Accoustics (SOFA) file.
1072 static MYSOFA_EASY
* LoadSofaFile(SourceRefT
*src
, const uint hrirRate
, const uint n
)
1074 struct MYSOFA_EASY
*sofa
{mysofa_cache_lookup(src
->mPath
, static_cast<float>(hrirRate
))};
1075 if(sofa
) return sofa
;
1077 sofa
= static_cast<MYSOFA_EASY
*>(calloc(1, sizeof(*sofa
)));
1080 fprintf(stderr
, "\nError: Out of memory.\n");
1083 sofa
->lookup
= nullptr;
1084 sofa
->neighborhood
= nullptr;
1087 sofa
->hrtf
= mysofa_load(src
->mPath
, &err
);
1091 fprintf(stderr
, "\nError: Could not load source file '%s'.\n", src
->mPath
);
1094 /* NOTE: Some valid SOFA files are failing this check. */
1095 err
= mysofa_check(sofa
->hrtf
);
1096 if(err
!= MYSOFA_OK
)
1097 fprintf(stderr
, "\nWarning: Supposedly malformed source file '%s'.\n", src
->mPath
);
1098 if((src
->mOffset
+ n
) > sofa
->hrtf
->N
)
1101 fprintf(stderr
, "\nError: Not enough samples in SOFA file '%s'.\n", src
->mPath
);
1104 if(src
->mChannel
>= sofa
->hrtf
->R
)
1107 fprintf(stderr
, "\nError: Missing source receiver in SOFA file '%s'.\n", src
->mPath
);
1110 mysofa_tocartesian(sofa
->hrtf
);
1111 sofa
->lookup
= mysofa_lookup_init(sofa
->hrtf
);
1112 if(sofa
->lookup
== nullptr)
1115 fprintf(stderr
, "\nError: Out of memory.\n");
1118 return mysofa_cache_store(sofa
, src
->mPath
, static_cast<float>(hrirRate
));
1121 // Copies the HRIR data from a particular SOFA measurement.
1122 static void ExtractSofaHrir(const MYSOFA_EASY
*sofa
, const uint index
, const uint channel
, const uint offset
, const uint n
, double *hrir
)
1124 for(uint i
{0u};i
< n
;i
++)
1125 hrir
[i
] = sofa
->hrtf
->DataIR
.values
[(index
*sofa
->hrtf
->R
+ channel
)*sofa
->hrtf
->N
+ offset
+ i
];
1128 // Load a source HRIR from a Spatially Oriented Format for Accoustics (SOFA)
1130 static int LoadSofaSource(SourceRefT
*src
, const uint hrirRate
, const uint n
, double *hrir
)
1132 struct MYSOFA_EASY
*sofa
;
1137 sofa
= LoadSofaFile(src
, hrirRate
, n
);
1141 /* NOTE: At some point it may be benficial or necessary to consider the
1142 various coordinate systems, listener/source orientations, and
1143 direciontal vectors defined in the SOFA file.
1145 target
[0] = static_cast<float>(src
->mAzimuth
);
1146 target
[1] = static_cast<float>(src
->mElevation
);
1147 target
[2] = static_cast<float>(src
->mRadius
);
1150 nearest
= mysofa_lookup(sofa
->lookup
, target
);
1153 fprintf(stderr
, "\nError: Lookup failed in source file '%s'.\n", src
->mPath
);
1157 coords
= &sofa
->hrtf
->SourcePosition
.values
[3 * nearest
];
1158 if(std::abs(coords
[0] - target
[0]) > 0.001 || std::abs(coords
[1] - target
[1]) > 0.001 || std::abs(coords
[2] - target
[2]) > 0.001)
1160 fprintf(stderr
, "\nError: No impulse response at coordinates (%.3fr, %.1fev, %.1faz) in file '%s'.\n", src
->mRadius
, src
->mElevation
, src
->mAzimuth
, src
->mPath
);
1161 target
[0] = coords
[0];
1162 target
[1] = coords
[1];
1163 target
[2] = coords
[2];
1165 fprintf(stderr
, " Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target
[2], target
[1], target
[0]);
1169 ExtractSofaHrir(sofa
, static_cast<uint
>(nearest
), src
->mChannel
, src
->mOffset
, n
, hrir
);
1174 // Load a source HRIR from a supported file type.
1175 static int LoadSource(SourceRefT
*src
, const uint hrirRate
, const uint n
, double *hrir
)
1177 std::unique_ptr
<al::ifstream
> istream
;
1178 if(src
->mFormat
!= SF_SOFA
)
1180 if(src
->mFormat
== SF_ASCII
)
1181 istream
.reset(new al::ifstream
{src
->mPath
});
1183 istream
.reset(new al::ifstream
{src
->mPath
, std::ios::binary
});
1184 if(!istream
->good())
1186 fprintf(stderr
, "\nError: Could not open source file '%s'.\n", src
->mPath
);
1191 switch(src
->mFormat
)
1194 result
= LoadAsciiSource(*istream
, src
, n
, hrir
);
1197 result
= LoadBinarySource(*istream
, src
, BO_LITTLE
, n
, hrir
);
1200 result
= LoadBinarySource(*istream
, src
, BO_BIG
, n
, hrir
);
1203 result
= LoadWaveSource(*istream
, src
, hrirRate
, n
, hrir
);
1206 result
= LoadSofaSource(src
, hrirRate
, n
, hrir
);
1215 // Match the channel type from a given identifier.
1216 static ChannelTypeT
MatchChannelType(const char *ident
)
1218 if(al::strcasecmp(ident
, "mono") == 0)
1220 if(al::strcasecmp(ident
, "stereo") == 0)
1226 // Process the data set definition to read and validate the data set metrics.
1227 static int ProcessMetrics(TokenReaderT
*tr
, const uint fftSize
, const uint truncSize
, const ChannelModeT chanMode
, HrirDataT
*hData
)
1229 int hasRate
= 0, hasType
= 0, hasPoints
= 0, hasRadius
= 0;
1230 int hasDistance
= 0, hasAzimuths
= 0;
1231 char ident
[MAX_IDENT_LEN
+1];
1236 double distances
[MAX_FD_COUNT
];
1238 uint evCounts
[MAX_FD_COUNT
];
1239 std::vector
<uint
> azCounts(MAX_FD_COUNT
* MAX_EV_COUNT
);
1241 TrIndication(tr
, &line
, &col
);
1242 while(TrIsIdent(tr
))
1244 TrIndication(tr
, &line
, &col
);
1245 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1247 if(al::strcasecmp(ident
, "rate") == 0)
1251 TrErrorAt(tr
, line
, col
, "Redefinition of 'rate'.\n");
1254 if(!TrReadOperator(tr
, "="))
1256 if(!TrReadInt(tr
, MIN_RATE
, MAX_RATE
, &intVal
))
1258 hData
->mIrRate
= static_cast<uint
>(intVal
);
1261 else if(al::strcasecmp(ident
, "type") == 0)
1263 char type
[MAX_IDENT_LEN
+1];
1267 TrErrorAt(tr
, line
, col
, "Redefinition of 'type'.\n");
1270 if(!TrReadOperator(tr
, "="))
1273 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1275 hData
->mChannelType
= MatchChannelType(type
);
1276 if(hData
->mChannelType
== CT_NONE
)
1278 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1281 else if(hData
->mChannelType
== CT_STEREO
)
1283 if(chanMode
== CM_ForceMono
)
1284 hData
->mChannelType
= CT_MONO
;
1288 else if(al::strcasecmp(ident
, "points") == 0)
1292 TrErrorAt(tr
, line
, col
, "Redefinition of 'points'.\n");
1295 if(!TrReadOperator(tr
, "="))
1297 TrIndication(tr
, &line
, &col
);
1298 if(!TrReadInt(tr
, MIN_POINTS
, MAX_POINTS
, &intVal
))
1300 points
= static_cast<uint
>(intVal
);
1301 if(fftSize
> 0 && points
> fftSize
)
1303 TrErrorAt(tr
, line
, col
, "Value exceeds the overridden FFT size.\n");
1306 if(points
< truncSize
)
1308 TrErrorAt(tr
, line
, col
, "Value is below the truncation size.\n");
1311 hData
->mIrPoints
= points
;
1312 hData
->mFftSize
= fftSize
;
1313 hData
->mIrSize
= 1 + (fftSize
/ 2);
1314 if(points
> hData
->mIrSize
)
1315 hData
->mIrSize
= points
;
1318 else if(al::strcasecmp(ident
, "radius") == 0)
1322 TrErrorAt(tr
, line
, col
, "Redefinition of 'radius'.\n");
1325 if(!TrReadOperator(tr
, "="))
1327 if(!TrReadFloat(tr
, MIN_RADIUS
, MAX_RADIUS
, &fpVal
))
1329 hData
->mRadius
= fpVal
;
1332 else if(al::strcasecmp(ident
, "distance") == 0)
1338 TrErrorAt(tr
, line
, col
, "Redefinition of 'distance'.\n");
1341 if(!TrReadOperator(tr
, "="))
1346 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1348 if(count
> 0 && fpVal
<= distances
[count
- 1])
1350 TrError(tr
, "Distances are not ascending.\n");
1353 distances
[count
++] = fpVal
;
1354 if(!TrIsOperator(tr
, ","))
1356 if(count
>= MAX_FD_COUNT
)
1358 TrError(tr
, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT
);
1361 TrReadOperator(tr
, ",");
1363 if(fdCount
!= 0 && count
!= fdCount
)
1365 TrError(tr
, "Did not match the specified number of %d fields.\n", fdCount
);
1371 else if(al::strcasecmp(ident
, "azimuths") == 0)
1377 TrErrorAt(tr
, line
, col
, "Redefinition of 'azimuths'.\n");
1380 if(!TrReadOperator(tr
, "="))
1386 if(!TrReadInt(tr
, MIN_AZ_COUNT
, MAX_AZ_COUNT
, &intVal
))
1388 azCounts
[(count
* MAX_EV_COUNT
) + evCounts
[count
]++] = static_cast<uint
>(intVal
);
1389 if(TrIsOperator(tr
, ","))
1391 if(evCounts
[count
] >= MAX_EV_COUNT
)
1393 TrError(tr
, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT
);
1396 TrReadOperator(tr
, ",");
1400 if(evCounts
[count
] < MIN_EV_COUNT
)
1402 TrErrorAt(tr
, line
, col
, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT
);
1405 if(azCounts
[count
* MAX_EV_COUNT
] != 1 || azCounts
[(count
* MAX_EV_COUNT
) + evCounts
[count
] - 1] != 1)
1407 TrError(tr
, "Poles are not singular for field %d.\n", count
- 1);
1411 if(!TrIsOperator(tr
, ";"))
1414 if(count
>= MAX_FD_COUNT
)
1416 TrError(tr
, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT
);
1419 evCounts
[count
] = 0;
1420 TrReadOperator(tr
, ";");
1423 if(fdCount
!= 0 && count
!= fdCount
)
1425 TrError(tr
, "Did not match the specified number of %d fields.\n", fdCount
);
1433 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1436 TrSkipWhitespace(tr
);
1438 if(!(hasRate
&& hasPoints
&& hasRadius
&& hasDistance
&& hasAzimuths
))
1440 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1443 if(distances
[0] < hData
->mRadius
)
1445 TrError(tr
, "Distance cannot start below head radius.\n");
1448 if(hData
->mChannelType
== CT_NONE
)
1449 hData
->mChannelType
= CT_MONO
;
1450 if(!PrepareHrirData(fdCount
, distances
, evCounts
, azCounts
.data(), hData
))
1452 fprintf(stderr
, "Error: Out of memory.\n");
1458 // Parse an index triplet from the data set definition.
1459 static int ReadIndexTriplet(TokenReaderT
*tr
, const HrirDataT
*hData
, uint
*fi
, uint
*ei
, uint
*ai
)
1463 if(hData
->mFdCount
> 1)
1465 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFdCount
) - 1, &intVal
))
1467 *fi
= static_cast<uint
>(intVal
);
1468 if(!TrReadOperator(tr
, ","))
1475 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvCount
) - 1, &intVal
))
1477 *ei
= static_cast<uint
>(intVal
);
1478 if(!TrReadOperator(tr
, ","))
1480 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvs
[*ei
].mAzCount
) - 1, &intVal
))
1482 *ai
= static_cast<uint
>(intVal
);
1486 // Match the source format from a given identifier.
1487 static SourceFormatT
MatchSourceFormat(const char *ident
)
1489 if(al::strcasecmp(ident
, "ascii") == 0)
1491 if(al::strcasecmp(ident
, "bin_le") == 0)
1493 if(al::strcasecmp(ident
, "bin_be") == 0)
1495 if(al::strcasecmp(ident
, "wave") == 0)
1497 if(al::strcasecmp(ident
, "sofa") == 0)
1502 // Match the source element type from a given identifier.
1503 static ElementTypeT
MatchElementType(const char *ident
)
1505 if(al::strcasecmp(ident
, "int") == 0)
1507 if(al::strcasecmp(ident
, "fp") == 0)
1512 // Parse and validate a source reference from the data set definition.
1513 static int ReadSourceRef(TokenReaderT
*tr
, SourceRefT
*src
)
1515 char ident
[MAX_IDENT_LEN
+1];
1520 TrIndication(tr
, &line
, &col
);
1521 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1523 src
->mFormat
= MatchSourceFormat(ident
);
1524 if(src
->mFormat
== SF_NONE
)
1526 TrErrorAt(tr
, line
, col
, "Expected a source format.\n");
1529 if(!TrReadOperator(tr
, "("))
1531 if(src
->mFormat
== SF_SOFA
)
1533 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1535 src
->mRadius
= fpVal
;
1536 if(!TrReadOperator(tr
, ","))
1538 if(!TrReadFloat(tr
, -90.0, 90.0, &fpVal
))
1540 src
->mElevation
= fpVal
;
1541 if(!TrReadOperator(tr
, ","))
1543 if(!TrReadFloat(tr
, -360.0, 360.0, &fpVal
))
1545 src
->mAzimuth
= fpVal
;
1546 if(!TrReadOperator(tr
, ":"))
1548 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1550 src
->mType
= ET_NONE
;
1553 src
->mChannel
= static_cast<uint
>(intVal
);
1556 else if(src
->mFormat
== SF_WAVE
)
1558 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1560 src
->mType
= ET_NONE
;
1563 src
->mChannel
= static_cast<uint
>(intVal
);
1568 TrIndication(tr
, &line
, &col
);
1569 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1571 src
->mType
= MatchElementType(ident
);
1572 if(src
->mType
== ET_NONE
)
1574 TrErrorAt(tr
, line
, col
, "Expected a source element type.\n");
1577 if(src
->mFormat
== SF_BIN_LE
|| src
->mFormat
== SF_BIN_BE
)
1579 if(!TrReadOperator(tr
, ","))
1581 if(src
->mType
== ET_INT
)
1583 if(!TrReadInt(tr
, MIN_BIN_SIZE
, MAX_BIN_SIZE
, &intVal
))
1585 src
->mSize
= static_cast<uint
>(intVal
);
1586 if(!TrIsOperator(tr
, ","))
1587 src
->mBits
= static_cast<int>(8*src
->mSize
);
1590 TrReadOperator(tr
, ",");
1591 TrIndication(tr
, &line
, &col
);
1592 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
1594 if(std::abs(intVal
) < MIN_BIN_BITS
|| static_cast<uint
>(std::abs(intVal
)) > (8*src
->mSize
))
1596 TrErrorAt(tr
, line
, col
, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS
, 8*src
->mSize
);
1599 src
->mBits
= intVal
;
1604 TrIndication(tr
, &line
, &col
);
1605 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
1607 if(intVal
!= 4 && intVal
!= 8)
1609 TrErrorAt(tr
, line
, col
, "Expected a value of 4 or 8.\n");
1612 src
->mSize
= static_cast<uint
>(intVal
);
1616 else if(src
->mFormat
== SF_ASCII
&& src
->mType
== ET_INT
)
1618 if(!TrReadOperator(tr
, ","))
1620 if(!TrReadInt(tr
, MIN_ASCII_BITS
, MAX_ASCII_BITS
, &intVal
))
1623 src
->mBits
= intVal
;
1631 if(!TrIsOperator(tr
, ";"))
1635 TrReadOperator(tr
, ";");
1636 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1638 src
->mSkip
= static_cast<uint
>(intVal
);
1641 if(!TrReadOperator(tr
, ")"))
1643 if(TrIsOperator(tr
, "@"))
1645 TrReadOperator(tr
, "@");
1646 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1648 src
->mOffset
= static_cast<uint
>(intVal
);
1652 if(!TrReadOperator(tr
, ":"))
1654 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
1659 // Parse and validate a SOFA source reference from the data set definition.
1660 static int ReadSofaRef(TokenReaderT
*tr
, SourceRefT
*src
)
1662 char ident
[MAX_IDENT_LEN
+1];
1666 TrIndication(tr
, &line
, &col
);
1667 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1669 src
->mFormat
= MatchSourceFormat(ident
);
1670 if(src
->mFormat
!= SF_SOFA
)
1672 TrErrorAt(tr
, line
, col
, "Expected the SOFA source format.\n");
1676 src
->mType
= ET_NONE
;
1682 if(TrIsOperator(tr
, "@"))
1684 TrReadOperator(tr
, "@");
1685 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1687 src
->mOffset
= static_cast<uint
>(intVal
);
1691 if(!TrReadOperator(tr
, ":"))
1693 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
1698 // Match the target ear (index) from a given identifier.
1699 static int MatchTargetEar(const char *ident
)
1701 if(al::strcasecmp(ident
, "left") == 0)
1703 if(al::strcasecmp(ident
, "right") == 0)
1708 // Calculate the onset time of an HRIR and average it with any existing
1709 // timing for its field, elevation, azimuth, and ear.
1710 static double AverageHrirOnset(const uint rate
, const uint n
, const double *hrir
, const double f
, const double onset
)
1712 std::vector
<double> upsampled(10 * n
);
1715 rs
.init(rate
, 10 * rate
);
1716 rs
.process(n
, hrir
, 10 * n
, upsampled
.data());
1719 auto abs_lt
= [](const double &lhs
, const double &rhs
) -> bool
1720 { return std::abs(lhs
) < std::abs(rhs
); };
1721 auto iter
= std::max_element(upsampled
.cbegin(), upsampled
.cend(), abs_lt
);
1722 return Lerp(onset
, static_cast<double>(std::distance(upsampled
.cbegin(), iter
))/(10*rate
), f
);
1725 // Calculate the magnitude response of an HRIR and average it with any
1726 // existing responses for its field, elevation, azimuth, and ear.
1727 static void AverageHrirMagnitude(const uint points
, const uint n
, const double *hrir
, const double f
, double *mag
)
1729 uint m
= 1 + (n
/ 2), i
;
1730 std::vector
<complex_d
> h(n
);
1731 std::vector
<double> r(n
);
1733 for(i
= 0;i
< points
;i
++)
1734 h
[i
] = complex_d
{hrir
[i
], 0.0};
1736 h
[i
] = complex_d
{0.0, 0.0};
1737 FftForward(n
, h
.data());
1738 MagnitudeResponse(n
, h
.data(), r
.data());
1739 for(i
= 0;i
< m
;i
++)
1740 mag
[i
] = Lerp(mag
[i
], r
[i
], f
);
1743 // Process the list of sources in the data set definition.
1744 static int ProcessSources(TokenReaderT
*tr
, HrirDataT
*hData
)
1746 uint channels
= (hData
->mChannelType
== CT_STEREO
) ? 2 : 1;
1747 hData
->mHrirsBase
.resize(channels
* hData
->mIrCount
* hData
->mIrSize
);
1748 double *hrirs
= hData
->mHrirsBase
.data();
1749 std::vector
<double> hrir(hData
->mIrPoints
);
1750 uint line
, col
, fi
, ei
, ai
;
1753 printf("Loading sources...");
1756 while(TrIsOperator(tr
, "["))
1758 double factor
[2]{ 1.0, 1.0 };
1760 TrIndication(tr
, &line
, &col
);
1761 TrReadOperator(tr
, "[");
1763 if(TrIsOperator(tr
, "*"))
1766 struct MYSOFA_EASY
*sofa
;
1769 TrReadOperator(tr
, "*");
1770 if(!TrReadOperator(tr
, "]") || !TrReadOperator(tr
, "="))
1773 TrIndication(tr
, &line
, &col
);
1774 if(!ReadSofaRef(tr
, &src
))
1777 if(hData
->mChannelType
== CT_STEREO
)
1779 char type
[MAX_IDENT_LEN
+1];
1780 ChannelTypeT channelType
;
1782 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1785 channelType
= MatchChannelType(type
);
1790 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1802 char type
[MAX_IDENT_LEN
+1];
1803 ChannelTypeT channelType
;
1805 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1808 channelType
= MatchChannelType(type
);
1809 if(channelType
!= CT_MONO
)
1811 TrErrorAt(tr
, line
, col
, "Expected a mono channel type.\n");
1817 sofa
= LoadSofaFile(&src
, hData
->mIrRate
, hData
->mIrPoints
);
1820 for(si
= 0;si
< sofa
->hrtf
->M
;si
++)
1822 printf("\rLoading sources... %d of %d", si
+1, sofa
->hrtf
->M
);
1826 sofa
->hrtf
->SourcePosition
.values
[3*si
],
1827 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 1],
1828 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 2]
1832 if(std::fabs(aer
[1]) >= 89.999f
)
1835 aer
[0] = std::fmod(360.0f
- aer
[0], 360.0f
);
1837 for(fi
= 0;fi
< hData
->mFdCount
;fi
++)
1839 double delta
= aer
[2] - hData
->mFds
[fi
].mDistance
;
1840 if(std::abs(delta
) < 0.001) break;
1842 if(fi
>= hData
->mFdCount
)
1845 double ef
{(90.0 + aer
[1]) / 180.0 * (hData
->mFds
[fi
].mEvCount
- 1)};
1846 ei
= static_cast<uint
>(std::round(ef
));
1847 ef
= (ef
- ei
) * 180.0 / (hData
->mFds
[fi
].mEvCount
- 1);
1848 if(std::abs(ef
) >= 0.1)
1851 double af
{aer
[0] / 360.0 * hData
->mFds
[fi
].mEvs
[ei
].mAzCount
};
1852 ai
= static_cast<uint
>(std::round(af
));
1853 af
= (af
- ai
) * 360.0 / hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;
1854 ai
= ai
% hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;
1855 if(std::abs(af
) >= 0.1)
1858 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1859 if(azd
->mIrs
[0] != nullptr)
1861 TrErrorAt(tr
, line
, col
, "Redefinition of source [ %d, %d, %d ].\n", fi
, ei
, ai
);
1865 ExtractSofaHrir(sofa
, si
, 0, src
.mOffset
, hData
->mIrPoints
, hrir
.data());
1866 azd
->mIrs
[0] = &hrirs
[hData
->mIrSize
* azd
->mIndex
];
1867 azd
->mDelays
[0] = AverageHrirOnset(hData
->mIrRate
, hData
->mIrPoints
, hrir
.data(), 1.0, azd
->mDelays
[0]);
1868 AverageHrirMagnitude(hData
->mIrPoints
, hData
->mFftSize
, hrir
.data(), 1.0, azd
->mIrs
[0]);
1870 if(src
.mChannel
== 1)
1872 ExtractSofaHrir(sofa
, si
, 1, src
.mOffset
, hData
->mIrPoints
, hrir
.data());
1873 azd
->mIrs
[1] = &hrirs
[hData
->mIrSize
* (hData
->mIrCount
+ azd
->mIndex
)];
1874 azd
->mDelays
[1] = AverageHrirOnset(hData
->mIrRate
, hData
->mIrPoints
, hrir
.data(), 1.0, azd
->mDelays
[1]);
1875 AverageHrirMagnitude(hData
->mIrPoints
, hData
->mFftSize
, hrir
.data(), 1.0, azd
->mIrs
[1]);
1878 // TODO: Since some SOFA files contain minimum phase HRIRs,
1879 // it would be beneficial to check for per-measurement delays
1880 // (when available) to reconstruct the HRTDs.
1886 if(!ReadIndexTriplet(tr
, hData
, &fi
, &ei
, &ai
))
1888 if(!TrReadOperator(tr
, "]"))
1890 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1892 if(azd
->mIrs
[0] != nullptr)
1894 TrErrorAt(tr
, line
, col
, "Redefinition of source.\n");
1897 if(!TrReadOperator(tr
, "="))
1904 if(!ReadSourceRef(tr
, &src
))
1907 // TODO: Would be nice to display 'x of y files', but that would
1908 // require preparing the source refs first to get a total count
1909 // before loading them.
1911 printf("\rLoading sources... %d file%s", count
, (count
==1)?"":"s");
1914 if(!LoadSource(&src
, hData
->mIrRate
, hData
->mIrPoints
, hrir
.data()))
1918 if(hData
->mChannelType
== CT_STEREO
)
1920 char ident
[MAX_IDENT_LEN
+1];
1922 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1924 ti
= static_cast<uint
>(MatchTargetEar(ident
));
1925 if(static_cast<int>(ti
) < 0)
1927 TrErrorAt(tr
, line
, col
, "Expected a target ear.\n");
1931 azd
->mIrs
[ti
] = &hrirs
[hData
->mIrSize
* (ti
* hData
->mIrCount
+ azd
->mIndex
)];
1932 azd
->mDelays
[ti
] = AverageHrirOnset(hData
->mIrRate
, hData
->mIrPoints
, hrir
.data(), 1.0 / factor
[ti
], azd
->mDelays
[ti
]);
1933 AverageHrirMagnitude(hData
->mIrPoints
, hData
->mFftSize
, hrir
.data(), 1.0 / factor
[ti
], azd
->mIrs
[ti
]);
1935 if(!TrIsOperator(tr
, "+"))
1937 TrReadOperator(tr
, "+");
1939 if(hData
->mChannelType
== CT_STEREO
)
1941 if(azd
->mIrs
[0] == nullptr)
1943 TrErrorAt(tr
, line
, col
, "Missing left ear source reference(s).\n");
1946 else if(azd
->mIrs
[1] == nullptr)
1948 TrErrorAt(tr
, line
, col
, "Missing right ear source reference(s).\n");
1954 for(fi
= 0;fi
< hData
->mFdCount
;fi
++)
1956 for(ei
= 0;ei
< hData
->mFds
[fi
].mEvCount
;ei
++)
1958 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;ai
++)
1960 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1961 if(azd
->mIrs
[0] != nullptr)
1964 if(ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
)
1967 if(ei
>= hData
->mFds
[fi
].mEvCount
)
1969 TrError(tr
, "Missing source references [ %d, *, * ].\n", fi
);
1972 hData
->mFds
[fi
].mEvStart
= ei
;
1973 for(;ei
< hData
->mFds
[fi
].mEvCount
;ei
++)
1975 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;ai
++)
1977 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1979 if(azd
->mIrs
[0] == nullptr)
1981 TrError(tr
, "Missing source reference [ %d, %d, %d ].\n", fi
, ei
, ai
);
1987 for(uint ti
{0};ti
< channels
;ti
++)
1989 for(fi
= 0;fi
< hData
->mFdCount
;fi
++)
1991 for(ei
= 0;ei
< hData
->mFds
[fi
].mEvCount
;ei
++)
1993 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;ai
++)
1995 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1997 azd
->mIrs
[ti
] = &hrirs
[hData
->mIrSize
* (ti
* hData
->mIrCount
+ azd
->mIndex
)];
2004 mysofa_cache_release_all();
2008 TrError(tr
, "Errant data at end of source list.\n");
2009 mysofa_cache_release_all();
2014 bool LoadDefInput(std::istream
&istream
, const char *startbytes
, std::streamsize startbytecount
,
2015 const char *filename
, const uint fftSize
, const uint truncSize
, const ChannelModeT chanMode
,
2018 TokenReaderT tr
{istream
};
2020 TrSetup(startbytes
, startbytecount
, filename
, &tr
);
2021 if(!ProcessMetrics(&tr
, fftSize
, truncSize
, chanMode
, hData
)
2022 || !ProcessSources(&tr
, hData
))