1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-07-05 15:34:48 +00:00

update mojoAL to current git

This commit is contained in:
fgenesis 2025-04-01 23:34:06 +02:00
parent 689d38ff10
commit 5fab8f4d81
2 changed files with 188 additions and 117 deletions

View file

@ -44,6 +44,7 @@ if(AQUARIA_USE_SDL2 AND SDL2_FOUND)
endif() endif()
if(AQUARIA_USE_MOJOAL) if(AQUARIA_USE_MOJOAL)
add_definitions(-DAL_LIBTYPE_STATIC=1)
set(xsrc ${xsrc} mojoal.c) set(xsrc ${xsrc} mojoal.c)
set(OPENAL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/AL" CACHE PATH "OpenAL include directory" FORCE) set(OPENAL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/AL" CACHE PATH "OpenAL include directory" FORCE)
else() else()

View file

@ -11,7 +11,10 @@
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
#ifdef _WIN32 /* Unless compiling statically into another app, we want the public API
to export on Windows. Define these before including al.h, so we override
its attempt to mark these as `dllimport`. */
#if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC)
#define AL_API __declspec(dllexport) #define AL_API __declspec(dllexport)
#define ALC_API __declspec(dllexport) #define ALC_API __declspec(dllexport)
#endif #endif
@ -24,7 +27,18 @@
#include "alc.h" #include "alc.h"
#include "SDL.h" #include "SDL.h"
#ifdef __SSE__ /* if you are on x86 or x86-64, we assume you have SSE1 by now. */ /* This is for debugging and/or pulling the fire alarm. */
#define FORCE_SCALAR_FALLBACK 0
#if FORCE_SCALAR_FALLBACK
# ifdef __SSE__
# undef __SSE__
# endif
# ifdef __ARM_NEON__
# undef __ARM_NEON__
# endif
#endif
#if defined(__SSE__) /* if you are on x86 or x86-64, we assume you have SSE1 by now. */
#define NEED_SCALAR_FALLBACK 0 #define NEED_SCALAR_FALLBACK 0
#elif (defined(__ARM_ARCH) && (__ARM_ARCH >= 8)) /* ARMv8 always has NEON. */ #elif (defined(__ARM_ARCH) && (__ARM_ARCH >= 8)) /* ARMv8 always has NEON. */
#define NEED_SCALAR_FALLBACK 0 #define NEED_SCALAR_FALLBACK 0
@ -38,7 +52,7 @@
/* Some platforms fail to define __ARM_NEON__, others need it or arm_neon.h will fail. */ /* Some platforms fail to define __ARM_NEON__, others need it or arm_neon.h will fail. */
#if (defined(__ARM_ARCH) || defined(_M_ARM)) #if (defined(__ARM_ARCH) || defined(_M_ARM))
# if !NEED_SCALAR_FALLBACK && !defined(__ARM_NEON__) # if !NEED_SCALAR_FALLBACK && !FORCE_SCALAR_FALLBACK && !defined(__ARM_NEON__)
# define __ARM_NEON__ 1 # define __ARM_NEON__ 1
# endif # endif
#endif #endif
@ -470,6 +484,7 @@ SIMDALIGNEDSTRUCT ALsource
ALfloat cone_outer_gain; ALfloat cone_outer_gain;
ALbuffer *buffer; ALbuffer *buffer;
SDL_AudioStream *stream; /* for resampling. */ SDL_AudioStream *stream; /* for resampling. */
SDL_atomic_t total_queued_buffers; /* everything queued, playing and processed. AL_BUFFERS_QUEUED value. */
BufferQueue buffer_queue; BufferQueue buffer_queue;
BufferQueue buffer_queue_processed; BufferQueue buffer_queue_processed;
ALsizei offset; /* offset in bytes for converted stream! */ ALsizei offset; /* offset in bytes for converted stream! */
@ -1194,11 +1209,11 @@ static void pitch_fft(float *fftBuffer, int fftFrameSize, int sign)
for (k = 0, le = 2; k < endval; k++) { for (k = 0, le = 2; k < endval; k++) {
le <<= 1; le <<= 1;
le2 = le>>1; le2 = le>>1;
ur = 1.0; ur = 1.0f;
ui = 0.0; ui = 0.0f;
arg = M_PI / (le2>>1); arg = (float) (M_PI / (le2>>1));
wr = SDL_cos(arg); wr = SDL_cosf(arg);
wi = sign*SDL_sin(arg); wi = sign*SDL_sinf(arg);
for (j = 0; j < le2; j += 2) { for (j = 0; j < le2; j += 2) {
p1r = fftBuffer+j; p1i = p1r+1; p1r = fftBuffer+j; p1i = p1r+1;
p2r = p1r+le2; p2i = p2r+1; p2r = p1r+le2; p2i = p2r+1;
@ -1250,8 +1265,8 @@ static void pitch_shift(ALsource *src, const ALbuffer *buffer, int numSampsToPro
/* do windowing and re,im interleave */ /* do windowing and re,im interleave */
for (k = 0; k < pitch_framesize;k++) { for (k = 0; k < pitch_framesize;k++) {
window = -.5*SDL_cos(2.*M_PI*(double)k/(double)pitch_framesize)+.5; window = -.5*SDL_cos(2.*M_PI*(double)k/(double)pitch_framesize)+.5;
state->workspace[2*k] = state->infifo[k] * window; state->workspace[2*k] = (ALfloat) (state->infifo[k] * window);
state->workspace[2*k+1] = 0.; state->workspace[2*k+1] = 0.0f;
} }
@ -1272,13 +1287,13 @@ static void pitch_shift(ALsource *src, const ALbuffer *buffer, int numSampsToPro
/* compute phase difference */ /* compute phase difference */
tmp = phase - state->lastphase[k]; tmp = phase - state->lastphase[k];
state->lastphase[k] = phase; state->lastphase[k] = (ALfloat) phase;
/* subtract expected phase difference */ /* subtract expected phase difference */
tmp -= (double)k*expct; tmp -= (double)k*expct;
/* map delta phase into +/- Pi interval */ /* map delta phase into +/- Pi interval */
qpd = tmp/M_PI; qpd = (int) (tmp/M_PI);
if (qpd >= 0) qpd += qpd&1; if (qpd >= 0) qpd += qpd&1;
else qpd -= qpd&1; else qpd -= qpd&1;
tmp -= M_PI*(double)qpd; tmp -= M_PI*(double)qpd;
@ -1290,8 +1305,8 @@ static void pitch_shift(ALsource *src, const ALbuffer *buffer, int numSampsToPro
tmp = (double)k*freqPerBin + tmp*freqPerBin; tmp = (double)k*freqPerBin + tmp*freqPerBin;
/* store magnitude and true frequency in analysis arrays */ /* store magnitude and true frequency in analysis arrays */
state->workspace[2*k] = magn; state->workspace[2*k] = (ALfloat) magn;
state->workspace[2*k+1] = tmp; state->workspace[2*k+1] = (ALfloat) tmp;
} }
@ -1299,7 +1314,7 @@ static void pitch_shift(ALsource *src, const ALbuffer *buffer, int numSampsToPro
/* this does the actual pitch shifting */ /* this does the actual pitch shifting */
SDL_memset(state->synmagn, '\0', sizeof (state->synmagn)); SDL_memset(state->synmagn, '\0', sizeof (state->synmagn));
for (k = 0; k <= pitch_framesize2; k++) { for (k = 0; k <= pitch_framesize2; k++) {
index = k*pitchShift; index = (int) (k*pitchShift);
if (index <= pitch_framesize2) { if (index <= pitch_framesize2) {
state->synmagn[index] += state->workspace[2*k]; state->synmagn[index] += state->workspace[2*k];
state->synfreq[index] = state->workspace[2*k+1] * pitchShift; state->synfreq[index] = state->workspace[2*k+1] * pitchShift;
@ -1327,12 +1342,12 @@ static void pitch_shift(ALsource *src, const ALbuffer *buffer, int numSampsToPro
tmp += (double)k*expct; tmp += (double)k*expct;
/* accumulate delta phase to get bin phase */ /* accumulate delta phase to get bin phase */
state->sumphase[k] += tmp; state->sumphase[k] += (ALfloat) tmp;
phase = state->sumphase[k]; phase = state->sumphase[k];
/* get real and imag part and re-interleave */ /* get real and imag part and re-interleave */
state->workspace[2*k] = magn*SDL_cos(phase); state->workspace[2*k] = (ALfloat) (magn*SDL_cos(phase));
state->workspace[2*k+1] = magn*SDL_sin(phase); state->workspace[2*k+1] = (ALfloat) (magn*SDL_sin(phase));
} }
/* zero negative frequencies */ /* zero negative frequencies */
@ -1344,7 +1359,7 @@ static void pitch_shift(ALsource *src, const ALbuffer *buffer, int numSampsToPro
/* do windowing and add to output accumulator */ /* do windowing and add to output accumulator */
for(k=0; k < pitch_framesize; k++) { for(k=0; k < pitch_framesize; k++) {
window = -.5*SDL_cos(2.*M_PI*(double)k/(double)pitch_framesize)+.5; window = -.5*SDL_cos(2.*M_PI*(double)k/(double)pitch_framesize)+.5;
state->outputaccum[k] += 2.*window*state->workspace[2*k]/(pitch_framesize2*osamp); state->outputaccum[k] += (ALfloat) (2.*window*state->workspace[2*k]/(pitch_framesize2*osamp));
} }
for (k = 0; k < stepSize; k++) state->outfifo[k] = state->outputaccum[k]; for (k = 0; k < stepSize; k++) state->outfifo[k] = state->outputaccum[k];
@ -1417,12 +1432,15 @@ static ALboolean mix_source_buffer(ALCcontext *ctx, ALsource *src, BufferQueueIt
if (src->stream) { /* resampling? */ if (src->stream) { /* resampling? */
int mixframes, mixlen, remainingmixframes; int mixframes, mixlen, remainingmixframes;
while ( (((mixlen = SDL_AudioStreamAvailable(src->stream)) / bufferframesize) < framesneeded) && (src->offset < buffer->len) ) { while ( (((mixlen = SDL_AudioStreamAvailable(src->stream)) / bufferframesize) < framesneeded) && (src->offset < buffer->len) ) {
const int framesput = (buffer->len - src->offset) / bufferframesize; const int bytesleft = (buffer->len - src->offset);
const int bytesput = SDL_min(framesput, 1024) * bufferframesize; /* workaround in case remains are less than bufferframesize */
const int framesput = (bytesleft + (bufferframesize - 1)) / bufferframesize;
const int bytesput = SDL_min(SDL_min(framesput, 1024) * bufferframesize, bytesleft);
FIXME("dynamically adjust frames here?"); /* we hardcode 1024 samples when opening the audio device, too. */ FIXME("dynamically adjust frames here?"); /* we hardcode 1024 samples when opening the audio device, too. */
SDL_AudioStreamPut(src->stream, data, bytesput); SDL_AudioStreamPut(src->stream, data, bytesput);
src->offset += bytesput; src->offset += bytesput;
data += bytesput / sizeof (float); /* workaround in case remains are not evenly divided by sizeof (float) */
data += (bytesput + (sizeof (float) - 1)) / sizeof (float);
} }
mixframes = SDL_min(mixlen / bufferframesize, framesneeded); mixframes = SDL_min(mixlen / bufferframesize, framesneeded);
@ -1733,12 +1751,13 @@ static void calculate_channel_gains(const ALCcontext *ctx, const ALsource *src,
{ {
#if NEED_SCALAR_FALLBACK #if NEED_SCALAR_FALLBACK
SDL_memcpy(position, src->position, sizeof (position));
/* if values aren't source-relative, then convert it to be so. */ /* if values aren't source-relative, then convert it to be so. */
if (!src->source_relative) { if (!src->source_relative) {
position[0] -= ctx->listener.position[0]; SDL_memcpy(position, src->position, sizeof (position));
position[1] -= ctx->listener.position[1]; } else {
position[2] -= ctx->listener.position[2]; position[0] = src->position[0] - ctx->listener.position[0];
position[1] = src->position[1] - ctx->listener.position[1];
position[2] = src->position[2] - ctx->listener.position[2];
} }
distance = magnitude(position); distance = magnitude(position);
#endif #endif
@ -1779,39 +1798,34 @@ static void calculate_channel_gains(const ALCcontext *ctx, const ALsource *src,
https://dsp.stackexchange.com/questions/21691/algorithm-to-pan-audio https://dsp.stackexchange.com/questions/21691/algorithm-to-pan-audio
Naturally, we'll need to know the angle between where our listener
is facing and where the source is to make that work...
https://www.youtube.com/watch?v=S_568VZWFJo
...but to do that, we need to rotate so we have the correct side of
the listener, which isn't just a point in space, but has a definite
direction it is facing. More or less, this is what gluLookAt deals
with...
http://www.songho.ca/opengl/gl_camera.html
...although I messed with the algorithm until it did what I wanted.
XYZZY!! https://en.wikipedia.org/wiki/Cross_product#Mnemonic XYZZY!! https://en.wikipedia.org/wiki/Cross_product#Mnemonic
*/ */
#ifdef __SSE__ /* (the math is explained in the scalar version.) */ #ifdef __SSE__ /* (the math is explained in the scalar version.) */
if (has_sse) { if (has_sse) {
const __m128 at_sse = _mm_load_ps(at); const __m128 at_sse = _mm_load_ps(at);
const __m128 U_sse = normalize_sse(xyzzy_sse(at_sse, _mm_load_ps(up))); const __m128 up_sse = _mm_load_ps(up);
const __m128 V_sse = xyzzy_sse(at_sse, U_sse); __m128 V_sse;
const __m128 N_sse = normalize_sse(at_sse); __m128 R_sse;
const __m128 rotated_sse = { ALfloat cosangle;
dotproduct_sse(position_sse, U_sse), ALfloat mags;
-dotproduct_sse(position_sse, V_sse), ALfloat a;
-dotproduct_sse(position_sse, N_sse),
0.0f
};
const ALfloat mags = magnitude_sse(at_sse) * magnitude_sse(rotated_sse); a = dotproduct_sse(position_sse, up_sse);
radians = (mags == 0.0f) ? 0.0f : SDL_acosf(dotproduct_sse(at_sse, rotated_sse) / mags); V_sse = _mm_sub_ps(position_sse, _mm_mul_ps(_mm_set1_ps(a), up_sse));
if (_mm_comilt_ss(rotated_sse, _mm_setzero_ps())) {
mags = magnitude_sse(at_sse) * magnitude_sse(V_sse);
if (mags == 0.0f) {
radians = 0.0f;
} else {
cosangle = dotproduct_sse(at_sse, V_sse) / mags;
cosangle = SDL_clamp(cosangle, -1.0f, 1.0f);
radians = SDL_acosf(cosangle);
}
R_sse = xyzzy_sse(at_sse, up_sse);
if (dotproduct_sse(R_sse, V_sse) < 0.0f) {
radians = -radians; radians = -radians;
} }
} else } else
@ -1820,64 +1834,63 @@ static void calculate_channel_gains(const ALCcontext *ctx, const ALsource *src,
#ifdef __ARM_NEON__ /* (the math is explained in the scalar version.) */ #ifdef __ARM_NEON__ /* (the math is explained in the scalar version.) */
if (has_neon) { if (has_neon) {
const float32x4_t at_neon = vld1q_f32(at); const float32x4_t at_neon = vld1q_f32(at);
const float32x4_t U_neon = normalize_neon(xyzzy_neon(at_neon, vld1q_f32(up))); const float32x4_t up_neon = vld1q_f32(up);
const float32x4_t V_neon = xyzzy_neon(at_neon, U_neon); float32x4_t V_neon;
const float32x4_t N_neon = normalize_neon(at_neon); float32x4_t R_neon;
const float32x4_t rotated_neon = { ALfloat cosangle;
dotproduct_neon(position_neon, U_neon), ALfloat mags;
-dotproduct_neon(position_neon, V_neon), ALfloat a;
-dotproduct_neon(position_neon, N_neon),
0.0f
};
const ALfloat mags = magnitude_neon(at_neon) * magnitude_neon(rotated_neon); a = dotproduct_neon(position_neon, up_neon);
radians = (mags == 0.0f) ? 0.0f : SDL_acosf(dotproduct_neon(at_neon, rotated_neon) / mags); V_neon = vsubq_f32(position_neon, vmulq_f32(vdupq_n_f32(a), up_neon));
if (rotated_neon[0] < 0.0f) {
mags = magnitude_neon(at_neon) * magnitude_neon(V_neon);
if (mags == 0.0f) {
radians = 0.0f;
} else {
cosangle = dotproduct_neon(at_neon, V_neon) / mags;
cosangle = SDL_clamp(cosangle, -1.0f, 1.0f);
radians = SDL_acosf(cosangle);
}
R_neon = xyzzy_neon(at_neon, up_neon);
if (dotproduct_neon(R_neon, V_neon) < 0.0f) {
radians = -radians; radians = -radians;
} }
} else } else
#endif #endif
{ {
#if NEED_SCALAR_FALLBACK #if NEED_SCALAR_FALLBACK
ALfloat U[3];
ALfloat V[3]; ALfloat V[3];
ALfloat N[3]; ALfloat R[3];
ALfloat rotated[3];
ALfloat mags; ALfloat mags;
ALfloat cosangle;
ALfloat a;
xyzzy(U, at, up); /* Remove upwards component so it lies completely within the horizontal plane. */
normalize(U); a = dotproduct(position, up);
xyzzy(V, at, U); V[0] = position[0] - (a * up[0]);
SDL_memcpy(N, at, sizeof (N)); V[1] = position[1] - (a * up[1]);
normalize(N); V[2] = position[2] - (a * up[2]);
/* we don't need the bottom row of the gluLookAt matrix, since we don't /* Calculate angle */
translate. (Matrix * Vector) is just filling in each element of the mags = magnitude(at) * magnitude(V);
output vector with the dot product of a row of the matrix and the if (mags == 0.0f) {
vector. I made some of these negative to make it work for my purposes, radians = 0.0f;
but that's not what GLU does here. } else {
cosangle = dotproduct(at, V) / mags;
cosangle = SDL_clamp(cosangle, -1.0f, 1.0f);
radians = SDL_acosf(cosangle);
}
(This says gluLookAt is left-handed, so maybe that's part of it?) /* Get "right" vector */
https://stackoverflow.com/questions/25933581/how-u-v-n-camera-coordinate-system-explained-with-opengl xyzzy(R, at, up);
*/
rotated[0] = dotproduct(position, U);
rotated[1] = -dotproduct(position, V);
rotated[2] = -dotproduct(position, N);
/* At this point, we have rotated vector and we can calculate the angle
from 0 (directly in front of where the listener is facing) to 180
degrees (directly behind) ... */
mags = magnitude(at) * magnitude(rotated);
radians = (mags == 0.0f) ? 0.0f : SDL_acosf(dotproduct(at, rotated) / mags);
/* and we already have what we need to decide if those degrees are on the
listener's left or right...
https://gamedev.stackexchange.com/questions/43897/determining-if-something-is-on-the-right-or-left-side-of-an-object
...we already did this dot product: it's in rotated[0]. */
/* make it negative to the left, positive to the right. */ /* make it negative to the left, positive to the right. */
if (rotated[0] < 0.0f) { if (dotproduct(R, V) < 0.0f) {
radians = -radians; radians = -radians;
} }
#endif #endif
@ -2569,6 +2582,16 @@ static void _alcGetIntegerv(ALCdevice *device, const ALCenum param, const ALCsiz
*values = OPENAL_VERSION_MINOR; *values = OPENAL_VERSION_MINOR;
return; return;
case ALC_FREQUENCY:
if (!device) {
*values = 0;
set_alc_error(device, ALC_INVALID_DEVICE);
return;
}
*values = device->frequency;
return;
default: break; default: break;
} }
@ -2754,7 +2777,7 @@ static ALsource *get_source(ALCcontext *ctx, const ALuint name, SourceBlock **_b
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
if (_block) *_block = NULL; if (_block) *_block = NULL;
return NULL; return NULL;
} else if ((name == 0) || (blockidx >= ctx->num_source_blocks)) { } else if ((name == 0) || (blockidx < 0) || (blockidx >= ctx->num_source_blocks)) {
set_al_error(ctx, AL_INVALID_NAME); set_al_error(ctx, AL_INVALID_NAME);
if (_block) *_block = NULL; if (_block) *_block = NULL;
return NULL; return NULL;
@ -2786,7 +2809,7 @@ static ALbuffer *get_buffer(ALCcontext *ctx, const ALuint name, BufferBlock **_b
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
if (_block) *_block = NULL; if (_block) *_block = NULL;
return NULL; return NULL;
} else if ((name == 0) || (blockidx >= ctx->device->playback.num_buffer_blocks)) { } else if ((name == 0) || (blockidx < 0) || (blockidx >= ctx->device->playback.num_buffer_blocks)) {
set_al_error(ctx, AL_INVALID_NAME); set_al_error(ctx, AL_INVALID_NAME);
if (_block) *_block = NULL; if (_block) *_block = NULL;
return NULL; return NULL;
@ -2921,7 +2944,7 @@ static const ALchar *_alGetString(const ALenum param)
return NULL; return NULL;
} }
ENTRYPOINT(const ALchar *,alGetString,(const ALenum param),(param)) ENTRYPOINT(const ALchar *,alGetString,(ALenum param),(param))
static void _alGetBooleanv(const ALenum param, ALboolean *values) static void _alGetBooleanv(const ALenum param, ALboolean *values)
{ {
@ -3478,9 +3501,14 @@ static void _alGenSources(const ALsizei n, ALuint *names)
ALsizei blocki; ALsizei blocki;
ALsizei i; ALsizei i;
if (!ctx) { if (n < 0) {
set_al_error(ctx, AL_INVALID_VALUE);
return;
} else if (!ctx) {
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
return; return;
} else if (n == 0) {
return; /* not an error, but nothing to do. */
} }
if (n <= SDL_arraysize(stackobjs)) { if (n <= SDL_arraysize(stackobjs)) {
@ -3589,6 +3617,7 @@ static void _alGenSources(const ALsizei n, ALuint *names)
SDL_zerop(src); SDL_zerop(src);
SDL_AtomicSet(&src->state, AL_INITIAL); SDL_AtomicSet(&src->state, AL_INITIAL);
SDL_AtomicSet(&src->total_queued_buffers, 0);
src->name = names[i]; src->name = names[i];
src->type = AL_UNDETERMINED; src->type = AL_UNDETERMINED;
src->recalc = AL_TRUE; src->recalc = AL_TRUE;
@ -3614,7 +3643,10 @@ static void _alDeleteSources(const ALsizei n, const ALuint *names)
ALCcontext *ctx = get_current_context(); ALCcontext *ctx = get_current_context();
ALsizei i; ALsizei i;
if (!ctx) { if (n < 0) {
set_al_error(ctx, AL_INVALID_VALUE);
return;
} else if (!ctx) {
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
return; return;
} }
@ -3906,7 +3938,7 @@ static void _alGetSourcefv(const ALuint name, const ALenum param, ALfloat *value
case AL_REFERENCE_DISTANCE: *values = src->reference_distance; break; case AL_REFERENCE_DISTANCE: *values = src->reference_distance; break;
case AL_ROLLOFF_FACTOR: *values = src->rolloff_factor; break; case AL_ROLLOFF_FACTOR: *values = src->rolloff_factor; break;
case AL_MAX_DISTANCE: *values = src->max_distance; break; case AL_MAX_DISTANCE: *values = src->max_distance; break;
case AL_PITCH: source_set_pitch(ctx, src, *values); break; case AL_PITCH: *values = src->pitch; break;
case AL_CONE_INNER_ANGLE: *values = src->cone_inner_angle; break; case AL_CONE_INNER_ANGLE: *values = src->cone_inner_angle; break;
case AL_CONE_OUTER_ANGLE: *values = src->cone_outer_angle; break; case AL_CONE_OUTER_ANGLE: *values = src->cone_outer_angle; break;
case AL_CONE_OUTER_GAIN: *values = src->cone_outer_gain; break; case AL_CONE_OUTER_GAIN: *values = src->cone_outer_gain; break;
@ -3973,8 +4005,7 @@ static void _alGetSourceiv(const ALuint name, const ALenum param, ALint *values)
case AL_SOURCE_STATE: *values = (ALint) SDL_AtomicGet(&src->state); break; case AL_SOURCE_STATE: *values = (ALint) SDL_AtomicGet(&src->state); break;
case AL_SOURCE_TYPE: *values = (ALint) src->type; break; case AL_SOURCE_TYPE: *values = (ALint) src->type; break;
case AL_BUFFER: *values = (ALint) (src->buffer ? src->buffer->name : 0); break; case AL_BUFFER: *values = (ALint) (src->buffer ? src->buffer->name : 0); break;
/* !!! FIXME: AL_BUFFERS_QUEUED is the total number of buffers pending, playing, and processed, so this is wrong. It might also have to be 1 if there's a static buffer, but I'm not sure. */ case AL_BUFFERS_QUEUED: *values = (ALint) SDL_AtomicGet(&src->total_queued_buffers); break;
case AL_BUFFERS_QUEUED: *values = (ALint) SDL_AtomicGet(&src->buffer_queue.num_items); break;
case AL_BUFFERS_PROCESSED: *values = (ALint) SDL_AtomicGet(&src->buffer_queue_processed.num_items); break; case AL_BUFFERS_PROCESSED: *values = (ALint) SDL_AtomicGet(&src->buffer_queue_processed.num_items); break;
case AL_SOURCE_RELATIVE: *values = (ALint) src->source_relative; break; case AL_SOURCE_RELATIVE: *values = (ALint) src->source_relative; break;
case AL_LOOPING: *values = (ALint) src->looping; break; case AL_LOOPING: *values = (ALint) src->looping; break;
@ -4050,7 +4081,7 @@ static void source_play(ALCcontext *ctx, const ALsizei n, const ALuint *names)
void *ptr; void *ptr;
ALsizei i; ALsizei i;
if (n == 0) { if (n <= 0) {
return; return;
} else if (!ctx) { } else if (!ctx) {
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
@ -4162,6 +4193,9 @@ static void source_stop(ALCcontext *ctx, const ALuint name)
} }
SDL_AtomicSet(&src->state, AL_STOPPED); SDL_AtomicSet(&src->state, AL_STOPPED);
source_mark_all_buffers_processed(src); source_mark_all_buffers_processed(src);
if (src->stream) {
SDL_AudioStreamClear(src->stream);
}
if (must_lock) { if (must_lock) {
SDL_UnlockMutex(ctx->source_lock); SDL_UnlockMutex(ctx->source_lock);
} }
@ -4228,9 +4262,10 @@ static void source_set_offset(ALsource *src, ALenum param, ALfloat value)
if (!ctx) { if (!ctx) {
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
return; return;
} } else if (src->type == AL_UNDETERMINED) { /* no buffer to seek in */
set_al_error(ctx, AL_INVALID_OPERATION);
if (src->type == AL_STREAMING) { return;
} else if (src->type == AL_STREAMING) {
FIXME("set_offset for streaming sources not implemented"); FIXME("set_offset for streaming sources not implemented");
return; return;
} }
@ -4242,14 +4277,18 @@ static void source_set_offset(ALsource *src, ALenum param, ALfloat value)
switch (param) { switch (param) {
case AL_SAMPLE_OFFSET: case AL_SAMPLE_OFFSET:
offset = value * framesize; offset = ((int) value) * framesize;
break; break;
case AL_SEC_OFFSET: case AL_SEC_OFFSET:
offset = value * freq * framesize; offset = ((int) value) * freq * framesize;
break; break;
case AL_BYTE_OFFSET: case AL_BYTE_OFFSET:
offset = ((int)value / framesize) * framesize; offset = (((int) value) / framesize) * framesize;
break; break;
default:
SDL_assert(!"Unexpected source offset type!");
set_al_error(ctx, AL_INVALID_ENUM); /* this is a MojoAL bug, not an app bug, but we'll try to recover. */
return;
} }
if ((offset < 0) || (offset > bufflen)) { if ((offset < 0) || (offset > bufflen)) {
@ -4267,6 +4306,10 @@ static void source_set_offset(ALsource *src, ALenum param, ALfloat value)
src->offset = offset; src->offset = offset;
SDL_UnlockMutex(ctx->source_lock); SDL_UnlockMutex(ctx->source_lock);
} }
if (SDL_AtomicGet(&src->state) != AL_PLAYING) {
src->offset_latched = SDL_TRUE;
}
} }
/* deal with alSourcePlay and alSourcePlayv (etc) boiler plate... */ /* deal with alSourcePlay and alSourcePlayv (etc) boiler plate... */
@ -4274,7 +4317,9 @@ static void source_set_offset(ALsource *src, ALenum param, ALfloat value)
void alSource##alfn(ALuint name) { source_##fn(get_current_context(), name); } \ void alSource##alfn(ALuint name) { source_##fn(get_current_context(), name); } \
void alSource##alfn##v(ALsizei n, const ALuint *sources) { \ void alSource##alfn##v(ALsizei n, const ALuint *sources) { \
ALCcontext *ctx = get_current_context(); \ ALCcontext *ctx = get_current_context(); \
if (!ctx) { \ if (n < 0) { \
set_al_error(ctx, AL_INVALID_VALUE); \
} else if (!ctx) { \
set_al_error(ctx, AL_INVALID_OPERATION); \ set_al_error(ctx, AL_INVALID_OPERATION); \
} else { \ } else { \
ALsizei i; \ ALsizei i; \
@ -4318,8 +4363,11 @@ static void _alSourceQueueBuffers(const ALuint name, const ALsizei nb, const ALu
return; return;
} }
if (nb == 0) { if (nb < 0) {
return; /* nothing to do. */ set_al_error(ctx, AL_INVALID_VALUE);
return;
} else if (nb == 0) {
return; /* not an error, but nothing to do. */
} }
for (i = nb; i > 0; i--) { /* build list in reverse */ for (i = nb; i > 0; i--) { /* build list in reverse */
@ -4446,6 +4494,7 @@ static void _alSourceQueueBuffers(const ALuint name, const ALsizei nb, const ALu
SDL_AtomicSetPtr(&queueend->next, ptr); SDL_AtomicSetPtr(&queueend->next, ptr);
} while (!SDL_AtomicCASPtr(&src->buffer_queue.just_queued, ptr, queue)); } while (!SDL_AtomicCASPtr(&src->buffer_queue.just_queued, ptr, queue));
SDL_AtomicAdd(&src->total_queued_buffers, (int) nb);
SDL_AtomicAdd(&src->buffer_queue.num_items, (int) nb); SDL_AtomicAdd(&src->buffer_queue.num_items, (int) nb);
} }
ENTRYPOINTVOID(alSourceQueueBuffers,(ALuint name, ALsizei nb, const ALuint *bufnames),(name,nb,bufnames)) ENTRYPOINTVOID(alSourceQueueBuffers,(ALuint name, ALsizei nb, const ALuint *bufnames),(name,nb,bufnames))
@ -4467,8 +4516,11 @@ static void _alSourceUnqueueBuffers(const ALuint name, const ALsizei nb, ALuint
return; return;
} }
if (nb == 0) { if (nb < 0) {
return; /* nothing to do. */ set_al_error(ctx, AL_INVALID_VALUE);
return;
} else if (nb == 0) {
return; /* not an error, but nothing to do. */
} }
if (((ALsizei) SDL_AtomicGet(&src->buffer_queue_processed.num_items)) < nb) { if (((ALsizei) SDL_AtomicGet(&src->buffer_queue_processed.num_items)) < nb) {
@ -4477,6 +4529,7 @@ static void _alSourceUnqueueBuffers(const ALuint name, const ALsizei nb, ALuint
} }
SDL_AtomicAdd(&src->buffer_queue_processed.num_items, -((int) nb)); SDL_AtomicAdd(&src->buffer_queue_processed.num_items, -((int) nb));
SDL_AtomicAdd(&src->total_queued_buffers, -((int) nb));
obtain_newly_queued_buffers(&src->buffer_queue_processed); obtain_newly_queued_buffers(&src->buffer_queue_processed);
@ -4521,9 +4574,14 @@ static void _alGenBuffers(const ALsizei n, ALuint *names)
ALsizei blocki; ALsizei blocki;
ALsizei i; ALsizei i;
if (!ctx) { if (n < 0) {
set_al_error(ctx, AL_INVALID_VALUE);
return;
} else if (!ctx) {
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
return; return;
} else if (n == 0) {
return; /* not an error, but nothing to do. */
} }
if (n <= SDL_arraysize(stackobjs)) { if (n <= SDL_arraysize(stackobjs)) {
@ -4635,9 +4693,14 @@ static void _alDeleteBuffers(const ALsizei n, const ALuint *names)
ALCcontext *ctx = get_current_context(); ALCcontext *ctx = get_current_context();
ALsizei i; ALsizei i;
if (!ctx) { if (n < 0) {
set_al_error(ctx, AL_INVALID_VALUE);
return;
} else if (!ctx) {
set_al_error(ctx, AL_INVALID_OPERATION); set_al_error(ctx, AL_INVALID_OPERATION);
return; return;
} else if (n == 0) {
return; /* not an error, but nothing to do. */
} }
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@ -4694,6 +4757,13 @@ static void _alBufferData(const ALuint name, const ALenum alfmt, const ALvoid *d
if (!buffer) return; if (!buffer) return;
if (size < 0) {
set_al_error(ctx, AL_INVALID_VALUE);
return;
} else if (freq < 0) {
return; /* not an error, but nothing to do. */
}
if (!alcfmt_to_sdlfmt(alfmt, &sdlfmt, &channels, &framesize)) { if (!alcfmt_to_sdlfmt(alfmt, &sdlfmt, &channels, &framesize)) {
set_al_error(ctx, AL_INVALID_VALUE); set_al_error(ctx, AL_INVALID_VALUE);
return; return;