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 std::vector
<uint
> azCounts(MAX_FD_COUNT
* MAX_EV_COUNT
);
1244 TrIndication(tr
, &line
, &col
);
1245 while(TrIsIdent(tr
))
1247 TrIndication(tr
, &line
, &col
);
1248 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1250 if(al::strcasecmp(ident
, "rate") == 0)
1254 TrErrorAt(tr
, line
, col
, "Redefinition of 'rate'.\n");
1257 if(!TrReadOperator(tr
, "="))
1259 if(!TrReadInt(tr
, MIN_RATE
, MAX_RATE
, &intVal
))
1261 hData
->mIrRate
= static_cast<uint
>(intVal
);
1264 else if(al::strcasecmp(ident
, "type") == 0)
1266 char type
[MAX_IDENT_LEN
+1];
1270 TrErrorAt(tr
, line
, col
, "Redefinition of 'type'.\n");
1273 if(!TrReadOperator(tr
, "="))
1276 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1278 hData
->mChannelType
= MatchChannelType(type
);
1279 if(hData
->mChannelType
== CT_NONE
)
1281 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1284 else if(hData
->mChannelType
== CT_STEREO
)
1286 if(chanMode
== CM_ForceMono
)
1287 hData
->mChannelType
= CT_MONO
;
1291 else if(al::strcasecmp(ident
, "points") == 0)
1295 TrErrorAt(tr
, line
, col
, "Redefinition of 'points'.\n");
1298 if(!TrReadOperator(tr
, "="))
1300 TrIndication(tr
, &line
, &col
);
1301 if(!TrReadInt(tr
, MIN_POINTS
, MAX_POINTS
, &intVal
))
1303 points
= static_cast<uint
>(intVal
);
1304 if(fftSize
> 0 && points
> fftSize
)
1306 TrErrorAt(tr
, line
, col
, "Value exceeds the overridden FFT size.\n");
1309 if(points
< truncSize
)
1311 TrErrorAt(tr
, line
, col
, "Value is below the truncation size.\n");
1314 hData
->mIrPoints
= points
;
1315 hData
->mFftSize
= fftSize
;
1316 hData
->mIrSize
= 1 + (fftSize
/ 2);
1317 if(points
> hData
->mIrSize
)
1318 hData
->mIrSize
= points
;
1321 else if(al::strcasecmp(ident
, "radius") == 0)
1325 TrErrorAt(tr
, line
, col
, "Redefinition of 'radius'.\n");
1328 if(!TrReadOperator(tr
, "="))
1330 if(!TrReadFloat(tr
, MIN_RADIUS
, MAX_RADIUS
, &fpVal
))
1332 hData
->mRadius
= fpVal
;
1335 else if(al::strcasecmp(ident
, "distance") == 0)
1341 TrErrorAt(tr
, line
, col
, "Redefinition of 'distance'.\n");
1344 if(!TrReadOperator(tr
, "="))
1349 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1351 if(count
> 0 && fpVal
<= distances
[count
- 1])
1353 TrError(tr
, "Distances are not ascending.\n");
1356 distances
[count
++] = fpVal
;
1357 if(!TrIsOperator(tr
, ","))
1359 if(count
>= MAX_FD_COUNT
)
1361 TrError(tr
, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT
);
1364 TrReadOperator(tr
, ",");
1366 if(fdCount
!= 0 && count
!= fdCount
)
1368 TrError(tr
, "Did not match the specified number of %d fields.\n", fdCount
);
1374 else if(al::strcasecmp(ident
, "azimuths") == 0)
1380 TrErrorAt(tr
, line
, col
, "Redefinition of 'azimuths'.\n");
1383 if(!TrReadOperator(tr
, "="))
1389 if(!TrReadInt(tr
, MIN_AZ_COUNT
, MAX_AZ_COUNT
, &intVal
))
1391 azCounts
[(count
* MAX_EV_COUNT
) + evCounts
[count
]++] = static_cast<uint
>(intVal
);
1392 if(TrIsOperator(tr
, ","))
1394 if(evCounts
[count
] >= MAX_EV_COUNT
)
1396 TrError(tr
, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT
);
1399 TrReadOperator(tr
, ",");
1403 if(evCounts
[count
] < MIN_EV_COUNT
)
1405 TrErrorAt(tr
, line
, col
, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT
);
1408 if(azCounts
[count
* MAX_EV_COUNT
] != 1 || azCounts
[(count
* MAX_EV_COUNT
) + evCounts
[count
] - 1] != 1)
1410 TrError(tr
, "Poles are not singular for field %d.\n", count
- 1);
1414 if(!TrIsOperator(tr
, ";"))
1417 if(count
>= MAX_FD_COUNT
)
1419 TrError(tr
, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT
);
1422 evCounts
[count
] = 0;
1423 TrReadOperator(tr
, ";");
1426 if(fdCount
!= 0 && count
!= fdCount
)
1428 TrError(tr
, "Did not match the specified number of %d fields.\n", fdCount
);
1436 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1439 TrSkipWhitespace(tr
);
1441 if(!(hasRate
&& hasPoints
&& hasRadius
&& hasDistance
&& hasAzimuths
))
1443 TrErrorAt(tr
, line
, col
, "Expected a metric name.\n");
1446 if(distances
[0] < hData
->mRadius
)
1448 TrError(tr
, "Distance cannot start below head radius.\n");
1451 if(hData
->mChannelType
== CT_NONE
)
1452 hData
->mChannelType
= CT_MONO
;
1453 if(!PrepareHrirData(fdCount
, distances
, evCounts
, azCounts
.data(), hData
))
1455 fprintf(stderr
, "Error: Out of memory.\n");
1461 // Parse an index triplet from the data set definition.
1462 static int ReadIndexTriplet(TokenReaderT
*tr
, const HrirDataT
*hData
, uint
*fi
, uint
*ei
, uint
*ai
)
1466 if(hData
->mFdCount
> 1)
1468 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFdCount
) - 1, &intVal
))
1470 *fi
= static_cast<uint
>(intVal
);
1471 if(!TrReadOperator(tr
, ","))
1478 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvCount
) - 1, &intVal
))
1480 *ei
= static_cast<uint
>(intVal
);
1481 if(!TrReadOperator(tr
, ","))
1483 if(!TrReadInt(tr
, 0, static_cast<int>(hData
->mFds
[*fi
].mEvs
[*ei
].mAzCount
) - 1, &intVal
))
1485 *ai
= static_cast<uint
>(intVal
);
1489 // Match the source format from a given identifier.
1490 static SourceFormatT
MatchSourceFormat(const char *ident
)
1492 if(al::strcasecmp(ident
, "ascii") == 0)
1494 if(al::strcasecmp(ident
, "bin_le") == 0)
1496 if(al::strcasecmp(ident
, "bin_be") == 0)
1498 if(al::strcasecmp(ident
, "wave") == 0)
1500 if(al::strcasecmp(ident
, "sofa") == 0)
1505 // Match the source element type from a given identifier.
1506 static ElementTypeT
MatchElementType(const char *ident
)
1508 if(al::strcasecmp(ident
, "int") == 0)
1510 if(al::strcasecmp(ident
, "fp") == 0)
1515 // Parse and validate a source reference from the data set definition.
1516 static int ReadSourceRef(TokenReaderT
*tr
, SourceRefT
*src
)
1518 char ident
[MAX_IDENT_LEN
+1];
1523 TrIndication(tr
, &line
, &col
);
1524 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1526 src
->mFormat
= MatchSourceFormat(ident
);
1527 if(src
->mFormat
== SF_NONE
)
1529 TrErrorAt(tr
, line
, col
, "Expected a source format.\n");
1532 if(!TrReadOperator(tr
, "("))
1534 if(src
->mFormat
== SF_SOFA
)
1536 if(!TrReadFloat(tr
, MIN_DISTANCE
, MAX_DISTANCE
, &fpVal
))
1538 src
->mRadius
= fpVal
;
1539 if(!TrReadOperator(tr
, ","))
1541 if(!TrReadFloat(tr
, -90.0, 90.0, &fpVal
))
1543 src
->mElevation
= fpVal
;
1544 if(!TrReadOperator(tr
, ","))
1546 if(!TrReadFloat(tr
, -360.0, 360.0, &fpVal
))
1548 src
->mAzimuth
= fpVal
;
1549 if(!TrReadOperator(tr
, ":"))
1551 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1553 src
->mType
= ET_NONE
;
1556 src
->mChannel
= static_cast<uint
>(intVal
);
1559 else if(src
->mFormat
== SF_WAVE
)
1561 if(!TrReadInt(tr
, 0, MAX_WAVE_CHANNELS
, &intVal
))
1563 src
->mType
= ET_NONE
;
1566 src
->mChannel
= static_cast<uint
>(intVal
);
1571 TrIndication(tr
, &line
, &col
);
1572 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1574 src
->mType
= MatchElementType(ident
);
1575 if(src
->mType
== ET_NONE
)
1577 TrErrorAt(tr
, line
, col
, "Expected a source element type.\n");
1580 if(src
->mFormat
== SF_BIN_LE
|| src
->mFormat
== SF_BIN_BE
)
1582 if(!TrReadOperator(tr
, ","))
1584 if(src
->mType
== ET_INT
)
1586 if(!TrReadInt(tr
, MIN_BIN_SIZE
, MAX_BIN_SIZE
, &intVal
))
1588 src
->mSize
= static_cast<uint
>(intVal
);
1589 if(!TrIsOperator(tr
, ","))
1590 src
->mBits
= static_cast<int>(8*src
->mSize
);
1593 TrReadOperator(tr
, ",");
1594 TrIndication(tr
, &line
, &col
);
1595 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
1597 if(std::abs(intVal
) < MIN_BIN_BITS
|| static_cast<uint
>(std::abs(intVal
)) > (8*src
->mSize
))
1599 TrErrorAt(tr
, line
, col
, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS
, 8*src
->mSize
);
1602 src
->mBits
= intVal
;
1607 TrIndication(tr
, &line
, &col
);
1608 if(!TrReadInt(tr
, -2147483647-1, 2147483647, &intVal
))
1610 if(intVal
!= 4 && intVal
!= 8)
1612 TrErrorAt(tr
, line
, col
, "Expected a value of 4 or 8.\n");
1615 src
->mSize
= static_cast<uint
>(intVal
);
1619 else if(src
->mFormat
== SF_ASCII
&& src
->mType
== ET_INT
)
1621 if(!TrReadOperator(tr
, ","))
1623 if(!TrReadInt(tr
, MIN_ASCII_BITS
, MAX_ASCII_BITS
, &intVal
))
1626 src
->mBits
= intVal
;
1634 if(!TrIsOperator(tr
, ";"))
1638 TrReadOperator(tr
, ";");
1639 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1641 src
->mSkip
= static_cast<uint
>(intVal
);
1644 if(!TrReadOperator(tr
, ")"))
1646 if(TrIsOperator(tr
, "@"))
1648 TrReadOperator(tr
, "@");
1649 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1651 src
->mOffset
= static_cast<uint
>(intVal
);
1655 if(!TrReadOperator(tr
, ":"))
1657 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
1662 // Parse and validate a SOFA source reference from the data set definition.
1663 static int ReadSofaRef(TokenReaderT
*tr
, SourceRefT
*src
)
1665 char ident
[MAX_IDENT_LEN
+1];
1669 TrIndication(tr
, &line
, &col
);
1670 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1672 src
->mFormat
= MatchSourceFormat(ident
);
1673 if(src
->mFormat
!= SF_SOFA
)
1675 TrErrorAt(tr
, line
, col
, "Expected the SOFA source format.\n");
1679 src
->mType
= ET_NONE
;
1685 if(TrIsOperator(tr
, "@"))
1687 TrReadOperator(tr
, "@");
1688 if(!TrReadInt(tr
, 0, 0x7FFFFFFF, &intVal
))
1690 src
->mOffset
= static_cast<uint
>(intVal
);
1694 if(!TrReadOperator(tr
, ":"))
1696 if(!TrReadString(tr
, MAX_PATH_LEN
, src
->mPath
))
1701 // Match the target ear (index) from a given identifier.
1702 static int MatchTargetEar(const char *ident
)
1704 if(al::strcasecmp(ident
, "left") == 0)
1706 if(al::strcasecmp(ident
, "right") == 0)
1711 // Calculate the onset time of an HRIR and average it with any existing
1712 // timing for its field, elevation, azimuth, and ear.
1713 static constexpr int OnsetRateMultiple
{10};
1714 static double AverageHrirOnset(PPhaseResampler
&rs
, al::span
<double> upsampled
, const uint rate
,
1715 const uint n
, const double *hrir
, const double f
, const double onset
)
1717 rs
.process(n
, hrir
, static_cast<uint
>(upsampled
.size()), 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
++)
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
, const uint outRate
)
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 auto hrir
= std::make_unique
<double[]>(hData
->mIrSize
);
1750 uint line
, col
, fi
, ei
, ai
;
1753 std::vector
<double> onsetSamples(OnsetRateMultiple
* hData
->mIrPoints
);
1754 PPhaseResampler onsetResampler
;
1755 onsetResampler
.init(hData
->mIrRate
, OnsetRateMultiple
*hData
->mIrRate
);
1757 al::optional
<PPhaseResampler
> resampler
;
1758 if(outRate
&& outRate
!= hData
->mIrRate
)
1759 resampler
.emplace().init(hData
->mIrRate
, outRate
);
1760 const double rateScale
{outRate
? static_cast<double>(outRate
) / hData
->mIrRate
: 1.0};
1761 const uint irPoints
{outRate
1762 ? std::min(static_cast<uint
>(std::ceil(hData
->mIrPoints
*rateScale
)), hData
->mIrPoints
)
1763 : hData
->mIrPoints
};
1765 printf("Loading sources...");
1768 while(TrIsOperator(tr
, "["))
1770 double factor
[2]{ 1.0, 1.0 };
1772 TrIndication(tr
, &line
, &col
);
1773 TrReadOperator(tr
, "[");
1775 if(TrIsOperator(tr
, "*"))
1778 struct MYSOFA_EASY
*sofa
;
1781 TrReadOperator(tr
, "*");
1782 if(!TrReadOperator(tr
, "]") || !TrReadOperator(tr
, "="))
1785 TrIndication(tr
, &line
, &col
);
1786 if(!ReadSofaRef(tr
, &src
))
1789 if(hData
->mChannelType
== CT_STEREO
)
1791 char type
[MAX_IDENT_LEN
+1];
1792 ChannelTypeT channelType
;
1794 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1797 channelType
= MatchChannelType(type
);
1802 TrErrorAt(tr
, line
, col
, "Expected a channel type.\n");
1814 char type
[MAX_IDENT_LEN
+1];
1815 ChannelTypeT channelType
;
1817 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, type
))
1820 channelType
= MatchChannelType(type
);
1821 if(channelType
!= CT_MONO
)
1823 TrErrorAt(tr
, line
, col
, "Expected a mono channel type.\n");
1829 sofa
= LoadSofaFile(&src
, hData
->mIrRate
, hData
->mIrPoints
);
1832 for(si
= 0;si
< sofa
->hrtf
->M
;si
++)
1834 printf("\rLoading sources... %d of %d", si
+1, sofa
->hrtf
->M
);
1838 sofa
->hrtf
->SourcePosition
.values
[3*si
],
1839 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 1],
1840 sofa
->hrtf
->SourcePosition
.values
[3*si
+ 2]
1844 if(std::fabs(aer
[1]) >= 89.999f
)
1847 aer
[0] = std::fmod(360.0f
- aer
[0], 360.0f
);
1849 for(fi
= 0;fi
< hData
->mFdCount
;fi
++)
1851 double delta
= aer
[2] - hData
->mFds
[fi
].mDistance
;
1852 if(std::abs(delta
) < 0.001) break;
1854 if(fi
>= hData
->mFdCount
)
1857 double ef
{(90.0 + aer
[1]) / 180.0 * (hData
->mFds
[fi
].mEvCount
- 1)};
1858 ei
= static_cast<uint
>(std::round(ef
));
1859 ef
= (ef
- ei
) * 180.0 / (hData
->mFds
[fi
].mEvCount
- 1);
1860 if(std::abs(ef
) >= 0.1)
1863 double af
{aer
[0] / 360.0 * hData
->mFds
[fi
].mEvs
[ei
].mAzCount
};
1864 ai
= static_cast<uint
>(std::round(af
));
1865 af
= (af
- ai
) * 360.0 / hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;
1866 ai
= ai
% hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;
1867 if(std::abs(af
) >= 0.1)
1870 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1871 if(azd
->mIrs
[0] != nullptr)
1873 TrErrorAt(tr
, line
, col
, "Redefinition of source [ %d, %d, %d ].\n", fi
, ei
, ai
);
1877 ExtractSofaHrir(sofa
, si
, 0, src
.mOffset
, hData
->mIrPoints
, hrir
.get());
1878 azd
->mIrs
[0] = &hrirs
[hData
->mIrSize
* azd
->mIndex
];
1879 azd
->mDelays
[0] = AverageHrirOnset(onsetResampler
, onsetSamples
, hData
->mIrRate
,
1880 hData
->mIrPoints
, hrir
.get(), 1.0, azd
->mDelays
[0]);
1882 resampler
->process(hData
->mIrPoints
, hrir
.get(), hData
->mIrSize
, hrir
.get());
1883 AverageHrirMagnitude(irPoints
, hData
->mFftSize
, hrir
.get(), 1.0, azd
->mIrs
[0]);
1885 if(src
.mChannel
== 1)
1887 ExtractSofaHrir(sofa
, si
, 1, src
.mOffset
, hData
->mIrPoints
, hrir
.get());
1888 azd
->mIrs
[1] = &hrirs
[hData
->mIrSize
* (hData
->mIrCount
+ azd
->mIndex
)];
1889 azd
->mDelays
[1] = AverageHrirOnset(onsetResampler
, onsetSamples
,
1890 hData
->mIrRate
, hData
->mIrPoints
, hrir
.get(), 1.0, azd
->mDelays
[1]);
1892 resampler
->process(hData
->mIrPoints
, hrir
.get(), hData
->mIrSize
,
1894 AverageHrirMagnitude(irPoints
, hData
->mFftSize
, hrir
.get(), 1.0, azd
->mIrs
[1]);
1897 // TODO: Since some SOFA files contain minimum phase HRIRs,
1898 // it would be beneficial to check for per-measurement delays
1899 // (when available) to reconstruct the HRTDs.
1905 if(!ReadIndexTriplet(tr
, hData
, &fi
, &ei
, &ai
))
1907 if(!TrReadOperator(tr
, "]"))
1909 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1911 if(azd
->mIrs
[0] != nullptr)
1913 TrErrorAt(tr
, line
, col
, "Redefinition of source.\n");
1916 if(!TrReadOperator(tr
, "="))
1923 if(!ReadSourceRef(tr
, &src
))
1926 // TODO: Would be nice to display 'x of y files', but that would
1927 // require preparing the source refs first to get a total count
1928 // before loading them.
1930 printf("\rLoading sources... %d file%s", count
, (count
==1)?"":"s");
1933 if(!LoadSource(&src
, hData
->mIrRate
, hData
->mIrPoints
, hrir
.get()))
1937 if(hData
->mChannelType
== CT_STEREO
)
1939 char ident
[MAX_IDENT_LEN
+1];
1941 if(!TrReadIdent(tr
, MAX_IDENT_LEN
, ident
))
1943 ti
= static_cast<uint
>(MatchTargetEar(ident
));
1944 if(static_cast<int>(ti
) < 0)
1946 TrErrorAt(tr
, line
, col
, "Expected a target ear.\n");
1950 azd
->mIrs
[ti
] = &hrirs
[hData
->mIrSize
* (ti
* hData
->mIrCount
+ azd
->mIndex
)];
1951 azd
->mDelays
[ti
] = AverageHrirOnset(onsetResampler
, onsetSamples
, hData
->mIrRate
,
1952 hData
->mIrPoints
, hrir
.get(), 1.0 / factor
[ti
], azd
->mDelays
[ti
]);
1954 resampler
->process(hData
->mIrPoints
, hrir
.get(), hData
->mIrSize
, hrir
.get());
1955 AverageHrirMagnitude(irPoints
, hData
->mFftSize
, hrir
.get(), 1.0 / factor
[ti
],
1958 if(!TrIsOperator(tr
, "+"))
1960 TrReadOperator(tr
, "+");
1962 if(hData
->mChannelType
== CT_STEREO
)
1964 if(azd
->mIrs
[0] == nullptr)
1966 TrErrorAt(tr
, line
, col
, "Missing left ear source reference(s).\n");
1969 else if(azd
->mIrs
[1] == nullptr)
1971 TrErrorAt(tr
, line
, col
, "Missing right ear source reference(s).\n");
1980 hData
->mIrRate
= outRate
;
1981 hData
->mIrPoints
= irPoints
;
1984 for(fi
= 0;fi
< hData
->mFdCount
;fi
++)
1986 for(ei
= 0;ei
< hData
->mFds
[fi
].mEvCount
;ei
++)
1988 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;ai
++)
1990 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
1991 if(azd
->mIrs
[0] != nullptr)
1994 if(ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
)
1997 if(ei
>= hData
->mFds
[fi
].mEvCount
)
1999 TrError(tr
, "Missing source references [ %d, *, * ].\n", fi
);
2002 hData
->mFds
[fi
].mEvStart
= ei
;
2003 for(;ei
< hData
->mFds
[fi
].mEvCount
;ei
++)
2005 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;ai
++)
2007 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
2009 if(azd
->mIrs
[0] == nullptr)
2011 TrError(tr
, "Missing source reference [ %d, %d, %d ].\n", fi
, ei
, ai
);
2017 for(uint ti
{0};ti
< channels
;ti
++)
2019 for(fi
= 0;fi
< hData
->mFdCount
;fi
++)
2021 for(ei
= 0;ei
< hData
->mFds
[fi
].mEvCount
;ei
++)
2023 for(ai
= 0;ai
< hData
->mFds
[fi
].mEvs
[ei
].mAzCount
;ai
++)
2025 HrirAzT
*azd
= &hData
->mFds
[fi
].mEvs
[ei
].mAzs
[ai
];
2027 azd
->mIrs
[ti
] = &hrirs
[hData
->mIrSize
* (ti
* hData
->mIrCount
+ azd
->mIndex
)];
2034 mysofa_cache_release_all();
2038 TrError(tr
, "Errant data at end of source list.\n");
2039 mysofa_cache_release_all();
2044 bool LoadDefInput(std::istream
&istream
, const char *startbytes
, std::streamsize startbytecount
,
2045 const char *filename
, const uint fftSize
, const uint truncSize
, const uint outRate
,
2046 const ChannelModeT chanMode
, HrirDataT
*hData
)
2048 TokenReaderT tr
{istream
};
2050 TrSetup(startbytes
, startbytecount
, filename
, &tr
);
2051 if(!ProcessMetrics(&tr
, fftSize
, truncSize
, chanMode
, hData
)
2052 || !ProcessSources(&tr
, hData
, outRate
))