Skip to content
This repository has been archived by the owner. It is now read-only.

OAL Loops, fixes #1018

Merged
merged 1 commit into from Feb 2, 2021
Merged
Changes from all commits
Commits
File filter
Filter file types
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.

Always

Just for now

OAL Loops, fixes
  • Loading branch information
erorcun committed Feb 2, 2021
commit 713562685a89578ae5e4008f0a283c39175429fc
@@ -15,6 +15,8 @@ ALuint alFilters[MAXCHANNELS+MAX2DCHANNELS];
ALuint alBuffers[MAXCHANNELS+MAX2DCHANNELS];
bool bChannelsCreated = false;

int32 CChannel::channelsThatNeedService = 0;

void
CChannel::InitChannels()
{
@@ -59,14 +61,20 @@ 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;
}

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;
@@ -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,14 +40,15 @@ class CChannel
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);
void SetPan(int32 pan);
void ClearBuffer();
void SetReverbMix(ALuint slot, float mix);
void UpdateReverb(ALuint slot);
bool Update();
};

#endif
@@ -499,6 +499,7 @@ class CMP3File : public IDecoder

m_bOpened = mpg123_open(m_pMH, path) == MPG123_OK
&& mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;

m_nRate = rate;
m_nChannels = channels;

@@ -980,7 +981,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/)
@@ -1078,7 +1080,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;
}

@@ -1236,6 +1238,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);
@@ -1246,6 +1250,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;
@@ -1305,52 +1316,59 @@ 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

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 )
{
TRACE("stream set looping");
alSourcei(m_pAlSources[0], AL_LOOPING, AL_TRUE);
alSourcei(m_pAlSources[1], AL_LOOPING, AL_TRUE);
}

assert(buffersProcessed[0] == buffersProcessed[1]);

while( buffersProcessed[0]-- )
// 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)
{
ALuint buffer[2];

alSourceUnqueueBuffers(m_pAlSources[0], 1, &buffer[0]);
alSourceUnqueueBuffers(m_pAlSources[1], 1, &buffer[1]);

if (m_bActive && FillBuffer(buffer))
{
alSourceQueueBuffers(m_pAlSources[0], 1, &buffer[0]);
alSourceQueueBuffers(m_pAlSources[1], 1, &buffer[1]);
}
Setup();
buffersRefilled = FillBuffers() != 0;
if (m_nLoopCount != 0)
m_nLoopCount--;
}

if ( sourceState[0] != AL_PLAYING )
else
{
alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]);
SetPlay(buffersProcessed[0]!=0);
while( buffersProcessed[0]-- )
{
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]);
}
}
}

// 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);
}
}

@@ -1362,6 +1380,7 @@ void CStream::ProviderInit()
{
SetPan(m_nPan);
SetVolume(m_nVolume);
SetLoopCount(m_nLoopCount);
SetPosMS(m_nPosBeforeReset);
if (m_bActive)
FillBuffers();
@@ -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 @@ class CStream
void Start();
void Stop();
void Update(void);
void SetLoopCount(int32);


void ProviderInit();
void ProviderTerm();