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() { }
s32 Test() const { return 0; }
void Configure(uptr parent) { }
bool Is51Out() const { return false; }
int GetEmptySampleCount() { return 0; }
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(StereoOut32*);
//template void SndBuffer::ReadSamples(StereoOutFloat*);
template void SndBuffer::ReadSamples(Stereo21Out16*);
template void SndBuffer::ReadSamples(StereoQuadOut16*);
template void SndBuffer::ReadSamples(Stereo40Out16*);
template void SndBuffer::ReadSamples(Stereo41Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16DplII*);
template void SndBuffer::ReadSamples(Stereo71Out16*);
//template void SndBuffer::ReadSamples(Stereo21Out32*);
//template void SndBuffer::ReadSamples(Stereo41Out32*);
//template void SndBuffer::ReadSamples(Stereo51Out32*);
template void SndBuffer::ReadSamples(Stereo20Out32*);
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)
{

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
// DSP effects get better precision results)
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
// 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 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
{
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
{
s32 Left;
s32 Right;
s32 LFE;
void ResampleFrom( const StereoOut32& src )
{
Left = src.Left << SndOutVolumeShift32;
Right = src.Right << SndOutVolumeShift32;
LFE = (src.Left + src.Right) << (SndOutVolumeShift32 - 1);
}
};
struct Stereo41Out32
@ -328,6 +389,16 @@ struct Stereo41Out32
s32 LFE;
s32 LeftBack;
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
@ -338,6 +409,16 @@ struct Stereo51Out32
s32 LFE;
s32 LeftBack;
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).
@ -429,9 +510,7 @@ public:
// Saves settings to the INI file for this driver
virtual void WriteSettings() const=0;
virtual bool Is51Out() const=0;
// Returns the number of empty samples in the output buffer.
// (which is effectively the amount of data played since the last update)
virtual int GetEmptySampleCount() =0;

View File

@ -59,33 +59,62 @@ private:
int writtenLastTime;
int availableLastTime;
int actualUsedChannels;
bool started;
PaStream* stream;
public:
int ActualPaCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
//////////////////////////////////////////////////////////////////////////////////////////
// Stuff necessary for speaker expansion
class SampleReader
{
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 )
SndBuffer::ReadSamples( p1 );
virtual int ReadSamples( const void *inputBuffer, void *outputBuffer,
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()
{
m_ApiId=-1;
m_SuggestedLatencyMinimal = true;
m_SuggestedLatencyMS = 20;
actualUsedChannels = 0;
}
s32 Init()
@ -147,6 +176,57 @@ public:
if(deviceIndex>=0)
{
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__
PaWasapiStreamInfo info = {
@ -171,7 +251,7 @@ public:
// PaTime suggestedLatency;
// void *hostApiSpecificStreamInfo;
deviceIndex,
2,
actualUsedChannels,
paInt32,
m_SuggestedLatencyMinimal?(SndOutPacketSize/(float)SampleRate):(m_SuggestedLatencyMS/1000.0f),
infoPtr
@ -188,7 +268,7 @@ public:
else
{
err = Pa_OpenDefaultStream( &stream,
0, 2, paInt32, 48000,
0, actualUsedChannels, paInt32, 48000,
SndOutPacketSize,
PaCallback,
NULL );
@ -455,9 +535,7 @@ public:
{
}
#endif
virtual bool Is51Out() const { return false; }
s32 Test() const
{
return 0;
@ -564,7 +642,7 @@ int PaCallback( const void *inputBuffer, void *outputBuffer,
PaStreamCallbackFlags statusFlags,
void *userData )
{
return PA.ActualPaCallback(inputBuffer,outputBuffer,framesPerBuffer,timeInfo,statusFlags,userData);
return PA.ActualPaCallback->ReadSamples(inputBuffer,outputBuffer,framesPerBuffer,timeInfo,statusFlags,userData);
}
#ifdef WIN32

View File

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

View File

@ -306,7 +306,7 @@ public:
case 4:
ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" );
voiceContext = new StreamingVoice<StereoQuadOut16>( pXAudio2 );
voiceContext = new StreamingVoice<Stereo40Out16>( pXAudio2 );
break;
case 5:
@ -367,9 +367,7 @@ public:
virtual void Configure(uptr parent)
{
}
virtual bool Is51Out() const { return false; }
s32 Test() const
{
return 0;

View File

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