diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/audio/private/snd_dev_openal.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'engine/audio/private/snd_dev_openal.cpp')
| -rw-r--r-- | engine/audio/private/snd_dev_openal.cpp | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/engine/audio/private/snd_dev_openal.cpp b/engine/audio/private/snd_dev_openal.cpp new file mode 100644 index 0000000..82c6136 --- /dev/null +++ b/engine/audio/private/snd_dev_openal.cpp @@ -0,0 +1,611 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "audio_pch.h" +#include <OpenAL/al.h> +#include <OpenAL/alc.h> +#ifdef OSX +#include <OpenAL/MacOSX_OALExtensions.h> +#endif + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifndef DEDICATED // have to test this because VPC is forcing us to compile this file. + +extern bool snd_firsttime; +extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans ); +extern void S_SpatializeChannel( int volume[6], int master_vol, const Vector *psourceDir, float gain, float mono ); + +#define NUM_BUFFERS_SOURCES 128 +#define BUFF_MASK (NUM_BUFFERS_SOURCES - 1 ) +#define BUFFER_SIZE 0x0400 + + +//----------------------------------------------------------------------------- +// +// NOTE: This only allows 16-bit, stereo wave out +// +//----------------------------------------------------------------------------- +class CAudioDeviceOpenAL : public CAudioDeviceBase +{ +public: + bool IsActive( void ); + bool Init( void ); + void Shutdown( void ); + void PaintEnd( void ); + int GetOutputPosition( void ); + void ChannelReset( int entnum, int channelIndex, float distanceMod ); + void Pause( void ); + void UnPause( void ); + float MixDryVolume( void ); + bool Should3DMix( void ); + void StopAllSounds( void ); + + int PaintBegin( float mixAheadTime, int soundtime, int paintedtime ); + void ClearBuffer( void ); + void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up ); + void MixBegin( int sampleCount ); + void MixUpsample( int sampleCount, int filtertype ); + void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ); + void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ); + void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ); + void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ); + + void TransferSamples( int end ); + void SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono); + void ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount ); + + const char *DeviceName( void ) { return "OpenAL"; } + int DeviceChannels( void ) { return 2; } + int DeviceSampleBits( void ) { return 16; } + int DeviceSampleBytes( void ) { return 2; } + int DeviceDmaSpeed( void ) { return SOUND_DMA_SPEED; } + int DeviceSampleCount( void ) { return m_deviceSampleCount; } + +private: + void OpenWaveOut( void ); + void CloseWaveOut( void ); + bool ValidWaveOut( void ) const; + + ALuint m_Buffer[NUM_BUFFERS_SOURCES]; + ALuint m_Source[1]; + int m_SndBufSize; + + void *m_sndBuffers; + + int m_deviceSampleCount; + + int m_buffersSent; + int m_buffersCompleted; + int m_pauseCount; + bool m_bSoundsShutdown; +}; + + +IAudioDevice *Audio_CreateOpenALDevice( void ) +{ + CAudioDeviceOpenAL *wave = NULL; + if ( !wave ) + { + wave = new CAudioDeviceOpenAL; + } + + if ( wave->Init() ) + return wave; + + delete wave; + wave = NULL; + + return NULL; +} + + +void OnSndSurroundCvarChanged( IConVar *pVar, const char *pOldString, float flOldValue ); +void OnSndSurroundLegacyChanged( IConVar *pVar, const char *pOldString, float flOldValue ); + +//----------------------------------------------------------------------------- +// Init, shutdown +//----------------------------------------------------------------------------- +bool CAudioDeviceOpenAL::Init( void ) +{ + m_SndBufSize = 0; + m_sndBuffers = NULL; + m_pauseCount = 0; + + m_bSurround = false; + m_bSurroundCenter = false; + m_bHeadphone = false; + m_buffersSent = 0; + m_buffersCompleted = 0; + m_pauseCount = 0; + m_bSoundsShutdown = false; + + static bool first = true; + if ( first ) + { + snd_surround.SetValue( 2 ); + snd_surround.InstallChangeCallback( &OnSndSurroundCvarChanged ); + snd_legacy_surround.InstallChangeCallback( &OnSndSurroundLegacyChanged ); + first = false; + } + + OpenWaveOut(); + + if ( snd_firsttime ) + { + DevMsg( "Wave sound initialized\n" ); + } + return ValidWaveOut(); +} + +void CAudioDeviceOpenAL::Shutdown( void ) +{ + CloseWaveOut(); +} + + +//----------------------------------------------------------------------------- +// WAV out device +//----------------------------------------------------------------------------- +inline bool CAudioDeviceOpenAL::ValidWaveOut( void ) const +{ + return m_sndBuffers != 0; +} + + +//----------------------------------------------------------------------------- +// Opens the windows wave out device +//----------------------------------------------------------------------------- +void CAudioDeviceOpenAL::OpenWaveOut( void ) +{ + m_buffersSent = 0; + m_buffersCompleted = 0; + + ALenum error; + ALCcontext *newContext = NULL; + ALCdevice *newDevice = NULL; + + // Create a new OpenAL Device + // Pass NULL to specify the system‚use default output device + const ALCchar *initStr = (const ALCchar *)"\'( (sampling-rate 44100 ))"; + + newDevice = alcOpenDevice(initStr); + if (newDevice != NULL) + { + // Create a new OpenAL Context + // The new context will render to the OpenAL Device just created + ALCint attr[] = { ALC_FREQUENCY, DeviceDmaSpeed(), ALC_SYNC, AL_FALSE, 0 }; + + newContext = alcCreateContext(newDevice, attr ); + if (newContext != NULL) + { + // Make the new context the Current OpenAL Context + alcMakeContextCurrent(newContext); + + // Create some OpenAL Buffer Objects + alGenBuffers( NUM_BUFFERS_SOURCES, m_Buffer); + if((error = alGetError()) != AL_NO_ERROR) + { + DevMsg("Error Generating Buffers: "); + return; + } + + // Create some OpenAL Source Objects + alGenSources(1, m_Source); + if(alGetError() != AL_NO_ERROR) + { + DevMsg("Error generating sources! \n"); + return; + } + + alListener3f( AL_POSITION,0.0f,0.0f,0.0f); + int i; + for ( i = 0; i < 1; i++ ) + { + alSource3f( m_Source[i],AL_POSITION,0.0f,0.0f,0.0f ); + alSourcef( m_Source[i], AL_PITCH, 1.0f ); + alSourcef( m_Source[i], AL_GAIN, 1.0f ); + } + + } + } + + m_SndBufSize = NUM_BUFFERS_SOURCES*BUFFER_SIZE; + m_deviceSampleCount = m_SndBufSize / DeviceSampleBytes(); + + if ( !m_sndBuffers ) + { + m_sndBuffers = malloc( m_SndBufSize ); + memset( m_sndBuffers, 0x0, m_SndBufSize ); + } +} + + +//----------------------------------------------------------------------------- +// Closes the windows wave out device +//----------------------------------------------------------------------------- +void CAudioDeviceOpenAL::CloseWaveOut( void ) +{ + if ( ValidWaveOut() ) + { + ALCcontext *context = NULL; + ALCdevice *device = NULL; + + m_bSoundsShutdown = true; + alSourceStop( m_Source[0] ); + + // Delete the Sources + alDeleteSources(1, m_Source); + // Delete the Buffers + alDeleteBuffers(NUM_BUFFERS_SOURCES, m_Buffer); + + //Get active context + context = alcGetCurrentContext(); + //Get device for active context + device = alcGetContextsDevice(context); + alcMakeContextCurrent( NULL ); + alcSuspendContext(context); + //Release context + alcDestroyContext(context); + //Close device + alcCloseDevice(device); + } + + if ( m_sndBuffers ) + { + free( m_sndBuffers ); + m_sndBuffers = NULL; + } +} + + + +//----------------------------------------------------------------------------- +// Mixing setup +//----------------------------------------------------------------------------- +int CAudioDeviceOpenAL::PaintBegin( float mixAheadTime, int soundtime, int paintedtime ) +{ + // soundtime - total samples that have been played out to hardware at dmaspeed + // paintedtime - total samples that have been mixed at speed + // endtime - target for samples in mixahead buffer at speed + + unsigned int endtime = soundtime + mixAheadTime * DeviceDmaSpeed(); + + int samps = DeviceSampleCount() >> (DeviceChannels()-1); + + if ((int)(endtime - soundtime) > samps) + endtime = soundtime + samps; + + if ((endtime - paintedtime) & 0x3) + { + // The difference between endtime and painted time should align on + // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz. + endtime -= (endtime - paintedtime) & 0x3; + } + + return endtime; +} + + +#ifdef OSX +ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) +{ + static alBufferDataStaticProcPtr proc = NULL; + + if (proc == NULL) { + proc = (alBufferDataStaticProcPtr) alGetProcAddress((const ALCchar*) "alBufferDataStatic"); + } + + if (proc) + proc(bid, format, data, size, freq); + +} +#endif + + +//----------------------------------------------------------------------------- +// Actually performs the mixing +//----------------------------------------------------------------------------- +void CAudioDeviceOpenAL::PaintEnd( void ) +{ + if ( !m_sndBuffers /*|| m_bSoundsShutdown*/ ) + return; + + ALint state; + ALenum error; + int iloop; + + int cblocks = 4 << 1; + ALint processed = 1; + ALuint lastUnqueuedBuffer = 0; + ALuint unqueuedBuffer = -1; + int nProcessedLoop = 200; // spin for a max of 200 times de-queing buffers, fixes a hang on exit + while ( processed > 0 && --nProcessedLoop > 0 ) + { + alGetSourcei( m_Source[ 0 ], AL_BUFFERS_PROCESSED, &processed); + error = alGetError(); + if (error != AL_NO_ERROR) + break; + + if ( processed > 0 ) + { + lastUnqueuedBuffer = unqueuedBuffer; + alSourceUnqueueBuffers( m_Source[ 0 ], 1, &unqueuedBuffer ); + error = alGetError(); + if ( error != AL_NO_ERROR && error != AL_INVALID_NAME ) + { + DevMsg( "Error alSourceUnqueueBuffers %d\n", error ); + break; + } + else + { + m_buffersCompleted++; // this buffer has been played + } + } + } + + // + // submit a few new sound blocks + // + // 44K sound support + while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks) + { + int iBuf = m_buffersSent&BUFF_MASK; +#ifdef OSX + alBufferDataStaticProc( m_Buffer[iBuf], AL_FORMAT_STEREO16, (char *)m_sndBuffers + iBuf*BUFFER_SIZE, BUFFER_SIZE, DeviceDmaSpeed() ); +#else + alBufferData( m_Buffer[iBuf], AL_FORMAT_STEREO16, (char *)m_sndBuffers + iBuf*BUFFER_SIZE, BUFFER_SIZE, DeviceDmaSpeed() ); +#endif + if ( (error = alGetError()) != AL_NO_ERROR ) + { + DevMsg( "Error alBufferData %d %d\n", iBuf, error ); + } + + alSourceQueueBuffers( m_Source[0], 1, &m_Buffer[iBuf] ); + if ( (error = alGetError() ) != AL_NO_ERROR ) + { + DevMsg( "Error alSourceQueueBuffers %d %d\n", iBuf, error ); + } + m_buffersSent++; + } + + // make sure the stream is playing + alGetSourcei( m_Source[ 0 ], AL_SOURCE_STATE, &state); + if ( state != AL_PLAYING ) + { + DevMsg( "Restarting sound playback\n" ); + alSourcePlay( m_Source[0] ); + if((error = alGetError()) != AL_NO_ERROR) + { + DevMsg( "Error alSourcePlay %d\n", error ); + } + } +} + +int CAudioDeviceOpenAL::GetOutputPosition( void ) +{ + int s = m_buffersSent * BUFFER_SIZE; + + s >>= SAMPLE_16BIT_SHIFT; + + s &= (DeviceSampleCount()-1); + + return s / DeviceChannels(); +} + + +//----------------------------------------------------------------------------- +// Pausing +//----------------------------------------------------------------------------- +void CAudioDeviceOpenAL::Pause( void ) +{ + m_pauseCount++; + if (m_pauseCount == 1) + { + alSourceStop( m_Source[0] ); + } +} + + +void CAudioDeviceOpenAL::UnPause( void ) +{ + if ( m_pauseCount > 0 ) + { + m_pauseCount--; + } + + if ( m_pauseCount == 0 ) + { + alSourcePlay( m_Source[0] ); + } +} + +bool CAudioDeviceOpenAL::IsActive( void ) +{ + return ( m_pauseCount == 0 ); +} + +float CAudioDeviceOpenAL::MixDryVolume( void ) +{ + return 0; +} + + +bool CAudioDeviceOpenAL::Should3DMix( void ) +{ + return false; +} + + +void CAudioDeviceOpenAL::ClearBuffer( void ) +{ + if ( !m_sndBuffers ) + return; + + Q_memset( m_sndBuffers, 0x0, DeviceSampleCount() * DeviceSampleBytes() ); +} + +void CAudioDeviceOpenAL::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up ) +{ +} + + +void CAudioDeviceOpenAL::MixBegin( int sampleCount ) +{ + MIX_ClearAllPaintBuffers( sampleCount, false ); +} + + +void CAudioDeviceOpenAL::MixUpsample( int sampleCount, int filtertype ) +{ + paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr(); + int ifilter = ppaint->ifilter; + + Assert (ifilter < CPAINTFILTERS); + + S_MixBufferUpsample2x( sampleCount, ppaint->pbuf, &(ppaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype ); + + ppaint->ifilter++; +} + +void CAudioDeviceOpenAL::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ) +{ + int volume[CCHANVOLUMES]; + paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr(); + + if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1)) + return; + + Mix8MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount ); +} + + +void CAudioDeviceOpenAL::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ) +{ + int volume[CCHANVOLUMES]; + paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr(); + + if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 )) + return; + + Mix8StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount ); +} + + +void CAudioDeviceOpenAL::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ) +{ + int volume[CCHANVOLUMES]; + paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr(); + + if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1 )) + return; + + Mix16MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount ); +} + + +void CAudioDeviceOpenAL::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress ) +{ + int volume[CCHANVOLUMES]; + paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr(); + + if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 )) + return; + + Mix16StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount ); +} + + +void CAudioDeviceOpenAL::ChannelReset( int entnum, int channelIndex, float distanceMod ) +{ +} + + +void CAudioDeviceOpenAL::TransferSamples( int end ) +{ + int lpaintedtime = g_paintedtime; + int endtime = end; + + // resumes playback... + + if ( m_sndBuffers ) + { + S_TransferStereo16( m_sndBuffers, PAINTBUFFER, lpaintedtime, endtime ); + } +} + +void CAudioDeviceOpenAL::SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono ) +{ + VPROF("CAudioDeviceOpenAL::SpatializeChannel"); + S_SpatializeChannel( volume, master_vol, &sourceDir, gain, mono ); +} + +void CAudioDeviceOpenAL::StopAllSounds( void ) +{ + m_bSoundsShutdown = true; + alSourceStop( m_Source[0] ); +} + + + +void CAudioDeviceOpenAL::ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount ) +{ + //SX_RoomFX( endtime, filter, timefx ); + DSP_Process( idsp, pbuffront, pbufrear, pbufcenter, samplecount ); +} + + +static uint32 GetOSXSpeakerConfig() +{ + return 2; +} + +static uint32 GetSpeakerConfigForSurroundMode( int surroundMode, const char **pConfigDesc ) +{ + uint32 newSpeakerConfig = 2; + *pConfigDesc = "stereo speaker"; + return newSpeakerConfig; +} + + + +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 ( flOldValue == -1 ) + return; + + // get the user's previous speaker config + uint32 speaker_config = GetOSXSpeakerConfig(); + + // get the new config + uint32 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 + //SetWindowsSpeakerConfig(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 ) +{ +} + +#endif // !DEDICATED + |