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:
gigaherz 2011-08-10 13:17:41 +00:00
parent a22b36815c
commit c0f9d1b619
6 changed files with 194 additions and 39 deletions

View File

@ -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)
{ {

View File

@ -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;

View File

@ -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

View File

@ -421,9 +421,7 @@ public:
return; return;
} }
} }
virtual bool Is51Out() const { return false; }
s32 Test() const s32 Test() const
{ {
return 0; return 0;

View File

@ -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;

View File

@ -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) {