Make the AmbDec speaker and matrix arrays dynamic
This commit is contained in:
+43
-41
@@ -3,8 +3,9 @@
|
||||
|
||||
#include "ambdec.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
@@ -61,10 +62,9 @@ bool is_at_end(const std::string &buffer, std::size_t endpos)
|
||||
}
|
||||
|
||||
|
||||
bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer)
|
||||
bool load_ambdec_speakers(al::vector<AmbDecConf::SpeakerConf> &spkrs, const std::size_t num_speakers, std::istream &f, std::string &buffer)
|
||||
{
|
||||
ALsizei cur = 0;
|
||||
while(cur < conf->NumSpeakers)
|
||||
while(spkrs.size() < num_speakers)
|
||||
{
|
||||
std::istringstream istr{buffer};
|
||||
|
||||
@@ -81,18 +81,20 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer
|
||||
|
||||
if(cmd == "add_spkr")
|
||||
{
|
||||
istr >> conf->Speakers[cur].Name;
|
||||
if(istr.fail()) WARN("Name not specified for speaker %u\n", cur+1);
|
||||
istr >> conf->Speakers[cur].Distance;
|
||||
if(istr.fail()) WARN("Distance not specified for speaker %u\n", cur+1);
|
||||
istr >> conf->Speakers[cur].Azimuth;
|
||||
if(istr.fail()) WARN("Azimuth not specified for speaker %u\n", cur+1);
|
||||
istr >> conf->Speakers[cur].Elevation;
|
||||
if(istr.fail()) WARN("Elevation not specified for speaker %u\n", cur+1);
|
||||
istr >> conf->Speakers[cur].Connection;
|
||||
if(istr.fail()) TRACE("Connection not specified for speaker %u\n", cur+1);
|
||||
spkrs.emplace_back();
|
||||
AmbDecConf::SpeakerConf &spkr = spkrs.back();
|
||||
const size_t spkr_num{spkrs.size()};
|
||||
|
||||
cur++;
|
||||
istr >> spkr.Name;
|
||||
if(istr.fail()) WARN("Name not specified for speaker " SZFMT "\n", spkr_num);
|
||||
istr >> spkr.Distance;
|
||||
if(istr.fail()) WARN("Distance not specified for speaker " SZFMT "\n", spkr_num);
|
||||
istr >> spkr.Azimuth;
|
||||
if(istr.fail()) WARN("Azimuth not specified for speaker " SZFMT "\n", spkr_num);
|
||||
istr >> spkr.Elevation;
|
||||
if(istr.fail()) WARN("Elevation not specified for speaker " SZFMT "\n", spkr_num);
|
||||
istr >> spkr.Connection;
|
||||
if(istr.fail()) TRACE("Connection not specified for speaker " SZFMT "\n", spkr_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -113,10 +115,10 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, std::istream &f, std::string &buffer)
|
||||
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)
|
||||
{
|
||||
bool gotgains = false;
|
||||
ALsizei cur = 0;
|
||||
bool gotgains{false};
|
||||
std::size_t cur{0u};
|
||||
while(cur < maxrow)
|
||||
{
|
||||
std::istringstream istr{buffer};
|
||||
@@ -134,7 +136,7 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi
|
||||
|
||||
if(cmd == "order_gain")
|
||||
{
|
||||
ALuint curgain = 0;
|
||||
std::size_t curgain{0u};
|
||||
float value;
|
||||
while(istr.good())
|
||||
{
|
||||
@@ -142,36 +144,37 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi
|
||||
if(istr.fail()) break;
|
||||
if(!istr.eof() && !std::isspace(istr.peek()))
|
||||
{
|
||||
ERR("Extra junk on gain %u: %s\n", curgain+1,
|
||||
ERR("Extra junk on gain " SZFMT ": %s\n", curgain+1,
|
||||
buffer.c_str()+static_cast<std::size_t>(istr.tellg()));
|
||||
return false;
|
||||
}
|
||||
if(curgain < MAX_AMBI_ORDER+1)
|
||||
if(curgain < countof(gains))
|
||||
gains[curgain++] = value;
|
||||
}
|
||||
while(curgain < MAX_AMBI_ORDER+1)
|
||||
gains[curgain++] = 0.0f;
|
||||
std::fill(std::begin(gains)+curgain, std::end(gains), 0.0f);
|
||||
gotgains = true;
|
||||
}
|
||||
else if(cmd == "add_row")
|
||||
{
|
||||
ALuint curidx = 0;
|
||||
float value;
|
||||
matrix.emplace_back();
|
||||
AmbDecConf::CoeffArray &mtxrow = matrix.back();
|
||||
std::size_t curidx{0u};
|
||||
float value{};
|
||||
while(istr.good())
|
||||
{
|
||||
istr >> value;
|
||||
if(istr.fail()) break;
|
||||
if(!istr.eof() && !std::isspace(istr.peek()))
|
||||
{
|
||||
ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx,
|
||||
buffer.c_str()+static_cast<std::size_t>(istr.tellg()));
|
||||
ERR("Extra junk on matrix element " SZFMT "x" SZFMT ": %s\n", curidx,
|
||||
matrix.size(), buffer.c_str()+static_cast<std::size_t>(istr.tellg()));
|
||||
matrix.pop_back();
|
||||
return false;
|
||||
}
|
||||
if(curidx < MAX_AMBI_COEFFS)
|
||||
matrix[cur][curidx++] = value;
|
||||
if(curidx < mtxrow.size())
|
||||
mtxrow[curidx++] = value;
|
||||
}
|
||||
while(curidx < MAX_AMBI_COEFFS)
|
||||
matrix[cur][curidx++] = 0.0f;
|
||||
std::fill(mtxrow.begin()+curidx, mtxrow.end(), 0.0f);
|
||||
cur++;
|
||||
}
|
||||
else
|
||||
@@ -210,6 +213,7 @@ int AmbDecConf::load(const char *fname) noexcept
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t num_speakers{0u};
|
||||
std::string buffer;
|
||||
while(read_clipped_line(f, buffer))
|
||||
{
|
||||
@@ -266,18 +270,16 @@ int AmbDecConf::load(const char *fname) noexcept
|
||||
}
|
||||
else if(command == "/dec/speakers")
|
||||
{
|
||||
istr >> NumSpeakers;
|
||||
istr >> num_speakers;
|
||||
if(!istr.eof() && !std::isspace(istr.peek()))
|
||||
{
|
||||
ERR("Extra junk after speakers: %s\n",
|
||||
buffer.c_str()+static_cast<std::size_t>(istr.tellg()));
|
||||
return 0;
|
||||
}
|
||||
if(NumSpeakers > MAX_OUTPUT_CHANNELS)
|
||||
{
|
||||
ERR("Unsupported speaker count: %u\n", NumSpeakers);
|
||||
return 0;
|
||||
}
|
||||
Speakers.reserve(num_speakers);
|
||||
LFMatrix.reserve(num_speakers);
|
||||
HFMatrix.reserve(num_speakers);
|
||||
}
|
||||
else if(command == "/dec/coeff_scale")
|
||||
{
|
||||
@@ -327,7 +329,7 @@ int AmbDecConf::load(const char *fname) noexcept
|
||||
}
|
||||
buffer.clear();
|
||||
|
||||
if(!load_ambdec_speakers(this, f, buffer))
|
||||
if(!load_ambdec_speakers(Speakers, num_speakers, f, buffer))
|
||||
return 0;
|
||||
|
||||
if(!read_clipped_line(f, buffer))
|
||||
@@ -361,19 +363,19 @@ int AmbDecConf::load(const char *fname) noexcept
|
||||
ERR("Unexpected \"%s\" type for a single-band decoder\n", command.c_str());
|
||||
return 0;
|
||||
}
|
||||
if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer))
|
||||
if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(command == "/lfmatrix/{")
|
||||
{
|
||||
if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer))
|
||||
if(!load_ambdec_matrix(LFOrderGain, LFMatrix, num_speakers, f, buffer))
|
||||
return 0;
|
||||
}
|
||||
else if(command == "/hfmatrix/{")
|
||||
{
|
||||
if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer))
|
||||
if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
|
||||
+17
-14
@@ -1,9 +1,11 @@
|
||||
#ifndef AMBDEC_H
|
||||
#define AMBDEC_H
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "vector.h"
|
||||
|
||||
/* Helpers to read .ambdec configuration files. */
|
||||
|
||||
@@ -14,30 +16,31 @@ enum class AmbDecScale {
|
||||
};
|
||||
struct AmbDecConf {
|
||||
std::string Description;
|
||||
ALuint Version; /* Must be 3 */
|
||||
int Version; /* Must be 3 */
|
||||
|
||||
ALuint ChanMask;
|
||||
ALuint FreqBands; /* Must be 1 or 2 */
|
||||
ALsizei NumSpeakers;
|
||||
unsigned int ChanMask;
|
||||
unsigned int FreqBands; /* Must be 1 or 2 */
|
||||
AmbDecScale CoeffScale;
|
||||
|
||||
ALfloat XOverFreq;
|
||||
ALfloat XOverRatio;
|
||||
float XOverFreq;
|
||||
float XOverRatio;
|
||||
|
||||
struct SpeakerConf {
|
||||
std::string Name;
|
||||
ALfloat Distance;
|
||||
ALfloat Azimuth;
|
||||
ALfloat Elevation;
|
||||
float Distance{0.0f};
|
||||
float Azimuth{0.0f};
|
||||
float Elevation{0.0f};
|
||||
std::string Connection;
|
||||
} Speakers[MAX_OUTPUT_CHANNELS];
|
||||
};
|
||||
al::vector<SpeakerConf> Speakers;
|
||||
|
||||
using CoeffArray = std::array<float,MAX_AMBI_COEFFS>;
|
||||
/* Unused when FreqBands == 1 */
|
||||
ALfloat LFOrderGain[MAX_AMBI_ORDER+1];
|
||||
ALfloat LFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
|
||||
float LFOrderGain[MAX_AMBI_ORDER+1];
|
||||
al::vector<CoeffArray> LFMatrix;
|
||||
|
||||
ALfloat HFOrderGain[MAX_AMBI_ORDER+1];
|
||||
ALfloat HFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
|
||||
float HFOrderGain[MAX_AMBI_ORDER+1];
|
||||
al::vector<CoeffArray> HFMatrix;
|
||||
|
||||
int load(const char *fname) noexcept;
|
||||
};
|
||||
|
||||
+3
-3
@@ -91,7 +91,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate,
|
||||
mSamplesHF = mSamples.data();
|
||||
mSamplesLF = mSamplesHF + chancount;
|
||||
|
||||
mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u,
|
||||
mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->Speakers.size(), 0u,
|
||||
[](ALuint mask, const ALsizei &chan) noexcept -> ALuint
|
||||
{ return mask | (1 << chan); }
|
||||
);
|
||||
@@ -139,7 +139,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate,
|
||||
mDualBand = (conf->FreqBands == 2);
|
||||
if(!mDualBand)
|
||||
{
|
||||
for(ALsizei i{0};i < conf->NumSpeakers;i++)
|
||||
for(size_t i{0u};i < conf->Speakers.size();i++)
|
||||
{
|
||||
ALfloat (&mtx)[MAX_AMBI_COEFFS] = mMatrix.Single[chanmap[i]];
|
||||
for(ALsizei j{0},k{0};j < coeff_count;j++)
|
||||
@@ -160,7 +160,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate,
|
||||
std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]);
|
||||
|
||||
const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)};
|
||||
for(ALsizei i{0};i < conf->NumSpeakers;i++)
|
||||
for(size_t i{0u};i < conf->Speakers.size();i++)
|
||||
{
|
||||
ALfloat (&mtx)[sNumBands][MAX_AMBI_COEFFS] = mMatrix.Dual[chanmap[i]];
|
||||
for(ALsizei j{0},k{0};j < coeff_count;j++)
|
||||
|
||||
+12
-11
@@ -119,7 +119,7 @@ struct ChannelMap {
|
||||
};
|
||||
|
||||
void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], ChannelConfig *ambicoeffs,
|
||||
const ChannelMap *chanmap, ALsizei count, ALsizei *outcount)
|
||||
const ChannelMap *chanmap, const size_t count, ALsizei *outcount)
|
||||
{
|
||||
auto copy_coeffs = [&devchans,ambicoeffs](ALsizei maxchans, const ChannelMap &channel) -> ALsizei
|
||||
{
|
||||
@@ -217,10 +217,9 @@ bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speaker
|
||||
ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str());
|
||||
return chidx;
|
||||
};
|
||||
auto speakers_end = std::begin(conf->Speakers) + conf->NumSpeakers;
|
||||
std::transform(std::begin(conf->Speakers), speakers_end, std::begin(speakermap), map_spkr);
|
||||
std::transform(conf->Speakers.begin(), conf->Speakers.end(), std::begin(speakermap), map_spkr);
|
||||
/* Return success if no invalid entries are found. */
|
||||
auto speakermap_end = std::begin(speakermap) + conf->NumSpeakers;
|
||||
auto speakermap_end = std::begin(speakermap) + conf->Speakers.size();
|
||||
return std::find(std::begin(speakermap), speakermap_end, -1) == speakermap_end;
|
||||
}
|
||||
|
||||
@@ -281,9 +280,8 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
auto speakers_end = std::begin(conf->Speakers) + conf->NumSpeakers;
|
||||
const ALfloat maxdist{
|
||||
std::accumulate(std::begin(conf->Speakers), speakers_end, float{0.0f},
|
||||
std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f},
|
||||
std::bind(maxf, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2))
|
||||
)
|
||||
};
|
||||
@@ -294,7 +292,7 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (
|
||||
|
||||
auto srate = static_cast<ALfloat>(device->Frequency);
|
||||
size_t total{0u};
|
||||
for(ALsizei i{0};i < conf->NumSpeakers;i++)
|
||||
for(size_t i{0u};i < conf->Speakers.size();i++)
|
||||
{
|
||||
const AmbDecConf::SpeakerConf &speaker = conf->Speakers[i];
|
||||
const ALsizei chan{speakermap[i]};
|
||||
@@ -536,7 +534,7 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei
|
||||
|
||||
const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale);
|
||||
ChannelMap chanmap[MAX_OUTPUT_CHANNELS]{};
|
||||
for(ALsizei i{0};i < conf->NumSpeakers;i++)
|
||||
for(size_t i{0u};i < conf->Speakers.size();i++)
|
||||
{
|
||||
chanmap[i].ChanName = device->RealOut.ChannelName[speakermap[i]];
|
||||
std::fill(std::begin(chanmap[i].Config), std::end(chanmap[i].Config), 0.0f);
|
||||
@@ -553,7 +551,7 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei
|
||||
}
|
||||
|
||||
SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap,
|
||||
conf->NumSpeakers, &device->Dry.NumChannels);
|
||||
conf->Speakers.size(), &device->Dry.NumChannels);
|
||||
device->Dry.CoeffCount = (conf->ChanMask > AMBI_2ORDER_MASK) ? 16 :
|
||||
(conf->ChanMask > AMBI_1ORDER_MASK) ? 9 : 4;
|
||||
|
||||
@@ -643,8 +641,8 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp
|
||||
std::plus<float>{}, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)
|
||||
);
|
||||
const ALfloat avg_dist{
|
||||
std::accumulate(std::begin(conf->Speakers), std::begin(conf->Speakers)+conf->NumSpeakers,
|
||||
float{0.0f}, accum_spkr_dist) / (ALfloat)conf->NumSpeakers
|
||||
std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f},
|
||||
accum_spkr_dist) / static_cast<ALfloat>(conf->Speakers.size())
|
||||
};
|
||||
InitNearFieldCtrl(device, avg_dist,
|
||||
(conf->ChanMask > AMBI_2ORDER_MASK) ? 3 :
|
||||
@@ -964,6 +962,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr
|
||||
{
|
||||
if(!conf.load(fname))
|
||||
ERR("Failed to load layout file %s\n", fname);
|
||||
else if(conf.Speakers.size() > MAX_OUTPUT_CHANNELS)
|
||||
ERR("Unsupported speaker count " SZFMT " (max %d)\n", conf.Speakers.size(),
|
||||
MAX_OUTPUT_CHANNELS);
|
||||
else if(conf.ChanMask > AMBI_3ORDER_MASK)
|
||||
ERR("Unsupported channel mask 0x%04x (max 0x%x)\n", conf.ChanMask,
|
||||
AMBI_3ORDER_MASK);
|
||||
|
||||
Reference in New Issue
Block a user