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"
40 #include "aloptional.h"
44 #include "polyphase_resampler.h"
48 // Constants for accessing the token reader's ring buffer.
49 #define TR_RING_BITS (16)
50 #define TR_RING_SIZE (1 << TR_RING_BITS)
51 #define TR_RING_MASK (TR_RING_SIZE - 1)
53 // The token reader's load interval in bytes.
54 #define TR_LOAD_SIZE (TR_RING_SIZE >> 2)
56 // Token reader state for parsing the data set definition.
58 std::istream
&mIStream
;
62 char mRing
[TR_RING_SIZE
]{};
63 std::streamsize mIn
{};
64 std::streamsize mOut
{};
66 TokenReaderT(std::istream
&istream
) noexcept
: mIStream
{istream
} { }
67 TokenReaderT(const TokenReaderT
&) = default;
71 // The maximum identifier length used when processing the data set
73 #define MAX_IDENT_LEN (16)
75 // The limits for the listener's head 'radius' in the data set definition.
76 #define MIN_RADIUS (0.05)
77 #define MAX_RADIUS (0.15)
79 // The maximum number of channels that can be addressed for a WAVE file
80 // source listed in the data set definition.
81 #define MAX_WAVE_CHANNELS (65535)
83 // The limits to the byte size for a binary source listed in the definition
85 #define MIN_BIN_SIZE (2)
86 #define MAX_BIN_SIZE (4)
88 // The minimum number of significant bits for binary sources listed in the
89 // data set definition. The maximum is calculated from the byte size.
90 #define MIN_BIN_BITS (16)
92 // The limits to the number of significant bits for an ASCII source listed in
93 // the data set definition.
94 #define MIN_ASCII_BITS (16)
95 #define MAX_ASCII_BITS (32)
97 // The four-character-codes for RIFF/RIFX WAVE file chunks.
98 #define FOURCC_RIFF (0x46464952) // 'RIFF'
99 #define FOURCC_RIFX (0x58464952) // 'RIFX'
100 #define FOURCC_WAVE (0x45564157) // 'WAVE'
101 #define FOURCC_FMT (0x20746D66) // 'fmt '
102 #define FOURCC_DATA (0x61746164) // 'data'
103 #define FOURCC_LIST (0x5453494C) // 'LIST'
104 #define FOURCC_WAVL (0x6C766177) // 'wavl'
105 #define FOURCC_SLNT (0x746E6C73) // 'slnt'
107 // The supported wave formats.
108 #define WAVE_FORMAT_PCM (0x0001)
109 #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
110 #define WAVE_FORMAT_EXTENSIBLE (0xFFFE)
119 // Source format for the references listed in the data set definition.
122 SF_ASCII
, // ASCII text file.
123 SF_BIN_LE
, // Little-endian binary file.
124 SF_BIN_BE
, // Big-endian binary file.
125 SF_WAVE
, // RIFF/RIFX WAVE file.
126 SF_SOFA
// Spatially Oriented Format for Accoustics (SOFA) file.
129 // Element types for the references listed in the data set definition.
132 ET_INT
, // Integer elements.
133 ET_FP
// Floating-point elements.
136 // Source reference state used when loading sources.
138 SourceFormatT mFormat
;
148 char mPath
[MAX_PATH_LEN
+1];
152 /* Whitespace is not significant. It can process tokens as identifiers, numbers
153 * (integer and floating-point), strings, and operators. Strings must be
154 * encapsulated by double-quotes and cannot span multiple lines.
157 // Setup the reader on the given file. The filename can be NULL if no error
158 // output is desired.
159 static void TrSetup(const char *startbytes
, std::streamsize startbytecount
, const char *filename
,
162 const char *name
= nullptr;
166 const char *slash
= strrchr(filename
, '/');
169 const char *bslash
= strrchr(slash
+1, '\\');
170 if(bslash
) name
= bslash
+1;
175 const char *bslash
= strrchr(filename
, '\\');
176 if(bslash
) name
= bslash
+1;
177 else name
= filename
;
187 if(startbytecount
> 0)
189 std::copy_n(startbytes
, startbytecount
, std::begin(tr
->mRing
));
190 tr
->mIn
+= startbytecount
;
194 // Prime the reader's ring buffer, and return a result indicating that there
195 // is text to process.
196 static int TrLoad(TokenReaderT
*tr
)
198 std::istream
&istream
= tr
->mIStream
;
200 std::streamsize toLoad
{TR_RING_SIZE
- static_cast<std::streamsize
>(tr
->mIn
- tr
->mOut
)};
201 if(toLoad
>= TR_LOAD_SIZE
&& istream
.good())
203 // Load TR_LOAD_SIZE (or less if at the end of the file) per read.
204 toLoad
= TR_LOAD_SIZE
;
205 std::streamsize in
{tr
->mIn
&TR_RING_MASK
};
206 std::streamsize count
{TR_RING_SIZE
- in
};
209 istream
.read(&tr
->mRing
[in
], count
);
210 tr
->mIn
+= istream
.gcount();
211 istream
.read(&tr
->mRing
[0], toLoad
-count
);
212 tr
->mIn
+= istream
.gcount();
216 istream
.read(&tr
->mRing
[in
], toLoad
);
217 tr
->mIn
+= istream
.gcount();
220 if(tr
->mOut
>= TR_RING_SIZE
)
222 tr
->mOut
-= TR_RING_SIZE
;
223 tr
->mIn
-= TR_RING_SIZE
;
226 if(tr
->mIn
> tr
->mOut
)
231 // Error display routine. Only displays when the base name is not NULL.
232 static void TrErrorVA(const TokenReaderT
*tr
, uint line
, uint column
, const char *format
, va_list argPtr
)
236 fprintf(stderr
, "\nError (%s:%u:%u): ", tr
->mName
, line
, column
);
237 vfprintf(stderr
, format
, argPtr
);
240 // Used to display an error at a saved line/column.
241 static void TrErrorAt(const TokenReaderT
*tr
, uint line
, uint column
, const char *format
, ...)
245 va_start(argPtr
, format
);
246 TrErrorVA(tr
, line
, column
, format
, argPtr
);
250 // Used to display an error at the current line/column.
251 static void TrError(const TokenReaderT
*tr
, const char *format
, ...)
255 va_start(argPtr
, format
);
256 TrErrorVA(tr
, tr
->mLine
, tr
->mColumn
, format
, argPtr
);
260 // Skips to the next line.
261 static void TrSkipLine(TokenReaderT
*tr
)
267 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
279 // Skips to the next token.
280 static int TrSkipWhitespace(TokenReaderT
*tr
)
284 char ch
{tr
->mRing
[tr
->mOut
&TR_RING_MASK
]};
304 // Get the line and/or column of the next token (or the end of input).
305 static void TrIndication(TokenReaderT
*tr
, uint
*line
, uint
*column
)
307 TrSkipWhitespace(tr
);
308 if(line
) *line
= tr
->mLine
;
309 if(column
) *column
= tr
->mColumn
;
312 // Checks to see if a token is (likely to be) an identifier. It does not
313 // display any errors and will not proceed to the next token.
314 static int TrIsIdent(TokenReaderT
*tr
)
316 if(!TrSkipWhitespace(tr
))
318 char ch
{tr
->mRing
[tr
->mOut
&TR_RING_MASK
]};
319 return ch
== '_' || isalpha(ch
);
323 // Checks to see if a token is the given operator. It does not display any
324 // errors and will not proceed to the next token.
325 static int TrIsOperator(TokenReaderT
*tr
, const char *op
)
331 if(!TrSkipWhitespace(tr
))
335 while(op
[len
] != '\0' && out
< tr
->mIn
)
337 ch
= tr
->mRing
[out
&TR_RING_MASK
];
338 if(ch
!= op
[len
]) break;
347 /* The TrRead*() routines obtain the value of a matching token type. They
348 * display type, form, and boundary errors and will proceed to the next
352 // Reads and validates an identifier token.
353 static int TrReadIdent(TokenReaderT
*tr
, const uint maxLen
, char *ident
)
359 if(TrSkipWhitespace(tr
))
362 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
363 if(ch
== '_' || isalpha(ch
))
373 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
374 } while(ch
== '_' || isdigit(ch
) || isalpha(ch
));
382 TrErrorAt(tr
, tr
->mLine
, col
, "Identifier is too long.\n");
386 TrErrorAt(tr
, tr
->mLine
, col
, "Expected an identifier.\n");
390 // Reads and validates (including bounds) an integer token.
391 static int TrReadInt(TokenReaderT
*tr
, const int loBound
, const int hiBound
, int *value
)
393 uint col
, digis
, len
;
397 if(TrSkipWhitespace(tr
))
401 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
402 if(ch
== '+' || ch
== '-')
411 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
412 if(!isdigit(ch
)) break;
420 if(digis
> 0 && ch
!= '.' && !isalpha(ch
))
424 TrErrorAt(tr
, tr
->mLine
, col
, "Integer is too long.");
428 *value
= static_cast<int>(strtol(temp
, nullptr, 10));
429 if(*value
< loBound
|| *value
> hiBound
)
431 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a value from %d to %d.\n", loBound
, hiBound
);
437 TrErrorAt(tr
, tr
->mLine
, col
, "Expected an integer.\n");
441 // Reads and validates (including bounds) a float token.
442 static int TrReadFloat(TokenReaderT
*tr
, const double loBound
, const double hiBound
, double *value
)
444 uint col
, digis
, len
;
448 if(TrSkipWhitespace(tr
))
452 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
453 if(ch
== '+' || ch
== '-')
463 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
464 if(!isdigit(ch
)) break;
480 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
481 if(!isdigit(ch
)) break;
490 if(ch
== 'E' || ch
== 'e')
497 if(ch
== '+' || ch
== '-')
506 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
507 if(!isdigit(ch
)) break;
516 if(digis
> 0 && ch
!= '.' && !isalpha(ch
))
520 TrErrorAt(tr
, tr
->mLine
, col
, "Float is too long.");
524 *value
= strtod(temp
, nullptr);
525 if(*value
< loBound
|| *value
> hiBound
)
527 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a value from %f to %f.\n", loBound
, hiBound
);
536 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a float.\n");
540 // Reads and validates a string token.
541 static int TrReadString(TokenReaderT
*tr
, const uint maxLen
, char *text
)
547 if(TrSkipWhitespace(tr
))
550 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
557 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
563 TrErrorAt(tr
, tr
->mLine
, col
, "Unterminated string at end of line.\n");
572 tr
->mColumn
+= 1 + len
;
573 TrErrorAt(tr
, tr
->mLine
, col
, "Unterminated string at end of input.\n");
576 tr
->mColumn
+= 2 + len
;
579 TrErrorAt(tr
, tr
->mLine
, col
, "String is too long.\n");
586 TrErrorAt(tr
, tr
->mLine
, col
, "Expected a string.\n");
590 // Reads and validates the given operator.
591 static int TrReadOperator(TokenReaderT
*tr
, const char *op
)
597 if(TrSkipWhitespace(tr
))
601 while(op
[len
] != '\0' && TrLoad(tr
))
603 ch
= tr
->mRing
[tr
->mOut
&TR_RING_MASK
];
604 if(ch
!= op
[len
]) break;
612 TrErrorAt(tr
, tr
->mLine
, col
, "Expected '%s' operator.\n", op
);
617 /*************************
618 *** File source input ***
619 *************************/
621 // Read a binary value of the specified byte order and byte size from a file,
622 // storing it as a 32-bit unsigned integer.
623 static int ReadBin4(std::istream
&istream
, const char *filename
, const ByteOrderT order
, const uint bytes
, uint32_t *out
)
626 istream
.read(reinterpret_cast<char*>(in
), static_cast<int>(bytes
));
627 if(istream
.gcount() != bytes
)
629 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
636 for(uint i
= 0;i
< bytes
;i
++)
637 accum
= (accum
<<8) | in
[bytes
- i
- 1];
640 for(uint i
= 0;i
< bytes
;i
++)
641 accum
= (accum
<<8) | in
[i
];
650 // Read a binary value of the specified byte order from a file, storing it as
651 // a 64-bit unsigned integer.
652 static int ReadBin8(std::istream
&istream
, const char *filename
, const ByteOrderT order
, uint64_t *out
)
658 istream
.read(reinterpret_cast<char*>(in
), 8);
659 if(istream
.gcount() != 8)
661 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
669 accum
= (accum
<<8) | in
[8 - i
- 1];
673 accum
= (accum
<<8) | in
[i
];
682 /* Read a binary value of the specified type, byte order, and byte size from
683 * a file, converting it to a double. For integer types, the significant
684 * bits are used to normalize the result. The sign of bits determines
685 * whether they are padded toward the MSB (negative) or LSB (positive).
686 * Floating-point types are not normalized.
688 static int ReadBinAsDouble(std::istream
&istream
, const char *filename
, const ByteOrderT order
,
689 const ElementTypeT type
, const uint bytes
, const int bits
, double *out
)
704 if(!ReadBin8(istream
, filename
, order
, &v8
.ui
))
711 if(!ReadBin4(istream
, filename
, order
, bytes
, &v4
.ui
))
718 v4
.ui
>>= (8*bytes
) - (static_cast<uint
>(bits
));
720 v4
.ui
&= (0xFFFFFFFF >> (32+bits
));
722 if(v4
.ui
&static_cast<uint
>(1<<(std::abs(bits
)-1)))
723 v4
.ui
|= (0xFFFFFFFF << std::abs(bits
));
724 *out
= v4
.i
/ static_cast<double>(1<<(std::abs(bits
)-1));
730 /* Read an ascii value of the specified type from a file, converting it to a
731 * double. For integer types, the significant bits are used to normalize the
732 * result. The sign of the bits should always be positive. This also skips
733 * up to one separator character before the element itself.
735 static int ReadAsciiAsDouble(TokenReaderT
*tr
, const char *filename
, const ElementTypeT type
, const uint bits
, double *out
)
737 if(TrIsOperator(tr
, ","))
738 TrReadOperator(tr
, ",");
739 else if(TrIsOperator(tr
, ":"))
740 TrReadOperator(tr
, ":");
741 else if(TrIsOperator(tr
, ";"))
742 TrReadOperator(tr
, ";");
743 else if(TrIsOperator(tr
, "|"))
744 TrReadOperator(tr
, "|");
748 if(!TrReadFloat(tr
, -std::numeric_limits
<double>::infinity(),
749 std::numeric_limits
<double>::infinity(), out
))
751 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
758 if(!TrReadInt(tr
, -(1<<(bits
-1)), (1<<(bits
-1))-1, &v
))
760 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", filename
);
763 *out
= v
/ static_cast<double>((1<<(bits
-1))-1);
768 // Read the RIFF/RIFX WAVE format chunk from a file, validating it against
769 // the source parameters and data set metrics.
770 static int ReadWaveFormat(std::istream
&istream
, const ByteOrderT order
, const uint hrirRate
,
773 uint32_t fourCC
, chunkSize
;
774 uint32_t format
, channels
, rate
, dummy
, block
, size
, bits
;
779 istream
.seekg(static_cast<int>(chunkSize
), std::ios::cur
);
780 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
781 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
783 } while(fourCC
!= FOURCC_FMT
);
784 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &format
)
785 || !ReadBin4(istream
, src
->mPath
, order
, 2, &channels
)
786 || !ReadBin4(istream
, src
->mPath
, order
, 4, &rate
)
787 || !ReadBin4(istream
, src
->mPath
, order
, 4, &dummy
)
788 || !ReadBin4(istream
, src
->mPath
, order
, 2, &block
))
793 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &size
))
801 if(format
== WAVE_FORMAT_EXTENSIBLE
)
803 istream
.seekg(2, std::ios::cur
);
804 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &bits
))
808 istream
.seekg(4, std::ios::cur
);
809 if(!ReadBin4(istream
, src
->mPath
, order
, 2, &format
))
811 istream
.seekg(static_cast<int>(chunkSize
- 26), std::ios::cur
);
817 istream
.seekg(static_cast<int>(chunkSize
- 16), std::ios::cur
);
819 istream
.seekg(static_cast<int>(chunkSize
- 14), std::ios::cur
);
821 if(format
!= WAVE_FORMAT_PCM
&& format
!= WAVE_FORMAT_IEEE_FLOAT
)
823 fprintf(stderr
, "\nError: Unsupported WAVE format in file '%s'.\n", src
->mPath
);
826 if(src
->mChannel
>= channels
)
828 fprintf(stderr
, "\nError: Missing source channel in WAVE file '%s'.\n", src
->mPath
);
833 fprintf(stderr
, "\nError: Mismatched source sample rate in WAVE file '%s'.\n", src
->mPath
);
836 if(format
== WAVE_FORMAT_PCM
)
838 if(size
< 2 || size
> 4)
840 fprintf(stderr
, "\nError: Unsupported sample size in WAVE file '%s'.\n", src
->mPath
);
843 if(bits
< 16 || bits
> (8*size
))
845 fprintf(stderr
, "\nError: Bad significant bits in WAVE file '%s'.\n", src
->mPath
);
852 if(size
!= 4 && size
!= 8)
854 fprintf(stderr
, "\nError: Unsupported sample size in WAVE file '%s'.\n", src
->mPath
);
860 src
->mBits
= static_cast<int>(bits
);
861 src
->mSkip
= channels
;
865 // Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles.
866 static int ReadWaveData(std::istream
&istream
, const SourceRefT
*src
, const ByteOrderT order
,
867 const uint n
, double *hrir
)
872 pre
= static_cast<int>(src
->mSize
* src
->mChannel
);
873 post
= static_cast<int>(src
->mSize
* (src
->mSkip
- src
->mChannel
- 1));
879 istream
.seekg(skip
, std::ios::cur
);
880 if(!ReadBinAsDouble(istream
, src
->mPath
, order
, src
->mType
, src
->mSize
, src
->mBits
, &hrir
[i
]))
885 istream
.seekg(skip
, std::ios::cur
);
889 // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to
891 static int ReadWaveList(std::istream
&istream
, const SourceRefT
*src
, const ByteOrderT order
,
892 const uint n
, double *hrir
)
894 uint32_t fourCC
, chunkSize
, listSize
, count
;
895 uint block
, skip
, offset
, i
;
900 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
901 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
904 if(fourCC
== FOURCC_DATA
)
906 block
= src
->mSize
* src
->mSkip
;
907 count
= chunkSize
/ block
;
908 if(count
< (src
->mOffset
+ n
))
910 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", src
->mPath
);
913 istream
.seekg(static_cast<long>(src
->mOffset
* block
), std::ios::cur
);
914 if(!ReadWaveData(istream
, src
, order
, n
, &hrir
[0]))
918 else if(fourCC
== FOURCC_LIST
)
920 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
))
923 if(fourCC
== FOURCC_WAVL
)
927 istream
.seekg(static_cast<long>(chunkSize
), std::ios::cur
);
929 listSize
= chunkSize
;
930 block
= src
->mSize
* src
->mSkip
;
934 while(offset
< n
&& listSize
> 8)
936 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
937 || !ReadBin4(istream
, src
->mPath
, order
, 4, &chunkSize
))
939 listSize
-= 8 + chunkSize
;
940 if(fourCC
== FOURCC_DATA
)
942 count
= chunkSize
/ block
;
945 istream
.seekg(static_cast<long>(skip
* block
), std::ios::cur
);
946 chunkSize
-= skip
* block
;
949 if(count
> (n
- offset
))
951 if(!ReadWaveData(istream
, src
, order
, count
, &hrir
[offset
]))
953 chunkSize
-= count
* block
;
955 lastSample
= hrir
[offset
- 1];
963 else if(fourCC
== FOURCC_SLNT
)
965 if(!ReadBin4(istream
, src
->mPath
, order
, 4, &count
))
972 if(count
> (n
- offset
))
974 for(i
= 0; i
< count
; i
++)
975 hrir
[offset
+ i
] = lastSample
;
985 istream
.seekg(static_cast<long>(chunkSize
), std::ios::cur
);
989 fprintf(stderr
, "\nError: Bad read from file '%s'.\n", src
->mPath
);
995 // Load a source HRIR from an ASCII text file containing a list of elements
996 // separated by whitespace or common list operators (',', ';', ':', '|').
997 static int LoadAsciiSource(std::istream
&istream
, const SourceRefT
*src
,
998 const uint n
, double *hrir
)
1000 TokenReaderT tr
{istream
};
1004 TrSetup(nullptr, 0, nullptr, &tr
);
1005 for(i
= 0;i
< src
->mOffset
;i
++)
1007 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &dummy
))
1010 for(i
= 0;i
< n
;i
++)
1012 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &hrir
[i
]))
1014 for(j
= 0;j
< src
->mSkip
;j
++)
1016 if(!ReadAsciiAsDouble(&tr
, src
->mPath
, src
->mType
, static_cast<uint
>(src
->mBits
), &dummy
))
1023 // Load a source HRIR from a binary file.
1024 static int LoadBinarySource(std::istream
&istream
, const SourceRefT
*src
, const ByteOrderT order
,
1025 const uint n
, double *hrir
)
1027 istream
.seekg(static_cast<long>(src
->mOffset
), std::ios::beg
);
1028 for(uint i
{0};i
< n
;i
++)
1030 if(!ReadBinAsDouble(istream
, src
->mPath
, order
, src
->mType
, src
->mSize
, src
->mBits
, &hrir
[i
]))
1033 istream
.seekg(static_cast<long>(src
->mSkip
), std::ios::cur
);
1038 // Load a source HRIR from a RIFF/RIFX WAVE file.
1039 static int LoadWaveSource(std::istream
&istream
, SourceRefT
*src
, const uint hrirRate
,
1040 const uint n
, double *hrir
)
1042 uint32_t fourCC
, dummy
;
1045 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
)
1046 || !ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &dummy
))
1048 if(fourCC
== FOURCC_RIFF
)
1050 else if(fourCC
== FOURCC_RIFX
)
1054 fprintf(stderr
, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src
->mPath
);
1058 if(!ReadBin4(istream
, src
->mPath
, BO_LITTLE
, 4, &fourCC
))
1060 if(fourCC
!= FOURCC_WAVE
)
1062 fprintf(stderr
, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src
->mPath
);
1065 if(!ReadWaveFormat(istream
, order
, hrirRate
, src
))
1067 if(!ReadWaveList(istream
, src
, order
, n
, hrir
))
1074 // Load a Spatially Oriented Format for Accoustics (SOFA) file.
1075 static MYSOFA_EASY
* LoadSofaFile(SourceRefT
*src
, const uint hrirRate
, const uint n
)
1077 struct MYSOFA_EASY
*sofa
{mysofa_cache_lookup(src
->mPath
, static_cast<float>(hrirRate
))};
1078 if(sofa
) return sofa
;
1080 sofa
= static_cast<MYSOFA_EASY
*>(calloc(1, sizeof(*sofa
)));
1083 fprintf(stderr
, "\nError: Out of memory.\n");
1086 sofa
->lookup
= nullptr;
1087 sofa
->neighborhood
= nullptr;
1090 sofa
->hrtf
= mysofa_load(src
->mPath
, &err
);
1094 fprintf(stderr
, "\nError: Could not load source file '%s'.\n", src
->mPath
);
1097 /* NOTE: Some valid SOFA files are failing this check. */
1098 err
= mysofa_check(sofa
->hrtf
);
1099 if(err
!= MYSOFA_OK
)
1100 fprintf(stderr
, "\nWarning: Supposedly malformed source file '%s'.\n", src
->mPath
);
1101 if((src
->mOffset
+ n
) > sofa
->hrtf
->N
)
1104 fprintf(stderr
, "\nError: Not enough samples in SOFA file '%s'.\n", src
->mPath
);
1107 if(src
->mChannel
>= sofa
->hrtf
->R
)
1110 fprintf(stderr
, "\nError: Missing source receiver in SOFA file '%s'.\n", src
->mPath
);
1113 mysofa_tocartesian(sofa
->hrtf
);
1114 sofa
->lookup
= mysofa_lookup_init(sofa
->hrtf
);
1115 if(sofa
->lookup
== nullptr)
1118 fprintf(stderr
, "\nError: Out of memory.\n");
1121 return mysofa_cache_store(sofa
, src
->mPath
, static_cast<float>(hrirRate
));
1124 // Copies the HRIR data from a particular SOFA measurement.
1125 static void ExtractSofaHrir(const MYSOFA_EASY
*sofa
, const uint index
, const uint channel
, const uint offset
, const uint n
, double *hrir
)
1127 for(uint i
{0u};i
< n
;i
++)
1128 hrir
[i
] = sofa
->hrtf
->DataIR
.values
[(index
*sofa
->hrtf
->R
+ channel
)*sofa
->hrtf
->N
+ offset
+ i
];
1131 // Load a source HRIR from a Spatially Oriented Format for Accoustics (SOFA)
1133 static int LoadSofaSource(SourceRefT
*src
, const uint hrirRate
, const uint n
, double *hrir
)
1135 struct MYSOFA_EASY
*sofa
;
1140 sofa
= LoadSofaFile(src
, hrirRate
, n
);
1144 /* NOTE: At some point it may be benficial or necessary to consider the
1145 various coordinate systems, listener/source orientations, and
1146 direciontal vectors defined in the SOFA file.
1148 target
[0] = static_cast<float>(src
->mAzimuth
);
1149 target
[1] = static_cast<float>(src
->mElevation
);
1150 target
[2] = static_cast<float>(src
->mRadius
);
1153 nearest
= mysofa_lookup(sofa
->lookup
, target
);
1156 fprintf(stderr
, "\nError: Lookup failed in source file '%s'.\n", src
->mPath
);
1160 coords
= &sofa
->hrtf
->SourcePosition
.values
[3 * nearest
];
1161 if(std::abs(coords
[0] - target
[0]) > 0.001 || std::abs(coords
[1] - target
[1]) > 0.001 || std::abs(coords
[2] - target
[2]) > 0.001)
1163 fprintf(stderr
, "\nError: No impulse response at coordinates (%.3fr, %.1fev, %.1faz) in file '%s'.\n", src
->mRadius
, src
->mElevation
, src
->mAzimuth
, src
->mPath
);
1164 target
[0] = coords
[0];
1165 target
[1] = coords
[1];
1166 target
[2] = coords
[2];
1168 fprintf(stderr
, " Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target
[2], target
[1], target
[0]);
1172 ExtractSofaHrir(sofa
, static_cast<uint
>(nearest
), src
->mChannel
, src
->mOffset
, n
, hrir
);
1177 // Load a source HRIR from a supported file type.
1178 static int LoadSource(SourceRefT
*src
, const uint hrirRate
, const uint n
, double *hrir
)
1180 std::unique_ptr
<al::ifstream
> istream
;
1181 if(src
->mFormat
!= SF_SOFA
)
1183 if(src
->mFormat
== SF_ASCII
)
1184 istream
.reset(new al::ifstream
{src
->mPath
});
1186 istream
.reset(new al::ifstream
{src
->mPath
, std::ios::binary
});
1187 if(!istream
->good())
1189 fprintf(stderr
, "\nError: Could not open source file '%s'.\n", src
->mPath
);
1194 switch(src
->mFormat
)
1197 result
= LoadAsciiSource(*istream
, src
, n
, hrir
);
1200 result
= LoadBinarySource(*istream
, src
, BO_LITTLE
, n
, hrir
);
1203 result
= LoadBinarySource(*istream
, src
, BO_BIG
, n
, hrir
);
1206 result
= LoadWaveSource(*istream
, src
, hrirRate
, n
, hrir
);
1209 result
= LoadSofaSource(src
, hrirRate
, n
, hrir
);
1218 // Match the channel type from a given identifier.
1219 static ChannelTypeT
MatchChannelType(const char *ident
)
1221 if(al::strcasecmp(ident
, "mono") == 0)
1223 if(al::strcasecmp(ident
, "stereo") == 0)
1229 // Process the data set definition to read and validate the data set metrics.
1230 static int ProcessMetrics(TokenReaderT
*tr
, const uint fftSize
, const uint truncSize
, const ChannelModeT chanMode
, HrirDataT
*hData
)
1232 int hasRate
= 0, hasType
= 0, hasPoints
= 0, hasRadius
= 0;
1233 int hasDistance
= 0, hasAzimuths
= 0;
1234 char ident
[MAX_IDENT_LEN
+1];
1239 double distances
[MAX_FD_COUNT
];
1241 uint evCounts
[MAX_FD_COUNT
];
1242 auto azCounts
= std::vector
<std::array
<uint
,MAX_EV_COUNT
>>(MAX_FD_COUNT
);
1243 for(auto &azs
: azCounts
) azs
.fill(0u);
1245 TrIndication(tr
, &line
, &col
);
1246 while(TrIsIdent(tr
))
1248 TrIndication(tr
, &line
, &col
);
1249 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1251 if(al::strcasecmp(ident
, "rate") == 0)
1255 TrErrorAt(tr
, line
, col
, "Redefinition of 'rate'.\n");
1258 if(!TrReadOperator(tr
, "="))
1260 if(!TrReadInt(tr
, MIN_RATE
, MAX_RATE
, &intVal
))
1262 hData
->mIrRate
= static_cast<uint
>(intVal
);
1265 else if(al::strcasecmp(ident
, "type") == 0)
1267 char type
[MAX_IDENT_LEN
+1];
1271 TrErrorAt(tr
, line
, col
, "Redefinition of 'type'.\n");
1274 if(!TrReadOperator(tr
, "="))
1277 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1279 hData
->mChannelType
= MatchChannelType(type
);
1280 if(hData
->mChannelType
== CT_NONE
)
1282 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1285 else if(hData
->mChannelType
== CT_STEREO
)
1287 if(chanMode
== CM_ForceMono
)
1288 hData
->mChannelType
= CT_MONO
;
1292 else if(al::strcasecmp(ident
, "points") == 0)
1296 TrErrorAt(tr
, line
, col
, "Redefinition of 'points'.\n");
1299 if(!TrReadOperator(tr
, "="))
1301 TrIndication(tr
, &line
, &col
);
1302 if(!TrReadInt(tr
, MIN_POINTS
, MAX_POINTS
, &intVal
))
1304 points
= static_cast<uint
>(intVal
);
1305 if(fftSize
> 0 && points
> fftSize
)
1307 TrErrorAt(tr
, line
, col
, "Value exceeds the overridden FFT size.\n");
1310 if(points
< truncSize
)
1312 TrErrorAt(tr
, line
, col
, "Value is below the truncation size.\n");
1315 hData
->mIrPoints
= points
;
1316 hData
->mFftSize
= fftSize
;
1317 hData
->mIrSize
= 1 + (fftSize
/ 2);
1318 if(points
> hData
->mIrSize
)
1319 hData
->mIrSize
= points
;
1322 else if(al::strcasecmp(ident
, "radius") == 0)
1326 TrErrorAt(tr
, line
, col
, "Redefinition of 'radius'.\n");
1329 if(!TrReadOperator(tr
, "="))
1331 if(!TrReadFloat(tr
, MIN_RADIUS
, MAX_RADIUS
, &fpVal
))
1333 hData
->mRadius
= fpVal
;
1336 else if(al::strcasecmp(ident
, "distance") == 0)
1342 TrErrorAt(tr
, line
, col
, "Redefinition of 'distance'.\n");
1345 if(!TrReadOperator(tr
, "="))
1350 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1352 if(count
> 0 && fpVal
<= distances
[count
- 1])
1354 TrError(tr
, "Distances are not ascending.\n");
1357 distances
[count
++] = fpVal
;
1358 if(!TrIsOperator(tr
, ","))
1360 if(count
>= MAX_FD_COUNT
)
1362 TrError(tr
, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT
);
1365 TrReadOperator(tr
, ",");
1367 if(fdCount
!= 0 && count
!= fdCount
)
1369 TrError(tr
, "Did not match the specified number of %d fields.\n", fdCount
);
1375 else if(al::strcasecmp(ident
, "azimuths") == 0)
1381 TrErrorAt(tr
, line
, col
, "Redefinition of 'azimuths'.\n");
1384 if(!TrReadOperator(tr
, "="))
1390 if(!TrReadInt(tr
, MIN_AZ_COUNT
, MAX_AZ_COUNT
, &intVal
))
1392 azCounts
[count
][evCounts
[count
]++] = static_cast<uint
>(intVal
);
1393 if(TrIsOperator(tr
, ","))
1395 if(evCounts
[count
] >= MAX_EV_COUNT
)
1397 TrError(tr
, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT
);
1400 TrReadOperator(tr
, ",");
1404 if(evCounts
[count
] < MIN_EV_COUNT
)
1406 TrErrorAt(tr
, line
, col
, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT
);
1409 if(azCounts
[count
][0] != 1 || azCounts
[count
][evCounts
[count
] - 1] != 1)
1411 TrError(tr
, "Poles are not singular for field %d.\n", count
- 1);
1415 if(!TrIsOperator(tr
, ";"))
1418 if(count
>= MAX_FD_COUNT
)
1420 TrError(tr
, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT
);
1423 evCounts
[count
] = 0;
1424 TrReadOperator(tr
, ";");
1427 if(fdCount
!= 0 && count
!= fdCount
)
1429 TrError(tr
, "Did not match the specified number of %d fields.\n", fdCount
);
1437 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1440 TrSkipWhitespace(tr
);
1442 if(!(hasRate
&& hasPoints
&& hasRadius
&& hasDistance
&& hasAzimuths
))
1444 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1447 if(distances
[0] < hData
->mRadius
)
1449 TrError(tr
, "Distance cannot start below head radius.\n");
1452 if(hData
->mChannelType
== CT_NONE
)
1453 hData
->mChannelType
= CT_MONO
;
1454 const auto azs
= al::as_span(azCounts
).first
<MAX_FD_COUNT
>();
1455 if(!PrepareHrirData({distances
, fdCount
}, evCounts
, azs
, hData
))
1457 fprintf(stderr
, "Error: Out of memory.\n");
1463 // Parse an index triplet from the data set definition.
1464 static int ReadIndexTriplet(TokenReaderT
*tr
, const HrirDataT
*hData
, uint
*fi
, uint
*ei
, uint
*ai
)
1468 if(hData
->mFds
.size() > 1)
1470 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
.size()-1), &intVal
))
1472 *fi
= static_cast<uint
>(intVal
);
1473 if(!TrReadOperator(tr
, ","))
1480 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvs
.size()-1), &intVal
))
1482 *ei
= static_cast<uint
>(intVal
);
1483 if(!TrReadOperator(tr
, ","))
1485 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvs
[*ei
].mAzs
.size()-1), &intVal
))
1487 *ai
= static_cast<uint
>(intVal
);
1491 // Match the source format from a given identifier.
1492 static SourceFormatT
MatchSourceFormat(const char *ident
)
1494 if(al::strcasecmp(ident
, "ascii") == 0)
1496 if(al::strcasecmp(ident
, "bin_le") == 0)
1498 if(al::strcasecmp(ident
, "bin_be") == 0)
1500 if(al::strcasecmp(ident
, "wave") == 0)
1502 if(al::strcasecmp(ident
, "sofa") == 0)
1507 // Match the source element type from a given identifier.
1508 static ElementTypeT
MatchElementType(const char *ident
)
1510 if(al::strcasecmp(ident
, "int") == 0)
1512 if(al::strcasecmp(ident
, "fp") == 0)
1517 // Parse and validate a source reference from the data set definition.
1518 static int ReadSourceRef(TokenReaderT
*tr
, SourceRefT
*src
)
1520 char ident
[MAX_IDENT_LEN
+1];
1525 TrIndication(tr
, &line
, &col
);
1526 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1528 src
->mFormat
= MatchSourceFormat(ident
);
1529 if(src
->mFormat
== SF_NONE
)
1531 TrErrorAt(tr
, line
, col
, "Expected a source format.\n");
1534 if(!TrReadOperator(tr
, "("))
1536 if(src
->mFormat
== SF_SOFA
)
1538 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1540 src
->mRadius
= fpVal
;
1541 if(!TrReadOperator(tr
, ","))
1543 if(!TrReadFloat(tr
, -90.0, 90.0, &fpVal
))
1545 src
->mElevation
= fpVal
;
1546 if(!TrReadOperator(tr
, ","))
1548 if(!TrReadFloat(tr
, -360.0, 360.0, &fpVal
))
1550 src
->mAzimuth
= fpVal
;
1551 if(!TrReadOperator(tr
, ":"))
1553 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1555 src
->mType
= ET_NONE
;
1558 src
->mChannel
= static_cast<uint
>(intVal
);
1561 else if(src
->mFormat
== SF_WAVE
)
1563 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1565 src
->mType
= ET_NONE
;
1568 src
->mChannel
= static_cast<uint
>(intVal
);
1573 TrIndication(tr
, &line
, &col
);
1574 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1576 src
->mType
= MatchElementType(ident
);
1577 if(src
->mType
== ET_NONE
)
1579 TrErrorAt(tr
, line
, col
, "Expected a source element type.\n");
1582 if(src
->mFormat
== SF_BIN_LE
|| src
->mFormat
== SF_BIN_BE
)
1584 if(!TrReadOperator(tr
, ","))
1586 if(src
->mType
== ET_INT
)
1588 if(!TrReadInt(tr
, MIN_BIN_SIZE
, MAX_BIN_SIZE
, &intVal
))
1590 src
->mSize
= static_cast<uint
>(intVal
);
1591 if(!TrIsOperator(tr
, ","))
1592 src
->mBits
= static_cast<int>(8*src
->mSize
);
1595 TrReadOperator(tr
, ",");
1596 TrIndication(tr
, &line
, &col
);
1597 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
1599 if(std::abs(intVal
) < MIN_BIN_BITS
|| static_cast<uint
>(std::abs(intVal
)) > (8*src
->mSize
))
1601 TrErrorAt(tr
, line
, col
, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS
, 8*src
->mSize
);
1604 src
->mBits
= intVal
;
1609 TrIndication(tr
, &line
, &col
);
1610 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
1612 if(intVal
!= 4 && intVal
!= 8)
1614 TrErrorAt(tr
, line
, col
, "Expected a value of 4 or 8.\n");
1617 src
->mSize
= static_cast<uint
>(intVal
);
1621 else if(src
->mFormat
== SF_ASCII
&& src
->mType
== ET_INT
)
1623 if(!TrReadOperator(tr
, ","))
1625 if(!TrReadInt(tr
, MIN_ASCII_BITS
, MAX_ASCII_BITS
, &intVal
))
1628 src
->mBits
= intVal
;
1636 if(!TrIsOperator(tr
, ";"))
1640 TrReadOperator(tr
, ";");
1641 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1643 src
->mSkip
= static_cast<uint
>(intVal
);
1646 if(!TrReadOperator(tr
, ")"))
1648 if(TrIsOperator(tr
, "@"))
1650 TrReadOperator(tr
, "@");
1651 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1653 src
->mOffset
= static_cast<uint
>(intVal
);
1657 if(!TrReadOperator(tr
, ":"))
1659 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
1664 // Parse and validate a SOFA source reference from the data set definition.
1665 static int ReadSofaRef(TokenReaderT
*tr
, SourceRefT
*src
)
1667 char ident
[MAX_IDENT_LEN
+1];
1671 TrIndication(tr
, &line
, &col
);
1672 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1674 src
->mFormat
= MatchSourceFormat(ident
);
1675 if(src
->mFormat
!= SF_SOFA
)
1677 TrErrorAt(tr
, line
, col
, "Expected the SOFA source format.\n");
1681 src
->mType
= ET_NONE
;
1687 if(TrIsOperator(tr
, "@"))
1689 TrReadOperator(tr
, "@");
1690 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1692 src
->mOffset
= static_cast<uint
>(intVal
);
1696 if(!TrReadOperator(tr
, ":"))
1698 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
1703 // Match the target ear (index) from a given identifier.
1704 static int MatchTargetEar(const char *ident
)
1706 if(al::strcasecmp(ident
, "left") == 0)
1708 if(al::strcasecmp(ident
, "right") == 0)
1713 // Calculate the onset time of an HRIR and average it with any existing
1714 // timing for its field, elevation, azimuth, and ear.
1715 static constexpr int OnsetRateMultiple
{10};
1716 static double AverageHrirOnset(PPhaseResampler
&rs
, al::span
<double> upsampled
, const uint rate
,
1717 const uint n
, const double *hrir
, const double f
, const double onset
)
1719 rs
.process(n
, hrir
, static_cast<uint
>(upsampled
.size()), upsampled
.data());
1721 auto abs_lt
= [](const double &lhs
, const double &rhs
) -> bool
1722 { return std::abs(lhs
) < std::abs(rhs
); };
1723 auto iter
= std::max_element(upsampled
.cbegin(), upsampled
.cend(), abs_lt
);
1724 return Lerp(onset
, static_cast<double>(std::distance(upsampled
.cbegin(), iter
))/(10*rate
), f
);
1727 // Calculate the magnitude response of an HRIR and average it with any
1728 // existing responses for its field, elevation, azimuth, and ear.
1729 static void AverageHrirMagnitude(const uint points
, const uint n
, const double *hrir
, const double f
, double *mag
)
1731 uint m
= 1 + (n
/ 2), i
;
1732 std::vector
<complex_d
> h(n
);
1733 std::vector
<double> r(n
);
1735 for(i
= 0;i
< points
;i
++)
1739 FftForward(n
, h
.data());
1740 MagnitudeResponse(n
, h
.data(), r
.data());
1741 for(i
= 0;i
< m
;i
++)
1742 mag
[i
] = Lerp(mag
[i
], r
[i
], f
);
1745 // Process the list of sources in the data set definition.
1746 static int ProcessSources(TokenReaderT
*tr
, HrirDataT
*hData
, const uint outRate
)
1748 const uint channels
{(hData
->mChannelType
== CT_STEREO
) ? 2u : 1u};
1749 hData
->mHrirsBase
.resize(channels
* hData
->mIrCount
* hData
->mIrSize
);
1750 double *hrirs
= hData
->mHrirsBase
.data();
1751 auto hrir
= std::make_unique
<double[]>(hData
->mIrSize
);
1752 uint line
, col
, fi
, ei
, ai
;
1754 std::vector
<double> onsetSamples(OnsetRateMultiple
* hData
->mIrPoints
);
1755 PPhaseResampler onsetResampler
;
1756 onsetResampler
.init(hData
->mIrRate
, OnsetRateMultiple
*hData
->mIrRate
);
1758 al::optional
<PPhaseResampler
> resampler
;
1759 if(outRate
&& outRate
!= hData
->mIrRate
)
1760 resampler
.emplace().init(hData
->mIrRate
, outRate
);
1761 const double rateScale
{outRate
? static_cast<double>(outRate
) / hData
->mIrRate
: 1.0};
1762 const uint irPoints
{outRate
1763 ? std::min(static_cast<uint
>(std::ceil(hData
->mIrPoints
*rateScale
)), hData
->mIrPoints
)
1764 : hData
->mIrPoints
};
1766 printf("Loading sources...");
1769 while(TrIsOperator(tr
, "["))
1771 double factor
[2]{ 1.0, 1.0 };
1773 TrIndication(tr
, &line
, &col
);
1774 TrReadOperator(tr
, "[");
1776 if(TrIsOperator(tr
, "*"))
1779 struct MYSOFA_EASY
*sofa
;
1782 TrReadOperator(tr
, "*");
1783 if(!TrReadOperator(tr
, "]") || !TrReadOperator(tr
, "="))
1786 TrIndication(tr
, &line
, &col
);
1787 if(!ReadSofaRef(tr
, &src
))
1790 if(hData
->mChannelType
== CT_STEREO
)
1792 char type
[MAX_IDENT_LEN
+1];
1793 ChannelTypeT channelType
;
1795 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1798 channelType
= MatchChannelType(type
);
1803 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1815 char type
[MAX_IDENT_LEN
+1];
1816 ChannelTypeT channelType
;
1818 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1821 channelType
= MatchChannelType(type
);
1822 if(channelType
!= CT_MONO
)
1824 TrErrorAt(tr
, line
, col
, "Expected a mono channel type.\n");
1830 sofa
= LoadSofaFile(&src
, hData
->mIrRate
, hData
->mIrPoints
);
1833 for(si
= 0;si
< sofa
->hrtf
->M
;si
++)
1835 printf("\rLoading sources... %d of %d", si
+1, sofa
->hrtf
->M
);
1839 sofa
->hrtf
->SourcePosition
.values
[3*si
],
1840 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 1],
1841 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 2]
1845 if(std::fabs(aer
[1]) >= 89.999f
)
1848 aer
[0] = std::fmod(360.0f
- aer
[0], 360.0f
);
1850 auto field
= std::find_if(hData
->mFds
.cbegin(), hData
->mFds
.cend(),
1851 [&aer
](const HrirFdT
&fld
) -> bool
1852 { return (std::abs(aer
[2] - fld
.mDistance
) < 0.001); });
1853 if(field
== hData
->mFds
.cend())
1855 fi
= static_cast<uint
>(std::distance(hData
->mFds
.cbegin(), field
));
1857 const double evscale
{180.0 / static_cast<double>(field
->mEvs
.size()-1)};
1858 double ef
{(90.0 + aer
[1]) / evscale
};
1859 ei
= static_cast<uint
>(std::round(ef
));
1860 ef
= (ef
- ei
) * evscale
;
1861 if(std::abs(ef
) >= 0.1)
1864 const double azscale
{360.0 / static_cast<double>(field
->mEvs
[ei
].mAzs
.size())};
1865 double af
{aer
[0] / azscale
};
1866 ai
= static_cast<uint
>(std::round(af
));
1867 af
= (af
- ai
) * azscale
;
1868 ai
%= static_cast<uint
>(field
->mEvs
[ei
].mAzs
.size());
1869 if(std::abs(af
) >= 0.1)
1872 HrirAzT
*azd
= &field
->mEvs
[ei
].mAzs
[ai
];
1873 if(azd
->mIrs
[0] != nullptr)
1875 TrErrorAt(tr
, line
, col
, "Redefinition of source [ %d, %d, %d ].\n", fi
, ei
, ai
);
1879 ExtractSofaHrir(sofa
, si
, 0, src
.mOffset
, hData
->mIrPoints
, hrir
.get());
1880 azd
->mIrs
[0] = &hrirs
[hData
->mIrSize
* azd
->mIndex
];
1881 azd
->mDelays
[0] = AverageHrirOnset(onsetResampler
, onsetSamples
, hData
->mIrRate
,
1882 hData
->mIrPoints
, hrir
.get(), 1.0, azd
->mDelays
[0]);
1884 resampler
->process(hData
->mIrPoints
, hrir
.get(), hData
->mIrSize
, hrir
.get());
1885 AverageHrirMagnitude(irPoints
, hData
->mFftSize
, hrir
.get(), 1.0, azd
->mIrs
[0]);
1887 if(src
.mChannel
== 1)
1889 ExtractSofaHrir(sofa
, si
, 1, src
.mOffset
, hData
->mIrPoints
, hrir
.get());
1890 azd
->mIrs
[1] = &hrirs
[hData
->mIrSize
* (hData
->mIrCount
+ azd
->mIndex
)];
1891 azd
->mDelays
[1] = AverageHrirOnset(onsetResampler
, onsetSamples
,
1892 hData
->mIrRate
, hData
->mIrPoints
, hrir
.get(), 1.0, azd
->mDelays
[1]);
1894 resampler
->process(hData
->mIrPoints
, hrir
.get(), hData
->mIrSize
,
1896 AverageHrirMagnitude(irPoints
, hData
->mFftSize
, hrir
.get(), 1.0, azd
->mIrs
[1]);
1899 // TODO: Since some SOFA files contain minimum phase HRIRs,
1900 // it would be beneficial to check for per-measurement delays
1901 // (when available) to reconstruct the HRTDs.
1907 if(!ReadIndexTriplet(tr
, hData
, &fi
, &ei
, &ai
))
1909 if(!TrReadOperator(tr
, "]"))
1911 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1913 if(azd
->mIrs
[0] != nullptr)
1915 TrErrorAt(tr
, line
, col
, "Redefinition of source.\n");
1918 if(!TrReadOperator(tr
, "="))
1925 if(!ReadSourceRef(tr
, &src
))
1928 // TODO: Would be nice to display 'x of y files', but that would
1929 // require preparing the source refs first to get a total count
1930 // before loading them.
1932 printf("\rLoading sources... %d file%s", count
, (count
==1)?"":"s");
1935 if(!LoadSource(&src
, hData
->mIrRate
, hData
->mIrPoints
, hrir
.get()))
1939 if(hData
->mChannelType
== CT_STEREO
)
1941 char ident
[MAX_IDENT_LEN
+1];
1943 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1945 ti
= static_cast<uint
>(MatchTargetEar(ident
));
1946 if(static_cast<int>(ti
) < 0)
1948 TrErrorAt(tr
, line
, col
, "Expected a target ear.\n");
1952 azd
->mIrs
[ti
] = &hrirs
[hData
->mIrSize
* (ti
* hData
->mIrCount
+ azd
->mIndex
)];
1953 azd
->mDelays
[ti
] = AverageHrirOnset(onsetResampler
, onsetSamples
, hData
->mIrRate
,
1954 hData
->mIrPoints
, hrir
.get(), 1.0 / factor
[ti
], azd
->mDelays
[ti
]);
1956 resampler
->process(hData
->mIrPoints
, hrir
.get(), hData
->mIrSize
, hrir
.get());
1957 AverageHrirMagnitude(irPoints
, hData
->mFftSize
, hrir
.get(), 1.0 / factor
[ti
],
1960 if(!TrIsOperator(tr
, "+"))
1962 TrReadOperator(tr
, "+");
1964 if(hData
->mChannelType
== CT_STEREO
)
1966 if(azd
->mIrs
[0] == nullptr)
1968 TrErrorAt(tr
, line
, col
, "Missing left ear source reference(s).\n");
1971 else if(azd
->mIrs
[1] == nullptr)
1973 TrErrorAt(tr
, line
, col
, "Missing right ear source reference(s).\n");
1982 hData
->mIrRate
= outRate
;
1983 hData
->mIrPoints
= irPoints
;
1986 for(fi
= 0;fi
< hData
->mFds
.size();fi
++)
1988 for(ei
= 0;ei
< hData
->mFds
[fi
].mEvs
.size();ei
++)
1990 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzs
.size();ai
++)
1992 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1993 if(azd
->mIrs
[0] != nullptr)
1996 if(ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzs
.size())
1999 if(ei
>= hData
->mFds
[fi
].mEvs
.size())
2001 TrError(tr
, "Missing source references [ %d, *, * ].\n", fi
);
2004 hData
->mFds
[fi
].mEvStart
= ei
;
2005 for(;ei
< hData
->mFds
[fi
].mEvs
.size();ei
++)
2007 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzs
.size();ai
++)
2009 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
2011 if(azd
->mIrs
[0] == nullptr)
2013 TrError(tr
, "Missing source reference [ %d, %d, %d ].\n", fi
, ei
, ai
);
2019 for(uint ti
{0};ti
< channels
;ti
++)
2021 for(fi
= 0;fi
< hData
->mFds
.size();fi
++)
2023 for(ei
= 0;ei
< hData
->mFds
[fi
].mEvs
.size();ei
++)
2025 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzs
.size();ai
++)
2027 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
2029 azd
->mIrs
[ti
] = &hrirs
[hData
->mIrSize
* (ti
* hData
->mIrCount
+ azd
->mIndex
)];
2036 mysofa_cache_release_all();
2040 TrError(tr
, "Errant data at end of source list.\n");
2041 mysofa_cache_release_all();
2046 bool LoadDefInput(std::istream
&istream
, const char *startbytes
, std::streamsize startbytecount
,
2047 const char *filename
, const uint fftSize
, const uint truncSize
, const uint outRate
,
2048 const ChannelModeT chanMode
, HrirDataT
*hData
)
2050 TokenReaderT tr
{istream
};
2052 TrSetup(startbytes
, startbytecount
, filename
, &tr
);
2053 if(!ProcessMetrics(&tr
, fftSize
, truncSize
, chanMode
, hData
)
2054 || !ProcessSources(&tr
, hData
, outRate
))