Added a Dolby Pro Logic II (DPL2) decoder in the OpenAL backend. DPL2 audio is decoded to 5.1. Code adapted from ffdshow.

Added an option in the DSP settings to disable the DPL2 decoder in case Dolphin incorrectly detects a 5.1 audio system.
Updated the OpenAL files to OpenAL Soft 1.15.1 in the Windows build.

Fixes issue 3023.
This commit is contained in:
skidau
2013-01-11 14:03:09 +11:00
parent c7ccf7e5c6
commit 80f4475e76
20 changed files with 2598 additions and 1566 deletions

View File

@ -109,7 +109,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -121,7 +121,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -147,7 +147,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -175,7 +175,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -192,6 +192,7 @@
<ClCompile Include="Src\AOSoundStream.cpp" />
<ClCompile Include="Src\AudioCommon.cpp" />
<ClCompile Include="Src\AudioCommonConfig.cpp" />
<ClCompile Include="Src\DPL2Decoder.cpp" />
<ClCompile Include="Src\DSoundStream.cpp" />
<ClCompile Include="Src\Mixer.cpp" />
<ClCompile Include="Src\NullSoundStream.cpp" />
@ -204,6 +205,7 @@
<ClInclude Include="Src\AOSoundStream.h" />
<ClInclude Include="Src\AudioCommon.h" />
<ClInclude Include="Src\AudioCommonConfig.h" />
<ClInclude Include="Src\DPL2Decoder.h" />
<ClInclude Include="Src\DSoundStream.h" />
<ClInclude Include="Src\Mixer.h" />
<ClInclude Include="Src\NullSoundStream.h" />

View File

@ -21,6 +21,7 @@
<ClCompile Include="Src\NullSoundStream.cpp">
<Filter>SoundStreams</Filter>
</ClCompile>
<ClCompile Include="Src\DPL2Decoder.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\aldlist.h" />
@ -44,6 +45,7 @@
<ClInclude Include="Src\XAudio2Stream.h">
<Filter>SoundStreams</Filter>
</ClInclude>
<ClInclude Include="Src\DPL2Decoder.h" />
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -1,5 +1,6 @@
set(SRCS Src/AudioCommon.cpp
Src/AudioCommonConfig.cpp
Src/DPL2Decoder.cpp
Src/Mixer.cpp
Src/WaveFile.cpp
Src/NullSoundStream.cpp)

View File

@ -0,0 +1,397 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Dolby Pro Logic 2 decoder from ffdshow-tryout
// * Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
// * Copyright (c) 2004-2006 Milan Cutka
// * based on mplayer HRTF plugin by ylai
#include <functional>
#include <vector>
#include "DPL2Decoder.h"
#define M_PI 3.14159265358979323846
#define M_SQRT1_2 0.70710678118654752440
int olddelay = -1;
unsigned int oldfreq = 0;
unsigned int dlbuflen;
int cyc_pos;
float l_fwr, r_fwr, lpr_fwr, lmr_fwr;
std::vector<float> fwrbuf_l, fwrbuf_r;
float adapt_l_gain, adapt_r_gain, adapt_lpr_gain, adapt_lmr_gain;
std::vector<float> lf, rf, lr, rr, cf, cr;
float LFE_buf[256];
unsigned int lfe_pos;
float *filter_coefs_lfe;
unsigned int len125;
template<class T,class _ftype_t> static _ftype_t dotproduct(int count,const T *buf,const _ftype_t *coefficients)
{
float sum0=0,sum1=0,sum2=0,sum3=0;
for (;count>=4;buf+=4,coefficients+=4,count-=4)
{
sum0+=buf[0]*coefficients[0];
sum1+=buf[1]*coefficients[1];
sum2+=buf[2]*coefficients[2];
sum3+=buf[3]*coefficients[3];
}
while (count--) sum0+= *buf++ * *coefficients++;
return sum0+sum1+sum2+sum3;
}
template<class T> static T firfilter(const T *buf, int pos, int len, int count, const float *coefficients)
{
int count1, count2;
if (pos >= count)
{
pos -= count;
count1 = count; count2 = 0;
}
else
{
count2 = pos;
count1 = count - pos;
pos = len - count1;
}
// high part of window
const T *ptr = &buf[pos];
float r1=dotproduct(count1,ptr,coefficients);coefficients+=count1;
float r2=dotproduct(count2,buf,coefficients);
return T(r1+r2);
}
template<class T> inline const T& limit(const T& val, const T& min, const T& max)
{
if (val < min) {
return min;
} else if (val > max) {
return max;
} else {
return val;
}
}
/*
// Hamming
// 2*pi*k
// w(k) = 0.54 - 0.46*cos(------), where 0 <= k < N
// N-1
//
// n window length
// w buffer for the window parameters
*/
void hamming(int n, float* w)
{
int i;
float k = float(2*M_PI/((float)(n-1))); // 2*pi/(N-1)
// Calculate window coefficients
for (i=0; i<n; i++)
*w++ = float(0.54 - 0.46*cos(k*(float)i));
}
/******************************************************************************
* FIR filter design
******************************************************************************/
/* Design FIR filter using the Window method
n filter length must be odd for HP and BS filters
w buffer for the filter taps (must be n long)
fc cutoff frequencies (1 for LP and HP, 2 for BP and BS)
0 < fc < 1 where 1 <=> Fs/2
flags window and filter type as defined in filter.h
variables are ored together: i.e. LP|HAMMING will give a
low pass filter designed using a hamming window
opt beta constant used only when designing using kaiser windows
returns 0 if OK, -1 if fail
*/
float* design_fir(unsigned int *n, float* fc, float opt)
{
unsigned int o = *n & 1; // Indicator for odd filter length
unsigned int end = ((*n + 1) >> 1) - o; // Loop end
unsigned int i; // Loop index
float k1 = 2 * float(M_PI); // 2*pi*fc1
float k2 = 0.5f * (float)(1 - o);// Constant used if the filter has even length
float g = 0.0f; // Gain
float t1; // Temporary variables
float fc1; // Cutoff frequencies
// Sanity check
if(*n==0) return NULL;
fc[0]=limit(fc[0],float(0.001),float(1));
float *w=(float*)calloc(sizeof(float),*n);
// Get window coefficients
hamming(*n,w);
fc1=*fc;
// Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2
fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25f;
k1 *= fc1;
// Low pass filter
// If the filter length is odd, there is one point which is exactly
// in the middle. The value at this point is 2*fCutoff*sin(x)/x,
// where x is zero. To make sure nothing strange happens, we set this
// value separately.
if (o)
{
w[end] = fc1 * w[end] * 2.0f;
g=w[end];
}
// Create filter
for (i=0 ; i<end ; i++)
{
t1 = (float)(i+1) - k2;
w[end-i-1] = w[*n-end+i] = float(w[end-i-1] * sin(k1 * t1)/(M_PI * t1)); // Sinc
g += 2*w[end-i-1]; // Total gain in filter
}
// Normalize gain
g=1/g;
for (i=0; i<*n; i++)
w[i] *= g;
return w;
}
void onSeek(void)
{
l_fwr = r_fwr = lpr_fwr = lmr_fwr = 0;
std::fill(fwrbuf_l.begin(), fwrbuf_l.end(), 0.0f);
std::fill(fwrbuf_r.begin(), fwrbuf_r.end(), 0.0f);
adapt_l_gain = adapt_r_gain = adapt_lpr_gain = adapt_lmr_gain = 0;
std::fill(lf.begin(), lf.end(), 0.0f);
std::fill(rf.begin(), rf.end(), 0.0f);
std::fill(lr.begin(), lr.end(), 0.0f);
std::fill(rr.begin(), rr.end(), 0.0f);
std::fill(cf.begin(), cf.end(), 0.0f);
std::fill(cr.begin(), cr.end(), 0.0f);
lfe_pos = 0;
memset(LFE_buf, 0, sizeof(LFE_buf));
}
void done(void)
{
onSeek();
if (filter_coefs_lfe)
{
free(filter_coefs_lfe);
}
filter_coefs_lfe = NULL;
}
float* calc_coefficients_125Hz_lowpass(int rate)
{
len125 = 256;
float f = 125.0f / (rate / 2);
float *coeffs = design_fir(&len125, &f, 0);
static const float M3_01DB = 0.7071067812f;
for (unsigned int i = 0; i < len125; i++)
{
coeffs[i] *= M3_01DB;
}
return coeffs;
}
float passive_lock(float x)
{
static const float MATAGCLOCK = 0.2f; /* AGC range (around 1) where the matrix behaves passively */
const float x1 = x - 1;
const float ax1s = fabs(x - 1) * (1.0f / MATAGCLOCK);
return x1 - x1 / (1 + ax1s * ax1s) + 1;
}
void matrix_decode(const float *in, const int k, const int il,
const int ir, bool decode_rear,
const int dlbuflen,
float l_fwr, float r_fwr,
float lpr_fwr, float lmr_fwr,
float *adapt_l_gain, float *adapt_r_gain,
float *adapt_lpr_gain, float *adapt_lmr_gain,
float *lf, float *rf, float *lr,
float *rr, float *cf)
{
static const float M9_03DB = 0.3535533906f;
static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */
static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */
static const float MATCOMPGAIN = 0.37f; /* Cross talk compensation gain, 0.50 - 0.55 is full cancellation. */
const int kr = (k + olddelay) % dlbuflen;
float l_gain = (l_fwr + r_fwr) / (1 + l_fwr + l_fwr);
float r_gain = (l_fwr + r_fwr) / (1 + r_fwr + r_fwr);
/* The 2nd axis has strong gain fluctuations, and therefore require
limits. The factor corresponds to the 1 / amplification of (Lt
- Rt) when (Lt, Rt) is strongly correlated. (e.g. during
dialogues). It should be bigger than -12 dB to prevent
distortion. */
float lmr_lim_fwr = lmr_fwr > M9_03DB * lpr_fwr ? lmr_fwr : M9_03DB * lpr_fwr;
float lpr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lpr_fwr + lpr_fwr);
float lmr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr);
float lmr_unlim_gain = (lpr_fwr + lmr_fwr) / (1 + lmr_fwr + lmr_fwr);
float lpr, lmr;
float l_agc, r_agc, lpr_agc, lmr_agc;
float f, d_gain, c_gain, c_agc_cfk;
/*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
/* AGC adaption */
d_gain = (fabs(l_gain - *adapt_l_gain) + fabs(r_gain - *adapt_r_gain)) * 0.5f;
f = d_gain * (1.0f / MATAGCTRIG);
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
*adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain;
*adapt_r_gain = (1 - f) * *adapt_r_gain + f * r_gain;
/* Matrix */
l_agc = in[il] * passive_lock(*adapt_l_gain);
r_agc = in[ir] * passive_lock(*adapt_r_gain);
cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2;
if (decode_rear)
{
lr[kr] = rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2;
/* Stereo rear channel is steered with the same AGC steering as
the decoding matrix. Note this requires a fast updating AGC
at the order of 20 ms (which is the case here). */
lr[kr] *= (l_fwr + l_fwr) / (1 + l_fwr + r_fwr);
rr[kr] *= (r_fwr + r_fwr) / (1 + l_fwr + r_fwr);
}
/*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
lpr = (in[il] + in[ir]) * (float)M_SQRT1_2;
lmr = (in[il] - in[ir]) * (float)M_SQRT1_2;
/* AGC adaption */
d_gain = fabs(lmr_unlim_gain - *adapt_lmr_gain);
f = d_gain * (1.0f / MATAGCTRIG);
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
*adapt_lpr_gain = (1 - f) * *adapt_lpr_gain + f * lpr_gain;
*adapt_lmr_gain = (1 - f) * *adapt_lmr_gain + f * lmr_gain;
/* Matrix */
lpr_agc = lpr * passive_lock(*adapt_lpr_gain);
lmr_agc = lmr * passive_lock(*adapt_lmr_gain);
lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2;
rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2;
/*** CENTER FRONT CANCELLATION ***/
/* A heuristic approach exploits that Lt + Rt gain contains the
information about Lt, Rt correlation. This effectively reshapes
the front and rear "cones" to concentrate Lt + Rt to C and
introduce Lt - Rt in L, R. */
/* 0.67677 is the empirical lower bound for lpr_gain. */
c_gain = 8 * (*adapt_lpr_gain - 0.67677f);
c_gain = c_gain > 0 ? c_gain : 0;
/* c_gain should not be too high, not even reaching full
cancellation (~ 0.50 - 0.55 at current AGC implementation), or
the center will sound too narrow. */
c_gain = MATCOMPGAIN / (1 + c_gain * c_gain);
c_agc_cfk = c_gain * cf[k];
lf[k] -= c_agc_cfk;
rf[k] -= c_agc_cfk;
cf[k] += c_agc_cfk + c_agc_cfk;
}
void dpl2decode(float *samples, int numsamples, float *out)
{
static const unsigned int FWRDURATION = 240; /* FWR average duration (samples) */
static const unsigned int cfg_delay = 0;
static const unsigned int fmt_freq = 48000;
static const unsigned int fmt_nchannels = 2; // input channels
int cur = 0;
if (olddelay != cfg_delay || oldfreq != fmt_freq)
{
done();
olddelay = cfg_delay;
oldfreq = fmt_freq;
dlbuflen = std::max(FWRDURATION, (fmt_freq * cfg_delay / 1000)); //+(len7000-1);
cyc_pos = dlbuflen - 1;
fwrbuf_l.resize(dlbuflen);
fwrbuf_r.resize(dlbuflen);
lf.resize(dlbuflen);
rf.resize(dlbuflen);
lr.resize(dlbuflen);
rr.resize(dlbuflen);
cf.resize(dlbuflen);
cr.resize(dlbuflen);
filter_coefs_lfe = calc_coefficients_125Hz_lowpass(fmt_freq);
lfe_pos = 0;
memset(LFE_buf, 0, sizeof(LFE_buf));
}
float *in = samples; // Input audio data
float *end = in + numsamples * fmt_nchannels; // Loop end
while (in < end)
{
const int k = cyc_pos;
const int fwr_pos = (k + FWRDURATION) % dlbuflen;
/* Update the full wave rectified total amplitude */
/* Input matrix decoder */
l_fwr += fabs(in[0]) - fabs(fwrbuf_l[fwr_pos]);
r_fwr += fabs(in[1]) - fabs(fwrbuf_r[fwr_pos]);
lpr_fwr += fabs(in[0] + in[1]) - fabs(fwrbuf_l[fwr_pos] + fwrbuf_r[fwr_pos]);
lmr_fwr += fabs(in[0] - in[1]) - fabs(fwrbuf_l[fwr_pos] - fwrbuf_r[fwr_pos]);
/* Matrix encoded 2 channel sources */
fwrbuf_l[k] = in[0];
fwrbuf_r[k] = in[1];
matrix_decode(in, k, 0, 1, true, dlbuflen,
l_fwr, r_fwr,
lpr_fwr, lmr_fwr,
&adapt_l_gain, &adapt_r_gain,
&adapt_lpr_gain, &adapt_lmr_gain,
&lf[0], &rf[0], &lr[0], &rr[0], &cf[0]);
out[cur + 0] = lf[k];
out[cur + 1] = rf[k];
out[cur + 2] = cf[k];
LFE_buf[lfe_pos] = (out[0] + out[1]) / 2;
out[cur + 3] = firfilter(LFE_buf, lfe_pos, len125, len125, filter_coefs_lfe);
lfe_pos++;
if (lfe_pos == len125)
{
lfe_pos = 0;
}
out[cur + 4] = lr[k];
out[cur + 5] = rr[k];
// Next sample...
in += 2;
cur += 6;
cyc_pos--;
if (cyc_pos < 0)
{
cyc_pos += dlbuflen;
}
}
}
void dpl2reset()
{
olddelay = -1;
oldfreq = 0;
filter_coefs_lfe = NULL;
}

View File

@ -0,0 +1,24 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DPL2DECODER_H_
#define _DPL2DECODER_H_
void dpl2decode(float *samples, int numsamples, float *out);
void dpl2reset();
#endif // _DPL2DECODER_H_

View File

@ -15,10 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <functional>
#include "aldlist.h"
#include "OpenALStream.h"
#include "DPL2Decoder.h"
#if defined HAVE_OPENAL && HAVE_OPENAL
@ -37,8 +36,10 @@ bool OpenALStream::Start()
pDeviceList = new ALDeviceList();
if ((pDeviceList) && (pDeviceList->GetNumDevices()))
{
char *defDevName = pDeviceList-> \
GetDeviceName(pDeviceList->GetDefaultDevice());
char *defDevName = pDeviceList->GetDeviceName(pDeviceList->GetDefaultDevice());
WARN_LOG(AUDIO, "Found OpenAL device %s", defDevName);
pDevice = alcOpenDevice(defDevName);
if (pDevice)
{
@ -52,8 +53,7 @@ bool OpenALStream::Start()
else
{
alcCloseDevice(pDevice);
PanicAlertT("OpenAL: can't create context "
"for device %s", defDevName);
PanicAlertT("OpenAL: can't create context for device %s", defDevName);
}
}
else
@ -67,6 +67,9 @@ bool OpenALStream::Start()
PanicAlertT("OpenAL: can't find sound devices");
}
// Initialise DPL2 parameters
dpl2reset();
soundTouch.clear();
return bReturn;
}
@ -76,6 +79,7 @@ void OpenALStream::Stop()
threadData = 1;
// kick the thread if it's waiting
soundSyncEvent.Set();
mainSyncEvent.Set();
soundTouch.clear();
@ -141,10 +145,15 @@ void OpenALStream::SoundLoop()
alGenSources(1, &uiSource);
// Short Silence
memset(sampleBuffer, 0, OAL_MAX_SAMPLES * 4 * OAL_NUM_BUFFERS);
memset(sampleBuffer, 0, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_NUM_BUFFERS);
memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * 4);
for (int i = 0; i < OAL_NUM_BUFFERS; i++)
alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_MAX_SAMPLES * 4, ulFrequency);
{
if (Core::g_CoreStartupParameter.bDPL2Decoder)
alBufferData(uiBuffers[i], AL_FORMAT_51CHN32, sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_NUM_BUFFERS, ulFrequency);
else
alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_MAX_SAMPLES * 4, ulFrequency);
}
alSourceQueueBuffers(uiSource, OAL_NUM_BUFFERS, uiBuffers);
alSourcePlay(uiSource);
@ -166,6 +175,8 @@ void OpenALStream::SoundLoop()
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28);
soundTouch.setSetting(SETTING_OVERLAP_MS, 12);
bool surround_capable = Core::g_CoreStartupParameter.bDPL2Decoder;
while (!threadData)
{
// num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD.
@ -201,18 +212,72 @@ void OpenALStream::SoundLoop()
soundTouch.setSetting(SETTING_SEQUENCE_MS, (int)(1 / (rate * rate)));
soundTouch.setTempo(rate);
}
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * 2 * OAL_NUM_BUFFERS);
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_NUM_BUFFERS);
if (nSamples > 0)
{
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
if (iBuffersFilled == 0)
{
alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp);
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, sampleBuffer, nSamples * 4, ulFrequency);
ALenum err = alGetError();
if (err != 0)
{
ERROR_LOG(AUDIO, "Error unqueuing buffers: %08x", err);
}
}
#if defined(__APPLE__)
// OSX does not have the alext AL_FORMAT_51CHN32 yet.
surround_capable = false;
#else
if (surround_capable)
{
// Convert the samples from short to float for the dpl2 decoder
float dest[OAL_MAX_SAMPLES * 2 * OAL_NUM_BUFFERS];
for (u32 i = 0; i < nSamples; ++i)
{
dest[i * 2 + 0] = (float)sampleBuffer[i * 2 + 0] / (1<<16);
dest[i * 2 + 1] = (float)sampleBuffer[i * 2 + 1] / (1<<16);
}
float dpl2[OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_NUM_BUFFERS];
dpl2decode(dest, nSamples, dpl2);
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN32, dpl2, nSamples * SIZE_FLOAT * SURROUND_CHANNELS, ulFrequency);
ALenum err = alGetError();
if (err == AL_INVALID_ENUM)
{
// 5.1 is not supported by the host, fallback to stereo
WARN_LOG(AUDIO, "Unable set 5.1 surround mode. Updating OpenAL Soft might fix this issue.");
surround_capable = false;
}
else if (err != 0)
{
ERROR_LOG(AUDIO, "Error occurred while buffering data: %08x", err);
}
}
#endif
if (!surround_capable)
{
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, sampleBuffer, nSamples * 2 * 2, ulFrequency);
}
alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]);
ALenum err = alGetError();
if (err != 0)
{
ERROR_LOG(AUDIO, "Error queuing buffers: %08x", err);
}
iBuffersFilled++;
if (iBuffersFilled == OAL_NUM_BUFFERS)
{
alSourcePlay(uiSource);
ALenum err = alGetError();
if (err != 0)
{
ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err);
}
}
}
}
else

View File

@ -26,12 +26,14 @@
#ifdef _WIN32
#include <OpenAL/include/al.h>
#include <OpenAL/include/alc.h>
#include <OpenAL/include/alext.h>
#elif defined __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alext.h>
#endif
#include "Core.h"
@ -44,6 +46,8 @@
#define SFX_MAX_SOURCE 1
#define OAL_NUM_BUFFERS 16
#define OAL_MAX_SAMPLES 512
#define SURROUND_CHANNELS 6 // number of channels in surround mode
#define SIZE_FLOAT 4 // size of a float in bytes
#endif
class OpenALStream: public SoundStream
@ -72,7 +76,7 @@ private:
Common::Event mainSyncEvent;
short realtimeBuffer[OAL_MAX_SAMPLES * 2];
soundtouch::SAMPLETYPE sampleBuffer[OAL_MAX_SAMPLES * 2 * OAL_NUM_BUFFERS];
soundtouch::SAMPLETYPE sampleBuffer[OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_NUM_BUFFERS];
ALuint uiBuffers[OAL_NUM_BUFFERS];
ALuint uiSource;
ALfloat fVolume;

View File

@ -227,6 +227,7 @@ void SConfig::SaveSettings()
ini.Set("Core", "Apploader", m_LocalCoreStartupParameter.m_strApploader);
ini.Set("Core", "EnableCheats", m_LocalCoreStartupParameter.bEnableCheats);
ini.Set("Core", "SelectedLanguage", m_LocalCoreStartupParameter.SelectedLanguage);
ini.Set("Core", "DPL2Decoder", m_LocalCoreStartupParameter.bDPL2Decoder);
ini.Set("Core", "MemcardA", m_strMemoryCardA);
ini.Set("Core", "MemcardB", m_strMemoryCardB);
ini.Set("Core", "SlotA", m_EXIDevice[0]);
@ -367,6 +368,7 @@ void SConfig::LoadSettings()
ini.Get("Core", "Apploader", &m_LocalCoreStartupParameter.m_strApploader);
ini.Get("Core", "EnableCheats", &m_LocalCoreStartupParameter.bEnableCheats, false);
ini.Get("Core", "SelectedLanguage", &m_LocalCoreStartupParameter.SelectedLanguage, 0);
ini.Get("Core", "DPL2Decoder", &m_LocalCoreStartupParameter.bDPL2Decoder, true);
ini.Get("Core", "MemcardA", &m_strMemoryCardA);
ini.Get("Core", "MemcardB", &m_strMemoryCardB);
ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD);

View File

@ -49,6 +49,7 @@ SCoreStartupParameter::SCoreStartupParameter()
bEnableCheats(false),
bMergeBlocks(false),
bRunCompareServer(false), bRunCompareClient(false),
bDPL2Decoder(true),
bMMU(false), bMMUBAT(false), iTLBHack(0), bVBeam(false),
bFastDiscSpeed(false),
SelectedLanguage(0), bWii(false), bDisableWiimoteSpeaker(false),
@ -84,6 +85,7 @@ void SCoreStartupParameter::LoadDefaults()
bMergeBlocks = false;
SelectedLanguage = 0;
bWii = false;
bDPL2Decoder = true;
iPosX = 100;
iPosY = 100;

View File

@ -107,6 +107,8 @@ struct SCoreStartupParameter
bool bEnableCheats;
bool bMergeBlocks;
bool bDPL2Decoder;
bool bRunCompareServer;
bool bRunCompareClient;

View File

@ -120,6 +120,7 @@ EVT_RADIOBOX(ID_DSPENGINE, CConfigMain::AudioSettingsChanged)
EVT_CHECKBOX(ID_DSPTHREAD, CConfigMain::AudioSettingsChanged)
EVT_CHECKBOX(ID_ENABLE_THROTTLE, CConfigMain::AudioSettingsChanged)
EVT_CHECKBOX(ID_DUMP_AUDIO, CConfigMain::AudioSettingsChanged)
EVT_CHECKBOX(ID_DPL2DECODER, CConfigMain::AudioSettingsChanged)
EVT_CHOICE(ID_FREQUENCY, CConfigMain::AudioSettingsChanged)
EVT_CHOICE(ID_BACKEND, CConfigMain::AudioSettingsChanged)
EVT_SLIDER(ID_VOLUME, CConfigMain::AudioSettingsChanged)
@ -363,6 +364,7 @@ void CConfigMain::InitializeGUIValues()
VolumeText->SetLabel(wxString::Format(wxT("%d %%"), ac_Config.m_Volume));
DSPThread->SetValue(startup_params.bDSPThread);
DumpAudio->SetValue(ac_Config.m_DumpAudio ? true : false);
DPL2Decoder->SetValue(startup_params.bDPL2Decoder);
FrequencySelection->SetSelection(
FrequencySelection->FindString(wxString::Format(_("%d Hz"), ac_Config.iFrequency)));
// add backends to the list
@ -517,6 +519,14 @@ void CConfigMain::InitializeGUITooltips()
// Wii - Devices
WiiKeyboard->SetToolTip(_("This could cause slow down in Wii Menu and some games."));
#if defined(__APPLE__)
DPL2Decoder->SetToolTip(_("Enables Dolby Pro Logic II emulation using 5.1 surround. Not available on OSX."));
#elif defined(__linux__)
DPL2Decoder->SetToolTip(_("Enables Dolby Pro Logic II emulation using 5.1 surround. OpenAL backend only."));
#elif defined(_WIN32)
DPL2Decoder->SetToolTip(_("Enables Dolby Pro Logic II emulation using 5.1 surround. OpenAL backend only. May need to rename soft_oal.dll to OpenAL32.dll to make it work."));
#endif
}
void CConfigMain::CreateGUIControls()
@ -613,6 +623,7 @@ void CConfigMain::CreateGUIControls()
DSPThread = new wxCheckBox(AudioPage, ID_DSPTHREAD, _("DSP LLE on Thread"));
DumpAudio = new wxCheckBox(AudioPage, ID_DUMP_AUDIO, _("Dump Audio"),
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
DPL2Decoder = new wxCheckBox(AudioPage, ID_DPL2DECODER, _("Dolby Pro Logic II decoder"));
VolumeSlider = new wxSlider(AudioPage, ID_VOLUME, 0, 1, 100,
wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL|wxSL_INVERSE);
VolumeText = new wxStaticText(AudioPage, wxID_ANY, wxT(""),
@ -634,6 +645,7 @@ void CConfigMain::CreateGUIControls()
sbAudioSettings->Add(DSPEngine, 0, wxALL | wxEXPAND, 5);
sbAudioSettings->Add(DSPThread, 0, wxALL, 5);
sbAudioSettings->Add(DumpAudio, 0, wxALL, 5);
sbAudioSettings->Add(DPL2Decoder, 0, wxALL, 5);
wxStaticBoxSizer *sbVolume = new wxStaticBoxSizer(wxVERTICAL, AudioPage, _("Volume"));
sbVolume->Add(VolumeSlider, 1, wxLEFT|wxRIGHT, 13);
@ -927,6 +939,10 @@ void CConfigMain::AudioSettingsChanged(wxCommandEvent& event)
SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPThread = DSPThread->IsChecked();
break;
case ID_DPL2DECODER:
SConfig::GetInstance().m_LocalCoreStartupParameter.bDPL2Decoder = DPL2Decoder->IsChecked();
break;
case ID_BACKEND:
VolumeSlider->Enable(SupportsVolumeChanges(std::string(BackendSelection->GetStringSelection().mb_str())));
ac_Config.sBackend = BackendSelection->GetStringSelection().mb_str();

View File

@ -79,6 +79,7 @@ private:
ID_ENABLE_HLE_AUDIO,
ID_ENABLE_THROTTLE,
ID_DUMP_AUDIO,
ID_DPL2DECODER,
ID_FREQUENCY,
ID_BACKEND,
ID_VOLUME,
@ -157,6 +158,7 @@ private:
wxSlider* VolumeSlider;
wxStaticText* VolumeText;
wxCheckBox* DumpAudio;
wxCheckBox* DPL2Decoder;
wxArrayString wxArrayBackends;
wxChoice* BackendSelection;
wxChoice* FrequencySelection;