mirror of https://github.com/PCSX2/pcsx2.git
SPU2-X: Added audio expansion support to the portaudio backend. This change also corrects the volume in normal stereo mode.
Removed an useless method from the module interfaces. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4858 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
a22b36815c
commit
c0f9d1b619
|
@ -57,7 +57,6 @@ public:
|
||||||
void Close() { }
|
void Close() { }
|
||||||
s32 Test() const { return 0; }
|
s32 Test() const { return 0; }
|
||||||
void Configure(uptr parent) { }
|
void Configure(uptr parent) { }
|
||||||
bool Is51Out() const { return false; }
|
|
||||||
int GetEmptySampleCount() { return 0; }
|
int GetEmptySampleCount() { return 0; }
|
||||||
|
|
||||||
const wchar_t* GetIdent() const
|
const wchar_t* GetIdent() const
|
||||||
|
@ -229,16 +228,21 @@ template<typename T> void SndBuffer::ReadSamples(T* bData)
|
||||||
|
|
||||||
template void SndBuffer::ReadSamples(StereoOut16*);
|
template void SndBuffer::ReadSamples(StereoOut16*);
|
||||||
template void SndBuffer::ReadSamples(StereoOut32*);
|
template void SndBuffer::ReadSamples(StereoOut32*);
|
||||||
|
|
||||||
//template void SndBuffer::ReadSamples(StereoOutFloat*);
|
//template void SndBuffer::ReadSamples(StereoOutFloat*);
|
||||||
template void SndBuffer::ReadSamples(Stereo21Out16*);
|
template void SndBuffer::ReadSamples(Stereo21Out16*);
|
||||||
template void SndBuffer::ReadSamples(StereoQuadOut16*);
|
template void SndBuffer::ReadSamples(Stereo40Out16*);
|
||||||
template void SndBuffer::ReadSamples(Stereo41Out16*);
|
template void SndBuffer::ReadSamples(Stereo41Out16*);
|
||||||
template void SndBuffer::ReadSamples(Stereo51Out16*);
|
template void SndBuffer::ReadSamples(Stereo51Out16*);
|
||||||
template void SndBuffer::ReadSamples(Stereo51Out16DplII*);
|
template void SndBuffer::ReadSamples(Stereo51Out16DplII*);
|
||||||
template void SndBuffer::ReadSamples(Stereo71Out16*);
|
template void SndBuffer::ReadSamples(Stereo71Out16*);
|
||||||
//template void SndBuffer::ReadSamples(Stereo21Out32*);
|
|
||||||
//template void SndBuffer::ReadSamples(Stereo41Out32*);
|
template void SndBuffer::ReadSamples(Stereo20Out32*);
|
||||||
//template void SndBuffer::ReadSamples(Stereo51Out32*);
|
template void SndBuffer::ReadSamples(Stereo21Out32*);
|
||||||
|
template void SndBuffer::ReadSamples(Stereo40Out32*);
|
||||||
|
template void SndBuffer::ReadSamples(Stereo41Out32*);
|
||||||
|
template void SndBuffer::ReadSamples(Stereo51Out32*);
|
||||||
|
template void SndBuffer::ReadSamples(Stereo71Out32*);
|
||||||
|
|
||||||
void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
|
void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,7 @@ static const int SndOutPacketSize = 64;
|
||||||
// downsamples 32 bit samples to 16 bit sound driver output (this way timestretching and
|
// downsamples 32 bit samples to 16 bit sound driver output (this way timestretching and
|
||||||
// DSP effects get better precision results)
|
// DSP effects get better precision results)
|
||||||
static const int SndOutVolumeShift = 12;
|
static const int SndOutVolumeShift = 12;
|
||||||
|
static const int SndOutVolumeShift32 = 16-SndOutVolumeShift; // shift up, not down
|
||||||
|
|
||||||
// Samplerate of the SPU2. For accurate playback we need to match this
|
// Samplerate of the SPU2. For accurate playback we need to match this
|
||||||
// exactly. Trying to scale samplerates and maintain SPU2's Ts timing accuracy
|
// exactly. Trying to scale samplerates and maintain SPU2's Ts timing accuracy
|
||||||
|
@ -111,7 +112,7 @@ struct Stereo21Out16
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StereoQuadOut16
|
struct Stereo40Out16
|
||||||
{
|
{
|
||||||
s16 Left;
|
s16 Left;
|
||||||
s16 Right;
|
s16 Right;
|
||||||
|
@ -127,6 +128,22 @@ struct StereoQuadOut16
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Stereo40Out32
|
||||||
|
{
|
||||||
|
s32 Left;
|
||||||
|
s32 Right;
|
||||||
|
s32 LeftBack;
|
||||||
|
s32 RightBack;
|
||||||
|
|
||||||
|
void ResampleFrom( const StereoOut32& src )
|
||||||
|
{
|
||||||
|
Left = src.Left << SndOutVolumeShift32;
|
||||||
|
Right = src.Right << SndOutVolumeShift32;
|
||||||
|
LeftBack = src.Left << SndOutVolumeShift32;
|
||||||
|
RightBack = src.Right << SndOutVolumeShift32;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Stereo41Out16
|
struct Stereo41Out16
|
||||||
{
|
{
|
||||||
s16 Left;
|
s16 Left;
|
||||||
|
@ -314,11 +331,55 @@ struct Stereo71Out16
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Stereo71Out32
|
||||||
|
{
|
||||||
|
s32 Left;
|
||||||
|
s32 Right;
|
||||||
|
s32 Center;
|
||||||
|
s32 LFE;
|
||||||
|
s32 LeftBack;
|
||||||
|
s32 RightBack;
|
||||||
|
s32 LeftSide;
|
||||||
|
s32 RightSide;
|
||||||
|
|
||||||
|
void ResampleFrom( const StereoOut32& src )
|
||||||
|
{
|
||||||
|
Left = src.Left << SndOutVolumeShift32;
|
||||||
|
Right = src.Right << SndOutVolumeShift32;
|
||||||
|
Center = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
|
||||||
|
LFE = Center;
|
||||||
|
LeftBack = src.Left << SndOutVolumeShift32;
|
||||||
|
RightBack = src.Right << SndOutVolumeShift32;
|
||||||
|
|
||||||
|
LeftSide = src.Left << (SndOutVolumeShift32 - 1);
|
||||||
|
RightSide = src.Right << (SndOutVolumeShift32 - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Stereo20Out32
|
||||||
|
{
|
||||||
|
s32 Left;
|
||||||
|
s32 Right;
|
||||||
|
|
||||||
|
void ResampleFrom( const StereoOut32& src )
|
||||||
|
{
|
||||||
|
Left = src.Left << SndOutVolumeShift32;
|
||||||
|
Right = src.Right << SndOutVolumeShift32;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Stereo21Out32
|
struct Stereo21Out32
|
||||||
{
|
{
|
||||||
s32 Left;
|
s32 Left;
|
||||||
s32 Right;
|
s32 Right;
|
||||||
s32 LFE;
|
s32 LFE;
|
||||||
|
|
||||||
|
void ResampleFrom( const StereoOut32& src )
|
||||||
|
{
|
||||||
|
Left = src.Left << SndOutVolumeShift32;
|
||||||
|
Right = src.Right << SndOutVolumeShift32;
|
||||||
|
LFE = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stereo41Out32
|
struct Stereo41Out32
|
||||||
|
@ -328,6 +389,16 @@ struct Stereo41Out32
|
||||||
s32 LFE;
|
s32 LFE;
|
||||||
s32 LeftBack;
|
s32 LeftBack;
|
||||||
s32 RightBack;
|
s32 RightBack;
|
||||||
|
|
||||||
|
void ResampleFrom( const StereoOut32& src )
|
||||||
|
{
|
||||||
|
Left = src.Left << SndOutVolumeShift32;
|
||||||
|
Right = src.Right << SndOutVolumeShift32;
|
||||||
|
LFE = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
|
||||||
|
|
||||||
|
LeftBack = src.Left << SndOutVolumeShift32;
|
||||||
|
RightBack = src.Right << SndOutVolumeShift32;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stereo51Out32
|
struct Stereo51Out32
|
||||||
|
@ -338,6 +409,16 @@ struct Stereo51Out32
|
||||||
s32 LFE;
|
s32 LFE;
|
||||||
s32 LeftBack;
|
s32 LeftBack;
|
||||||
s32 RightBack;
|
s32 RightBack;
|
||||||
|
|
||||||
|
void ResampleFrom( const StereoOut32& src )
|
||||||
|
{
|
||||||
|
Left = src.Left << SndOutVolumeShift32;
|
||||||
|
Right = src.Right << SndOutVolumeShift32;
|
||||||
|
Center = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
|
||||||
|
LFE = Center;
|
||||||
|
LeftBack = src.Left << SndOutVolumeShift32;
|
||||||
|
RightBack = src.Right << SndOutVolumeShift32;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Developer Note: This is a static class only (all static members).
|
// Developer Note: This is a static class only (all static members).
|
||||||
|
@ -429,9 +510,7 @@ public:
|
||||||
|
|
||||||
// Saves settings to the INI file for this driver
|
// Saves settings to the INI file for this driver
|
||||||
virtual void WriteSettings() const=0;
|
virtual void WriteSettings() const=0;
|
||||||
|
|
||||||
virtual bool Is51Out() const=0;
|
|
||||||
|
|
||||||
// Returns the number of empty samples in the output buffer.
|
// Returns the number of empty samples in the output buffer.
|
||||||
// (which is effectively the amount of data played since the last update)
|
// (which is effectively the amount of data played since the last update)
|
||||||
virtual int GetEmptySampleCount() =0;
|
virtual int GetEmptySampleCount() =0;
|
||||||
|
|
|
@ -59,33 +59,62 @@ private:
|
||||||
int writtenLastTime;
|
int writtenLastTime;
|
||||||
int availableLastTime;
|
int availableLastTime;
|
||||||
|
|
||||||
|
int actualUsedChannels;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
PaStream* stream;
|
PaStream* stream;
|
||||||
|
|
||||||
public:
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
int ActualPaCallback( const void *inputBuffer, void *outputBuffer,
|
// Stuff necessary for speaker expansion
|
||||||
unsigned long framesPerBuffer,
|
class SampleReader
|
||||||
const PaStreamCallbackTimeInfo* timeInfo,
|
|
||||||
PaStreamCallbackFlags statusFlags,
|
|
||||||
void *userData )
|
|
||||||
{
|
{
|
||||||
StereoOut32* p1 = (StereoOut32*)outputBuffer;
|
public:
|
||||||
|
virtual int ReadSamples( const void *inputBuffer, void *outputBuffer,
|
||||||
|
unsigned long framesPerBuffer,
|
||||||
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
|
PaStreamCallbackFlags statusFlags,
|
||||||
|
void *userData ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
int packets = framesPerBuffer / SndOutPacketSize;
|
template<class T>
|
||||||
|
class ConvertedSampleReader : public SampleReader
|
||||||
|
{
|
||||||
|
int* written;
|
||||||
|
public:
|
||||||
|
ConvertedSampleReader(int* pWritten)
|
||||||
|
{
|
||||||
|
written = pWritten;
|
||||||
|
}
|
||||||
|
|
||||||
for(int p=0; p<packets; p++, p1+=SndOutPacketSize )
|
virtual int ReadSamples( const void *inputBuffer, void *outputBuffer,
|
||||||
SndBuffer::ReadSamples( p1 );
|
unsigned long framesPerBuffer,
|
||||||
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
|
PaStreamCallbackFlags statusFlags,
|
||||||
|
void *userData )
|
||||||
|
{
|
||||||
|
T* p1 = (T*)outputBuffer;
|
||||||
|
|
||||||
writtenSoFar += packets * SndOutPacketSize;
|
int packets = framesPerBuffer / SndOutPacketSize;
|
||||||
|
|
||||||
return 0;
|
for(int p=0; p<packets; p++, p1+=SndOutPacketSize )
|
||||||
}
|
SndBuffer::ReadSamples( p1 );
|
||||||
|
|
||||||
|
(*written) += packets * SndOutPacketSize;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
SampleReader* ActualPaCallback;
|
||||||
|
|
||||||
Portaudio()
|
Portaudio()
|
||||||
{
|
{
|
||||||
m_ApiId=-1;
|
m_ApiId=-1;
|
||||||
m_SuggestedLatencyMinimal = true;
|
m_SuggestedLatencyMinimal = true;
|
||||||
m_SuggestedLatencyMS = 20;
|
m_SuggestedLatencyMS = 20;
|
||||||
|
|
||||||
|
actualUsedChannels = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 Init()
|
s32 Init()
|
||||||
|
@ -147,6 +176,57 @@ public:
|
||||||
if(deviceIndex>=0)
|
if(deviceIndex>=0)
|
||||||
{
|
{
|
||||||
void* infoPtr = NULL;
|
void* infoPtr = NULL;
|
||||||
|
|
||||||
|
const PaDeviceInfo * devinfo = Pa_GetDeviceInfo(deviceIndex);
|
||||||
|
const PaHostApiInfo * apiinfo = Pa_GetHostApiInfo(devinfo->hostApi);
|
||||||
|
|
||||||
|
int speakers;
|
||||||
|
switch(numSpeakers) // speakers = (numSpeakers + 1) *2; ?
|
||||||
|
{
|
||||||
|
case 0: speakers = 2; break; // Stereo
|
||||||
|
case 1: speakers = 4; break; // Quadrafonic
|
||||||
|
case 2: speakers = 6; break; // Surround 5.1
|
||||||
|
case 3: speakers = 8; break; // Surround 7.1
|
||||||
|
default: speakers = 2;
|
||||||
|
}
|
||||||
|
actualUsedChannels = devinfo->maxOutputChannels;
|
||||||
|
if(actualUsedChannels > speakers)
|
||||||
|
actualUsedChannels = speakers;
|
||||||
|
|
||||||
|
switch( actualUsedChannels )
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
ConLog( "* SPU2 > Using normal 2 speaker stereo output.\n" );
|
||||||
|
ActualPaCallback = new ConvertedSampleReader<Stereo20Out32>(&writtenSoFar);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
ConLog( "* SPU2 > 2.1 speaker expansion enabled.\n" );
|
||||||
|
ActualPaCallback = new ConvertedSampleReader<Stereo21Out32>(&writtenSoFar);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" );
|
||||||
|
ActualPaCallback = new ConvertedSampleReader<Stereo40Out32>(&writtenSoFar);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
ConLog( "* SPU2 > 4.1 speaker expansion enabled.\n" );
|
||||||
|
ActualPaCallback = new ConvertedSampleReader<Stereo41Out32>(&writtenSoFar);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" );
|
||||||
|
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32>(&writtenSoFar); //"normal" stereo upmix
|
||||||
|
//ActualPaCallback = new ConvertedSampleReader<Stereo51Out32DplII>(&writtenSoFar); //gigas PLII
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // anything 8 or more gets the 7.1 treatment!
|
||||||
|
ConLog( "* SPU2 > 7.1 speaker expansion enabled.\n" );
|
||||||
|
ActualPaCallback = new ConvertedSampleReader<Stereo71Out32>(&writtenSoFar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __WIN32__
|
#ifdef __WIN32__
|
||||||
PaWasapiStreamInfo info = {
|
PaWasapiStreamInfo info = {
|
||||||
|
@ -171,7 +251,7 @@ public:
|
||||||
// PaTime suggestedLatency;
|
// PaTime suggestedLatency;
|
||||||
// void *hostApiSpecificStreamInfo;
|
// void *hostApiSpecificStreamInfo;
|
||||||
deviceIndex,
|
deviceIndex,
|
||||||
2,
|
actualUsedChannels,
|
||||||
paInt32,
|
paInt32,
|
||||||
m_SuggestedLatencyMinimal?(SndOutPacketSize/(float)SampleRate):(m_SuggestedLatencyMS/1000.0f),
|
m_SuggestedLatencyMinimal?(SndOutPacketSize/(float)SampleRate):(m_SuggestedLatencyMS/1000.0f),
|
||||||
infoPtr
|
infoPtr
|
||||||
|
@ -188,7 +268,7 @@ public:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = Pa_OpenDefaultStream( &stream,
|
err = Pa_OpenDefaultStream( &stream,
|
||||||
0, 2, paInt32, 48000,
|
0, actualUsedChannels, paInt32, 48000,
|
||||||
SndOutPacketSize,
|
SndOutPacketSize,
|
||||||
PaCallback,
|
PaCallback,
|
||||||
NULL );
|
NULL );
|
||||||
|
@ -455,9 +535,7 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual bool Is51Out() const { return false; }
|
|
||||||
|
|
||||||
s32 Test() const
|
s32 Test() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -564,7 +642,7 @@ int PaCallback( const void *inputBuffer, void *outputBuffer,
|
||||||
PaStreamCallbackFlags statusFlags,
|
PaStreamCallbackFlags statusFlags,
|
||||||
void *userData )
|
void *userData )
|
||||||
{
|
{
|
||||||
return PA.ActualPaCallback(inputBuffer,outputBuffer,framesPerBuffer,timeInfo,statusFlags,userData);
|
return PA.ActualPaCallback->ReadSamples(inputBuffer,outputBuffer,framesPerBuffer,timeInfo,statusFlags,userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
|
@ -421,9 +421,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool Is51Out() const { return false; }
|
|
||||||
|
|
||||||
s32 Test() const
|
s32 Test() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -306,7 +306,7 @@ public:
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" );
|
ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" );
|
||||||
voiceContext = new StreamingVoice<StereoQuadOut16>( pXAudio2 );
|
voiceContext = new StreamingVoice<Stereo40Out16>( pXAudio2 );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
|
@ -367,9 +367,7 @@ public:
|
||||||
virtual void Configure(uptr parent)
|
virtual void Configure(uptr parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool Is51Out() const { return false; }
|
|
||||||
|
|
||||||
s32 Test() const
|
s32 Test() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -280,9 +280,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool Is51Out() const { return false; }
|
|
||||||
|
|
||||||
s32 Test() const
|
s32 Test() const
|
||||||
{
|
{
|
||||||
if (waveOutGetNumDevs() == 0) {
|
if (waveOutGetNumDevs() == 0) {
|
||||||
|
|
Loading…
Reference in New Issue