annotate OpenAL32/alSource.c @ 0:f9476ff7637e

initial forking of open-al to create multiple listeners
author Robert McIntyre <rlm@mit.edu>
date Tue, 25 Oct 2011 13:02:31 -0700
parents
children
rev   line source
rlm@0 1 /**
rlm@0 2 * OpenAL cross platform audio library
rlm@0 3 * Copyright (C) 1999-2007 by authors.
rlm@0 4 * This library is free software; you can redistribute it and/or
rlm@0 5 * modify it under the terms of the GNU Library General Public
rlm@0 6 * License as published by the Free Software Foundation; either
rlm@0 7 * version 2 of the License, or (at your option) any later version.
rlm@0 8 *
rlm@0 9 * This library is distributed in the hope that it will be useful,
rlm@0 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rlm@0 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
rlm@0 12 * Library General Public License for more details.
rlm@0 13 *
rlm@0 14 * You should have received a copy of the GNU Library General Public
rlm@0 15 * License along with this library; if not, write to the
rlm@0 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
rlm@0 17 * Boston, MA 02111-1307, USA.
rlm@0 18 * Or go to http://www.gnu.org/copyleft/lgpl.html
rlm@0 19 */
rlm@0 20
rlm@0 21 #include "config.h"
rlm@0 22
rlm@0 23 #include <stdlib.h>
rlm@0 24 #include <math.h>
rlm@0 25 #include <float.h>
rlm@0 26 #include "alMain.h"
rlm@0 27 #include "AL/al.h"
rlm@0 28 #include "AL/alc.h"
rlm@0 29 #include "alError.h"
rlm@0 30 #include "alSource.h"
rlm@0 31 #include "alBuffer.h"
rlm@0 32 #include "alThunk.h"
rlm@0 33 #include "alAuxEffectSlot.h"
rlm@0 34
rlm@0 35
rlm@0 36 enum Resampler DefaultResampler;
rlm@0 37 const ALsizei ResamplerPadding[RESAMPLER_MAX] = {
rlm@0 38 0, /* Point */
rlm@0 39 1, /* Linear */
rlm@0 40 2, /* Cubic */
rlm@0 41 };
rlm@0 42 const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
rlm@0 43 0, /* Point */
rlm@0 44 0, /* Linear */
rlm@0 45 1, /* Cubic */
rlm@0 46 };
rlm@0 47
rlm@0 48
rlm@0 49 static ALvoid InitSourceParams(ALsource *Source);
rlm@0 50 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
rlm@0 51 static ALint GetByteOffset(ALsource *Source);
rlm@0 52
rlm@0 53 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
rlm@0 54 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
rlm@0 55 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
rlm@0 56 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
rlm@0 57
rlm@0 58 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
rlm@0 59 {
rlm@0 60 ALCcontext *Context;
rlm@0 61 ALCdevice *Device;
rlm@0 62
rlm@0 63 Context = GetLockedContext();
rlm@0 64 if(!Context) return;
rlm@0 65
rlm@0 66 Device = Context->Device;
rlm@0 67 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
rlm@0 68 alSetError(Context, AL_INVALID_VALUE);
rlm@0 69 else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
rlm@0 70 alSetError(Context, AL_INVALID_VALUE);
rlm@0 71 else
rlm@0 72 {
rlm@0 73 ALenum err;
rlm@0 74 ALsizei i;
rlm@0 75
rlm@0 76 // Add additional sources to the list
rlm@0 77 i = 0;
rlm@0 78 while(i < n)
rlm@0 79 {
rlm@0 80 ALsource *source = calloc(1, sizeof(ALsource));
rlm@0 81 if(!source)
rlm@0 82 {
rlm@0 83 alSetError(Context, AL_OUT_OF_MEMORY);
rlm@0 84 alDeleteSources(i, sources);
rlm@0 85 break;
rlm@0 86 }
rlm@0 87
rlm@0 88 err = NewThunkEntry(&source->source);
rlm@0 89 if(err == AL_NO_ERROR)
rlm@0 90 err = InsertUIntMapEntry(&Context->SourceMap, source->source, source);
rlm@0 91 if(err != AL_NO_ERROR)
rlm@0 92 {
rlm@0 93 FreeThunkEntry(source->source);
rlm@0 94 memset(source, 0, sizeof(ALsource));
rlm@0 95 free(source);
rlm@0 96
rlm@0 97 alSetError(Context, err);
rlm@0 98 alDeleteSources(i, sources);
rlm@0 99 break;
rlm@0 100 }
rlm@0 101
rlm@0 102 sources[i++] = source->source;
rlm@0 103 InitSourceParams(source);
rlm@0 104 }
rlm@0 105 }
rlm@0 106
rlm@0 107 UnlockContext(Context);
rlm@0 108 }
rlm@0 109
rlm@0 110
rlm@0 111 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
rlm@0 112 {
rlm@0 113 ALCcontext *Context;
rlm@0 114 ALsource *Source;
rlm@0 115 ALsizei i, j;
rlm@0 116 ALbufferlistitem *BufferList;
rlm@0 117 ALboolean SourcesValid = AL_FALSE;
rlm@0 118
rlm@0 119 Context = GetLockedContext();
rlm@0 120 if(!Context) return;
rlm@0 121
rlm@0 122 if(n < 0)
rlm@0 123 alSetError(Context, AL_INVALID_VALUE);
rlm@0 124 else
rlm@0 125 {
rlm@0 126 SourcesValid = AL_TRUE;
rlm@0 127 // Check that all Sources are valid (and can therefore be deleted)
rlm@0 128 for(i = 0;i < n;i++)
rlm@0 129 {
rlm@0 130 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
rlm@0 131 {
rlm@0 132 alSetError(Context, AL_INVALID_NAME);
rlm@0 133 SourcesValid = AL_FALSE;
rlm@0 134 break;
rlm@0 135 }
rlm@0 136 }
rlm@0 137 }
rlm@0 138
rlm@0 139 if(SourcesValid)
rlm@0 140 {
rlm@0 141 // All Sources are valid, and can be deleted
rlm@0 142 for(i = 0;i < n;i++)
rlm@0 143 {
rlm@0 144 // Recheck that the Source is valid, because there could be duplicated Source names
rlm@0 145 if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
rlm@0 146 continue;
rlm@0 147
rlm@0 148 for(j = 0;j < Context->ActiveSourceCount;j++)
rlm@0 149 {
rlm@0 150 if(Context->ActiveSources[j] == Source)
rlm@0 151 {
rlm@0 152 ALsizei end = --(Context->ActiveSourceCount);
rlm@0 153 Context->ActiveSources[j] = Context->ActiveSources[end];
rlm@0 154 break;
rlm@0 155 }
rlm@0 156 }
rlm@0 157
rlm@0 158 // For each buffer in the source's queue...
rlm@0 159 while(Source->queue != NULL)
rlm@0 160 {
rlm@0 161 BufferList = Source->queue;
rlm@0 162 Source->queue = BufferList->next;
rlm@0 163
rlm@0 164 if(BufferList->buffer != NULL)
rlm@0 165 BufferList->buffer->refcount--;
rlm@0 166 free(BufferList);
rlm@0 167 }
rlm@0 168
rlm@0 169 for(j = 0;j < MAX_SENDS;++j)
rlm@0 170 {
rlm@0 171 if(Source->Send[j].Slot)
rlm@0 172 Source->Send[j].Slot->refcount--;
rlm@0 173 Source->Send[j].Slot = NULL;
rlm@0 174 }
rlm@0 175
rlm@0 176 // Remove Source from list of Sources
rlm@0 177 RemoveUIntMapKey(&Context->SourceMap, Source->source);
rlm@0 178 FreeThunkEntry(Source->source);
rlm@0 179
rlm@0 180 memset(Source,0,sizeof(ALsource));
rlm@0 181 free(Source);
rlm@0 182 }
rlm@0 183 }
rlm@0 184
rlm@0 185 UnlockContext(Context);
rlm@0 186 }
rlm@0 187
rlm@0 188
rlm@0 189 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
rlm@0 190 {
rlm@0 191 ALCcontext *Context;
rlm@0 192 ALboolean result;
rlm@0 193
rlm@0 194 Context = GetLockedContext();
rlm@0 195 if(!Context) return AL_FALSE;
rlm@0 196
rlm@0 197 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
rlm@0 198
rlm@0 199 UnlockContext(Context);
rlm@0 200
rlm@0 201 return result;
rlm@0 202 }
rlm@0 203
rlm@0 204
rlm@0 205 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
rlm@0 206 {
rlm@0 207 ALCcontext *pContext;
rlm@0 208 ALsource *Source;
rlm@0 209
rlm@0 210 pContext = GetLockedContext();
rlm@0 211 if(!pContext) return;
rlm@0 212
rlm@0 213 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 214 {
rlm@0 215 switch(eParam)
rlm@0 216 {
rlm@0 217 case AL_PITCH:
rlm@0 218 if(flValue >= 0.0f)
rlm@0 219 {
rlm@0 220 Source->flPitch = flValue;
rlm@0 221 Source->NeedsUpdate = AL_TRUE;
rlm@0 222 }
rlm@0 223 else
rlm@0 224 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 225 break;
rlm@0 226
rlm@0 227 case AL_CONE_INNER_ANGLE:
rlm@0 228 if(flValue >= 0.0f && flValue <= 360.0f)
rlm@0 229 {
rlm@0 230 Source->flInnerAngle = flValue;
rlm@0 231 Source->NeedsUpdate = AL_TRUE;
rlm@0 232 }
rlm@0 233 else
rlm@0 234 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 235 break;
rlm@0 236
rlm@0 237 case AL_CONE_OUTER_ANGLE:
rlm@0 238 if(flValue >= 0.0f && flValue <= 360.0f)
rlm@0 239 {
rlm@0 240 Source->flOuterAngle = flValue;
rlm@0 241 Source->NeedsUpdate = AL_TRUE;
rlm@0 242 }
rlm@0 243 else
rlm@0 244 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 245 break;
rlm@0 246
rlm@0 247 case AL_GAIN:
rlm@0 248 if(flValue >= 0.0f)
rlm@0 249 {
rlm@0 250 Source->flGain = flValue;
rlm@0 251 Source->NeedsUpdate = AL_TRUE;
rlm@0 252 }
rlm@0 253 else
rlm@0 254 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 255 break;
rlm@0 256
rlm@0 257 case AL_MAX_DISTANCE:
rlm@0 258 if(flValue >= 0.0f)
rlm@0 259 {
rlm@0 260 Source->flMaxDistance = flValue;
rlm@0 261 Source->NeedsUpdate = AL_TRUE;
rlm@0 262 }
rlm@0 263 else
rlm@0 264 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 265 break;
rlm@0 266
rlm@0 267 case AL_ROLLOFF_FACTOR:
rlm@0 268 if(flValue >= 0.0f)
rlm@0 269 {
rlm@0 270 Source->flRollOffFactor = flValue;
rlm@0 271 Source->NeedsUpdate = AL_TRUE;
rlm@0 272 }
rlm@0 273 else
rlm@0 274 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 275 break;
rlm@0 276
rlm@0 277 case AL_REFERENCE_DISTANCE:
rlm@0 278 if(flValue >= 0.0f)
rlm@0 279 {
rlm@0 280 Source->flRefDistance = flValue;
rlm@0 281 Source->NeedsUpdate = AL_TRUE;
rlm@0 282 }
rlm@0 283 else
rlm@0 284 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 285 break;
rlm@0 286
rlm@0 287 case AL_MIN_GAIN:
rlm@0 288 if(flValue >= 0.0f && flValue <= 1.0f)
rlm@0 289 {
rlm@0 290 Source->flMinGain = flValue;
rlm@0 291 Source->NeedsUpdate = AL_TRUE;
rlm@0 292 }
rlm@0 293 else
rlm@0 294 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 295 break;
rlm@0 296
rlm@0 297 case AL_MAX_GAIN:
rlm@0 298 if(flValue >= 0.0f && flValue <= 1.0f)
rlm@0 299 {
rlm@0 300 Source->flMaxGain = flValue;
rlm@0 301 Source->NeedsUpdate = AL_TRUE;
rlm@0 302 }
rlm@0 303 else
rlm@0 304 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 305 break;
rlm@0 306
rlm@0 307 case AL_CONE_OUTER_GAIN:
rlm@0 308 if(flValue >= 0.0f && flValue <= 1.0f)
rlm@0 309 {
rlm@0 310 Source->flOuterGain = flValue;
rlm@0 311 Source->NeedsUpdate = AL_TRUE;
rlm@0 312 }
rlm@0 313 else
rlm@0 314 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 315 break;
rlm@0 316
rlm@0 317 case AL_CONE_OUTER_GAINHF:
rlm@0 318 if(flValue >= 0.0f && flValue <= 1.0f)
rlm@0 319 {
rlm@0 320 Source->OuterGainHF = flValue;
rlm@0 321 Source->NeedsUpdate = AL_TRUE;
rlm@0 322 }
rlm@0 323 else
rlm@0 324 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 325 break;
rlm@0 326
rlm@0 327 case AL_AIR_ABSORPTION_FACTOR:
rlm@0 328 if(flValue >= 0.0f && flValue <= 10.0f)
rlm@0 329 {
rlm@0 330 Source->AirAbsorptionFactor = flValue;
rlm@0 331 Source->NeedsUpdate = AL_TRUE;
rlm@0 332 }
rlm@0 333 else
rlm@0 334 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 335 break;
rlm@0 336
rlm@0 337 case AL_ROOM_ROLLOFF_FACTOR:
rlm@0 338 if(flValue >= 0.0f && flValue <= 10.0f)
rlm@0 339 {
rlm@0 340 Source->RoomRolloffFactor = flValue;
rlm@0 341 Source->NeedsUpdate = AL_TRUE;
rlm@0 342 }
rlm@0 343 else
rlm@0 344 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 345 break;
rlm@0 346
rlm@0 347 case AL_DOPPLER_FACTOR:
rlm@0 348 if(flValue >= 0.0f && flValue <= 1.0f)
rlm@0 349 {
rlm@0 350 Source->DopplerFactor = flValue;
rlm@0 351 Source->NeedsUpdate = AL_TRUE;
rlm@0 352 }
rlm@0 353 else
rlm@0 354 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 355 break;
rlm@0 356
rlm@0 357 case AL_SEC_OFFSET:
rlm@0 358 case AL_SAMPLE_OFFSET:
rlm@0 359 case AL_BYTE_OFFSET:
rlm@0 360 if(flValue >= 0.0f)
rlm@0 361 {
rlm@0 362 Source->lOffsetType = eParam;
rlm@0 363
rlm@0 364 // Store Offset (convert Seconds into Milliseconds)
rlm@0 365 if(eParam == AL_SEC_OFFSET)
rlm@0 366 Source->lOffset = (ALint)(flValue * 1000.0f);
rlm@0 367 else
rlm@0 368 Source->lOffset = (ALint)flValue;
rlm@0 369
rlm@0 370 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
rlm@0 371 !pContext->DeferUpdates)
rlm@0 372 {
rlm@0 373 if(ApplyOffset(Source) == AL_FALSE)
rlm@0 374 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 375 }
rlm@0 376 }
rlm@0 377 else
rlm@0 378 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 379 break;
rlm@0 380
rlm@0 381 default:
rlm@0 382 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 383 break;
rlm@0 384 }
rlm@0 385 }
rlm@0 386 else
rlm@0 387 {
rlm@0 388 // Invalid Source Name
rlm@0 389 alSetError(pContext, AL_INVALID_NAME);
rlm@0 390 }
rlm@0 391
rlm@0 392 UnlockContext(pContext);
rlm@0 393 }
rlm@0 394
rlm@0 395
rlm@0 396 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
rlm@0 397 {
rlm@0 398 ALCcontext *pContext;
rlm@0 399 ALsource *Source;
rlm@0 400
rlm@0 401 pContext = GetLockedContext();
rlm@0 402 if(!pContext) return;
rlm@0 403
rlm@0 404 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 405 {
rlm@0 406 switch(eParam)
rlm@0 407 {
rlm@0 408 case AL_POSITION:
rlm@0 409 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
rlm@0 410 {
rlm@0 411 Source->vPosition[0] = flValue1;
rlm@0 412 Source->vPosition[1] = flValue2;
rlm@0 413 Source->vPosition[2] = flValue3;
rlm@0 414 Source->NeedsUpdate = AL_TRUE;
rlm@0 415 }
rlm@0 416 else
rlm@0 417 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 418 break;
rlm@0 419
rlm@0 420 case AL_VELOCITY:
rlm@0 421 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
rlm@0 422 {
rlm@0 423 Source->vVelocity[0] = flValue1;
rlm@0 424 Source->vVelocity[1] = flValue2;
rlm@0 425 Source->vVelocity[2] = flValue3;
rlm@0 426 Source->NeedsUpdate = AL_TRUE;
rlm@0 427 }
rlm@0 428 else
rlm@0 429 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 430 break;
rlm@0 431
rlm@0 432 case AL_DIRECTION:
rlm@0 433 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
rlm@0 434 {
rlm@0 435 Source->vOrientation[0] = flValue1;
rlm@0 436 Source->vOrientation[1] = flValue2;
rlm@0 437 Source->vOrientation[2] = flValue3;
rlm@0 438 Source->NeedsUpdate = AL_TRUE;
rlm@0 439 }
rlm@0 440 else
rlm@0 441 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 442 break;
rlm@0 443
rlm@0 444 default:
rlm@0 445 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 446 break;
rlm@0 447 }
rlm@0 448 }
rlm@0 449 else
rlm@0 450 alSetError(pContext, AL_INVALID_NAME);
rlm@0 451
rlm@0 452 UnlockContext(pContext);
rlm@0 453 }
rlm@0 454
rlm@0 455
rlm@0 456 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
rlm@0 457 {
rlm@0 458 ALCcontext *pContext;
rlm@0 459
rlm@0 460 if(pflValues)
rlm@0 461 {
rlm@0 462 switch(eParam)
rlm@0 463 {
rlm@0 464 case AL_PITCH:
rlm@0 465 case AL_CONE_INNER_ANGLE:
rlm@0 466 case AL_CONE_OUTER_ANGLE:
rlm@0 467 case AL_GAIN:
rlm@0 468 case AL_MAX_DISTANCE:
rlm@0 469 case AL_ROLLOFF_FACTOR:
rlm@0 470 case AL_REFERENCE_DISTANCE:
rlm@0 471 case AL_MIN_GAIN:
rlm@0 472 case AL_MAX_GAIN:
rlm@0 473 case AL_CONE_OUTER_GAIN:
rlm@0 474 case AL_CONE_OUTER_GAINHF:
rlm@0 475 case AL_SEC_OFFSET:
rlm@0 476 case AL_SAMPLE_OFFSET:
rlm@0 477 case AL_BYTE_OFFSET:
rlm@0 478 case AL_AIR_ABSORPTION_FACTOR:
rlm@0 479 case AL_ROOM_ROLLOFF_FACTOR:
rlm@0 480 alSourcef(source, eParam, pflValues[0]);
rlm@0 481 return;
rlm@0 482
rlm@0 483 case AL_POSITION:
rlm@0 484 case AL_VELOCITY:
rlm@0 485 case AL_DIRECTION:
rlm@0 486 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
rlm@0 487 return;
rlm@0 488 }
rlm@0 489 }
rlm@0 490
rlm@0 491 pContext = GetLockedContext();
rlm@0 492 if(!pContext) return;
rlm@0 493
rlm@0 494 if(pflValues)
rlm@0 495 {
rlm@0 496 if(LookupSource(pContext->SourceMap, source) != NULL)
rlm@0 497 {
rlm@0 498 switch(eParam)
rlm@0 499 {
rlm@0 500 default:
rlm@0 501 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 502 break;
rlm@0 503 }
rlm@0 504 }
rlm@0 505 else
rlm@0 506 alSetError(pContext, AL_INVALID_NAME);
rlm@0 507 }
rlm@0 508 else
rlm@0 509 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 510
rlm@0 511 UnlockContext(pContext);
rlm@0 512 }
rlm@0 513
rlm@0 514
rlm@0 515 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
rlm@0 516 {
rlm@0 517 ALCcontext *pContext;
rlm@0 518 ALsource *Source;
rlm@0 519 ALbufferlistitem *BufferListItem;
rlm@0 520
rlm@0 521 switch(eParam)
rlm@0 522 {
rlm@0 523 case AL_MAX_DISTANCE:
rlm@0 524 case AL_ROLLOFF_FACTOR:
rlm@0 525 case AL_CONE_INNER_ANGLE:
rlm@0 526 case AL_CONE_OUTER_ANGLE:
rlm@0 527 case AL_REFERENCE_DISTANCE:
rlm@0 528 alSourcef(source, eParam, (ALfloat)lValue);
rlm@0 529 return;
rlm@0 530 }
rlm@0 531
rlm@0 532 pContext = GetLockedContext();
rlm@0 533 if(!pContext) return;
rlm@0 534
rlm@0 535 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 536 {
rlm@0 537 ALCdevice *device = pContext->Device;
rlm@0 538
rlm@0 539 switch(eParam)
rlm@0 540 {
rlm@0 541 case AL_SOURCE_RELATIVE:
rlm@0 542 if(lValue == AL_FALSE || lValue == AL_TRUE)
rlm@0 543 {
rlm@0 544 Source->bHeadRelative = (ALboolean)lValue;
rlm@0 545 Source->NeedsUpdate = AL_TRUE;
rlm@0 546 }
rlm@0 547 else
rlm@0 548 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 549 break;
rlm@0 550
rlm@0 551 case AL_LOOPING:
rlm@0 552 if(lValue == AL_FALSE || lValue == AL_TRUE)
rlm@0 553 Source->bLooping = (ALboolean)lValue;
rlm@0 554 else
rlm@0 555 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 556 break;
rlm@0 557
rlm@0 558 case AL_BUFFER:
rlm@0 559 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
rlm@0 560 {
rlm@0 561 ALbuffer *buffer = NULL;
rlm@0 562
rlm@0 563 if(lValue == 0 ||
rlm@0 564 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
rlm@0 565 {
rlm@0 566 // Remove all elements in the queue
rlm@0 567 while(Source->queue != NULL)
rlm@0 568 {
rlm@0 569 BufferListItem = Source->queue;
rlm@0 570 Source->queue = BufferListItem->next;
rlm@0 571
rlm@0 572 if(BufferListItem->buffer)
rlm@0 573 BufferListItem->buffer->refcount--;
rlm@0 574 free(BufferListItem);
rlm@0 575 }
rlm@0 576 Source->BuffersInQueue = 0;
rlm@0 577
rlm@0 578 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
rlm@0 579 if(buffer != NULL)
rlm@0 580 {
rlm@0 581 // Source is now in STATIC mode
rlm@0 582 Source->lSourceType = AL_STATIC;
rlm@0 583
rlm@0 584 // Add the selected buffer to the queue
rlm@0 585 BufferListItem = malloc(sizeof(ALbufferlistitem));
rlm@0 586 BufferListItem->buffer = buffer;
rlm@0 587 BufferListItem->next = NULL;
rlm@0 588 BufferListItem->prev = NULL;
rlm@0 589
rlm@0 590 Source->queue = BufferListItem;
rlm@0 591 Source->BuffersInQueue = 1;
rlm@0 592
rlm@0 593 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
rlm@0 594 Source->SampleSize = BytesFromFmt(buffer->FmtType);
rlm@0 595 if(buffer->FmtChannels == FmtMono)
rlm@0 596 Source->Update = CalcSourceParams;
rlm@0 597 else
rlm@0 598 Source->Update = CalcNonAttnSourceParams;
rlm@0 599
rlm@0 600 // Increment reference counter for buffer
rlm@0 601 buffer->refcount++;
rlm@0 602 }
rlm@0 603 else
rlm@0 604 {
rlm@0 605 // Source is now in UNDETERMINED mode
rlm@0 606 Source->lSourceType = AL_UNDETERMINED;
rlm@0 607 }
rlm@0 608 Source->BuffersPlayed = 0;
rlm@0 609
rlm@0 610 // Update AL_BUFFER parameter
rlm@0 611 Source->Buffer = buffer;
rlm@0 612 Source->NeedsUpdate = AL_TRUE;
rlm@0 613 }
rlm@0 614 else
rlm@0 615 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 616 }
rlm@0 617 else
rlm@0 618 alSetError(pContext, AL_INVALID_OPERATION);
rlm@0 619 break;
rlm@0 620
rlm@0 621 case AL_SOURCE_STATE:
rlm@0 622 // Query only
rlm@0 623 alSetError(pContext, AL_INVALID_OPERATION);
rlm@0 624 break;
rlm@0 625
rlm@0 626 case AL_SEC_OFFSET:
rlm@0 627 case AL_SAMPLE_OFFSET:
rlm@0 628 case AL_BYTE_OFFSET:
rlm@0 629 if(lValue >= 0)
rlm@0 630 {
rlm@0 631 Source->lOffsetType = eParam;
rlm@0 632
rlm@0 633 // Store Offset (convert Seconds into Milliseconds)
rlm@0 634 if(eParam == AL_SEC_OFFSET)
rlm@0 635 Source->lOffset = lValue * 1000;
rlm@0 636 else
rlm@0 637 Source->lOffset = lValue;
rlm@0 638
rlm@0 639 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
rlm@0 640 !pContext->DeferUpdates)
rlm@0 641 {
rlm@0 642 if(ApplyOffset(Source) == AL_FALSE)
rlm@0 643 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 644 }
rlm@0 645 }
rlm@0 646 else
rlm@0 647 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 648 break;
rlm@0 649
rlm@0 650 case AL_DIRECT_FILTER: {
rlm@0 651 ALfilter *filter = NULL;
rlm@0 652
rlm@0 653 if(lValue == 0 ||
rlm@0 654 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
rlm@0 655 {
rlm@0 656 if(!filter)
rlm@0 657 {
rlm@0 658 Source->DirectFilter.type = AL_FILTER_NULL;
rlm@0 659 Source->DirectFilter.filter = 0;
rlm@0 660 }
rlm@0 661 else
rlm@0 662 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
rlm@0 663 Source->NeedsUpdate = AL_TRUE;
rlm@0 664 }
rlm@0 665 else
rlm@0 666 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 667 } break;
rlm@0 668
rlm@0 669 case AL_DIRECT_FILTER_GAINHF_AUTO:
rlm@0 670 if(lValue == AL_TRUE || lValue == AL_FALSE)
rlm@0 671 {
rlm@0 672 Source->DryGainHFAuto = lValue;
rlm@0 673 Source->NeedsUpdate = AL_TRUE;
rlm@0 674 }
rlm@0 675 else
rlm@0 676 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 677 break;
rlm@0 678
rlm@0 679 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
rlm@0 680 if(lValue == AL_TRUE || lValue == AL_FALSE)
rlm@0 681 {
rlm@0 682 Source->WetGainAuto = lValue;
rlm@0 683 Source->NeedsUpdate = AL_TRUE;
rlm@0 684 }
rlm@0 685 else
rlm@0 686 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 687 break;
rlm@0 688
rlm@0 689 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
rlm@0 690 if(lValue == AL_TRUE || lValue == AL_FALSE)
rlm@0 691 {
rlm@0 692 Source->WetGainHFAuto = lValue;
rlm@0 693 Source->NeedsUpdate = AL_TRUE;
rlm@0 694 }
rlm@0 695 else
rlm@0 696 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 697 break;
rlm@0 698
rlm@0 699 case AL_VIRTUAL_CHANNELS_SOFT:
rlm@0 700 if(lValue == AL_TRUE || lValue == AL_FALSE)
rlm@0 701 {
rlm@0 702 Source->VirtualChannels = lValue;
rlm@0 703 Source->NeedsUpdate = AL_TRUE;
rlm@0 704 }
rlm@0 705 else
rlm@0 706 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 707 break;
rlm@0 708
rlm@0 709 case AL_DISTANCE_MODEL:
rlm@0 710 if(lValue == AL_NONE ||
rlm@0 711 lValue == AL_INVERSE_DISTANCE ||
rlm@0 712 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
rlm@0 713 lValue == AL_LINEAR_DISTANCE ||
rlm@0 714 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
rlm@0 715 lValue == AL_EXPONENT_DISTANCE ||
rlm@0 716 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
rlm@0 717 {
rlm@0 718 Source->DistanceModel = lValue;
rlm@0 719 if(pContext->SourceDistanceModel)
rlm@0 720 Source->NeedsUpdate = AL_TRUE;
rlm@0 721 }
rlm@0 722 else
rlm@0 723 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 724 break;
rlm@0 725
rlm@0 726 default:
rlm@0 727 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 728 break;
rlm@0 729 }
rlm@0 730 }
rlm@0 731 else
rlm@0 732 alSetError(pContext, AL_INVALID_NAME);
rlm@0 733
rlm@0 734 UnlockContext(pContext);
rlm@0 735 }
rlm@0 736
rlm@0 737
rlm@0 738 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
rlm@0 739 {
rlm@0 740 ALCcontext *pContext;
rlm@0 741 ALsource *Source;
rlm@0 742
rlm@0 743 switch(eParam)
rlm@0 744 {
rlm@0 745 case AL_POSITION:
rlm@0 746 case AL_VELOCITY:
rlm@0 747 case AL_DIRECTION:
rlm@0 748 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
rlm@0 749 return;
rlm@0 750 }
rlm@0 751
rlm@0 752 pContext = GetLockedContext();
rlm@0 753 if(!pContext) return;
rlm@0 754
rlm@0 755 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 756 {
rlm@0 757 ALCdevice *device = pContext->Device;
rlm@0 758
rlm@0 759 switch(eParam)
rlm@0 760 {
rlm@0 761 case AL_AUXILIARY_SEND_FILTER: {
rlm@0 762 ALeffectslot *ALEffectSlot = NULL;
rlm@0 763 ALfilter *ALFilter = NULL;
rlm@0 764
rlm@0 765 if((ALuint)lValue2 < device->NumAuxSends &&
rlm@0 766 (lValue1 == 0 ||
rlm@0 767 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
rlm@0 768 (lValue3 == 0 ||
rlm@0 769 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
rlm@0 770 {
rlm@0 771 /* Release refcount on the previous slot, and add one for
rlm@0 772 * the new slot */
rlm@0 773 if(Source->Send[lValue2].Slot)
rlm@0 774 Source->Send[lValue2].Slot->refcount--;
rlm@0 775 Source->Send[lValue2].Slot = ALEffectSlot;
rlm@0 776 if(Source->Send[lValue2].Slot)
rlm@0 777 Source->Send[lValue2].Slot->refcount++;
rlm@0 778
rlm@0 779 if(!ALFilter)
rlm@0 780 {
rlm@0 781 /* Disable filter */
rlm@0 782 Source->Send[lValue2].WetFilter.type = 0;
rlm@0 783 Source->Send[lValue2].WetFilter.filter = 0;
rlm@0 784 }
rlm@0 785 else
rlm@0 786 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
rlm@0 787 Source->NeedsUpdate = AL_TRUE;
rlm@0 788 }
rlm@0 789 else
rlm@0 790 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 791 } break;
rlm@0 792
rlm@0 793 default:
rlm@0 794 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 795 break;
rlm@0 796 }
rlm@0 797 }
rlm@0 798 else
rlm@0 799 alSetError(pContext, AL_INVALID_NAME);
rlm@0 800
rlm@0 801 UnlockContext(pContext);
rlm@0 802 }
rlm@0 803
rlm@0 804
rlm@0 805 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
rlm@0 806 {
rlm@0 807 ALCcontext *pContext;
rlm@0 808
rlm@0 809 if(plValues)
rlm@0 810 {
rlm@0 811 switch(eParam)
rlm@0 812 {
rlm@0 813 case AL_SOURCE_RELATIVE:
rlm@0 814 case AL_CONE_INNER_ANGLE:
rlm@0 815 case AL_CONE_OUTER_ANGLE:
rlm@0 816 case AL_LOOPING:
rlm@0 817 case AL_BUFFER:
rlm@0 818 case AL_SOURCE_STATE:
rlm@0 819 case AL_SEC_OFFSET:
rlm@0 820 case AL_SAMPLE_OFFSET:
rlm@0 821 case AL_BYTE_OFFSET:
rlm@0 822 case AL_MAX_DISTANCE:
rlm@0 823 case AL_ROLLOFF_FACTOR:
rlm@0 824 case AL_REFERENCE_DISTANCE:
rlm@0 825 case AL_DIRECT_FILTER:
rlm@0 826 case AL_DIRECT_FILTER_GAINHF_AUTO:
rlm@0 827 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
rlm@0 828 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
rlm@0 829 case AL_DISTANCE_MODEL:
rlm@0 830 case AL_VIRTUAL_CHANNELS_SOFT:
rlm@0 831 alSourcei(source, eParam, plValues[0]);
rlm@0 832 return;
rlm@0 833
rlm@0 834 case AL_POSITION:
rlm@0 835 case AL_VELOCITY:
rlm@0 836 case AL_DIRECTION:
rlm@0 837 case AL_AUXILIARY_SEND_FILTER:
rlm@0 838 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
rlm@0 839 return;
rlm@0 840 }
rlm@0 841 }
rlm@0 842
rlm@0 843 pContext = GetLockedContext();
rlm@0 844 if(!pContext) return;
rlm@0 845
rlm@0 846 if(plValues)
rlm@0 847 {
rlm@0 848 if(LookupSource(pContext->SourceMap, source) != NULL)
rlm@0 849 {
rlm@0 850 switch(eParam)
rlm@0 851 {
rlm@0 852 default:
rlm@0 853 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 854 break;
rlm@0 855 }
rlm@0 856 }
rlm@0 857 else
rlm@0 858 alSetError(pContext, AL_INVALID_NAME);
rlm@0 859 }
rlm@0 860 else
rlm@0 861 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 862
rlm@0 863 UnlockContext(pContext);
rlm@0 864 }
rlm@0 865
rlm@0 866
rlm@0 867 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
rlm@0 868 {
rlm@0 869 ALCcontext *pContext;
rlm@0 870 ALsource *Source;
rlm@0 871 ALdouble Offsets[2];
rlm@0 872 ALdouble updateLen;
rlm@0 873
rlm@0 874 pContext = GetLockedContext();
rlm@0 875 if(!pContext) return;
rlm@0 876
rlm@0 877 if(pflValue)
rlm@0 878 {
rlm@0 879 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 880 {
rlm@0 881 switch(eParam)
rlm@0 882 {
rlm@0 883 case AL_PITCH:
rlm@0 884 *pflValue = Source->flPitch;
rlm@0 885 break;
rlm@0 886
rlm@0 887 case AL_GAIN:
rlm@0 888 *pflValue = Source->flGain;
rlm@0 889 break;
rlm@0 890
rlm@0 891 case AL_MIN_GAIN:
rlm@0 892 *pflValue = Source->flMinGain;
rlm@0 893 break;
rlm@0 894
rlm@0 895 case AL_MAX_GAIN:
rlm@0 896 *pflValue = Source->flMaxGain;
rlm@0 897 break;
rlm@0 898
rlm@0 899 case AL_MAX_DISTANCE:
rlm@0 900 *pflValue = Source->flMaxDistance;
rlm@0 901 break;
rlm@0 902
rlm@0 903 case AL_ROLLOFF_FACTOR:
rlm@0 904 *pflValue = Source->flRollOffFactor;
rlm@0 905 break;
rlm@0 906
rlm@0 907 case AL_CONE_OUTER_GAIN:
rlm@0 908 *pflValue = Source->flOuterGain;
rlm@0 909 break;
rlm@0 910
rlm@0 911 case AL_CONE_OUTER_GAINHF:
rlm@0 912 *pflValue = Source->OuterGainHF;
rlm@0 913 break;
rlm@0 914
rlm@0 915 case AL_SEC_OFFSET:
rlm@0 916 case AL_SAMPLE_OFFSET:
rlm@0 917 case AL_BYTE_OFFSET:
rlm@0 918 updateLen = (ALdouble)pContext->Device->UpdateSize /
rlm@0 919 pContext->Device->Frequency;
rlm@0 920 GetSourceOffset(Source, eParam, Offsets, updateLen);
rlm@0 921 *pflValue = Offsets[0];
rlm@0 922 break;
rlm@0 923
rlm@0 924 case AL_CONE_INNER_ANGLE:
rlm@0 925 *pflValue = Source->flInnerAngle;
rlm@0 926 break;
rlm@0 927
rlm@0 928 case AL_CONE_OUTER_ANGLE:
rlm@0 929 *pflValue = Source->flOuterAngle;
rlm@0 930 break;
rlm@0 931
rlm@0 932 case AL_REFERENCE_DISTANCE:
rlm@0 933 *pflValue = Source->flRefDistance;
rlm@0 934 break;
rlm@0 935
rlm@0 936 case AL_AIR_ABSORPTION_FACTOR:
rlm@0 937 *pflValue = Source->AirAbsorptionFactor;
rlm@0 938 break;
rlm@0 939
rlm@0 940 case AL_ROOM_ROLLOFF_FACTOR:
rlm@0 941 *pflValue = Source->RoomRolloffFactor;
rlm@0 942 break;
rlm@0 943
rlm@0 944 case AL_DOPPLER_FACTOR:
rlm@0 945 *pflValue = Source->DopplerFactor;
rlm@0 946 break;
rlm@0 947
rlm@0 948 default:
rlm@0 949 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 950 break;
rlm@0 951 }
rlm@0 952 }
rlm@0 953 else
rlm@0 954 alSetError(pContext, AL_INVALID_NAME);
rlm@0 955 }
rlm@0 956 else
rlm@0 957 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 958
rlm@0 959 UnlockContext(pContext);
rlm@0 960 }
rlm@0 961
rlm@0 962
rlm@0 963 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
rlm@0 964 {
rlm@0 965 ALCcontext *pContext;
rlm@0 966 ALsource *Source;
rlm@0 967
rlm@0 968 pContext = GetLockedContext();
rlm@0 969 if(!pContext) return;
rlm@0 970
rlm@0 971 if(pflValue1 && pflValue2 && pflValue3)
rlm@0 972 {
rlm@0 973 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 974 {
rlm@0 975 switch(eParam)
rlm@0 976 {
rlm@0 977 case AL_POSITION:
rlm@0 978 *pflValue1 = Source->vPosition[0];
rlm@0 979 *pflValue2 = Source->vPosition[1];
rlm@0 980 *pflValue3 = Source->vPosition[2];
rlm@0 981 break;
rlm@0 982
rlm@0 983 case AL_VELOCITY:
rlm@0 984 *pflValue1 = Source->vVelocity[0];
rlm@0 985 *pflValue2 = Source->vVelocity[1];
rlm@0 986 *pflValue3 = Source->vVelocity[2];
rlm@0 987 break;
rlm@0 988
rlm@0 989 case AL_DIRECTION:
rlm@0 990 *pflValue1 = Source->vOrientation[0];
rlm@0 991 *pflValue2 = Source->vOrientation[1];
rlm@0 992 *pflValue3 = Source->vOrientation[2];
rlm@0 993 break;
rlm@0 994
rlm@0 995 default:
rlm@0 996 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 997 break;
rlm@0 998 }
rlm@0 999 }
rlm@0 1000 else
rlm@0 1001 alSetError(pContext, AL_INVALID_NAME);
rlm@0 1002 }
rlm@0 1003 else
rlm@0 1004 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 1005
rlm@0 1006 UnlockContext(pContext);
rlm@0 1007 }
rlm@0 1008
rlm@0 1009
rlm@0 1010 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
rlm@0 1011 {
rlm@0 1012 ALCcontext *pContext;
rlm@0 1013 ALsource *Source;
rlm@0 1014 ALdouble Offsets[2];
rlm@0 1015 ALdouble updateLen;
rlm@0 1016
rlm@0 1017 switch(eParam)
rlm@0 1018 {
rlm@0 1019 case AL_PITCH:
rlm@0 1020 case AL_GAIN:
rlm@0 1021 case AL_MIN_GAIN:
rlm@0 1022 case AL_MAX_GAIN:
rlm@0 1023 case AL_MAX_DISTANCE:
rlm@0 1024 case AL_ROLLOFF_FACTOR:
rlm@0 1025 case AL_DOPPLER_FACTOR:
rlm@0 1026 case AL_CONE_OUTER_GAIN:
rlm@0 1027 case AL_SEC_OFFSET:
rlm@0 1028 case AL_SAMPLE_OFFSET:
rlm@0 1029 case AL_BYTE_OFFSET:
rlm@0 1030 case AL_CONE_INNER_ANGLE:
rlm@0 1031 case AL_CONE_OUTER_ANGLE:
rlm@0 1032 case AL_REFERENCE_DISTANCE:
rlm@0 1033 case AL_CONE_OUTER_GAINHF:
rlm@0 1034 case AL_AIR_ABSORPTION_FACTOR:
rlm@0 1035 case AL_ROOM_ROLLOFF_FACTOR:
rlm@0 1036 alGetSourcef(source, eParam, pflValues);
rlm@0 1037 return;
rlm@0 1038
rlm@0 1039 case AL_POSITION:
rlm@0 1040 case AL_VELOCITY:
rlm@0 1041 case AL_DIRECTION:
rlm@0 1042 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
rlm@0 1043 return;
rlm@0 1044 }
rlm@0 1045
rlm@0 1046 pContext = GetLockedContext();
rlm@0 1047 if(!pContext) return;
rlm@0 1048
rlm@0 1049 if(pflValues)
rlm@0 1050 {
rlm@0 1051 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 1052 {
rlm@0 1053 switch(eParam)
rlm@0 1054 {
rlm@0 1055 case AL_SAMPLE_RW_OFFSETS_SOFT:
rlm@0 1056 case AL_BYTE_RW_OFFSETS_SOFT:
rlm@0 1057 updateLen = (ALdouble)pContext->Device->UpdateSize /
rlm@0 1058 pContext->Device->Frequency;
rlm@0 1059 GetSourceOffset(Source, eParam, Offsets, updateLen);
rlm@0 1060 pflValues[0] = Offsets[0];
rlm@0 1061 pflValues[1] = Offsets[1];
rlm@0 1062 break;
rlm@0 1063
rlm@0 1064 default:
rlm@0 1065 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 1066 break;
rlm@0 1067 }
rlm@0 1068 }
rlm@0 1069 else
rlm@0 1070 alSetError(pContext, AL_INVALID_NAME);
rlm@0 1071 }
rlm@0 1072 else
rlm@0 1073 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 1074
rlm@0 1075 UnlockContext(pContext);
rlm@0 1076 }
rlm@0 1077
rlm@0 1078
rlm@0 1079 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
rlm@0 1080 {
rlm@0 1081 ALCcontext *pContext;
rlm@0 1082 ALsource *Source;
rlm@0 1083 ALdouble Offsets[2];
rlm@0 1084 ALdouble updateLen;
rlm@0 1085
rlm@0 1086 pContext = GetLockedContext();
rlm@0 1087 if(!pContext) return;
rlm@0 1088
rlm@0 1089 if(plValue)
rlm@0 1090 {
rlm@0 1091 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 1092 {
rlm@0 1093 switch(eParam)
rlm@0 1094 {
rlm@0 1095 case AL_MAX_DISTANCE:
rlm@0 1096 *plValue = (ALint)Source->flMaxDistance;
rlm@0 1097 break;
rlm@0 1098
rlm@0 1099 case AL_ROLLOFF_FACTOR:
rlm@0 1100 *plValue = (ALint)Source->flRollOffFactor;
rlm@0 1101 break;
rlm@0 1102
rlm@0 1103 case AL_REFERENCE_DISTANCE:
rlm@0 1104 *plValue = (ALint)Source->flRefDistance;
rlm@0 1105 break;
rlm@0 1106
rlm@0 1107 case AL_SOURCE_RELATIVE:
rlm@0 1108 *plValue = Source->bHeadRelative;
rlm@0 1109 break;
rlm@0 1110
rlm@0 1111 case AL_CONE_INNER_ANGLE:
rlm@0 1112 *plValue = (ALint)Source->flInnerAngle;
rlm@0 1113 break;
rlm@0 1114
rlm@0 1115 case AL_CONE_OUTER_ANGLE:
rlm@0 1116 *plValue = (ALint)Source->flOuterAngle;
rlm@0 1117 break;
rlm@0 1118
rlm@0 1119 case AL_LOOPING:
rlm@0 1120 *plValue = Source->bLooping;
rlm@0 1121 break;
rlm@0 1122
rlm@0 1123 case AL_BUFFER:
rlm@0 1124 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
rlm@0 1125 break;
rlm@0 1126
rlm@0 1127 case AL_SOURCE_STATE:
rlm@0 1128 *plValue = Source->state;
rlm@0 1129 break;
rlm@0 1130
rlm@0 1131 case AL_BUFFERS_QUEUED:
rlm@0 1132 *plValue = Source->BuffersInQueue;
rlm@0 1133 break;
rlm@0 1134
rlm@0 1135 case AL_BUFFERS_PROCESSED:
rlm@0 1136 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
rlm@0 1137 {
rlm@0 1138 /* Buffers on a looping source are in a perpetual state
rlm@0 1139 * of PENDING, so don't report any as PROCESSED */
rlm@0 1140 *plValue = 0;
rlm@0 1141 }
rlm@0 1142 else
rlm@0 1143 *plValue = Source->BuffersPlayed;
rlm@0 1144 break;
rlm@0 1145
rlm@0 1146 case AL_SOURCE_TYPE:
rlm@0 1147 *plValue = Source->lSourceType;
rlm@0 1148 break;
rlm@0 1149
rlm@0 1150 case AL_SEC_OFFSET:
rlm@0 1151 case AL_SAMPLE_OFFSET:
rlm@0 1152 case AL_BYTE_OFFSET:
rlm@0 1153 updateLen = (ALdouble)pContext->Device->UpdateSize /
rlm@0 1154 pContext->Device->Frequency;
rlm@0 1155 GetSourceOffset(Source, eParam, Offsets, updateLen);
rlm@0 1156 *plValue = (ALint)Offsets[0];
rlm@0 1157 break;
rlm@0 1158
rlm@0 1159 case AL_DIRECT_FILTER:
rlm@0 1160 *plValue = Source->DirectFilter.filter;
rlm@0 1161 break;
rlm@0 1162
rlm@0 1163 case AL_DIRECT_FILTER_GAINHF_AUTO:
rlm@0 1164 *plValue = Source->DryGainHFAuto;
rlm@0 1165 break;
rlm@0 1166
rlm@0 1167 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
rlm@0 1168 *plValue = Source->WetGainAuto;
rlm@0 1169 break;
rlm@0 1170
rlm@0 1171 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
rlm@0 1172 *plValue = Source->WetGainHFAuto;
rlm@0 1173 break;
rlm@0 1174
rlm@0 1175 case AL_DOPPLER_FACTOR:
rlm@0 1176 *plValue = (ALint)Source->DopplerFactor;
rlm@0 1177 break;
rlm@0 1178
rlm@0 1179 case AL_VIRTUAL_CHANNELS_SOFT:
rlm@0 1180 *plValue = Source->VirtualChannels;
rlm@0 1181 break;
rlm@0 1182
rlm@0 1183 case AL_DISTANCE_MODEL:
rlm@0 1184 *plValue = Source->DistanceModel;
rlm@0 1185 break;
rlm@0 1186
rlm@0 1187 default:
rlm@0 1188 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 1189 break;
rlm@0 1190 }
rlm@0 1191 }
rlm@0 1192 else
rlm@0 1193 alSetError(pContext, AL_INVALID_NAME);
rlm@0 1194 }
rlm@0 1195 else
rlm@0 1196 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 1197
rlm@0 1198 UnlockContext(pContext);
rlm@0 1199 }
rlm@0 1200
rlm@0 1201
rlm@0 1202 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
rlm@0 1203 {
rlm@0 1204 ALCcontext *pContext;
rlm@0 1205 ALsource *Source;
rlm@0 1206
rlm@0 1207 pContext = GetLockedContext();
rlm@0 1208 if(!pContext) return;
rlm@0 1209
rlm@0 1210 if(plValue1 && plValue2 && plValue3)
rlm@0 1211 {
rlm@0 1212 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 1213 {
rlm@0 1214 switch(eParam)
rlm@0 1215 {
rlm@0 1216 case AL_POSITION:
rlm@0 1217 *plValue1 = (ALint)Source->vPosition[0];
rlm@0 1218 *plValue2 = (ALint)Source->vPosition[1];
rlm@0 1219 *plValue3 = (ALint)Source->vPosition[2];
rlm@0 1220 break;
rlm@0 1221
rlm@0 1222 case AL_VELOCITY:
rlm@0 1223 *plValue1 = (ALint)Source->vVelocity[0];
rlm@0 1224 *plValue2 = (ALint)Source->vVelocity[1];
rlm@0 1225 *plValue3 = (ALint)Source->vVelocity[2];
rlm@0 1226 break;
rlm@0 1227
rlm@0 1228 case AL_DIRECTION:
rlm@0 1229 *plValue1 = (ALint)Source->vOrientation[0];
rlm@0 1230 *plValue2 = (ALint)Source->vOrientation[1];
rlm@0 1231 *plValue3 = (ALint)Source->vOrientation[2];
rlm@0 1232 break;
rlm@0 1233
rlm@0 1234 default:
rlm@0 1235 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 1236 break;
rlm@0 1237 }
rlm@0 1238 }
rlm@0 1239 else
rlm@0 1240 alSetError(pContext, AL_INVALID_NAME);
rlm@0 1241 }
rlm@0 1242 else
rlm@0 1243 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 1244
rlm@0 1245 UnlockContext(pContext);
rlm@0 1246 }
rlm@0 1247
rlm@0 1248
rlm@0 1249 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
rlm@0 1250 {
rlm@0 1251 ALCcontext *pContext;
rlm@0 1252 ALsource *Source;
rlm@0 1253 ALdouble Offsets[2];
rlm@0 1254 ALdouble updateLen;
rlm@0 1255
rlm@0 1256 switch(eParam)
rlm@0 1257 {
rlm@0 1258 case AL_SOURCE_RELATIVE:
rlm@0 1259 case AL_CONE_INNER_ANGLE:
rlm@0 1260 case AL_CONE_OUTER_ANGLE:
rlm@0 1261 case AL_LOOPING:
rlm@0 1262 case AL_BUFFER:
rlm@0 1263 case AL_SOURCE_STATE:
rlm@0 1264 case AL_BUFFERS_QUEUED:
rlm@0 1265 case AL_BUFFERS_PROCESSED:
rlm@0 1266 case AL_SEC_OFFSET:
rlm@0 1267 case AL_SAMPLE_OFFSET:
rlm@0 1268 case AL_BYTE_OFFSET:
rlm@0 1269 case AL_MAX_DISTANCE:
rlm@0 1270 case AL_ROLLOFF_FACTOR:
rlm@0 1271 case AL_DOPPLER_FACTOR:
rlm@0 1272 case AL_REFERENCE_DISTANCE:
rlm@0 1273 case AL_SOURCE_TYPE:
rlm@0 1274 case AL_DIRECT_FILTER:
rlm@0 1275 case AL_DIRECT_FILTER_GAINHF_AUTO:
rlm@0 1276 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
rlm@0 1277 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
rlm@0 1278 case AL_DISTANCE_MODEL:
rlm@0 1279 case AL_VIRTUAL_CHANNELS_SOFT:
rlm@0 1280 alGetSourcei(source, eParam, plValues);
rlm@0 1281 return;
rlm@0 1282
rlm@0 1283 case AL_POSITION:
rlm@0 1284 case AL_VELOCITY:
rlm@0 1285 case AL_DIRECTION:
rlm@0 1286 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
rlm@0 1287 return;
rlm@0 1288 }
rlm@0 1289
rlm@0 1290 pContext = GetLockedContext();
rlm@0 1291 if(!pContext) return;
rlm@0 1292
rlm@0 1293 if(plValues)
rlm@0 1294 {
rlm@0 1295 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
rlm@0 1296 {
rlm@0 1297 switch(eParam)
rlm@0 1298 {
rlm@0 1299 case AL_SAMPLE_RW_OFFSETS_SOFT:
rlm@0 1300 case AL_BYTE_RW_OFFSETS_SOFT:
rlm@0 1301 updateLen = (ALdouble)pContext->Device->UpdateSize /
rlm@0 1302 pContext->Device->Frequency;
rlm@0 1303 GetSourceOffset(Source, eParam, Offsets, updateLen);
rlm@0 1304 plValues[0] = (ALint)Offsets[0];
rlm@0 1305 plValues[1] = (ALint)Offsets[1];
rlm@0 1306 break;
rlm@0 1307
rlm@0 1308 default:
rlm@0 1309 alSetError(pContext, AL_INVALID_ENUM);
rlm@0 1310 break;
rlm@0 1311 }
rlm@0 1312 }
rlm@0 1313 else
rlm@0 1314 alSetError(pContext, AL_INVALID_NAME);
rlm@0 1315 }
rlm@0 1316 else
rlm@0 1317 alSetError(pContext, AL_INVALID_VALUE);
rlm@0 1318
rlm@0 1319 UnlockContext(pContext);
rlm@0 1320 }
rlm@0 1321
rlm@0 1322
rlm@0 1323 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
rlm@0 1324 {
rlm@0 1325 alSourcePlayv(1, &source);
rlm@0 1326 }
rlm@0 1327
rlm@0 1328 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
rlm@0 1329 {
rlm@0 1330 ALCcontext *Context;
rlm@0 1331 ALsource *Source;
rlm@0 1332 ALsizei i;
rlm@0 1333
rlm@0 1334 Context = GetLockedContext();
rlm@0 1335 if(!Context) return;
rlm@0 1336
rlm@0 1337 if(n < 0)
rlm@0 1338 {
rlm@0 1339 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1340 goto done;
rlm@0 1341 }
rlm@0 1342 if(n > 0 && !sources)
rlm@0 1343 {
rlm@0 1344 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1345 goto done;
rlm@0 1346 }
rlm@0 1347
rlm@0 1348 // Check that all the Sources are valid
rlm@0 1349 for(i = 0;i < n;i++)
rlm@0 1350 {
rlm@0 1351 if(!LookupSource(Context->SourceMap, sources[i]))
rlm@0 1352 {
rlm@0 1353 alSetError(Context, AL_INVALID_NAME);
rlm@0 1354 goto done;
rlm@0 1355 }
rlm@0 1356 }
rlm@0 1357
rlm@0 1358 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
rlm@0 1359 {
rlm@0 1360 void *temp = NULL;
rlm@0 1361 ALsizei newcount;
rlm@0 1362
rlm@0 1363 newcount = Context->MaxActiveSources << 1;
rlm@0 1364 if(newcount > 0)
rlm@0 1365 temp = realloc(Context->ActiveSources,
rlm@0 1366 sizeof(*Context->ActiveSources) * newcount);
rlm@0 1367 if(!temp)
rlm@0 1368 {
rlm@0 1369 alSetError(Context, AL_OUT_OF_MEMORY);
rlm@0 1370 goto done;
rlm@0 1371 }
rlm@0 1372
rlm@0 1373 Context->ActiveSources = temp;
rlm@0 1374 Context->MaxActiveSources = newcount;
rlm@0 1375 }
rlm@0 1376
rlm@0 1377 for(i = 0;i < n;i++)
rlm@0 1378 {
rlm@0 1379 Source = LookupSource(Context->SourceMap, sources[i]);
rlm@0 1380 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
rlm@0 1381 else SetSourceState(Source, Context, AL_PLAYING);
rlm@0 1382 }
rlm@0 1383
rlm@0 1384 done:
rlm@0 1385 UnlockContext(Context);
rlm@0 1386 }
rlm@0 1387
rlm@0 1388 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
rlm@0 1389 {
rlm@0 1390 alSourcePausev(1, &source);
rlm@0 1391 }
rlm@0 1392
rlm@0 1393 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
rlm@0 1394 {
rlm@0 1395 ALCcontext *Context;
rlm@0 1396 ALsource *Source;
rlm@0 1397 ALsizei i;
rlm@0 1398
rlm@0 1399 Context = GetLockedContext();
rlm@0 1400 if(!Context) return;
rlm@0 1401
rlm@0 1402 if(n < 0)
rlm@0 1403 {
rlm@0 1404 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1405 goto done;
rlm@0 1406 }
rlm@0 1407 if(n > 0 && !sources)
rlm@0 1408 {
rlm@0 1409 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1410 goto done;
rlm@0 1411 }
rlm@0 1412
rlm@0 1413 // Check all the Sources are valid
rlm@0 1414 for(i = 0;i < n;i++)
rlm@0 1415 {
rlm@0 1416 if(!LookupSource(Context->SourceMap, sources[i]))
rlm@0 1417 {
rlm@0 1418 alSetError(Context, AL_INVALID_NAME);
rlm@0 1419 goto done;
rlm@0 1420 }
rlm@0 1421 }
rlm@0 1422
rlm@0 1423 for(i = 0;i < n;i++)
rlm@0 1424 {
rlm@0 1425 Source = LookupSource(Context->SourceMap, sources[i]);
rlm@0 1426 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
rlm@0 1427 else SetSourceState(Source, Context, AL_PAUSED);
rlm@0 1428 }
rlm@0 1429
rlm@0 1430 done:
rlm@0 1431 UnlockContext(Context);
rlm@0 1432 }
rlm@0 1433
rlm@0 1434 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
rlm@0 1435 {
rlm@0 1436 alSourceStopv(1, &source);
rlm@0 1437 }
rlm@0 1438
rlm@0 1439 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
rlm@0 1440 {
rlm@0 1441 ALCcontext *Context;
rlm@0 1442 ALsource *Source;
rlm@0 1443 ALsizei i;
rlm@0 1444
rlm@0 1445 Context = GetLockedContext();
rlm@0 1446 if(!Context) return;
rlm@0 1447
rlm@0 1448 if(n < 0)
rlm@0 1449 {
rlm@0 1450 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1451 goto done;
rlm@0 1452 }
rlm@0 1453 if(n > 0 && !sources)
rlm@0 1454 {
rlm@0 1455 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1456 goto done;
rlm@0 1457 }
rlm@0 1458
rlm@0 1459 // Check all the Sources are valid
rlm@0 1460 for(i = 0;i < n;i++)
rlm@0 1461 {
rlm@0 1462 if(!LookupSource(Context->SourceMap, sources[i]))
rlm@0 1463 {
rlm@0 1464 alSetError(Context, AL_INVALID_NAME);
rlm@0 1465 goto done;
rlm@0 1466 }
rlm@0 1467 }
rlm@0 1468
rlm@0 1469 for(i = 0;i < n;i++)
rlm@0 1470 {
rlm@0 1471 Source = LookupSource(Context->SourceMap, sources[i]);
rlm@0 1472 if(Context->DeferUpdates) Source->new_state = AL_STOPPED;
rlm@0 1473 else SetSourceState(Source, Context, AL_STOPPED);
rlm@0 1474 }
rlm@0 1475
rlm@0 1476 done:
rlm@0 1477 UnlockContext(Context);
rlm@0 1478 }
rlm@0 1479
rlm@0 1480 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
rlm@0 1481 {
rlm@0 1482 alSourceRewindv(1, &source);
rlm@0 1483 }
rlm@0 1484
rlm@0 1485 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
rlm@0 1486 {
rlm@0 1487 ALCcontext *Context;
rlm@0 1488 ALsource *Source;
rlm@0 1489 ALsizei i;
rlm@0 1490
rlm@0 1491 Context = GetLockedContext();
rlm@0 1492 if(!Context) return;
rlm@0 1493
rlm@0 1494 if(n < 0)
rlm@0 1495 {
rlm@0 1496 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1497 goto done;
rlm@0 1498 }
rlm@0 1499 if(n > 0 && !sources)
rlm@0 1500 {
rlm@0 1501 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1502 goto done;
rlm@0 1503 }
rlm@0 1504
rlm@0 1505 // Check all the Sources are valid
rlm@0 1506 for(i = 0;i < n;i++)
rlm@0 1507 {
rlm@0 1508 if(!LookupSource(Context->SourceMap, sources[i]))
rlm@0 1509 {
rlm@0 1510 alSetError(Context, AL_INVALID_NAME);
rlm@0 1511 goto done;
rlm@0 1512 }
rlm@0 1513 }
rlm@0 1514
rlm@0 1515 for(i = 0;i < n;i++)
rlm@0 1516 {
rlm@0 1517 Source = LookupSource(Context->SourceMap, sources[i]);
rlm@0 1518 if(Context->DeferUpdates) Source->new_state = AL_INITIAL;
rlm@0 1519 else SetSourceState(Source, Context, AL_INITIAL);
rlm@0 1520 }
rlm@0 1521
rlm@0 1522 done:
rlm@0 1523 UnlockContext(Context);
rlm@0 1524 }
rlm@0 1525
rlm@0 1526
rlm@0 1527 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
rlm@0 1528 {
rlm@0 1529 ALCcontext *Context;
rlm@0 1530 ALCdevice *device;
rlm@0 1531 ALsource *Source;
rlm@0 1532 ALbuffer *buffer;
rlm@0 1533 ALsizei i;
rlm@0 1534 ALbufferlistitem *BufferListStart;
rlm@0 1535 ALbufferlistitem *BufferList;
rlm@0 1536 ALbuffer *BufferFmt;
rlm@0 1537
rlm@0 1538 if(n == 0)
rlm@0 1539 return;
rlm@0 1540
rlm@0 1541 Context = GetLockedContext();
rlm@0 1542 if(!Context) return;
rlm@0 1543
rlm@0 1544 if(n < 0)
rlm@0 1545 {
rlm@0 1546 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1547 goto done;
rlm@0 1548 }
rlm@0 1549
rlm@0 1550 // Check that all buffers are valid or zero and that the source is valid
rlm@0 1551
rlm@0 1552 // Check that this is a valid source
rlm@0 1553 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
rlm@0 1554 {
rlm@0 1555 alSetError(Context, AL_INVALID_NAME);
rlm@0 1556 goto done;
rlm@0 1557 }
rlm@0 1558
rlm@0 1559 // Check that this is not a STATIC Source
rlm@0 1560 if(Source->lSourceType == AL_STATIC)
rlm@0 1561 {
rlm@0 1562 // Invalid Source Type (can't queue on a Static Source)
rlm@0 1563 alSetError(Context, AL_INVALID_OPERATION);
rlm@0 1564 goto done;
rlm@0 1565 }
rlm@0 1566
rlm@0 1567 device = Context->Device;
rlm@0 1568
rlm@0 1569 BufferFmt = NULL;
rlm@0 1570
rlm@0 1571 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
rlm@0 1572 BufferList = Source->queue;
rlm@0 1573 while(BufferList)
rlm@0 1574 {
rlm@0 1575 if(BufferList->buffer)
rlm@0 1576 {
rlm@0 1577 BufferFmt = BufferList->buffer;
rlm@0 1578 break;
rlm@0 1579 }
rlm@0 1580 BufferList = BufferList->next;
rlm@0 1581 }
rlm@0 1582
rlm@0 1583 for(i = 0;i < n;i++)
rlm@0 1584 {
rlm@0 1585 if(!buffers[i])
rlm@0 1586 continue;
rlm@0 1587
rlm@0 1588 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
rlm@0 1589 {
rlm@0 1590 alSetError(Context, AL_INVALID_NAME);
rlm@0 1591 goto done;
rlm@0 1592 }
rlm@0 1593
rlm@0 1594 if(BufferFmt == NULL)
rlm@0 1595 {
rlm@0 1596 BufferFmt = buffer;
rlm@0 1597
rlm@0 1598 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
rlm@0 1599 Source->SampleSize = BytesFromFmt(buffer->FmtType);
rlm@0 1600 if(buffer->FmtChannels == FmtMono)
rlm@0 1601 Source->Update = CalcSourceParams;
rlm@0 1602 else
rlm@0 1603 Source->Update = CalcNonAttnSourceParams;
rlm@0 1604
rlm@0 1605 Source->NeedsUpdate = AL_TRUE;
rlm@0 1606 }
rlm@0 1607 else if(BufferFmt->Frequency != buffer->Frequency ||
rlm@0 1608 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
rlm@0 1609 BufferFmt->OriginalType != buffer->OriginalType)
rlm@0 1610 {
rlm@0 1611 alSetError(Context, AL_INVALID_OPERATION);
rlm@0 1612 goto done;
rlm@0 1613 }
rlm@0 1614 }
rlm@0 1615
rlm@0 1616 // Change Source Type
rlm@0 1617 Source->lSourceType = AL_STREAMING;
rlm@0 1618
rlm@0 1619 buffer = LookupBuffer(device->BufferMap, buffers[0]);
rlm@0 1620
rlm@0 1621 // All buffers are valid - so add them to the list
rlm@0 1622 BufferListStart = malloc(sizeof(ALbufferlistitem));
rlm@0 1623 BufferListStart->buffer = buffer;
rlm@0 1624 BufferListStart->next = NULL;
rlm@0 1625 BufferListStart->prev = NULL;
rlm@0 1626
rlm@0 1627 // Increment reference counter for buffer
rlm@0 1628 if(buffer) buffer->refcount++;
rlm@0 1629
rlm@0 1630 BufferList = BufferListStart;
rlm@0 1631
rlm@0 1632 for(i = 1;i < n;i++)
rlm@0 1633 {
rlm@0 1634 buffer = LookupBuffer(device->BufferMap, buffers[i]);
rlm@0 1635
rlm@0 1636 BufferList->next = malloc(sizeof(ALbufferlistitem));
rlm@0 1637 BufferList->next->buffer = buffer;
rlm@0 1638 BufferList->next->next = NULL;
rlm@0 1639 BufferList->next->prev = BufferList;
rlm@0 1640
rlm@0 1641 // Increment reference counter for buffer
rlm@0 1642 if(buffer) buffer->refcount++;
rlm@0 1643
rlm@0 1644 BufferList = BufferList->next;
rlm@0 1645 }
rlm@0 1646
rlm@0 1647 if(Source->queue == NULL)
rlm@0 1648 {
rlm@0 1649 Source->queue = BufferListStart;
rlm@0 1650 // Update Current Buffer
rlm@0 1651 Source->Buffer = BufferListStart->buffer;
rlm@0 1652 }
rlm@0 1653 else
rlm@0 1654 {
rlm@0 1655 // Find end of queue
rlm@0 1656 BufferList = Source->queue;
rlm@0 1657 while(BufferList->next != NULL)
rlm@0 1658 BufferList = BufferList->next;
rlm@0 1659
rlm@0 1660 BufferList->next = BufferListStart;
rlm@0 1661 BufferList->next->prev = BufferList;
rlm@0 1662 }
rlm@0 1663
rlm@0 1664 // Update number of buffers in queue
rlm@0 1665 Source->BuffersInQueue += n;
rlm@0 1666
rlm@0 1667 done:
rlm@0 1668 UnlockContext(Context);
rlm@0 1669 }
rlm@0 1670
rlm@0 1671
rlm@0 1672 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
rlm@0 1673 // an array of buffer IDs that are to be filled with the names of the buffers removed
rlm@0 1674 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
rlm@0 1675 {
rlm@0 1676 ALCcontext *Context;
rlm@0 1677 ALsource *Source;
rlm@0 1678 ALsizei i;
rlm@0 1679 ALbufferlistitem *BufferList;
rlm@0 1680
rlm@0 1681 if(n == 0)
rlm@0 1682 return;
rlm@0 1683
rlm@0 1684 Context = GetLockedContext();
rlm@0 1685 if(!Context) return;
rlm@0 1686
rlm@0 1687 if(n < 0)
rlm@0 1688 {
rlm@0 1689 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1690 goto done;
rlm@0 1691 }
rlm@0 1692
rlm@0 1693 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
rlm@0 1694 {
rlm@0 1695 alSetError(Context, AL_INVALID_NAME);
rlm@0 1696 goto done;
rlm@0 1697 }
rlm@0 1698
rlm@0 1699 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
rlm@0 1700 (ALuint)n > Source->BuffersPlayed)
rlm@0 1701 {
rlm@0 1702 // Some buffers can't be unqueue because they have not been processed
rlm@0 1703 alSetError(Context, AL_INVALID_VALUE);
rlm@0 1704 goto done;
rlm@0 1705 }
rlm@0 1706
rlm@0 1707 for(i = 0;i < n;i++)
rlm@0 1708 {
rlm@0 1709 BufferList = Source->queue;
rlm@0 1710 Source->queue = BufferList->next;
rlm@0 1711
rlm@0 1712 if(BufferList->buffer)
rlm@0 1713 {
rlm@0 1714 // Record name of buffer
rlm@0 1715 buffers[i] = BufferList->buffer->buffer;
rlm@0 1716 // Decrement buffer reference counter
rlm@0 1717 BufferList->buffer->refcount--;
rlm@0 1718 }
rlm@0 1719 else
rlm@0 1720 buffers[i] = 0;
rlm@0 1721
rlm@0 1722 // Release memory for buffer list item
rlm@0 1723 free(BufferList);
rlm@0 1724 Source->BuffersInQueue--;
rlm@0 1725 }
rlm@0 1726 if(Source->queue)
rlm@0 1727 Source->queue->prev = NULL;
rlm@0 1728
rlm@0 1729 if(Source->state != AL_PLAYING)
rlm@0 1730 {
rlm@0 1731 if(Source->queue)
rlm@0 1732 Source->Buffer = Source->queue->buffer;
rlm@0 1733 else
rlm@0 1734 Source->Buffer = NULL;
rlm@0 1735 }
rlm@0 1736 Source->BuffersPlayed -= n;
rlm@0 1737
rlm@0 1738 done:
rlm@0 1739 UnlockContext(Context);
rlm@0 1740 }
rlm@0 1741
rlm@0 1742
rlm@0 1743 static ALvoid InitSourceParams(ALsource *Source)
rlm@0 1744 {
rlm@0 1745 Source->flInnerAngle = 360.0f;
rlm@0 1746 Source->flOuterAngle = 360.0f;
rlm@0 1747 Source->flPitch = 1.0f;
rlm@0 1748 Source->vPosition[0] = 0.0f;
rlm@0 1749 Source->vPosition[1] = 0.0f;
rlm@0 1750 Source->vPosition[2] = 0.0f;
rlm@0 1751 Source->vOrientation[0] = 0.0f;
rlm@0 1752 Source->vOrientation[1] = 0.0f;
rlm@0 1753 Source->vOrientation[2] = 0.0f;
rlm@0 1754 Source->vVelocity[0] = 0.0f;
rlm@0 1755 Source->vVelocity[1] = 0.0f;
rlm@0 1756 Source->vVelocity[2] = 0.0f;
rlm@0 1757 Source->flRefDistance = 1.0f;
rlm@0 1758 Source->flMaxDistance = FLT_MAX;
rlm@0 1759 Source->flRollOffFactor = 1.0f;
rlm@0 1760 Source->bLooping = AL_FALSE;
rlm@0 1761 Source->flGain = 1.0f;
rlm@0 1762 Source->flMinGain = 0.0f;
rlm@0 1763 Source->flMaxGain = 1.0f;
rlm@0 1764 Source->flOuterGain = 0.0f;
rlm@0 1765 Source->OuterGainHF = 1.0f;
rlm@0 1766
rlm@0 1767 Source->DryGainHFAuto = AL_TRUE;
rlm@0 1768 Source->WetGainAuto = AL_TRUE;
rlm@0 1769 Source->WetGainHFAuto = AL_TRUE;
rlm@0 1770 Source->AirAbsorptionFactor = 0.0f;
rlm@0 1771 Source->RoomRolloffFactor = 0.0f;
rlm@0 1772 Source->DopplerFactor = 1.0f;
rlm@0 1773 Source->VirtualChannels = AL_TRUE;
rlm@0 1774
rlm@0 1775 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
rlm@0 1776
rlm@0 1777 Source->Resampler = DefaultResampler;
rlm@0 1778
rlm@0 1779 Source->state = AL_INITIAL;
rlm@0 1780 Source->new_state = AL_NONE;
rlm@0 1781 Source->lSourceType = AL_UNDETERMINED;
rlm@0 1782 Source->lOffset = -1;
rlm@0 1783
rlm@0 1784 Source->NeedsUpdate = AL_TRUE;
rlm@0 1785
rlm@0 1786 Source->Buffer = NULL;
rlm@0 1787
rlm@0 1788 Source->HrtfMoving = AL_FALSE;
rlm@0 1789 Source->HrtfCounter = 0;
rlm@0 1790 }
rlm@0 1791
rlm@0 1792
rlm@0 1793 /*
rlm@0 1794 * SetSourceState
rlm@0 1795 *
rlm@0 1796 * Sets the source's new play state given its current state
rlm@0 1797 */
rlm@0 1798 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
rlm@0 1799 {
rlm@0 1800 if(state == AL_PLAYING)
rlm@0 1801 {
rlm@0 1802 ALbufferlistitem *BufferList;
rlm@0 1803 ALsizei j, k;
rlm@0 1804
rlm@0 1805 /* Check that there is a queue containing at least one non-null, non zero length AL Buffer */
rlm@0 1806 BufferList = Source->queue;
rlm@0 1807 while(BufferList)
rlm@0 1808 {
rlm@0 1809 if(BufferList->buffer != NULL && BufferList->buffer->size)
rlm@0 1810 break;
rlm@0 1811 BufferList = BufferList->next;
rlm@0 1812 }
rlm@0 1813
rlm@0 1814 /* If there's nothing to play, or device is disconnected, go right to
rlm@0 1815 * stopped */
rlm@0 1816 if(!BufferList || !Context->Device->Connected)
rlm@0 1817 {
rlm@0 1818 SetSourceState(Source, Context, AL_STOPPED);
rlm@0 1819 return;
rlm@0 1820 }
rlm@0 1821
rlm@0 1822 if(Source->state != AL_PLAYING)
rlm@0 1823 {
rlm@0 1824 for(j = 0;j < MAXCHANNELS;j++)
rlm@0 1825 {
rlm@0 1826 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
rlm@0 1827 Source->HrtfHistory[j][k] = 0.0f;
rlm@0 1828 for(k = 0;k < HRIR_LENGTH;k++)
rlm@0 1829 {
rlm@0 1830 Source->HrtfValues[j][k][0] = 0.0f;
rlm@0 1831 Source->HrtfValues[j][k][1] = 0.0f;
rlm@0 1832 }
rlm@0 1833 }
rlm@0 1834 }
rlm@0 1835
rlm@0 1836 if(Source->state != AL_PAUSED)
rlm@0 1837 {
rlm@0 1838 Source->state = AL_PLAYING;
rlm@0 1839 Source->position = 0;
rlm@0 1840 Source->position_fraction = 0;
rlm@0 1841 Source->BuffersPlayed = 0;
rlm@0 1842
rlm@0 1843 Source->Buffer = Source->queue->buffer;
rlm@0 1844 }
rlm@0 1845 else
rlm@0 1846 Source->state = AL_PLAYING;
rlm@0 1847
rlm@0 1848 // Check if an Offset has been set
rlm@0 1849 if(Source->lOffset != -1)
rlm@0 1850 ApplyOffset(Source);
rlm@0 1851
rlm@0 1852 for(j = 0;j < Context->ActiveSourceCount;j++)
rlm@0 1853 {
rlm@0 1854 if(Context->ActiveSources[j] == Source)
rlm@0 1855 break;
rlm@0 1856 }
rlm@0 1857 if(j == Context->ActiveSourceCount)
rlm@0 1858 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
rlm@0 1859 }
rlm@0 1860 else if(state == AL_PAUSED)
rlm@0 1861 {
rlm@0 1862 if(Source->state == AL_PLAYING)
rlm@0 1863 {
rlm@0 1864 Source->state = AL_PAUSED;
rlm@0 1865 Source->HrtfMoving = AL_FALSE;
rlm@0 1866 Source->HrtfCounter = 0;
rlm@0 1867 }
rlm@0 1868 }
rlm@0 1869 else if(state == AL_STOPPED)
rlm@0 1870 {
rlm@0 1871 if(Source->state != AL_INITIAL)
rlm@0 1872 {
rlm@0 1873 Source->state = AL_STOPPED;
rlm@0 1874 Source->BuffersPlayed = Source->BuffersInQueue;
rlm@0 1875 Source->HrtfMoving = AL_FALSE;
rlm@0 1876 Source->HrtfCounter = 0;
rlm@0 1877 }
rlm@0 1878 Source->lOffset = -1;
rlm@0 1879 }
rlm@0 1880 else if(state == AL_INITIAL)
rlm@0 1881 {
rlm@0 1882 if(Source->state != AL_INITIAL)
rlm@0 1883 {
rlm@0 1884 Source->state = AL_INITIAL;
rlm@0 1885 Source->position = 0;
rlm@0 1886 Source->position_fraction = 0;
rlm@0 1887 Source->BuffersPlayed = 0;
rlm@0 1888 if(Source->queue)
rlm@0 1889 Source->Buffer = Source->queue->buffer;
rlm@0 1890 Source->HrtfMoving = AL_FALSE;
rlm@0 1891 Source->HrtfCounter = 0;
rlm@0 1892 }
rlm@0 1893 Source->lOffset = -1;
rlm@0 1894 }
rlm@0 1895 }
rlm@0 1896
rlm@0 1897 /*
rlm@0 1898 GetSourceOffset
rlm@0 1899
rlm@0 1900 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
rlm@0 1901 The offset is relative to the start of the queue (not the start of the current buffer)
rlm@0 1902 */
rlm@0 1903 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
rlm@0 1904 {
rlm@0 1905 const ALbufferlistitem *BufferList;
rlm@0 1906 const ALbuffer *Buffer = NULL;
rlm@0 1907 enum UserFmtType OriginalType;
rlm@0 1908 ALsizei BufferFreq;
rlm@0 1909 ALint Channels, Bytes;
rlm@0 1910 ALuint readPos, writePos;
rlm@0 1911 ALuint TotalBufferDataSize;
rlm@0 1912 ALuint i;
rlm@0 1913
rlm@0 1914 // Find the first non-NULL Buffer in the Queue
rlm@0 1915 BufferList = Source->queue;
rlm@0 1916 while(BufferList)
rlm@0 1917 {
rlm@0 1918 if(BufferList->buffer)
rlm@0 1919 {
rlm@0 1920 Buffer = BufferList->buffer;
rlm@0 1921 break;
rlm@0 1922 }
rlm@0 1923 BufferList = BufferList->next;
rlm@0 1924 }
rlm@0 1925
rlm@0 1926 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
rlm@0 1927 {
rlm@0 1928 offset[0] = 0.0;
rlm@0 1929 offset[1] = 0.0;
rlm@0 1930 return;
rlm@0 1931 }
rlm@0 1932
rlm@0 1933 // Get Current Buffer Size and frequency (in milliseconds)
rlm@0 1934 BufferFreq = Buffer->Frequency;
rlm@0 1935 OriginalType = Buffer->OriginalType;
rlm@0 1936 Channels = ChannelsFromFmt(Buffer->FmtChannels);
rlm@0 1937 Bytes = BytesFromFmt(Buffer->FmtType);
rlm@0 1938
rlm@0 1939 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
rlm@0 1940 readPos = Source->position * Channels * Bytes;
rlm@0 1941 // Add byte length of any processed buffers in the queue
rlm@0 1942 TotalBufferDataSize = 0;
rlm@0 1943 BufferList = Source->queue;
rlm@0 1944 for(i = 0;BufferList;i++)
rlm@0 1945 {
rlm@0 1946 if(BufferList->buffer)
rlm@0 1947 {
rlm@0 1948 if(i < Source->BuffersPlayed)
rlm@0 1949 readPos += BufferList->buffer->size;
rlm@0 1950 TotalBufferDataSize += BufferList->buffer->size;
rlm@0 1951 }
rlm@0 1952 BufferList = BufferList->next;
rlm@0 1953 }
rlm@0 1954 if(Source->state == AL_PLAYING)
rlm@0 1955 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
rlm@0 1956 else
rlm@0 1957 writePos = readPos;
rlm@0 1958
rlm@0 1959 if(Source->bLooping)
rlm@0 1960 {
rlm@0 1961 readPos %= TotalBufferDataSize;
rlm@0 1962 writePos %= TotalBufferDataSize;
rlm@0 1963 }
rlm@0 1964 else
rlm@0 1965 {
rlm@0 1966 // Wrap positions back to 0
rlm@0 1967 if(readPos >= TotalBufferDataSize)
rlm@0 1968 readPos = 0;
rlm@0 1969 if(writePos >= TotalBufferDataSize)
rlm@0 1970 writePos = 0;
rlm@0 1971 }
rlm@0 1972
rlm@0 1973 switch(name)
rlm@0 1974 {
rlm@0 1975 case AL_SEC_OFFSET:
rlm@0 1976 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
rlm@0 1977 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
rlm@0 1978 break;
rlm@0 1979 case AL_SAMPLE_OFFSET:
rlm@0 1980 case AL_SAMPLE_RW_OFFSETS_SOFT:
rlm@0 1981 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
rlm@0 1982 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
rlm@0 1983 break;
rlm@0 1984 case AL_BYTE_OFFSET:
rlm@0 1985 case AL_BYTE_RW_OFFSETS_SOFT:
rlm@0 1986 // Take into account the original format of the Buffer
rlm@0 1987 if(OriginalType == UserFmtIMA4)
rlm@0 1988 {
rlm@0 1989 ALuint FrameBlockSize = 65 * Bytes * Channels;
rlm@0 1990 ALuint BlockSize = 36 * Channels;
rlm@0 1991
rlm@0 1992 // Round down to nearest ADPCM block
rlm@0 1993 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
rlm@0 1994 if(Source->state != AL_PLAYING)
rlm@0 1995 offset[1] = offset[0];
rlm@0 1996 else
rlm@0 1997 {
rlm@0 1998 // Round up to nearest ADPCM block
rlm@0 1999 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
rlm@0 2000 FrameBlockSize * BlockSize);
rlm@0 2001 }
rlm@0 2002 }
rlm@0 2003 else
rlm@0 2004 {
rlm@0 2005 ALuint OrigBytes = BytesFromUserFmt(OriginalType);
rlm@0 2006 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
rlm@0 2007 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
rlm@0 2008 }
rlm@0 2009 break;
rlm@0 2010 }
rlm@0 2011 }
rlm@0 2012
rlm@0 2013
rlm@0 2014 /*
rlm@0 2015 ApplyOffset
rlm@0 2016
rlm@0 2017 Apply a playback offset to the Source. This function will update the queue (to correctly
rlm@0 2018 mark buffers as 'pending' or 'processed' depending upon the new offset.
rlm@0 2019 */
rlm@0 2020 ALboolean ApplyOffset(ALsource *Source)
rlm@0 2021 {
rlm@0 2022 const ALbufferlistitem *BufferList;
rlm@0 2023 const ALbuffer *Buffer;
rlm@0 2024 ALint lBufferSize, lTotalBufferSize;
rlm@0 2025 ALint BuffersPlayed;
rlm@0 2026 ALint lByteOffset;
rlm@0 2027
rlm@0 2028 // Get true byte offset
rlm@0 2029 lByteOffset = GetByteOffset(Source);
rlm@0 2030
rlm@0 2031 // If the offset is invalid, don't apply it
rlm@0 2032 if(lByteOffset == -1)
rlm@0 2033 return AL_FALSE;
rlm@0 2034
rlm@0 2035 // Sort out the queue (pending and processed states)
rlm@0 2036 BufferList = Source->queue;
rlm@0 2037 lTotalBufferSize = 0;
rlm@0 2038 BuffersPlayed = 0;
rlm@0 2039
rlm@0 2040 while(BufferList)
rlm@0 2041 {
rlm@0 2042 Buffer = BufferList->buffer;
rlm@0 2043 lBufferSize = Buffer ? Buffer->size : 0;
rlm@0 2044
rlm@0 2045 if(lBufferSize <= lByteOffset-lTotalBufferSize)
rlm@0 2046 {
rlm@0 2047 // Offset is past this buffer so increment BuffersPlayed
rlm@0 2048 BuffersPlayed++;
rlm@0 2049 }
rlm@0 2050 else if(lTotalBufferSize <= lByteOffset)
rlm@0 2051 {
rlm@0 2052 // Offset is within this buffer
rlm@0 2053 // Set Current Buffer
rlm@0 2054 Source->Buffer = BufferList->buffer;
rlm@0 2055 Source->BuffersPlayed = BuffersPlayed;
rlm@0 2056
rlm@0 2057 // SW Mixer Positions are in Samples
rlm@0 2058 Source->position = (lByteOffset - lTotalBufferSize) /
rlm@0 2059 FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
rlm@0 2060 return AL_TRUE;
rlm@0 2061 }
rlm@0 2062
rlm@0 2063 // Increment the TotalBufferSize
rlm@0 2064 lTotalBufferSize += lBufferSize;
rlm@0 2065
rlm@0 2066 // Move on to next buffer in the Queue
rlm@0 2067 BufferList = BufferList->next;
rlm@0 2068 }
rlm@0 2069 // Offset is out of range of the buffer queue
rlm@0 2070 return AL_FALSE;
rlm@0 2071 }
rlm@0 2072
rlm@0 2073
rlm@0 2074 /*
rlm@0 2075 GetByteOffset
rlm@0 2076
rlm@0 2077 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
rlm@0 2078 offset supplied by the application). This takes into account the fact that the buffer format
rlm@0 2079 may have been modifed by AL (e.g 8bit samples are converted to float)
rlm@0 2080 */
rlm@0 2081 static ALint GetByteOffset(ALsource *Source)
rlm@0 2082 {
rlm@0 2083 const ALbuffer *Buffer = NULL;
rlm@0 2084 const ALbufferlistitem *BufferList;
rlm@0 2085 ALint ByteOffset = -1;
rlm@0 2086
rlm@0 2087 // Find the first non-NULL Buffer in the Queue
rlm@0 2088 BufferList = Source->queue;
rlm@0 2089 while(BufferList)
rlm@0 2090 {
rlm@0 2091 if(BufferList->buffer)
rlm@0 2092 {
rlm@0 2093 Buffer = BufferList->buffer;
rlm@0 2094 break;
rlm@0 2095 }
rlm@0 2096 BufferList = BufferList->next;
rlm@0 2097 }
rlm@0 2098
rlm@0 2099 if(!Buffer)
rlm@0 2100 {
rlm@0 2101 Source->lOffset = -1;
rlm@0 2102 return -1;
rlm@0 2103 }
rlm@0 2104
rlm@0 2105 // Determine the ByteOffset (and ensure it is block aligned)
rlm@0 2106 switch(Source->lOffsetType)
rlm@0 2107 {
rlm@0 2108 case AL_BYTE_OFFSET:
rlm@0 2109 // Take into consideration the original format
rlm@0 2110 ByteOffset = Source->lOffset;
rlm@0 2111 if(Buffer->OriginalType == UserFmtIMA4)
rlm@0 2112 {
rlm@0 2113 // Round down to nearest ADPCM block
rlm@0 2114 ByteOffset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
rlm@0 2115 // Multiply by compression rate (65 sample frames per block)
rlm@0 2116 ByteOffset *= 65;
rlm@0 2117 }
rlm@0 2118 else
rlm@0 2119 ByteOffset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
rlm@0 2120 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
rlm@0 2121 break;
rlm@0 2122
rlm@0 2123 case AL_SAMPLE_OFFSET:
rlm@0 2124 ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
rlm@0 2125 break;
rlm@0 2126
rlm@0 2127 case AL_SEC_OFFSET:
rlm@0 2128 // Note - lOffset is internally stored as Milliseconds
rlm@0 2129 ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
rlm@0 2130 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
rlm@0 2131 break;
rlm@0 2132 }
rlm@0 2133 // Clear Offset
rlm@0 2134 Source->lOffset = -1;
rlm@0 2135
rlm@0 2136 return ByteOffset;
rlm@0 2137 }
rlm@0 2138
rlm@0 2139
rlm@0 2140 ALvoid ReleaseALSources(ALCcontext *Context)
rlm@0 2141 {
rlm@0 2142 ALsizei pos;
rlm@0 2143 ALuint j;
rlm@0 2144 for(pos = 0;pos < Context->SourceMap.size;pos++)
rlm@0 2145 {
rlm@0 2146 ALsource *temp = Context->SourceMap.array[pos].value;
rlm@0 2147 Context->SourceMap.array[pos].value = NULL;
rlm@0 2148
rlm@0 2149 // For each buffer in the source's queue, decrement its reference counter and remove it
rlm@0 2150 while(temp->queue != NULL)
rlm@0 2151 {
rlm@0 2152 ALbufferlistitem *BufferList = temp->queue;
rlm@0 2153 temp->queue = BufferList->next;
rlm@0 2154
rlm@0 2155 if(BufferList->buffer != NULL)
rlm@0 2156 BufferList->buffer->refcount--;
rlm@0 2157 free(BufferList);
rlm@0 2158 }
rlm@0 2159
rlm@0 2160 for(j = 0;j < MAX_SENDS;++j)
rlm@0 2161 {
rlm@0 2162 if(temp->Send[j].Slot)
rlm@0 2163 temp->Send[j].Slot->refcount--;
rlm@0 2164 temp->Send[j].Slot = NULL;
rlm@0 2165 }
rlm@0 2166
rlm@0 2167 // Release source structure
rlm@0 2168 FreeThunkEntry(temp->source);
rlm@0 2169 memset(temp, 0, sizeof(ALsource));
rlm@0 2170 free(temp);
rlm@0 2171 }
rlm@0 2172 }