summaryrefslogtreecommitdiffstats
path: root/src/audio/oal
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/audio/oal/channel.cpp56
-rw-r--r--src/audio/oal/channel.h6
-rw-r--r--src/audio/oal/stream.cpp79
-rw-r--r--src/audio/oal/stream.h3
4 files changed, 110 insertions, 34 deletions
diff --git a/src/audio/oal/channel.cpp b/src/audio/oal/channel.cpp
index 673a4aed..d1fd0aea 100644
--- a/src/audio/oal/channel.cpp
+++ b/src/audio/oal/channel.cpp
@@ -15,6 +15,8 @@ ALuint alFilters[MAXCHANNELS+MAX2DCHANNELS];
ALuint alBuffers[MAXCHANNELS+MAX2DCHANNELS];
bool bChannelsCreated = false;
+int32 CChannel::channelsThatNeedService = 0;
+
void
CChannel::InitChannels()
{
@@ -59,7 +61,9 @@ void CChannel::SetDefault()
Position[0] = 0.0f; Position[1] = 0.0f; Position[2] = 0.0f;
Distances[0] = 0.0f; Distances[1] = FLT_MAX;
- LoopCount = 1;
+
+ LoopCount = 1;
+ LastProcessedOffset = UINT32_MAX;
LoopPoints[0] = 0; LoopPoints[1] = -1;
Frequency = MAX_FREQ;
@@ -67,6 +71,10 @@ void CChannel::SetDefault()
void CChannel::Reset()
{
+ // Here is safe because ctor don't call this
+ if (LoopCount > 1)
+ channelsThatNeedService--;
+
ClearBuffer();
SetDefault();
}
@@ -165,10 +173,51 @@ void CChannel::SetCurrentFreq(uint32 freq)
SetPitch(ALfloat(freq) / Frequency);
}
-void CChannel::SetLoopCount(int32 loopCount) // fake. TODO:
+void CChannel::SetLoopCount(int32 count)
{
if ( !HasSource() ) return;
- alSourcei(alSources[id], AL_LOOPING, loopCount == 1 ? AL_FALSE : AL_TRUE);
+
+ // 0: loop indefinitely, 1: play one time, 2: play two times etc...
+ // only > 1 needs manual processing
+
+ if (LoopCount > 1 && count < 2)
+ channelsThatNeedService--;
+ else if (LoopCount < 2 && count > 1)
+ channelsThatNeedService++;
+
+ alSourcei(alSources[id], AL_LOOPING, count == 1 ? AL_FALSE : AL_TRUE);
+ LoopCount = count;
+}
+
+bool CChannel::Update()
+{
+ if (!HasSource()) return false;
+ if (LoopCount < 2) return false;
+
+ ALint state;
+ alGetSourcei(alSources[id], AL_SOURCE_STATE, &state);
+ if (state == AL_STOPPED) {
+ debug("Looping channels(%d in this case) shouldn't report AL_STOPPED, but nvm\n", id);
+ SetLoopCount(1);
+ return true;
+ }
+
+ assert(channelsThatNeedService > 0 && "Ref counting is broken");
+
+ ALint offset;
+ alGetSourcei(alSources[id], AL_SAMPLE_OFFSET, &offset);
+
+ // Rewound
+ if (offset < LastProcessedOffset) {
+ LoopCount--;
+ if (LoopCount == 1) {
+ // Playing last tune...
+ channelsThatNeedService--;
+ alSourcei(alSources[id], AL_LOOPING, AL_FALSE);
+ }
+ }
+ LastProcessedOffset = offset;
+ return true;
}
void CChannel::SetLoopPoints(ALint start, ALint end)
@@ -200,6 +249,7 @@ void CChannel::SetPan(int32 pan)
void CChannel::ClearBuffer()
{
if ( !HasSource() ) return;
+ alSourcei(alSources[id], AL_LOOPING, AL_FALSE);
alSourcei(alSources[id], AL_BUFFER, AL_NONE);
Data = nil;
DataSize = 0;
diff --git a/src/audio/oal/channel.h b/src/audio/oal/channel.h
index 81817a32..b081be25 100644
--- a/src/audio/oal/channel.h
+++ b/src/audio/oal/channel.h
@@ -19,7 +19,10 @@ class CChannel
float Distances[2];
int32 LoopCount;
ALint LoopPoints[2];
+ ALint LastProcessedOffset;
public:
+ static int32 channelsThatNeedService;
+
static void InitChannels();
static void DestroyChannels();
@@ -37,7 +40,7 @@ public:
void SetVolume(int32 vol);
void SetSampleData(void *_data, size_t _DataSize, int32 freq);
void SetCurrentFreq(uint32 freq);
- void SetLoopCount(int32 loopCount); // fake
+ void SetLoopCount(int32 count);
void SetLoopPoints(ALint start, ALint end);
void SetPosition(float x, float y, float z);
void SetDistances(float max, float min);
@@ -45,6 +48,7 @@ public:
void ClearBuffer();
void SetReverbMix(ALuint slot, float mix);
void UpdateReverb(ALuint slot);
+ bool Update();
};
#endif \ No newline at end of file
diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp
index 74ed86f4..61cd243d 100644
--- a/src/audio/oal/stream.cpp
+++ b/src/audio/oal/stream.cpp
@@ -492,6 +492,7 @@ public:
m_bOpened = mpg123_open(m_pMH, path) == MPG123_OK
&& mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;
+
m_nRate = rate;
m_nChannels = channels;
@@ -925,7 +926,8 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU
m_bReset(false),
m_nVolume(0),
m_nPan(0),
- m_nPosBeforeReset(0)
+ m_nPosBeforeReset(0),
+ m_nLoopCount(1)
{
// Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/)
@@ -1021,7 +1023,7 @@ bool CStream::IsPlaying()
ALint sourceState[2];
alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]);
alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]);
- if ( m_bActive || sourceState[0] == AL_PLAYING || sourceState[1] == AL_PLAYING)
+ if (sourceState[0] == AL_PLAYING || sourceState[1] == AL_PLAYING)
return true;
}
@@ -1179,6 +1181,8 @@ bool CStream::Setup()
{
if ( IsOpened() )
{
+ alSourcei(m_pAlSources[0], AL_LOOPING, AL_FALSE);
+ alSourcei(m_pAlSources[1], AL_LOOPING, AL_FALSE);
m_pSoundFile->Seek(0);
//SetPosition(0.0f, 0.0f, 0.0f);
SetPitch(1.0f);
@@ -1189,6 +1193,13 @@ bool CStream::Setup()
return IsOpened();
}
+void CStream::SetLoopCount(int32 count)
+{
+ if ( !HasSource() ) return;
+
+ m_nLoopCount = count;
+}
+
void CStream::SetPlay(bool state)
{
if ( !HasSource() ) return;
@@ -1248,7 +1259,7 @@ void CStream::Update()
if ( !m_bPaused )
{
- ALint sourceState[2];
+ ALint totalBuffers[2] = { 0, 0 };
ALint buffersProcessed[2] = { 0, 0 };
// Relying a lot on left buffer states in here
@@ -1256,44 +1267,51 @@ void CStream::Update()
do
{
//alSourcef(m_pAlSources[0], AL_ROLLOFF_FACTOR, 0.0f);
- alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]);
+ alGetSourcei(m_pAlSources[0], AL_BUFFERS_QUEUED, &totalBuffers[0]);
alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]);
//alSourcef(m_pAlSources[1], AL_ROLLOFF_FACTOR, 0.0f);
- alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]);
+ alGetSourcei(m_pAlSources[1], AL_BUFFERS_QUEUED, &totalBuffers[1]);
alGetSourcei(m_pAlSources[1], AL_BUFFERS_PROCESSED, &buffersProcessed[1]);
} while (buffersProcessed[0] != buffersProcessed[1]);
- ALint looping = AL_FALSE;
- alGetSourcei(m_pAlSources[0], AL_LOOPING, &looping);
-
- if ( looping == AL_TRUE )
+ assert(buffersProcessed[0] == buffersProcessed[1]);
+
+ // Correcting OpenAL concepts here:
+ // AL_BUFFERS_QUEUED = Number of *all* buffers in queue, including processed, processing and pending
+ // AL_BUFFERS_PROCESSED = Index of the buffer being processing right now. Buffers coming after that(have greater index) are pending buffers.
+ // which means: totalBuffers[0] - buffersProcessed[0] = pending buffers
+
+ bool buffersRefilled = false;
+
+ // We should wait queue to be cleared to loop track, because position calculation relies on queue.
+ if (m_nLoopCount != 1 && m_bActive && totalBuffers[0] == 0)
{
- TRACE("stream set looping");
- alSourcei(m_pAlSources[0], AL_LOOPING, AL_TRUE);
- alSourcei(m_pAlSources[1], AL_LOOPING, AL_TRUE);
+ Setup();
+ buffersRefilled = FillBuffers() != 0;
+ if (m_nLoopCount != 0)
+ m_nLoopCount--;
}
-
- assert(buffersProcessed[0] == buffersProcessed[1]);
-
- while( buffersProcessed[0]-- )
+ else
{
- ALuint buffer[2];
-
- alSourceUnqueueBuffers(m_pAlSources[0], 1, &buffer[0]);
- alSourceUnqueueBuffers(m_pAlSources[1], 1, &buffer[1]);
-
- if (m_bActive && FillBuffer(buffer))
+ while( buffersProcessed[0]-- )
{
- alSourceQueueBuffers(m_pAlSources[0], 1, &buffer[0]);
- alSourceQueueBuffers(m_pAlSources[1], 1, &buffer[1]);
+ ALuint buffer[2];
+
+ alSourceUnqueueBuffers(m_pAlSources[0], 1, &buffer[0]);
+ alSourceUnqueueBuffers(m_pAlSources[1], 1, &buffer[1]);
+
+ if (m_bActive && FillBuffer(buffer))
+ {
+ buffersRefilled = true;
+ alSourceQueueBuffers(m_pAlSources[0], 1, &buffer[0]);
+ alSourceQueueBuffers(m_pAlSources[1], 1, &buffer[1]);
+ }
}
}
-
- if ( sourceState[0] != AL_PLAYING )
- {
- alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]);
- SetPlay(buffersProcessed[0]!=0);
- }
+
+ // Two reasons: 1-Source may be starved to audio and stopped itself, 2- We're already waiting it to starve and die for looping track!
+ if (m_bActive && (buffersRefilled || (totalBuffers[1] - buffersProcessed[1] != 0)))
+ SetPlay(true);
}
}
@@ -1305,6 +1323,7 @@ void CStream::ProviderInit()
{
SetPan(m_nPan);
SetVolume(m_nVolume);
+ SetLoopCount(m_nLoopCount);
SetPosMS(m_nPosBeforeReset);
if (m_bActive)
FillBuffers();
diff --git a/src/audio/oal/stream.h b/src/audio/oal/stream.h
index bcbc5e54..b3e96809 100644
--- a/src/audio/oal/stream.h
+++ b/src/audio/oal/stream.h
@@ -69,6 +69,7 @@ class CStream
uint32 m_nVolume;
uint8 m_nPan;
uint32 m_nPosBeforeReset;
+ int32 m_nLoopCount;
IDecoder *m_pSoundFile;
@@ -103,6 +104,8 @@ public:
void Start();
void Stop();
void Update(void);
+ void SetLoopCount(int32);
+
void ProviderInit();
void ProviderTerm();