You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
9.3 KiB
403 lines
9.3 KiB
//===== 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 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, 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 );
|
|
}
|
|
}
|
|
|
|
|