19 int readline(std::istream
&f
, std::string
&output
)
21 while(f
.good() && f
.peek() == '\n')
24 return std::getline(f
, output
) && !output
.empty();
27 bool read_clipped_line(std::istream
&f
, std::string
&buffer
)
29 while(readline(f
, buffer
))
32 while(pos
< buffer
.length() && std::isspace(buffer
[pos
]))
36 std::size_t cmtpos
{buffer
.find_first_of('#')};
37 if(cmtpos
< buffer
.length())
38 buffer
.resize(cmtpos
);
39 while(!buffer
.empty() && std::isspace(buffer
.back()))
49 std::string
read_word(std::istream
&f
)
56 bool is_at_end(const std::string
&buffer
, std::size_t endpos
)
58 while(endpos
< buffer
.length() && std::isspace(buffer
[endpos
]))
60 if(endpos
< buffer
.length())
66 bool load_ambdec_speakers(AmbDecConf
*conf
, std::istream
&f
, std::string
&buffer
)
69 while(cur
< conf
->NumSpeakers
)
71 std::istringstream istr
{buffer
};
73 std::string cmd
{read_word(istr
)};
76 if(!read_clipped_line(f
, buffer
))
78 ERR("Unexpected end of file\n");
86 istr
>> conf
->Speakers
[cur
].Name
;
87 if(istr
.fail()) WARN("Name not specified for speaker %u\n", cur
+1);
88 istr
>> conf
->Speakers
[cur
].Distance
;
89 if(istr
.fail()) WARN("Distance not specified for speaker %u\n", cur
+1);
90 istr
>> conf
->Speakers
[cur
].Azimuth
;
91 if(istr
.fail()) WARN("Azimuth not specified for speaker %u\n", cur
+1);
92 istr
>> conf
->Speakers
[cur
].Elevation
;
93 if(istr
.fail()) WARN("Elevation not specified for speaker %u\n", cur
+1);
94 istr
>> conf
->Speakers
[cur
].Connection
;
95 if(istr
.fail()) TRACE("Connection not specified for speaker %u\n", cur
+1);
101 ERR("Unexpected speakers command: %s\n", cmd
.c_str());
106 std::istream::pos_type endpos
{istr
.tellg()};
107 if(!is_at_end(buffer
, endpos
))
109 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
118 bool load_ambdec_matrix(ALfloat
*gains
, ALfloat (*matrix
)[MAX_AMBI_COEFFS
], ALsizei maxrow
, std::istream
&f
, std::string
&buffer
)
120 bool gotgains
= false;
124 std::istringstream istr
{buffer
};
126 std::string cmd
{read_word(istr
)};
129 if(!read_clipped_line(f
, buffer
))
131 ERR("Unexpected end of file\n");
137 if(cmd
== "order_gain")
144 if(istr
.fail()) break;
145 if(!istr
.eof() && !std::isspace(istr
.peek()))
147 ERR("Extra junk on gain %u: %s\n", curgain
+1, buffer
.c_str()+istr
.tellg());
150 if(curgain
< MAX_AMBI_ORDER
+1)
151 gains
[curgain
++] = value
;
153 while(curgain
< MAX_AMBI_ORDER
+1)
154 gains
[curgain
++] = 0.0f
;
157 else if(cmd
== "add_row")
164 if(istr
.fail()) break;
165 if(!istr
.eof() && !std::isspace(istr
.peek()))
167 ERR("Extra junk on matrix element %ux%u: %s\n", cur
, curidx
,
168 buffer
.c_str()+istr
.tellg());
171 if(curidx
< MAX_AMBI_COEFFS
)
172 matrix
[cur
][curidx
++] = value
;
174 while(curidx
< MAX_AMBI_COEFFS
)
175 matrix
[cur
][curidx
++] = 0.0f
;
180 ERR("Unexpected matrix command: %s\n", cmd
.c_str());
185 std::istream::pos_type endpos
{istr
.tellg()};
186 if(!is_at_end(buffer
, endpos
))
188 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
196 ERR("Matrix order_gain not specified\n");
205 int AmbDecConf::load(const char *fname
) noexcept
207 al::ifstream f
{fname
};
210 ERR("Failed to open: %s\n", fname
);
215 while(read_clipped_line(f
, buffer
))
217 std::istringstream istr
{buffer
};
219 std::string command
{read_word(istr
)};
222 ERR("Malformed line: %s\n", buffer
.c_str());
226 if(command
== "/description")
228 else if(command
== "/version")
231 if(!istr
.eof() && !std::isspace(istr
.peek()))
233 ERR("Extra junk after version: %s\n", buffer
.c_str()+istr
.tellg());
238 ERR("Unsupported version: %u\n", Version
);
242 else if(command
== "/dec/chan_mask")
244 istr
>> std::hex
>> ChanMask
>> std::dec
;
245 if(!istr
.eof() && !std::isspace(istr
.peek()))
247 ERR("Extra junk after mask: %s\n", buffer
.c_str()+istr
.tellg());
251 else if(command
== "/dec/freq_bands")
254 if(!istr
.eof() && !std::isspace(istr
.peek()))
256 ERR("Extra junk after freq_bands: %s\n", buffer
.c_str()+istr
.tellg());
259 if(FreqBands
!= 1 && FreqBands
!= 2)
261 ERR("Invalid freq_bands value: %u\n", FreqBands
);
265 else if(command
== "/dec/speakers")
268 if(!istr
.eof() && !std::isspace(istr
.peek()))
270 ERR("Extra junk after speakers: %s\n", buffer
.c_str()+istr
.tellg());
273 if(NumSpeakers
> MAX_OUTPUT_CHANNELS
)
275 ERR("Unsupported speaker count: %u\n", NumSpeakers
);
279 else if(command
== "/dec/coeff_scale")
281 std::string scale
= read_word(istr
);
282 if(scale
== "n3d") CoeffScale
= AmbDecScale::N3D
;
283 else if(scale
== "sn3d") CoeffScale
= AmbDecScale::SN3D
;
284 else if(scale
== "fuma") CoeffScale
= AmbDecScale::FuMa
;
287 ERR("Unsupported coeff scale: %s\n", scale
.c_str());
291 else if(command
== "/opt/xover_freq")
294 if(!istr
.eof() && !std::isspace(istr
.peek()))
296 ERR("Extra junk after xover_freq: %s\n", buffer
.c_str()+istr
.tellg());
300 else if(command
== "/opt/xover_ratio")
303 if(!istr
.eof() && !std::isspace(istr
.peek()))
305 ERR("Extra junk after xover_ratio: %s\n", buffer
.c_str()+istr
.tellg());
309 else if(command
== "/opt/input_scale" || command
== "/opt/nfeff_comp" ||
310 command
== "/opt/delay_comp" || command
== "/opt/level_comp")
315 else if(command
== "/speakers/{")
317 std::istream::pos_type endpos
{istr
.tellg()};
318 if(!is_at_end(buffer
, endpos
))
320 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
325 if(!load_ambdec_speakers(this, f
, buffer
))
328 if(!read_clipped_line(f
, buffer
))
330 ERR("Unexpected end of file\n");
333 std::istringstream istr2
{buffer
};
334 std::string endmark
{read_word(istr2
)};
337 ERR("Expected /} after speaker definitions, got %s\n", endmark
.c_str());
342 else if(command
== "/lfmatrix/{" || command
== "/hfmatrix/{" || command
== "/matrix/{")
344 std::istream::pos_type endpos
{istr
.tellg()};
345 if(!is_at_end(buffer
, endpos
))
347 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
354 if(command
!= "/matrix/{")
356 ERR("Unexpected \"%s\" type for a single-band decoder\n", command
.c_str());
359 if(!load_ambdec_matrix(HFOrderGain
, HFMatrix
, NumSpeakers
, f
, buffer
))
364 if(command
== "/lfmatrix/{")
366 if(!load_ambdec_matrix(LFOrderGain
, LFMatrix
, NumSpeakers
, f
, buffer
))
369 else if(command
== "/hfmatrix/{")
371 if(!load_ambdec_matrix(HFOrderGain
, HFMatrix
, NumSpeakers
, f
, buffer
))
376 ERR("Unexpected \"%s\" type for a dual-band decoder\n", command
.c_str());
381 if(!read_clipped_line(f
, buffer
))
383 ERR("Unexpected end of file\n");
386 std::istringstream istr2
{buffer
};
387 std::string endmark
{read_word(istr2
)};
390 ERR("Expected /} after matrix definitions, got %s\n", endmark
.c_str());
395 else if(command
== "/end")
397 std::istream::pos_type endpos
{istr
.tellg()};
398 if(!is_at_end(buffer
, endpos
))
400 ERR("Unexpected junk on end: %s\n", buffer
.c_str()+endpos
);
408 ERR("Unexpected command: %s\n", command
.c_str());
413 std::istream::pos_type endpos
{istr
.tellg()};
414 if(!is_at_end(buffer
, endpos
))
416 ERR("Unexpected junk on line: %s\n", buffer
.c_str()+endpos
);
421 ERR("Unexpected end of file\n");