13 #include "alfstream.h"
19 template<typename T
, std::size_t N
>
20 constexpr inline std::size_t size(const T(&)[N
]) noexcept
23 int readline(std::istream
&f
, std::string
&output
)
25 while(f
.good() && f
.peek() == '\n')
28 return std::getline(f
, output
) && !output
.empty();
31 bool read_clipped_line(std::istream
&f
, std::string
&buffer
)
33 while(readline(f
, buffer
))
36 while(pos
< buffer
.length() && std::isspace(buffer
[pos
]))
40 std::size_t cmtpos
{buffer
.find_first_of('#')};
41 if(cmtpos
< buffer
.length())
42 buffer
.resize(cmtpos
);
43 while(!buffer
.empty() && std::isspace(buffer
.back()))
53 std::string
read_word(std::istream
&f
)
60 bool is_at_end(const std::string
&buffer
, std::size_t endpos
)
62 while(endpos
< buffer
.length() && std::isspace(buffer
[endpos
]))
64 return !(endpos
< buffer
.length());
68 bool load_ambdec_speakers(al::vector
<AmbDecConf::SpeakerConf
> &spkrs
, const std::size_t num_speakers
, std::istream
&f
, std::string
&buffer
)
70 while(spkrs
.size() < num_speakers
)
72 std::istringstream istr
{buffer
};
74 std::string cmd
{read_word(istr
)};
77 if(!read_clipped_line(f
, buffer
))
79 ERR("Unexpected end of file\n");
88 AmbDecConf::SpeakerConf
&spkr
= spkrs
.back();
89 const size_t spkr_num
{spkrs
.size()};
92 if(istr
.fail()) WARN("Name not specified for speaker %zu\n", spkr_num
);
93 istr
>> spkr
.Distance
;
94 if(istr
.fail()) WARN("Distance not specified for speaker %zu\n", spkr_num
);
96 if(istr
.fail()) WARN("Azimuth not specified for speaker %zu\n", spkr_num
);
97 istr
>> spkr
.Elevation
;
98 if(istr
.fail()) WARN("Elevation not specified for speaker %zu\n", spkr_num
);
99 istr
>> spkr
.Connection
;
100 if(istr
.fail()) TRACE("Connection not specified for speaker %zu\n", spkr_num
);
104 ERR("Unexpected speakers command: %s\n", cmd
.c_str());
109 const auto endpos
= static_cast<std::size_t>(istr
.tellg());
110 if(!is_at_end(buffer
, endpos
))
112 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
121 bool load_ambdec_matrix(float (&gains
)[MAX_AMBI_ORDER
+1], al::vector
<AmbDecConf::CoeffArray
> &matrix
, const std::size_t maxrow
, std::istream
&f
, std::string
&buffer
)
123 bool gotgains
{false};
127 std::istringstream istr
{buffer
};
129 std::string cmd
{read_word(istr
)};
132 if(!read_clipped_line(f
, buffer
))
134 ERR("Unexpected end of file\n");
140 if(cmd
== "order_gain")
142 std::size_t curgain
{0u};
147 if(istr
.fail()) break;
148 if(!istr
.eof() && !std::isspace(istr
.peek()))
150 ERR("Extra junk on gain %zu: %s\n", curgain
+1,
151 buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
154 if(curgain
< size(gains
))
155 gains
[curgain
++] = value
;
157 std::fill(std::begin(gains
)+curgain
, std::end(gains
), 0.0f
);
160 else if(cmd
== "add_row")
162 matrix
.emplace_back();
163 AmbDecConf::CoeffArray
&mtxrow
= matrix
.back();
164 std::size_t curidx
{0u};
169 if(istr
.fail()) break;
170 if(!istr
.eof() && !std::isspace(istr
.peek()))
172 ERR("Extra junk on matrix element %zux%zu: %s\n", curidx
,
173 matrix
.size(), buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
177 if(curidx
< mtxrow
.size())
178 mtxrow
[curidx
++] = value
;
180 std::fill(mtxrow
.begin()+curidx
, mtxrow
.end(), 0.0f
);
185 ERR("Unexpected matrix command: %s\n", cmd
.c_str());
190 const auto endpos
= static_cast<std::size_t>(istr
.tellg());
191 if(!is_at_end(buffer
, endpos
))
193 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
201 ERR("Matrix order_gain not specified\n");
210 int AmbDecConf::load(const char *fname
) noexcept
212 al::ifstream f
{fname
};
215 ERR("Failed to open: %s\n", fname
);
219 std::size_t num_speakers
{0u};
221 while(read_clipped_line(f
, buffer
))
223 std::istringstream istr
{buffer
};
225 std::string command
{read_word(istr
)};
228 ERR("Malformed line: %s\n", buffer
.c_str());
232 if(command
== "/description")
234 else if(command
== "/version")
237 if(!istr
.eof() && !std::isspace(istr
.peek()))
239 ERR("Extra junk after version: %s\n",
240 buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
245 ERR("Unsupported version: %u\n", Version
);
249 else if(command
== "/dec/chan_mask")
251 istr
>> std::hex
>> ChanMask
>> std::dec
;
252 if(!istr
.eof() && !std::isspace(istr
.peek()))
254 ERR("Extra junk after mask: %s\n",
255 buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
259 else if(command
== "/dec/freq_bands")
262 if(!istr
.eof() && !std::isspace(istr
.peek()))
264 ERR("Extra junk after freq_bands: %s\n",
265 buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
268 if(FreqBands
!= 1 && FreqBands
!= 2)
270 ERR("Invalid freq_bands value: %u\n", FreqBands
);
274 else if(command
== "/dec/speakers")
276 istr
>> num_speakers
;
277 if(!istr
.eof() && !std::isspace(istr
.peek()))
279 ERR("Extra junk after speakers: %s\n",
280 buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
283 Speakers
.reserve(num_speakers
);
284 LFMatrix
.reserve(num_speakers
);
285 HFMatrix
.reserve(num_speakers
);
287 else if(command
== "/dec/coeff_scale")
289 std::string scale
= read_word(istr
);
290 if(scale
== "n3d") CoeffScale
= AmbDecScale::N3D
;
291 else if(scale
== "sn3d") CoeffScale
= AmbDecScale::SN3D
;
292 else if(scale
== "fuma") CoeffScale
= AmbDecScale::FuMa
;
295 ERR("Unsupported coeff scale: %s\n", scale
.c_str());
299 else if(command
== "/opt/xover_freq")
302 if(!istr
.eof() && !std::isspace(istr
.peek()))
304 ERR("Extra junk after xover_freq: %s\n",
305 buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
309 else if(command
== "/opt/xover_ratio")
312 if(!istr
.eof() && !std::isspace(istr
.peek()))
314 ERR("Extra junk after xover_ratio: %s\n",
315 buffer
.c_str()+static_cast<std::size_t>(istr
.tellg()));
319 else if(command
== "/opt/input_scale" || command
== "/opt/nfeff_comp" ||
320 command
== "/opt/delay_comp" || command
== "/opt/level_comp")
325 else if(command
== "/speakers/{")
327 const auto endpos
= static_cast<std::size_t>(istr
.tellg());
328 if(!is_at_end(buffer
, endpos
))
330 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
335 if(!load_ambdec_speakers(Speakers
, num_speakers
, f
, buffer
))
338 if(!read_clipped_line(f
, buffer
))
340 ERR("Unexpected end of file\n");
343 std::istringstream istr2
{buffer
};
344 std::string endmark
{read_word(istr2
)};
347 ERR("Expected /} after speaker definitions, got %s\n", endmark
.c_str());
352 else if(command
== "/lfmatrix/{" || command
== "/hfmatrix/{" || command
== "/matrix/{")
354 const auto endpos
= static_cast<std::size_t>(istr
.tellg());
355 if(!is_at_end(buffer
, endpos
))
357 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
364 if(command
!= "/matrix/{")
366 ERR("Unexpected \"%s\" type for a single-band decoder\n", command
.c_str());
369 if(!load_ambdec_matrix(HFOrderGain
, HFMatrix
, num_speakers
, f
, buffer
))
374 if(command
== "/lfmatrix/{")
376 if(!load_ambdec_matrix(LFOrderGain
, LFMatrix
, num_speakers
, f
, buffer
))
379 else if(command
== "/hfmatrix/{")
381 if(!load_ambdec_matrix(HFOrderGain
, HFMatrix
, num_speakers
, f
, buffer
))
386 ERR("Unexpected \"%s\" type for a dual-band decoder\n", command
.c_str());
391 if(!read_clipped_line(f
, buffer
))
393 ERR("Unexpected end of file\n");
396 std::istringstream istr2
{buffer
};
397 std::string endmark
{read_word(istr2
)};
400 ERR("Expected /} after matrix definitions, got %s\n", endmark
.c_str());
405 else if(command
== "/end")
407 const auto endpos
= static_cast<std::size_t>(istr
.tellg());
408 if(!is_at_end(buffer
, endpos
))
410 ERR("Unexpected junk on end: %s\n", buffer
.c_str()+endpos
);
418 ERR("Unexpected command: %s\n", command
.c_str());
423 const auto endpos
= static_cast<std::size_t>(istr
.tellg());
424 if(!is_at_end(buffer
, endpos
))
426 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
431 ERR("Unexpected end of file\n");