summaryrefslogtreecommitdiff
path: root/engine/audio/private/snd_dev_direct.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/audio/private/snd_dev_direct.cpp')
-rw-r--r--engine/audio/private/snd_dev_direct.cpp2094
1 files changed, 2094 insertions, 0 deletions
diff --git a/engine/audio/private/snd_dev_direct.cpp b/engine/audio/private/snd_dev_direct.cpp
new file mode 100644
index 0000000..9149964
--- /dev/null
+++ b/engine/audio/private/snd_dev_direct.cpp
@@ -0,0 +1,2094 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=====================================================================================//
+
+#include "audio_pch.h"
+#include <dsound.h>
+#pragma warning(disable : 4201) // nameless struct/union
+#include <ks.h>
+// Fix for VS 2010 build errors copied from Dota
+#if !defined( NEW_DXSDK ) && ( _MSC_VER >= 1600 )
+#undef KSDATAFORMAT_SUBTYPE_WAVEFORMATEX
+#undef KSDATAFORMAT_SUBTYPE_PCM
+#undef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
+#endif
+#include <ksmedia.h>
+#include "iprediction.h"
+#include "eax.h"
+#include "tier0/icommandline.h"
+#include "video//ivideoservices.h"
+#include "../../sys_dll.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern bool snd_firsttime;
+
+extern void DEBUG_StartSoundMeasure(int type, int samplecount );
+extern void DEBUG_StopSoundMeasure(int type, int samplecount );
+
+// legacy support
+extern ConVar sxroom_off;
+extern ConVar sxroom_type;
+extern ConVar sxroomwater_type;
+extern float sxroom_typeprev;
+
+extern HWND* pmainwindow;
+
+typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
+
+#define SECONDARY_BUFFER_SIZE 0x10000 // output buffer size in bytes
+#define SECONDARY_BUFFER_SIZE_SURROUND 0x04000 // output buffer size in bytes, one per channel
+
+#if !defined( NEW_DXSDK )
+// hack - need to include latest dsound.h
+#undef DSSPEAKER_5POINT1
+#undef DSSPEAKER_7POINT1
+#define DSSPEAKER_5POINT1 6
+#define DSSPEAKER_7POINT1 7
+#define DSSPEAKER_7POINT1_SURROUND 8
+#define DSSPEAKER_5POINT1_SURROUND 9
+#endif
+
+HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
+
+extern void ReleaseSurround(void);
+extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );
+void OnSndSurroundCvarChanged( IConVar *var, const char *pOldString, float flOldValue );
+void OnSndSurroundLegacyChanged( IConVar *var, const char *pOldString, float flOldValue );
+void OnSndVarChanged( IConVar *var, const char *pOldString, float flOldValue );
+
+static LPDIRECTSOUND pDS = NULL;
+static LPDIRECTSOUNDBUFFER pDSBuf = NULL, pDSPBuf = NULL;
+
+static GUID IID_IDirectSound3DBufferDef = {0x279AFA86, 0x4981, 0x11CE, {0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}};
+static ConVar windows_speaker_config("windows_speaker_config", "-1", FCVAR_ARCHIVE);
+static DWORD g_ForcedSpeakerConfig = 0;
+
+extern ConVar snd_mute_losefocus;
+
+//-----------------------------------------------------------------------------
+// Purpose: Implementation of direct sound
+//-----------------------------------------------------------------------------
+class CAudioDirectSound : public CAudioDeviceBase
+{
+public:
+ ~CAudioDirectSound( void );
+ bool IsActive( void ) { return true; }
+ bool Init( void );
+ void Shutdown( void );
+ void Pause( void );
+ void UnPause( void );
+ float MixDryVolume( void );
+ bool Should3DMix( void );
+ void StopAllSounds( void );
+
+ int PaintBegin( float mixAheadTime, int soundtime, int paintedtime );
+ void PaintEnd( void );
+
+ int GetOutputPosition( void );
+ void ClearBuffer( void );
+ void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
+
+ void ChannelReset( int entnum, int channelIndex, float distanceMod );
+ void TransferSamples( int end );
+
+ const char *DeviceName( void );
+ int DeviceChannels( void ) { return m_deviceChannels; }
+ int DeviceSampleBits( void ) { return m_deviceSampleBits; }
+ int DeviceSampleBytes( void ) { return m_deviceSampleBits/8; }
+ int DeviceDmaSpeed( void ) { return m_deviceDmaSpeed; }
+ int DeviceSampleCount( void ) { return m_deviceSampleCount; }
+
+ bool IsInterleaved() { return m_isInterleaved; }
+
+ // Singleton object
+ static CAudioDirectSound *m_pSingleton;
+
+private:
+ void DetectWindowsSpeakerSetup();
+ bool LockDSBuffer( LPDIRECTSOUNDBUFFER pBuffer, DWORD **pdwWriteBuffer, DWORD *pdwSizeBuffer, const char *pBufferName, int lockFlags = 0 );
+ bool IsUsingBufferPerSpeaker();
+
+ sndinitstat SNDDMA_InitDirect( void );
+ bool SNDDMA_InitInterleaved( LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, int channelCount );
+ bool SNDDMA_InitSurround(LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, DSBCAPS* lpdsbc, int cchan);
+ void S_TransferSurround16( portable_samplepair_t *pfront, portable_samplepair_t *prear, portable_samplepair_t *pcenter, int lpaintedtime, int endtime, int cchan);
+ void S_TransferSurround16Interleaved( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int lpaintedtime, int endtime);
+ void S_TransferSurround16Interleaved_FullLock( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int lpaintedtime, int endtime);
+
+ int m_deviceChannels; // channels per hardware output buffer (1 for quad/5.1, 2 for stereo)
+ int m_deviceSampleBits; // bits per sample (16)
+ int m_deviceSampleCount; // count of mono samples in output buffer
+ int m_deviceDmaSpeed; // samples per second per output buffer
+ int m_bufferSizeBytes; // size of a single hardware output buffer, in bytes
+
+ DWORD m_outputBufferStartOffset; // output buffer playback starting byte offset
+ HINSTANCE m_hInstDS;
+ bool m_isInterleaved;
+};
+
+CAudioDirectSound *CAudioDirectSound::m_pSingleton = NULL;
+
+LPDIRECTSOUNDBUFFER pDSBufFL = NULL;
+LPDIRECTSOUNDBUFFER pDSBufFR = NULL;
+LPDIRECTSOUNDBUFFER pDSBufRL = NULL;
+LPDIRECTSOUNDBUFFER pDSBufRR = NULL;
+LPDIRECTSOUNDBUFFER pDSBufFC = NULL;
+LPDIRECTSOUND3DBUFFER pDSBuf3DFL = NULL;
+LPDIRECTSOUND3DBUFFER pDSBuf3DFR = NULL;
+LPDIRECTSOUND3DBUFFER pDSBuf3DRL = NULL;
+LPDIRECTSOUND3DBUFFER pDSBuf3DRR = NULL;
+LPDIRECTSOUND3DBUFFER pDSBuf3DFC = NULL;
+
+// ----------------------------------------------------------------------------- //
+// Helpers.
+// ----------------------------------------------------------------------------- //
+
+
+CAudioDirectSound::~CAudioDirectSound( void )
+{
+ m_pSingleton = NULL;
+}
+
+bool CAudioDirectSound::Init( void )
+{
+ m_hInstDS = NULL;
+
+ static bool first = true;
+ if ( first )
+ {
+ snd_surround.InstallChangeCallback( &OnSndSurroundCvarChanged );
+ snd_legacy_surround.InstallChangeCallback( &OnSndSurroundLegacyChanged );
+ snd_mute_losefocus.InstallChangeCallback( &OnSndVarChanged );
+ first = false;
+ }
+
+ if ( SNDDMA_InitDirect() == SIS_SUCCESS)
+ {
+ if ( g_pVideo != NULL )
+ {
+ g_pVideo->SoundDeviceCommand( VideoSoundDeviceOperation::SET_DIRECT_SOUND_DEVICE, pDS );
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void CAudioDirectSound::Shutdown( void )
+{
+ ReleaseSurround();
+
+ if (pDSBuf)
+ {
+ pDSBuf->Stop();
+ pDSBuf->Release();
+ }
+
+ // only release primary buffer if it's not also the mixing buffer we just released
+ if (pDSPBuf && (pDSBuf != pDSPBuf))
+ {
+ pDSPBuf->Release();
+ }
+
+ if (pDS)
+ {
+ pDS->SetCooperativeLevel(*pmainwindow, DSSCL_NORMAL);
+ pDS->Release();
+ }
+
+ pDS = NULL;
+ pDSBuf = NULL;
+ pDSPBuf = NULL;
+
+ if ( m_hInstDS )
+ {
+ FreeLibrary( m_hInstDS );
+ m_hInstDS = NULL;
+ }
+
+ if ( this == CAudioDirectSound::m_pSingleton )
+ {
+ CAudioDirectSound::m_pSingleton = NULL;
+ }
+}
+
+// Total number of samples that have played out to hardware
+// for current output buffer (ie: from buffer offset start).
+// return playback position within output playback buffer:
+// the output units are dependant on the device channels
+// so the ouput units for a 2 channel device are as 16 bit LR pairs
+// and the output unit for a 1 channel device are as 16 bit mono samples.
+// take into account the original start position within the buffer, and
+// calculate difference between current position (with buffer wrap) and
+// start position.
+int CAudioDirectSound::GetOutputPosition( void )
+{
+ int samp16;
+ int start, current;
+ DWORD dwCurrent;
+
+ // get size in bytes of output buffer
+ const int size_bytes = m_bufferSizeBytes;
+ if ( IsUsingBufferPerSpeaker() )
+ {
+ // mono output buffers
+ // get byte offset of playback cursor in Front Left output buffer
+ pDSBufFL->GetCurrentPosition(&dwCurrent, NULL);
+
+ start = (int) m_outputBufferStartOffset;
+ current = (int) dwCurrent;
+ }
+ else
+ {
+ // multi-channel interleavd output buffer
+ // get byte offset of playback cursor in output buffer
+ pDSBuf->GetCurrentPosition(&dwCurrent, NULL);
+
+ start = (int) m_outputBufferStartOffset;
+ current = (int) dwCurrent;
+ }
+
+ // get 16 bit samples played, relative to buffer starting offset
+ if (current > start)
+ {
+ // get difference & convert to 16 bit mono samples
+ samp16 = (current - start) >> SAMPLE_16BIT_SHIFT;
+ }
+ else
+ {
+ // get difference (with buffer wrap) convert to 16 bit mono samples
+ samp16 = ((size_bytes - start) + current) >> SAMPLE_16BIT_SHIFT;
+ }
+
+ int outputPosition = samp16 / DeviceChannels();
+
+ return outputPosition;
+}
+
+void CAudioDirectSound::Pause( void )
+{
+ if (pDSBuf)
+ {
+ pDSBuf->Stop();
+ }
+
+ if ( pDSBufFL ) pDSBufFL->Stop();
+ if ( pDSBufFR ) pDSBufFR->Stop();
+ if ( pDSBufRL ) pDSBufRL->Stop();
+ if ( pDSBufRR ) pDSBufRR->Stop();
+ if ( pDSBufFC ) pDSBufFC->Stop();
+}
+
+
+void CAudioDirectSound::UnPause( void )
+{
+ if (pDSBuf)
+ pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
+
+ if (pDSBufFL) pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
+ if (pDSBufFR) pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
+ if (pDSBufRL) pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
+ if (pDSBufRR) pDSBufRR->Play( 0, 0, DSBPLAY_LOOPING);
+ if (pDSBufFC) pDSBufFC->Play( 0, 0, DSBPLAY_LOOPING);
+}
+
+
+float CAudioDirectSound::MixDryVolume( void )
+{
+ return 0;
+}
+
+
+bool CAudioDirectSound::Should3DMix( void )
+{
+ if ( m_bSurround )
+ return true;
+ return false;
+}
+
+
+IAudioDevice *Audio_CreateDirectSoundDevice( void )
+{
+ if ( !CAudioDirectSound::m_pSingleton )
+ CAudioDirectSound::m_pSingleton = new CAudioDirectSound;
+
+ if ( CAudioDirectSound::m_pSingleton->Init() )
+ {
+ if (snd_firsttime)
+ DevMsg ("DirectSound initialized\n");
+
+ return CAudioDirectSound::m_pSingleton;
+ }
+
+ DevMsg ("DirectSound failed to init\n");
+
+ delete CAudioDirectSound::m_pSingleton;
+ CAudioDirectSound::m_pSingleton = NULL;
+
+ return NULL;
+}
+
+int CAudioDirectSound::PaintBegin( float mixAheadTime, int soundtime, int lpaintedtime )
+{
+ // soundtime - total full samples that have been played out to hardware at dmaspeed
+ // paintedtime - total full samples that have been mixed at speed
+ // endtime - target for full samples in mixahead buffer at speed
+ // samps - size of output buffer in full samples
+
+ int mixaheadtime = mixAheadTime * DeviceDmaSpeed();
+ int endtime = soundtime + mixaheadtime;
+
+ if ( endtime <= lpaintedtime )
+ return endtime;
+
+ uint nSamples = endtime - lpaintedtime;
+ if ( nSamples & 0x3 )
+ {
+ // The difference between endtime and painted time should align on
+ // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
+ nSamples += (4 - (nSamples & 3));
+ }
+ // clamp to min 512 samples per mix
+ if ( nSamples > 0 && nSamples < 512 )
+ {
+ nSamples = 512;
+ }
+ endtime = lpaintedtime + nSamples;
+
+ int fullsamps = DeviceSampleCount() / DeviceChannels();
+ if ( (endtime - soundtime) > fullsamps)
+ {
+ endtime = soundtime + fullsamps;
+ endtime += (4 - (endtime & 3));
+ }
+
+ DWORD dwStatus;
+
+ // If using surround, there are 4 or 5 different buffers being used and the pDSBuf is NULL.
+ if ( IsUsingBufferPerSpeaker() )
+ {
+ if (pDSBufFL->GetStatus(&dwStatus) != DS_OK)
+ Msg ("Couldn't get SURROUND FL sound buffer status\n");
+
+ if (dwStatus & DSBSTATUS_BUFFERLOST)
+ pDSBufFL->Restore();
+
+ if (!(dwStatus & DSBSTATUS_PLAYING))
+ pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
+
+ if (pDSBufFR->GetStatus(&dwStatus) != DS_OK)
+ Msg ("Couldn't get SURROUND FR sound buffer status\n");
+
+ if (dwStatus & DSBSTATUS_BUFFERLOST)
+ pDSBufFR->Restore();
+
+ if (!(dwStatus & DSBSTATUS_PLAYING))
+ pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
+
+ if (pDSBufRL->GetStatus(&dwStatus) != DS_OK)
+ Msg ("Couldn't get SURROUND RL sound buffer status\n");
+
+ if (dwStatus & DSBSTATUS_BUFFERLOST)
+ pDSBufRL->Restore();
+
+ if (!(dwStatus & DSBSTATUS_PLAYING))
+ pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
+
+ if (pDSBufRR->GetStatus(&dwStatus) != DS_OK)
+ Msg ("Couldn't get SURROUND RR sound buffer status\n");
+
+ if (dwStatus & DSBSTATUS_BUFFERLOST)
+ pDSBufRR->Restore();
+
+ if (!(dwStatus & DSBSTATUS_PLAYING))
+ pDSBufRR->Play(0, 0, DSBPLAY_LOOPING);
+
+ if ( m_bSurroundCenter )
+ {
+ if (pDSBufFC->GetStatus(&dwStatus) != DS_OK)
+ Msg ("Couldn't get SURROUND FC sound buffer status\n");
+
+ if (dwStatus & DSBSTATUS_BUFFERLOST)
+ pDSBufFC->Restore();
+
+ if (!(dwStatus & DSBSTATUS_PLAYING))
+ pDSBufFC->Play(0, 0, DSBPLAY_LOOPING);
+ }
+ }
+ else if (pDSBuf)
+ {
+ if ( pDSBuf->GetStatus (&dwStatus) != DS_OK )
+ Msg("Couldn't get sound buffer status\n");
+
+ if ( dwStatus & DSBSTATUS_BUFFERLOST )
+ pDSBuf->Restore();
+
+ if ( !(dwStatus & DSBSTATUS_PLAYING) )
+ pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
+ }
+
+ return endtime;
+}
+
+
+void CAudioDirectSound::PaintEnd( void )
+{
+}
+
+
+void CAudioDirectSound::ClearBuffer( void )
+{
+ int clear;
+
+ DWORD dwSizeFL, dwSizeFR, dwSizeRL, dwSizeRR, dwSizeFC;
+ char *pDataFL, *pDataFR, *pDataRL, *pDataRR, *pDataFC;
+
+ dwSizeFC = 0; // compiler warning
+ pDataFC = NULL;
+
+ if ( IsUsingBufferPerSpeaker() )
+ {
+ int SURROUNDreps;
+ HRESULT SURROUNDhresult;
+ SURROUNDreps = 0;
+
+ if ( !pDSBufFL && !pDSBufFR && !pDSBufRL && !pDSBufRR && !pDSBufFC )
+ return;
+
+ while ((SURROUNDhresult = pDSBufFL->Lock(0, m_bufferSizeBytes, (void**)&pDataFL, &dwSizeFL, NULL, NULL, 0)) != DS_OK)
+ {
+ if (SURROUNDhresult != DSERR_BUFFERLOST)
+ {
+ Msg ("S_ClearBuffer: DS::Lock FL Sound Buffer Failed\n");
+ S_Shutdown ();
+ return;
+ }
+
+ if (++SURROUNDreps > 10000)
+ {
+ Msg ("S_ClearBuffer: DS: couldn't restore FL buffer\n");
+ S_Shutdown ();
+ return;
+ }
+ }
+
+ SURROUNDreps = 0;
+ while ((SURROUNDhresult = pDSBufFR->Lock(0, m_bufferSizeBytes, (void**)&pDataFR, &dwSizeFR, NULL, NULL, 0)) != DS_OK)
+ {
+ if (SURROUNDhresult != DSERR_BUFFERLOST)
+ {
+ Msg ("S_ClearBuffer: DS::Lock FR Sound Buffer Failed\n");
+ S_Shutdown ();
+ return;
+ }
+
+ if (++SURROUNDreps > 10000)
+ {
+ Msg ("S_ClearBuffer: DS: couldn't restore FR buffer\n");
+ S_Shutdown ();
+ return;
+ }
+ }
+
+ SURROUNDreps = 0;
+ while ((SURROUNDhresult = pDSBufRL->Lock(0, m_bufferSizeBytes, (void**)&pDataRL, &dwSizeRL, NULL, NULL, 0)) != DS_OK)
+ {
+ if (SURROUNDhresult != DSERR_BUFFERLOST)
+ {
+ Msg ("S_ClearBuffer: DS::Lock RL Sound Buffer Failed\n");
+ S_Shutdown ();
+ return;
+ }
+
+ if (++SURROUNDreps > 10000)
+ {
+ Msg ("S_ClearBuffer: DS: couldn't restore RL buffer\n");
+ S_Shutdown ();
+ return;
+ }
+ }
+
+ SURROUNDreps = 0;
+ while ((SURROUNDhresult = pDSBufRR->Lock(0, m_bufferSizeBytes, (void**)&pDataRR, &dwSizeRR, NULL, NULL, 0)) != DS_OK)
+ {
+ if (SURROUNDhresult != DSERR_BUFFERLOST)
+ {
+ Msg ("S_ClearBuffer: DS::Lock RR Sound Buffer Failed\n");
+ S_Shutdown ();
+ return;
+ }
+
+ if (++SURROUNDreps > 10000)
+ {
+ Msg ("S_ClearBuffer: DS: couldn't restore RR buffer\n");
+ S_Shutdown ();
+ return;
+ }
+ }
+
+ if (m_bSurroundCenter)
+ {
+ SURROUNDreps = 0;
+ while ((SURROUNDhresult = pDSBufFC->Lock(0, m_bufferSizeBytes, (void**)&pDataFC, &dwSizeFC, NULL, NULL, 0)) != DS_OK)
+ {
+ if (SURROUNDhresult != DSERR_BUFFERLOST)
+ {
+ Msg ("S_ClearBuffer: DS::Lock FC Sound Buffer Failed\n");
+ S_Shutdown ();
+ return;
+ }
+
+ if (++SURROUNDreps > 10000)
+ {
+ Msg ("S_ClearBuffer: DS: couldn't restore FC buffer\n");
+ S_Shutdown ();
+ return;
+ }
+ }
+ }
+
+ Q_memset(pDataFL, 0, m_bufferSizeBytes);
+ Q_memset(pDataFR, 0, m_bufferSizeBytes);
+ Q_memset(pDataRL, 0, m_bufferSizeBytes);
+ Q_memset(pDataRR, 0, m_bufferSizeBytes);
+
+ if (m_bSurroundCenter)
+ Q_memset(pDataFC, 0, m_bufferSizeBytes);
+
+ pDSBufFL->Unlock(pDataFL, dwSizeFL, NULL, 0);
+ pDSBufFR->Unlock(pDataFR, dwSizeFR, NULL, 0);
+ pDSBufRL->Unlock(pDataRL, dwSizeRL, NULL, 0);
+ pDSBufRR->Unlock(pDataRR, dwSizeRR, NULL, 0);
+
+ if (m_bSurroundCenter)
+ pDSBufFC->Unlock(pDataFC, dwSizeFC, NULL, 0);
+
+ return;
+ }
+
+ if ( !pDSBuf )
+ return;
+
+ if ( DeviceSampleBits() == 8 )
+ clear = 0x80;
+ else
+ clear = 0;
+
+ if (pDSBuf)
+ {
+ DWORD dwSize;
+ DWORD *pData;
+ int reps;
+ HRESULT hresult;
+
+ reps = 0;
+ while ((hresult = pDSBuf->Lock(0, m_bufferSizeBytes, (void**)&pData, &dwSize, NULL, NULL, 0)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST)
+ {
+ Msg("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");
+ S_Shutdown();
+ return;
+ }
+
+ if (++reps > 10000)
+ {
+ Msg("S_ClearBuffer: DS: couldn't restore buffer\n");
+ S_Shutdown();
+ return;
+ }
+ }
+
+ Q_memset(pData, clear, dwSize);
+
+ pDSBuf->Unlock(pData, dwSize, NULL, 0);
+ }
+}
+
+void CAudioDirectSound::StopAllSounds( void )
+{
+}
+
+bool CAudioDirectSound::SNDDMA_InitInterleaved( LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, int channelCount )
+{
+ WAVEFORMATEXTENSIBLE wfx = { 0 } ; // DirectSoundBuffer wave format (extensible)
+
+ // set the channel mask and number of channels based on the command line parameter
+ if(channelCount == 2)
+ {
+ wfx.Format.nChannels = 2;
+ wfx.dwChannelMask = KSAUDIO_SPEAKER_STEREO; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
+ }
+ else if(channelCount == 4)
+ {
+ wfx.Format.nChannels = 4;
+ wfx.dwChannelMask = KSAUDIO_SPEAKER_QUAD; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
+ }
+ else if(channelCount == 6)
+ {
+ wfx.Format.nChannels = 6;
+ wfx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
+ }
+ else
+ {
+ return false;
+ }
+
+ // setup the extensible structure
+ wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ //wfx.Format.nChannels = SET ABOVE
+ wfx.Format.nSamplesPerSec = lpFormat->nSamplesPerSec;
+ wfx.Format.wBitsPerSample = lpFormat->wBitsPerSample;
+ wfx.Format.nBlockAlign = wfx.Format.wBitsPerSample / 8 * wfx.Format.nChannels;
+ wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
+ wfx.Format.cbSize = 22; // size from after this to end of extensible struct. sizeof(WORD + DWORD + GUID)
+ wfx.Samples.wValidBitsPerSample = lpFormat->wBitsPerSample;
+ //wfx.dwChannelMask = SET ABOVE BASED ON COMMAND LINE PARAMETERS
+ wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+
+ // setup the DirectSound
+ DSBUFFERDESC dsbdesc = { 0 }; // DirectSoundBuffer descriptor
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = 0;
+
+ dsbdesc.dwBufferBytes = SECONDARY_BUFFER_SIZE_SURROUND * channelCount;
+
+ dsbdesc.lpwfxFormat = (WAVEFORMATEX*)&wfx;
+ bool bSuccess = false;
+ for ( int i = 0; i < 3; i++ )
+ {
+ switch(i)
+ {
+ case 0:
+ dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE;
+ break;
+ case 1:
+ dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE;
+ break;
+ case 2:
+ dsbdesc.dwFlags = 0;
+ break;
+ }
+ if ( !snd_mute_losefocus.GetBool() )
+ {
+ dsbdesc.dwFlags |= DSBCAPS_GLOBALFOCUS;
+ }
+
+ if(!FAILED(lpDS->CreateSoundBuffer(&dsbdesc, &pDSBuf, NULL)))
+ {
+ bSuccess = true;
+ break;
+ }
+ }
+ if ( !bSuccess )
+ return false;
+
+ DWORD dwSize = 0, dwWrite;
+ DWORD *pBuffer = 0;
+ if ( !LockDSBuffer( pDSBuf, &pBuffer, &dwSize, "DS_INTERLEAVED", DSBLOCK_ENTIREBUFFER ) )
+ return false;
+
+ m_deviceChannels = wfx.Format.nChannels;
+ m_deviceSampleBits = wfx.Format.wBitsPerSample;
+ m_deviceDmaSpeed = wfx.Format.nSamplesPerSec;
+ m_bufferSizeBytes = dsbdesc.dwBufferBytes;
+ m_isInterleaved = true;
+
+ Q_memset( pBuffer, 0, dwSize );
+
+ pDSBuf->Unlock(pBuffer, dwSize, NULL, 0);
+
+ // Make sure mixer is active (this was moved after the zeroing to avoid popping on startup -- at least when using the dx9.0b debug .dlls)
+ pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
+
+ pDSBuf->Stop();
+ pDSBuf->GetCurrentPosition(&m_outputBufferStartOffset, &dwWrite);
+
+ pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
+
+ return true;
+}
+
+/*
+==================
+SNDDMA_InitDirect
+
+Direct-Sound support
+==================
+*/
+sndinitstat CAudioDirectSound::SNDDMA_InitDirect( void )
+{
+ DSBUFFERDESC dsbuf;
+ DSBCAPS dsbcaps;
+ DWORD dwSize, dwWrite;
+ WAVEFORMATEX format;
+ WAVEFORMATEX pformat;
+ HRESULT hresult;
+ void *lpData = NULL;
+ bool primary_format_set = false;
+ int pri_channels = 2;
+
+ if (!m_hInstDS)
+ {
+ m_hInstDS = LoadLibrary("dsound.dll");
+ if (m_hInstDS == NULL)
+ {
+ Warning( "Couldn't load dsound.dll\n");
+ return SIS_FAILURE;
+ }
+
+ pDirectSoundCreate = (long (__stdcall *)(struct _GUID *,struct IDirectSound ** ,struct IUnknown *))GetProcAddress(m_hInstDS,"DirectSoundCreate");
+ if (!pDirectSoundCreate)
+ {
+ Warning( "Couldn't get DS proc addr\n");
+ return SIS_FAILURE;
+ }
+ }
+
+ while ((hresult = pDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK)
+ {
+ if (hresult != DSERR_ALLOCATED)
+ {
+ DevMsg ("DirectSound create failed\n");
+ return SIS_FAILURE;
+ }
+
+ return SIS_NOTAVAIL;
+ }
+
+ // get snd_surround value from window settings
+ DetectWindowsSpeakerSetup();
+
+ m_bSurround = false;
+ m_bSurroundCenter = false;
+ m_bHeadphone = false;
+ m_isInterleaved = false;
+
+ switch ( snd_surround.GetInt() )
+ {
+ case 0:
+ m_bHeadphone = true; // stereo headphone
+ pri_channels = 2; // primary buffer mixes stereo input data
+ break;
+ default:
+ case 2:
+ pri_channels = 2; // primary buffer mixes stereo input data
+ break; // no surround
+ case 4:
+ m_bSurround = true; // quad surround
+ pri_channels = 1; // primary buffer mixes 3d mono input data
+ break;
+ case 5:
+ case 7:
+ m_bSurround = true; // 5.1 surround
+ m_bSurroundCenter = true;
+ pri_channels = 1; // primary buffer mixes 3d mono input data
+ break;
+ }
+
+ m_deviceChannels = pri_channels; // secondary buffers should have same # channels as primary
+ m_deviceSampleBits = 16; // hardware bits per sample
+ m_deviceDmaSpeed = SOUND_DMA_SPEED; // hardware playback rate
+
+ Q_memset( &format, 0, sizeof(format) );
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = pri_channels;
+ format.wBitsPerSample = m_deviceSampleBits;
+ format.nSamplesPerSec = m_deviceDmaSpeed;
+ format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
+ format.cbSize = 0;
+ format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
+
+ DSCAPS dscaps;
+ Q_memset( &dscaps, 0, sizeof(dscaps) );
+ dscaps.dwSize = sizeof(dscaps);
+ if (DS_OK != pDS->GetCaps(&dscaps))
+ {
+ Warning( "Couldn't get DS caps\n");
+ }
+
+ if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
+ {
+ Warning( "No DirectSound driver installed\n");
+ Shutdown();
+ return SIS_FAILURE;
+ }
+
+ if (DS_OK != pDS->SetCooperativeLevel(*pmainwindow, DSSCL_EXCLUSIVE))
+ {
+ Warning( "Set coop level failed\n");
+ Shutdown();
+ return SIS_FAILURE;
+ }
+
+ // get access to the primary buffer, if possible, so we can set the
+ // sound hardware format
+ Q_memset( &dsbuf, 0, sizeof(dsbuf) );
+ dsbuf.dwSize = sizeof(DSBUFFERDESC);
+ dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ if ( snd_legacy_surround.GetBool() || m_bSurround )
+ {
+ dsbuf.dwFlags |= DSBCAPS_CTRL3D;
+ }
+ dsbuf.dwBufferBytes = 0;
+ dsbuf.lpwfxFormat = NULL;
+
+ Q_memset( &dsbcaps, 0, sizeof(dsbcaps) );
+ dsbcaps.dwSize = sizeof(dsbcaps);
+
+ if ( !CommandLine()->CheckParm("-snoforceformat"))
+ {
+ if (DS_OK == pDS->CreateSoundBuffer(&dsbuf, &pDSPBuf, NULL))
+ {
+ pformat = format;
+
+ if (DS_OK != pDSPBuf->SetFormat(&pformat))
+ {
+ if (snd_firsttime)
+ DevMsg ("Set primary sound buffer format: no\n");
+ }
+ else
+ {
+ if (snd_firsttime)
+ DevMsg ("Set primary sound buffer format: yes\n");
+
+ primary_format_set = true;
+ }
+ }
+ }
+
+ if ( m_bSurround )
+ {
+ // try to init surround
+ m_bSurround = false;
+ if ( snd_legacy_surround.GetBool() )
+ {
+ if (snd_surround.GetInt() == 4)
+ {
+ // attempt to init 4 channel surround
+ m_bSurround = SNDDMA_InitSurround(pDS, &format, &dsbcaps, 4);
+ }
+ else if (snd_surround.GetInt() == 5 || snd_surround.GetInt() == 7)
+ {
+ // attempt to init 5 channel surround
+ m_bSurroundCenter = SNDDMA_InitSurround(pDS, &format, &dsbcaps, 5);
+ m_bSurround = m_bSurroundCenter;
+ }
+ }
+ if ( !m_bSurround )
+ {
+ pri_channels = 6;
+ if ( snd_surround.GetInt() < 5 )
+ {
+ pri_channels = 4;
+ }
+
+ m_bSurround = SNDDMA_InitInterleaved( pDS, &format, pri_channels );
+ }
+ }
+
+ if ( !m_bSurround )
+ {
+ // snd_surround.SetValue( 0 );
+ if ( !primary_format_set || !CommandLine()->CheckParm ("-primarysound") )
+ {
+ // create the secondary buffer we'll actually work with
+ Q_memset( &dsbuf, 0, sizeof(dsbuf) );
+ dsbuf.dwSize = sizeof(DSBUFFERDESC);
+ dsbuf.dwFlags = DSBCAPS_LOCSOFTWARE; // NOTE: don't use CTRLFREQUENCY (slow)
+ dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
+ dsbuf.lpwfxFormat = &format;
+ if ( !snd_mute_losefocus.GetBool() )
+ {
+ dsbuf.dwFlags |= DSBCAPS_GLOBALFOCUS;
+ }
+
+ if (DS_OK != pDS->CreateSoundBuffer(&dsbuf, &pDSBuf, NULL))
+ {
+ Warning( "DS:CreateSoundBuffer Failed");
+ Shutdown();
+ return SIS_FAILURE;
+ }
+
+ m_deviceChannels = format.nChannels;
+ m_deviceSampleBits = format.wBitsPerSample;
+ m_deviceDmaSpeed = format.nSamplesPerSec;
+
+ Q_memset(&dsbcaps, 0, sizeof(dsbcaps));
+ dsbcaps.dwSize = sizeof(dsbcaps);
+
+ if (DS_OK != pDSBuf->GetCaps( &dsbcaps ))
+ {
+ Warning( "DS:GetCaps failed\n");
+ Shutdown();
+ return SIS_FAILURE;
+ }
+
+ if ( snd_firsttime )
+ DevMsg ("Using secondary sound buffer\n");
+ }
+ else
+ {
+ if (DS_OK != pDS->SetCooperativeLevel(*pmainwindow, DSSCL_WRITEPRIMARY))
+ {
+ Warning( "Set coop level failed\n");
+ Shutdown();
+ return SIS_FAILURE;
+ }
+
+ Q_memset(&dsbcaps, 0, sizeof(dsbcaps));
+ dsbcaps.dwSize = sizeof(dsbcaps);
+ if (DS_OK != pDSPBuf->GetCaps(&dsbcaps))
+ {
+ Msg ("DS:GetCaps failed\n");
+ return SIS_FAILURE;
+ }
+
+ pDSBuf = pDSPBuf;
+ DevMsg ("Using primary sound buffer\n");
+ }
+
+ if ( snd_firsttime )
+ {
+ DevMsg(" %d channel(s)\n"
+ " %d bits/sample\n"
+ " %d samples/sec\n",
+ DeviceChannels(), DeviceSampleBits(), DeviceDmaSpeed());
+ }
+
+ // initialize the buffer
+ m_bufferSizeBytes = dsbcaps.dwBufferBytes;
+ int reps = 0;
+ while ((hresult = pDSBuf->Lock(0, m_bufferSizeBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST)
+ {
+ Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n");
+ Shutdown();
+ return SIS_FAILURE;
+ }
+
+ if (++reps > 10000)
+ {
+ Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer\n");
+ Shutdown();
+ return SIS_FAILURE;
+ }
+ }
+
+ Q_memset( lpData, 0, dwSize );
+ pDSBuf->Unlock(lpData, dwSize, NULL, 0);
+
+ // Make sure mixer is active (this was moved after the zeroing to avoid popping on startup -- at least when using the dx9.0b debug .dlls)
+ pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
+
+ // we don't want anyone to access the buffer directly w/o locking it first.
+ lpData = NULL;
+
+ pDSBuf->Stop();
+
+ pDSBuf->GetCurrentPosition(&m_outputBufferStartOffset, &dwWrite);
+
+ pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
+ }
+
+ // number of mono samples output buffer may hold
+ m_deviceSampleCount = m_bufferSizeBytes/(DeviceSampleBytes());
+
+ return SIS_SUCCESS;
+
+}
+
+static DWORD GetSpeakerConfigForSurroundMode( int surroundMode, const char **pConfigDesc )
+{
+ DWORD newSpeakerConfig = DSSPEAKER_STEREO;
+ const char *speakerConfigDesc = "";
+
+ switch ( surroundMode )
+ {
+ case 0:
+ newSpeakerConfig = DSSPEAKER_HEADPHONE;
+ speakerConfigDesc = "headphone";
+ break;
+
+ case 2:
+ default:
+ newSpeakerConfig = DSSPEAKER_STEREO;
+ speakerConfigDesc = "stereo speaker";
+ break;
+
+ case 4:
+ newSpeakerConfig = DSSPEAKER_QUAD;
+ speakerConfigDesc = "quad speaker";
+ break;
+
+ case 5:
+ newSpeakerConfig = DSSPEAKER_5POINT1;
+ speakerConfigDesc = "5.1 speaker";
+ break;
+
+ case 7:
+ newSpeakerConfig = DSSPEAKER_7POINT1;
+ speakerConfigDesc = "7.1 speaker";
+ break;
+ }
+ if ( pConfigDesc )
+ {
+ *pConfigDesc = speakerConfigDesc;
+ }
+ return newSpeakerConfig;
+}
+
+// Read the speaker config from windows
+static DWORD GetWindowsSpeakerConfig()
+{
+ DWORD speaker_config = windows_speaker_config.GetInt();
+ if ( windows_speaker_config.GetInt() < 0 )
+ {
+ speaker_config = DSSPEAKER_STEREO;
+ if (DS_OK == pDS->GetSpeakerConfig( &speaker_config ))
+ {
+ // split out settings
+ speaker_config = DSSPEAKER_CONFIG(speaker_config);
+ if ( speaker_config == DSSPEAKER_7POINT1_SURROUND )
+ speaker_config = DSSPEAKER_7POINT1;
+ if ( speaker_config == DSSPEAKER_5POINT1_SURROUND)
+ speaker_config = DSSPEAKER_5POINT1;
+ }
+ windows_speaker_config.SetValue((int)speaker_config);
+ }
+
+ return speaker_config;
+}
+
+// Writes snd_surround convar given a directsound speaker config
+static void SetSurroundModeFromSpeakerConfig( DWORD speakerConfig )
+{
+ // set the cvar to be the windows setting
+ switch (speakerConfig)
+ {
+ case DSSPEAKER_HEADPHONE:
+ snd_surround.SetValue(0);
+ break;
+
+ case DSSPEAKER_MONO:
+ case DSSPEAKER_STEREO:
+ default:
+ snd_surround.SetValue( 2 );
+ break;
+
+ case DSSPEAKER_QUAD:
+ snd_surround.SetValue(4);
+ break;
+
+ case DSSPEAKER_5POINT1:
+ snd_surround.SetValue(5);
+ break;
+
+ case DSSPEAKER_7POINT1:
+ snd_surround.SetValue(7);
+ break;
+ }
+}
+/*
+ Sets the snd_surround_speakers cvar based on the windows setting
+*/
+
+void CAudioDirectSound::DetectWindowsSpeakerSetup()
+{
+ // detect speaker settings from windows
+ DWORD speaker_config = GetWindowsSpeakerConfig();
+ SetSurroundModeFromSpeakerConfig(speaker_config);
+
+ // DEBUG
+ if (speaker_config == DSSPEAKER_MONO)
+ DevMsg( "DS:mono configuration detected\n");
+
+ if (speaker_config == DSSPEAKER_HEADPHONE)
+ DevMsg( "DS:headphone configuration detected\n");
+
+ if (speaker_config == DSSPEAKER_STEREO)
+ DevMsg( "DS:stereo speaker configuration detected\n");
+
+ if (speaker_config == DSSPEAKER_QUAD)
+ DevMsg( "DS:quad speaker configuration detected\n");
+
+ if (speaker_config == DSSPEAKER_SURROUND)
+ DevMsg( "DS:surround speaker configuration detected\n");
+
+ if (speaker_config == DSSPEAKER_5POINT1)
+ DevMsg( "DS:5.1 speaker configuration detected\n");
+
+ if (speaker_config == DSSPEAKER_7POINT1)
+ DevMsg( "DS:7.1 speaker configuration detected\n");
+}
+
+/*
+ Updates windows settings based on snd_surround_speakers cvar changing
+ This should only happen if the user has changed it via the console or the UI
+ Changes won't take effect until the engine has restarted
+*/
+void OnSndSurroundCvarChanged( IConVar *pVar, const char *pOldString, float flOldValue )
+{
+ // if the old value is -1, we're setting this from the detect routine for the first time
+ // no need to reset the device
+ if (!pDS || flOldValue == -1 )
+ return;
+
+ // get the user's previous speaker config
+ DWORD speaker_config = GetWindowsSpeakerConfig();
+
+ // get the new config
+ DWORD newSpeakerConfig = 0;
+ const char *speakerConfigDesc = "";
+
+ ConVarRef var( pVar );
+ newSpeakerConfig = GetSpeakerConfigForSurroundMode( var.GetInt(), &speakerConfigDesc );
+ // make sure the config has changed
+ if (newSpeakerConfig == speaker_config)
+ return;
+
+ // set new configuration
+ windows_speaker_config.SetValue( (int)newSpeakerConfig );
+
+ Msg("Speaker configuration has been changed to %s.\n", speakerConfigDesc);
+
+ // restart sound system so it takes effect
+ g_pSoundServices->RestartSoundSystem();
+}
+
+void OnSndSurroundLegacyChanged( IConVar *pVar, const char *pOldString, float flOldValue )
+{
+ if ( pDS && CAudioDirectSound::m_pSingleton )
+ {
+ ConVarRef var( pVar );
+ // should either be interleaved or have legacy surround set, not both
+ if ( CAudioDirectSound::m_pSingleton->IsInterleaved() == var.GetBool() )
+ {
+ Msg( "Legacy Surround %s.\n", var.GetBool() ? "enabled" : "disabled" );
+ // restart sound system so it takes effect
+ g_pSoundServices->RestartSoundSystem();
+ }
+ }
+}
+
+void OnSndVarChanged( IConVar *pVar, const char *pOldString, float flOldValue )
+{
+ ConVarRef var(pVar);
+ // restart sound system so the change takes effect
+ if ( var.GetInt() != int(flOldValue) )
+ {
+ g_pSoundServices->RestartSoundSystem();
+ }
+}
+
+/*
+ Release all Surround buffer pointers
+*/
+void ReleaseSurround(void)
+{
+ if ( pDSBuf3DFL != NULL )
+ {
+ pDSBuf3DFL->Release();
+ pDSBuf3DFL = NULL;
+ }
+
+ if ( pDSBuf3DFR != NULL)
+ {
+ pDSBuf3DFR->Release();
+ pDSBuf3DFR = NULL;
+ }
+
+ if ( pDSBuf3DRL != NULL )
+ {
+ pDSBuf3DRL->Release();
+ pDSBuf3DRL = NULL;
+ }
+
+ if ( pDSBuf3DRR != NULL )
+ {
+ pDSBuf3DRR->Release();
+ pDSBuf3DRR = NULL;
+ }
+
+ if ( pDSBufFL != NULL )
+ {
+ pDSBufFL->Release();
+ pDSBufFL = NULL;
+ }
+
+ if ( pDSBufFR != NULL )
+ {
+ pDSBufFR->Release();
+ pDSBufFR = NULL;
+ }
+
+ if ( pDSBufRL != NULL )
+ {
+ pDSBufRL->Release();
+ pDSBufRL = NULL;
+ }
+
+ if ( pDSBufRR != NULL )
+ {
+ pDSBufRR->Release();
+ pDSBufRR = NULL;
+ }
+
+ if ( pDSBufFC != NULL )
+ {
+ pDSBufFC->Release();
+ pDSBufFC = NULL;
+ }
+}
+
+void DEBUG_DS_FillSquare( void *lpData, DWORD dwSize )
+{
+ short *lpshort = (short *)lpData;
+ DWORD j = min((DWORD)10000, dwSize/2);
+
+ for (DWORD i = 0; i < j; i++)
+ lpshort[i] = 8000;
+}
+
+void DEBUG_DS_FillSquare2( void *lpData, DWORD dwSize )
+{
+ short *lpshort = (short *)lpData;
+ DWORD j = min((DWORD)1000, dwSize/2);
+
+ for (DWORD i = 0; i < j; i++)
+ lpshort[i] = 16000;
+}
+
+// helper to set default buffer params
+void DS3D_SetBufferParams( LPDIRECTSOUND3DBUFFER pDSBuf3D, D3DVECTOR *pbpos, D3DVECTOR *pbdir )
+{
+ DS3DBUFFER bparm;
+ D3DVECTOR bvel;
+ D3DVECTOR bpos, bdir;
+ HRESULT hr;
+
+ bvel.x = 0.0f; bvel.y = 0.0f; bvel.z = 0.0f;
+ bpos = *pbpos;
+ bdir = *pbdir;
+
+ bparm.dwSize = sizeof(DS3DBUFFER);
+
+ hr = pDSBuf3D->GetAllParameters( &bparm );
+
+ bparm.vPosition = bpos;
+ bparm.vVelocity = bvel;
+ bparm.dwInsideConeAngle = 5.0; // narrow cones for each speaker
+ bparm.dwOutsideConeAngle = 10.0;
+ bparm.vConeOrientation = bdir;
+ bparm.lConeOutsideVolume = DSBVOLUME_MIN;
+ bparm.flMinDistance = 100.0; // no rolloff (until > 2.0 meter distance)
+ bparm.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
+ bparm.dwMode = DS3DMODE_NORMAL;
+
+ hr = pDSBuf3D->SetAllParameters( &bparm, DS3D_DEFERRED );
+}
+
+// Initialization for Surround sound support (4 channel or 5 channel).
+// Creates 4 or 5 mono 3D buffers to be used as Front Left, (Front Center), Front Right, Rear Left, Rear Right
+bool CAudioDirectSound::SNDDMA_InitSurround(LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, DSBCAPS* lpdsbc, int cchan)
+{
+ DSBUFFERDESC dsbuf;
+ WAVEFORMATEX wvex;
+ DWORD dwSize, dwWrite;
+ int reps;
+ HRESULT hresult;
+ void *lpData = NULL;
+
+ if ( lpDS == NULL ) return FALSE;
+
+ // Force format to mono channel
+
+ memcpy(&wvex, lpFormat, sizeof(WAVEFORMATEX));
+ wvex.nChannels = 1;
+ wvex.nBlockAlign = wvex.nChannels * wvex.wBitsPerSample / 8;
+ wvex.nAvgBytesPerSec = wvex.nSamplesPerSec * wvex.nBlockAlign;
+
+ memset (&dsbuf, 0, sizeof(dsbuf));
+ dsbuf.dwSize = sizeof(DSBUFFERDESC);
+ // NOTE: LOCHARDWARE causes SB AWE64 to crash in it's DSOUND driver
+ dsbuf.dwFlags = DSBCAPS_CTRL3D; // don't use CTRLFREQUENCY (slow)
+ if ( !snd_mute_losefocus.GetBool() )
+ {
+ dsbuf.dwFlags |= DSBCAPS_GLOBALFOCUS;
+ }
+
+ // reserve space for each buffer
+
+ dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE_SURROUND;
+
+ dsbuf.lpwfxFormat = &wvex;
+
+ // create 4 mono buffers FL, FR, RL, RR
+
+ if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufFL, NULL))
+ {
+ Warning( "DS:CreateSoundBuffer for 3d front left failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufFR, NULL))
+ {
+ Warning( "DS:CreateSoundBuffer for 3d front right failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufRL, NULL))
+ {
+ Warning( "DS:CreateSoundBuffer for 3d rear left failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufRR, NULL))
+ {
+ Warning( "DS:CreateSoundBuffer for 3d rear right failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ // create center channel
+
+ if (cchan == 5)
+ {
+ if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufFC, NULL))
+ {
+ Warning( "DS:CreateSoundBuffer for 3d front center failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+ }
+
+ // Try to get 4 or 5 3D buffers from the mono DS buffers
+
+ if (DS_OK != pDSBufFL->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DFL))
+ {
+ Warning( "DS:Query 3DBuffer for 3d front left failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (DS_OK != pDSBufFR->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DFR))
+ {
+ Warning( "DS:Query 3DBuffer for 3d front right failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (DS_OK != pDSBufRL->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DRL))
+ {
+ Warning( "DS:Query 3DBuffer for 3d rear left failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (DS_OK != pDSBufRR->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DRR))
+ {
+ Warning( "DS:Query 3DBuffer for 3d rear right failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (cchan == 5)
+ {
+ if (DS_OK != pDSBufFC->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DFC))
+ {
+ Warning( "DS:Query 3DBuffer for 3d front center failed");
+ ReleaseSurround();
+ return FALSE;
+ }
+ }
+
+ // set listener position & orientation.
+ // DS uses left handed coord system: +x is right, +y is up, +z is forward
+
+ HRESULT hr;
+
+ IDirectSound3DListener *plistener = NULL;
+
+ hr = pDSPBuf->QueryInterface(IID_IDirectSound3DListener, (void**)&plistener);
+ if (plistener)
+ {
+ DS3DLISTENER lparm;
+ lparm.dwSize = sizeof(DS3DLISTENER);
+
+ hr = plistener->GetAllParameters( &lparm );
+
+ hr = plistener->SetOrientation( 0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f, DS3D_IMMEDIATE); // frontx,y,z topx,y,z
+ hr = plistener->SetPosition(0.0f, 0.0f, 0.0f, DS3D_IMMEDIATE);
+ }
+ else
+ {
+ Warning( "DS: failed to get 3D listener interface.");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ // set 3d buffer position and orientation params
+
+ D3DVECTOR bpos, bdir;
+
+ bpos.x = -1.0; bpos.y = 0.0; bpos.z = 1.0; // FL
+ bdir.x = 1.0; bdir.y = 0.0; bdir.z = -1.0;
+
+ DS3D_SetBufferParams( pDSBuf3DFL, &bpos, &bdir );
+
+ bpos.x = 1.0; bpos.y = 0.0; bpos.z = 1.0; // FR
+ bdir.x = -1.0; bdir.y = 0.0; bdir.z = -1.0;
+
+ DS3D_SetBufferParams( pDSBuf3DFR, &bpos, &bdir );
+
+ bpos.x = -1.0; bpos.y = 0.0; bpos.z = -1.0; // RL
+ bdir.x = 1.0; bdir.y = 0.0; bdir.z = 1.0;
+
+ DS3D_SetBufferParams( pDSBuf3DRL, &bpos, &bdir );
+
+ bpos.x = 1.0; bpos.y = 0.0; bpos.z = -1.0; // RR
+ bdir.x = -1.0; bdir.y = 0.0; bdir.z = 1.0;
+
+ DS3D_SetBufferParams( pDSBuf3DRR, &bpos, &bdir );
+
+ if (cchan == 5)
+ {
+ bpos.x = 0.0; bpos.y = 0.0; bpos.z = 1.0; // FC
+ bdir.x = 0.0; bdir.y = 0.0; bdir.z = -1.0;
+
+ DS3D_SetBufferParams( pDSBuf3DFC, &bpos, &bdir );
+ }
+
+ // commit all buffer param settings
+
+ hr = plistener->CommitDeferredSettings();
+
+ m_deviceChannels = 1; // 1 mono 3d output buffer
+ m_deviceSampleBits = lpFormat->wBitsPerSample;
+ m_deviceDmaSpeed = lpFormat->nSamplesPerSec;
+
+ memset(lpdsbc, 0, sizeof(DSBCAPS));
+ lpdsbc->dwSize = sizeof(DSBCAPS);
+
+ if (DS_OK != pDSBufFL->GetCaps (lpdsbc))
+ {
+ Warning( "DS:GetCaps failed for 3d sound buffer\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
+ pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
+ pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
+ pDSBufRR->Play(0, 0, DSBPLAY_LOOPING);
+
+ if (cchan == 5)
+ pDSBufFC->Play(0, 0, DSBPLAY_LOOPING);
+
+ if (snd_firsttime)
+ DevMsg(" %d channel(s)\n"
+ " %d bits/sample\n"
+ " %d samples/sec\n",
+ cchan, DeviceSampleBits(), DeviceDmaSpeed());
+
+ m_bufferSizeBytes = lpdsbc->dwBufferBytes;
+
+ // Test everything just like in the normal initialization.
+ if (cchan == 5)
+ {
+ reps = 0;
+ while ((hresult = pDSBufFC->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST)
+ {
+ Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed for FC\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (++reps > 10000)
+ {
+ Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer for FC\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+ }
+ memset(lpData, 0, dwSize);
+// DEBUG_DS_FillSquare( lpData, dwSize );
+ pDSBufFC->Unlock(lpData, dwSize, NULL, 0);
+ }
+
+ reps = 0;
+ while ((hresult = pDSBufFL->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST)
+ {
+ Warning( "SNDDMA_InitSurround: DS::Lock Sound Buffer Failed for 3d FL\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (++reps > 10000)
+ {
+ Warning( "SNDDMA_InitSurround: DS: couldn't restore buffer for 3d FL\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+ }
+ memset(lpData, 0, dwSize);
+// DEBUG_DS_FillSquare( lpData, dwSize );
+ pDSBufFL->Unlock(lpData, dwSize, NULL, 0);
+
+ reps = 0;
+ while ((hresult = pDSBufFR->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST)
+ {
+ Warning( "SNDDMA_InitSurround: DS::Lock Sound Buffer Failed for 3d FR\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (++reps > 10000)
+ {
+ Warning( "SNDDMA_InitSurround: DS: couldn't restore buffer for FR\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+ }
+ memset(lpData, 0, dwSize);
+// DEBUG_DS_FillSquare( lpData, dwSize );
+ pDSBufFR->Unlock(lpData, dwSize, NULL, 0);
+
+ reps = 0;
+ while ((hresult = pDSBufRL->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST)
+ {
+ Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed for RL\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (++reps > 10000)
+ {
+ Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer for RL\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+ }
+ memset(lpData, 0, dwSize);
+// DEBUG_DS_FillSquare( lpData, dwSize );
+ pDSBufRL->Unlock(lpData, dwSize, NULL, 0);
+
+ reps = 0;
+ while ((hresult = pDSBufRR->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST)
+ {
+ Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed for RR\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+
+ if (++reps > 10000)
+ {
+ Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer for RR\n");
+ ReleaseSurround();
+ return FALSE;
+ }
+ }
+ memset(lpData, 0, dwSize);
+// DEBUG_DS_FillSquare( lpData, dwSize );
+ pDSBufRR->Unlock(lpData, dwSize, NULL, 0);
+
+ lpData = NULL; // this is invalid now
+
+ // OK Stop and get our positions and were good to go.
+ pDSBufFL->Stop();
+ pDSBufFR->Stop();
+ pDSBufRL->Stop();
+ pDSBufRR->Stop();
+ if (cchan == 5)
+ pDSBufFC->Stop();
+
+ // get hardware playback position, store it, syncronize all buffers to FL
+
+ pDSBufFL->GetCurrentPosition(&m_outputBufferStartOffset, &dwWrite);
+ pDSBufFR->SetCurrentPosition(m_outputBufferStartOffset);
+ pDSBufRL->SetCurrentPosition(m_outputBufferStartOffset);
+ pDSBufRR->SetCurrentPosition(m_outputBufferStartOffset);
+ if (cchan == 5)
+ pDSBufFC->SetCurrentPosition(m_outputBufferStartOffset);
+
+ pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
+ pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
+ pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
+ pDSBufRR->Play(0, 0, DSBPLAY_LOOPING);
+ if (cchan == 5)
+ pDSBufFC->Play(0, 0, DSBPLAY_LOOPING);
+
+ if (snd_firsttime)
+ Warning( "3d surround sound initialization successful\n");
+
+ return TRUE;
+}
+
+void CAudioDirectSound::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up )
+{
+}
+
+void CAudioDirectSound::ChannelReset( int entnum, int channelIndex, float distanceMod )
+{
+}
+
+const char *CAudioDirectSound::DeviceName( void )
+{
+ if ( m_bSurroundCenter )
+ return "5 Channel Surround";
+
+ if ( m_bSurround )
+ return "4 Channel Surround";
+
+ return "Direct Sound";
+}
+
+// use the partial buffer locking code in stereo as well - not available when recording a movie
+ConVar snd_lockpartial("snd_lockpartial","1");
+
+// Transfer up to a full paintbuffer (PAINTBUFFER_SIZE) of stereo samples
+// out to the directsound secondary buffer(s).
+// For 4 or 5 ch surround, there are 4 or 5 mono 16 bit secondary DS streaming buffers.
+// For stereo speakers, there is one stereo 16 bit secondary DS streaming buffer.
+
+void CAudioDirectSound::TransferSamples( int end )
+{
+ int lpaintedtime = g_paintedtime;
+ int endtime = end;
+
+ // When Surround is enabled, divert to 4 or 5 chan xfer scheme.
+ if ( m_bSurround )
+ {
+ if ( m_isInterleaved )
+ {
+ S_TransferSurround16Interleaved( PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, lpaintedtime, endtime);
+ }
+ else
+ {
+ int cchan = ( m_bSurroundCenter ? 5 : 4);
+
+ S_TransferSurround16( PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, lpaintedtime, endtime, cchan);
+ }
+ return;
+ }
+ else if ( snd_lockpartial.GetBool() && DeviceChannels() == 2 && DeviceSampleBits() == 16 && !SND_IsRecording() )
+ {
+ S_TransferSurround16Interleaved( PAINTBUFFER, NULL, NULL, lpaintedtime, endtime );
+ }
+ else
+ {
+ DWORD *pBuffer = NULL;
+ DWORD dwSize = 0;
+ if ( !LockDSBuffer( pDSBuf, &pBuffer, &dwSize, "DS_STEREO" ) )
+ {
+ S_Shutdown();
+ S_Startup();
+ return;
+ }
+ if ( pBuffer )
+ {
+ if ( DeviceChannels() == 2 && DeviceSampleBits() == 16 )
+ {
+ S_TransferStereo16( pBuffer, PAINTBUFFER, lpaintedtime, endtime );
+ }
+ else
+ {
+ // UNDONE: obsolete - no 8 bit mono output supported
+ S_TransferPaintBuffer( pBuffer, PAINTBUFFER, lpaintedtime, endtime );
+ }
+ pDSBuf->Unlock( pBuffer, dwSize, NULL, 0 );
+ }
+ }
+}
+
+bool CAudioDirectSound::IsUsingBufferPerSpeaker()
+{
+ return m_bSurround && !m_isInterleaved;
+}
+
+bool CAudioDirectSound::LockDSBuffer( LPDIRECTSOUNDBUFFER pBuffer, DWORD **pdwWriteBuffer, DWORD *pdwSizeBuffer, const char *pBufferName, int lockFlags )
+{
+ if ( !pBuffer )
+ return false;
+ HRESULT hr;
+ int reps = 0;
+ while ((hr = pBuffer->Lock(0, m_bufferSizeBytes, (void**)pdwWriteBuffer, pdwSizeBuffer,
+ NULL, NULL, lockFlags)) != DS_OK)
+ {
+ if (hr != DSERR_BUFFERLOST)
+ {
+ Msg ("DS::Lock Sound Buffer Failed %s\n", pBufferName);
+ return false;
+ }
+
+ if (++reps > 10000)
+ {
+ Msg ("DS:: couldn't restore buffer %s\n", pBufferName);
+ return false;
+ }
+ }
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// Given front, rear and center stereo paintbuffers, split samples into 4 or 5 mono directsound buffers (FL, FC, FR, RL, RR)
+void CAudioDirectSound::S_TransferSurround16( portable_samplepair_t *pfront, portable_samplepair_t *prear, portable_samplepair_t *pcenter, int lpaintedtime, int endtime, int cchan)
+{
+ int lpos;
+ DWORD *pdwWriteFL=NULL, *pdwWriteFR=NULL, *pdwWriteRL=NULL, *pdwWriteRR=NULL, *pdwWriteFC=NULL;
+ DWORD dwSizeFL=0, dwSizeFR=0, dwSizeRL=0, dwSizeRR=0, dwSizeFC=0;
+ int i, j, *snd_p, *snd_rp, *snd_cp, volumeFactor;
+ short *snd_out_fleft, *snd_out_fright, *snd_out_rleft, *snd_out_rright, *snd_out_fcenter;
+
+ pdwWriteFC = NULL; // compiler warning
+ dwSizeFC = 0;
+ snd_out_fcenter = NULL;
+
+ volumeFactor = S_GetMasterVolume() * 256;
+
+ // lock all 4 or 5 mono directsound buffers FL, FR, RL, RR, FC
+ if ( !LockDSBuffer( pDSBufFL, &pdwWriteFL, &dwSizeFL, "FL" ) ||
+ !LockDSBuffer( pDSBufFR, &pdwWriteFR, &dwSizeFR, "FR" ) ||
+ !LockDSBuffer( pDSBufRL, &pdwWriteRL, &dwSizeRL, "RL" ) ||
+ !LockDSBuffer( pDSBufRR, &pdwWriteRR, &dwSizeRR, "RR" ) )
+ {
+ S_Shutdown();
+ S_Startup();
+ return;
+ }
+
+ if (cchan == 5 && !LockDSBuffer( pDSBufFC, &pdwWriteFC, &dwSizeFC, "FC" ))
+ {
+ S_Shutdown ();
+ S_Startup ();
+ return;
+ }
+
+ // take stereo front and rear paintbuffers, and center paintbuffer if provided,
+ // and copy samples into the 4 or 5 mono directsound buffers
+
+ snd_rp = (int *)prear;
+ snd_cp = (int *)pcenter;
+ snd_p = (int *)pfront;
+
+ int linearCount; // space in output buffer for linearCount mono samples
+ int sampleMonoCount = DeviceSampleCount(); // number of mono samples per output buffer (was;(DeviceSampleCount()>>1))
+ int sampleMask = sampleMonoCount - 1;
+
+ // paintedtime - number of full samples that have played since start
+ // endtime - number of full samples to play to - endtime is g_soundtime + mixahead samples
+
+ while (lpaintedtime < endtime)
+ {
+ lpos = lpaintedtime & sampleMask; // lpos is next output position in output buffer
+
+ linearCount = sampleMonoCount - lpos;
+
+ // limit output count to requested number of samples
+
+ if (linearCount > endtime - lpaintedtime)
+ linearCount = endtime - lpaintedtime;
+
+ snd_out_fleft = (short *)pdwWriteFL + lpos;
+ snd_out_fright = (short *)pdwWriteFR + lpos;
+ snd_out_rleft = (short *)pdwWriteRL + lpos;
+ snd_out_rright = (short *)pdwWriteRR + lpos;
+
+ if (cchan == 5)
+ snd_out_fcenter = (short *)pdwWriteFC + lpos;
+
+ // for 16 bit sample in the front and rear stereo paintbuffers, copy
+ // into the 4 or 5 FR, FL, RL, RR, FC directsound paintbuffers
+
+ for (i=0, j= 0 ; i<linearCount ; i++, j+=2)
+ {
+ snd_out_fleft[i] = (snd_p[j]*volumeFactor)>>8;
+ snd_out_fright[i] = (snd_p[j + 1]*volumeFactor)>>8;
+ snd_out_rleft[i] = (snd_rp[j]*volumeFactor)>>8;
+ snd_out_rright[i] = (snd_rp[j + 1]*volumeFactor)>>8;
+ }
+
+ // copy front center buffer (mono) data to center chan directsound paintbuffer
+
+ if (cchan == 5)
+ {
+ for (i=0, j=0 ; i<linearCount ; i++, j+=2)
+ {
+ snd_out_fcenter[i] = (snd_cp[j]*volumeFactor)>>8;
+
+ }
+ }
+
+ snd_p += linearCount << 1;
+ snd_rp += linearCount << 1;
+ snd_cp += linearCount << 1;
+
+ lpaintedtime += linearCount;
+ }
+
+ pDSBufFL->Unlock(pdwWriteFL, dwSizeFL, NULL, 0);
+ pDSBufFR->Unlock(pdwWriteFR, dwSizeFR, NULL, 0);
+ pDSBufRL->Unlock(pdwWriteRL, dwSizeRL, NULL, 0);
+ pDSBufRR->Unlock(pdwWriteRR, dwSizeRR, NULL, 0);
+
+ if (cchan == 5)
+ pDSBufFC->Unlock(pdwWriteFC, dwSizeFC, NULL, 0);
+}
+
+struct surround_transfer_t
+{
+ int paintedtime;
+ int linearCount;
+ int sampleMask;
+ int channelCount;
+ int *snd_p;
+ int *snd_rp;
+ int *snd_cp;
+ short *pOutput;
+};
+
+static void TransferSamplesToSurroundBuffer( int outputCount, surround_transfer_t &transfer )
+{
+ int i, j;
+ int volumeFactor = S_GetMasterVolume() * 256;
+
+ if ( transfer.channelCount == 2 )
+ {
+ for (i=0, j=0; i<outputCount ; i++, j+=2)
+ {
+ transfer.pOutput[0] = (transfer.snd_p[j]*volumeFactor)>>8; // FL
+ transfer.pOutput[1] = (transfer.snd_p[j + 1]*volumeFactor)>>8; // FR
+ transfer.pOutput += 2;
+ }
+ }
+ // no center channel, 4 channel surround
+ else if ( transfer.channelCount == 4 )
+ {
+ for (i=0, j=0; i<outputCount ; i++, j+=2)
+ {
+ transfer.pOutput[0] = (transfer.snd_p[j]*volumeFactor)>>8; // FL
+ transfer.pOutput[1] = (transfer.snd_p[j + 1]*volumeFactor)>>8; // FR
+ transfer.pOutput[2] = (transfer.snd_rp[j]*volumeFactor)>>8; // RL
+ transfer.pOutput[3] = (transfer.snd_rp[j + 1]*volumeFactor)>>8; // RR
+ transfer.pOutput += 4;
+ //Assert( baseOffset <= (DeviceSampleCount()) );
+ }
+ }
+ else
+ {
+ Assert(transfer.snd_cp);
+ // 6 channel / 5.1
+ for (i=0, j=0 ; i<outputCount ; i++, j+=2)
+ {
+ transfer.pOutput[0] = (transfer.snd_p[j]*volumeFactor)>>8; // FL
+ transfer.pOutput[1] = (transfer.snd_p[j + 1]*volumeFactor)>>8; // FR
+
+ transfer.pOutput[2] = (transfer.snd_cp[j]*volumeFactor)>>8; // Center
+
+ transfer.pOutput[3] = 0;
+
+ transfer.pOutput[4] = (transfer.snd_rp[j]*volumeFactor)>>8; // RL
+ transfer.pOutput[5] = (transfer.snd_rp[j + 1]*volumeFactor)>>8; // RR
+
+#if 0
+ // average channels into the subwoofer, let the sub filter the output
+ // NOTE: avg l/r rear to do 2 shifts instead of divide by 5
+ int sumFront = (int)transfer.pOutput[0] + (int)transfer.pOutput[1] + (int)transfer.pOutput[2];
+ int sumRear = (int)transfer.pOutput[4] + (int)transfer.pOutput[5];
+ transfer.pOutput[3] = (sumFront + (sumRear>>1)) >> 2;
+#endif
+
+ transfer.pOutput += 6;
+ //Assert( baseOffset <= (DeviceSampleCount()) );
+ }
+ }
+
+ transfer.snd_p += outputCount << 1;
+ if ( transfer.snd_rp )
+ {
+ transfer.snd_rp += outputCount << 1;
+ }
+ if ( transfer.snd_cp )
+ {
+ transfer.snd_cp += outputCount << 1;
+ }
+
+ transfer.paintedtime += outputCount;
+ transfer.linearCount -= outputCount;
+
+}
+
+void CAudioDirectSound::S_TransferSurround16Interleaved_FullLock( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int lpaintedtime, int endtime )
+{
+ int lpos;
+ DWORD *pdwWrite = NULL;
+ DWORD dwSize = 0;
+ int i, j, *snd_p, *snd_rp, *snd_cp, volumeFactor;
+
+ volumeFactor = S_GetMasterVolume() * 256;
+ int channelCount = m_bSurroundCenter ? 5 : 4;
+ if ( DeviceChannels() == 2 )
+ {
+ channelCount = 2;
+ }
+
+ // lock single interleaved buffer
+ if ( !LockDSBuffer( pDSBuf, &pdwWrite, &dwSize, "DS_INTERLEAVED" ) )
+ {
+ S_Shutdown ();
+ S_Startup ();
+ return;
+ }
+
+ // take stereo front and rear paintbuffers, and center paintbuffer if provided,
+ // and copy samples into the 4 or 5 mono directsound buffers
+
+ snd_rp = (int *)prear;
+ snd_cp = (int *)pcenter;
+ snd_p = (int *)pfront;
+
+ int linearCount; // space in output buffer for linearCount mono samples
+ int sampleMonoCount = m_bufferSizeBytes/(DeviceSampleBytes()*DeviceChannels()); // number of mono samples per output buffer (was;(DeviceSampleCount()>>1))
+ int sampleMask = sampleMonoCount - 1;
+
+ // paintedtime - number of full samples that have played since start
+ // endtime - number of full samples to play to - endtime is g_soundtime + mixahead samples
+
+ short *pOutput = (short *)pdwWrite;
+ while (lpaintedtime < endtime)
+ {
+ lpos = lpaintedtime & sampleMask; // lpos is next output position in output buffer
+
+ linearCount = sampleMonoCount - lpos;
+
+ // limit output count to requested number of samples
+
+ if (linearCount > endtime - lpaintedtime)
+ linearCount = endtime - lpaintedtime;
+
+ if ( channelCount == 4 )
+ {
+ int baseOffset = lpos * channelCount;
+ for (i=0, j= 0 ; i<linearCount ; i++, j+=2)
+ {
+ pOutput[baseOffset+0] = (snd_p[j]*volumeFactor)>>8; // FL
+ pOutput[baseOffset+1] = (snd_p[j + 1]*volumeFactor)>>8; // FR
+ pOutput[baseOffset+2] = (snd_rp[j]*volumeFactor)>>8; // RL
+ pOutput[baseOffset+3] = (snd_rp[j + 1]*volumeFactor)>>8; // RR
+ baseOffset += 4;
+ }
+ }
+ else
+ {
+ Assert(channelCount==5); // 6 channel / 5.1
+ int baseOffset = lpos * 6;
+ for (i=0, j= 0 ; i<linearCount ; i++, j+=2)
+ {
+ pOutput[baseOffset+0] = (snd_p[j]*volumeFactor)>>8; // FL
+ pOutput[baseOffset+1] = (snd_p[j + 1]*volumeFactor)>>8; // FR
+
+ pOutput[baseOffset+2] = (snd_cp[j]*volumeFactor)>>8; // Center
+ // NOTE: Let the hardware mix the sub from the main channels since
+ // we don't have any sub-specific sounds, or direct sub-addressing
+ pOutput[baseOffset+3] = 0;
+
+ pOutput[baseOffset+4] = (snd_rp[j]*volumeFactor)>>8; // RL
+ pOutput[baseOffset+5] = (snd_rp[j + 1]*volumeFactor)>>8; // RR
+
+
+ baseOffset += 6;
+ }
+ }
+
+ snd_p += linearCount << 1;
+ snd_rp += linearCount << 1;
+ snd_cp += linearCount << 1;
+
+ lpaintedtime += linearCount;
+ }
+
+ pDSBuf->Unlock(pdwWrite, dwSize, NULL, 0);
+}
+
+void CAudioDirectSound::S_TransferSurround16Interleaved( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int lpaintedtime, int endtime )
+{
+ if ( !pDSBuf )
+ return;
+ if ( !snd_lockpartial.GetBool() )
+ {
+ S_TransferSurround16Interleaved_FullLock( pfront, prear, pcenter, lpaintedtime, endtime );
+ return;
+ }
+ // take stereo front and rear paintbuffers, and center paintbuffer if provided,
+ // and copy samples into the 4 or 5 mono directsound buffers
+
+ surround_transfer_t transfer;
+ transfer.snd_rp = (int *)prear;
+ transfer.snd_cp = (int *)pcenter;
+ transfer.snd_p = (int *)pfront;
+
+ int sampleMonoCount = DeviceSampleCount()/DeviceChannels(); // number of full samples per output buffer
+ Assert(IsPowerOfTwo(sampleMonoCount));
+ transfer.sampleMask = sampleMonoCount - 1;
+ transfer.paintedtime = lpaintedtime;
+ transfer.linearCount = endtime - lpaintedtime;
+ // paintedtime - number of full samples that have played since start
+ // endtime - number of full samples to play to - endtime is g_soundtime + mixahead samples
+ int channelCount = m_bSurroundCenter ? 6 : 4;
+ if ( DeviceChannels() == 2 )
+ {
+ channelCount = 2;
+ }
+ transfer.channelCount = channelCount;
+ void *pBuffer0=NULL;
+ void *pBuffer1=NULL;
+ DWORD size0, size1;
+ int lpos = transfer.paintedtime & transfer.sampleMask; // lpos is next output position in output buffer
+
+ int offset = lpos*2*channelCount;
+ int lockSize = transfer.linearCount*2*channelCount;
+ int reps = 0;
+ HRESULT hr;
+ while ( (hr = pDSBuf->Lock( offset, lockSize, &pBuffer0, &size0, &pBuffer1, &size1, 0 )) != DS_OK )
+ {
+ if ( hr == DSERR_BUFFERLOST )
+ {
+ if ( ++reps < 10000 )
+ continue;
+ }
+ Msg ("DS::Lock Sound Buffer Failed\n");
+ return;
+ }
+
+ if ( pBuffer0 )
+ {
+ transfer.pOutput = (short *)pBuffer0;
+ TransferSamplesToSurroundBuffer( size0 / (channelCount*2), transfer );
+ }
+ if ( pBuffer1 )
+ {
+ transfer.pOutput = (short *)pBuffer1;
+ TransferSamplesToSurroundBuffer( size1 / (channelCount*2), transfer );
+ }
+ pDSBuf->Unlock(pBuffer0, size0, pBuffer1, size1);
+}
+