2007-11-13 18:02:18 -08:00
|
|
|
/**
|
|
|
|
* OpenAL cross platform audio library
|
|
|
|
* Copyright (C) 1999-2007 by authors.
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
2014-08-18 14:11:03 +02:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2007-11-13 18:02:18 -08:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
2008-01-16 14:09:04 -08:00
|
|
|
#include "config.h"
|
|
|
|
|
2019-07-29 17:54:07 -07:00
|
|
|
#include "source.h"
|
2012-08-20 12:22:00 -07:00
|
|
|
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
|
|
|
#include <atomic>
|
|
|
|
#include <cassert>
|
|
|
|
#include <chrono>
|
|
|
|
#include <climits>
|
2018-11-18 03:25:32 -08:00
|
|
|
#include <cmath>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <cstdint>
|
|
|
|
#include <functional>
|
|
|
|
#include <iterator>
|
2018-11-22 12:02:02 -08:00
|
|
|
#include <limits>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <memory>
|
|
|
|
#include <mutex>
|
|
|
|
#include <new>
|
2019-03-09 15:04:51 -08:00
|
|
|
#include <numeric>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <thread>
|
|
|
|
#include <utility>
|
2018-11-18 02:15:31 -08:00
|
|
|
|
2007-11-13 18:02:18 -08:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "AL/alext.h"
|
|
|
|
#include "AL/efx.h"
|
2018-11-17 23:02:27 -08:00
|
|
|
|
2019-07-28 18:33:29 -07:00
|
|
|
#include "alcmain.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "alcontext.h"
|
2019-04-10 17:47:13 -07:00
|
|
|
#include "alexcpt.h"
|
2016-03-29 00:44:58 -07:00
|
|
|
#include "almalloc.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "alnumeric.h"
|
|
|
|
#include "alu.h"
|
|
|
|
#include "ambidefs.h"
|
|
|
|
#include "atomic.h"
|
2019-07-29 17:54:07 -07:00
|
|
|
#include "auxeffectslot.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "backends/base.h"
|
|
|
|
#include "bformatdec.h"
|
2019-07-29 17:54:07 -07:00
|
|
|
#include "buffer.h"
|
2019-07-29 15:57:48 -07:00
|
|
|
#include "event.h"
|
2019-07-29 17:54:07 -07:00
|
|
|
#include "filter.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "filters/nfc.h"
|
|
|
|
#include "filters/splitter.h"
|
|
|
|
#include "inprogext.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "math_defs.h"
|
|
|
|
#include "opthelpers.h"
|
|
|
|
#include "ringbuffer.h"
|
|
|
|
#include "threads.h"
|
2014-05-11 03:52:22 -07:00
|
|
|
|
2010-11-28 17:37:14 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
namespace {
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-12-26 21:55:39 -08:00
|
|
|
using namespace std::placeholders;
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context)
|
2018-01-27 13:02:17 -08:00
|
|
|
{
|
2019-08-02 12:38:20 -07:00
|
|
|
ALuint idx{source->VoiceIdx};
|
|
|
|
if(idx < context->mVoiceCount.load(std::memory_order_relaxed))
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2018-11-30 10:08:18 -08:00
|
|
|
ALuint sid{source->id};
|
2019-07-30 09:05:54 -07:00
|
|
|
ALvoice &voice = (*context->mVoices)[idx];
|
2019-06-09 18:13:54 -07:00
|
|
|
if(voice.mSourceID.load(std::memory_order_acquire) == sid)
|
|
|
|
return &voice;
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-08-02 12:38:20 -07:00
|
|
|
source->VoiceIdx = INVALID_VOICE_IDX;
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
2018-01-27 13:02:17 -08:00
|
|
|
}
|
2018-01-27 11:56:31 -08:00
|
|
|
|
2018-12-26 22:27:34 -08:00
|
|
|
void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context)
|
2018-01-27 01:51:01 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Get an unused property container, or allocate a new one as needed. */
|
2019-07-30 09:05:54 -07:00
|
|
|
ALvoiceProps *props{context->mFreeVoiceProps.load(std::memory_order_acquire)};
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!props)
|
2018-11-30 16:56:23 -08:00
|
|
|
props = new ALvoiceProps{};
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ALvoiceProps *next;
|
|
|
|
do {
|
|
|
|
next = props->next.load(std::memory_order_relaxed);
|
2019-07-30 09:05:54 -07:00
|
|
|
} while(context->mFreeVoiceProps.compare_exchange_weak(props, next,
|
2018-11-22 12:02:02 -08:00
|
|
|
std::memory_order_acq_rel, std::memory_order_acquire) == 0);
|
|
|
|
}
|
2018-01-27 01:51:01 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Copy in current property values. */
|
|
|
|
props->Pitch = source->Pitch;
|
|
|
|
props->Gain = source->Gain;
|
|
|
|
props->OuterGain = source->OuterGain;
|
|
|
|
props->MinGain = source->MinGain;
|
|
|
|
props->MaxGain = source->MaxGain;
|
|
|
|
props->InnerAngle = source->InnerAngle;
|
|
|
|
props->OuterAngle = source->OuterAngle;
|
|
|
|
props->RefDistance = source->RefDistance;
|
|
|
|
props->MaxDistance = source->MaxDistance;
|
|
|
|
props->RolloffFactor = source->RolloffFactor;
|
2018-12-26 22:27:34 -08:00
|
|
|
props->Position = source->Position;
|
|
|
|
props->Velocity = source->Velocity;
|
|
|
|
props->Direction = source->Direction;
|
|
|
|
props->OrientAt = source->OrientAt;
|
|
|
|
props->OrientUp = source->OrientUp;
|
2018-11-22 12:02:02 -08:00
|
|
|
props->HeadRelative = source->HeadRelative;
|
|
|
|
props->mDistanceModel = source->mDistanceModel;
|
2018-12-24 19:29:01 -08:00
|
|
|
props->mResampler = source->mResampler;
|
2018-11-22 12:02:02 -08:00
|
|
|
props->DirectChannels = source->DirectChannels;
|
2018-12-24 19:29:01 -08:00
|
|
|
props->mSpatializeMode = source->mSpatialize;
|
2018-01-27 19:40:47 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
props->DryGainHFAuto = source->DryGainHFAuto;
|
|
|
|
props->WetGainAuto = source->WetGainAuto;
|
|
|
|
props->WetGainHFAuto = source->WetGainHFAuto;
|
|
|
|
props->OuterGainHF = source->OuterGainHF;
|
2018-01-27 19:40:47 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
props->AirAbsorptionFactor = source->AirAbsorptionFactor;
|
|
|
|
props->RoomRolloffFactor = source->RoomRolloffFactor;
|
|
|
|
props->DopplerFactor = source->DopplerFactor;
|
2018-01-27 17:24:18 -08:00
|
|
|
|
2018-12-26 22:27:34 -08:00
|
|
|
props->StereoPan = source->StereoPan;
|
2018-01-27 01:51:01 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
props->Radius = source->Radius;
|
2015-09-22 08:48:26 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
props->Direct.Gain = source->Direct.Gain;
|
|
|
|
props->Direct.GainHF = source->Direct.GainHF;
|
|
|
|
props->Direct.HFReference = source->Direct.HFReference;
|
|
|
|
props->Direct.GainLF = source->Direct.GainLF;
|
|
|
|
props->Direct.LFReference = source->Direct.LFReference;
|
2015-09-22 08:48:26 -07:00
|
|
|
|
2018-12-26 22:27:34 -08:00
|
|
|
auto copy_send = [](const ALsource::SendData &srcsend) noexcept -> ALvoicePropsBase::SendData
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2018-12-26 22:27:34 -08:00
|
|
|
ALvoicePropsBase::SendData ret;
|
|
|
|
ret.Slot = srcsend.Slot;
|
|
|
|
ret.Gain = srcsend.Gain;
|
|
|
|
ret.GainHF = srcsend.GainHF;
|
|
|
|
ret.HFReference = srcsend.HFReference;
|
|
|
|
ret.GainLF = srcsend.GainLF;
|
|
|
|
ret.LFReference = srcsend.LFReference;
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send);
|
2012-12-05 09:22:38 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Set the new container for updating internal parameters. */
|
2019-03-10 16:29:06 -07:00
|
|
|
props = voice->mUpdate.exchange(props, std::memory_order_acq_rel);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(props)
|
|
|
|
{
|
|
|
|
/* If there was an unused update container, put it back in the
|
|
|
|
* freelist.
|
|
|
|
*/
|
2019-07-30 09:05:54 -07:00
|
|
|
AtomicReplaceHead(context->mFreeVoiceProps, props);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
}
|
2012-12-05 09:22:38 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* GetSourceSampleOffset
|
|
|
|
*
|
|
|
|
* Gets the current read offset for the given Source, in 32.32 fixed-point
|
|
|
|
* samples. The offset is relative to the start of the queue (not the start of
|
|
|
|
* the current buffer).
|
|
|
|
*/
|
2019-02-11 12:16:58 -08:00
|
|
|
int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2018-11-22 12:02:02 -08:00
|
|
|
const ALbufferlistitem *Current;
|
2019-02-11 12:16:58 -08:00
|
|
|
uint64_t readPos;
|
2018-11-22 12:02:02 -08:00
|
|
|
ALuint refcount;
|
|
|
|
ALvoice *voice;
|
2012-12-05 13:48:33 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
do {
|
|
|
|
Current = nullptr;
|
|
|
|
readPos = 0;
|
|
|
|
while(((refcount=device->MixCount.load(std::memory_order_acquire))&1))
|
2018-11-26 23:06:49 -08:00
|
|
|
std::this_thread::yield();
|
2018-11-22 12:02:02 -08:00
|
|
|
*clocktime = GetDeviceClockTime(device);
|
2014-10-31 22:43:13 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
voice = GetSourceVoice(Source, context);
|
|
|
|
if(voice)
|
|
|
|
{
|
2019-03-10 16:29:06 -07:00
|
|
|
Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
|
2016-03-25 14:40:44 -07:00
|
|
|
|
2019-03-10 16:29:06 -07:00
|
|
|
readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << 32;
|
|
|
|
readPos |= int64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} <<
|
2018-11-22 12:02:02 -08:00
|
|
|
(32-FRACTIONBITS);
|
|
|
|
}
|
|
|
|
std::atomic_thread_fence(std::memory_order_acquire);
|
|
|
|
} while(refcount != device->MixCount.load(std::memory_order_relaxed));
|
2016-04-25 00:30:47 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(voice)
|
|
|
|
{
|
|
|
|
const ALbufferlistitem *BufferList{Source->queue};
|
|
|
|
while(BufferList && BufferList != Current)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
readPos += int64_t{BufferList->mMaxSamples} << 32;
|
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-01-07 04:06:40 -08:00
|
|
|
readPos = minu64(readPos, 0x7fffffffffffffff_u64);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2017-04-21 15:48:39 -07:00
|
|
|
|
2019-02-11 12:16:58 -08:00
|
|
|
return static_cast<int64_t>(readPos);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2017-05-05 02:41:34 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* GetSourceSecOffset
|
|
|
|
*
|
|
|
|
* Gets the current read offset for the given Source, in seconds. The offset is
|
|
|
|
* relative to the start of the queue (not the start of the current buffer).
|
|
|
|
*/
|
2018-11-22 14:32:48 -08:00
|
|
|
ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2018-11-22 12:02:02 -08:00
|
|
|
const ALbufferlistitem *Current;
|
2019-02-11 12:16:58 -08:00
|
|
|
uint64_t readPos;
|
2018-11-22 12:02:02 -08:00
|
|
|
ALuint refcount;
|
|
|
|
ALvoice *voice;
|
2017-12-03 14:45:19 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
do {
|
|
|
|
Current = nullptr;
|
|
|
|
readPos = 0;
|
|
|
|
while(((refcount=device->MixCount.load(std::memory_order_acquire))&1))
|
2018-11-26 23:06:49 -08:00
|
|
|
std::this_thread::yield();
|
2018-11-22 12:02:02 -08:00
|
|
|
*clocktime = GetDeviceClockTime(device);
|
2012-12-05 09:55:05 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
voice = GetSourceVoice(Source, context);
|
|
|
|
if(voice)
|
|
|
|
{
|
2019-03-10 16:29:06 -07:00
|
|
|
Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-03-10 16:29:06 -07:00
|
|
|
readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << FRACTIONBITS;
|
|
|
|
readPos |= voice->mPositionFrac.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
std::atomic_thread_fence(std::memory_order_acquire);
|
|
|
|
} while(refcount != device->MixCount.load(std::memory_order_relaxed));
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
ALdouble offset{0.0};
|
|
|
|
if(voice)
|
2016-11-22 02:28:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
const ALbufferlistitem *BufferList{Source->queue};
|
|
|
|
const ALbuffer *BufferFmt{nullptr};
|
|
|
|
while(BufferList && BufferList != Current)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i)
|
|
|
|
BufferFmt = (*BufferList)[i];
|
|
|
|
readPos += int64_t{BufferList->mMaxSamples} << FRACTIONBITS;
|
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2016-11-22 02:28:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
while(BufferList && !BufferFmt)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i)
|
|
|
|
BufferFmt = (*BufferList)[i];
|
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
assert(BufferFmt != nullptr);
|
2017-02-24 01:47:34 -08:00
|
|
|
|
2019-01-08 19:42:44 +01:00
|
|
|
offset = static_cast<ALdouble>(readPos) / static_cast<ALdouble>FRACTIONONE /
|
|
|
|
static_cast<ALdouble>(BufferFmt->Frequency);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2017-03-06 13:16:14 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
return offset;
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* GetSourceOffset
|
|
|
|
*
|
|
|
|
* Gets the current read offset for the given Source, in the appropriate format
|
|
|
|
* (Bytes, Samples or Seconds). The offset is relative to the start of the
|
|
|
|
* queue (not the start of the current buffer).
|
|
|
|
*/
|
|
|
|
ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
|
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2018-11-22 12:02:02 -08:00
|
|
|
const ALbufferlistitem *Current;
|
|
|
|
ALuint readPos;
|
|
|
|
ALsizei readPosFrac;
|
|
|
|
ALuint refcount;
|
|
|
|
ALvoice *voice;
|
|
|
|
|
|
|
|
do {
|
|
|
|
Current = nullptr;
|
|
|
|
readPos = readPosFrac = 0;
|
|
|
|
while(((refcount=device->MixCount.load(std::memory_order_acquire))&1))
|
2018-11-26 23:06:49 -08:00
|
|
|
std::this_thread::yield();
|
2018-11-22 12:02:02 -08:00
|
|
|
voice = GetSourceVoice(Source, context);
|
|
|
|
if(voice)
|
|
|
|
{
|
2019-03-10 16:29:06 -07:00
|
|
|
Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-03-10 16:29:06 -07:00
|
|
|
readPos = voice->mPosition.load(std::memory_order_relaxed);
|
|
|
|
readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
std::atomic_thread_fence(std::memory_order_acquire);
|
|
|
|
} while(refcount != device->MixCount.load(std::memory_order_relaxed));
|
|
|
|
|
|
|
|
ALdouble offset{0.0};
|
|
|
|
if(voice)
|
|
|
|
{
|
|
|
|
const ALbufferlistitem *BufferList{Source->queue};
|
|
|
|
const ALbuffer *BufferFmt{nullptr};
|
|
|
|
ALboolean readFin{AL_FALSE};
|
|
|
|
ALuint totalBufferLen{0u};
|
|
|
|
|
|
|
|
while(BufferList)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i)
|
|
|
|
BufferFmt = (*BufferList)[i];
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
readFin |= (BufferList == Current);
|
2019-07-31 09:20:53 -07:00
|
|
|
totalBufferLen += BufferList->mMaxSamples;
|
|
|
|
if(!readFin) readPos += BufferList->mMaxSamples;
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
assert(BufferFmt != nullptr);
|
|
|
|
|
|
|
|
if(Source->Looping)
|
|
|
|
readPos %= totalBufferLen;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Wrap back to 0 */
|
|
|
|
if(readPos >= totalBufferLen)
|
|
|
|
readPos = readPosFrac = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset = 0.0;
|
|
|
|
switch(name)
|
|
|
|
{
|
|
|
|
case AL_SEC_OFFSET:
|
2019-01-08 19:42:44 +01:00
|
|
|
offset = (readPos + static_cast<ALdouble>(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency;
|
2018-11-22 12:02:02 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_SAMPLE_OFFSET:
|
2019-01-08 19:42:44 +01:00
|
|
|
offset = readPos + static_cast<ALdouble>(readPosFrac)/FRACTIONONE;
|
2018-11-22 12:02:02 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
if(BufferFmt->OriginalType == UserFmtIMA4)
|
|
|
|
{
|
|
|
|
ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
|
2018-12-24 19:29:01 -08:00
|
|
|
ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels);
|
2018-11-22 12:02:02 -08:00
|
|
|
ALuint FrameBlockSize = BufferFmt->OriginalAlign;
|
|
|
|
|
|
|
|
/* Round down to nearest ADPCM block */
|
2019-01-08 19:42:44 +01:00
|
|
|
offset = static_cast<ALdouble>(readPos / FrameBlockSize * BlockSize);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
else if(BufferFmt->OriginalType == UserFmtMSADPCM)
|
|
|
|
{
|
|
|
|
ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
|
2018-12-24 19:29:01 -08:00
|
|
|
ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels);
|
2018-11-22 12:02:02 -08:00
|
|
|
ALuint FrameBlockSize = BufferFmt->OriginalAlign;
|
|
|
|
|
|
|
|
/* Round down to nearest ADPCM block */
|
2019-01-08 19:42:44 +01:00
|
|
|
offset = static_cast<ALdouble>(readPos / FrameBlockSize * BlockSize);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-24 19:29:01 -08:00
|
|
|
const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels,
|
|
|
|
BufferFmt->mFmtType)};
|
2019-01-08 19:42:44 +01:00
|
|
|
offset = static_cast<ALdouble>(readPos * FrameSize);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* GetSampleOffset
|
|
|
|
*
|
|
|
|
* Retrieves the sample offset into the Source's queue (from the Sample, Byte
|
|
|
|
* or Second offset supplied by the application). This takes into account the
|
|
|
|
* fact that the buffer format may have been modifed since.
|
|
|
|
*/
|
|
|
|
ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
|
|
|
|
{
|
|
|
|
const ALbuffer *BufferFmt{nullptr};
|
|
|
|
const ALbufferlistitem *BufferList;
|
|
|
|
|
|
|
|
/* Find the first valid Buffer in the Queue */
|
|
|
|
BufferList = Source->queue;
|
|
|
|
while(BufferList)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++)
|
|
|
|
BufferFmt = (*BufferList)[i];
|
2018-11-22 12:02:02 -08:00
|
|
|
if(BufferFmt) break;
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
if(!BufferFmt)
|
|
|
|
{
|
|
|
|
Source->OffsetType = AL_NONE;
|
|
|
|
Source->Offset = 0.0;
|
|
|
|
return AL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ALdouble dbloff, dblfrac;
|
|
|
|
switch(Source->OffsetType)
|
|
|
|
{
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
/* Determine the ByteOffset (and ensure it is block aligned) */
|
2019-01-08 19:42:44 +01:00
|
|
|
*offset = static_cast<ALuint>(Source->Offset);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(BufferFmt->OriginalType == UserFmtIMA4)
|
|
|
|
{
|
|
|
|
ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
|
2018-12-24 19:29:01 -08:00
|
|
|
*offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels);
|
2018-11-22 12:02:02 -08:00
|
|
|
*offset *= BufferFmt->OriginalAlign;
|
|
|
|
}
|
|
|
|
else if(BufferFmt->OriginalType == UserFmtMSADPCM)
|
|
|
|
{
|
|
|
|
ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
|
2018-12-24 19:29:01 -08:00
|
|
|
*offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels);
|
2018-11-22 12:02:02 -08:00
|
|
|
*offset *= BufferFmt->OriginalAlign;
|
|
|
|
}
|
|
|
|
else
|
2018-12-24 19:29:01 -08:00
|
|
|
*offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType);
|
2018-11-22 12:02:02 -08:00
|
|
|
*frac = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
dblfrac = modf(Source->Offset, &dbloff);
|
2019-01-08 19:42:44 +01:00
|
|
|
*offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<unsigned int>::max()));
|
|
|
|
*frac = static_cast<ALsizei>(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0));
|
2018-11-22 12:02:02 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
|
2019-01-08 19:42:44 +01:00
|
|
|
*offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<unsigned int>::max()));
|
|
|
|
*frac = static_cast<ALsizei>(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0));
|
2018-11-22 12:02:02 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Source->OffsetType = AL_NONE;
|
|
|
|
Source->Offset = 0.0;
|
|
|
|
|
|
|
|
return AL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ApplyOffset
|
|
|
|
*
|
|
|
|
* Apply the stored playback offset to the Source. This function will update
|
|
|
|
* the number of buffers "played" given the stored offset.
|
|
|
|
*/
|
|
|
|
ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
|
|
|
|
{
|
|
|
|
/* Get sample frame offset */
|
|
|
|
ALuint offset{0u};
|
|
|
|
ALsizei frac{0};
|
|
|
|
if(!GetSampleOffset(Source, &offset, &frac))
|
|
|
|
return AL_FALSE;
|
|
|
|
|
|
|
|
ALuint totalBufferLen{0u};
|
|
|
|
ALbufferlistitem *BufferList{Source->queue};
|
|
|
|
while(BufferList && totalBufferLen <= offset)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
if(static_cast<ALuint>(BufferList->mMaxSamples) > offset-totalBufferLen)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
/* Offset is in this buffer */
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed);
|
|
|
|
voice->mPositionFrac.store(frac, std::memory_order_relaxed);
|
|
|
|
voice->mCurrentBuffer.store(BufferList, std::memory_order_release);
|
2018-11-22 12:02:02 -08:00
|
|
|
return AL_TRUE;
|
|
|
|
}
|
2019-07-31 09:20:53 -07:00
|
|
|
totalBufferLen += BufferList->mMaxSamples;
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Offset is out of range of the queue */
|
|
|
|
return AL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ALsource *AllocSource(ALCcontext *context)
|
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
|
|
|
if(context->mNumSources >= device->SourcesMax)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax);
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2019-07-30 09:05:54 -07:00
|
|
|
auto sublist = std::find_if(context->mSourceList.begin(), context->mSourceList.end(),
|
2018-12-26 21:55:39 -08:00
|
|
|
[](const SourceSubList &entry) noexcept -> bool
|
2018-11-22 12:02:02 -08:00
|
|
|
{ return entry.FreeMask != 0; }
|
|
|
|
);
|
2019-07-30 09:05:54 -07:00
|
|
|
auto lidx = static_cast<ALsizei>(std::distance(context->mSourceList.begin(), sublist));
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *source;
|
|
|
|
ALsizei slidx;
|
2019-07-30 09:05:54 -07:00
|
|
|
if(LIKELY(sublist != context->mSourceList.end()))
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
slidx = CTZ64(sublist->FreeMask);
|
|
|
|
source = sublist->Sources + slidx;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Don't allocate so many list entries that the 32-bit ID could
|
|
|
|
* overflow...
|
|
|
|
*/
|
2019-07-30 09:05:54 -07:00
|
|
|
if(UNLIKELY(context->mSourceList.size() >= 1<<25))
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_OUT_OF_MEMORY, "Too many sources allocated");
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2019-07-30 09:05:54 -07:00
|
|
|
context->mSourceList.emplace_back();
|
|
|
|
sublist = context->mSourceList.end() - 1;
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-01-07 04:06:40 -08:00
|
|
|
sublist->FreeMask = ~0_u64;
|
2018-11-22 12:02:02 -08:00
|
|
|
sublist->Sources = static_cast<ALsource*>(al_calloc(16, sizeof(ALsource)*64));
|
|
|
|
if(UNLIKELY(!sublist->Sources))
|
|
|
|
{
|
2019-07-30 09:05:54 -07:00
|
|
|
context->mSourceList.pop_back();
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_OUT_OF_MEMORY, "Failed to allocate source batch");
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
slidx = 0;
|
|
|
|
source = sublist->Sources + slidx;
|
|
|
|
}
|
|
|
|
|
|
|
|
source = new (source) ALsource{device->NumAuxSends};
|
|
|
|
|
|
|
|
/* Add 1 to avoid source ID 0. */
|
|
|
|
source->id = ((lidx<<6) | slidx) + 1;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
context->mNumSources += 1;
|
2019-01-07 04:06:40 -08:00
|
|
|
sublist->FreeMask &= ~(1_u64 << slidx);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeSource(ALCcontext *context, ALsource *source)
|
|
|
|
{
|
|
|
|
ALuint id = source->id - 1;
|
|
|
|
ALsizei lidx = id >> 6;
|
|
|
|
ALsizei slidx = id & 0x3f;
|
|
|
|
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2019-01-01 16:38:54 -08:00
|
|
|
BackendUniqueLock backlock{*device->Backend};
|
|
|
|
if(ALvoice *voice{GetSourceVoice(source, context)})
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
|
|
|
|
voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
|
|
|
|
voice->mSourceID.store(0u, std::memory_order_relaxed);
|
2019-03-09 16:48:07 -08:00
|
|
|
std::atomic_thread_fence(std::memory_order_release);
|
|
|
|
/* Don't set the voice to stopping if it was already stopped or
|
|
|
|
* stopping.
|
|
|
|
*/
|
|
|
|
ALvoice::State oldvstate{ALvoice::Playing};
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
|
2019-03-09 16:48:07 -08:00
|
|
|
std::memory_order_acq_rel, std::memory_order_acquire);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-01-01 16:38:54 -08:00
|
|
|
backlock.unlock();
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-06-05 17:25:08 -07:00
|
|
|
al::destroy_at(source);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
context->mSourceList[lidx].FreeMask |= 1_u64 << slidx;
|
|
|
|
context->mNumSources--;
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept
|
|
|
|
{
|
|
|
|
ALuint lidx = (id-1) >> 6;
|
|
|
|
ALsizei slidx = (id-1) & 0x3f;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
if(UNLIKELY(lidx >= context->mSourceList.size()))
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
2019-07-30 09:05:54 -07:00
|
|
|
SourceSubList &sublist{context->mSourceList[lidx]};
|
2019-01-07 04:06:40 -08:00
|
|
|
if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
|
|
|
return sublist.Sources + slidx;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept
|
|
|
|
{
|
|
|
|
ALuint lidx = (id-1) >> 6;
|
|
|
|
ALsizei slidx = (id-1) & 0x3f;
|
|
|
|
|
|
|
|
if(UNLIKELY(lidx >= device->BufferList.size()))
|
|
|
|
return nullptr;
|
|
|
|
BufferSubList &sublist = device->BufferList[lidx];
|
2019-01-07 04:06:40 -08:00
|
|
|
if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
|
|
|
return sublist.Buffers + slidx;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept
|
|
|
|
{
|
|
|
|
ALuint lidx = (id-1) >> 6;
|
|
|
|
ALsizei slidx = (id-1) & 0x3f;
|
|
|
|
|
|
|
|
if(UNLIKELY(lidx >= device->FilterList.size()))
|
|
|
|
return nullptr;
|
|
|
|
FilterSubList &sublist = device->FilterList[lidx];
|
2019-01-07 04:06:40 -08:00
|
|
|
if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
|
|
|
return sublist.Filters + slidx;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept
|
|
|
|
{
|
2019-02-20 22:00:26 -08:00
|
|
|
ALuint lidx = (id-1) >> 6;
|
|
|
|
ALsizei slidx = (id-1) & 0x3f;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
if(UNLIKELY(lidx >= context->mEffectSlotList.size()))
|
2019-02-20 22:00:26 -08:00
|
|
|
return nullptr;
|
2019-07-30 09:05:54 -07:00
|
|
|
EffectSlotSubList &sublist{context->mEffectSlotList[lidx]};
|
2019-02-20 22:00:26 -08:00
|
|
|
if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
|
2018-11-22 12:02:02 -08:00
|
|
|
return nullptr;
|
2019-02-20 22:00:26 -08:00
|
|
|
return sublist.EffectSlots + slidx;
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-24 11:41:50 -08:00
|
|
|
enum SourceProp : ALenum {
|
2018-11-22 12:02:02 -08:00
|
|
|
srcPitch = AL_PITCH,
|
|
|
|
srcGain = AL_GAIN,
|
|
|
|
srcMinGain = AL_MIN_GAIN,
|
|
|
|
srcMaxGain = AL_MAX_GAIN,
|
|
|
|
srcMaxDistance = AL_MAX_DISTANCE,
|
|
|
|
srcRolloffFactor = AL_ROLLOFF_FACTOR,
|
|
|
|
srcDopplerFactor = AL_DOPPLER_FACTOR,
|
|
|
|
srcConeOuterGain = AL_CONE_OUTER_GAIN,
|
|
|
|
srcSecOffset = AL_SEC_OFFSET,
|
|
|
|
srcSampleOffset = AL_SAMPLE_OFFSET,
|
|
|
|
srcByteOffset = AL_BYTE_OFFSET,
|
|
|
|
srcConeInnerAngle = AL_CONE_INNER_ANGLE,
|
|
|
|
srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
|
|
|
|
srcRefDistance = AL_REFERENCE_DISTANCE,
|
|
|
|
|
|
|
|
srcPosition = AL_POSITION,
|
|
|
|
srcVelocity = AL_VELOCITY,
|
|
|
|
srcDirection = AL_DIRECTION,
|
|
|
|
|
|
|
|
srcSourceRelative = AL_SOURCE_RELATIVE,
|
|
|
|
srcLooping = AL_LOOPING,
|
|
|
|
srcBuffer = AL_BUFFER,
|
|
|
|
srcSourceState = AL_SOURCE_STATE,
|
|
|
|
srcBuffersQueued = AL_BUFFERS_QUEUED,
|
|
|
|
srcBuffersProcessed = AL_BUFFERS_PROCESSED,
|
|
|
|
srcSourceType = AL_SOURCE_TYPE,
|
|
|
|
|
|
|
|
/* ALC_EXT_EFX */
|
|
|
|
srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
|
|
|
|
srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
|
|
|
|
srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
|
|
|
|
srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
|
|
|
|
srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
|
|
|
|
srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
|
|
|
|
srcDirectFilter = AL_DIRECT_FILTER,
|
|
|
|
srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
|
|
|
|
|
|
|
|
/* AL_SOFT_direct_channels */
|
|
|
|
srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
|
|
|
|
|
|
|
|
/* AL_EXT_source_distance_model */
|
|
|
|
srcDistanceModel = AL_DISTANCE_MODEL,
|
|
|
|
|
|
|
|
/* AL_SOFT_source_latency */
|
|
|
|
srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
|
|
|
|
srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
|
|
|
|
|
|
|
|
/* AL_EXT_STEREO_ANGLES */
|
|
|
|
srcAngles = AL_STEREO_ANGLES,
|
|
|
|
|
|
|
|
/* AL_EXT_SOURCE_RADIUS */
|
|
|
|
srcRadius = AL_SOURCE_RADIUS,
|
|
|
|
|
|
|
|
/* AL_EXT_BFORMAT */
|
|
|
|
srcOrientation = AL_ORIENTATION,
|
|
|
|
|
|
|
|
/* AL_SOFT_source_resampler */
|
|
|
|
srcResampler = AL_SOURCE_RESAMPLER_SOFT,
|
|
|
|
|
|
|
|
/* AL_SOFT_source_spatialize */
|
|
|
|
srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT,
|
|
|
|
|
|
|
|
/* ALC_SOFT_device_clock */
|
|
|
|
srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT,
|
|
|
|
srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns if the last known state for the source was playing or paused. Does
|
|
|
|
* not sync with the mixer voice.
|
|
|
|
*/
|
|
|
|
inline bool IsPlayingOrPaused(ALsource *source)
|
|
|
|
{ return source->state == AL_PLAYING || source->state == AL_PAUSED; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an updated source state using the matching voice's status (or lack
|
|
|
|
* thereof).
|
|
|
|
*/
|
|
|
|
inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
|
|
|
|
{
|
|
|
|
if(!voice && source->state == AL_PLAYING)
|
|
|
|
source->state = AL_STOPPED;
|
|
|
|
return source->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns if the source should specify an update, given the context's
|
|
|
|
* deferring state and the source's last known state.
|
|
|
|
*/
|
|
|
|
inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
|
|
|
|
{
|
2019-07-30 09:05:54 -07:00
|
|
|
return !context->mDeferUpdates.load(std::memory_order_acquire) &&
|
2018-11-22 12:02:02 -08:00
|
|
|
IsPlayingOrPaused(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Can only be called while the mixer is locked! */
|
|
|
|
void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state)
|
2018-02-24 09:24:18 -08:00
|
|
|
{
|
2019-07-30 09:05:54 -07:00
|
|
|
ALbitfieldSOFT enabledevt{context->mEnabledEvts.load(std::memory_order_acquire)};
|
2018-02-24 09:24:18 -08:00
|
|
|
if(!(enabledevt&EventType_SourceStateChange)) return;
|
|
|
|
|
|
|
|
/* The mixer may have queued a state change that's not yet been processed,
|
|
|
|
* and we don't want state change messages to occur out of order, so send
|
|
|
|
* it through the async queue to ensure proper ordering.
|
|
|
|
*/
|
2019-07-30 09:05:54 -07:00
|
|
|
RingBuffer *ring{context->mAsyncEvents.get()};
|
2018-12-26 21:22:17 -08:00
|
|
|
auto evt_vec = ring->getWriteVector();
|
|
|
|
if(evt_vec.first.len < 1) return;
|
2018-12-25 09:32:38 -08:00
|
|
|
|
2018-12-26 21:22:17 -08:00
|
|
|
AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}};
|
2018-12-25 09:32:38 -08:00
|
|
|
evt->u.srcstate.id = id;
|
|
|
|
evt->u.srcstate.state = state;
|
2018-12-26 21:22:17 -08:00
|
|
|
ring->writeAdvance(1);
|
2019-07-30 09:05:54 -07:00
|
|
|
context->mEventSem.post();
|
2018-02-24 09:24:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-03 19:36:19 -07:00
|
|
|
ALuint FloatValsByProp(ALenum prop)
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
2018-11-24 11:41:50 -08:00
|
|
|
switch(static_cast<SourceProp>(prop))
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_PITCH:
|
|
|
|
case AL_GAIN:
|
|
|
|
case AL_MIN_GAIN:
|
|
|
|
case AL_MAX_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
|
|
|
case AL_DISTANCE_MODEL:
|
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
case AL_LOOPING:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
case AL_SOURCE_TYPE:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2017-04-21 15:48:39 -07:00
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
2017-05-05 02:41:34 -07:00
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2012-12-05 20:51:25 -08:00
|
|
|
return 1;
|
|
|
|
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
2012-12-05 20:51:25 -08:00
|
|
|
return 2;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2012-12-05 20:51:25 -08:00
|
|
|
return 3;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_ORIENTATION:
|
2014-10-31 22:43:13 -07:00
|
|
|
return 6;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
2012-12-05 20:51:25 -08:00
|
|
|
break; /* Double only */
|
2015-09-22 08:48:26 -07:00
|
|
|
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
|
|
|
break; /* i/i64 only */
|
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
2015-09-22 08:48:26 -07:00
|
|
|
break; /* i64 only */
|
2012-12-05 20:51:25 -08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2019-08-03 19:36:19 -07:00
|
|
|
ALuint DoubleValsByProp(ALenum prop)
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
2018-11-24 11:41:50 -08:00
|
|
|
switch(static_cast<SourceProp>(prop))
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_PITCH:
|
|
|
|
case AL_GAIN:
|
|
|
|
case AL_MIN_GAIN:
|
|
|
|
case AL_MAX_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
|
|
|
case AL_DISTANCE_MODEL:
|
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
case AL_LOOPING:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
case AL_SOURCE_TYPE:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2017-04-21 15:48:39 -07:00
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
2017-05-05 02:41:34 -07:00
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2012-12-05 20:51:25 -08:00
|
|
|
return 1;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
2012-12-05 20:51:25 -08:00
|
|
|
return 2;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2012-12-05 20:51:25 -08:00
|
|
|
return 3;
|
2014-10-31 22:43:13 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_ORIENTATION:
|
2014-10-31 22:43:13 -07:00
|
|
|
return 6;
|
2015-09-22 08:48:26 -07:00
|
|
|
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
|
|
|
break; /* i/i64 only */
|
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
2015-09-22 08:48:26 -07:00
|
|
|
break; /* i64 only */
|
2012-12-05 20:51:25 -08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2012-12-05 19:58:01 -08:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<const ALfloat> values);
|
|
|
|
bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<const ALint> values);
|
|
|
|
bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<const ALint64SOFT> values);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
#define CHECKSIZE(v, s) do { \
|
|
|
|
if(UNLIKELY((v).size() != INT_MAX && (v).size() != (s))) \
|
|
|
|
{ \
|
|
|
|
Context->setError(AL_INVALID_ENUM, \
|
|
|
|
"Property 0x%04x expects %d value(s), got %zu", prop, (s), \
|
|
|
|
(v).size()); \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
} while(0)
|
2012-08-28 22:16:55 -07:00
|
|
|
#define CHECKVAL(x) do { \
|
2019-08-03 18:57:38 -07:00
|
|
|
if(UNLIKELY(!(x))) \
|
2018-01-24 17:07:01 -08:00
|
|
|
{ \
|
2019-07-30 21:32:05 -07:00
|
|
|
Context->setError(AL_INVALID_VALUE, "Value out of range"); \
|
2019-08-03 18:57:38 -07:00
|
|
|
return false; \
|
2018-01-24 17:07:01 -08:00
|
|
|
} \
|
2012-08-28 22:16:55 -07:00
|
|
|
} while(0)
|
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
bool UpdateSourceProps(ALsource *source, ALCcontext *context)
|
2019-05-23 05:06:26 -07:00
|
|
|
{
|
|
|
|
ALvoice *voice;
|
|
|
|
if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr)
|
|
|
|
UpdateSourceProps(source, voice, context);
|
|
|
|
else
|
|
|
|
source->PropsClean.clear(std::memory_order_release);
|
2019-08-03 18:57:38 -07:00
|
|
|
return true;
|
2019-05-23 05:06:26 -07:00
|
|
|
}
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<const ALfloat> values)
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2012-12-05 09:22:38 -08:00
|
|
|
ALint ival;
|
|
|
|
|
|
|
|
switch(prop)
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
2015-09-22 08:48:26 -07:00
|
|
|
/* Query only */
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_OPERATION, false,
|
|
|
|
"Setting read-only source property 0x%04x", prop);
|
2015-09-22 08:48:26 -07:00
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_PITCH:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->Pitch = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->InnerAngle = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->OuterAngle = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_GAIN:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->Gain = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_MAX_DISTANCE:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->MaxDistance = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->RolloffFactor = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->RefDistance = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_MIN_GAIN:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->MinGain = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_MAX_GAIN:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->MaxGain = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->OuterGain = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->OuterGainHF = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->AirAbsorptionFactor = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->RoomRolloffFactor = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DOPPLER_FACTOR:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->DopplerFactor = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2012-12-05 09:22:38 -08:00
|
|
|
Source->OffsetType = prop;
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->Offset = values[0];
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2017-03-19 13:48:40 -07:00
|
|
|
if(IsPlayingOrPaused(Source))
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{Context->mDevice.get()};
|
2019-01-01 16:38:54 -08:00
|
|
|
BackendLockGuard _{*device->Backend};
|
2017-02-24 01:47:34 -08:00
|
|
|
/* Double-check that the source is still playing while we have
|
|
|
|
* the lock.
|
|
|
|
*/
|
2019-01-01 16:38:54 -08:00
|
|
|
if(ALvoice *voice{GetSourceVoice(Source, Context)})
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2017-02-27 15:35:15 -08:00
|
|
|
if(ApplyOffset(Source, voice) == AL_FALSE)
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid offset");
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
}
|
2019-08-03 18:57:38 -07:00
|
|
|
return true;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0.0f && std::isfinite(values[0]));
|
2016-04-25 00:30:47 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->Radius = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 2);
|
2018-11-18 03:25:32 -08:00
|
|
|
CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]));
|
2016-03-25 14:40:44 -07:00
|
|
|
|
|
|
|
Source->StereoPan[0] = values[0];
|
|
|
|
Source->StereoPan[1] = values[1];
|
2019-08-03 18:57:38 -07:00
|
|
|
return UpdateSourceProps(Source, Context);
|
2016-03-25 14:40:44 -07:00
|
|
|
|
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_POSITION:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2018-11-18 03:25:32 -08:00
|
|
|
CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
|
2012-08-28 22:16:55 -07:00
|
|
|
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
Source->Position[0] = values[0];
|
|
|
|
Source->Position[1] = values[1];
|
|
|
|
Source->Position[2] = values[2];
|
2019-08-03 18:57:38 -07:00
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_VELOCITY:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2018-11-18 03:25:32 -08:00
|
|
|
CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
|
2012-08-28 22:16:55 -07:00
|
|
|
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
Source->Velocity[0] = values[0];
|
|
|
|
Source->Velocity[1] = values[1];
|
|
|
|
Source->Velocity[2] = values[2];
|
2019-08-03 18:57:38 -07:00
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DIRECTION:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2018-11-18 03:25:32 -08:00
|
|
|
CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
|
2012-08-28 22:16:55 -07:00
|
|
|
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
Source->Direction[0] = values[0];
|
|
|
|
Source->Direction[1] = values[1];
|
|
|
|
Source->Direction[2] = values[2];
|
2019-08-03 18:57:38 -07:00
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2014-10-31 22:43:13 -07:00
|
|
|
case AL_ORIENTATION:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 6);
|
2018-11-18 03:25:32 -08:00
|
|
|
CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) &&
|
|
|
|
std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]));
|
2014-10-31 22:43:13 -07:00
|
|
|
|
2018-12-26 22:27:34 -08:00
|
|
|
Source->OrientAt[0] = values[0];
|
|
|
|
Source->OrientAt[1] = values[1];
|
|
|
|
Source->OrientAt[2] = values[2];
|
|
|
|
Source->OrientUp[0] = values[3];
|
|
|
|
Source->OrientUp[1] = values[4];
|
|
|
|
Source->OrientUp[2] = values[5];
|
2019-08-03 18:57:38 -07:00
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-12-05 09:22:38 -08:00
|
|
|
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
case AL_LOOPING:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
case AL_DISTANCE_MODEL:
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
2017-04-21 15:48:39 -07:00
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
2017-05-05 02:41:34 -07:00
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
2019-01-08 19:42:44 +01:00
|
|
|
ival = static_cast<ALint>(values[0]);
|
2019-08-03 18:57:38 -07:00
|
|
|
return SetSourceiv(Source, Context, prop, {&ival, 1u});
|
2012-12-05 09:22:38 -08:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
2019-01-08 19:42:44 +01:00
|
|
|
ival = static_cast<ALint>(static_cast<ALuint>(values[0]));
|
2019-08-03 18:57:38 -07:00
|
|
|
return SetSourceiv(Source, Context, prop, {&ival, 1u});
|
2015-09-22 08:48:26 -07:00
|
|
|
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
2015-09-22 08:48:26 -07:00
|
|
|
break;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:22:38 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2019-07-30 21:32:05 -07:00
|
|
|
Context->setError(AL_INVALID_ENUM, "Invalid source float property 0x%04x", prop);
|
2019-08-03 18:57:38 -07:00
|
|
|
return false;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<const ALint> values)
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{Context->mDevice.get()};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbuffer *buffer{nullptr};
|
|
|
|
ALfilter *filter{nullptr};
|
|
|
|
ALeffectslot *slot{nullptr};
|
|
|
|
ALbufferlistitem *oldlist{nullptr};
|
2018-11-26 21:50:48 -08:00
|
|
|
std::unique_lock<std::mutex> slotlock;
|
2018-11-26 22:06:53 -08:00
|
|
|
std::unique_lock<std::mutex> filtlock;
|
|
|
|
std::unique_lock<std::mutex> buflock;
|
2014-10-31 22:43:13 -07:00
|
|
|
ALfloat fvals[6];
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
switch(prop)
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
/* Query only */
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_OPERATION, false,
|
|
|
|
"Setting read-only source property 0x%04x", prop);
|
2015-09-22 08:48:26 -07:00
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_SOURCE_RELATIVE:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->HeadRelative = static_cast<ALboolean>(values[0]);
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_LOOPING:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->Looping = static_cast<ALboolean>(values[0]);
|
2017-04-18 00:58:33 -07:00
|
|
|
if(IsPlayingOrPaused(Source))
|
2017-04-02 06:35:44 -07:00
|
|
|
{
|
2019-08-03 18:57:38 -07:00
|
|
|
if(ALvoice *voice{GetSourceVoice(Source, Context)})
|
2017-04-18 00:58:33 -07:00
|
|
|
{
|
|
|
|
if(Source->Looping)
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mLoopBuffer.store(Source->queue, std::memory_order_release);
|
2017-04-18 00:58:33 -07:00
|
|
|
else
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mLoopBuffer.store(nullptr, std::memory_order_release);
|
2017-04-18 00:58:33 -07:00
|
|
|
|
|
|
|
/* If the source is playing, wait for the current mix to finish
|
|
|
|
* to ensure it isn't currently looping back or reaching the
|
|
|
|
* end.
|
|
|
|
*/
|
2018-11-22 12:02:02 -08:00
|
|
|
while((device->MixCount.load(std::memory_order_acquire)&1))
|
2018-11-26 23:06:49 -08:00
|
|
|
std::this_thread::yield();
|
2017-04-18 00:58:33 -07:00
|
|
|
}
|
2017-04-02 06:35:44 -07:00
|
|
|
}
|
2019-08-03 18:57:38 -07:00
|
|
|
return true;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_BUFFER:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
2018-11-26 22:06:53 -08:00
|
|
|
buflock = std::unique_lock<std::mutex>{device->BufferLock};
|
2019-08-03 18:57:38 -07:00
|
|
|
if(!(values[0] == 0 || (buffer=LookupBuffer(device, values[0])) != nullptr))
|
|
|
|
SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid buffer ID %u", values[0]);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2018-01-23 10:38:27 -08:00
|
|
|
if(buffer && buffer->MappedAccess != 0 &&
|
|
|
|
!(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_OPERATION, false,
|
|
|
|
"Setting non-persistently mapped buffer %u", buffer->id);
|
2018-01-20 11:49:01 -08:00
|
|
|
else
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2017-03-06 13:16:14 -08:00
|
|
|
ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
|
|
|
|
if(state == AL_PLAYING || state == AL_PAUSED)
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_OPERATION, false,
|
|
|
|
"Setting buffer on playing or paused source %u", Source->id);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
2017-04-18 00:58:33 -07:00
|
|
|
oldlist = Source->queue;
|
2018-11-22 12:02:02 -08:00
|
|
|
if(buffer != nullptr)
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
|
|
|
/* Add the selected buffer to a one-item queue */
|
2019-06-06 00:37:00 -07:00
|
|
|
auto newlist = static_cast<ALbufferlistitem*>(al_calloc(alignof(void*),
|
2019-02-11 11:14:34 -08:00
|
|
|
ALbufferlistitem::Sizeof(1u)));
|
2019-07-31 09:20:53 -07:00
|
|
|
newlist->mNext.store(nullptr, std::memory_order_relaxed);
|
|
|
|
newlist->mMaxSamples = buffer->SampleLen;
|
|
|
|
newlist->mNumBuffers = 1;
|
|
|
|
newlist->mBuffers[0] = buffer;
|
2019-08-01 13:28:53 -07:00
|
|
|
IncrementRef(buffer->ref);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2014-05-10 03:33:41 -07:00
|
|
|
/* Source is now Static */
|
|
|
|
Source->SourceType = AL_STATIC;
|
2017-04-18 00:58:33 -07:00
|
|
|
Source->queue = newlist;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Source is now Undetermined */
|
|
|
|
Source->SourceType = AL_UNDETERMINED;
|
2018-11-22 12:02:02 -08:00
|
|
|
Source->queue = nullptr;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
buflock.unlock();
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
/* Delete all elements in the previous queue */
|
2018-11-22 12:02:02 -08:00
|
|
|
while(oldlist != nullptr)
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbufferlistitem *temp{oldlist};
|
2019-07-31 09:20:53 -07:00
|
|
|
oldlist = temp->mNext.load(std::memory_order_relaxed);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
std::for_each(temp->begin(), temp->end(),
|
|
|
|
[](ALbuffer *buffer) -> void
|
2019-08-01 13:28:53 -07:00
|
|
|
{ if(buffer) DecrementRef(buffer->ref); });
|
2017-02-27 20:43:16 -08:00
|
|
|
al_free(temp);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2019-08-03 18:57:38 -07:00
|
|
|
return true;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
Source->OffsetType = prop;
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->Offset = values[0];
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2017-03-19 13:48:40 -07:00
|
|
|
if(IsPlayingOrPaused(Source))
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{Context->mDevice.get()};
|
2019-01-01 16:38:54 -08:00
|
|
|
BackendLockGuard _{*device->Backend};
|
|
|
|
if(ALvoice *voice{GetSourceVoice(Source, Context)})
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
2017-02-27 15:35:15 -08:00
|
|
|
if(ApplyOffset(Source, voice) == AL_FALSE)
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid source offset");
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
}
|
2019-08-03 18:57:38 -07:00
|
|
|
return true;
|
2012-12-05 09:55:05 -08:00
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_DIRECT_FILTER:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
2018-11-26 22:06:53 -08:00
|
|
|
filtlock = std::unique_lock<std::mutex>{device->FilterLock};
|
2019-08-03 18:57:38 -07:00
|
|
|
if(!(values[0] == 0 || (filter=LookupFilter(device, values[0])) != nullptr))
|
|
|
|
SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", values[0]);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
if(!filter)
|
|
|
|
{
|
2014-05-11 01:36:18 -07:00
|
|
|
Source->Direct.Gain = 1.0f;
|
|
|
|
Source->Direct.GainHF = 1.0f;
|
2014-05-14 01:24:18 -07:00
|
|
|
Source->Direct.HFReference = LOWPASSFREQREF;
|
2014-05-17 07:54:25 -07:00
|
|
|
Source->Direct.GainLF = 1.0f;
|
|
|
|
Source->Direct.LFReference = HIGHPASSFREQREF;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-05-11 01:36:18 -07:00
|
|
|
Source->Direct.Gain = filter->Gain;
|
|
|
|
Source->Direct.GainHF = filter->GainHF;
|
2014-05-14 01:24:18 -07:00
|
|
|
Source->Direct.HFReference = filter->HFReference;
|
2014-05-17 07:54:25 -07:00
|
|
|
Source->Direct.GainLF = filter->GainLF;
|
|
|
|
Source->Direct.LFReference = filter->LFReference;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2018-11-26 18:25:29 -08:00
|
|
|
filtlock.unlock();
|
2019-08-03 18:57:38 -07:00
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->DryGainHFAuto = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->WetGainAuto = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->WetGainHFAuto = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->DirectChannels = values[0];
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DISTANCE_MODEL:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] == AL_NONE ||
|
|
|
|
values[0] == AL_INVERSE_DISTANCE || values[0] == AL_INVERSE_DISTANCE_CLAMPED ||
|
|
|
|
values[0] == AL_LINEAR_DISTANCE || values[0] == AL_LINEAR_DISTANCE_CLAMPED ||
|
|
|
|
values[0] == AL_EXPONENT_DISTANCE || values[0] == AL_EXPONENT_DISTANCE_CLAMPED);
|
|
|
|
|
|
|
|
Source->mDistanceModel = static_cast<DistanceModel>(values[0]);
|
2019-07-30 09:05:54 -07:00
|
|
|
if(Context->mSourceDistanceModel)
|
2019-08-03 18:57:38 -07:00
|
|
|
return UpdateSourceProps(Source, Context);
|
|
|
|
return true;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2017-04-21 15:48:39 -07:00
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= 0 && values[0] <= ResamplerMax);
|
2017-04-21 15:48:39 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->mResampler = static_cast<Resampler>(values[0]);
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2017-04-21 15:48:39 -07:00
|
|
|
|
2017-05-05 02:41:34 -07:00
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] >= AL_FALSE && values[0] <= AL_AUTO_SOFT);
|
2017-05-05 02:41:34 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
Source->mSpatialize = static_cast<SpatializeMode>(values[0]);
|
|
|
|
return UpdateSourceProps(Source, Context);
|
2017-05-05 02:41:34 -07:00
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2019-07-30 09:05:54 -07:00
|
|
|
slotlock = std::unique_lock<std::mutex>{Context->mEffectSlotLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr))
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid effect ID %u", values[0]);
|
2019-01-08 19:42:44 +01:00
|
|
|
if(static_cast<ALuint>(values[1]) >= static_cast<ALuint>(device->NumAuxSends))
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid send %u", values[1]);
|
2018-11-26 18:25:29 -08:00
|
|
|
|
2018-11-26 22:06:53 -08:00
|
|
|
filtlock = std::unique_lock<std::mutex>{device->FilterLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr))
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", values[2]);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
if(!filter)
|
|
|
|
{
|
|
|
|
/* Disable filter */
|
|
|
|
Source->Send[values[1]].Gain = 1.0f;
|
|
|
|
Source->Send[values[1]].GainHF = 1.0f;
|
2014-05-14 01:24:18 -07:00
|
|
|
Source->Send[values[1]].HFReference = LOWPASSFREQREF;
|
2014-05-17 07:54:25 -07:00
|
|
|
Source->Send[values[1]].GainLF = 1.0f;
|
|
|
|
Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Source->Send[values[1]].Gain = filter->Gain;
|
|
|
|
Source->Send[values[1]].GainHF = filter->GainHF;
|
2014-05-14 01:24:18 -07:00
|
|
|
Source->Send[values[1]].HFReference = filter->HFReference;
|
2014-05-17 07:54:25 -07:00
|
|
|
Source->Send[values[1]].GainLF = filter->GainLF;
|
|
|
|
Source->Send[values[1]].LFReference = filter->LFReference;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2018-11-26 18:25:29 -08:00
|
|
|
filtlock.unlock();
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
|
2017-03-12 19:27:51 -07:00
|
|
|
if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
|
|
|
/* Add refcount on the new slot, and release the previous slot */
|
2019-08-01 13:28:53 -07:00
|
|
|
if(slot) IncrementRef(slot->ref);
|
2016-05-25 06:45:56 -07:00
|
|
|
if(Source->Send[values[1]].Slot)
|
2019-08-01 13:28:53 -07:00
|
|
|
DecrementRef(Source->Send[values[1]].Slot->ref);
|
2016-05-25 06:45:56 -07:00
|
|
|
Source->Send[values[1]].Slot = slot;
|
|
|
|
|
2017-04-17 21:16:01 -07:00
|
|
|
/* We must force an update if the auxiliary slot changed on an
|
|
|
|
* active source, in case the slot is about to be deleted.
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
*/
|
2018-11-22 12:02:02 -08:00
|
|
|
ALvoice *voice{GetSourceVoice(Source, Context)};
|
|
|
|
if(voice) UpdateSourceProps(Source, voice, Context);
|
|
|
|
else Source->PropsClean.clear(std::memory_order_release);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-08-01 13:28:53 -07:00
|
|
|
if(slot) IncrementRef(slot->ref);
|
2016-05-25 06:45:56 -07:00
|
|
|
if(Source->Send[values[1]].Slot)
|
2019-08-01 13:28:53 -07:00
|
|
|
DecrementRef(Source->Send[values[1]].Slot->ref);
|
2016-05-25 06:45:56 -07:00
|
|
|
Source->Send[values[1]].Slot = slot;
|
2019-05-23 05:06:26 -07:00
|
|
|
UpdateSourceProps(Source, Context);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
2019-08-03 18:57:38 -07:00
|
|
|
return true;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 1x float */
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_PITCH:
|
|
|
|
case AL_GAIN:
|
|
|
|
case AL_MIN_GAIN:
|
|
|
|
case AL_MAX_GAIN:
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_REFERENCE_DISTANCE:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
fvals[0] = static_cast<ALfloat>(values[0]);
|
|
|
|
return SetSourcefv(Source, Context, prop, {fvals, 1u});
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 3x float */
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2019-01-08 19:42:44 +01:00
|
|
|
fvals[0] = static_cast<ALfloat>(values[0]);
|
|
|
|
fvals[1] = static_cast<ALfloat>(values[1]);
|
|
|
|
fvals[2] = static_cast<ALfloat>(values[2]);
|
2019-08-03 18:57:38 -07:00
|
|
|
return SetSourcefv(Source, Context, prop, {fvals, 3u});
|
2012-12-06 09:03:48 -08:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 6x float */
|
2014-10-31 22:43:13 -07:00
|
|
|
case AL_ORIENTATION:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 6);
|
2019-01-08 19:42:44 +01:00
|
|
|
fvals[0] = static_cast<ALfloat>(values[0]);
|
|
|
|
fvals[1] = static_cast<ALfloat>(values[1]);
|
|
|
|
fvals[2] = static_cast<ALfloat>(values[2]);
|
|
|
|
fvals[3] = static_cast<ALfloat>(values[3]);
|
|
|
|
fvals[4] = static_cast<ALfloat>(values[4]);
|
|
|
|
fvals[5] = static_cast<ALfloat>(values[5]);
|
2019-08-03 18:57:38 -07:00
|
|
|
return SetSourcefv(Source, Context, prop, {fvals, 6u});
|
2014-10-31 22:43:13 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
2012-12-06 09:03:48 -08:00
|
|
|
break;
|
2012-10-14 01:36:46 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2019-07-30 21:32:05 -07:00
|
|
|
Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop);
|
2019-08-03 18:57:38 -07:00
|
|
|
return false;
|
2012-10-14 01:36:46 -07:00
|
|
|
}
|
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<const ALint64SOFT> values)
|
2012-10-14 01:36:46 -07:00
|
|
|
{
|
2014-10-31 22:43:13 -07:00
|
|
|
ALfloat fvals[6];
|
2012-10-14 01:36:46 -07:00
|
|
|
ALint ivals[3];
|
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
switch(prop)
|
2012-10-14 01:36:46 -07:00
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
2012-11-01 18:35:20 -07:00
|
|
|
/* Query only */
|
2019-08-03 18:57:38 -07:00
|
|
|
SETERR_RETURN(Context, AL_INVALID_OPERATION, false,
|
|
|
|
"Setting read-only source property 0x%04x", prop);
|
2012-11-01 18:35:20 -07:00
|
|
|
|
2012-10-14 01:36:46 -07:00
|
|
|
/* 1x int */
|
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
case AL_LOOPING:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SEC_OFFSET:
|
2012-10-14 01:36:46 -07:00
|
|
|
case AL_SAMPLE_OFFSET:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_BYTE_OFFSET:
|
2012-10-14 01:36:46 -07:00
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
|
|
|
case AL_DISTANCE_MODEL:
|
2017-04-21 15:48:39 -07:00
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
2017-05-05 02:41:34 -07:00
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] <= INT_MAX && values[0] >= INT_MIN);
|
2012-10-14 01:36:46 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
ivals[0] = static_cast<ALint>(values[0]);
|
|
|
|
return SetSourceiv(Source, Context, prop, {ivals, 1u});
|
2012-10-14 01:36:46 -07:00
|
|
|
|
|
|
|
/* 1x uint */
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0);
|
2012-10-14 01:36:46 -07:00
|
|
|
|
2019-08-03 18:57:38 -07:00
|
|
|
ivals[0] = static_cast<ALuint>(values[0]);
|
|
|
|
return SetSourceiv(Source, Context, prop, {ivals, 1u});
|
2012-10-14 01:36:46 -07:00
|
|
|
|
|
|
|
/* 3x uint */
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2012-10-14 01:36:46 -07:00
|
|
|
CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
|
|
|
|
values[1] <= UINT_MAX && values[1] >= 0 &&
|
|
|
|
values[2] <= UINT_MAX && values[2] >= 0);
|
|
|
|
|
2019-01-08 19:42:44 +01:00
|
|
|
ivals[0] = static_cast<ALuint>(values[0]);
|
|
|
|
ivals[1] = static_cast<ALuint>(values[1]);
|
|
|
|
ivals[2] = static_cast<ALuint>(values[2]);
|
2019-08-03 18:57:38 -07:00
|
|
|
return SetSourceiv(Source, Context, prop, {ivals, 3u});
|
2012-10-14 01:36:46 -07:00
|
|
|
|
|
|
|
/* 1x float */
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_PITCH:
|
|
|
|
case AL_GAIN:
|
|
|
|
case AL_MIN_GAIN:
|
|
|
|
case AL_MAX_GAIN:
|
2012-10-14 01:36:46 -07:00
|
|
|
case AL_REFERENCE_DISTANCE:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
fvals[0] = static_cast<ALfloat>(values[0]);
|
|
|
|
return SetSourcefv(Source, Context, prop, {fvals, 1u});
|
2012-10-14 01:36:46 -07:00
|
|
|
|
|
|
|
/* 3x float */
|
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2019-01-08 19:42:44 +01:00
|
|
|
fvals[0] = static_cast<ALfloat>(values[0]);
|
|
|
|
fvals[1] = static_cast<ALfloat>(values[1]);
|
|
|
|
fvals[2] = static_cast<ALfloat>(values[2]);
|
2019-08-03 18:57:38 -07:00
|
|
|
return SetSourcefv(Source, Context, prop, {fvals, 3u});
|
2014-10-31 22:43:13 -07:00
|
|
|
|
|
|
|
/* 6x float */
|
|
|
|
case AL_ORIENTATION:
|
2019-08-03 18:57:38 -07:00
|
|
|
CHECKSIZE(values, 6);
|
2019-01-08 19:42:44 +01:00
|
|
|
fvals[0] = static_cast<ALfloat>(values[0]);
|
|
|
|
fvals[1] = static_cast<ALfloat>(values[1]);
|
|
|
|
fvals[2] = static_cast<ALfloat>(values[2]);
|
|
|
|
fvals[3] = static_cast<ALfloat>(values[3]);
|
|
|
|
fvals[4] = static_cast<ALfloat>(values[4]);
|
|
|
|
fvals[5] = static_cast<ALfloat>(values[5]);
|
2019-08-03 18:57:38 -07:00
|
|
|
return SetSourcefv(Source, Context, prop, {fvals, 6u});
|
2015-09-22 08:48:26 -07:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
2017-12-03 14:45:19 -08:00
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
2015-09-22 08:48:26 -07:00
|
|
|
break;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2019-07-30 21:32:05 -07:00
|
|
|
Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop);
|
2019-08-03 19:36:19 -07:00
|
|
|
return false;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef CHECKVAL
|
|
|
|
|
|
|
|
|
2019-08-03 19:36:19 -07:00
|
|
|
bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<ALdouble> values);
|
|
|
|
bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<ALint> values);
|
|
|
|
bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<ALint64SOFT> values);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-08-03 19:36:19 -07:00
|
|
|
bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<ALdouble> values)
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{Context->mDevice.get()};
|
2016-05-28 00:43:14 -07:00
|
|
|
ClockLatency clocktime;
|
2018-11-22 14:32:48 -08:00
|
|
|
std::chrono::nanoseconds srcclock;
|
2013-10-07 09:54:35 -07:00
|
|
|
ALint ivals[3];
|
|
|
|
ALboolean err;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2012-12-05 09:22:38 -08:00
|
|
|
switch(prop)
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
2012-12-05 08:27:02 -08:00
|
|
|
case AL_GAIN:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->Gain;
|
|
|
|
return true;
|
2012-12-05 08:27:02 -08:00
|
|
|
|
2012-10-21 11:36:27 -07:00
|
|
|
case AL_PITCH:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->Pitch;
|
|
|
|
return true;
|
2012-10-21 11:36:27 -07:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_MAX_DISTANCE:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->MaxDistance;
|
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->RolloffFactor;
|
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->RefDistance;
|
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->InnerAngle;
|
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->OuterAngle;
|
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2012-10-21 11:36:27 -07:00
|
|
|
case AL_MIN_GAIN:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->MinGain;
|
|
|
|
return true;
|
2012-10-21 11:36:27 -07:00
|
|
|
|
|
|
|
case AL_MAX_GAIN:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->MaxGain;
|
|
|
|
return true;
|
2012-10-21 11:36:27 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->OuterGain;
|
|
|
|
return true;
|
2012-10-21 11:36:27 -07:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = GetSourceOffset(Source, prop, Context);
|
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2012-09-14 09:02:36 -07:00
|
|
|
case AL_CONE_OUTER_GAINHF:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->OuterGainHF;
|
|
|
|
return true;
|
2012-09-14 09:02:36 -07:00
|
|
|
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->AirAbsorptionFactor;
|
|
|
|
return true;
|
2012-09-14 09:02:36 -07:00
|
|
|
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->RoomRolloffFactor;
|
|
|
|
return true;
|
2012-09-14 09:02:36 -07:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_DOPPLER_FACTOR:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->DopplerFactor;
|
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->Radius;
|
|
|
|
return true;
|
2012-08-20 15:57:27 -07:00
|
|
|
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 2);
|
2016-03-25 14:40:44 -07:00
|
|
|
values[0] = Source->StereoPan[0];
|
|
|
|
values[1] = Source->StereoPan[1];
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 2);
|
2016-05-28 04:11:57 -07:00
|
|
|
/* Get the source offset with the clock time first. Then get the
|
|
|
|
* clock time with the device latency. Order is important.
|
|
|
|
*/
|
2018-11-22 12:02:02 -08:00
|
|
|
values[0] = GetSourceSecOffset(Source, Context, &srcclock);
|
2018-12-30 21:38:42 -08:00
|
|
|
{ std::lock_guard<std::mutex> _{device->StateLock};
|
2018-11-20 23:42:21 -08:00
|
|
|
clocktime = GetClockLatency(device);
|
|
|
|
}
|
2018-11-22 14:32:48 -08:00
|
|
|
if(srcclock == clocktime.ClockTime)
|
2019-01-08 19:42:44 +01:00
|
|
|
values[1] = static_cast<ALdouble>(clocktime.Latency.count()) / 1000000000.0;
|
2016-05-28 04:11:57 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If the clock time incremented, reduce the latency by that
|
|
|
|
* much since it's that much closer to the source offset it got
|
|
|
|
* earlier.
|
|
|
|
*/
|
2018-11-22 14:32:48 -08:00
|
|
|
std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock;
|
2019-01-08 19:42:44 +01:00
|
|
|
values[1] = static_cast<ALdouble>((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) /
|
2018-11-22 12:02:02 -08:00
|
|
|
1000000000.0;
|
2016-05-28 04:11:57 -07:00
|
|
|
}
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 2);
|
2018-11-22 12:02:02 -08:00
|
|
|
values[0] = GetSourceSecOffset(Source, Context, &srcclock);
|
2018-11-22 14:32:48 -08:00
|
|
|
values[1] = srcclock.count() / 1000000000.0;
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2017-12-03 14:45:19 -08:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_POSITION:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2018-11-22 12:02:02 -08:00
|
|
|
values[0] = Source->Position[0];
|
|
|
|
values[1] = Source->Position[1];
|
|
|
|
values[2] = Source->Position[2];
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_VELOCITY:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2018-11-22 12:02:02 -08:00
|
|
|
values[0] = Source->Velocity[0];
|
|
|
|
values[1] = Source->Velocity[1];
|
|
|
|
values[2] = Source->Velocity[2];
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_DIRECTION:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 3);
|
2018-11-22 12:02:02 -08:00
|
|
|
values[0] = Source->Direction[0];
|
|
|
|
values[1] = Source->Direction[1];
|
|
|
|
values[2] = Source->Direction[2];
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2014-10-31 22:43:13 -07:00
|
|
|
case AL_ORIENTATION:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 6);
|
2018-12-26 22:27:34 -08:00
|
|
|
values[0] = Source->OrientAt[0];
|
|
|
|
values[1] = Source->OrientAt[1];
|
|
|
|
values[2] = Source->OrientAt[2];
|
|
|
|
values[3] = Source->OrientUp[0];
|
|
|
|
values[4] = Source->OrientUp[1];
|
|
|
|
values[5] = Source->OrientUp[2];
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2014-10-31 22:43:13 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 1x int */
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
case AL_LOOPING:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
|
|
|
case AL_DISTANCE_MODEL:
|
2017-04-21 15:48:39 -07:00
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
2017-05-05 02:41:34 -07:00
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != AL_FALSE)
|
|
|
|
values[0] = static_cast<ALdouble>(ivals[0]);
|
2012-12-07 18:43:13 -08:00
|
|
|
return err;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
|
|
|
break;
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2019-07-30 21:32:05 -07:00
|
|
|
Context->setError(AL_INVALID_ENUM, "Invalid source double property 0x%04x", prop);
|
2019-08-03 19:36:19 -07:00
|
|
|
return false;
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2019-08-03 19:36:19 -07:00
|
|
|
bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<ALint> values)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbufferlistitem *BufferList;
|
|
|
|
ALdouble dvals[6];
|
|
|
|
ALboolean err;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
switch(prop)
|
2018-11-21 11:11:25 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SOURCE_RELATIVE:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->HeadRelative;
|
|
|
|
return true;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_LOOPING:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->Looping;
|
|
|
|
return true;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_BUFFER:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr;
|
2019-08-03 19:36:19 -07:00
|
|
|
values[0] = (BufferList && !BufferList->empty() && BufferList->front()) ?
|
|
|
|
BufferList->front()->id : 0;
|
|
|
|
return true;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SOURCE_STATE:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = GetSourceState(Source, GetSourceVoice(Source, Context));
|
|
|
|
return true;
|
2012-04-23 19:46:05 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_BUFFERS_QUEUED:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!(BufferList=Source->queue))
|
2019-08-03 19:36:19 -07:00
|
|
|
values[0] = 0;
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2018-11-21 11:11:25 -08:00
|
|
|
{
|
2019-08-03 19:36:19 -07:00
|
|
|
ALsizei count{0};
|
2018-11-22 12:02:02 -08:00
|
|
|
do {
|
2019-07-31 09:20:53 -07:00
|
|
|
count += BufferList->mNumBuffers;
|
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
} while(BufferList != nullptr);
|
2019-08-03 19:36:19 -07:00
|
|
|
values[0] = count;
|
2018-11-21 11:11:25 -08:00
|
|
|
}
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(Source->Looping || Source->SourceType != AL_STREAMING)
|
2018-11-21 11:11:25 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Buffers on a looping source are in a perpetual state of
|
|
|
|
* PENDING, so don't report any as PROCESSED */
|
2019-08-03 19:36:19 -07:00
|
|
|
values[0] = 0;
|
2018-11-21 11:11:25 -08:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const ALbufferlistitem *BufferList{Source->queue};
|
|
|
|
const ALbufferlistitem *Current{nullptr};
|
|
|
|
ALsizei played{0};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
ALvoice *voice{GetSourceVoice(Source, Context)};
|
|
|
|
if(voice != nullptr)
|
2019-03-10 16:29:06 -07:00
|
|
|
Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(Source->state == AL_INITIAL)
|
|
|
|
Current = BufferList;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
while(BufferList && BufferList != Current)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
played += BufferList->mNumBuffers;
|
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-08-03 19:36:19 -07:00
|
|
|
values[0] = played;
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SOURCE_TYPE:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->SourceType;
|
|
|
|
return true;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->DryGainHFAuto;
|
|
|
|
return true;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->WetGainAuto;
|
|
|
|
return true;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->WetGainHFAuto;
|
|
|
|
return true;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->DirectChannels;
|
|
|
|
return true;
|
2012-10-13 00:56:39 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_DISTANCE_MODEL:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = static_cast<int>(Source->mDistanceModel);
|
|
|
|
return true;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->mResampler;
|
|
|
|
return true;
|
2012-10-13 00:56:39 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
values[0] = Source->mSpatialize;
|
|
|
|
return true;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 1x float/double */
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
|
|
|
case AL_PITCH:
|
|
|
|
case AL_GAIN:
|
|
|
|
case AL_MIN_GAIN:
|
|
|
|
case AL_MAX_GAIN:
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_SOURCE_RADIUS:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false)
|
|
|
|
values[0] = static_cast<ALint>(dvals[0]);
|
2018-11-22 12:02:02 -08:00
|
|
|
return err;
|
2012-11-01 18:35:20 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 3x float/double */
|
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 3);
|
|
|
|
if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-01-08 19:42:44 +01:00
|
|
|
values[0] = static_cast<ALint>(dvals[0]);
|
|
|
|
values[1] = static_cast<ALint>(dvals[1]);
|
|
|
|
values[2] = static_cast<ALint>(dvals[2]);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* 6x float/double */
|
|
|
|
case AL_ORIENTATION:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 6);
|
|
|
|
if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-01-08 19:42:44 +01:00
|
|
|
values[0] = static_cast<ALint>(dvals[0]);
|
|
|
|
values[1] = static_cast<ALint>(dvals[1]);
|
|
|
|
values[2] = static_cast<ALint>(dvals[2]);
|
|
|
|
values[3] = static_cast<ALint>(dvals[3]);
|
|
|
|
values[4] = static_cast<ALint>(dvals[4]);
|
|
|
|
values[5] = static_cast<ALint>(dvals[5]);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
return err;
|
2012-10-13 00:56:39 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
|
|
|
break; /* i64 only */
|
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
|
|
|
break; /* Double only */
|
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
break; /* Float/double only */
|
2012-10-13 00:56:39 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
|
|
|
break; /* ??? */
|
|
|
|
}
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2019-07-30 21:32:05 -07:00
|
|
|
Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop);
|
2019-08-03 19:36:19 -07:00
|
|
|
return false;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2019-08-03 19:36:19 -07:00
|
|
|
bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span<ALint64SOFT> values)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device = Context->mDevice.get();
|
2018-11-22 12:02:02 -08:00
|
|
|
ClockLatency clocktime;
|
2018-11-22 14:32:48 -08:00
|
|
|
std::chrono::nanoseconds srcclock;
|
2018-11-22 12:02:02 -08:00
|
|
|
ALdouble dvals[6];
|
|
|
|
ALint ivals[3];
|
|
|
|
ALboolean err;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
switch(prop)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 2);
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Get the source offset with the clock time first. Then get the
|
|
|
|
* clock time with the device latency. Order is important.
|
|
|
|
*/
|
|
|
|
values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
|
2018-12-30 21:38:42 -08:00
|
|
|
{ std::lock_guard<std::mutex> _{device->StateLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
clocktime = GetClockLatency(device);
|
|
|
|
}
|
2018-11-22 14:32:48 -08:00
|
|
|
if(srcclock == clocktime.ClockTime)
|
|
|
|
values[1] = clocktime.Latency.count();
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If the clock time incremented, reduce the latency by that
|
|
|
|
* much since it's that much closer to the source offset it got
|
|
|
|
* earlier.
|
|
|
|
*/
|
2018-11-22 14:32:48 -08:00
|
|
|
auto diff = clocktime.ClockTime - srcclock;
|
|
|
|
values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count();
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-08-03 19:36:19 -07:00
|
|
|
return true;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SAMPLE_OFFSET_CLOCK_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 2);
|
2018-11-22 12:02:02 -08:00
|
|
|
values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
|
2018-11-22 14:32:48 -08:00
|
|
|
values[1] = srcclock.count();
|
2018-11-22 12:02:02 -08:00
|
|
|
return AL_TRUE;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 1x float/double */
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
|
|
|
case AL_PITCH:
|
|
|
|
case AL_GAIN:
|
|
|
|
case AL_MIN_GAIN:
|
|
|
|
case AL_MAX_GAIN:
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_SOURCE_RADIUS:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false)
|
|
|
|
values[0] = static_cast<int64_t>(dvals[0]);
|
2018-11-22 12:02:02 -08:00
|
|
|
return err;
|
|
|
|
|
|
|
|
/* 3x float/double */
|
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 3);
|
|
|
|
if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-02-11 12:16:58 -08:00
|
|
|
values[0] = static_cast<int64_t>(dvals[0]);
|
|
|
|
values[1] = static_cast<int64_t>(dvals[1]);
|
|
|
|
values[2] = static_cast<int64_t>(dvals[2]);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
return err;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 6x float/double */
|
|
|
|
case AL_ORIENTATION:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 6);
|
|
|
|
if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-02-11 12:16:58 -08:00
|
|
|
values[0] = static_cast<int64_t>(dvals[0]);
|
|
|
|
values[1] = static_cast<int64_t>(dvals[1]);
|
|
|
|
values[2] = static_cast<int64_t>(dvals[2]);
|
|
|
|
values[3] = static_cast<int64_t>(dvals[3]);
|
|
|
|
values[4] = static_cast<int64_t>(dvals[4]);
|
|
|
|
values[5] = static_cast<int64_t>(dvals[5]);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
return err;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 1x int */
|
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
case AL_LOOPING:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
|
|
|
case AL_DISTANCE_MODEL:
|
|
|
|
case AL_SOURCE_RESAMPLER_SOFT:
|
|
|
|
case AL_SOURCE_SPATIALIZE_SOFT:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false)
|
|
|
|
values[0] = ivals[0];
|
2018-11-22 12:02:02 -08:00
|
|
|
return err;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 1x uint */
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 1);
|
|
|
|
if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false)
|
|
|
|
values[0] = static_cast<ALuint>(ivals[0]);
|
2018-11-22 12:02:02 -08:00
|
|
|
return err;
|
2012-10-13 00:56:39 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 3x uint */
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2019-08-03 19:36:19 -07:00
|
|
|
CHECKSIZE(values, 3);
|
|
|
|
if((err=GetSourceiv(Source, Context, prop, {ivals, 3u})) != false)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-01-08 19:42:44 +01:00
|
|
|
values[0] = static_cast<ALuint>(ivals[0]);
|
|
|
|
values[1] = static_cast<ALuint>(ivals[1]);
|
|
|
|
values[2] = static_cast<ALuint>(ivals[2]);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
return err;
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
case AL_SEC_OFFSET_CLOCK_SOFT:
|
|
|
|
break; /* Double only */
|
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
break; /* Float/double only */
|
2012-10-13 00:56:39 -07:00
|
|
|
}
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2019-07-30 21:32:05 -07:00
|
|
|
Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop);
|
2019-08-03 19:36:19 -07:00
|
|
|
return false;
|
2012-10-13 00:56:39 -07:00
|
|
|
}
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
} // namespace
|
2012-10-13 00:56:39 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Generating %d sources", n);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(n == 1)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *source = AllocSource(context.get());
|
|
|
|
if(source) sources[0] = source->id;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2012-12-05 20:51:25 -08:00
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
al::vector<ALuint> tempids(n);
|
|
|
|
auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(),
|
|
|
|
[&context](ALuint &id) -> bool
|
|
|
|
{
|
|
|
|
ALsource *source{AllocSource(context.get())};
|
|
|
|
if(!source) return false;
|
|
|
|
id = source->id;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
if(alloc_end != tempids.end())
|
2018-12-12 21:18:31 -08:00
|
|
|
alDeleteSources(static_cast<ALsizei>(std::distance(tempids.begin(), alloc_end)),
|
|
|
|
tempids.data());
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
|
|
|
std::copy(tempids.cbegin(), tempids.cend(), sources);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2011-06-16 09:14:41 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Deleting %d sources", n);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
/* Check that all Sources are valid */
|
|
|
|
const ALuint *sources_end = sources + n;
|
|
|
|
auto invsrc = std::find_if_not(sources, sources_end,
|
|
|
|
[&context](ALuint sid) -> bool
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!LookupSource(context.get(), sid))
|
2018-11-21 11:11:25 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", sid);
|
2018-11-22 12:02:02 -08:00
|
|
|
return false;
|
2018-11-21 11:11:25 -08:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
return true;
|
2012-12-05 20:51:25 -08:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
);
|
|
|
|
if(LIKELY(invsrc == sources_end))
|
|
|
|
{
|
|
|
|
/* All good. Delete source IDs. */
|
|
|
|
std::for_each(sources, sources_end,
|
|
|
|
[&context](ALuint sid) -> void
|
|
|
|
{
|
|
|
|
ALsource *src{LookupSource(context.get(), sid)};
|
|
|
|
if(src) FreeSource(context.get(), src);
|
|
|
|
}
|
|
|
|
);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2012-08-20 15:26:35 -07:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
2018-11-22 12:02:02 -08:00
|
|
|
if(LIKELY(context))
|
2012-08-20 15:26:35 -07:00
|
|
|
{
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
if(LookupSource(context.get(), source) != nullptr)
|
|
|
|
return AL_TRUE;
|
2012-08-20 15:26:35 -07:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
return AL_FALSE;
|
2012-08-20 15:26:35 -07:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2012-08-20 15:26:35 -07:00
|
|
|
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
2018-11-21 11:11:25 -08:00
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2012-12-05 19:58:01 -08:00
|
|
|
else
|
2019-08-03 18:57:38 -07:00
|
|
|
SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {&value, 1u});
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
2018-11-21 11:11:25 -08:00
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2012-12-05 19:58:01 -08:00
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2019-08-03 18:57:38 -07:00
|
|
|
const ALfloat fvals[3]{ value1, value2, value3 };
|
2018-11-22 12:02:02 -08:00
|
|
|
SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fvals);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2011-06-16 09:14:41 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
2018-11-21 11:11:25 -08:00
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2012-08-29 00:25:01 -07:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2012-12-05 19:58:01 -08:00
|
|
|
else
|
2019-08-03 18:57:38 -07:00
|
|
|
SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {values, INT_MAX});
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2012-08-18 11:02:54 -07:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2012-08-18 11:02:54 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
2018-11-21 11:11:25 -08:00
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2012-12-05 19:58:01 -08:00
|
|
|
else
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-08-03 18:57:38 -07:00
|
|
|
const auto fval = static_cast<ALfloat>(value);
|
|
|
|
SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {&fval, 1u});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
2018-11-21 11:11:25 -08:00
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2019-08-03 18:57:38 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const ALfloat fvals[3]{static_cast<ALfloat>(value1), static_cast<ALfloat>(value2),
|
|
|
|
static_cast<ALfloat>(value3)};
|
2018-11-22 12:02:02 -08:00
|
|
|
SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fvals);
|
2012-08-18 11:02:54 -07:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2012-08-18 11:02:54 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2012-08-18 11:02:54 -07:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2012-08-18 11:02:54 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
2018-11-21 11:11:25 -08:00
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2012-08-29 00:25:01 -07:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2012-12-05 19:58:01 -08:00
|
|
|
else
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-08-03 19:36:19 -07:00
|
|
|
const ALuint count{DoubleValsByProp(param)};
|
|
|
|
ALfloat fvals[6];
|
|
|
|
for(ALuint i{0};i < count;i++)
|
|
|
|
fvals[i] = static_cast<ALfloat>(values[i]);
|
|
|
|
SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), {fvals, count});
|
2013-10-07 09:24:50 -07:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 18:57:38 -07:00
|
|
|
SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {&value, 1u});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2016-08-08 22:31:08 -07:00
|
|
|
{
|
2019-08-03 18:57:38 -07:00
|
|
|
const ALint ivals[3]{ value1, value2, value3 };
|
2018-11-22 12:02:02 -08:00
|
|
|
SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), ivals);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source = LookupSource(context.get(), source);
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 18:57:38 -07:00
|
|
|
SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {values, INT_MAX});
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
|
|
|
|
AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 18:57:38 -07:00
|
|
|
SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {&value, 1u});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-11-21 11:11:25 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2013-10-07 09:24:50 -07:00
|
|
|
{
|
2019-08-03 18:57:38 -07:00
|
|
|
const ALint64SOFT i64vals[3]{ value1, value2, value3 };
|
2018-11-22 12:02:02 -08:00
|
|
|
SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), i64vals);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mPropLock};
|
|
|
|
std::lock_guard<std::mutex> __{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 18:57:38 -07:00
|
|
|
SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {values, INT_MAX});
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!value)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2013-10-07 09:24:50 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALdouble dval;
|
2019-08-03 19:36:19 -07:00
|
|
|
if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), {&dval, 1u}))
|
2019-01-08 19:42:44 +01:00
|
|
|
*value = static_cast<ALfloat>(dval);
|
2013-10-07 09:24:50 -07:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2012-04-23 19:46:05 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!(value1 && value2 && value3))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ALdouble dvals[3];
|
|
|
|
if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dvals))
|
|
|
|
{
|
2019-01-08 19:42:44 +01:00
|
|
|
*value1 = static_cast<ALfloat>(dvals[0]);
|
|
|
|
*value2 = static_cast<ALfloat>(dvals[1]);
|
|
|
|
*value3 = static_cast<ALfloat>(dvals[2]);
|
2011-09-11 03:57:40 -07:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2014-05-10 08:55:28 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
|
|
|
{
|
2019-08-03 19:36:19 -07:00
|
|
|
const ALuint count{FloatValsByProp(param)};
|
|
|
|
ALdouble dvals[6];
|
|
|
|
if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), {dvals, count}))
|
2018-05-21 23:25:56 -07:00
|
|
|
{
|
2019-08-03 19:36:19 -07:00
|
|
|
for(ALuint i{0};i < count;i++)
|
|
|
|
values[i] = static_cast<ALfloat>(dvals[i]);
|
2018-05-21 23:25:56 -07:00
|
|
|
}
|
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-05-21 23:25:56 -07:00
|
|
|
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!value)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 19:36:19 -07:00
|
|
|
GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), {value, 1u});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!(value1 && value2 && value3))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-05-21 23:25:56 -07:00
|
|
|
else
|
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALdouble dvals[3];
|
|
|
|
if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dvals))
|
|
|
|
{
|
|
|
|
*value1 = dvals[0];
|
|
|
|
*value2 = dvals[1];
|
|
|
|
*value3 = dvals[2];
|
|
|
|
}
|
2018-05-21 23:25:56 -07:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-05-21 23:25:56 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-05-21 23:25:56 -07:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2018-05-21 23:25:56 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 19:36:19 -07:00
|
|
|
GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), {values, INT_MAX});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
|
|
|
|
AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2018-05-21 23:25:56 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!value)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 19:36:19 -07:00
|
|
|
GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {value, 1u});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-05-21 23:25:56 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!(value1 && value2 && value3))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2018-05-21 23:25:56 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALint ivals[3];
|
|
|
|
if(GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), ivals))
|
2018-05-21 23:25:56 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
*value1 = ivals[0];
|
|
|
|
*value2 = ivals[1];
|
|
|
|
*value3 = ivals[2];
|
2018-05-21 23:25:56 -07:00
|
|
|
}
|
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-05-21 23:25:56 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2018-05-21 23:25:56 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 19:36:19 -07:00
|
|
|
GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), {values, INT_MAX});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2018-05-21 23:25:56 -07:00
|
|
|
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2014-05-10 08:55:28 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!value)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 19:36:19 -07:00
|
|
|
GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {value, 1u});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!(value1 && value2 && value3))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2017-04-18 00:58:33 -07:00
|
|
|
else
|
2013-10-07 09:24:50 -07:00
|
|
|
{
|
2019-02-11 12:16:58 -08:00
|
|
|
ALint64SOFT i64vals[3];
|
2018-11-22 12:02:02 -08:00
|
|
|
if(GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), i64vals))
|
|
|
|
{
|
|
|
|
*value1 = i64vals[0];
|
|
|
|
*value2 = i64vals[1];
|
|
|
|
*value3 = i64vals[2];
|
|
|
|
}
|
2013-10-07 09:24:50 -07:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-21 11:11:25 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *Source{LookupSource(context.get(), source)};
|
|
|
|
if(UNLIKELY(!Source))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid source ID %u", source);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-08-03 19:36:19 -07:00
|
|
|
GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), {values, INT_MAX});
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2017-02-27 15:35:15 -08:00
|
|
|
|
2016-07-31 23:42:30 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
|
|
|
{ alSourcePlayv(1, &source); }
|
|
|
|
END_API_FUNC
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Playing %d sources", n);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n == 0) return;
|
|
|
|
|
2019-07-06 14:59:26 -07:00
|
|
|
al::vector<ALsource*> extra_sources;
|
|
|
|
std::array<ALsource*,16> source_storage;
|
|
|
|
ALsource **srchandles{source_storage.data()};
|
|
|
|
if(UNLIKELY(static_cast<ALuint>(n) > source_storage.size()))
|
|
|
|
{
|
|
|
|
extra_sources.resize(n);
|
|
|
|
srchandles = extra_sources.data();
|
|
|
|
}
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2019-07-06 14:59:26 -07:00
|
|
|
for(ALsizei i{0};i < n;i++)
|
|
|
|
{
|
|
|
|
srchandles[i] = LookupSource(context.get(), sources[i]);
|
|
|
|
if(!srchandles[i])
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]);
|
2019-07-06 14:59:26 -07:00
|
|
|
}
|
2014-05-10 05:07:13 -07:00
|
|
|
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2019-01-01 16:38:54 -08:00
|
|
|
BackendLockGuard __{*device->Backend};
|
2018-11-22 12:02:02 -08:00
|
|
|
/* If the device is disconnected, go right to stopped. */
|
2018-12-03 01:41:52 -08:00
|
|
|
if(UNLIKELY(!device->Connected.load(std::memory_order_acquire)))
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
/* TODO: Send state change event? */
|
2019-07-06 14:59:26 -07:00
|
|
|
std::for_each(srchandles, srchandles+n,
|
2019-07-15 06:03:35 -07:00
|
|
|
[](ALsource *source) -> void
|
2018-12-03 01:41:52 -08:00
|
|
|
{
|
|
|
|
source->OffsetType = AL_NONE;
|
|
|
|
source->Offset = 0.0;
|
|
|
|
source->state = AL_STOPPED;
|
|
|
|
}
|
|
|
|
);
|
2018-11-22 12:02:02 -08:00
|
|
|
return;
|
2018-02-25 09:51:07 -08:00
|
|
|
}
|
|
|
|
|
2019-03-09 15:04:51 -08:00
|
|
|
/* Count the number of reusable voices. */
|
2019-07-30 09:05:54 -07:00
|
|
|
auto voices_end = context->mVoices->begin() +
|
|
|
|
context->mVoiceCount.load(std::memory_order_relaxed);
|
|
|
|
auto free_voices = std::accumulate(context->mVoices->begin(), voices_end, ALsizei{0},
|
2019-06-09 18:13:54 -07:00
|
|
|
[](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei
|
2019-03-09 16:48:07 -08:00
|
|
|
{
|
2019-06-09 18:13:54 -07:00
|
|
|
if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped &&
|
|
|
|
voice.mSourceID.load(std::memory_order_relaxed) == 0u)
|
2019-03-09 16:48:07 -08:00
|
|
|
return count + 1;
|
|
|
|
return count;
|
|
|
|
}
|
2019-03-09 15:04:51 -08:00
|
|
|
);
|
|
|
|
if(UNLIKELY(n > free_voices))
|
2018-02-25 09:51:07 -08:00
|
|
|
{
|
2019-03-09 15:04:51 -08:00
|
|
|
/* Increment the number of voices to handle the request. */
|
2019-06-09 18:13:54 -07:00
|
|
|
const ALuint need_voices{static_cast<ALuint>(n) - free_voices};
|
2019-07-30 09:05:54 -07:00
|
|
|
const size_t rem_voices{context->mVoices->size() -
|
|
|
|
context->mVoiceCount.load(std::memory_order_relaxed)};
|
2019-03-09 15:04:51 -08:00
|
|
|
|
|
|
|
if(UNLIKELY(need_voices > rem_voices))
|
|
|
|
{
|
|
|
|
/* Allocate more voices to get enough. */
|
2019-06-09 18:13:54 -07:00
|
|
|
const size_t alloc_count{need_voices - rem_voices};
|
2019-07-30 09:05:54 -07:00
|
|
|
if(UNLIKELY(context->mVoices->size() > std::numeric_limits<ALsizei>::max()-alloc_count))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
|
2019-07-30 09:05:54 -07:00
|
|
|
"Overflow increasing voice count to %zu + %zu", context->mVoices->size(),
|
2019-06-09 18:13:54 -07:00
|
|
|
alloc_count);
|
2019-03-09 15:04:51 -08:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
const size_t newcount{context->mVoices->size() + alloc_count};
|
2019-07-30 14:13:05 -07:00
|
|
|
context->allocVoices(newcount);
|
2019-03-09 15:04:51 -08:00
|
|
|
}
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
context->mVoiceCount.fetch_add(need_voices, std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
|
2019-07-06 14:59:26 -07:00
|
|
|
auto start_source = [&context,device](ALsource *source) -> void
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
/* Check that there is a queue containing at least one valid, non zero
|
|
|
|
* length buffer.
|
|
|
|
*/
|
|
|
|
ALbufferlistitem *BufferList{source->queue};
|
2019-07-31 09:20:53 -07:00
|
|
|
while(BufferList && BufferList->mMaxSamples == 0)
|
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
/* If there's nothing to play, go right to stopped. */
|
|
|
|
if(UNLIKELY(!BufferList))
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
/* 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.
|
2018-02-25 09:51:07 -08:00
|
|
|
*/
|
2018-11-22 12:02:02 -08:00
|
|
|
ALenum oldstate{GetSourceState(source, nullptr)};
|
|
|
|
source->OffsetType = AL_NONE;
|
|
|
|
source->Offset = 0.0;
|
|
|
|
if(oldstate != AL_STOPPED)
|
2018-03-27 08:27:16 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
source->state = AL_STOPPED;
|
|
|
|
SendStateChangeEvent(context.get(), source->id, AL_STOPPED);
|
2018-03-27 08:27:16 -07:00
|
|
|
}
|
2018-12-03 01:41:52 -08:00
|
|
|
return;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
ALvoice *voice{GetSourceVoice(source, context.get())};
|
|
|
|
switch(GetSourceState(source, voice))
|
|
|
|
{
|
2018-12-03 01:41:52 -08:00
|
|
|
case AL_PLAYING:
|
|
|
|
assert(voice != nullptr);
|
|
|
|
/* A source that's already playing is restarted from the beginning. */
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed);
|
|
|
|
voice->mPosition.store(0u, std::memory_order_relaxed);
|
|
|
|
voice->mPositionFrac.store(0, std::memory_order_release);
|
2018-12-03 01:41:52 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case AL_PAUSED:
|
|
|
|
assert(voice != nullptr);
|
|
|
|
/* A source that's paused simply resumes. */
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mPlayState.store(ALvoice::Playing, std::memory_order_release);
|
2018-12-03 01:41:52 -08:00
|
|
|
source->state = AL_PLAYING;
|
|
|
|
SendStateChangeEvent(context.get(), source->id, AL_PLAYING);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert(voice == nullptr);
|
|
|
|
break;
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Look for an unused voice to play this source with. */
|
2019-07-30 09:05:54 -07:00
|
|
|
auto voices_end = context->mVoices->begin() +
|
|
|
|
context->mVoiceCount.load(std::memory_order_relaxed);
|
|
|
|
voice = std::find_if(context->mVoices->begin(), voices_end,
|
2019-06-09 18:13:54 -07:00
|
|
|
[](const ALvoice &voice) noexcept -> bool
|
2019-03-09 16:48:07 -08:00
|
|
|
{
|
2019-06-09 18:13:54 -07:00
|
|
|
return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped &&
|
|
|
|
voice.mSourceID.load(std::memory_order_relaxed) == 0u;
|
2019-03-09 16:48:07 -08:00
|
|
|
}
|
2018-11-23 16:16:31 -08:00
|
|
|
);
|
2019-06-09 18:13:54 -07:00
|
|
|
assert(voice != voices_end);
|
2019-08-02 12:38:20 -07:00
|
|
|
auto vidx = static_cast<ALuint>(std::distance(context->mVoices->begin(), voice));
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release);
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
source->PropsClean.test_and_set(std::memory_order_acquire);
|
|
|
|
UpdateSourceProps(source, voice, context.get());
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* A source that's not playing or paused has any offset applied when it
|
|
|
|
* starts playing.
|
|
|
|
*/
|
|
|
|
if(source->Looping)
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mLoopBuffer.store(source->queue, std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
else
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
|
|
|
|
voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed);
|
|
|
|
voice->mPosition.store(0u, std::memory_order_relaxed);
|
|
|
|
voice->mPositionFrac.store(0, std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
bool start_fading{false};
|
|
|
|
if(ApplyOffset(source, voice) != AL_FALSE)
|
2019-03-10 16:29:06 -07:00
|
|
|
start_fading = voice->mPosition.load(std::memory_order_relaxed) != 0 ||
|
|
|
|
voice->mPositionFrac.load(std::memory_order_relaxed) != 0 ||
|
|
|
|
voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList;
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
auto buffer = std::find_if(BufferList->cbegin(), BufferList->cend(),
|
2018-12-26 21:55:39 -08:00
|
|
|
std::bind(std::not_equal_to<const ALbuffer*>{}, _1, nullptr));
|
2019-07-31 09:20:53 -07:00
|
|
|
if(buffer != BufferList->cend())
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mFrequency = (*buffer)->Frequency;
|
|
|
|
voice->mFmtChannels = (*buffer)->mFmtChannels;
|
|
|
|
voice->mNumChannels = ChannelsFromFmt((*buffer)->mFmtChannels);
|
|
|
|
voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Clear the stepping value so the mixer knows not to mix this until
|
|
|
|
* the update gets applied.
|
|
|
|
*/
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mStep = 0;
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mFlags = start_fading ? VOICE_IS_FADING : 0;
|
|
|
|
if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC;
|
2018-12-03 01:41:52 -08:00
|
|
|
|
2019-02-21 04:57:56 -08:00
|
|
|
/* Don't need to set the VOICE_IS_AMBISONIC flag if the device is
|
|
|
|
* mixing in first order. No HF scaling is necessary to mix it.
|
|
|
|
*/
|
2019-03-10 16:29:06 -07:00
|
|
|
if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) &&
|
2019-02-21 04:57:56 -08:00
|
|
|
device->mAmbiOrder > 1)
|
|
|
|
{
|
2019-05-17 20:39:28 -07:00
|
|
|
const int *OrderFromChan;
|
2019-03-10 16:29:06 -07:00
|
|
|
if(voice->mFmtChannels == FmtBFormat2D)
|
2019-03-10 15:46:46 -07:00
|
|
|
{
|
|
|
|
static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{
|
|
|
|
0, 1,1, 2,2, 3,3
|
|
|
|
};
|
2019-05-17 20:39:28 -07:00
|
|
|
OrderFromChan = Order2DFromChan;
|
2019-03-10 15:46:46 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-17 20:39:28 -07:00
|
|
|
static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{
|
2019-03-10 15:46:46 -07:00
|
|
|
0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3,
|
|
|
|
};
|
2019-05-17 20:39:28 -07:00
|
|
|
OrderFromChan = Order3DFromChan;
|
2019-03-10 15:46:46 -07:00
|
|
|
}
|
|
|
|
|
2019-05-22 03:03:24 -07:00
|
|
|
BandSplitter splitter{400.0f / static_cast<ALfloat>(device->Frequency)};
|
2019-05-17 20:39:28 -07:00
|
|
|
|
|
|
|
const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder);
|
2019-06-03 22:24:26 -07:00
|
|
|
auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void
|
2019-05-17 20:39:28 -07:00
|
|
|
{
|
2019-06-03 22:24:26 -07:00
|
|
|
chandata.mPrevSamples.fill(0.0f);
|
|
|
|
chandata.mAmbiScale = scales[*(OrderFromChan++)];
|
|
|
|
chandata.mAmbiSplitter = splitter;
|
2019-05-17 20:39:28 -07:00
|
|
|
};
|
2019-06-03 22:24:26 -07:00
|
|
|
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
|
|
|
init_ambi);
|
2019-05-17 20:39:28 -07:00
|
|
|
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mFlags |= VOICE_IS_AMBISONIC;
|
2019-02-21 04:57:56 -08:00
|
|
|
}
|
2019-05-17 20:39:28 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Clear previous samples. */
|
2019-06-03 22:24:26 -07:00
|
|
|
auto clear_prevs = [](ALvoice::ChannelData &chandata) -> void
|
|
|
|
{ chandata.mPrevSamples.fill(0.0f); };
|
|
|
|
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
|
|
|
clear_prevs);
|
2019-05-17 20:39:28 -07:00
|
|
|
}
|
2019-02-21 04:57:56 -08:00
|
|
|
|
2019-06-03 22:24:26 -07:00
|
|
|
auto clear_params = [device](ALvoice::ChannelData &chandata) -> void
|
|
|
|
{
|
|
|
|
chandata.mDryParams = DirectParams{};
|
|
|
|
std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{});
|
|
|
|
};
|
|
|
|
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
|
|
|
clear_params);
|
2018-12-03 01:41:52 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(device->AvgSpeakerDist > 0.0f)
|
|
|
|
{
|
2019-05-17 20:39:28 -07:00
|
|
|
const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC /
|
|
|
|
(device->AvgSpeakerDist * device->Frequency)};
|
2019-06-03 22:24:26 -07:00
|
|
|
auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void
|
|
|
|
{ chandata.mDryParams.NFCtrlFilter.init(w1); };
|
|
|
|
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
|
|
|
init_nfc);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mSourceID.store(source->id, std::memory_order_relaxed);
|
|
|
|
voice->mPlayState.store(ALvoice::Playing, std::memory_order_release);
|
2018-11-22 12:02:02 -08:00
|
|
|
source->state = AL_PLAYING;
|
|
|
|
source->VoiceIdx = vidx;
|
|
|
|
|
|
|
|
SendStateChangeEvent(context.get(), source->id, AL_PLAYING);
|
2018-12-03 01:41:52 -08:00
|
|
|
};
|
2019-07-06 14:59:26 -07:00
|
|
|
std::for_each(srchandles, srchandles+n, start_source);
|
2018-11-20 12:25:15 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
|
|
|
|
2018-11-20 12:25:15 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
|
|
|
{ alSourcePausev(1, &source); }
|
|
|
|
END_API_FUNC
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
|
|
|
if(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Pausing %d sources", n);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n == 0) return;
|
|
|
|
|
2019-07-06 14:59:26 -07:00
|
|
|
al::vector<ALsource*> extra_sources;
|
|
|
|
std::array<ALsource*,16> source_storage;
|
|
|
|
ALsource **srchandles{source_storage.data()};
|
|
|
|
if(UNLIKELY(static_cast<ALuint>(n) > source_storage.size()))
|
|
|
|
{
|
|
|
|
extra_sources.resize(n);
|
|
|
|
srchandles = extra_sources.data();
|
|
|
|
}
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
for(ALsizei i{0};i < n;i++)
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
2019-07-06 14:59:26 -07:00
|
|
|
srchandles[i] = LookupSource(context.get(), sources[i]);
|
|
|
|
if(!srchandles[i])
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
|
|
|
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2019-01-01 16:38:54 -08:00
|
|
|
BackendLockGuard __{*device->Backend};
|
2019-07-06 14:59:26 -07:00
|
|
|
auto pause_source = [&context](ALsource *source) -> void
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ALvoice *voice{GetSourceVoice(source, context.get())};
|
2019-03-09 16:48:07 -08:00
|
|
|
if(voice)
|
|
|
|
{
|
|
|
|
std::atomic_thread_fence(std::memory_order_release);
|
|
|
|
ALvoice::State oldvstate{ALvoice::Playing};
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
|
2019-03-09 16:48:07 -08:00
|
|
|
std::memory_order_acq_rel, std::memory_order_acquire);
|
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
if(GetSourceState(source, voice) == AL_PLAYING)
|
2017-02-21 16:31:59 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
source->state = AL_PAUSED;
|
|
|
|
SendStateChangeEvent(context.get(), source->id, AL_PAUSED);
|
2017-02-21 16:31:59 -08:00
|
|
|
}
|
2019-07-06 14:59:26 -07:00
|
|
|
};
|
|
|
|
std::for_each(srchandles, srchandles+n, pause_source);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
|
|
|
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
|
|
|
{ alSourceStopv(1, &source); }
|
|
|
|
END_API_FUNC
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
|
|
|
if(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Stopping %d sources", n);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n == 0) return;
|
|
|
|
|
2019-07-06 14:59:26 -07:00
|
|
|
al::vector<ALsource*> extra_sources;
|
|
|
|
std::array<ALsource*,16> source_storage;
|
|
|
|
ALsource **srchandles{source_storage.data()};
|
|
|
|
if(UNLIKELY(static_cast<ALuint>(n) > source_storage.size()))
|
|
|
|
{
|
|
|
|
extra_sources.resize(n);
|
|
|
|
srchandles = extra_sources.data();
|
|
|
|
}
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
for(ALsizei i{0};i < n;i++)
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
2019-07-06 14:59:26 -07:00
|
|
|
srchandles[i] = LookupSource(context.get(), sources[i]);
|
|
|
|
if(!srchandles[i])
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
|
|
|
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2019-01-01 16:38:54 -08:00
|
|
|
BackendLockGuard __{*device->Backend};
|
2019-07-06 14:59:26 -07:00
|
|
|
auto stop_source = [&context](ALsource *source) -> void
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALvoice *voice{GetSourceVoice(source, context.get())};
|
|
|
|
if(voice != nullptr)
|
|
|
|
{
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
|
|
|
|
voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
|
|
|
|
voice->mSourceID.store(0u, std::memory_order_relaxed);
|
2019-03-09 16:48:07 -08:00
|
|
|
std::atomic_thread_fence(std::memory_order_release);
|
|
|
|
ALvoice::State oldvstate{ALvoice::Playing};
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
|
2019-03-09 16:48:07 -08:00
|
|
|
std::memory_order_acq_rel, std::memory_order_acquire);
|
2018-11-22 12:02:02 -08:00
|
|
|
voice = nullptr;
|
|
|
|
}
|
|
|
|
ALenum oldstate{GetSourceState(source, voice)};
|
|
|
|
if(oldstate != AL_INITIAL && oldstate != AL_STOPPED)
|
|
|
|
{
|
|
|
|
source->state = AL_STOPPED;
|
|
|
|
SendStateChangeEvent(context.get(), source->id, AL_STOPPED);
|
|
|
|
}
|
|
|
|
source->OffsetType = AL_NONE;
|
|
|
|
source->Offset = 0.0;
|
2019-07-06 14:59:26 -07:00
|
|
|
};
|
|
|
|
std::for_each(srchandles, srchandles+n, stop_source);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
|
|
|
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
|
|
|
{ alSourceRewindv(1, &source); }
|
|
|
|
END_API_FUNC
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Rewinding %d sources", n);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(n == 0) return;
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
|
2019-07-06 14:59:26 -07:00
|
|
|
al::vector<ALsource*> extra_sources;
|
|
|
|
std::array<ALsource*,16> source_storage;
|
|
|
|
ALsource **srchandles{source_storage.data()};
|
|
|
|
if(UNLIKELY(static_cast<ALuint>(n) > source_storage.size()))
|
|
|
|
{
|
|
|
|
extra_sources.resize(n);
|
|
|
|
srchandles = extra_sources.data();
|
|
|
|
}
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
for(ALsizei i{0};i < n;i++)
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
2019-07-06 14:59:26 -07:00
|
|
|
srchandles[i] = LookupSource(context.get(), sources[i]);
|
|
|
|
if(!srchandles[i])
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
|
|
|
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2019-01-01 16:38:54 -08:00
|
|
|
BackendLockGuard __{*device->Backend};
|
2019-07-06 14:59:26 -07:00
|
|
|
auto rewind_source = [&context](ALsource *source) -> void
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALvoice *voice{GetSourceVoice(source, context.get())};
|
|
|
|
if(voice != nullptr)
|
|
|
|
{
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
|
|
|
|
voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
|
|
|
|
voice->mSourceID.store(0u, std::memory_order_relaxed);
|
2019-03-09 16:48:07 -08:00
|
|
|
std::atomic_thread_fence(std::memory_order_release);
|
|
|
|
ALvoice::State oldvstate{ALvoice::Playing};
|
2019-03-10 16:29:06 -07:00
|
|
|
voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
|
2019-03-09 16:48:07 -08:00
|
|
|
std::memory_order_acq_rel, std::memory_order_acquire);
|
2018-11-22 12:02:02 -08:00
|
|
|
voice = nullptr;
|
|
|
|
}
|
|
|
|
if(GetSourceState(source, voice) != AL_INITIAL)
|
|
|
|
{
|
|
|
|
source->state = AL_INITIAL;
|
|
|
|
SendStateChangeEvent(context.get(), source->id, AL_INITIAL);
|
|
|
|
}
|
|
|
|
source->OffsetType = AL_NONE;
|
|
|
|
source->Offset = 0.0;
|
2019-07-06 14:59:26 -07:00
|
|
|
};
|
|
|
|
std::for_each(srchandles, srchandles+n, rewind_source);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
|
|
|
if(nb < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Queueing %d buffers", nb);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(nb == 0) return;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *source{LookupSource(context.get(),src)};
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(!source))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
/* Can't queue on a Static Source */
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(source->SourceType == AL_STATIC))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
/* Check for a valid Buffer, for its frequency and format */
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbuffer *BufferFmt{nullptr};
|
|
|
|
ALbufferlistitem *BufferList{source->queue};
|
|
|
|
while(BufferList)
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++)
|
|
|
|
BufferFmt = (*BufferList)[i];
|
2018-11-22 12:02:02 -08:00
|
|
|
if(BufferFmt) break;
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
Provide asynchronous property updates for sources
This necessitates a change in how source updates are handled. Rather than just
being able to update sources when a dependent object state is changed (e.g. a
listener gain change), now all source updates must be proactively provided.
Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or
alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be
filling out more update containers for the mixer thread to use.
The upside is that there's less blocking between the app's calling thread and
the mixer thread, particularly for vectors and other multi-value properties
(filters and sends). Deferring behavior when used is also improved, since
updates that shouldn't be applied yet are simply not provided. And when they
are provided, the mixer doesn't have to ignore them, meaning the actual
deferring of a context doesn't have to synchrnously force an update -- the
process call will send any pending updates, which the mixer will apply even if
another deferral occurs before the mixer runs, because it'll still be there
waiting on the next mixer invocation.
There is one slight bug introduced by this commit. When a listener change is
made, or changes to multiple sources while updates are being deferred, it is
possible for the mixer to run while the sources are prepping their updates,
causing some of the source updates to be seen before the other. This will be
fixed in short order.
2016-05-14 23:43:40 -07:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-26 22:06:53 -08:00
|
|
|
std::unique_lock<std::mutex> buflock{device->BufferLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbufferlistitem *BufferListStart{nullptr};
|
|
|
|
BufferList = nullptr;
|
|
|
|
for(ALsizei i{0};i < nb;i++)
|
|
|
|
{
|
|
|
|
ALbuffer *buffer{nullptr};
|
|
|
|
if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr)
|
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]);
|
2018-11-22 12:02:02 -08:00
|
|
|
goto buffer_error;
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!BufferListStart)
|
|
|
|
{
|
2019-06-06 00:37:00 -07:00
|
|
|
BufferListStart = static_cast<ALbufferlistitem*>(al_calloc(alignof(void*),
|
2019-02-11 11:14:34 -08:00
|
|
|
ALbufferlistitem::Sizeof(1u)));
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferList = BufferListStart;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-06 00:37:00 -07:00
|
|
|
auto item = static_cast<ALbufferlistitem*>(al_calloc(alignof(void*),
|
2019-02-11 11:14:34 -08:00
|
|
|
ALbufferlistitem::Sizeof(1u)));
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList->mNext.store(item, std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferList = item;
|
|
|
|
}
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList->mNext.store(nullptr, std::memory_order_relaxed);
|
|
|
|
BufferList->mMaxSamples = buffer ? buffer->SampleLen : 0;
|
|
|
|
BufferList->mNumBuffers = 1;
|
|
|
|
BufferList->mBuffers[0] = buffer;
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!buffer) continue;
|
2012-08-18 11:02:54 -07:00
|
|
|
|
2019-08-01 13:28:53 -07:00
|
|
|
IncrementRef(buffer->ref);
|
2016-07-07 19:48:21 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
|
2017-02-24 01:47:34 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Queueing non-persistently mapped buffer %u",
|
|
|
|
buffer->id);
|
2018-11-22 12:02:02 -08:00
|
|
|
goto buffer_error;
|
2017-02-24 01:47:34 -08:00
|
|
|
}
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(BufferFmt == nullptr)
|
|
|
|
BufferFmt = buffer;
|
|
|
|
else if(BufferFmt->Frequency != buffer->Frequency ||
|
2018-12-24 19:29:01 -08:00
|
|
|
BufferFmt->mFmtChannels != buffer->mFmtChannels ||
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferFmt->OriginalType != buffer->OriginalType)
|
2017-02-27 15:35:15 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format");
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
buffer_error:
|
|
|
|
/* A buffer failed (invalid ID or format), so unlock and release
|
|
|
|
* each buffer we had. */
|
|
|
|
while(BufferListStart)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
ALbufferlistitem *next = BufferListStart->mNext.load(std::memory_order_relaxed);
|
|
|
|
std::for_each(BufferListStart->begin(), BufferListStart->end(),
|
|
|
|
[](ALbuffer *buffer) -> void
|
2019-08-01 13:28:53 -07:00
|
|
|
{ if(buffer) DecrementRef(buffer->ref); });
|
2018-11-22 12:02:02 -08:00
|
|
|
al_free(BufferListStart);
|
|
|
|
BufferListStart = next;
|
|
|
|
}
|
|
|
|
return;
|
2017-02-27 15:35:15 -08:00
|
|
|
}
|
2012-08-18 11:02:54 -07:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
/* All buffers good. */
|
|
|
|
buflock.unlock();
|
2012-08-18 11:02:54 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Source is now streaming */
|
|
|
|
source->SourceType = AL_STREAMING;
|
|
|
|
|
|
|
|
if(!(BufferList=source->queue))
|
|
|
|
source->queue = BufferListStart;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALbufferlistitem *next;
|
2019-07-31 09:20:53 -07:00
|
|
|
while((next=BufferList->mNext.load(std::memory_order_relaxed)) != nullptr)
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferList = next;
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList->mNext.store(BufferListStart, std::memory_order_release);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2012-08-18 11:02:54 -07:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2012-08-18 11:02:54 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2012-08-20 15:57:27 -07:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
2012-08-20 15:57:27 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(nb < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Queueing %d buffer layers", nb);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(nb == 0) return;
|
2016-07-07 19:48:21 -07:00
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *source{LookupSource(context.get(),src)};
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(!source))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src);
|
2016-07-07 19:48:21 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Can't queue on a Static Source */
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(source->SourceType == AL_STATIC))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src);
|
2017-02-24 01:47:34 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Check for a valid Buffer, for its frequency and format */
|
2019-08-01 19:44:09 -07:00
|
|
|
ALCdevice *device{context->mDevice.get()};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbuffer *BufferFmt{nullptr};
|
|
|
|
ALbufferlistitem *BufferList{source->queue};
|
|
|
|
while(BufferList)
|
2012-08-20 15:57:27 -07:00
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++)
|
|
|
|
BufferFmt = (*BufferList)[i];
|
2018-11-22 12:02:02 -08:00
|
|
|
if(BufferFmt) break;
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList = BufferList->mNext.load(std::memory_order_relaxed);
|
2012-08-20 15:57:27 -07:00
|
|
|
}
|
|
|
|
|
2018-11-26 22:06:53 -08:00
|
|
|
std::unique_lock<std::mutex> buflock{device->BufferLock};
|
2019-06-06 00:37:00 -07:00
|
|
|
auto BufferListStart = static_cast<ALbufferlistitem*>(al_calloc(alignof(void*),
|
2019-02-11 11:14:34 -08:00
|
|
|
ALbufferlistitem::Sizeof(nb)));
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferList = BufferListStart;
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList->mNext.store(nullptr, std::memory_order_relaxed);
|
|
|
|
BufferList->mMaxSamples = 0;
|
|
|
|
BufferList->mNumBuffers = 0;
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
for(ALsizei i{0};i < nb;i++)
|
|
|
|
{
|
|
|
|
ALbuffer *buffer{nullptr};
|
|
|
|
if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr)
|
2017-02-27 15:35:15 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]);
|
2018-11-22 12:02:02 -08:00
|
|
|
goto buffer_error;
|
2017-02-27 15:35:15 -08:00
|
|
|
}
|
2017-02-24 01:47:34 -08:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList->mBuffers[BufferList->mNumBuffers++] = buffer;
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!buffer) continue;
|
2017-12-15 22:59:51 -08:00
|
|
|
|
2019-08-01 13:28:53 -07:00
|
|
|
IncrementRef(buffer->ref);
|
2017-12-15 22:59:51 -08:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList->mMaxSamples = maxu(BufferList->mMaxSamples, buffer->SampleLen);
|
2014-05-14 03:40:01 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
|
2017-04-18 00:58:33 -07:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Queueing non-persistently mapped buffer %u",
|
|
|
|
buffer->id);
|
2018-11-22 12:02:02 -08:00
|
|
|
goto buffer_error;
|
2017-04-18 00:58:33 -07:00
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
if(BufferFmt == nullptr)
|
|
|
|
BufferFmt = buffer;
|
|
|
|
else if(BufferFmt->Frequency != buffer->Frequency ||
|
2018-12-24 19:29:01 -08:00
|
|
|
BufferFmt->mFmtChannels != buffer->mFmtChannels ||
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferFmt->OriginalType != buffer->OriginalType)
|
2017-04-18 00:58:33 -07:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format");
|
2014-03-04 22:44:30 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
buffer_error:
|
|
|
|
/* A buffer failed (invalid ID or format), so unlock and release
|
|
|
|
* each buffer we had. */
|
|
|
|
while(BufferListStart)
|
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
ALbufferlistitem *next{BufferListStart->mNext.load(std::memory_order_relaxed)};
|
|
|
|
std::for_each(BufferListStart->begin(), BufferListStart->end(),
|
|
|
|
[](ALbuffer *buffer) -> void
|
2019-08-01 13:28:53 -07:00
|
|
|
{ if(buffer) DecrementRef(buffer->ref); });
|
2018-11-22 12:02:02 -08:00
|
|
|
al_free(BufferListStart);
|
|
|
|
BufferListStart = next;
|
|
|
|
}
|
|
|
|
return;
|
2017-04-18 00:58:33 -07:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
/* All buffers good. */
|
|
|
|
buflock.unlock();
|
2015-09-22 08:48:26 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Source is now streaming */
|
|
|
|
source->SourceType = AL_STREAMING;
|
|
|
|
|
|
|
|
if(!(BufferList=source->queue))
|
|
|
|
source->queue = BufferListStart;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALbufferlistitem *next;
|
2019-07-31 09:20:53 -07:00
|
|
|
while((next=BufferList->mNext.load(std::memory_order_relaxed)) != nullptr)
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferList = next;
|
2019-07-31 09:20:53 -07:00
|
|
|
BufferList->mNext.store(BufferListStart, std::memory_order_release);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
|
2019-04-10 17:47:13 -07:00
|
|
|
START_API_FUNC
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if(UNLIKELY(!context)) return;
|
|
|
|
|
|
|
|
if(nb < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing %d buffers", nb);
|
2018-11-22 12:02:02 -08:00
|
|
|
if(nb == 0) return;
|
|
|
|
|
2019-07-30 09:05:54 -07:00
|
|
|
std::lock_guard<std::mutex> _{context->mSourceLock};
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource *source{LookupSource(context.get(),src)};
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(!source))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(source->Looping))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing from looping source %u", src);
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(source->SourceType != AL_STREAMING))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing from a non-streaming source %u",
|
|
|
|
src);
|
2018-11-22 12:02:02 -08:00
|
|
|
|
|
|
|
/* Make sure enough buffers have been processed to unqueue. */
|
|
|
|
ALbufferlistitem *BufferList{source->queue};
|
|
|
|
ALvoice *voice{GetSourceVoice(source, context.get())};
|
|
|
|
ALbufferlistitem *Current{nullptr};
|
|
|
|
if(voice)
|
2019-03-10 16:29:06 -07:00
|
|
|
Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
else if(source->state == AL_INITIAL)
|
|
|
|
Current = BufferList;
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(BufferList == Current))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers");
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
ALuint i{BufferList->mNumBuffers};
|
|
|
|
while(i < static_cast<ALuint>(nb))
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
/* If the next bufferlist to check is NULL or is the current one, it's
|
|
|
|
* trying to unqueue pending buffers.
|
|
|
|
*/
|
2019-07-31 09:20:53 -07:00
|
|
|
ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)};
|
2018-12-02 15:29:26 -08:00
|
|
|
if(UNLIKELY(!next) || UNLIKELY(next == Current))
|
2019-07-30 21:32:05 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers");
|
2018-11-22 12:02:02 -08:00
|
|
|
BufferList = next;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-31 09:20:53 -07:00
|
|
|
i += BufferList->mNumBuffers;
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
while(nb > 0)
|
2010-01-12 02:22:38 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbufferlistitem *head{source->queue};
|
2019-07-31 09:20:53 -07:00
|
|
|
ALbufferlistitem *next{head->mNext.load(std::memory_order_relaxed)};
|
|
|
|
for(i = 0;i < head->mNumBuffers && nb > 0;i++,nb--)
|
2010-01-12 02:22:38 -08:00
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
ALbuffer *buffer{(*head)[i]};
|
2018-11-22 12:02:02 -08:00
|
|
|
if(!buffer)
|
|
|
|
*(buffers++) = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*(buffers++) = buffer->id;
|
2019-08-01 13:28:53 -07:00
|
|
|
DecrementRef(buffer->ref);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
|
|
|
}
|
2019-07-31 09:20:53 -07:00
|
|
|
if(i < head->mNumBuffers)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
|
|
|
/* This head has some buffers left over, so move them to the front
|
|
|
|
* and update the sample and buffer count.
|
|
|
|
*/
|
2019-07-31 09:20:53 -07:00
|
|
|
ALuint max_length{0};
|
|
|
|
ALuint j{0};
|
|
|
|
while(i < head->mNumBuffers)
|
2018-11-22 12:02:02 -08:00
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
ALbuffer *buffer{(*head)[i++]};
|
|
|
|
if(buffer) max_length = maxu(max_length, buffer->SampleLen);
|
|
|
|
head->mBuffers[j++] = buffer;
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2019-07-31 09:20:53 -07:00
|
|
|
head->mMaxSamples = max_length;
|
|
|
|
head->mNumBuffers = j;
|
2018-11-22 12:02:02 -08:00
|
|
|
break;
|
2010-01-12 02:22:38 -08:00
|
|
|
}
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
/* Otherwise, free this item and set the source queue head to the next
|
|
|
|
* one.
|
|
|
|
*/
|
|
|
|
al_free(head);
|
|
|
|
source->queue = next;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:47:13 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource::ALsource(ALsizei num_sends)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
InnerAngle = 360.0f;
|
|
|
|
OuterAngle = 360.0f;
|
|
|
|
Pitch = 1.0f;
|
|
|
|
Position[0] = 0.0f;
|
|
|
|
Position[1] = 0.0f;
|
|
|
|
Position[2] = 0.0f;
|
|
|
|
Velocity[0] = 0.0f;
|
|
|
|
Velocity[1] = 0.0f;
|
|
|
|
Velocity[2] = 0.0f;
|
|
|
|
Direction[0] = 0.0f;
|
|
|
|
Direction[1] = 0.0f;
|
|
|
|
Direction[2] = 0.0f;
|
2018-12-26 22:27:34 -08:00
|
|
|
OrientAt[0] = 0.0f;
|
|
|
|
OrientAt[1] = 0.0f;
|
|
|
|
OrientAt[2] = -1.0f;
|
|
|
|
OrientUp[0] = 0.0f;
|
|
|
|
OrientUp[1] = 1.0f;
|
|
|
|
OrientUp[2] = 0.0f;
|
2018-11-22 12:02:02 -08:00
|
|
|
RefDistance = 1.0f;
|
2018-12-26 22:27:34 -08:00
|
|
|
MaxDistance = std::numeric_limits<float>::max();
|
2018-11-22 12:02:02 -08:00
|
|
|
RolloffFactor = 1.0f;
|
|
|
|
Gain = 1.0f;
|
|
|
|
MinGain = 0.0f;
|
|
|
|
MaxGain = 1.0f;
|
|
|
|
OuterGain = 0.0f;
|
|
|
|
OuterGainHF = 1.0f;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
DryGainHFAuto = AL_TRUE;
|
|
|
|
WetGainAuto = AL_TRUE;
|
|
|
|
WetGainHFAuto = AL_TRUE;
|
|
|
|
AirAbsorptionFactor = 0.0f;
|
|
|
|
RoomRolloffFactor = 0.0f;
|
|
|
|
DopplerFactor = 1.0f;
|
|
|
|
HeadRelative = AL_FALSE;
|
|
|
|
Looping = AL_FALSE;
|
|
|
|
mDistanceModel = DistanceModel::Default;
|
2018-12-24 19:29:01 -08:00
|
|
|
mResampler = ResamplerDefault;
|
2018-11-22 12:02:02 -08:00
|
|
|
DirectChannels = AL_FALSE;
|
2018-12-24 19:29:01 -08:00
|
|
|
mSpatialize = SpatializeAuto;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-12-22 16:01:14 -08:00
|
|
|
StereoPan[0] = Deg2Rad( 30.0f);
|
|
|
|
StereoPan[1] = Deg2Rad(-30.0f);
|
2010-05-11 11:06:48 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
Radius = 0.0f;
|
2010-05-11 11:06:48 -07:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
Direct.Gain = 1.0f;
|
|
|
|
Direct.GainHF = 1.0f;
|
|
|
|
Direct.HFReference = LOWPASSFREQREF;
|
|
|
|
Direct.GainLF = 1.0f;
|
|
|
|
Direct.LFReference = HIGHPASSFREQREF;
|
|
|
|
Send.resize(num_sends);
|
|
|
|
for(auto &send : Send)
|
|
|
|
{
|
|
|
|
send.Slot = nullptr;
|
|
|
|
send.Gain = 1.0f;
|
|
|
|
send.GainHF = 1.0f;
|
|
|
|
send.HFReference = LOWPASSFREQREF;
|
|
|
|
send.GainLF = 1.0f;
|
|
|
|
send.LFReference = HIGHPASSFREQREF;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2019-02-04 21:28:37 -08:00
|
|
|
PropsClean.test_and_set(std::memory_order_relaxed);
|
2018-11-22 12:02:02 -08:00
|
|
|
}
|
2008-01-16 13:27:15 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
ALsource::~ALsource()
|
2018-01-27 13:02:17 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
ALbufferlistitem *BufferList{queue};
|
|
|
|
while(BufferList != nullptr)
|
2018-01-27 13:02:17 -08:00
|
|
|
{
|
2019-07-31 09:20:53 -07:00
|
|
|
ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)};
|
|
|
|
std::for_each(BufferList->begin(), BufferList->end(),
|
|
|
|
[](ALbuffer *buffer) -> void
|
2019-08-01 13:28:53 -07:00
|
|
|
{ if(buffer) DecrementRef(buffer->ref); });
|
2018-11-22 12:02:02 -08:00
|
|
|
al_free(BufferList);
|
|
|
|
BufferList = next;
|
|
|
|
}
|
|
|
|
queue = nullptr;
|
2018-11-18 02:15:31 -08:00
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
std::for_each(Send.begin(), Send.end(),
|
|
|
|
[](ALsource::SendData &send) -> void
|
2018-01-27 13:02:17 -08:00
|
|
|
{
|
2018-11-22 12:02:02 -08:00
|
|
|
if(send.Slot)
|
2019-08-01 13:28:53 -07:00
|
|
|
DecrementRef(send.Slot->ref);
|
2018-11-22 12:02:02 -08:00
|
|
|
send.Slot = nullptr;
|
2018-01-27 13:02:17 -08:00
|
|
|
}
|
2018-11-22 12:02:02 -08:00
|
|
|
);
|
2018-01-27 13:02:17 -08:00
|
|
|
}
|
|
|
|
|
2018-11-22 12:02:02 -08:00
|
|
|
void UpdateAllSourceProps(ALCcontext *context)
|
2018-01-27 13:02:17 -08:00
|
|
|
{
|
2019-07-30 09:05:54 -07:00
|
|
|
auto voices_end = context->mVoices->begin() +
|
|
|
|
context->mVoiceCount.load(std::memory_order_relaxed);
|
|
|
|
std::for_each(context->mVoices->begin(), voices_end,
|
2019-06-09 18:13:54 -07:00
|
|
|
[context](ALvoice &voice) -> void
|
2018-11-23 16:16:31 -08:00
|
|
|
{
|
2019-06-09 18:13:54 -07:00
|
|
|
ALuint sid{voice.mSourceID.load(std::memory_order_acquire)};
|
2018-11-29 22:49:01 -08:00
|
|
|
ALsource *source = sid ? LookupSource(context, sid) : nullptr;
|
2018-11-23 16:16:31 -08:00
|
|
|
if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel))
|
2019-06-09 18:13:54 -07:00
|
|
|
UpdateSourceProps(source, &voice, context);
|
2018-11-23 16:16:31 -08:00
|
|
|
}
|
|
|
|
);
|
2018-01-27 13:02:17 -08:00
|
|
|
}
|
|
|
|
|
2018-11-25 08:42:43 -08:00
|
|
|
SourceSubList::~SourceSubList()
|
2008-01-16 13:27:15 -08:00
|
|
|
{
|
2019-02-11 12:16:58 -08:00
|
|
|
uint64_t usemask{~FreeMask};
|
2018-11-25 08:42:43 -08:00
|
|
|
while(usemask)
|
2008-01-16 13:27:15 -08:00
|
|
|
{
|
2018-11-25 08:42:43 -08:00
|
|
|
ALsizei idx{CTZ64(usemask)};
|
2019-06-05 17:25:08 -07:00
|
|
|
al::destroy_at(Sources+idx);
|
2019-01-07 04:06:40 -08:00
|
|
|
usemask &= ~(1_u64 << idx);
|
2008-01-16 13:27:15 -08:00
|
|
|
}
|
2018-11-25 08:42:43 -08:00
|
|
|
FreeMask = ~usemask;
|
|
|
|
al_free(Sources);
|
|
|
|
Sources = nullptr;
|
2008-01-16 13:27:15 -08:00
|
|
|
}
|