csgo-2018-source/engine/audio/private/snd_dev_openal.cpp
2021-07-24 21:11:47 -07:00

404 lines
9.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "audio_pch.h"
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool snd_firsttime;
#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:
CAudioDeviceOpenAL()
{
m_pName = "OpenAL Audio";
m_nChannels = 2;
m_nSampleBits = 16;
m_nSampleRate = 44100;
m_bIsActive = true;
}
bool IsActive( void );
bool Init( void );
void Shutdown( void );
int GetOutputPosition( void );
void Pause( void );
void UnPause( void );
int64 PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime );
void PaintEnd( void );
void ClearBuffer( void );
void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
void TransferSamples( int end );
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_bHeadphone;
bool m_bSurround;
bool m_bSurroundCenter;
};
IAudioDevice *Audio_CreateOpenALDevice( void )
{
static CAudioDeviceOpenAL *wave = NULL;
if ( !wave )
{
wave = new CAudioDeviceOpenAL;
}
if ( wave->Init() )
return wave;
delete wave;
wave = NULL;
return NULL;
}
//-----------------------------------------------------------------------------
// Init, shutdown
//-----------------------------------------------------------------------------
bool CAudioDeviceOpenAL::Init( void )
{
m_SndBufSize = 0;
m_sndBuffers = NULL;
m_pauseCount = 0;
m_bIsHeadphone = false;
m_buffersSent = 0;
m_buffersCompleted = 0;
m_pauseCount = 0;
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 systemuse 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, SampleRate(), 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;
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
//-----------------------------------------------------------------------------
int64 CAudioDeviceOpenAL::PaintBegin( float mixAheadTime, int64 soundtime, int64 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
int64 endtime = soundtime + mixAheadTime * SampleRate();
int samps = DeviceSampleCount() >> (ChannelCount()-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;
}
//-----------------------------------------------------------------------------
// Actually performs the mixing
//-----------------------------------------------------------------------------
void CAudioDeviceOpenAL::PaintEnd( void )
{
if ( !m_sndBuffers )
return;
ALint state;
ALenum error;
int iloop;
int cblocks = 4 << 1;
ALint processed = 1;
while ( processed > 0 )
{
alGetSourcei( m_Source[ 0 ], AL_BUFFERS_PROCESSED, &processed);
if ( processed > 0 )
{
ALuint tempVal = 0;
alSourceUnqueueBuffers( m_Source[ 0 ], 1, &tempVal );
error = alGetError();
if ( error != AL_NO_ERROR && error != AL_INVALID_NAME )
{
DevMsg( "Error alSourceUnqueueBuffers %d\n", error );
}
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;
alBufferData( m_Buffer[iBuf], AL_FORMAT_STEREO16, (char *)m_sndBuffers + iBuf*BUFFER_SIZE, BUFFER_SIZE, SampleRate() );
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 )
{
Warning( "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 / ChannelCount();
}
//-----------------------------------------------------------------------------
// 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 );
}
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::TransferSamples( int end )
{
int64 lpaintedtime = g_paintedtime;
int64 endtime = end;
// resumes playback...
if ( m_sndBuffers )
{
S_TransferStereo16( m_sndBuffers, PAINTBUFFER, lpaintedtime, endtime );
}
}