oal wav/mp3 stream update
This commit is contained in:
@@ -1,48 +1,223 @@
|
||||
#include "stream.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifdef AUDIO_OAL
|
||||
#include "common.h"
|
||||
#include "sampman.h"
|
||||
|
||||
typedef long ssize_t;
|
||||
|
||||
#include <sndfile.h>
|
||||
#include <mpg123.h>
|
||||
|
||||
#pragma comment( lib, "libsndfile-1.lib" )
|
||||
#pragma comment( lib, "libmpg123.lib" )
|
||||
|
||||
class CSndFile : public IDecoder
|
||||
{
|
||||
SNDFILE *m_pfSound;
|
||||
SF_INFO m_soundInfo;
|
||||
public:
|
||||
CSndFile(const char *path) :
|
||||
m_pfSound(nil)
|
||||
{
|
||||
memset(&m_soundInfo, 0, sizeof(m_soundInfo));
|
||||
m_pfSound = sf_open(path, SFM_READ, &m_soundInfo);
|
||||
}
|
||||
|
||||
~CSndFile()
|
||||
{
|
||||
if ( m_pfSound )
|
||||
{
|
||||
sf_close(m_pfSound);
|
||||
m_pfSound = nil;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOpened()
|
||||
{
|
||||
return m_pfSound != nil;
|
||||
}
|
||||
|
||||
uint32 GetSampleSize()
|
||||
{
|
||||
return sizeof(uint16);
|
||||
}
|
||||
|
||||
uint32 GetSampleCount()
|
||||
{
|
||||
return m_soundInfo.frames;
|
||||
}
|
||||
|
||||
uint32 GetSampleRate()
|
||||
{
|
||||
return m_soundInfo.samplerate;
|
||||
}
|
||||
|
||||
uint32 GetChannels()
|
||||
{
|
||||
return m_soundInfo.channels;
|
||||
}
|
||||
|
||||
void Seek(uint32 milliseconds)
|
||||
{
|
||||
if ( !IsOpened() ) return;
|
||||
sf_seek(m_pfSound, ms2samples(milliseconds), SF_SEEK_SET);
|
||||
}
|
||||
|
||||
uint32 Tell()
|
||||
{
|
||||
if ( !IsOpened() ) return 0;
|
||||
return samples2ms(sf_seek(m_pfSound, 0, SF_SEEK_CUR));
|
||||
}
|
||||
|
||||
uint32 Decode(void *buffer)
|
||||
{
|
||||
if ( !IsOpened() ) return 0;
|
||||
return sf_read_short(m_pfSound, (short *)buffer, GetBufferSamples()) * GetSampleSize();
|
||||
}
|
||||
};
|
||||
|
||||
class CMP3File : public IDecoder
|
||||
{
|
||||
mpg123_handle *m_pMH;
|
||||
bool m_bOpened;
|
||||
uint32 m_nRate;
|
||||
uint32 m_nChannels;
|
||||
public:
|
||||
CMP3File(const char *path) :
|
||||
m_pMH(nil),
|
||||
m_bOpened(false),
|
||||
m_nRate(0),
|
||||
m_nChannels(0)
|
||||
{
|
||||
m_pMH = mpg123_new(nil, nil);
|
||||
if ( m_pMH )
|
||||
{
|
||||
long rate = 0;
|
||||
int channels = 0;
|
||||
int encoding = 0;
|
||||
|
||||
m_bOpened = mpg123_open(m_pMH, path) == MPG123_OK
|
||||
&& mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;
|
||||
m_nRate = rate;
|
||||
m_nChannels = channels;
|
||||
|
||||
if ( IsOpened() )
|
||||
{
|
||||
mpg123_format_none(m_pMH);
|
||||
mpg123_format(m_pMH, rate, channels, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~CMP3File()
|
||||
{
|
||||
if ( m_pMH )
|
||||
{
|
||||
mpg123_close(m_pMH);
|
||||
mpg123_delete(m_pMH);
|
||||
m_pMH = nil;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOpened()
|
||||
{
|
||||
return m_bOpened;
|
||||
}
|
||||
|
||||
uint32 GetSampleSize()
|
||||
{
|
||||
return sizeof(uint16);
|
||||
}
|
||||
|
||||
uint32 GetSampleCount()
|
||||
{
|
||||
if ( !IsOpened() ) return 0;
|
||||
return mpg123_length(m_pMH);
|
||||
}
|
||||
|
||||
uint32 GetSampleRate()
|
||||
{
|
||||
return m_nRate;
|
||||
}
|
||||
|
||||
uint32 GetChannels()
|
||||
{
|
||||
return m_nChannels;
|
||||
}
|
||||
|
||||
void Seek(uint32 milliseconds)
|
||||
{
|
||||
if ( !IsOpened() ) return;
|
||||
mpg123_seek(m_pMH, ms2samples(milliseconds)*GetSampleSize(), SEEK_SET);
|
||||
}
|
||||
|
||||
uint32 Tell()
|
||||
{
|
||||
if ( !IsOpened() ) return 0;
|
||||
return samples2ms(mpg123_tell(m_pMH)/GetSampleSize());
|
||||
}
|
||||
|
||||
uint32 Decode(void *buffer)
|
||||
{
|
||||
if ( !IsOpened() ) return 0;
|
||||
|
||||
size_t size;
|
||||
int err = mpg123_read(m_pMH, (unsigned char *)buffer, GetBufferSize(), &size);
|
||||
if (err != MPG123_OK && err != MPG123_DONE) return 0;
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
void CStream::Initialise()
|
||||
{
|
||||
//mpg123_init();
|
||||
mpg123_init();
|
||||
}
|
||||
|
||||
void CStream::Terminate()
|
||||
{
|
||||
//mpg123_exit();
|
||||
mpg123_exit();
|
||||
}
|
||||
|
||||
CStream::CStream(char *filename, ALuint &source, ALuint (&buffers)[NUM_STREAMBUFFERS]) :
|
||||
m_alSource(source),
|
||||
m_alBuffers(buffers),
|
||||
m_nBitRate(0),
|
||||
m_nFormat(0),
|
||||
m_nFreq(0),
|
||||
m_nLength(0),
|
||||
m_nLengthMS(0),
|
||||
m_nBufferSize(0),
|
||||
m_pBuffer(NULL),
|
||||
m_bIsOpened(false),
|
||||
m_bPaused(true)
|
||||
m_pBuffer(nil),
|
||||
m_bPaused(false),
|
||||
m_bActive(false),
|
||||
m_pSoundFile(nil),
|
||||
m_bReset(false),
|
||||
m_nVolume(0),
|
||||
m_nPan(0),
|
||||
m_nPosBeforeReset(0)
|
||||
|
||||
{
|
||||
strcpy(m_aFilename, filename);
|
||||
|
||||
//DEV("Stream %s\n", m_aFilename);
|
||||
DEV("Stream %s\n", m_aFilename);
|
||||
|
||||
/*
|
||||
if ( true )
|
||||
{
|
||||
m_nBitRate = (wBitsPerSample * nChannels * wfex.nSamplesPerSec)/1000;
|
||||
m_nLength = ulDataSize;
|
||||
m_nLengthMS = m_nLength*8 / m_nBitRate;
|
||||
m_nBufferSize = nAvgBytesPerSec >> 2;
|
||||
m_nBufferSize -= (m_nLength % wfex.nBlockAlign);
|
||||
m_pBuffer = malloc(m_nBufferSize);
|
||||
m_bIsOpened = true;
|
||||
if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3"))
|
||||
m_pSoundFile = new CMP3File(m_aFilename);
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav"))
|
||||
m_pSoundFile = new CSndFile(m_aFilename);
|
||||
else
|
||||
m_pSoundFile = nil;
|
||||
ASSERT(m_pSoundFile != nil);
|
||||
if (m_pSoundFile && m_pSoundFile->IsOpened() )
|
||||
{
|
||||
m_pBuffer = malloc(m_pSoundFile->GetBufferSize());
|
||||
ASSERT(m_pBuffer!=nil);
|
||||
|
||||
DEV("AvgSamplesPerSec: %d\n", m_pSoundFile->GetAvgSamplesPerSec());
|
||||
DEV("SampleCount: %d\n", m_pSoundFile->GetSampleCount());
|
||||
DEV("SampleRate: %d\n", m_pSoundFile->GetSampleRate());
|
||||
DEV("Channels: %d\n", m_pSoundFile->GetChannels());
|
||||
DEV("Buffer Samples: %d\n", m_pSoundFile->GetBufferSamples());
|
||||
DEV("Buffer sec: %f\n", (float(m_pSoundFile->GetBufferSamples()) / float(m_pSoundFile->GetChannels())/ float(m_pSoundFile->GetSampleRate())));
|
||||
DEV("Length MS: %02d:%02d\n", (m_pSoundFile->GetLength() / 1000) / 60, (m_pSoundFile->GetLength() / 1000) % 60);
|
||||
|
||||
return;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
CStream::~CStream()
|
||||
@@ -51,68 +226,295 @@ CStream::~CStream()
|
||||
}
|
||||
|
||||
void CStream::Delete()
|
||||
{
|
||||
{
|
||||
Stop();
|
||||
ClearBuffers();
|
||||
|
||||
if ( m_pSoundFile )
|
||||
{
|
||||
delete m_pSoundFile;
|
||||
m_pSoundFile = nil;
|
||||
}
|
||||
|
||||
if ( m_pBuffer )
|
||||
{
|
||||
free(m_pBuffer);
|
||||
m_pBuffer = NULL;
|
||||
m_pBuffer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
bool CStream::HasSource()
|
||||
{
|
||||
return m_alSource != AL_NONE;
|
||||
}
|
||||
|
||||
bool CStream::IsOpened()
|
||||
{
|
||||
return m_bIsOpened;
|
||||
return m_pSoundFile->IsOpened();
|
||||
}
|
||||
|
||||
bool CStream::IsPlaying()
|
||||
{
|
||||
if ( !HasSource() || !IsOpened() ) return false;
|
||||
|
||||
if ( m_pSoundFile->IsOpened() && !m_bPaused )
|
||||
{
|
||||
ALint sourceState;
|
||||
alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
|
||||
if ( m_bActive || sourceState == AL_PLAYING )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CStream::Pause()
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
ALint sourceState = AL_PAUSED;
|
||||
alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
|
||||
if (sourceState != AL_PAUSED )
|
||||
alSourcePause(m_alSource);
|
||||
}
|
||||
|
||||
void CStream::SetPause(bool bPause)
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
if ( bPause )
|
||||
{
|
||||
Pause();
|
||||
m_bPaused = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bPaused)
|
||||
SetPlay(true);
|
||||
m_bPaused = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CStream::SetPitch(float pitch)
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
alSourcef(m_alSource, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void CStream::SetGain(float gain)
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
alSourcef(m_alSource, AL_GAIN, gain);
|
||||
}
|
||||
|
||||
void CStream::SetPosition(float x, float y, float z)
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
alSource3f(m_alSource, AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void CStream::SetVolume(uint32 nVol)
|
||||
{
|
||||
|
||||
m_nVolume = nVol;
|
||||
SetGain(ALfloat(nVol) / MAX_VOLUME);
|
||||
}
|
||||
|
||||
void CStream::SetPan(uint8 nPan)
|
||||
{
|
||||
m_nPan = nPan;
|
||||
SetPosition((nPan - 63)/64.0f, 0.0f, Sqrt(1.0f-SQR((nPan-63)/64.0f)));
|
||||
}
|
||||
|
||||
void CStream::SetPos(uint32 nPos)
|
||||
void CStream::SetPosMS(uint32 nPos)
|
||||
{
|
||||
if ( !m_pSoundFile->IsOpened() ) return;
|
||||
m_pSoundFile->Seek(nPos);
|
||||
ClearBuffers();
|
||||
}
|
||||
|
||||
uint32 CStream::GetPos()
|
||||
uint32 CStream::GetPosMS()
|
||||
{
|
||||
return 0;
|
||||
if ( !HasSource() ) return 0;
|
||||
if ( !m_pSoundFile->IsOpened() ) return 0;
|
||||
|
||||
ALint offset;
|
||||
//alGetSourcei(m_alSource, AL_SAMPLE_OFFSET, &offset);
|
||||
alGetSourcei(m_alSource, AL_BYTE_OFFSET, &offset);
|
||||
|
||||
return m_pSoundFile->Tell()
|
||||
- m_pSoundFile->samples2ms(m_pSoundFile->GetBufferSamples() * (NUM_STREAMBUFFERS-1))
|
||||
+ m_pSoundFile->samples2ms(offset/m_pSoundFile->GetSampleSize());
|
||||
}
|
||||
|
||||
uint32 CStream::GetLength()
|
||||
uint32 CStream::GetLengthMS()
|
||||
{
|
||||
return m_nLengthMS;
|
||||
if ( !m_pSoundFile->IsOpened() ) return 0;
|
||||
return m_pSoundFile->GetLength();
|
||||
}
|
||||
|
||||
bool CStream::FillBuffer(ALuint alBuffer)
|
||||
{
|
||||
if ( !HasSource() )
|
||||
return false;
|
||||
if ( !m_pSoundFile->IsOpened() )
|
||||
return false;
|
||||
if ( !(alBuffer != AL_NONE && alIsBuffer(alBuffer)) )
|
||||
return false;
|
||||
|
||||
uint32 size = m_pSoundFile->Decode(m_pBuffer);
|
||||
if( size == 0 )
|
||||
return false;
|
||||
|
||||
alBufferData(alBuffer, m_pSoundFile->GetChannels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16,
|
||||
m_pBuffer, size, m_pSoundFile->GetSampleRate());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 CStream::FillBuffers()
|
||||
{
|
||||
int32 i = 0;
|
||||
for ( i = 0; i < NUM_STREAMBUFFERS; i++ )
|
||||
{
|
||||
if ( !FillBuffer(m_alBuffers[i]) )
|
||||
break;
|
||||
alSourceQueueBuffers(m_alSource, 1, &m_alBuffers[i]);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void CStream::ClearBuffers()
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
|
||||
ALint buffersQueued;
|
||||
alGetSourcei(m_alSource, AL_BUFFERS_QUEUED, &buffersQueued);
|
||||
|
||||
ALuint value;
|
||||
while (buffersQueued--)
|
||||
alSourceUnqueueBuffers(m_alSource, 1, &value);
|
||||
}
|
||||
|
||||
bool CStream::Setup()
|
||||
{
|
||||
if ( !IsOpened() )
|
||||
return false;
|
||||
|
||||
if ( m_pSoundFile->IsOpened() )
|
||||
{
|
||||
m_pSoundFile->Seek(0);
|
||||
alSourcei(m_alSource, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
//SetPosition(0.0f, 0.0f, 0.0f);
|
||||
SetPitch(1.0f);
|
||||
//SetPan(m_nPan);
|
||||
//SetVolume(100);
|
||||
}
|
||||
|
||||
return IsOpened();
|
||||
}
|
||||
|
||||
void CStream::SetPlay(bool state)
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
if ( state )
|
||||
{
|
||||
ALint sourceState = AL_PLAYING;
|
||||
alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
|
||||
if (sourceState != AL_PLAYING )
|
||||
alSourcePlay(m_alSource);
|
||||
m_bActive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ALint sourceState = AL_STOPPED;
|
||||
alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
|
||||
if (sourceState != AL_STOPPED )
|
||||
alSourceStop(m_alSource);
|
||||
m_bActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CStream::Start()
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
if ( FillBuffers() != 0 )
|
||||
SetPlay(true);
|
||||
}
|
||||
|
||||
void CStream::Stop()
|
||||
{
|
||||
if ( !HasSource() ) return;
|
||||
SetPlay(false);
|
||||
}
|
||||
|
||||
void CStream::Update()
|
||||
{
|
||||
if ( !IsOpened() )
|
||||
return;
|
||||
|
||||
if ( !HasSource() )
|
||||
return;
|
||||
|
||||
if ( m_bReset )
|
||||
return;
|
||||
|
||||
if ( !m_bPaused )
|
||||
{
|
||||
ALint sourceState;
|
||||
ALint buffersProcessed = 0;
|
||||
|
||||
alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
|
||||
alGetSourcei(m_alSource, AL_BUFFERS_PROCESSED, &buffersProcessed);
|
||||
|
||||
ALint looping = AL_FALSE;
|
||||
alGetSourcei(m_alSource, AL_LOOPING, &looping);
|
||||
|
||||
if ( looping == AL_TRUE )
|
||||
{
|
||||
TRACE("stream set looping");
|
||||
alSourcei(m_alSource, AL_LOOPING, AL_TRUE);
|
||||
}
|
||||
|
||||
while( buffersProcessed-- )
|
||||
{
|
||||
ALuint buffer;
|
||||
|
||||
alSourceUnqueueBuffers(m_alSource, 1, &buffer);
|
||||
|
||||
if ( m_bActive && FillBuffer(buffer) )
|
||||
alSourceQueueBuffers(m_alSource, 1, &buffer);
|
||||
}
|
||||
|
||||
if ( sourceState != AL_PLAYING )
|
||||
{
|
||||
alGetSourcei(m_alSource, AL_BUFFERS_PROCESSED, &buffersProcessed);
|
||||
SetPlay(buffersProcessed!=0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CStream::ProviderInit()
|
||||
{
|
||||
if ( m_bReset )
|
||||
{
|
||||
if ( Setup() )
|
||||
{
|
||||
SetPan(m_nPan);
|
||||
SetVolume(m_nVolume);
|
||||
SetPosMS(m_nPosBeforeReset);
|
||||
if (m_bActive)
|
||||
FillBuffers();
|
||||
SetPlay(m_bActive);
|
||||
if ( m_bPaused )
|
||||
Pause();
|
||||
}
|
||||
|
||||
m_bReset = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CStream::ProviderTerm()
|
||||
{
|
||||
m_bReset = true;
|
||||
m_nPosBeforeReset = GetPosMS();
|
||||
|
||||
ClearBuffers();
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user