diff --git a/plugins/spu2-x/src/SndOut.cpp b/plugins/spu2-x/src/SndOut.cpp index ac23f10140..fa744ce4ea 100644 --- a/plugins/spu2-x/src/SndOut.cpp +++ b/plugins/spu2-x/src/SndOut.cpp @@ -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 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) { diff --git a/plugins/spu2-x/src/SndOut.h b/plugins/spu2-x/src/SndOut.h index 9ba5bfa542..926dd1134d 100644 --- a/plugins/spu2-x/src/SndOut.h +++ b/plugins/spu2-x/src/SndOut.h @@ -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; diff --git a/plugins/spu2-x/src/SndOut_Portaudio.cpp b/plugins/spu2-x/src/SndOut_Portaudio.cpp index 81d8470f33..d74a4c257e 100644 --- a/plugins/spu2-x/src/SndOut_Portaudio.cpp +++ b/plugins/spu2-x/src/SndOut_Portaudio.cpp @@ -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 ConvertedSampleReader : public SampleReader + { + int* written; + public: + ConvertedSampleReader(int* pWritten) + { + written = pWritten; + } - for(int p=0; p=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(&writtenSoFar); + break; + + case 3: + ConLog( "* SPU2 > 2.1 speaker expansion enabled.\n" ); + ActualPaCallback = new ConvertedSampleReader(&writtenSoFar); + break; + + case 4: + ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" ); + ActualPaCallback = new ConvertedSampleReader(&writtenSoFar); + break; + + case 5: + ConLog( "* SPU2 > 4.1 speaker expansion enabled.\n" ); + ActualPaCallback = new ConvertedSampleReader(&writtenSoFar); + break; + + case 6: + case 7: + ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" ); + ActualPaCallback = new ConvertedSampleReader(&writtenSoFar); //"normal" stereo upmix + //ActualPaCallback = new ConvertedSampleReader(&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(&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 diff --git a/plugins/spu2-x/src/Windows/SndOut_DSound.cpp b/plugins/spu2-x/src/Windows/SndOut_DSound.cpp index 0d68bb9474..4b1485b204 100644 --- a/plugins/spu2-x/src/Windows/SndOut_DSound.cpp +++ b/plugins/spu2-x/src/Windows/SndOut_DSound.cpp @@ -421,9 +421,7 @@ public: return; } } - - virtual bool Is51Out() const { return false; } - + s32 Test() const { return 0; diff --git a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp index aef73db26a..b69868b3fc 100644 --- a/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp +++ b/plugins/spu2-x/src/Windows/SndOut_XAudio2.cpp @@ -306,7 +306,7 @@ public: case 4: ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" ); - voiceContext = new StreamingVoice( pXAudio2 ); + voiceContext = new StreamingVoice( 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; diff --git a/plugins/spu2-x/src/Windows/SndOut_waveOut.cpp b/plugins/spu2-x/src/Windows/SndOut_waveOut.cpp index 45817ee5aa..7ae1078956 100644 --- a/plugins/spu2-x/src/Windows/SndOut_waveOut.cpp +++ b/plugins/spu2-x/src/Windows/SndOut_waveOut.cpp @@ -280,9 +280,7 @@ public: return; } } - - virtual bool Is51Out() const { return false; } - + s32 Test() const { if (waveOutGetNumDevs() == 0) {