Allow distance compensation for non-HQ rendering as well

It still requires a custom configuration to specify appropriate speaker
distances.
This commit is contained in:
Chris Robinson 2017-02-20 09:08:57 -08:00
parent b23f81b686
commit 5a2ef2590f
5 changed files with 49 additions and 53 deletions

View File

@ -610,6 +610,47 @@ static void InitPanning(ALCdevice *device)
}
}
static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
{
const char *devname = al_string_get_cstr(device->DeviceName);
ALfloat maxdist = 0.0f;
ALsizei i;
for(i = 0;i < conf->NumSpeakers;i++)
maxdist = maxf(maxdist, conf->Speakers[i].Distance);
if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f)
{
ALfloat srate = (ALfloat)device->Frequency;
for(i = 0;i < conf->NumSpeakers;i++)
{
ALsizei chan = speakermap[i];
ALfloat delay;
/* Distance compensation only delays in steps of the sample rate.
* This is a bit less accurate since the delay time falls to the
* nearest sample time, but it's far simpler as it doesn't have to
* deal with phase offsets. This means at 48khz, for instance, the
* distance delay will be in steps of about 7 millimeters.
*/
delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC *
srate + 0.5f);
if(delay >= (ALfloat)MAX_DELAY_LENGTH)
ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n",
al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH);
device->ChannelDelay[chan].Length = (ALsizei)clampf(
delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)
);
device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist;
TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan,
al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length,
device->ChannelDelay[chan].Gain
);
}
}
}
static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
{
ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
@ -688,16 +729,15 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A
device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale;
}
device->FOAOut.CoeffCount = 4;
InitDistanceComp(device, conf, speakermap);
}
static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
{
const char *devname;
size_t count;
size_t i;
devname = al_string_get_cstr(device->DeviceName);
if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
{
count = (conf->ChanMask > 0x1ff) ? 16 :
@ -756,40 +796,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz
device->FOAOut.CoeffCount = 0;
}
ALfloat maxdist = 0.0f;
for(i = 0;i < (size_t)conf->NumSpeakers;i++)
maxdist = maxf(maxdist, conf->Speakers[i].Distance);
if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f)
{
ALfloat srate = (ALfloat)device->Frequency;
for(i = 0;i < (size_t)conf->NumSpeakers;i++)
{
ALsizei chan = speakermap[i];
ALfloat delay;
/* Distance compensation only delays in steps of the sample rate.
* This is a bit less accurate since the delay time falls to the
* nearest sample time, but it's far simpler as it doesn't have to
* deal with phase offsets. This means at 48khz, for instance, the
* distance delay will be in steps of about 7 millimeters.
*/
delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC *
srate + 0.5f);
if(delay >= (ALfloat)MAX_DELAY_LENGTH)
ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n",
al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH);
device->ChannelDelay[chan].Length = (ALsizei)clampf(
delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)
);
device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist;
TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan,
al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length,
device->ChannelDelay[chan].Gain
);
}
}
InitDistanceComp(device, conf, speakermap);
}
static void InitHrtfPanning(ALCdevice *device, bool hoa_mode)

View File

@ -235,9 +235,8 @@ hq-mode = false
# Enables compensation for the speakers' relative distances to the listener.
# This applies the necessary delays and attenuation to make the speakers
# behave as though they are all equidistant, which is important for proper
# playback of 3D sound rendering. Requires the high-quality ambisonic decoder,
# as well as the proper distances to be specified in the decoder configuration
# file.
# playback of 3D sound rendering. Requires the proper distances to be
# specified in the decoder configuration file.
distance-comp = true
## quad:

View File

@ -329,7 +329,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->stereoPanningComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton()));
connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton()));
connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(toggleHqState(int)));
connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile()));
@ -665,7 +665,6 @@ void MainWindow::loadConfig(const QString &fname)
ui->decoderHQModeCheckBox->setChecked(hqmode);
bool distcomp = settings.value("decoder/distance-comp", true).toBool();
ui->decoderDistCompCheckBox->setChecked(distcomp);
ui->decoderDistCompCheckBox->setEnabled(hqmode);
ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString());
ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString());
@ -1110,12 +1109,6 @@ void MainWindow::updatePeriodCountSlider()
}
void MainWindow::toggleHqState(int state)
{
ui->decoderDistCompCheckBox->setEnabled(state);
enableApplyButton();
}
void MainWindow::selectQuadDecoderFile()
{ selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");}
void MainWindow::select51DecoderFile()

View File

@ -35,8 +35,6 @@ private slots:
void updatePeriodCountEdit(int size);
void updatePeriodCountSlider();
void toggleHqState(int state);
void selectQuadDecoderFile();
void select51DecoderFile();
void select61DecoderFile();

View File

@ -601,9 +601,8 @@ appropriate speaker configuration you intend to use.</string>
<string>This applies the necessary delays and attenuation
to make the speakers behave as though they are
all equidistant, which is important for proper
playback of 3D sound rendering. Requires the high
quality ambisonic renderer, as well as the proper
distances to be specified in the decoder
playback of 3D sound rendering. Requires the
proper distances to be specified in the decoder
configuration file.</string>
</property>
<property name="layoutDirection">