diff options
-rw-r--r-- | OpenAL32/alSource.c | 345 |
1 files changed, 169 insertions, 176 deletions
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 540821eb..fef00e5a 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -54,7 +54,6 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); -static void SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); typedef enum SourceProp { @@ -2330,10 +2329,11 @@ AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) } AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { - ALCdevice *device; ALCcontext *context; + ALCdevice *device; ALsource *source; - ALsizei i; + ALvoice *voice; + ALsizei i, j; context = GetContextRef(); if(!context) return; @@ -2374,8 +2374,122 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { + ALbufferlistitem *BufferList; + ALbuffer *buffer = NULL; + source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_PLAYING); + WriteLock(&source->queue_lock); + /* Check that there is a queue containing at least one valid, non zero + * length Buffer. + */ + BufferList = ATOMIC_LOAD_SEQ(&source->queue); + while(BufferList) + { + if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) + break; + BufferList = BufferList->next; + } + + /* If there's nothing to play, go right to stopped. */ + if(!BufferList) + { + /* NOTE: A source without any playable buffers should not have an + * ALvoice since it shouldn't be in a playing or paused state. So + * there's no need to look up its voice and clear the source. + */ + ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + goto finish_play; + } + + voice = GetSourceVoice(source, context); + switch(GetSourceState(source, voice)) + { + case AL_PLAYING: + assert(voice != NULL); + /* A source that's already playing is restarted from the beginning. */ + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); + goto finish_play; + + case AL_PAUSED: + assert(voice != NULL); + /* A source that's paused simply resumes. Make sure it uses the + * volume last specified; there's no reason to fade from where + * it stopped at. + */ + voice->Flags &= ~VOICE_IS_MOVING; + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + goto finish_play; + + default: + break; + } + + source->NeedsUpdate = AL_FALSE; + UpdateSourceProps(source, device->NumAuxSends); + + /* Make sure this source isn't already active, and if not, look for an + * unused voice to put it in. + */ + assert(voice == NULL); + for(j = 0;j < context->VoiceCount;j++) + { + if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL) + { + voice = context->Voices[j]; + break; + } + } + if(voice == NULL) + voice = context->Voices[context->VoiceCount++]; + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); + if(source->OffsetType != AL_NONE) + ApplyOffset(source, voice); + + voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + voice->SampleSize = BytesFromFmt(buffer->FmtType); + + /* Clear previous samples. */ + memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + + /* Clear the stepping value so the mixer knows not to mix this until + * the update gets applied. + */ + voice->Step = 0; + + voice->Flags = 0; + for(j = 0;j < voice->NumChannels;j++) + memset(&voice->Direct.Params[j].Hrtf.State, 0, + sizeof(voice->Direct.Params[j].Hrtf.State)); + if(device->AvgSpeakerDist > 0.0f) + { + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + for(j = 0;j < voice->NumChannels;j++) + { + NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1); + NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1); + NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1); + } + } + + ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + finish_play: + WriteUnlock(&source->queue_lock); } ALCdevice_Unlock(device); @@ -2391,7 +2505,9 @@ AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) { ALCcontext *context; + ALCdevice *device; ALsource *source; + ALvoice *voice; ALsizei i; context = GetContextRef(); @@ -2406,13 +2522,23 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - ALCdevice_Lock(context->Device); + device = context->Device; + ALCdevice_Lock(device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_PAUSED); + WriteLock(&source->queue_lock); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } + if(GetSourceState(source, voice) == AL_PLAYING) + ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release); + WriteUnlock(&source->queue_lock); } - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); done: UnlockSourcesRead(context); @@ -2426,7 +2552,9 @@ AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) { ALCcontext *context; + ALCdevice *device; ALsource *source; + ALvoice *voice; ALsizei i; context = GetContextRef(); @@ -2441,13 +2569,26 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - ALCdevice_Lock(context->Device); + device = context->Device; + ALCdevice_Lock(device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_STOPPED); + WriteLock(&source->queue_lock); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } + if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL) + ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + WriteUnlock(&source->queue_lock); } - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); done: UnlockSourcesRead(context); @@ -2461,7 +2602,9 @@ AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) { ALCcontext *context; + ALCdevice *device; ALsource *source; + ALvoice *voice; ALsizei i; context = GetContextRef(); @@ -2476,13 +2619,26 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - ALCdevice_Lock(context->Device); + device = context->Device; + ALCdevice_Lock(device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_INITIAL); + WriteLock(&source->queue_lock); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } + if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL) + ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + WriteUnlock(&source->queue_lock); } - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); done: UnlockSourcesRead(context); @@ -2951,169 +3107,6 @@ void UpdateAllSourceProps(ALCcontext *context) } -/* SetSourceState - * - * Sets the source's new play state given its current state. - */ -static void SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) -{ - ALCdevice *device = Context->Device; - ALvoice *voice; - - WriteLock(&Source->queue_lock); - if(state == AL_PLAYING) - { - ALCdevice *device = Context->Device; - ALbufferlistitem *BufferList; - ALbuffer *buffer = NULL; - ALsizei i; - - /* Check that there is a queue containing at least one valid, non zero - * length Buffer. */ - BufferList = ATOMIC_LOAD_SEQ(&Source->queue); - while(BufferList) - { - if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) - break; - BufferList = BufferList->next; - } - - /* If there's nothing to play, go right to stopped. */ - if(!BufferList) - { - /* NOTE: A source without any playable buffers should not have an - * ALvoice since it shouldn't be in a playing or paused state. So - * there's no need to look up its voice and clear the source. - */ - ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - goto done; - } - - voice = GetSourceVoice(Source, Context); - switch(GetSourceState(Source, voice)) - { - case AL_PLAYING: - assert(voice != NULL); - /* A source that's already playing is restarted from the beginning. */ - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); - goto done; - - case AL_PAUSED: - assert(voice != NULL); - /* A source that's paused simply resumes. Make sure it uses the - * volume last specified; there's no reason to fade from where - * it stopped at. - */ - voice->Flags &= ~VOICE_IS_MOVING; - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - ATOMIC_STORE(&Source->state, AL_PLAYING, almemory_order_release); - goto done; - - default: - break; - } - - Source->NeedsUpdate = AL_FALSE; - UpdateSourceProps(Source, device->NumAuxSends); - - /* Make sure this source isn't already active, and if not, look for an - * unused voice to put it in. - */ - assert(voice == NULL); - for(i = 0;i < Context->VoiceCount;i++) - { - if(ATOMIC_LOAD(&Context->Voices[i]->Source, almemory_order_acquire) == NULL) - { - voice = Context->Voices[i]; - break; - } - } - if(voice == NULL) - voice = Context->Voices[Context->VoiceCount++]; - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - ATOMIC_THREAD_FENCE(almemory_order_acquire); - - /* A source that's not playing or paused has any offset applied when it - * starts playing. - */ - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); - if(Source->OffsetType != AL_NONE) - ApplyOffset(Source, voice); - - voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - voice->SampleSize = BytesFromFmt(buffer->FmtType); - - /* Clear previous samples. */ - memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); - - /* Clear the stepping value so the mixer knows not to mix this until - * the update gets applied. - */ - voice->Step = 0; - - voice->Flags = 0; - for(i = 0;i < MAX_INPUT_CHANNELS;i++) - { - ALsizei j; - for(j = 0;j < HRTF_HISTORY_LENGTH;j++) - voice->Direct.Params[i].Hrtf.State.History[j] = 0.0f; - for(j = 0;j < HRIR_LENGTH;j++) - { - voice->Direct.Params[i].Hrtf.State.Values[j][0] = 0.0f; - voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f; - } - } - if(device->AvgSpeakerDist > 0.0f) - { - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); - for(i = 0;i < voice->NumChannels;i++) - { - NfcFilterCreate1(&voice->Direct.Params[i].NFCtrlFilter[0], 0.0f, w1); - NfcFilterCreate2(&voice->Direct.Params[i].NFCtrlFilter[1], 0.0f, w1); - NfcFilterCreate3(&voice->Direct.Params[i].NFCtrlFilter[2], 0.0f, w1); - } - } - - ATOMIC_STORE(&voice->Source, Source, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - ATOMIC_STORE(&Source->state, AL_PLAYING, almemory_order_release); - } - else if(state == AL_PAUSED) - { - if((voice=GetSourceVoice(Source, Context)) != NULL) - { - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - } - if(GetSourceState(Source, voice) == AL_PLAYING) - ATOMIC_STORE(&Source->state, AL_PAUSED, almemory_order_release); - } - else /*if(state == AL_STOPPED || state == AL_INITIAL)*/ - { - if((voice=GetSourceVoice(Source, Context)) != NULL) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - } - if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - ATOMIC_STORE(&Source->state, state, almemory_order_relaxed); - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - } -done: - WriteUnlock(&Source->queue_lock); -} - /* GetSourceSampleOffset * * Gets the current read offset for the given Source, in 32.32 fixed-point |