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"
|
|
|
|
|
2007-11-13 18:02:18 -08:00
|
|
|
#include <stdlib.h>
|
2015-10-14 03:23:19 -07:00
|
|
|
#include <limits.h>
|
2007-11-13 18:02:18 -08:00
|
|
|
#include <math.h>
|
|
|
|
#include <float.h>
|
2012-08-20 12:22:00 -07:00
|
|
|
|
2007-11-13 18:02:18 -08:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
2012-08-20 12:22:00 -07:00
|
|
|
#include "alMain.h"
|
2007-11-13 18:02:18 -08:00
|
|
|
#include "alError.h"
|
|
|
|
#include "alSource.h"
|
2007-12-31 01:09:57 -08:00
|
|
|
#include "alBuffer.h"
|
|
|
|
#include "alThunk.h"
|
2008-01-16 14:01:24 -08:00
|
|
|
#include "alAuxEffectSlot.h"
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2015-09-21 05:52:01 -07:00
|
|
|
#include "backends/base.h"
|
|
|
|
|
2014-05-11 03:52:22 -07:00
|
|
|
#include "threads.h"
|
2016-03-29 00:44:58 -07:00
|
|
|
#include "almalloc.h"
|
2014-05-11 03:52:22 -07:00
|
|
|
|
2010-11-28 17:37:14 -08:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
extern inline void LockSourcesRead(ALCcontext *context);
|
|
|
|
extern inline void UnlockSourcesRead(ALCcontext *context);
|
|
|
|
extern inline void LockSourcesWrite(ALCcontext *context);
|
|
|
|
extern inline void UnlockSourcesWrite(ALCcontext *context);
|
2013-11-04 13:44:46 -08:00
|
|
|
extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
|
|
|
|
extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
|
|
|
|
|
2010-03-26 00:41:27 -07:00
|
|
|
static ALvoid InitSourceParams(ALsource *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
|
|
|
static ALvoid DeinitSource(ALsource *source);
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALint64 GetSourceSampleOffset(ALsource *Source);
|
|
|
|
static ALdouble GetSourceSecOffset(ALsource *Source);
|
2016-04-25 02:22:54 -07:00
|
|
|
static ALdouble GetSourceOffset(ALsource *Source, ALenum name);
|
2015-10-13 03:01:34 -07:00
|
|
|
static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
typedef enum SourceProp {
|
|
|
|
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,
|
2012-12-05 09:22:38 -08:00
|
|
|
|
|
|
|
/* ALC_EXT_EFX */
|
2015-09-22 08:48:26 -07:00
|
|
|
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,
|
2012-12-05 09:22:38 -08:00
|
|
|
|
2012-12-05 13:48:33 -08:00
|
|
|
/* AL_SOFT_direct_channels */
|
2015-09-22 08:48:26 -07:00
|
|
|
srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
|
2012-12-05 13:48:33 -08:00
|
|
|
|
|
|
|
/* AL_EXT_source_distance_model */
|
2015-09-22 08:48:26 -07:00
|
|
|
srcDistanceModel = AL_DISTANCE_MODEL,
|
2012-12-05 13:48:33 -08:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
|
|
|
|
srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
|
|
|
|
srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
|
2014-05-25 16:16:55 -07:00
|
|
|
|
2012-12-05 09:22:38 -08:00
|
|
|
/* AL_SOFT_source_latency */
|
2015-09-22 08:48:26 -07:00
|
|
|
srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
|
|
|
|
srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
|
2014-10-31 22:43:13 -07:00
|
|
|
|
2016-03-25 14:40:44 -07:00
|
|
|
/* AL_EXT_STEREO_ANGLES */
|
|
|
|
srcAngles = AL_STEREO_ANGLES,
|
|
|
|
|
2016-04-25 00:30:47 -07:00
|
|
|
/* AL_EXT_SOURCE_RADIUS */
|
|
|
|
srcRadius = AL_SOURCE_RADIUS,
|
|
|
|
|
2014-10-31 22:43:13 -07:00
|
|
|
/* AL_EXT_BFORMAT */
|
2015-09-22 08:48:26 -07:00
|
|
|
srcOrientation = AL_ORIENTATION,
|
|
|
|
} SourceProp;
|
2012-12-05 09:55:05 -08:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
|
|
|
|
static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
|
|
|
|
static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
|
|
|
|
static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
|
|
|
|
static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
|
2012-08-20 14:16:58 -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
|
|
|
static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context)
|
|
|
|
{
|
|
|
|
return (source->state == AL_PLAYING || source->state == AL_PAUSED) &&
|
|
|
|
!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
|
|
|
|
}
|
|
|
|
|
2012-12-05 20:51:25 -08:00
|
|
|
static ALint FloatValsByProp(ALenum prop)
|
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
if(prop != (ALenum)((SourceProp)prop))
|
2012-12-05 20:51:25 -08:00
|
|
|
return 0;
|
2015-09-22 08:48:26 -07:00
|
|
|
switch((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:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
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:
|
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:
|
|
|
|
break; /* i64 only */
|
2012-12-05 20:51:25 -08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static ALint DoubleValsByProp(ALenum prop)
|
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
if(prop != (ALenum)((SourceProp)prop))
|
2012-12-05 20:51:25 -08:00
|
|
|
return 0;
|
2015-09-22 08:48:26 -07:00
|
|
|
switch((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:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2012-12-05 20:51:25 -08:00
|
|
|
return 1;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SEC_OFFSET_LATENCY_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:
|
|
|
|
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
|
|
|
static ALint IntValsByProp(ALenum prop)
|
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
if(prop != (ALenum)((SourceProp)prop))
|
2012-12-05 19:58:01 -08:00
|
|
|
return 0;
|
2015-09-22 08:48:26 -07:00
|
|
|
switch((SourceProp)prop)
|
2012-12-05 19:58:01 -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_BUFFER:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2012-12-05 19:58:01 -08:00
|
|
|
return 1;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2012-12-05 19:58:01 -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_SAMPLE_OFFSET_LATENCY_SOFT:
|
2012-12-05 19:58:01 -08:00
|
|
|
break; /* i64 only */
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
break; /* Double only */
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
break; /* Float/double only */
|
2012-12-05 19:58:01 -08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static ALint Int64ValsByProp(ALenum prop)
|
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
if(prop != (ALenum)((SourceProp)prop))
|
2012-12-05 19:58:01 -08:00
|
|
|
return 0;
|
2015-09-22 08:48:26 -07:00
|
|
|
switch((SourceProp)prop)
|
2012-12-05 19:58:01 -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_BUFFER:
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2012-12-05 19:58:01 -08:00
|
|
|
return 1;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
2012-12-05 19:58:01 -08:00
|
|
|
return 2;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2012-12-05 19:58:01 -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_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
break; /* Double only */
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
break; /* Float/double only */
|
2012-12-05 19:58:01 -08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
#define CHECKVAL(x) do { \
|
|
|
|
if(!(x)) \
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
|
2012-08-28 22:16:55 -07:00
|
|
|
} while(0)
|
|
|
|
|
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
|
|
|
#define DO_UPDATEPROPS() do { \
|
|
|
|
if(SourceShouldUpdate(Source, Context)) \
|
2016-05-17 20:02:46 -07:00
|
|
|
UpdateSourceProps(Source, device->NumAuxSends, 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
|
|
|
} while(0)
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
|
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
|
|
|
ALCdevice *device = Context->Device;
|
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_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
/* Query only */
|
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
|
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_PITCH:
|
|
|
|
CHECKVAL(*values >= 0.0f);
|
|
|
|
|
|
|
|
Source->Pitch = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
|
|
|
|
|
|
|
|
Source->InnerAngle = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
|
|
|
|
|
|
|
|
Source->OuterAngle = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_GAIN:
|
|
|
|
CHECKVAL(*values >= 0.0f);
|
|
|
|
|
|
|
|
Source->Gain = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
CHECKVAL(*values >= 0.0f);
|
|
|
|
|
|
|
|
Source->MaxDistance = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
CHECKVAL(*values >= 0.0f);
|
|
|
|
|
|
|
|
Source->RollOffFactor = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
CHECKVAL(*values >= 0.0f);
|
|
|
|
|
|
|
|
Source->RefDistance = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_MIN_GAIN:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
|
|
|
|
|
|
|
|
Source->MinGain = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_MAX_GAIN:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
|
|
|
|
|
|
|
|
Source->MaxGain = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
|
|
|
|
|
|
|
|
Source->OuterGain = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
|
|
|
|
|
|
|
|
Source->OuterGainHF = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
|
|
|
|
|
|
|
|
Source->AirAbsorptionFactor = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
|
|
|
|
|
|
|
|
Source->RoomRolloffFactor = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
|
|
|
|
|
|
|
|
Source->DopplerFactor = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
CHECKVAL(*values >= 0.0f);
|
|
|
|
|
2012-12-05 09:22:38 -08:00
|
|
|
Source->OffsetType = prop;
|
2012-08-28 22:16:55 -07:00
|
|
|
Source->Offset = *values;
|
|
|
|
|
|
|
|
if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
|
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
|
|
|
!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
|
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
|
|
|
LockContext(Context);
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteLock(&Source->queue_lock);
|
2012-08-28 22:16:55 -07:00
|
|
|
if(ApplyOffset(Source) == AL_FALSE)
|
|
|
|
{
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteUnlock(&Source->queue_lock);
|
2012-08-28 22:16:55 -07:00
|
|
|
UnlockContext(Context);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteUnlock(&Source->queue_lock);
|
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
|
|
|
UnlockContext(Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
|
|
|
CHECKVAL(*values >= 0.0f && isfinite(*values));
|
|
|
|
|
|
|
|
Source->Radius = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2016-04-25 00:30:47 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
|
|
|
|
|
|
|
|
Source->StereoPan[0] = values[0];
|
|
|
|
Source->StereoPan[1] = values[1];
|
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
|
|
|
DO_UPDATEPROPS();
|
2016-03-25 14:40:44 -07:00
|
|
|
return AL_TRUE;
|
|
|
|
|
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
|
|
|
|
|
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];
|
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_VELOCITY:
|
|
|
|
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
|
|
|
|
|
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];
|
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DIRECTION:
|
|
|
|
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
|
|
|
|
|
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];
|
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2014-10-31 22:43:13 -07:00
|
|
|
case AL_ORIENTATION:
|
|
|
|
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
|
|
|
|
isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
|
|
|
|
|
|
|
|
Source->Orientation[0][0] = values[0];
|
|
|
|
Source->Orientation[0][1] = values[1];
|
|
|
|
Source->Orientation[0][2] = values[2];
|
|
|
|
Source->Orientation[1][0] = values[3];
|
|
|
|
Source->Orientation[1][1] = values[4];
|
|
|
|
Source->Orientation[1][2] = values[5];
|
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
|
|
|
DO_UPDATEPROPS();
|
2014-10-31 22:43:13 -07:00
|
|
|
return AL_TRUE;
|
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:
|
2012-12-05 09:22:38 -08:00
|
|
|
ival = (ALint)values[0];
|
2015-09-22 08:48:26 -07:00
|
|
|
return SetSourceiv(Source, Context, prop, &ival);
|
2012-12-05 09:22:38 -08:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_BUFFERS_QUEUED:
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
2012-12-05 09:22:38 -08:00
|
|
|
ival = (ALint)((ALuint)values[0]);
|
2015-09-22 08:48:26 -07:00
|
|
|
return SetSourceiv(Source, Context, prop, &ival);
|
|
|
|
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
|
|
|
break;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:22:38 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
|
2012-08-28 22:16:55 -07:00
|
|
|
{
|
|
|
|
ALCdevice *device = Context->Device;
|
|
|
|
ALbuffer *buffer = NULL;
|
|
|
|
ALfilter *filter = NULL;
|
|
|
|
ALeffectslot *slot = NULL;
|
|
|
|
ALbufferlistitem *oldlist;
|
2014-07-31 07:20:36 -07:00
|
|
|
ALbufferlistitem *newlist;
|
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:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
|
|
|
/* Query only */
|
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
|
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
|
|
|
|
|
|
|
|
Source->HeadRelative = (ALboolean)*values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_LOOPING:
|
|
|
|
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
|
|
|
|
|
|
|
|
Source->Looping = (ALboolean)*values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_BUFFER:
|
2016-05-10 23:42:44 -07:00
|
|
|
LockBuffersRead(device);
|
|
|
|
if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
|
|
|
|
{
|
|
|
|
UnlockBuffersRead(device);
|
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
|
|
|
|
}
|
2012-08-28 22:16:55 -07:00
|
|
|
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteLock(&Source->queue_lock);
|
2012-08-28 22:16:55 -07:00
|
|
|
if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
|
|
|
|
{
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteUnlock(&Source->queue_lock);
|
2016-05-10 23:42:44 -07:00
|
|
|
UnlockBuffersRead(device);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if(buffer != NULL)
|
|
|
|
{
|
|
|
|
/* Add the selected buffer to a one-item queue */
|
2014-07-31 07:20:36 -07:00
|
|
|
newlist = malloc(sizeof(ALbufferlistitem));
|
|
|
|
newlist->buffer = buffer;
|
|
|
|
newlist->next = NULL;
|
2012-08-28 22:16:55 -07:00
|
|
|
IncrementRef(&buffer->ref);
|
|
|
|
|
2014-05-10 03:33:41 -07:00
|
|
|
/* Source is now Static */
|
|
|
|
Source->SourceType = AL_STATIC;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
ReadLock(&buffer->lock);
|
|
|
|
Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
|
|
|
|
Source->SampleSize = BytesFromFmt(buffer->FmtType);
|
|
|
|
ReadUnlock(&buffer->lock);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Source is now Undetermined */
|
|
|
|
Source->SourceType = AL_UNDETERMINED;
|
2014-07-31 07:20:36 -07:00
|
|
|
newlist = NULL;
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2014-07-31 07:20:36 -07:00
|
|
|
oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
|
|
|
|
ATOMIC_STORE(&Source->current_buffer, newlist);
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteUnlock(&Source->queue_lock);
|
2016-05-10 23:42:44 -07:00
|
|
|
UnlockBuffersRead(device);
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
/* Delete all elements in the previous queue */
|
|
|
|
while(oldlist != NULL)
|
|
|
|
{
|
|
|
|
ALbufferlistitem *temp = oldlist;
|
|
|
|
oldlist = temp->next;
|
|
|
|
|
|
|
|
if(temp->buffer)
|
|
|
|
DecrementRef(&temp->buffer->ref);
|
|
|
|
free(temp);
|
|
|
|
}
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
CHECKVAL(*values >= 0);
|
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
Source->OffsetType = prop;
|
2012-08-28 22:16:55 -07:00
|
|
|
Source->Offset = *values;
|
|
|
|
|
|
|
|
if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
|
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
|
|
|
!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
|
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
|
|
|
LockContext(Context);
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteLock(&Source->queue_lock);
|
2012-08-28 22:16:55 -07:00
|
|
|
if(ApplyOffset(Source) == AL_FALSE)
|
|
|
|
{
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteUnlock(&Source->queue_lock);
|
2012-08-28 22:16:55 -07:00
|
|
|
UnlockContext(Context);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteUnlock(&Source->queue_lock);
|
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
|
|
|
UnlockContext(Context);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-12-05 09:55:05 -08:00
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
case AL_DIRECT_FILTER:
|
2016-05-12 23:12:11 -07:00
|
|
|
LockFiltersRead(device);
|
|
|
|
if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
|
|
|
|
{
|
|
|
|
UnlockFiltersRead(device);
|
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
|
|
|
|
}
|
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
|
|
|
}
|
2016-05-12 23:12:11 -07:00
|
|
|
UnlockFiltersRead(device);
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
|
|
|
|
|
|
|
|
Source->DryGainHFAuto = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
|
|
|
|
|
|
|
|
Source->WetGainAuto = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
|
|
|
|
|
|
|
|
Source->WetGainHFAuto = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
|
|
|
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
|
|
|
|
|
|
|
|
Source->DirectChannels = *values;
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
case AL_DISTANCE_MODEL:
|
|
|
|
CHECKVAL(*values == AL_NONE ||
|
|
|
|
*values == AL_INVERSE_DISTANCE ||
|
|
|
|
*values == AL_INVERSE_DISTANCE_CLAMPED ||
|
|
|
|
*values == AL_LINEAR_DISTANCE ||
|
|
|
|
*values == AL_LINEAR_DISTANCE_CLAMPED ||
|
|
|
|
*values == AL_EXPONENT_DISTANCE ||
|
|
|
|
*values == AL_EXPONENT_DISTANCE_CLAMPED);
|
|
|
|
|
|
|
|
Source->DistanceModel = *values;
|
|
|
|
if(Context->SourceDistanceModel)
|
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
|
|
|
DO_UPDATEPROPS();
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-28 22:16:55 -07:00
|
|
|
|
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2016-05-12 23:12:11 -07:00
|
|
|
LockFiltersRead(device);
|
2012-08-28 22:16:55 -07:00
|
|
|
if(!((ALuint)values[1] < device->NumAuxSends &&
|
|
|
|
(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
|
|
|
|
(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
|
|
|
|
{
|
2016-05-12 23:12:11 -07:00
|
|
|
UnlockFiltersRead(device);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
|
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
|
|
|
}
|
2016-05-12 23:12:11 -07:00
|
|
|
UnlockFiltersRead(device);
|
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
|
|
|
|
|
|
|
if(slot != Source->Send[values[1]].Slot &&
|
|
|
|
(Source->state == AL_PLAYING || Source->state == AL_PAUSED))
|
|
|
|
{
|
|
|
|
/* Add refcount on the new slot, and release the previous slot */
|
|
|
|
if(slot) IncrementRef(&slot->ref);
|
|
|
|
slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
|
|
|
|
if(slot) DecrementRef(&slot->ref);
|
|
|
|
/* We must force an update if the auxiliary slot changed on a
|
|
|
|
* playing source, in case the slot is about to be deleted.
|
|
|
|
*/
|
2016-05-17 20:02:46 -07:00
|
|
|
UpdateSourceProps(Source, device->NumAuxSends, 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
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(slot) IncrementRef(&slot->ref);
|
|
|
|
slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
|
|
|
|
if(slot) DecrementRef(&slot->ref);
|
|
|
|
DO_UPDATEPROPS();
|
|
|
|
}
|
|
|
|
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_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:
|
2012-08-28 22:16:55 -07:00
|
|
|
fvals[0] = (ALfloat)*values;
|
2012-12-05 09:55:05 -08:00
|
|
|
return SetSourcefv(Source, Context, (int)prop, fvals);
|
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:
|
|
|
|
fvals[0] = (ALfloat)values[0];
|
|
|
|
fvals[1] = (ALfloat)values[1];
|
|
|
|
fvals[2] = (ALfloat)values[2];
|
2012-12-05 09:55:05 -08:00
|
|
|
return SetSourcefv(Source, Context, (int)prop, fvals);
|
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:
|
|
|
|
fvals[0] = (ALfloat)values[0];
|
|
|
|
fvals[1] = (ALfloat)values[1];
|
|
|
|
fvals[2] = (ALfloat)values[2];
|
|
|
|
fvals[3] = (ALfloat)values[3];
|
|
|
|
fvals[4] = (ALfloat)values[4];
|
|
|
|
fvals[5] = (ALfloat)values[5];
|
|
|
|
return SetSourcefv(Source, Context, (int)prop, fvals);
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
|
|
|
case AL_SEC_OFFSET_LATENCY_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);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
|
2012-10-14 01:36:46 -07:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, 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:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2012-11-01 18:35:20 -07:00
|
|
|
/* Query only */
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
|
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:
|
|
|
|
CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
|
|
|
|
|
2012-10-25 14:46:27 -07:00
|
|
|
ivals[0] = (ALint)*values;
|
2012-12-05 09:55:05 -08:00
|
|
|
return SetSourceiv(Source, Context, (int)prop, ivals);
|
2012-10-14 01:36:46 -07:00
|
|
|
|
|
|
|
/* 1x uint */
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
CHECKVAL(*values <= UINT_MAX && *values >= 0);
|
|
|
|
|
|
|
|
ivals[0] = (ALuint)*values;
|
2012-12-05 09:55:05 -08:00
|
|
|
return SetSourceiv(Source, Context, (int)prop, ivals);
|
2012-10-14 01:36:46 -07:00
|
|
|
|
|
|
|
/* 3x uint */
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
|
|
|
CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
|
|
|
|
values[1] <= UINT_MAX && values[1] >= 0 &&
|
|
|
|
values[2] <= UINT_MAX && values[2] >= 0);
|
|
|
|
|
|
|
|
ivals[0] = (ALuint)values[0];
|
|
|
|
ivals[1] = (ALuint)values[1];
|
|
|
|
ivals[2] = (ALuint)values[2];
|
2012-12-05 09:55:05 -08:00
|
|
|
return SetSourceiv(Source, Context, (int)prop, ivals);
|
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:
|
2012-10-14 01:36:46 -07:00
|
|
|
fvals[0] = (ALfloat)*values;
|
2012-12-05 09:55:05 -08:00
|
|
|
return SetSourcefv(Source, Context, (int)prop, fvals);
|
2012-10-14 01:36:46 -07:00
|
|
|
|
|
|
|
/* 3x float */
|
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
|
|
|
fvals[0] = (ALfloat)values[0];
|
|
|
|
fvals[1] = (ALfloat)values[1];
|
|
|
|
fvals[2] = (ALfloat)values[2];
|
2012-12-05 09:55:05 -08:00
|
|
|
return SetSourcefv(Source, Context, (int)prop, fvals);
|
2014-10-31 22:43:13 -07:00
|
|
|
|
|
|
|
/* 6x float */
|
|
|
|
case AL_ORIENTATION:
|
|
|
|
fvals[0] = (ALfloat)values[0];
|
|
|
|
fvals[1] = (ALfloat)values[1];
|
|
|
|
fvals[2] = (ALfloat)values[2];
|
|
|
|
fvals[3] = (ALfloat)values[3];
|
|
|
|
fvals[4] = (ALfloat)values[4];
|
|
|
|
fvals[5] = (ALfloat)values[5];
|
|
|
|
return SetSourcefv(Source, Context, (int)prop, fvals);
|
2015-09-22 08:48:26 -07:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET_LATENCY_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);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
|
2012-08-28 22:16:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef CHECKVAL
|
|
|
|
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
2015-09-21 05:52:01 -07:00
|
|
|
ALCdevice *device = Context->Device;
|
2014-05-25 16:16:55 -07:00
|
|
|
ALbufferlistitem *BufferList;
|
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:
|
|
|
|
*values = Source->Gain;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-12-05 08:27:02 -08:00
|
|
|
|
2012-10-21 11:36:27 -07:00
|
|
|
case AL_PITCH:
|
|
|
|
*values = Source->Pitch;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-10-21 11:36:27 -07:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_MAX_DISTANCE:
|
|
|
|
*values = Source->MaxDistance;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
*values = Source->RollOffFactor;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
*values = Source->RefDistance;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_CONE_INNER_ANGLE:
|
|
|
|
*values = Source->InnerAngle;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_ANGLE:
|
|
|
|
*values = Source->OuterAngle;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2012-10-21 11:36:27 -07:00
|
|
|
case AL_MIN_GAIN:
|
|
|
|
*values = Source->MinGain;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-10-21 11:36:27 -07:00
|
|
|
|
|
|
|
case AL_MAX_GAIN:
|
|
|
|
*values = Source->MaxGain;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-10-21 11:36:27 -07:00
|
|
|
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
*values = Source->OuterGain;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_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:
|
|
|
|
LockContext(Context);
|
2016-04-25 02:22:54 -07:00
|
|
|
*values = GetSourceOffset(Source, prop);
|
2014-08-03 00:56:58 -07:00
|
|
|
UnlockContext(Context);
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2012-09-14 09:02:36 -07:00
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
*values = Source->OuterGainHF;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-09-14 09:02:36 -07:00
|
|
|
|
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
*values = Source->AirAbsorptionFactor;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-09-14 09:02:36 -07:00
|
|
|
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
*values = Source->RoomRolloffFactor;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-09-14 09:02:36 -07:00
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_DOPPLER_FACTOR:
|
|
|
|
*values = Source->DopplerFactor;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2014-05-25 16:16:55 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2014-07-31 07:20:36 -07:00
|
|
|
if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
|
2014-05-25 16:16:55 -07:00
|
|
|
*values = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALint length = 0;
|
|
|
|
ALsizei freq = 1;
|
|
|
|
do {
|
|
|
|
ALbuffer *buffer = BufferList->buffer;
|
|
|
|
if(buffer && buffer->SampleLen > 0)
|
|
|
|
{
|
|
|
|
freq = buffer->Frequency;
|
|
|
|
length += buffer->SampleLen;
|
|
|
|
}
|
|
|
|
} while((BufferList=BufferList->next) != NULL);
|
|
|
|
*values = (ALdouble)length / (ALdouble)freq;
|
|
|
|
}
|
|
|
|
ReadUnlock(&Source->queue_lock);
|
|
|
|
return AL_TRUE;
|
|
|
|
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
|
|
|
*values = Source->Radius;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 15:57:27 -07:00
|
|
|
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
values[0] = Source->StereoPan[0];
|
|
|
|
values[1] = Source->StereoPan[1];
|
|
|
|
return AL_TRUE;
|
|
|
|
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
LockContext(Context);
|
|
|
|
values[0] = GetSourceSecOffset(Source);
|
|
|
|
values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
|
|
|
|
1000000000.0;
|
|
|
|
UnlockContext(Context);
|
|
|
|
return AL_TRUE;
|
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_POSITION:
|
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
|
|
|
values[0] = Source->Position[0];
|
|
|
|
values[1] = Source->Position[1];
|
|
|
|
values[2] = Source->Position[2];
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_VELOCITY:
|
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
|
|
|
values[0] = Source->Velocity[0];
|
|
|
|
values[1] = Source->Velocity[1];
|
|
|
|
values[2] = Source->Velocity[2];
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_DIRECTION:
|
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
|
|
|
values[0] = Source->Direction[0];
|
|
|
|
values[1] = Source->Direction[1];
|
|
|
|
values[2] = Source->Direction[2];
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2014-10-31 22:43:13 -07:00
|
|
|
case AL_ORIENTATION:
|
|
|
|
values[0] = Source->Orientation[0][0];
|
|
|
|
values[1] = Source->Orientation[0][1];
|
|
|
|
values[2] = Source->Orientation[0][2];
|
|
|
|
values[3] = Source->Orientation[1][0];
|
|
|
|
values[4] = Source->Orientation[1][1];
|
|
|
|
values[5] = Source->Orientation[1][2];
|
|
|
|
return AL_TRUE;
|
|
|
|
|
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:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_DISTANCE_MODEL:
|
2013-10-07 09:54:35 -07:00
|
|
|
if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
|
2012-12-05 09:22:38 -08:00
|
|
|
*values = (ALdouble)ivals[0];
|
|
|
|
return err;
|
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:
|
|
|
|
break;
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:22:38 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
|
|
|
ALbufferlistitem *BufferList;
|
2014-10-31 22:43:13 -07:00
|
|
|
ALdouble dvals[6];
|
2013-10-07 09:54:35 -07:00
|
|
|
ALboolean err;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
switch(prop)
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
|
|
|
case AL_SOURCE_RELATIVE:
|
|
|
|
*values = Source->HeadRelative;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_LOOPING:
|
|
|
|
*values = Source->Looping;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_BUFFER:
|
2014-05-10 05:07:13 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
|
|
|
|
ATOMIC_LOAD(&Source->current_buffer);
|
2014-05-10 03:21:40 -07:00
|
|
|
*values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
|
2014-05-10 05:07:13 -07:00
|
|
|
ReadUnlock(&Source->queue_lock);
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_SOURCE_STATE:
|
|
|
|
*values = Source->state;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
2014-05-25 16:16:55 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2014-07-31 07:20:36 -07:00
|
|
|
if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
|
2014-05-25 16:16:55 -07:00
|
|
|
*values = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALint length = 0;
|
|
|
|
do {
|
|
|
|
ALbuffer *buffer = BufferList->buffer;
|
|
|
|
if(buffer && buffer->SampleLen > 0)
|
|
|
|
{
|
|
|
|
ALuint byte_align, sample_align;
|
|
|
|
if(buffer->OriginalType == UserFmtIMA4)
|
|
|
|
{
|
|
|
|
ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
|
|
|
|
byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
|
|
|
|
sample_align = buffer->OriginalAlign;
|
|
|
|
}
|
|
|
|
else if(buffer->OriginalType == UserFmtMSADPCM)
|
|
|
|
{
|
|
|
|
ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
|
|
|
|
byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
|
|
|
|
sample_align = buffer->OriginalAlign;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALsizei align = buffer->OriginalAlign;
|
|
|
|
byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
|
|
|
|
sample_align = buffer->OriginalAlign;
|
|
|
|
}
|
|
|
|
|
|
|
|
length += buffer->SampleLen / sample_align * byte_align;
|
|
|
|
}
|
|
|
|
} while((BufferList=BufferList->next) != NULL);
|
|
|
|
*values = length;
|
|
|
|
}
|
|
|
|
ReadUnlock(&Source->queue_lock);
|
|
|
|
return AL_TRUE;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
2014-05-25 16:16:55 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2014-07-31 07:20:36 -07:00
|
|
|
if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
|
2014-05-25 16:16:55 -07:00
|
|
|
*values = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALint length = 0;
|
|
|
|
do {
|
|
|
|
ALbuffer *buffer = BufferList->buffer;
|
|
|
|
if(buffer) length += buffer->SampleLen;
|
|
|
|
} while((BufferList=BufferList->next) != NULL);
|
|
|
|
*values = length;
|
|
|
|
}
|
|
|
|
ReadUnlock(&Source->queue_lock);
|
|
|
|
return AL_TRUE;
|
|
|
|
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_BUFFERS_QUEUED:
|
2014-05-10 05:07:13 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2014-07-31 07:20:36 -07:00
|
|
|
if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
|
2014-05-10 03:33:41 -07:00
|
|
|
*values = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALsizei count = 0;
|
|
|
|
do {
|
|
|
|
++count;
|
|
|
|
} while((BufferList=BufferList->next) != NULL);
|
|
|
|
*values = count;
|
|
|
|
}
|
2014-05-10 05:07:13 -07:00
|
|
|
ReadUnlock(&Source->queue_lock);
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_BUFFERS_PROCESSED:
|
2014-05-10 05:07:13 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2012-08-20 14:16:58 -07:00
|
|
|
if(Source->Looping || Source->SourceType != AL_STREAMING)
|
|
|
|
{
|
|
|
|
/* Buffers on a looping source are in a perpetual state of
|
|
|
|
* PENDING, so don't report any as PROCESSED */
|
|
|
|
*values = 0;
|
|
|
|
}
|
|
|
|
else
|
2014-05-10 03:21:40 -07:00
|
|
|
{
|
2014-07-31 07:20:36 -07:00
|
|
|
const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
|
|
|
|
const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
|
2014-05-10 03:21:40 -07:00
|
|
|
ALsizei played = 0;
|
2014-07-31 07:20:36 -07:00
|
|
|
while(BufferList && BufferList != Current)
|
2014-05-10 03:21:40 -07:00
|
|
|
{
|
|
|
|
played++;
|
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
|
|
|
*values = played;
|
|
|
|
}
|
2014-05-10 05:07:13 -07:00
|
|
|
ReadUnlock(&Source->queue_lock);
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_SOURCE_TYPE:
|
|
|
|
*values = Source->SourceType;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_DIRECT_FILTER_GAINHF_AUTO:
|
|
|
|
*values = Source->DryGainHFAuto;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
|
|
|
|
*values = Source->WetGainAuto;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
|
|
|
|
*values = Source->WetGainHFAuto;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_DIRECT_CHANNELS_SOFT:
|
|
|
|
*values = Source->DirectChannels;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
case AL_DISTANCE_MODEL:
|
|
|
|
*values = Source->DistanceModel;
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 1x float/double */
|
2012-08-20 14:16:58 -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:
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
|
2012-12-05 09:55:05 -08:00
|
|
|
*values = (ALint)dvals[0];
|
|
|
|
return err;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 3x float/double */
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
|
2012-12-05 09:55:05 -08:00
|
|
|
{
|
|
|
|
values[0] = (ALint)dvals[0];
|
|
|
|
values[1] = (ALint)dvals[1];
|
|
|
|
values[2] = (ALint)dvals[2];
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 6x float/double */
|
2014-10-31 22:43:13 -07:00
|
|
|
case AL_ORIENTATION:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
|
2014-10-31 22:43:13 -07:00
|
|
|
{
|
|
|
|
values[0] = (ALint)dvals[0];
|
|
|
|
values[1] = (ALint)dvals[1];
|
|
|
|
values[2] = (ALint)dvals[2];
|
|
|
|
values[3] = (ALint)dvals[3];
|
|
|
|
values[4] = (ALint)dvals[4];
|
|
|
|
values[5] = (ALint)dvals[5];
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
|
|
|
break; /* i64 only */
|
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
break; /* Double only */
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
break; /* Float/double only */
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_DIRECT_FILTER:
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
|
|
|
break; /* ??? */
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
2015-09-21 05:52:01 -07:00
|
|
|
ALCdevice *device = Context->Device;
|
2014-10-31 22:43:13 -07:00
|
|
|
ALdouble dvals[6];
|
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:55:05 -08:00
|
|
|
switch(prop)
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
|
|
|
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
|
|
|
|
LockContext(Context);
|
2015-09-22 08:48:26 -07:00
|
|
|
values[0] = GetSourceSampleOffset(Source);
|
2015-09-21 05:52:01 -07:00
|
|
|
values[1] = V0(device->Backend,getLatency)();
|
2012-08-20 14:16:58 -07:00
|
|
|
UnlockContext(Context);
|
2013-10-07 09:54:35 -07:00
|
|
|
return AL_TRUE;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 1x float/double */
|
2012-08-20 14:16:58 -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:
|
|
|
|
case AL_REFERENCE_DISTANCE:
|
|
|
|
case AL_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAIN:
|
|
|
|
case AL_MAX_DISTANCE:
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_SEC_OFFSET:
|
|
|
|
case AL_SAMPLE_OFFSET:
|
|
|
|
case AL_BYTE_OFFSET:
|
|
|
|
case AL_DOPPLER_FACTOR:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_AIR_ABSORPTION_FACTOR:
|
|
|
|
case AL_ROOM_ROLLOFF_FACTOR:
|
|
|
|
case AL_CONE_OUTER_GAINHF:
|
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2016-04-25 00:30:47 -07:00
|
|
|
case AL_SOURCE_RADIUS:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
|
2012-12-05 09:55:05 -08:00
|
|
|
*values = (ALint64)dvals[0];
|
|
|
|
return err;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 3x float/double */
|
2012-08-20 14:16:58 -07:00
|
|
|
case AL_POSITION:
|
|
|
|
case AL_VELOCITY:
|
|
|
|
case AL_DIRECTION:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
|
2012-12-05 09:55:05 -08:00
|
|
|
{
|
|
|
|
values[0] = (ALint64)dvals[0];
|
|
|
|
values[1] = (ALint64)dvals[1];
|
|
|
|
values[2] = (ALint64)dvals[2];
|
|
|
|
}
|
|
|
|
return err;
|
2012-08-20 14:16:58 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 6x float/double */
|
2014-10-31 22:43:13 -07:00
|
|
|
case AL_ORIENTATION:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
|
2014-10-31 22:43:13 -07:00
|
|
|
{
|
|
|
|
values[0] = (ALint64)dvals[0];
|
|
|
|
values[1] = (ALint64)dvals[1];
|
|
|
|
values[2] = (ALint64)dvals[2];
|
|
|
|
values[3] = (ALint64)dvals[3];
|
|
|
|
values[4] = (ALint64)dvals[4];
|
|
|
|
values[5] = (ALint64)dvals[5];
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
|
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:
|
2015-09-22 08:48:26 -07:00
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
2012-08-20 14:16:58 -07:00
|
|
|
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:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
|
2012-12-07 18:43:13 -08:00
|
|
|
*values = ivals[0];
|
|
|
|
return err;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 1x uint */
|
|
|
|
case AL_BUFFER:
|
|
|
|
case AL_DIRECT_FILTER:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
|
2014-07-05 02:01:36 -07:00
|
|
|
*values = (ALuint)ivals[0];
|
2012-12-07 18:43:13 -08:00
|
|
|
return err;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* 3x uint */
|
|
|
|
case AL_AUXILIARY_SEND_FILTER:
|
2015-10-16 10:52:10 -07:00
|
|
|
if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
|
2012-12-07 18:43:13 -08:00
|
|
|
{
|
2014-07-05 02:01:36 -07:00
|
|
|
values[0] = (ALuint)ivals[0];
|
|
|
|
values[1] = (ALuint)ivals[1];
|
|
|
|
values[2] = (ALuint)ivals[2];
|
2012-12-07 18:43:13 -08:00
|
|
|
}
|
2012-12-05 09:55:05 -08:00
|
|
|
return err;
|
2015-09-22 08:48:26 -07:00
|
|
|
|
|
|
|
case AL_SEC_OFFSET_LATENCY_SOFT:
|
|
|
|
break; /* Double only */
|
2016-03-25 14:40:44 -07:00
|
|
|
case AL_STEREO_ANGLES:
|
|
|
|
break; /* Float/double only */
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2012-12-05 09:55:05 -08:00
|
|
|
ERR("Unexpected property: 0x%04x\n", prop);
|
2013-10-07 09:54:35 -07:00
|
|
|
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
|
2012-08-20 14:16:58 -07:00
|
|
|
}
|
|
|
|
|
2010-05-01 19:59:41 -07:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsizei cur = 0;
|
|
|
|
ALenum err;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
for(cur = 0;cur < n;cur++)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALsource *source = al_calloc(16, sizeof(ALsource));
|
|
|
|
if(!source)
|
2009-08-16 15:09:36 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
alDeleteSources(cur, sources);
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
|
|
|
|
}
|
|
|
|
InitSourceParams(source);
|
2010-09-21 15:12:08 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
err = NewThunkEntry(&source->id);
|
|
|
|
if(err == AL_NO_ERROR)
|
|
|
|
err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
|
|
|
|
if(err != AL_NO_ERROR)
|
|
|
|
{
|
|
|
|
FreeThunkEntry(source->id);
|
|
|
|
memset(source, 0, sizeof(ALsource));
|
|
|
|
al_free(source);
|
2010-09-21 15:12:08 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
alDeleteSources(cur, sources);
|
|
|
|
SET_ERROR_AND_GOTO(context, err, done);
|
2009-08-16 15:09:36 -07:00
|
|
|
}
|
2013-10-07 09:24:50 -07:00
|
|
|
|
|
|
|
sources[cur] = source->id;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
done:
|
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsource *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
|
|
|
ALsizei i;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesWrite(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
2012-04-23 19:46:05 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
/* Check that all Sources are valid */
|
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
|
|
|
if(LookupSource(context, sources[i]) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
}
|
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
2014-08-21 03:24:48 -07:00
|
|
|
ALvoice *voice, *voice_end;
|
2012-04-23 19:46:05 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
if((Source=RemoveSource(context, sources[i])) == NULL)
|
|
|
|
continue;
|
|
|
|
FreeThunkEntry(Source->id);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
LockContext(context);
|
2014-08-21 03:24:48 -07:00
|
|
|
voice = context->Voices;
|
|
|
|
voice_end = voice + context->VoiceCount;
|
|
|
|
while(voice != voice_end)
|
2009-08-16 15:09:36 -07:00
|
|
|
{
|
2014-08-20 21:35:18 -07:00
|
|
|
ALsource *old = Source;
|
2014-08-21 03:24:48 -07:00
|
|
|
if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
|
2013-10-07 09:24:50 -07:00
|
|
|
break;
|
2014-08-21 03:24:48 -07:00
|
|
|
voice++;
|
2013-10-07 09:24:50 -07:00
|
|
|
}
|
|
|
|
UnlockContext(context);
|
2010-11-06 14:07:30 -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
|
|
|
DeinitSource(Source);
|
2013-10-07 09:24:50 -07:00
|
|
|
|
|
|
|
memset(Source, 0, sizeof(*Source));
|
|
|
|
al_free(Source);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
done:
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesWrite(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALboolean ret;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return AL_FALSE;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
return ret;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext *Context;
|
2011-09-11 00:47:31 -07:00
|
|
|
ALsource *Source;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(FloatValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
SetSourcefv(Source, Context, param, &value);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext *Context;
|
2011-09-11 00:47:31 -07:00
|
|
|
ALsource *Source;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(FloatValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-12-05 20:51:25 -08:00
|
|
|
ALfloat fvals[3] = { value1, value2, value3 };
|
|
|
|
SetSourcefv(Source, Context, param, fvals);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext *Context;
|
2012-08-28 22:16:55 -07:00
|
|
|
ALsource *Source;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-08-28 22:16:55 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(FloatValsByProp(param) > 0))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
SetSourcefv(Source, Context, param, values);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-13 00:56:39 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-10-13 00:56:39 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(DoubleValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2012-10-13 00:56:39 -07:00
|
|
|
{
|
2012-12-05 20:51:25 -08:00
|
|
|
ALfloat fval = (ALfloat)value;
|
|
|
|
SetSourcefv(Source, Context, param, &fval);
|
2012-10-13 00:56:39 -07:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2012-10-13 00:56:39 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-10-13 00:56:39 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(DoubleValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2012-10-13 00:56:39 -07:00
|
|
|
{
|
2012-12-05 20:51:25 -08:00
|
|
|
ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
|
|
|
|
SetSourcefv(Source, Context, param, fvals);
|
2012-10-13 00:56:39 -07:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2012-10-13 00:56:39 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
2012-12-05 20:51:25 -08:00
|
|
|
ALint count;
|
2012-10-13 00:56:39 -07:00
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-10-13 00:56:39 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2015-09-21 09:42:51 -07:00
|
|
|
else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
|
2012-12-05 20:51:25 -08:00
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2012-10-13 00:56:39 -07:00
|
|
|
{
|
2015-09-21 09:42:51 -07:00
|
|
|
ALfloat fvals[6];
|
2012-12-05 20:51:25 -08:00
|
|
|
ALint i;
|
2012-11-01 18:35:20 -07:00
|
|
|
|
2012-12-05 20:51:25 -08:00
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
fvals[i] = (ALfloat)values[i];
|
|
|
|
SetSourcefv(Source, Context, param, fvals);
|
2012-10-13 00:56:39 -07:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2012-10-13 00:56:39 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-23 19:46:05 -07:00
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
2011-06-16 09:14:41 -07:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(IntValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
SetSourceiv(Source, Context, param, &value);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-08-28 22:16:55 -07:00
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
2011-06-16 09:14:41 -07:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(IntValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-12-05 19:58:01 -08:00
|
|
|
ALint ivals[3] = { value1, value2, value3 };
|
|
|
|
SetSourceiv(Source, Context, param, ivals);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext *Context;
|
2012-08-28 22:16:55 -07:00
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2007-11-13 18:02:18 -08: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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(IntValsByProp(param) > 0))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
SetSourceiv(Source, Context, param, values);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-13 00:56:39 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-10-13 00:56:39 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(Int64ValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
SetSourcei64v(Source, Context, param, &value);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2012-10-13 00:56:39 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-10-13 00:56:39 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(Int64ValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2012-10-13 00:56:39 -07:00
|
|
|
{
|
2012-12-05 19:58:01 -08:00
|
|
|
ALint64SOFT i64vals[3] = { value1, value2, value3 };
|
|
|
|
SetSourcei64v(Source, Context, param, i64vals);
|
2012-10-13 00:56:39 -07:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2012-10-13 00:56:39 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
WriteLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-10-13 00:56:39 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(Int64ValsByProp(param) > 0))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
SetSourcei64v(Source, Context, param, values);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
WriteUnlock(&Context->PropLock);
|
2012-10-13 00:56:39 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-21 05:53:27 -07:00
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!value)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(FloatValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-12-05 20:51:25 -08:00
|
|
|
ALdouble dval;
|
2013-12-09 13:04:16 -08:00
|
|
|
if(GetSourcedv(Source, Context, param, &dval))
|
2012-12-05 20:51:25 -08:00
|
|
|
*value = (ALfloat)dval;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext *Context;
|
2011-09-11 00:47:31 -07:00
|
|
|
ALsource *Source;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!(value1 && value2 && value3))
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(FloatValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-12-05 20:51:25 -08:00
|
|
|
ALdouble dvals[3];
|
2013-12-09 13:04:16 -08:00
|
|
|
if(GetSourcedv(Source, Context, param, dvals))
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
|
|
|
*value1 = (ALfloat)dvals[0];
|
|
|
|
*value2 = (ALfloat)dvals[1];
|
|
|
|
*value3 = (ALfloat)dvals[2];
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-21 05:53:27 -07:00
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
2012-12-05 20:51:25 -08:00
|
|
|
ALint count;
|
2011-06-16 09:14:41 -07:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2015-09-21 09:42:51 -07:00
|
|
|
else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
|
2012-12-05 20:51:25 -08:00
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2015-09-21 09:42:51 -07:00
|
|
|
ALdouble dvals[6];
|
2013-12-09 13:04:16 -08:00
|
|
|
if(GetSourcedv(Source, Context, param, dvals))
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
|
|
|
ALint i;
|
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
values[i] = (ALfloat)dvals[i];
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-20 15:26:35 -07:00
|
|
|
AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!value)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(DoubleValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
GetSourcedv(Source, Context, param, value);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2012-08-20 15:26:35 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!(value1 && value2 && value3))
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(DoubleValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2012-08-20 15:26:35 -07:00
|
|
|
{
|
2012-12-05 20:51:25 -08:00
|
|
|
ALdouble dvals[3];
|
2013-12-09 13:04:16 -08:00
|
|
|
if(GetSourcedv(Source, Context, param, dvals))
|
2012-12-05 20:51:25 -08:00
|
|
|
{
|
|
|
|
*value1 = dvals[0];
|
|
|
|
*value2 = dvals[1];
|
|
|
|
*value3 = dvals[2];
|
|
|
|
}
|
2012-08-20 15:26:35 -07:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2012-08-20 15:26:35 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 20:51:25 -08:00
|
|
|
else if(!(DoubleValsByProp(param) > 0))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
GetSourcedv(Source, Context, param, values);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2012-08-20 15:26:35 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext *Context;
|
2010-03-26 00:41:27 -07:00
|
|
|
ALsource *Source;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!value)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(IntValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
GetSourceiv(Source, Context, param, value);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-21 05:53:27 -07:00
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!(value1 && value2 && value3))
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(IntValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-12-05 19:58:01 -08:00
|
|
|
ALint ivals[3];
|
2013-12-09 13:04:16 -08:00
|
|
|
if(GetSourceiv(Source, Context, param, ivals))
|
2012-12-05 19:58:01 -08:00
|
|
|
{
|
|
|
|
*value1 = ivals[0];
|
|
|
|
*value2 = ivals[1];
|
|
|
|
*value3 = ivals[2];
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-21 05:53:27 -07:00
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
2011-06-16 09:14:41 -07:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Context = GetContextRef();
|
|
|
|
if(!Context) return;
|
2009-08-16 15:09:36 -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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(IntValsByProp(param) > 0))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
GetSourceiv(Source, Context, param, values);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
ALCcontext_DecRef(Context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-20 14:50:43 -07:00
|
|
|
AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
|
2012-08-18 11:02:54 -07:00
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!value)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(Int64ValsByProp(param) == 1))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
GetSourcei64v(Source, Context, param, value);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2012-08-20 14:16:58 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
|
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!(value1 && value2 && value3))
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(Int64ValsByProp(param) == 3))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
2012-08-20 14:16:58 -07:00
|
|
|
{
|
2012-12-05 19:58:01 -08:00
|
|
|
ALint64 i64vals[3];
|
2013-12-09 13:04:16 -08:00
|
|
|
if(GetSourcei64v(Source, Context, param, i64vals))
|
2012-12-05 19:58:01 -08:00
|
|
|
{
|
|
|
|
*value1 = i64vals[0];
|
|
|
|
*value2 = i64vals[1];
|
|
|
|
*value3 = i64vals[2];
|
|
|
|
}
|
2012-08-18 11:02:54 -07:00
|
|
|
}
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2012-08-18 11:02:54 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
2012-08-20 12:22:00 -07:00
|
|
|
AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
|
2012-08-18 11:02:54 -07:00
|
|
|
{
|
|
|
|
ALCcontext *Context;
|
|
|
|
ALsource *Source;
|
|
|
|
|
|
|
|
Context = GetContextRef();
|
|
|
|
if(!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
|
|
|
ReadLock(&Context->PropLock);
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(Context);
|
2012-08-29 00:25:01 -07:00
|
|
|
if((Source=LookupSource(Context, source)) == NULL)
|
|
|
|
alSetError(Context, AL_INVALID_NAME);
|
|
|
|
else if(!values)
|
|
|
|
alSetError(Context, AL_INVALID_VALUE);
|
2012-12-05 19:58:01 -08:00
|
|
|
else if(!(Int64ValsByProp(param) > 0))
|
|
|
|
alSetError(Context, AL_INVALID_ENUM);
|
|
|
|
else
|
|
|
|
GetSourcei64v(Source, Context, param, values);
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(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
|
|
|
ReadUnlock(&Context->PropLock);
|
2012-08-18 11:02:54 -07:00
|
|
|
|
|
|
|
ALCcontext_DecRef(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
|
|
|
alSourcePlayv(1, &source);
|
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsource *source;
|
|
|
|
ALsizei i;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
for(i = 0;i < n;i++)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!LookupSource(context, sources[i]))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
LockContext(context);
|
2014-08-21 03:24:48 -07:00
|
|
|
while(n > context->MaxVoices-context->VoiceCount)
|
2013-10-07 09:24:50 -07:00
|
|
|
{
|
2014-08-21 03:24:48 -07:00
|
|
|
ALvoice *temp = NULL;
|
2013-10-07 09:24:50 -07:00
|
|
|
ALsizei newcount;
|
|
|
|
|
2014-08-21 03:24:48 -07:00
|
|
|
newcount = context->MaxVoices << 1;
|
2013-10-07 09:24:50 -07:00
|
|
|
if(newcount > 0)
|
2014-08-21 03:24:48 -07:00
|
|
|
temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!temp)
|
2010-06-06 00:17:50 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
UnlockContext(context);
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
|
2012-04-23 19:46:05 -07:00
|
|
|
}
|
2014-08-21 03:24:48 -07:00
|
|
|
memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
|
2010-06-06 00:17:50 -07:00
|
|
|
|
2014-08-21 03:24:48 -07:00
|
|
|
context->Voices = temp;
|
|
|
|
context->MaxVoices = newcount;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
|
|
|
source = LookupSource(context, 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
|
|
|
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
|
|
|
|
source->new_state = AL_PLAYING;
|
|
|
|
else
|
|
|
|
SetSourceState(source, context, AL_PLAYING);
|
2013-10-07 09:24:50 -07:00
|
|
|
}
|
|
|
|
UnlockContext(context);
|
|
|
|
|
|
|
|
done:
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
|
|
|
alSourcePausev(1, &source);
|
|
|
|
}
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsource *source;
|
|
|
|
ALsizei i;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
for(i = 0;i < n;i++)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!LookupSource(context, sources[i]))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
LockContext(context);
|
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
|
|
|
source = LookupSource(context, 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
|
|
|
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
|
|
|
|
source->new_state = AL_PAUSED;
|
|
|
|
else
|
|
|
|
SetSourceState(source, context, AL_PAUSED);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2013-10-07 09:24:50 -07:00
|
|
|
UnlockContext(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
done:
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
|
|
|
alSourceStopv(1, &source);
|
|
|
|
}
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsource *source;
|
|
|
|
ALsizei i;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
for(i = 0;i < n;i++)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!LookupSource(context, sources[i]))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
LockContext(context);
|
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
|
|
|
source = LookupSource(context, sources[i]);
|
|
|
|
source->new_state = AL_NONE;
|
|
|
|
SetSourceState(source, context, AL_STOPPED);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2013-10-07 09:24:50 -07:00
|
|
|
UnlockContext(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
done:
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
|
|
|
alSourceRewindv(1, &source);
|
|
|
|
}
|
2010-03-19 14:34:18 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsource *source;
|
|
|
|
ALsizei i;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(n >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
for(i = 0;i < n;i++)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!LookupSource(context, sources[i]))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
LockContext(context);
|
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
|
|
|
source = LookupSource(context, sources[i]);
|
|
|
|
source->new_state = AL_NONE;
|
|
|
|
SetSourceState(source, context, AL_INITIAL);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2013-10-07 09:24:50 -07:00
|
|
|
UnlockContext(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
done:
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALsource *source;
|
|
|
|
ALsizei i;
|
2014-05-10 08:55:28 -07:00
|
|
|
ALbufferlistitem *BufferListStart;
|
2010-03-24 02:23:00 -07:00
|
|
|
ALbufferlistitem *BufferList;
|
2013-10-07 09:24:50 -07:00
|
|
|
ALbuffer *BufferFmt = NULL;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-23 19:46:05 -07:00
|
|
|
if(nb == 0)
|
2007-11-13 18:02:18 -08:00
|
|
|
return;
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
device = context->Device;
|
2010-03-16 18:54:36 -07:00
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(nb >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
if((source=LookupSource(context, src)) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
2009-10-22 09:31:26 -07:00
|
|
|
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteLock(&source->queue_lock);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(source->SourceType == AL_STATIC)
|
|
|
|
{
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteUnlock(&source->queue_lock);
|
2013-10-07 09:24:50 -07:00
|
|
|
/* Can't queue on a Static Source */
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
/* Check for a valid Buffer, for its frequency and format */
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = ATOMIC_LOAD(&source->queue);
|
2013-10-07 09:24:50 -07:00
|
|
|
while(BufferList)
|
|
|
|
{
|
|
|
|
if(BufferList->buffer)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
BufferFmt = BufferList->buffer;
|
|
|
|
break;
|
2010-03-24 02:23:00 -07:00
|
|
|
}
|
2013-10-07 09:24:50 -07:00
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2016-05-10 23:42:44 -07:00
|
|
|
LockBuffersRead(device);
|
2014-05-10 08:55:28 -07:00
|
|
|
BufferListStart = NULL;
|
|
|
|
BufferList = NULL;
|
2013-10-07 09:24:50 -07:00
|
|
|
for(i = 0;i < nb;i++)
|
|
|
|
{
|
|
|
|
ALbuffer *buffer = NULL;
|
|
|
|
if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
|
|
|
|
{
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteUnlock(&source->queue_lock);
|
2014-05-10 08:55:28 -07:00
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
|
2013-10-07 09:24:50 -07:00
|
|
|
}
|
2012-04-23 19:46:05 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!BufferListStart)
|
2011-09-11 03:57:40 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
BufferListStart = malloc(sizeof(ALbufferlistitem));
|
|
|
|
BufferList = BufferListStart;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BufferList->next = malloc(sizeof(ALbufferlistitem));
|
2011-09-11 03:57:40 -07:00
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
2016-01-31 00:42:58 -08:00
|
|
|
BufferList->buffer = buffer;
|
|
|
|
BufferList->next = NULL;
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!buffer) continue;
|
2012-04-21 05:53:27 -07:00
|
|
|
|
2014-05-10 08:55:28 -07:00
|
|
|
/* Hold a read lock on each buffer being queued while checking all
|
|
|
|
* provided buffers. This is done so other threads don't see an extra
|
|
|
|
* reference on some buffers if this operation ends up failing. */
|
2013-10-07 09:24:50 -07:00
|
|
|
ReadLock(&buffer->lock);
|
2014-05-10 08:55:28 -07:00
|
|
|
IncrementRef(&buffer->ref);
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
if(BufferFmt == NULL)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
BufferFmt = buffer;
|
2010-09-26 01:15:27 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
|
|
|
|
source->SampleSize = BytesFromFmt(buffer->FmtType);
|
|
|
|
}
|
|
|
|
else if(BufferFmt->Frequency != buffer->Frequency ||
|
|
|
|
BufferFmt->OriginalChannels != buffer->OriginalChannels ||
|
|
|
|
BufferFmt->OriginalType != buffer->OriginalType)
|
|
|
|
{
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteUnlock(&source->queue_lock);
|
2014-05-10 08:55:28 -07:00
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
|
|
|
|
|
|
|
|
buffer_error:
|
|
|
|
/* A buffer failed (invalid ID or format), so unlock and release
|
|
|
|
* each buffer we had. */
|
2016-01-31 00:42:58 -08:00
|
|
|
while(BufferListStart)
|
2014-05-10 08:55:28 -07:00
|
|
|
{
|
2016-01-31 00:42:58 -08:00
|
|
|
ALbufferlistitem *next = BufferListStart->next;
|
|
|
|
if((buffer=BufferListStart->buffer) != NULL)
|
2014-05-10 08:55:28 -07:00
|
|
|
{
|
|
|
|
DecrementRef(&buffer->ref);
|
|
|
|
ReadUnlock(&buffer->lock);
|
|
|
|
}
|
2016-01-31 00:42:58 -08:00
|
|
|
free(BufferListStart);
|
|
|
|
BufferListStart = next;
|
2014-05-10 08:55:28 -07:00
|
|
|
}
|
2016-05-10 23:42:44 -07:00
|
|
|
UnlockBuffersRead(device);
|
2014-05-10 08:55:28 -07:00
|
|
|
goto done;
|
2010-03-24 02:23:00 -07:00
|
|
|
}
|
2014-05-10 08:55:28 -07:00
|
|
|
}
|
|
|
|
/* All buffers good, unlock them now. */
|
2016-01-31 00:42:58 -08:00
|
|
|
BufferList = BufferListStart;
|
2014-05-10 08:55:28 -07:00
|
|
|
while(BufferList != NULL)
|
|
|
|
{
|
|
|
|
ALbuffer *buffer = BufferList->buffer;
|
|
|
|
if(buffer) ReadUnlock(&buffer->lock);
|
2016-01-31 00:42:58 -08:00
|
|
|
BufferList = BufferList->next;
|
2013-10-07 09:24:50 -07:00
|
|
|
}
|
2016-05-10 23:42:44 -07:00
|
|
|
UnlockBuffersRead(device);
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
/* Source is now streaming */
|
|
|
|
source->SourceType = AL_STREAMING;
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = NULL;
|
|
|
|
if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
|
2013-10-07 09:24:50 -07:00
|
|
|
{
|
2014-05-11 03:11:35 -07:00
|
|
|
/* Queue head is not NULL, append to the end of the queue */
|
2013-10-07 09:24:50 -07:00
|
|
|
while(BufferList->next != NULL)
|
|
|
|
BufferList = BufferList->next;
|
|
|
|
BufferList->next = BufferListStart;
|
|
|
|
}
|
2016-01-31 00:42:58 -08:00
|
|
|
/* If the current buffer was at the end (NULL), put it at the start of the newly queued
|
|
|
|
* buffers.
|
|
|
|
*/
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = NULL;
|
|
|
|
ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteUnlock(&source->queue_lock);
|
2013-03-24 13:55:41 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
done:
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsource *source;
|
2014-05-11 03:11:35 -07:00
|
|
|
ALbufferlistitem *OldHead;
|
2016-01-31 00:42:58 -08:00
|
|
|
ALbufferlistitem *OldTail;
|
2014-07-31 07:20:36 -07:00
|
|
|
ALbufferlistitem *Current;
|
2016-01-31 00:42:58 -08:00
|
|
|
ALsizei i = 0;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-23 19:46:05 -07:00
|
|
|
if(nb == 0)
|
2007-11-13 18:02:18 -08:00
|
|
|
return;
|
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
|
|
|
|
2016-05-10 22:49:24 -07:00
|
|
|
LockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
if(!(nb >= 0))
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
|
|
|
|
if((source=LookupSource(context, src)) == NULL)
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteLock(&source->queue_lock);
|
|
|
|
/* Find the new buffer queue head */
|
2016-01-31 00:42:58 -08:00
|
|
|
OldTail = ATOMIC_LOAD(&source->queue);
|
2014-07-31 07:20:36 -07:00
|
|
|
Current = ATOMIC_LOAD(&source->current_buffer);
|
2016-01-31 00:42:58 -08:00
|
|
|
if(OldTail != Current)
|
2014-05-10 03:21:40 -07:00
|
|
|
{
|
2016-01-31 00:42:58 -08:00
|
|
|
for(i = 1;i < nb;i++)
|
|
|
|
{
|
|
|
|
ALbufferlistitem *next = OldTail->next;
|
|
|
|
if(!next || next == Current) break;
|
|
|
|
OldTail = next;
|
|
|
|
}
|
2014-05-10 03:21:40 -07:00
|
|
|
}
|
|
|
|
if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2014-05-10 05:07:13 -07:00
|
|
|
WriteUnlock(&source->queue_lock);
|
2013-10-07 09:24:50 -07:00
|
|
|
/* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
|
|
|
|
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2014-05-10 05:07:13 -07:00
|
|
|
/* Swap it, and cut the new head from the old. */
|
2016-01-31 00:42:58 -08:00
|
|
|
OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
|
|
|
|
if(OldTail->next)
|
2013-10-07 09:24:50 -07:00
|
|
|
{
|
2014-05-11 03:52:22 -07:00
|
|
|
ALCdevice *device = context->Device;
|
2014-05-14 02:47:07 -07:00
|
|
|
uint count;
|
2014-05-11 03:52:22 -07:00
|
|
|
|
2016-01-31 00:42:58 -08:00
|
|
|
/* Once the active mix (if any) is done, it's safe to cut the old tail
|
|
|
|
* from the new head.
|
|
|
|
*/
|
2014-05-14 02:47:07 -07:00
|
|
|
if(((count=ReadRef(&device->MixCount))&1) != 0)
|
2014-05-11 03:52:22 -07:00
|
|
|
{
|
2014-05-14 02:47:07 -07:00
|
|
|
while(count == ReadRef(&device->MixCount))
|
2014-05-11 03:52:22 -07:00
|
|
|
althrd_yield();
|
|
|
|
}
|
2014-07-31 07:20:36 -07:00
|
|
|
OldTail->next = NULL;
|
2014-05-10 05:07:13 -07:00
|
|
|
}
|
|
|
|
WriteUnlock(&source->queue_lock);
|
2009-08-16 15:09:36 -07:00
|
|
|
|
2014-05-11 03:11:35 -07:00
|
|
|
while(OldHead != NULL)
|
2014-05-10 05:07:13 -07:00
|
|
|
{
|
2014-05-11 03:11:35 -07:00
|
|
|
ALbufferlistitem *next = OldHead->next;
|
|
|
|
ALbuffer *buffer = OldHead->buffer;
|
2014-05-10 05:07:13 -07:00
|
|
|
|
2014-05-11 03:11:35 -07:00
|
|
|
if(!buffer)
|
|
|
|
*(buffers++) = 0;
|
2014-05-10 05:07:13 -07:00
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2014-05-11 03:11:35 -07:00
|
|
|
*(buffers++) = buffer->id;
|
|
|
|
DecrementRef(&buffer->ref);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2014-05-11 03:11:35 -07:00
|
|
|
free(OldHead);
|
|
|
|
OldHead = next;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2013-10-07 09:24:50 -07:00
|
|
|
done:
|
2016-05-10 22:49:24 -07:00
|
|
|
UnlockSourcesRead(context);
|
2013-10-07 09:24:50 -07:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-26 00:41:27 -07:00
|
|
|
static ALvoid InitSourceParams(ALsource *Source)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2011-08-31 02:18:16 -07:00
|
|
|
ALuint i;
|
|
|
|
|
2014-05-10 05:07:13 -07:00
|
|
|
RWLockInit(&Source->queue_lock);
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
Source->InnerAngle = 360.0f;
|
|
|
|
Source->OuterAngle = 360.0f;
|
|
|
|
Source->Pitch = 1.0f;
|
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] = 0.0f;
|
|
|
|
Source->Position[1] = 0.0f;
|
|
|
|
Source->Position[2] = 0.0f;
|
|
|
|
Source->Velocity[0] = 0.0f;
|
|
|
|
Source->Velocity[1] = 0.0f;
|
|
|
|
Source->Velocity[2] = 0.0f;
|
|
|
|
Source->Direction[0] = 0.0f;
|
|
|
|
Source->Direction[1] = 0.0f;
|
|
|
|
Source->Direction[2] = 0.0f;
|
2014-10-31 22:43:13 -07:00
|
|
|
Source->Orientation[0][0] = 0.0f;
|
|
|
|
Source->Orientation[0][1] = 0.0f;
|
|
|
|
Source->Orientation[0][2] = -1.0f;
|
|
|
|
Source->Orientation[1][0] = 0.0f;
|
|
|
|
Source->Orientation[1][1] = 1.0f;
|
|
|
|
Source->Orientation[1][2] = 0.0f;
|
2012-04-19 21:46:29 -07:00
|
|
|
Source->RefDistance = 1.0f;
|
|
|
|
Source->MaxDistance = FLT_MAX;
|
|
|
|
Source->RollOffFactor = 1.0f;
|
|
|
|
Source->Looping = AL_FALSE;
|
|
|
|
Source->Gain = 1.0f;
|
|
|
|
Source->MinGain = 0.0f;
|
|
|
|
Source->MaxGain = 1.0f;
|
|
|
|
Source->OuterGain = 0.0f;
|
2010-03-26 00:41:27 -07:00
|
|
|
Source->OuterGainHF = 1.0f;
|
|
|
|
|
|
|
|
Source->DryGainHFAuto = AL_TRUE;
|
|
|
|
Source->WetGainAuto = AL_TRUE;
|
|
|
|
Source->WetGainHFAuto = AL_TRUE;
|
|
|
|
Source->AirAbsorptionFactor = 0.0f;
|
|
|
|
Source->RoomRolloffFactor = 0.0f;
|
|
|
|
Source->DopplerFactor = 1.0f;
|
2012-02-09 23:35:17 -08:00
|
|
|
Source->DirectChannels = AL_FALSE;
|
2010-03-26 00:41:27 -07:00
|
|
|
|
2016-03-25 14:40:44 -07:00
|
|
|
Source->StereoPan[0] = DEG2RAD( 30.0f);
|
|
|
|
Source->StereoPan[1] = DEG2RAD(-30.0f);
|
|
|
|
|
2014-07-08 09:13:35 -07:00
|
|
|
Source->Radius = 0.0f;
|
|
|
|
|
2012-02-12 08:18:20 -08:00
|
|
|
Source->DistanceModel = DefaultDistanceModel;
|
2010-03-26 00:41:27 -07:00
|
|
|
|
2014-05-11 01:36:18 -07:00
|
|
|
Source->Direct.Gain = 1.0f;
|
|
|
|
Source->Direct.GainHF = 1.0f;
|
2014-05-11 10:09:52 -07:00
|
|
|
Source->Direct.HFReference = LOWPASSFREQREF;
|
2014-05-17 07:54:25 -07:00
|
|
|
Source->Direct.GainLF = 1.0f;
|
|
|
|
Source->Direct.LFReference = HIGHPASSFREQREF;
|
2011-08-31 02:18:16 -07:00
|
|
|
for(i = 0;i < MAX_SENDS;i++)
|
|
|
|
{
|
2012-04-27 00:45:42 -07:00
|
|
|
Source->Send[i].Gain = 1.0f;
|
|
|
|
Source->Send[i].GainHF = 1.0f;
|
2014-05-11 10:09:52 -07:00
|
|
|
Source->Send[i].HFReference = LOWPASSFREQREF;
|
2014-05-17 07:54:25 -07:00
|
|
|
Source->Send[i].GainLF = 1.0f;
|
|
|
|
Source->Send[i].LFReference = HIGHPASSFREQREF;
|
2011-08-31 02:18:16 -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->state = AL_INITIAL;
|
|
|
|
Source->new_state = AL_NONE;
|
|
|
|
Source->SourceType = AL_UNDETERMINED;
|
|
|
|
Source->OffsetType = AL_NONE;
|
|
|
|
Source->Offset = 0.0;
|
|
|
|
|
|
|
|
ATOMIC_INIT(&Source->queue, NULL);
|
|
|
|
ATOMIC_INIT(&Source->current_buffer, NULL);
|
|
|
|
|
|
|
|
ATOMIC_INIT(&Source->Update, NULL);
|
|
|
|
ATOMIC_INIT(&Source->FreeList, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ALvoid DeinitSource(ALsource *source)
|
|
|
|
{
|
|
|
|
ALbufferlistitem *BufferList;
|
|
|
|
struct ALsourceProps *props;
|
|
|
|
size_t count = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
props = ATOMIC_LOAD(&source->Update);
|
|
|
|
if(props) al_free(props);
|
|
|
|
|
|
|
|
props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
|
|
|
|
while(props)
|
|
|
|
{
|
|
|
|
struct ALsourceProps *next;
|
|
|
|
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
|
|
|
al_free(props);
|
|
|
|
props = next;
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
/* This is excessively spammy if it traces every source destruction, so
|
|
|
|
* just warn if it was unexpectedly large.
|
|
|
|
*/
|
|
|
|
if(count > 3)
|
|
|
|
WARN("Freed "SZFMT" Source property objects\n", count);
|
|
|
|
|
|
|
|
BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NULL);
|
|
|
|
while(BufferList != NULL)
|
|
|
|
{
|
|
|
|
ALbufferlistitem *next = BufferList->next;
|
|
|
|
if(BufferList->buffer != NULL)
|
|
|
|
DecrementRef(&BufferList->buffer->ref);
|
|
|
|
free(BufferList);
|
|
|
|
BufferList = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0;i < MAX_SENDS;++i)
|
|
|
|
{
|
|
|
|
if(source->Send[i].Slot)
|
|
|
|
DecrementRef(&source->Send[i].Slot->ref);
|
|
|
|
source->Send[i].Slot = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-17 20:02:46 -07:00
|
|
|
void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *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
|
|
|
{
|
|
|
|
struct ALsourceProps *props;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
/* Get an unused property container, or allocate a new one as needed. */
|
|
|
|
props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
|
|
|
|
if(!props)
|
|
|
|
props = al_calloc(16, sizeof(*props));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct ALsourceProps *next;
|
|
|
|
do {
|
|
|
|
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
|
|
|
|
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
|
|
|
|
&source->FreeList, &props, next, almemory_order_seq_cst,
|
|
|
|
almemory_order_consume) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy in current property values. */
|
|
|
|
ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
|
|
|
|
for(i = 0;i < 3;i++)
|
|
|
|
ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
|
|
|
|
for(i = 0;i < 3;i++)
|
|
|
|
ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
|
|
|
|
for(i = 0;i < 3;i++)
|
|
|
|
ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
|
|
|
|
for(i = 0;i < 2;i++)
|
|
|
|
{
|
|
|
|
size_t j;
|
|
|
|
for(j = 0;j < 3;j++)
|
|
|
|
ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
|
|
|
|
almemory_order_relaxed);
|
|
|
|
}
|
|
|
|
ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Looping, source->Looping, almemory_order_relaxed);
|
2016-05-17 20:02:46 -07:00
|
|
|
ATOMIC_STORE(&props->DistanceModel,
|
|
|
|
context->SourceDistanceModel ? source->DistanceModel : context->DistanceModel,
|
|
|
|
almemory_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
|
|
|
ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
|
|
|
|
|
|
|
|
ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
|
|
|
|
|
|
|
|
ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
|
|
|
|
|
|
|
|
ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
|
|
|
|
|
|
|
|
ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
|
|
|
|
|
|
|
|
ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
|
|
|
|
|
|
|
|
for(i = 0;i < num_sends;i++)
|
|
|
|
{
|
|
|
|
ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
|
|
|
|
almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
|
|
|
|
ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
|
|
|
|
almemory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the new container for updating internal parameters. */
|
|
|
|
props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
|
|
|
|
if(props)
|
|
|
|
{
|
|
|
|
/* If there was an unused update container, put it back in the
|
|
|
|
* freelist.
|
|
|
|
*/
|
|
|
|
struct ALsourceProps *first = ATOMIC_LOAD(&source->FreeList);
|
|
|
|
do {
|
|
|
|
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
|
|
|
|
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
|
|
|
|
&source->FreeList, &first, props) == 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateAllSourceProps(ALCcontext *context)
|
|
|
|
{
|
|
|
|
ALuint num_sends = context->Device->NumAuxSends;
|
2016-05-15 17:14:58 -07:00
|
|
|
uint updates;
|
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
|
|
|
ALsizei pos;
|
2016-05-15 17:14:58 -07:00
|
|
|
|
|
|
|
/* Tell the mixer to stop applying updates, then wait for any active
|
|
|
|
* updating to finish, before providing source updates.
|
|
|
|
*/
|
|
|
|
ATOMIC_STORE(&context->HoldUpdates, AL_TRUE);
|
|
|
|
while(((updates=ReadRef(&context->UpdateCount))&1) != 0)
|
|
|
|
althrd_yield();
|
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
|
|
|
for(pos = 0;pos < context->VoiceCount;pos++)
|
|
|
|
{
|
|
|
|
ALvoice *voice = &context->Voices[pos];
|
|
|
|
ALsource *source = voice->Source;
|
|
|
|
if(source != NULL && (source->state == AL_PLAYING ||
|
|
|
|
source->state == AL_PAUSED))
|
2016-05-17 20:02:46 -07:00
|
|
|
UpdateSourceProps(source, num_sends, 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
|
|
|
}
|
2016-05-15 17:14:58 -07:00
|
|
|
/* Now with all updates declared, let the mixer continue applying them so
|
|
|
|
* they all happen at once.
|
|
|
|
*/
|
|
|
|
ATOMIC_STORE(&context->HoldUpdates, AL_FALSE);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* SetSourceState
|
2011-08-20 06:31:10 -07:00
|
|
|
*
|
2012-04-21 05:53:27 -07:00
|
|
|
* Sets the source's new play state given its current state.
|
2011-08-20 06:31:10 -07:00
|
|
|
*/
|
|
|
|
ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
|
|
|
|
{
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteLock(&Source->queue_lock);
|
2011-08-20 06:31:10 -07:00
|
|
|
if(state == AL_PLAYING)
|
|
|
|
{
|
2014-03-23 16:11:21 -07:00
|
|
|
ALCdevice *device = Context->Device;
|
2011-08-20 06:31:10 -07:00
|
|
|
ALbufferlistitem *BufferList;
|
2015-10-15 07:29:25 -07:00
|
|
|
ALboolean discontinuity;
|
2014-08-21 03:24:48 -07:00
|
|
|
ALvoice *voice = NULL;
|
2014-08-20 21:35:18 -07:00
|
|
|
ALsizei i;
|
2011-08-20 06:31:10 -07:00
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* Check that there is a queue containing at least one valid, non zero
|
|
|
|
* length Buffer. */
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = ATOMIC_LOAD(&Source->queue);
|
2011-08-20 06:31:10 -07:00
|
|
|
while(BufferList)
|
|
|
|
{
|
2014-05-10 03:21:40 -07:00
|
|
|
ALbuffer *buffer;
|
|
|
|
if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
|
2011-08-20 06:31:10 -07:00
|
|
|
break;
|
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Source->state != AL_PAUSED)
|
|
|
|
{
|
|
|
|
Source->state = AL_PLAYING;
|
|
|
|
Source->position = 0;
|
|
|
|
Source->position_fraction = 0;
|
2014-07-31 07:20:36 -07:00
|
|
|
ATOMIC_STORE(&Source->current_buffer, BufferList);
|
2015-10-15 07:29:25 -07:00
|
|
|
discontinuity = AL_TRUE;
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
|
|
|
else
|
2015-10-15 07:29:25 -07:00
|
|
|
{
|
2011-08-20 06:31:10 -07:00
|
|
|
Source->state = AL_PLAYING;
|
2015-10-15 07:29:25 -07:00
|
|
|
discontinuity = AL_FALSE;
|
|
|
|
}
|
2011-08-20 06:31:10 -07:00
|
|
|
|
|
|
|
// Check if an Offset has been set
|
2016-05-09 16:34:54 -07:00
|
|
|
if(Source->OffsetType != AL_NONE)
|
2015-10-15 07:29:25 -07:00
|
|
|
{
|
2011-08-20 06:31:10 -07:00
|
|
|
ApplyOffset(Source);
|
2015-10-15 07:29:25 -07:00
|
|
|
/* discontinuity = AL_TRUE;??? */
|
|
|
|
}
|
2011-08-20 06:31:10 -07:00
|
|
|
|
2011-10-15 10:33:30 -07:00
|
|
|
/* If there's nothing to play, or device is disconnected, go right to
|
|
|
|
* stopped */
|
2014-03-23 16:11:21 -07:00
|
|
|
if(!BufferList || !device->Connected)
|
2014-05-10 05:07:13 -07:00
|
|
|
goto do_stop;
|
2011-10-15 10:33:30 -07:00
|
|
|
|
2014-08-21 02:27:56 -07:00
|
|
|
/* Make sure this source isn't already active, while looking for an
|
|
|
|
* unused active source slot to put it in. */
|
2014-08-21 03:24:48 -07:00
|
|
|
for(i = 0;i < Context->VoiceCount;i++)
|
2011-08-20 06:31:10 -07:00
|
|
|
{
|
2014-08-21 02:27:56 -07:00
|
|
|
ALsource *old = Source;
|
2014-08-21 03:24:48 -07:00
|
|
|
if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
|
2014-03-19 13:14:11 -07:00
|
|
|
{
|
2014-08-21 03:24:48 -07:00
|
|
|
if(voice == NULL)
|
2014-08-21 02:27:56 -07:00
|
|
|
{
|
2014-08-21 03:24:48 -07:00
|
|
|
voice = &Context->Voices[i];
|
|
|
|
voice->Source = Source;
|
2014-08-21 02:27:56 -07:00
|
|
|
}
|
2011-08-20 06:31:10 -07:00
|
|
|
break;
|
2014-03-19 13:14:11 -07:00
|
|
|
}
|
2014-08-21 02:27:56 -07:00
|
|
|
old = NULL;
|
2014-08-21 03:24:48 -07:00
|
|
|
if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
|
|
|
|
voice = &Context->Voices[i];
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
2014-08-21 03:24:48 -07:00
|
|
|
if(voice == NULL)
|
2014-03-18 19:56:25 -07:00
|
|
|
{
|
2014-08-21 03:24:48 -07:00
|
|
|
voice = &Context->Voices[Context->VoiceCount++];
|
|
|
|
voice->Source = Source;
|
2014-03-18 19:56:25 -07:00
|
|
|
}
|
2014-08-21 02:27:56 -07:00
|
|
|
|
2015-10-15 07:29:25 -07:00
|
|
|
/* Clear previous samples if playback is discontinuous. */
|
|
|
|
if(discontinuity)
|
|
|
|
memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
|
|
|
|
|
2016-02-14 01:22:01 -08:00
|
|
|
voice->Moving = AL_FALSE;
|
2014-11-23 10:49:54 -08:00
|
|
|
for(i = 0;i < MAX_INPUT_CHANNELS;i++)
|
|
|
|
{
|
|
|
|
ALsizei j;
|
|
|
|
for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
|
2015-02-09 05:54:14 -08:00
|
|
|
voice->Direct.Hrtf[i].State.History[j] = 0.0f;
|
2014-11-23 10:49:54 -08:00
|
|
|
for(j = 0;j < HRIR_LENGTH;j++)
|
|
|
|
{
|
2015-02-09 05:54:14 -08:00
|
|
|
voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
|
|
|
|
voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
|
2014-11-23 10:49:54 -08:00
|
|
|
}
|
|
|
|
}
|
2014-07-26 16:41:39 -07:00
|
|
|
|
2016-05-17 20:02:46 -07:00
|
|
|
UpdateSourceProps(Source, device->NumAuxSends, Context);
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
|
|
|
else if(state == AL_PAUSED)
|
|
|
|
{
|
|
|
|
if(Source->state == AL_PLAYING)
|
|
|
|
Source->state = AL_PAUSED;
|
|
|
|
}
|
|
|
|
else if(state == AL_STOPPED)
|
|
|
|
{
|
2014-05-10 05:07:13 -07:00
|
|
|
do_stop:
|
2011-08-20 06:31:10 -07:00
|
|
|
if(Source->state != AL_INITIAL)
|
|
|
|
{
|
|
|
|
Source->state = AL_STOPPED;
|
2014-07-31 07:20:36 -07:00
|
|
|
ATOMIC_STORE(&Source->current_buffer, NULL);
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
2016-05-09 16:34:54 -07:00
|
|
|
Source->OffsetType = AL_NONE;
|
|
|
|
Source->Offset = 0.0;
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
|
|
|
else if(state == AL_INITIAL)
|
|
|
|
{
|
|
|
|
if(Source->state != AL_INITIAL)
|
|
|
|
{
|
|
|
|
Source->state = AL_INITIAL;
|
|
|
|
Source->position = 0;
|
|
|
|
Source->position_fraction = 0;
|
2014-07-31 07:20:36 -07:00
|
|
|
ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
2016-05-09 16:34:54 -07:00
|
|
|
Source->OffsetType = AL_NONE;
|
|
|
|
Source->Offset = 0.0;
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
2015-10-24 16:31:28 -07:00
|
|
|
WriteUnlock(&Source->queue_lock);
|
2011-08-20 06:31:10 -07:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
/* GetSourceSampleOffset
|
2012-08-18 11:02:54 -07:00
|
|
|
*
|
|
|
|
* 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).
|
|
|
|
*/
|
2015-09-22 08:48:26 -07:00
|
|
|
ALint64 GetSourceSampleOffset(ALsource *Source)
|
2012-08-18 11:02:54 -07:00
|
|
|
{
|
|
|
|
const ALbufferlistitem *BufferList;
|
2014-07-31 07:20:36 -07:00
|
|
|
const ALbufferlistitem *Current;
|
2012-08-18 11:02:54 -07:00
|
|
|
ALuint64 readPos;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2012-08-18 11:02:54 -07:00
|
|
|
if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
|
2015-09-22 08:48:26 -07:00
|
|
|
{
|
|
|
|
ReadUnlock(&Source->queue_lock);
|
2012-08-18 11:02:54 -07:00
|
|
|
return 0;
|
2015-09-22 08:48:26 -07:00
|
|
|
}
|
2012-08-18 11:02:54 -07:00
|
|
|
|
|
|
|
/* NOTE: This is the offset into the *current* buffer, so add the length of
|
|
|
|
* any played buffers */
|
|
|
|
readPos = (ALuint64)Source->position << 32;
|
|
|
|
readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = ATOMIC_LOAD(&Source->queue);
|
|
|
|
Current = ATOMIC_LOAD(&Source->current_buffer);
|
|
|
|
while(BufferList && BufferList != Current)
|
2012-08-18 11:02:54 -07:00
|
|
|
{
|
|
|
|
if(BufferList->buffer)
|
|
|
|
readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
|
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
ReadUnlock(&Source->queue_lock);
|
2013-10-06 04:21:03 -07:00
|
|
|
return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
|
2012-08-18 11:02:54 -07:00
|
|
|
}
|
|
|
|
|
2012-08-20 15:57:27 -07: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).
|
|
|
|
*/
|
2015-09-22 08:48:26 -07:00
|
|
|
static ALdouble GetSourceSecOffset(ALsource *Source)
|
2012-08-20 15:57:27 -07:00
|
|
|
{
|
|
|
|
const ALbufferlistitem *BufferList;
|
2014-07-31 07:20:36 -07:00
|
|
|
const ALbufferlistitem *Current;
|
2014-05-10 07:56:41 -07:00
|
|
|
const ALbuffer *Buffer = NULL;
|
2012-08-20 15:57:27 -07:00
|
|
|
ALuint64 readPos;
|
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2014-05-10 03:21:40 -07:00
|
|
|
if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
|
2015-09-22 08:48:26 -07:00
|
|
|
{
|
|
|
|
ReadUnlock(&Source->queue_lock);
|
2012-08-20 15:57:27 -07:00
|
|
|
return 0.0;
|
2015-09-22 08:48:26 -07:00
|
|
|
}
|
2012-08-20 15:57:27 -07:00
|
|
|
|
|
|
|
/* NOTE: This is the offset into the *current* buffer, so add the length of
|
|
|
|
* any played buffers */
|
|
|
|
readPos = (ALuint64)Source->position << FRACTIONBITS;
|
|
|
|
readPos |= (ALuint64)Source->position_fraction;
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = ATOMIC_LOAD(&Source->queue);
|
|
|
|
Current = ATOMIC_LOAD(&Source->current_buffer);
|
|
|
|
while(BufferList && BufferList != Current)
|
2012-08-20 15:57:27 -07:00
|
|
|
{
|
2014-05-10 03:21:40 -07:00
|
|
|
const ALbuffer *buffer = BufferList->buffer;
|
|
|
|
if(buffer != NULL)
|
|
|
|
{
|
|
|
|
if(!Buffer) Buffer = buffer;
|
|
|
|
readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
|
|
|
|
}
|
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(BufferList && !Buffer)
|
|
|
|
{
|
|
|
|
Buffer = BufferList->buffer;
|
2012-08-20 15:57:27 -07:00
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
2014-05-14 03:40:01 -07:00
|
|
|
assert(Buffer != NULL);
|
2012-08-20 15:57:27 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
ReadUnlock(&Source->queue_lock);
|
2012-08-20 15:57:27 -07:00
|
|
|
return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
|
|
|
|
}
|
|
|
|
|
2016-04-25 02:22:54 -07:00
|
|
|
/* GetSourceOffset
|
2012-04-21 05:53:27 -07:00
|
|
|
*
|
2016-04-25 02:22:54 -07:00
|
|
|
* 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).
|
2012-04-21 05:53:27 -07:00
|
|
|
*/
|
2016-04-25 02:22:54 -07:00
|
|
|
static ALdouble GetSourceOffset(ALsource *Source, ALenum name)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2010-12-09 19:47:08 -08:00
|
|
|
const ALbufferlistitem *BufferList;
|
2014-07-31 07:20:36 -07:00
|
|
|
const ALbufferlistitem *Current;
|
2014-05-10 03:21:40 -07:00
|
|
|
const ALbuffer *Buffer = NULL;
|
|
|
|
ALboolean readFin = AL_FALSE;
|
2016-04-25 02:22:54 -07:00
|
|
|
ALuint readPos, readPosFrac;
|
2012-04-21 05:53:27 -07:00
|
|
|
ALuint totalBufferLen;
|
2016-04-25 02:22:54 -07:00
|
|
|
ALdouble offset = 0.0;
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2015-09-22 08:48:26 -07:00
|
|
|
ReadLock(&Source->queue_lock);
|
2014-05-10 03:21:40 -07:00
|
|
|
if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2015-09-22 08:48:26 -07:00
|
|
|
ReadUnlock(&Source->queue_lock);
|
2016-04-25 02:22:54 -07:00
|
|
|
return 0.0;
|
2010-03-24 02:23:00 -07:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* NOTE: This is the offset into the *current* buffer, so add the length of
|
|
|
|
* any played buffers */
|
2011-10-03 10:07:50 -07:00
|
|
|
totalBufferLen = 0;
|
2014-05-10 07:56:41 -07:00
|
|
|
readPos = Source->position;
|
2015-10-16 10:52:10 -07:00
|
|
|
readPosFrac = Source->position_fraction;
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = ATOMIC_LOAD(&Source->queue);
|
|
|
|
Current = ATOMIC_LOAD(&Source->current_buffer);
|
2014-05-10 03:21:40 -07:00
|
|
|
while(BufferList != NULL)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2014-05-10 03:21:40 -07:00
|
|
|
const ALbuffer *buffer;
|
2014-07-31 07:20:36 -07:00
|
|
|
readFin = readFin || (BufferList == Current);
|
2014-05-10 03:21:40 -07:00
|
|
|
if((buffer=BufferList->buffer) != NULL)
|
2010-04-23 07:23:38 -07:00
|
|
|
{
|
2014-05-10 07:56:41 -07:00
|
|
|
if(!Buffer) Buffer = buffer;
|
2014-05-10 03:21:40 -07:00
|
|
|
totalBufferLen += buffer->SampleLen;
|
|
|
|
if(!readFin) readPos += buffer->SampleLen;
|
2010-04-23 07:23:38 -07:00
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
BufferList = BufferList->next;
|
|
|
|
}
|
2014-05-14 03:40:01 -07:00
|
|
|
assert(Buffer != NULL);
|
|
|
|
|
2012-04-19 21:46:29 -07:00
|
|
|
if(Source->Looping)
|
2011-10-03 10:07:50 -07:00
|
|
|
readPos %= totalBufferLen;
|
2010-03-24 02:23:00 -07:00
|
|
|
else
|
|
|
|
{
|
2016-04-25 02:22:54 -07:00
|
|
|
/* Wrap back to 0 */
|
2011-10-03 10:07:50 -07:00
|
|
|
if(readPos >= totalBufferLen)
|
2015-10-16 10:52:10 -07:00
|
|
|
readPos = readPosFrac = 0;
|
2010-03-24 02:23:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
switch(name)
|
|
|
|
{
|
2007-11-13 18:02:18 -08:00
|
|
|
case AL_SEC_OFFSET:
|
2016-04-25 02:22:54 -07:00
|
|
|
offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
|
2007-11-13 18:02:18 -08:00
|
|
|
break;
|
2012-04-21 05:53:27 -07:00
|
|
|
|
2007-11-13 18:02:18 -08:00
|
|
|
case AL_SAMPLE_OFFSET:
|
2016-04-25 02:22:54 -07:00
|
|
|
offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
|
2007-11-13 18:02:18 -08:00
|
|
|
break;
|
2012-04-21 05:53:27 -07:00
|
|
|
|
2007-11-13 18:02:18 -08:00
|
|
|
case AL_BYTE_OFFSET:
|
2011-10-03 10:07:50 -07:00
|
|
|
if(Buffer->OriginalType == UserFmtIMA4)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2014-03-03 17:05:08 -08:00
|
|
|
ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
|
|
|
|
ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
|
|
|
|
ALuint FrameBlockSize = Buffer->OriginalAlign;
|
2010-11-27 00:51:21 -08:00
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* Round down to nearest ADPCM block */
|
2016-04-25 02:22:54 -07:00
|
|
|
offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2014-03-04 22:44:30 -08:00
|
|
|
else if(Buffer->OriginalType == UserFmtMSADPCM)
|
|
|
|
{
|
|
|
|
ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
|
|
|
|
ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
|
|
|
|
ALuint FrameBlockSize = Buffer->OriginalAlign;
|
|
|
|
|
|
|
|
/* Round down to nearest ADPCM block */
|
2016-04-25 02:22:54 -07:00
|
|
|
offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
|
2014-03-04 22:44:30 -08:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
else
|
|
|
|
{
|
2011-10-03 10:07:50 -07:00
|
|
|
ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
|
2016-04-25 02:22:54 -07:00
|
|
|
offset = (ALdouble)(readPos * FrameSize);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-09-22 08:48:26 -07:00
|
|
|
|
|
|
|
ReadUnlock(&Source->queue_lock);
|
2016-04-25 02:22:54 -07:00
|
|
|
return offset;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* ApplyOffset
|
|
|
|
*
|
|
|
|
* Apply the stored playback offset to the Source. This function will update
|
2012-04-23 19:46:05 -07:00
|
|
|
* the number of buffers "played" given the stored offset.
|
|
|
|
*/
|
2011-08-21 00:49:04 -07:00
|
|
|
ALboolean ApplyOffset(ALsource *Source)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2014-05-10 03:21:40 -07:00
|
|
|
ALbufferlistitem *BufferList;
|
|
|
|
const ALbuffer *Buffer;
|
2015-10-13 03:01:34 -07:00
|
|
|
ALuint bufferLen, totalBufferLen;
|
2015-10-13 11:38:53 -07:00
|
|
|
ALuint offset=0, frac=0;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* Get sample frame offset */
|
2015-10-13 03:01:34 -07:00
|
|
|
if(!GetSampleOffset(Source, &offset, &frac))
|
2010-01-12 02:22:38 -08:00
|
|
|
return AL_FALSE;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
totalBufferLen = 0;
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = ATOMIC_LOAD(&Source->queue);
|
2014-05-10 03:21:40 -07:00
|
|
|
while(BufferList && totalBufferLen <= offset)
|
2010-01-12 02:22:38 -08:00
|
|
|
{
|
2010-03-26 00:41:27 -07:00
|
|
|
Buffer = BufferList->buffer;
|
2011-10-03 10:07:50 -07:00
|
|
|
bufferLen = Buffer ? Buffer->SampleLen : 0;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2014-05-10 03:21:40 -07:00
|
|
|
if(bufferLen > offset-totalBufferLen)
|
2010-01-12 02:22:38 -08:00
|
|
|
{
|
2012-04-21 05:53:27 -07:00
|
|
|
/* Offset is in this buffer */
|
2014-07-31 07:20:36 -07:00
|
|
|
ATOMIC_STORE(&Source->current_buffer, BufferList);
|
2010-01-12 02:22:38 -08:00
|
|
|
|
2011-10-03 10:07:50 -07:00
|
|
|
Source->position = offset - totalBufferLen;
|
2015-10-13 03:01:34 -07:00
|
|
|
Source->position_fraction = frac;
|
2010-05-11 11:59:41 -07:00
|
|
|
return AL_TRUE;
|
2010-01-12 02:22:38 -08:00
|
|
|
}
|
|
|
|
|
2011-10-03 10:07:50 -07:00
|
|
|
totalBufferLen += bufferLen;
|
2010-01-12 02:22:38 -08:00
|
|
|
|
2010-03-26 00:41:27 -07:00
|
|
|
BufferList = BufferList->next;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2012-04-21 05:53:27 -07:00
|
|
|
|
|
|
|
/* Offset is out of range of the queue */
|
2010-05-11 11:59:41 -07:00
|
|
|
return AL_FALSE;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* GetSampleOffset
|
|
|
|
*
|
2015-10-13 03:01:34 -07:00
|
|
|
* 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.
|
2012-04-21 05:53:27 -07:00
|
|
|
*/
|
2015-10-13 03:01:34 -07:00
|
|
|
static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2010-12-09 19:47:08 -08:00
|
|
|
const ALbuffer *Buffer = NULL;
|
|
|
|
const ALbufferlistitem *BufferList;
|
2015-10-14 03:23:19 -07:00
|
|
|
ALdouble dbloff, dblfrac;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* Find the first valid Buffer in the Queue */
|
2014-07-31 07:20:36 -07:00
|
|
|
BufferList = ATOMIC_LOAD(&Source->queue);
|
2010-03-24 02:23:00 -07:00
|
|
|
while(BufferList)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2010-03-24 02:23:00 -07:00
|
|
|
if(BufferList->buffer)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2010-03-24 02:23:00 -07:00
|
|
|
Buffer = BufferList->buffer;
|
2007-11-13 18:02:18 -08:00
|
|
|
break;
|
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
BufferList = BufferList->next;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2010-03-24 02:23:00 -07:00
|
|
|
if(!Buffer)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2016-05-09 16:34:54 -07:00
|
|
|
Source->OffsetType = AL_NONE;
|
|
|
|
Source->Offset = 0.0;
|
2015-10-13 03:01:34 -07:00
|
|
|
return AL_FALSE;
|
2010-03-24 02:23:00 -07:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-16 22:11:03 -07:00
|
|
|
switch(Source->OffsetType)
|
2010-03-24 02:23:00 -07:00
|
|
|
{
|
2010-05-11 11:06:48 -07:00
|
|
|
case AL_BYTE_OFFSET:
|
2012-04-21 05:53:27 -07:00
|
|
|
/* Determine the ByteOffset (and ensure it is block aligned) */
|
2015-10-13 03:01:34 -07:00
|
|
|
*offset = (ALuint)Source->Offset;
|
2010-12-03 22:33:41 -08:00
|
|
|
if(Buffer->OriginalType == UserFmtIMA4)
|
2010-11-29 19:27:33 -08:00
|
|
|
{
|
2014-03-03 17:05:08 -08:00
|
|
|
ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
|
2015-10-13 03:01:34 -07:00
|
|
|
*offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
|
|
|
|
*offset *= Buffer->OriginalAlign;
|
2010-11-29 19:27:33 -08:00
|
|
|
}
|
2014-03-04 22:44:30 -08:00
|
|
|
else if(Buffer->OriginalType == UserFmtMSADPCM)
|
|
|
|
{
|
|
|
|
ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
|
2015-10-13 03:01:34 -07:00
|
|
|
*offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
|
|
|
|
*offset *= Buffer->OriginalAlign;
|
2014-03-04 22:44:30 -08:00
|
|
|
}
|
2010-11-29 19:27:33 -08:00
|
|
|
else
|
2015-10-13 03:01:34 -07:00
|
|
|
*offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
|
|
|
|
*frac = 0;
|
2010-05-11 11:06:48 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_SAMPLE_OFFSET:
|
2015-10-24 15:13:56 -07:00
|
|
|
dblfrac = modf(Source->Offset, &dbloff);
|
2015-10-14 03:23:19 -07:00
|
|
|
*offset = (ALuint)mind(dbloff, UINT_MAX);
|
|
|
|
*frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
|
2010-05-11 11:06:48 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_SEC_OFFSET:
|
2015-10-24 15:13:56 -07:00
|
|
|
dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
|
2015-10-14 03:23:19 -07:00
|
|
|
*offset = (ALuint)mind(dbloff, UINT_MAX);
|
|
|
|
*frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
|
2010-05-11 11:06:48 -07:00
|
|
|
break;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2016-05-09 16:34:54 -07:00
|
|
|
Source->OffsetType = AL_NONE;
|
|
|
|
Source->Offset = 0.0;
|
2010-03-24 02:23:00 -07:00
|
|
|
|
2015-10-13 03:01:34 -07:00
|
|
|
return AL_TRUE;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2008-01-16 13:27:15 -08:00
|
|
|
|
|
|
|
|
2012-04-21 05:53:27 -07:00
|
|
|
/* ReleaseALSources
|
|
|
|
*
|
|
|
|
* Destroys all sources in the source map.
|
|
|
|
*/
|
2008-01-16 13:27:15 -08:00
|
|
|
ALvoid ReleaseALSources(ALCcontext *Context)
|
|
|
|
{
|
2010-05-01 19:59:41 -07:00
|
|
|
ALsizei pos;
|
|
|
|
for(pos = 0;pos < Context->SourceMap.size;pos++)
|
2008-01-16 13:27:15 -08:00
|
|
|
{
|
2010-05-01 19:59:41 -07:00
|
|
|
ALsource *temp = Context->SourceMap.array[pos].value;
|
|
|
|
Context->SourceMap.array[pos].value = NULL;
|
2009-10-24 07:09:44 -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
|
|
|
DeinitSource(temp);
|
2008-01-16 13:27:15 -08:00
|
|
|
|
2012-04-19 22:28:01 -07:00
|
|
|
FreeThunkEntry(temp->id);
|
2012-04-21 05:53:27 -07:00
|
|
|
memset(temp, 0, sizeof(*temp));
|
2012-08-15 05:54:13 -07:00
|
|
|
al_free(temp);
|
2008-01-16 13:27:15 -08:00
|
|
|
}
|
|
|
|
}
|