Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/al_source.c @ 17

Last change on this file since 17 was 17, checked in by landauf, 16 years ago

added openal

File size: 72.6 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * al_source.c
5 *
6 * Contains the implementation for source related functions like
7 * GenSource, DeleteSource, SourcePlay, etc, as well as internal
8 * use functions intended to manage the source structure.
9 *
10 */
11#include "al_siteconfig.h"
12
13#include <AL/al.h>
14#include <AL/alc.h>
15#include <AL/alext.h>
16#include <math.h>
17#include <limits.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <float.h>
22
23#include "al_buffer.h"
24#include "al_config.h"
25#include "al_debug.h"
26#include "al_error.h"
27#include "al_main.h"
28#include "al_mixer.h"
29#include "al_spool.h"
30#include "al_source.h"
31#include "al_queue.h"
32#include "al_types.h"
33#include "al_vector.h"
34#include "alc/alc_context.h"
35#include "alc/alc_speaker.h"
36#include "al_ext.h"
37
38/*
39 * _alInitSource( ALuint sid )
40 *
41 * Initialize an already allocated source.
42 */
43static void _alInitSource( ALuint sid );
44
45/*
46 * _alSource2D( AL_source *src )
47 *
48 * Turns off 3D attributes of a source
49 */
50static void _alSource2D( AL_source *src );
51
52/*
53 * Monoify functions copy an interleaved array of PCM data, usually in LRLR
54 * format into seperate dst buffers.
55 */
56static void _alMonoifyOffset1to2(ALshort **dstref, ALuint offset, ALvoid *src, ALuint ssize);
57static void _alMonoifyOffset2to2(ALshort **dstref, ALuint offset, ALvoid *src, ALuint ssize);
58static void _alMonoifyOffset1to4(ALshort **dstref, ALuint offset, ALvoid *src, ALuint ssize);
59static void _alMonoifyOffset2to4(ALshort **dstref, ALuint offset, ALvoid *src, ALuint ssize);
60static void _alMonoifyOffset4to4(ALshort **dstref, ALuint offset, ALvoid *src, ALuint ssize);
61
62/*
63 * Channelify functions copy the PCM data from srcs[0..nc-1] into an
64 * interleaved destination.  nc ( number of channels) is specified in the
65 * function name, ie _alChannelify2 specifies that srcs[0] and srcs[1] contain
66 * left and right channel data, respectively.
67 */
68static void _alChannelify2Offset(ALshort *dst, ALuint offset, ALshort **srcs, ALuint size);
69static void _alChannelify4Offset(ALshort *dst, ALuint offset, ALshort **srcs, ALuint size);
70
71/* static data */
72static ALshort *stereoptr = NULL; /*
73                                   * scratch space for splitting multichannels
74                                   * sources.
75                                   */
76
77/*
78 * special split source to handle callbacks
79 */
80static void _alSplitSourceCallback(ALuint cid,
81                     ALuint sourceid,
82                     ALint nc, ALuint len,
83                     AL_buffer *samp,
84                     ALshort **buffers);
85/*
86 * special split source to handle looping end case (wrap-around).
87 */
88static void _alSplitSourceLooping(ALuint cid,
89                     ALuint sourceid,
90                     ALint nc, ALuint len,
91                     AL_buffer *samp,
92                     ALshort **buffers);
93
94/*
95 * special split source to handle buffer queue transitions
96 * (wrap-around).
97 */
98static void _alSplitSourceQueue(ALuint cid,
99                     ALuint sourceid,
100                     ALint nc, ALuint len,
101                     AL_buffer *samp,
102                     ALshort **buffers);
103
104/*
105 * get a channel pointer into the buffer's data, scaled by the source's
106 * position into the PCM data.
107 */
108void *_alSourceGetBufptr(AL_source *src, AL_buffer *buf, ALuint ind);
109
110/*
111 * alIsSource( ALuint sid )
112 *
113 * Returns AL_TRUE if sid is a currently valid source id,
114 * AL_FALSE otherwise.
115 */
116ALboolean alIsSource( ALuint sid )
117{
118        ALboolean retval = AL_FALSE;
119
120        _alDCLockSource( sid );
121
122        retval = _alIsSource( sid );
123
124        _alDCUnlockSource( sid );
125
126        return retval;
127}
128
129/*
130 * _alIsSource( ALuint sid )
131 *
132 * Returns AL_TRUE if sid is a currently valid source id,
133 * AL_FALSE otherwise.
134 *
135 * Assumes locked source
136 */
137ALboolean _alIsSource( ALuint sid )
138{
139        AL_source *src;
140        ALboolean retval = AL_TRUE;
141
142        src = _alDCGetSource( sid );
143        if(src == NULL) {
144                retval = AL_FALSE;
145        }
146
147        return retval;
148}
149
150/*
151 * alGenSources( ALsizei n, ALuint *buffer )
152 *
153 * Generate n sources, with sids in buffer[0..(n-1)].  Only
154 * full allocation is performed, with error being set otherwise.
155 *
156 * If n is 0, this is a legal nop.  If n < 0, INVALID_VALUE is
157 * set and this is a nop.
158 */
159void alGenSources( ALsizei n, ALuint *buffer ) {
160        AL_context *cc;
161        ALint sindex;
162        ALuint *temp;
163        int i;
164
165        if( n == 0 ) {
166                /* with n == 0, we NOP */
167                return;
168        }
169
170        _alcDCLockContext();
171        cc = _alcDCGetContext();
172        if(cc == NULL)
173        {
174                /*
175                 * alGenSources called without current context.  Is there even
176                 * an error for this?
177                 *
178                 * JIV FIXME: set some sort of error?  Where?
179                 */
180
181                return;
182        }
183
184        if( n < 0 ) {
185                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
186                      "alGenSources: illegal n value %d\n", n );
187
188                _alDCSetError( AL_INVALID_VALUE );
189                _alcDCUnlockContext();
190
191                return;
192        }
193
194        temp = malloc( n * sizeof *temp );
195        if(temp == NULL) {
196                /*
197                 * Could not reserve memory for temporary
198                 * ALuint *buffer.
199                 */
200                _alDCSetError( AL_OUT_OF_MEMORY );
201                _alcDCUnlockContext();
202
203                return;
204        }
205
206        for(i = 0; i < n; i++) {
207                sindex = spool_alloc( &cc->source_pool );
208                if( sindex == -1 ) {
209                        /* We ran into a problem somewhere in
210                         * allocing a set of source ids.  Run
211                         * through the ones we did alloc,
212                         * realloc them, set error and return.
213                         *
214                         * FIXME: Should unlock, or have a non-locking
215                         * version of alDelSources called inside
216                         * the current lock?
217                         */
218                        _alcDCUnlockContext();
219
220                        if(i > 0) {
221                                /*
222                                 *  We delete i sources, and not i + 1, because
223                                 *  the last alloc did not happen.  And only
224                                 *  if i > 0.
225                                 */
226                                alDeleteSources( i, temp );
227                        }
228
229                        free( temp );
230
231                        _alDCSetError( AL_OUT_OF_MEMORY );
232
233                        return;
234                }
235
236                temp[i] = sindex;
237                _alInitSource( temp[i] );
238        }
239
240        _alcDCUnlockContext();
241
242        /*
243         * temp[0...n-1] now contains the generated buffers.  Copy them
244         * to the user data.
245         */
246        memcpy( buffer, temp, n * sizeof *buffer );
247
248        free( temp );
249
250        return;
251}
252
253/*
254 * _alSource2D( AL_source *src )
255 *
256 * Turns off 3D attributes of a source
257 *
258 * Assumes locked source
259 */
260void _alSource2D( AL_source *src ) {
261        _alDebug(ALD_MAXIMUS, __FILE__, __LINE__,
262                        "_alSource2D: source turned 2D");
263
264        src->position.isset = AL_FALSE;
265        _alSourceGetParamDefault( AL_POSITION, src->position.data );
266
267        src->direction.isset = AL_FALSE;
268        _alSourceGetParamDefault( AL_DIRECTION, src->direction.data );
269
270        src->cone_inner_angle.isset = AL_FALSE;
271        _alSourceGetParamDefault( AL_CONE_INNER_ANGLE, &src->cone_inner_angle.data );
272
273        src->cone_outer_angle.isset = AL_FALSE;
274        _alSourceGetParamDefault( AL_CONE_OUTER_ANGLE, &src->cone_outer_angle.data );
275
276        src->cone_outer_gain.isset = AL_FALSE;
277}
278
279/*
280 * alSourcei( ALuint sid, ALenum param, ALint i1 )
281 *
282 * Sets an attribute for a source.
283 *
284 * If sid does not name a valid source, AL_INVALID_NAME.
285 * If param does not specify a source attribute, AL_INVALID_ENUM.
286 * If i1 is out of range for the attribute, AL_INVALID_VALUE.
287 *
288 * If param is AL_BUFFER, and the source in question is not in the state
289 * AL_INITIAL or AL_STOPPED, AL_INVALID_OPERATION.
290 *
291 */
292void alSourcei( ALuint sid, ALenum param, ALint i1 )
293{
294        AL_source *src;
295        ALboolean inrange = AL_TRUE;
296        ALfloat temp;
297
298        /*
299         * If param refers to a integer attribute, accept it.
300         * If it refers to a float attribute, delegate it to alSourcefv.  If
301         * it is an invalid attribute, set INVALID_ENUM and bail out.
302         *
303         * Float vectors are obviously not possible, so we set
304         * INVALID_OPERATION.  This is probably a spec violation.
305         */
306        switch( param ) {
307                case AL_BUFFER:
308                case AL_LOOPING:
309                case AL_SOURCE_RELATIVE:
310                        /*
311                         * We handle these natively.
312                         */
313                        break;
314                case AL_PITCH:
315                case AL_MIN_GAIN:
316                case AL_MAX_GAIN:
317                case AL_CONE_INNER_ANGLE:
318                case AL_CONE_OUTER_ANGLE:
319                case AL_CONE_OUTER_GAIN:
320                case AL_GAIN:
321                case AL_GAIN_LINEAR_LOKI:
322                case AL_REFERENCE_DISTANCE:
323                case AL_ROLLOFF_FACTOR:
324                case AL_MAX_DISTANCE:
325                        temp = i1;
326
327                        alSourcef( sid, param, temp );
328
329                        return;
330                        break;
331                case AL_POSITION:
332                case AL_VELOCITY:
333                case AL_DIRECTION:
334                default:
335                        _alcDCLockContext();
336                        _alDCSetError( AL_INVALID_ENUM );
337                        _alcDCUnlockContext();
338
339                        return;
340                        break;
341        }
342
343        SOURCELOCK();
344
345        src = _alDCGetSource( sid );
346        if(src == NULL) {
347                /*
348                 * sid is invalid.
349                 */
350                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
351                        "alSourcei: source id %d is not valid", sid);
352
353                _alDCSetError( AL_INVALID_NAME );
354
355                SOURCEUNLOCK();
356                return;
357        }
358
359        /*
360         * all calls to alSourcei specify ALboolean parameters,
361         * which means that i1 is either AL_TRUE, AL_FALSE, or
362         * not valid.  So check for validity of i1 first, and
363         * set error if that's the case.
364         */
365        switch( param ) {
366                case AL_LOOPING:
367                case AL_SOURCE_RELATIVE:
368                        inrange = _alCheckRangeb( i1 );
369                        break;
370                case AL_BUFFER:
371                        inrange = alIsBuffer( i1 );
372
373                        if( i1 == 0 ) {
374                                /*
375                                 * bid of 0 has a special meaning: unset the
376                                 * parameter.   So it's in range.
377                                 */
378                                inrange = AL_TRUE;
379                        }
380                        break;
381                default:
382                        /* invalid param, error below. */
383                        break;
384        }
385
386        if( inrange == AL_FALSE ) {
387                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
388                      "alSourcei(%d, 0x%x, ...) called with invalid value %d",
389                      sid, param, i1);
390
391                _alDCSetError( AL_INVALID_VALUE );
392
393                SOURCEUNLOCK();
394                return;
395        }
396
397        switch(param)
398        {
399                case AL_BUFFER:
400                        switch( src->state )
401                        {
402                                case AL_PLAYING:
403                                case AL_PAUSED:
404                                        /*
405                                         * Invalid state to set buffer in.
406                                         */
407                                        _alDebug( ALD_SOURCE,
408                                                 __FILE__, __LINE__,
409                                                "alSourcei(%d): source is playing, AL_BUFFER invalid",
410                                                sid );
411                                        _alDCSetError( AL_INVALID_OPERATION );
412                                        break;
413                                default:
414                                        _alSourceQueueHead( src, i1 );
415                                        break;
416                        }
417
418                        break;
419                case AL_LOOPING:
420                        src->looping.isset = AL_TRUE;
421                        src->looping.data = i1;
422                        break;
423                case AL_SOURCE_RELATIVE:
424                        src->relative.isset = AL_TRUE;
425                        src->relative.data = i1;
426                        /* If this is a relative source with zero position,
427                           perform the 2D sound hack...
428                           (Tribes 2 reuses 3D sources as 2D sources)
429                        */
430                        if ( i1 && src->position.isset &&
431                             ! src->position.data[0] &&
432                             ! src->position.data[1] &&
433                             ! src->position.data[2] ) {
434                                _alSource2D(src);
435                        }
436                        break;
437                default:
438                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
439                                "alSourcei: invalid or stubbed source param 0x%x",
440                                param );
441
442                        _alDCSetError( AL_INVALID_ENUM );
443                        break;
444        }
445
446        SOURCEUNLOCK();
447
448        return;
449}
450
451/*
452 * alSourcef( ALuint sid, ALenum param, ALfloat f1 )
453 *
454 * Sets an attribute for a source.
455 *
456 * If sid does not name a valid source, AL_INVALID_NAME.
457 * If param does not specify a source attribute, AL_INVALID_ENUM.
458 * If f1 is out of range for the attribute, AL_INVALID_VALUE.
459 *
460 */
461void alSourcef( ALuint sid, ALenum param, ALfloat f1 ) {
462        /*
463         * If param refers to a integer attribute, delegate it to alSourcei.
464         * If it refers to a float attribute, delegate it to alSourcefv.  If
465         * it is an invalid attribute, set INVALID_ENUM and bail out.
466         *
467         * Float vectors are obviously not possible, so we set
468         * INVALID_OPERATION.  This is probably a spec violation.
469         */
470        switch( param ) {
471                case AL_BUFFER:
472                case AL_LOOPING:
473                case AL_SOURCE_RELATIVE:
474                        alSourcei( sid, param, (ALint) f1 );
475                        return;
476                case AL_PITCH:
477                case AL_MIN_GAIN:
478                case AL_MAX_GAIN:
479                case AL_CONE_INNER_ANGLE:
480                case AL_CONE_OUTER_ANGLE:
481                case AL_CONE_OUTER_GAIN:
482                case AL_GAIN:
483                case AL_GAIN_LINEAR_LOKI:
484                case AL_REFERENCE_DISTANCE:
485                case AL_ROLLOFF_FACTOR:
486                case AL_MAX_DISTANCE:
487                        alSourcefv( sid, param, &f1 );
488                        return;
489                case AL_POSITION:
490                case AL_VELOCITY:
491                case AL_DIRECTION:
492                default:
493                        _alcDCLockContext();
494                        _alDCSetError( AL_INVALID_ENUM );
495                        _alcDCUnlockContext();
496                        return;
497        }
498}
499
500/*
501 * alSource3f( ALuint sid, ALenum param, ALfloat f1, ALfloat f2, ALfloat f3 )
502 *
503 * Sets an 3 float parameter for a source.
504 *
505 * If sid does not name a valid source, AL_INVALID_NAME.
506 * If param does not specify a source attribute, AL_INVALID_ENUM.
507 * If f1, f2, or f3 is out of range for the attribute, AL_INVALID_VALUE.
508 *
509 */
510void alSource3f( ALuint sid, ALenum param,
511                 ALfloat f1, ALfloat f2, ALfloat f3 ) {
512        ALfloat fv[3];
513
514        fv[0] = f1;
515        fv[1] = f2;
516        fv[2] = f3;
517
518        alSourcefv( sid, param, fv );
519
520        return;
521}
522
523/*
524 * alSourcefv( ALuint sid, ALenum param, ALfloat fv )
525 *
526 * Sets an float vector parameter for a source.
527 *
528 * If sid does not name a valid source, AL_INVALID_NAME.
529 * If param does not specify a source attribute, AL_INVALID_ENUM.
530 * If any member of fv is out of range for the attribute, AL_INVALID_VALUE.
531 *
532 */
533void alSourcefv( ALuint sid, ALenum param, const ALfloat *fv1 )
534{
535        AL_source *source;
536        ALboolean inrange = AL_TRUE;
537
538        /*
539         * If param refers to a integer attribute, delegate it to alSourcei.
540         * If it refers to a float attribute, we accept it.
541         */
542        switch( param ) {
543                case AL_BUFFER:
544                case AL_LOOPING:
545                case AL_SOURCE_RELATIVE:
546                        alSourcei( sid, param, (ALint) fv1[0] );
547                        return;
548                case AL_PITCH:
549                case AL_MIN_GAIN:
550                case AL_MAX_GAIN:
551                case AL_CONE_INNER_ANGLE:
552                case AL_CONE_OUTER_ANGLE:
553                case AL_CONE_OUTER_GAIN:
554                case AL_GAIN:
555                case AL_GAIN_LINEAR_LOKI:
556                case AL_REFERENCE_DISTANCE:
557                case AL_ROLLOFF_FACTOR:
558                case AL_MAX_DISTANCE:
559                case AL_POSITION:
560                case AL_VELOCITY:
561                case AL_DIRECTION:
562                        break;
563                default:
564                        _alcDCLockContext();
565                        _alDCSetError( AL_INVALID_ENUM );
566                        _alcDCUnlockContext();
567                        return;
568        }
569
570
571        SOURCELOCK();
572        source = _alDCGetSource( sid );
573
574        if( source == NULL ) {
575                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
576                        "alSourcefv: %d is an invalid source id", sid );
577
578                _alDCSetError( AL_INVALID_NAME );
579
580                SOURCEUNLOCK();
581
582                return;
583        }
584
585        if( fv1 == NULL ) {
586                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
587                        "alSourcefv: passed fv is NULL");
588
589                _alDCSetError( AL_INVALID_VALUE );
590
591                SOURCEUNLOCK();
592
593                return;
594        }
595
596        /* check to see if we are in range, first */
597        switch( param ) {
598                case AL_MIN_GAIN:
599                case AL_MAX_GAIN:
600                case AL_CONE_OUTER_GAIN:
601                case AL_GAIN:
602                case AL_GAIN_LINEAR_LOKI:
603                  inrange = _alCheckRangef( fv1[0], 0.0, FLT_MAX );
604                  break;
605                case AL_CONE_INNER_ANGLE:
606                case AL_CONE_OUTER_ANGLE:
607                  inrange = _alCheckRangef( fv1[0], 0.0, 360.0 );
608                  break;
609                case AL_PITCH:
610                  /* FIXME: deviates from spec */
611                  inrange = _alCheckRangef( fv1[0], 0.0, 2.0 );
612                  break;
613                case AL_REFERENCE_DISTANCE:
614                case AL_MAX_DISTANCE:
615                case AL_ROLLOFF_FACTOR:
616                  inrange = _alCheckRangef( fv1[0], 0.0, FLT_MAX );
617                  break;
618                case AL_POSITION:
619                case AL_DIRECTION:
620                  inrange = inrange && ( _alIsFinite( fv1[0] ) == AL_TRUE );
621                  inrange = inrange && ( _alIsFinite( fv1[1] ) == AL_TRUE );
622                  inrange = inrange && ( _alIsFinite( fv1[2] ) == AL_TRUE );
623
624                  assert( inrange );
625                  break;
626                default:
627                  /* invalid param. error below */
628                  break;
629        }
630
631        if( inrange == AL_FALSE ) {
632                /*
633                 *  We have a range error, exit early.
634                 */
635                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
636                      "alSourcef(%d, 0x%x, ...): %f out of range",
637                      sid, param, fv1[0] );
638
639                _alDCSetError( AL_INVALID_VALUE );
640
641                SOURCEUNLOCK();
642
643                return;
644        }
645
646        switch( param ) {
647                case AL_POSITION:
648                  source->position.isset = AL_TRUE;
649                  memcpy( &source->position.data, fv1, SIZEOFVECTOR );
650                  /* If this is a relative source with zero position,
651                     perform the 2D sound hack...
652                     (Tribes 2 reuses 3D sources as 2D sources)
653                   */
654                  if ( !fv1[0] && !fv1[1] && !fv1[2] &&
655                       source->relative.isset &&
656                       source->relative.data ) {
657                        _alSource2D(source);
658                  }
659                  break;
660                case AL_DIRECTION:
661                  /*
662                   * The zero vector will make a directional sound
663                   * non-directional.
664                   */
665                  if(_alIsZeroVector(fv1) == AL_TRUE) {
666                          /* clear DIRECTION flag */
667                          source->direction.isset = AL_FALSE;
668                  } else {
669                          source->direction.isset = AL_TRUE;
670                          memcpy( &source->direction.data, fv1, SIZEOFVECTOR );
671                  }
672                  break;
673                case AL_VELOCITY:
674                  source->velocity.isset = AL_TRUE;
675                  memcpy( &source->velocity.data, fv1, SIZEOFVECTOR );
676
677                  /*
678                   * velocity means doppler, which means that we
679                   * need pitch, which means alf_tpitch takes care of
680                   * incrementing soundpos.  Very kludgey, I'll admit.
681                   *
682                   */
683                  source->flags      |= ALS_NEEDPITCH;
684                  break;
685                case AL_MIN_GAIN:
686                  source->min_gain.isset = AL_TRUE;
687                  source->min_gain.data  = fv1[0];
688                  break;
689                case AL_MAX_GAIN:
690                  source->max_gain.isset = AL_TRUE;
691                  source->max_gain.data  = fv1[0];
692                  break;
693                case AL_CONE_INNER_ANGLE:
694                  source->cone_inner_angle.isset = AL_TRUE;
695                  source->cone_inner_angle.data  = fv1[0];
696                  break;
697                case AL_CONE_OUTER_ANGLE:
698                  source->cone_outer_angle.isset = AL_TRUE;
699                  source->cone_outer_angle.data  = fv1[0];
700                  break;
701                case AL_CONE_OUTER_GAIN:
702                  source->cone_outer_gain.isset = AL_TRUE;
703                  source->cone_outer_gain.data  = fv1[0];
704                  break;
705                case AL_PITCH:
706                  /* only set pitch if it differs from 1.0 */
707                  if(fv1[0] == 1.0) {
708                        source->pitch.isset = AL_FALSE;
709                        source->pitch.data  = 1.0;
710
711                        /*
712                         * If velocity is set, then doppler may
713                         * change the pitch.
714                         */
715                        if (!source->velocity.isset) {
716                                source->flags &= ~ALS_NEEDPITCH;
717                        }
718                  } else {
719                        source->pitch.isset = AL_TRUE;
720                        source->pitch.data  = fv1[0];
721
722                        /* tpitch messes with soundpos */
723                        source->flags |= ALS_NEEDPITCH;
724                  }
725                  break;
726                case AL_GAIN:
727                case AL_GAIN_LINEAR_LOKI:
728                  source->gain.isset = AL_TRUE;
729                  source->gain.data = fv1[0];
730                  break;
731                case AL_REFERENCE_DISTANCE:
732                  source->reference_distance.isset = AL_TRUE;
733                  source->reference_distance.data = fv1[0];
734                  break;
735                case AL_MAX_DISTANCE:
736                  source->max_distance.isset = AL_TRUE;
737                  source->max_distance.data = fv1[0];
738                  break;
739                case AL_ROLLOFF_FACTOR:
740                  source->rolloff_factor.isset = AL_TRUE;
741                  source->rolloff_factor.data = fv1[0];
742                  break;
743                default:
744                  _alDebug(ALD_SOURCE, __FILE__, __LINE__,
745                          "alSourcefv(%d): param 0x%x not valid", sid, param );
746
747                  _alDCSetError( AL_INVALID_ENUM );
748                  break;
749        }
750
751        SOURCEUNLOCK();
752
753        return;
754}
755
756/*
757 * alGetSourcei( ALuint sid, ALenum pname, ALint *retref )
758 *
759 * Retrieve the value of a source (scalar) attribute
760 *
761 * If sid does not name a valid source, AL_INVALID_NAME.
762 * If param does not specify a source attribute, AL_INVALID_ENUM.
763 *
764 */
765void alGetSourcei( ALuint sid, ALenum param, ALint *retref )
766{
767        ALint safety_first[6];
768
769        alGetSourceiv( sid, param, safety_first );
770
771        *retref = safety_first[0];
772
773        return;
774}
775
776/*
777 * alGetSourceiv( ALuint sid, ALenum pname, ALint *retref )
778 *
779 * Retrieve the value of a source attribute.
780 *
781 * If sid does not name a valid source, AL_INVALID_NAME.
782 * If param does not specify a source attribute, AL_INVALID_ENUM.
783 *
784 */
785void alGetSourceiv( ALuint sid, ALenum param, ALint *retref )
786{
787        AL_source *src;
788        ALint *temp;
789
790        /*
791         * Check for invalid type request: eg AL_GAIN.  We need
792         * to convert these.
793         */
794        switch( param ) {
795                case AL_GAIN:
796                case AL_GAIN_LINEAR_LOKI:
797                case AL_CONE_INNER_ANGLE:
798                case AL_CONE_OUTER_ANGLE:
799                case AL_CONE_OUTER_GAIN:
800                case AL_PITCH:
801                case AL_REFERENCE_DISTANCE:
802                case AL_ROLLOFF_FACTOR:
803                case AL_MAX_DISTANCE:
804                        /* float conversion */
805                        do {
806                                ALfloat ftemp = 0.0f;
807
808                                alGetSourcefv( sid, param, &ftemp );
809
810                                /* how do we know if we've failed? */
811                                *retref = ftemp;
812
813                                return;
814                        } while(0);
815                        break;
816                case AL_VELOCITY:
817                case AL_POSITION:
818                case AL_DIRECTION:
819                        /* float conversion */
820                        do {
821                                ALfloat ftemp[3];
822
823                                alGetSourcefv( sid, param, ftemp );
824
825                                /* how do we know if we've failed? */
826                                retref[0] = ftemp[0];
827                                retref[1] = ftemp[1];
828                                retref[2] = ftemp[2];
829
830                                return;
831                        } while(0);
832                        break;
833                default:
834                        /*
835                         * either integer, boolean, or invalid
836                         * param.
837                         */
838                        break;
839        }
840
841        SOURCELOCK();
842        src = _alDCGetSource( sid );
843
844        if( src == NULL ) {
845                /*
846                 * Invalid source id
847                 */
848                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
849                      "alGetSourcei: invalid source id %d",
850                      sid);
851
852                _alDCSetError( AL_INVALID_NAME );
853
854                SOURCEUNLOCK();
855                return;
856        }
857
858        if(retref == NULL) {
859                /* silently ignore */
860
861                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
862                      "alGetSourcei(%d): NULL value", sid);
863
864                SOURCEUNLOCK();
865                return;
866        }
867
868
869        /*
870         * get param value, and store it in temp.  We need it
871         * for most, but not all, of the following params enums.
872         */
873        temp = _alGetSourceParam( src, param );
874        if(temp != NULL) {
875                /* If temp is not NULL, then there is a value set,
876                 * and we don't have to slog through the defaults
877                 * below.
878                 */
879
880                switch( param ) {
881                        case AL_LOOPING:
882                        case AL_SOURCE_RELATIVE:
883                                *retref = * (ALboolean *) temp;
884                                break;
885                        default:
886                                *retref = *temp;
887                                break;
888                }
889
890                SOURCEUNLOCK();
891
892                return;
893        }
894
895        switch(param) {
896                case AL_BUFFERS_QUEUED:
897                  /* AL_BUFFERS_QUEUED is not setable, and has no default. */
898                  /* Following code incorrectly subtracts the number of
899                   * processed buffers from the total number of buffers
900                   * queued.  We return the total number of buffers queued at
901                   * all times.
902                   *
903                   * *retref = src->bid_queue.size - src->bid_queue.read_index;
904                   *
905                   * Following code correctly returns total number of buffers
906                   * queued.
907                   */
908                  if(src->bid_queue.size == 1)
909                  {
910                        /*
911                         * Test to see if the only buffer queued is the 0
912                         * buffer.  If so, don't report it.
913                         */
914                        if(src->bid_queue.queue[0] == 0)
915                        {
916                                *retref = 0;
917                        }
918                        else
919                        {
920                                /*
921                                 * There was only one bid but it wasn't the
922                                 * 0 buffer.
923                                 */
924                                *retref = 1;
925                        }
926                  }
927                  else
928                  {
929                        /*
930                         * More than one bid, not the 0 buffer.  Or is it
931                         * possible to stick it in there?  Do we count it?
932                         *
933                         * JIV FIXME: check it out.
934                         */
935                        *retref = src->bid_queue.size;
936                  }
937                  break;
938                case AL_BUFFERS_PROCESSED:
939                  /* AL_BUFFERS_PROCESSED is not setable, and has no default. */
940
941                  if( src->bid_queue.read_index == 0 ) {
942                        /*
943                         * We're still reading the first bid, so we haven't
944                         * processed any yet.  So return 0.
945                         */
946                        *retref = 0;
947                  } else {
948                        *retref = src->bid_queue.read_index;
949                  }
950                  break;
951#ifdef AL_SUPPORT_BYTE_LOKI_SOURCE_ATTR_
952                case AL_BYTE_LOKI:
953                  /* AL_BYTE_LOKI is not setable, and has no default. */
954                  switch(src->state) {
955                          case AL_PLAYING:
956                          case AL_PAUSED:
957                            *retref = src->srcParams.soundpos;
958                            break;
959                          default:
960                            *retref = -1;
961                            break;
962                  }
963                  break;
964#endif
965                case AL_SOURCE_STATE:
966                  *retref = src->state;
967                  break;
968                case AL_LOOPING:
969                case AL_SOURCE_RELATIVE:
970                        /*
971                         * These all have default states, but must be handled
972                         * differently because they are booleans.
973                         */
974                        {
975                                ALboolean val;
976
977                                _alSourceGetParamDefault( param, &val );
978
979                                *retref = val;
980                        }
981                        break;
982                case AL_BUFFER:
983                        /* These all have default states */
984                        _alSourceGetParamDefault( param, retref );
985                        break;
986                default:
987                  _alDebug(ALD_SOURCE, __FILE__, __LINE__,
988                        "alGetSourcei: invalid or unsupported param 0x%x",
989                        param);
990
991                  _alDCSetError( AL_INVALID_ENUM );
992
993                  break;
994        }
995
996        SOURCEUNLOCK();
997
998        return;
999}
1000
1001/*
1002 * alGetSource3f( ALuint sid, ALenum param,
1003 *                ALfloat *value1, ALfloat *value2, ALfloat *value3)
1004 *
1005 * Retrieve the value of a (potentially) 3-tuple valued source attribute.
1006 *
1007 * If sid does not name a valid source, AL_INVALID_NAME.
1008 * If param does not specify a source attribute, AL_INVALID_ENUM.
1009 */
1010void alGetSource3f( ALuint sid, ALenum param,
1011                    ALfloat *value1, ALfloat *value2, ALfloat *value3)
1012{
1013        ALfloat safety_first[6];
1014
1015        if(( value1 == NULL ) &&
1016           ( value2 == NULL ) &&
1017           ( value3 == NULL ))
1018        {
1019                /* silently ignore */
1020                _alDebug( ALD_SOURCE, __FILE__, __LINE__,
1021                        "alGetSource3f: value passed is NULL" );
1022
1023                return;
1024        }
1025
1026        alGetSourcefv( sid, param, safety_first );
1027
1028        if(value1)
1029        {
1030                *value1 = safety_first[0];
1031        }
1032
1033        if(value2)
1034        {
1035                *value2 = safety_first[1];
1036        }
1037
1038        if(value3)
1039        {
1040                *value3 = safety_first[2];
1041        }
1042
1043        return;
1044}
1045
1046/*
1047 * alGetSourcef( ALuint sid, ALenum param, ALfloat *value )
1048 *
1049 * Retrieve the value of a source attribute.
1050 *
1051 * If sid does not name a valid source, AL_INVALID_NAME.
1052 * If param does not specify a source attribute, AL_INVALID_ENUM.
1053 */
1054void alGetSourcef( ALuint sid, ALenum param, ALfloat *value )
1055{
1056        ALfloat safety_first[6];
1057
1058        if( value == NULL )
1059        {
1060                /* silently ignore */
1061                _alDebug( ALD_SOURCE, __FILE__, __LINE__,
1062                        "alGetSourcef: value passed is NULL" );
1063
1064                return;
1065        }
1066
1067        alGetSourcefv( sid, param, safety_first );
1068
1069        *value = safety_first[0];
1070
1071        return;
1072}
1073
1074/*
1075 * alGetSourcefv( ALuint sid, ALenum param, ALfloat *values )
1076 *
1077 * Retrieve the value of a source attribute.
1078 *
1079 * If sid does not name a valid source, AL_INVALID_NAME.
1080 * If param does not specify a source attribute, AL_INVALID_ENUM.
1081 */
1082void alGetSourcefv( ALuint sid, ALenum param, ALfloat *values ) {
1083        AL_source *src;
1084        ALfloat *srcvals;
1085        ALsizei numvalues; /* number of values to copy */
1086
1087        /*
1088         * Check for invalid type request: eg integer, boolean
1089         * or single float types.
1090         *
1091         * We need to convert these.
1092         */
1093        switch( param ) {
1094                case AL_GAIN:
1095                case AL_GAIN_LINEAR_LOKI:
1096                case AL_CONE_INNER_ANGLE:
1097                case AL_CONE_OUTER_ANGLE:
1098                case AL_CONE_OUTER_GAIN:
1099                case AL_PITCH:
1100                case AL_REFERENCE_DISTANCE:
1101                case AL_MAX_DISTANCE:
1102                case AL_ROLLOFF_FACTOR:
1103                        /* scalar param, only copy 1 value */
1104                        numvalues = 1;
1105                        break;
1106                case AL_LOOPING:
1107                case AL_SOURCE_RELATIVE:
1108                case AL_BUFFERS_QUEUED:
1109                case AL_BUFFERS_PROCESSED:
1110#ifdef AL_SUPPORT_BYTE_LOKI_SOURCE_ATTR_
1111                case AL_BYTE_LOKI:
1112#endif
1113                case AL_SOURCE_STATE:
1114                case AL_BUFFER:
1115                        /* conversion to integer */
1116                        do {
1117                                ALint temp = 0;
1118
1119                                alGetSourceiv( sid, param, &temp );
1120
1121                                /*
1122                                 * how do we know if we've failed?
1123                                 *
1124                                 * only populate first entry
1125                                 */
1126                                *values = temp;
1127
1128                                return;
1129                        } while(0);
1130                        break;
1131                default:
1132                        /*
1133                         * either float vector or invalid
1134                         * param.
1135                         */
1136                        numvalues = 3;
1137                        break;
1138        }
1139
1140        SOURCELOCK();
1141        src = _alDCGetSource( sid );
1142
1143        if(src == NULL) {
1144                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
1145                        "alGetSourcefv: source id %d is invalid", sid);
1146
1147                _alDCSetError( AL_INVALID_NAME );
1148
1149                SOURCEUNLOCK();
1150                return;
1151        }
1152
1153        if( values == NULL ) {
1154                /* silently ignore */
1155
1156                _alDebug( ALD_SOURCE, __FILE__, __LINE__,
1157                        "alGetSourcefv: values passed is NULL" );
1158
1159                SOURCEUNLOCK();
1160
1161                return;
1162        }
1163
1164        srcvals = _alGetSourceParam( src, param );
1165        if(srcvals != NULL) {
1166                /*
1167                 * If srcvals is not NULL, then the attribute has been set by
1168                 * the application, and we don't need to set defaults.
1169                 */
1170                memcpy( values, srcvals, numvalues * sizeof *values );
1171
1172                SOURCEUNLOCK();
1173
1174                return;
1175        }
1176
1177        /* If we are at this point, srcvals is NULL, which means
1178         * that either param is an invalid param, or that the value
1179         * is not set.  Check for a valid param, in which case we
1180         * set the default, or set error.
1181         */
1182        switch( param ) {
1183                /* scalars */
1184                case AL_GAIN:
1185                case AL_GAIN_LINEAR_LOKI:
1186                case AL_MIN_GAIN:
1187                case AL_MAX_GAIN:
1188                case AL_CONE_INNER_ANGLE:
1189                case AL_CONE_OUTER_ANGLE:
1190                case AL_CONE_OUTER_GAIN:
1191                case AL_PITCH:
1192                case AL_ROLLOFF_FACTOR:
1193                case AL_REFERENCE_DISTANCE:
1194                case AL_MAX_DISTANCE:
1195                case AL_VELOCITY:
1196                case AL_POSITION:
1197                case AL_DIRECTION:
1198                        _alSourceGetParamDefault( param, values );
1199                        break;
1200                default:
1201                        _alDebug( ALD_SOURCE, __FILE__, __LINE__,
1202                               "alGetSourcefv: param 0x%x either invalid or unset",
1203                               param);
1204
1205                        _alDCSetError( AL_INVALID_ENUM );
1206
1207                        break;
1208        }
1209
1210        SOURCEUNLOCK();
1211
1212        return;
1213}
1214
1215/*
1216 * _alGetSource( ALuint cid, ALuint sid )
1217 *
1218 * Returns the address of the source sid from the
1219 * context cid, or NULL if the cid or sid is
1220 * invalid.
1221 *
1222 * Assumes locked context
1223 */
1224AL_source *_alGetSource( ALuint cid, ALuint sid ) {
1225        AL_context *cc;
1226
1227        cc  = _alcGetContext( cid );
1228        if(cc == NULL) {
1229                /*
1230                 * FIXME: Where, if at all, should be set the error?
1231                 */
1232                return NULL;
1233        }
1234
1235        return spool_index( &cc->source_pool, sid );
1236}
1237
1238/*
1239 * _alSplitSources( ALuint cid, ALuint sid,
1240 *                  ALint nc, ALuint len,
1241 *                  AL_buffer *buf, ALshort **buffs );
1242 *
1243 * Populate buffs[0..nc-1][0..len/2-1] with data from buf, with offset into
1244 * buf given by the position associated with the source named by sid in the
1245 * context named by cid.
1246 *
1247 * This function delegates to static functions in the case of looping,
1248 * callback or queue sounds.
1249 *
1250 * assumes locked context
1251 *
1252 * FIXME: what an ugly mess
1253 */
1254void _alSplitSources( ALuint cid,
1255                      ALuint sourceid,
1256                      ALint nc, ALuint len,
1257                      AL_buffer *samp,
1258                      ALshort **buffers ) {
1259        AL_source *src;
1260        AL_sourcestate *srcstate;
1261        ALuint i;
1262        char *bufptr = NULL;
1263        static ALuint buflen = 0;
1264
1265        src = _alGetSource( cid, sourceid );
1266        if(src == NULL)
1267        {
1268                /* bad mojo */
1269                return;
1270        }
1271
1272        /*
1273         * if buflen is less that the passed len, this is probably
1274         * the first initialization and we need to allocate the
1275         * stereoptr (stereoptr being that buffer where we mix this
1276         * sort of thing).
1277         *
1278         * or buflen is equal to len and stereoptr is null because
1279         * the device was destroyed and then restarted.
1280         */
1281        if(buflen < len || stereoptr == NULL)
1282        {
1283                buflen = len;
1284
1285                stereoptr = realloc(stereoptr, buflen * 2);
1286
1287                memset( stereoptr, 0, buflen * 2 );
1288        }
1289
1290        if(stereoptr == NULL)
1291        {
1292                /* at this point, we're dead and don't know it. */
1293                return;
1294        }
1295
1296        /* Shouldn't happen. */
1297        if(len == 0) {
1298                _alDebug(ALD_SOURCE,
1299                        __FILE__, __LINE__,
1300                        "wtf? size = 0!!!!!!");
1301                _alDebug(ALD_SOURCE,
1302                        __FILE__, __LINE__,
1303                        "Expect SIGSEGV soon");
1304                return;
1305        }
1306
1307
1308        srcstate = _alSourceQueueGetCurrentState( src );
1309
1310        /*
1311         *  If we have a callback function, read from it.
1312         */
1313        if(samp->flags & ALB_CALLBACK)
1314        {
1315                srcstate->flags |= ALQ_CALLBACKBUFFER;
1316
1317                _alSplitSourceCallback(cid, sourceid, nc, len, samp, buffers);
1318                return;
1319        } else {
1320                /* make sure we mark this as a normal buffer */
1321                srcstate->flags &= ~ALQ_CALLBACKBUFFER;
1322        }
1323
1324        if(_alSourceBytesLeftByChannel(src, samp) < (ALint) len)
1325        {
1326                if(_alSourceIsLooping(src) == AL_TRUE &&
1327                   _alSourceIsQueue(src) == AL_FALSE )
1328                {
1329                        /*
1330                         * looping sources, when they need to wrap,
1331                         * are handled via SplitSourceLooping.
1332                         */
1333                        _alSplitSourceLooping(cid, sourceid,
1334                                        nc, len,
1335                                        samp,
1336                                        buffers);
1337
1338                        return;
1339                }
1340
1341                if(_alSourceGetPendingBids(src) > 0)
1342                {
1343                        /*
1344                         * There are more buffers in the queue, so
1345                         * do the wrapping.
1346                         */
1347                        _alSplitSourceQueue(cid, sourceid,
1348                                            nc, len, samp, buffers);
1349
1350                        return;
1351                }
1352
1353                len = _alSourceBytesLeftByChannel(src, samp);
1354
1355                if((len <= 0) || (len > samp->size))
1356                {
1357                        /* really short sound */
1358                        len = samp->size;
1359
1360                        return;
1361                }
1362        }
1363
1364        if(_alSourceGetPendingBids(src) > 0)
1365                assert(src->bid_queue.read_index < src->bid_queue.size );
1366
1367        for(i = 0; i < _alcGetNumSpeakers(cid); i++)
1368        {
1369                bufptr = _alSourceGetBufptr(src, samp, i);
1370
1371                memcpy(buffers[i], bufptr, len);
1372        }
1373
1374        return;
1375}
1376
1377/*
1378 * _alSplitSourceCallback( ALuint cid,
1379 *                         ALuint sourceid,
1380 *                         ALint nc, ALuint len,
1381 *                         AL_buffer *samp,
1382 *                         ALshort **buffers )
1383 *
1384 *  Special SplitSource for callback sources, which need to have their
1385 *  data populated not from the buffer's original data, but from the
1386 *  callback.
1387 */
1388static void _alSplitSourceCallback( ALuint cid,
1389                                    ALuint sourceid,
1390                                    ALint nc, ALuint len,
1391                                    AL_buffer *samp,
1392                                    ALshort **buffers ) {
1393        AL_source *src;
1394        int *bid            = NULL;
1395        ALuint nsamps = 0;
1396        int resultsamps     = -1;
1397        int bufchannels     = _alGetChannelsFromFormat( samp->format );
1398
1399        src = _alGetSource( cid, sourceid );
1400        if(src == NULL) {
1401                /*
1402                 * Should we really be setting the error here?
1403                 */
1404                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
1405                      "_alSplitSourceCallback: invalid source id %d",
1406                      sourceid);
1407
1408                _alSetError(cid, AL_INVALID_NAME);
1409                return;
1410        }
1411
1412        bid = (int *) _alGetSourceParam(src, AL_BUFFER);
1413        if(bid == NULL) {
1414                return;
1415        }
1416
1417        nsamps = bufchannels * len / sizeof **buffers;
1418
1419        resultsamps = samp->callback(sourceid, *bid,
1420                                     stereoptr,
1421                                     samp->format,
1422                                     samp->frequency,
1423                                     nsamps);
1424
1425        if(resultsamps < 0) {
1426                /* callback problem */
1427                _alDebug(ALD_STREAMING, __FILE__, __LINE__,
1428                        "%d callback returned -1", sourceid);
1429
1430                memset(stereoptr, 0, len);
1431
1432                _alRemoveSourceFromMixer(sourceid);
1433
1434                return;
1435        }
1436
1437        if(resultsamps < (ALint) nsamps) {
1438                /* source is over */
1439                _alDebug(ALD_STREAMING, __FILE__, __LINE__,
1440                        "time for %d to die", sourceid);
1441
1442                /* FIXME:
1443                 *
1444                 * offset memset at resultsamps / width to end
1445
1446                 memset(stereoptr, 0, len);
1447                 */
1448
1449                /*
1450                 * we want this to end.  please.
1451                 * What a cheat.
1452                 */
1453
1454                src->srcParams.soundpos = samp->size + nc * resultsamps * sizeof **buffers;
1455        }
1456
1457        /* set len to the number of bytes we actually got back
1458         * from the callback.
1459         */
1460        len = resultsamps * sizeof **buffers / bufchannels;
1461
1462        /*
1463         * since we're decoding it, copy it to the orig_buffers so we only
1464         * have to do it once.
1465         */
1466        _alMonoify(buffers, stereoptr, len, samp->num_buffers, bufchannels);
1467
1468        samp->size += nc * resultsamps * sizeof **buffers;
1469
1470        return;
1471}
1472
1473/*
1474 * _alSplitSourceLooping( ALuint cid,
1475 *                        ALuint sourceid,
1476 *                        ALint nc, ALuint len,
1477 *                        AL_buffer *samp,
1478 *                        ALshort **buffers )
1479 *
1480 * _alSplitSourceLooping is called to split a looping source that
1481 * has reached the loop point (ie, point where it needs to wrap around.
1482 *
1483 * This is very ugly, and needs to be cleaned up.  I'd prefer not to
1484 * have a special case so if you're looking to contribute, please
1485 * consider redoing this.
1486 *
1487 * assumes locked context
1488 *
1489 * FIXME: this is so ugly.
1490 */
1491static void _alSplitSourceLooping( ALuint cid,
1492                                   ALuint sourceid,
1493                                   ALint nc, ALuint len,
1494                                   AL_buffer *samp,
1495                                   ALshort **buffers ) {
1496        AL_source *src;
1497        long mixable;
1498        long remaining;
1499        char *bufptr;
1500        int i;
1501        int bi;
1502        int bufchannels = _alGetChannelsFromFormat(samp->format);
1503        char *mdp;
1504
1505        src = _alGetSource(cid, sourceid);
1506        if(src == NULL) {
1507                /*
1508                 * Should we really be setting the error here?
1509                 */
1510                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
1511                      "_alSplitSourceLooping: invalid source id %d",
1512                      sourceid);
1513
1514                _alSetError(cid, AL_INVALID_NAME);
1515                return;
1516        }
1517
1518        mixable    = _alSourceBytesLeftByChannel(src, samp);
1519        remaining  = 0;
1520
1521        assert(mixable >= 0);
1522
1523        /* in case samp->size < len, we don't want
1524         * to overwrite with the memcpy
1525         */
1526        if(len * bufchannels <= samp->size) {
1527                /* normal case */
1528                remaining = (len * bufchannels) - mixable;
1529
1530                for(i = 0; i < nc; i++) {
1531                        bufptr = _alSourceGetBufptr(src, samp, i);
1532
1533                        memcpy(buffers[i], bufptr, mixable);
1534                        memcpy(buffers[i] + mixable/2, samp->orig_buffers[i],
1535                                remaining);
1536                }
1537
1538                return;
1539        } else {
1540                /* really small looping sample */
1541                if(mixable < 0) {
1542                        /* we loop sound in monoptr */
1543                        mixable = src->srcParams.soundpos % len;
1544                }
1545
1546                for(bi = 0; bi < nc; bi++) {
1547                        mdp = (char *) buffers[bi];
1548
1549                        /* copy samp again and again */
1550                        for(i = mixable; i < (signed int) len; i += samp->size) {
1551                                int copylen;
1552
1553                                if(i + samp->size < len) {
1554                                        copylen = samp->size;
1555                                } else {
1556                                        copylen = len - i;
1557                                }
1558
1559                                memcpy(&mdp[i], samp->orig_buffers[bi], copylen);
1560                        }
1561
1562                        for(i = 0; i < mixable; i += samp->size) {
1563                                int copylen;
1564
1565                                if(i + samp->size < (unsigned int) mixable) {
1566                                        copylen = samp->size;
1567                                } else {
1568                                        copylen = mixable - i;
1569                                }
1570
1571                                memcpy(&mdp[i],
1572                                        samp->orig_buffers[bi],
1573                                        copylen);
1574                        }
1575                }
1576
1577                return;
1578        }
1579#if 0
1580        /* ToDo: This is never reached?! */
1581        for(i = 0; i < nc; i++) {
1582                bufptr = _alSourceGetBufptr(src, samp, i);
1583
1584                memcpy(buffers[i], bufptr, len);
1585        }
1586#endif
1587}
1588
1589/*
1590 * _alSplitSourceQueue( ALuint cid,
1591 *                      ALuint sourceid,
1592 *                      ALint nc, ALuint len,
1593 *                      AL_buffer *samp,
1594 *                      ALshort **buffers )
1595 *
1596 * _alSplitSourceQueue is called to ease the transition between
1597 * buffers in a source's queue.
1598 *
1599 * This is very ugly, and needs to be cleaned up.  I'd prefer not to
1600 * have a special case so if you're looking to contribute, please
1601 * consider redoing this.
1602 *
1603 * assumes locked context
1604 *
1605 * FIXME: this is so ugly.
1606 */
1607static void _alSplitSourceQueue( ALuint cid,
1608                                 ALuint sourceid,
1609                                 ALint nc, ALuint len,
1610                                 AL_buffer *samp,
1611                                 ALshort **buffers )
1612{
1613        AL_source *src;
1614        AL_buffer *nextsamp;
1615        long mixable;
1616        ALuint remaining;
1617        char *bufptr;
1618        ALuint nextbid;
1619        void *nextpcm;
1620        int new_soundpos = -1;
1621        int old_soundpos;
1622        int old_readindex;
1623        ALuint collected_bytes = 0;
1624        int i;
1625
1626        src = _alGetSource(cid, sourceid);
1627        if(src == NULL)
1628        {
1629                /*
1630                 * Should we really be setting the error here?
1631                 */
1632                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
1633                      "_alSplitSourceQueue: invalid source id %d",
1634                      sourceid);
1635
1636                _alSetError(cid, AL_INVALID_NAME);
1637                return;
1638        }
1639
1640        old_soundpos = src->srcParams.soundpos;
1641        old_readindex = src->bid_queue.read_index;
1642
1643#if 1
1644        if( _alSourceBytesLeftByChannel(src, samp) <= 0)
1645        {
1646
1647                ALuint bid = 0;
1648
1649                /* no data left in this buffer */
1650                src->bid_queue.read_index++;
1651                if(src->bid_queue.read_index >= src->bid_queue.size)
1652                {
1653                        /* JIV FIXME: breaks queue looping? */
1654                        if(_alSourceIsLooping(src))
1655                        {
1656                                src->bid_queue.read_index = 0;
1657                        }
1658                        else
1659                        {
1660                                /* JIV FIXME: doesn't mix last queue bit */
1661
1662                                return;
1663                        }
1664                }
1665
1666                bid  = src->bid_queue.queue[src->bid_queue.read_index];
1667                samp = _alGetBuffer(bid);
1668                if(samp == NULL)
1669                {
1670                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
1671                                 "_alSplitSourceQueue: null buffer");
1672
1673                        return;
1674                }
1675
1676                src->srcParams.soundpos = 0;
1677
1678                /* ho ho ho ho */
1679                _alSplitSources(cid, sourceid, nc, len, samp, buffers);
1680                return;
1681        }
1682#endif
1683
1684        nextbid = src->bid_queue.queue[src->bid_queue.read_index + 1];
1685        nextsamp = _alGetBuffer(nextbid);
1686        if(nextsamp == NULL)
1687        {
1688                /*
1689                 * Should we really be setting the error here?
1690                 */
1691                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
1692                      "_alSplitSourceQueue: shouldn't happen");
1693
1694                return;
1695        }
1696
1697/*      assert(len >= 0); */
1698/*      assert(src->srcParams.soundpos >= 0); */
1699
1700        /*
1701         *
1702         * First, test whether we can get enough data to fill the
1703         * request with the current buffer's data ( minus current sound
1704         * pos ) plus the next buffer's data.
1705         */
1706        if( samp->size + nextsamp->size >= len + src->srcParams.soundpos )
1707        {
1708#ifdef DEBUG_QUEUE
1709                _alDebug(ALD_QUEUE, __FILE__, __LINE__,
1710                         "Queue filling from two buffers ( size + nextsize (%d) vs soundpos + len %d",
1711                        samp->size + nextsamp->size,
1712                         len + src->srcParams.soundpos);
1713#endif
1714
1715                /* we can fill the request */
1716                mixable = _alSourceBytesLeftByChannel(src, samp);
1717                remaining = 0;
1718
1719                assert( mixable >= 0 );
1720
1721                /*
1722                 * in case samp->size < len, we don't want
1723                 * to overwrite with the memcpy
1724                 */
1725                remaining = len - mixable;
1726
1727#ifdef DEBUG_QUEUE
1728                _alDebug(ALD_QUEUE, __FILE__, __LINE__,
1729                         "first buffer %d, second buffer %d",
1730                         mixable, remaining);
1731#endif
1732
1733
1734                for(i = 0; i < nc; i++) {
1735                        bufptr = _alSourceGetBufptr(src, samp, i);
1736                        nextpcm = nextsamp->orig_buffers[i];
1737
1738                        memcpy(buffers[i], bufptr, mixable);
1739                        memcpy(buffers[i] + mixable/2, nextpcm, remaining);
1740                }
1741
1742                src->srcParams.new_readindex = src->bid_queue.read_index + 1;
1743                src->srcParams.new_soundpos = remaining;
1744
1745                if(remaining >= nextsamp->size)
1746                {
1747                        /* we read all of the next buffer */
1748                        src->srcParams.new_readindex++;
1749                }
1750
1751#ifdef DEBUG_QUEUE
1752                _alDebug(ALD_QUEUE, __FILE__, __LINE__,
1753                         "SplitSourceQueue, read_index is now %d",
1754                         src->srcParams.new_readindex);
1755#endif
1756
1757                return;
1758        }
1759
1760#ifdef DEBUG_QUEUE
1761        fprintf(stderr, "Splitting from multiple needed %d left %d\n",
1762                len,
1763                samp->size - src->srcParams.soundpos);
1764#endif
1765
1766        /*
1767         * We need to get data from more than one buffer
1768         */
1769        while( collected_bytes < len )
1770        {
1771                int bid;
1772
1773                if( src->bid_queue.read_index >= src->bid_queue.size )
1774                {
1775#ifdef DEBUG_QUEUE
1776                        fprintf(stderr, "end of buffer queue\n" );
1777#endif
1778
1779                        /*
1780                         * Read past the last buffer and we still
1781                         * have to write out.  Pad the rest with silence,
1782                         * I guess.  Do we support looping queued buffers?
1783                         */
1784                        for(i = 0; i < nc; i++)
1785                        {
1786                                memset(buffers[i] + collected_bytes/2,
1787                                       0, len - collected_bytes);
1788                        }
1789
1790                        src->bid_queue.read_index = old_readindex;
1791                        src->srcParams.soundpos   = old_soundpos;
1792
1793                        return;
1794                }
1795
1796                assert(src->bid_queue.read_index < src->bid_queue.size );
1797
1798                bid = src->bid_queue.queue[src->bid_queue.read_index];
1799                samp = _alGetBuffer(bid);
1800
1801                mixable = samp->size - src->srcParams.soundpos;
1802
1803                if(mixable > (int) (len - collected_bytes))
1804                {
1805                        mixable = len - collected_bytes;
1806                        new_soundpos = src->srcParams.soundpos + mixable;
1807                }
1808                else
1809                {
1810                        src->bid_queue.read_index++;
1811                        new_soundpos = 0;
1812                }
1813
1814                /* copy from current buffer */
1815                for(i = 0; i < nc; i++)
1816                {
1817                        bufptr = _alSourceGetBufptr(src, samp, i);
1818
1819                        memcpy(buffers[i] + collected_bytes/2, bufptr, mixable);
1820                }
1821
1822                collected_bytes += mixable;
1823
1824                src->srcParams.soundpos = new_soundpos;
1825        }
1826
1827        src->srcParams.new_readindex = src->bid_queue.read_index;
1828        src->srcParams.new_soundpos = new_soundpos;
1829
1830        src->bid_queue.read_index = old_readindex;
1831        src->srcParams.soundpos   = old_soundpos;
1832
1833        return;
1834}
1835
1836/*
1837 * _alMonoifyOffset( ALshort **dstref, ALuint offset,
1838 *                   ALvoid *src, ALuint src_size,
1839 *                   ALuint dest_channels, ALuint src_channels )
1840 *
1841 * Copies the interleaved data from src[0..(src_size/2)-1] to
1842 * dstret[0..dest_channels-1], splitting it into seperate channels.
1843 * src_channels describes the period of the channel repetition in src,
1844 * dest_channels describes the number of independant buffers in dstref.
1845 * src_size is the size of src in bytes, and offset is the offset into each
1846 * seperate channel in dstref where the copying begins.
1847 *
1848 * assumes locked context
1849 */
1850void _alMonoifyOffset(ALshort **dstref, ALuint offset,
1851                      ALvoid *srcp, ALuint size, ALuint dc, ALuint sc) {
1852        switch( dc ) {
1853                case 4:
1854                  switch(sc) {
1855                          case 1:
1856                                _alMonoifyOffset1to4(dstref, offset, srcp, size);
1857                                break;
1858                          case 2:
1859                                _alMonoifyOffset2to4(dstref, offset, srcp, size);
1860                                break;
1861                          case 4:
1862                                _alMonoifyOffset4to4(dstref, offset, srcp, size);
1863                                break;
1864                          default:
1865                                fprintf(stderr, "unhandled Monoify (dc %d sc %d)\n",
1866                                        dc, sc);
1867                                break;
1868                  }
1869                  break;
1870                case 2:
1871                  switch(sc) {
1872                          case 1:
1873                                _alMonoifyOffset1to2(dstref, offset, srcp, size);
1874                                break;
1875                          case 2:
1876                                _alMonoifyOffset2to2(dstref, offset, srcp, size);
1877                                break;
1878                          default:
1879                                fprintf(stderr, "unhandled Monoify (dc %d sc %d)\n",
1880                                        dc, sc);
1881                                break;
1882                  }
1883                  break;
1884                case 1:
1885                  switch(sc) {
1886                          case 1:
1887                                memcpy((char *) *dstref + offset, srcp, size);
1888                                break;
1889                          default:
1890                                fprintf(stderr, "unhandled Monoify (dc %d sc %d)\n",
1891                                        dc, sc);
1892                                break;
1893                  }
1894                  break;
1895                default:
1896                  _alDebug(ALD_SOURCE, __FILE__, __LINE__,
1897                        "Unhandled dc %d", dc);
1898                  break;
1899        }
1900
1901        return;
1902}
1903
1904static void _alMonoifyOffset1to4( ALshort **dsts, ALuint offset,
1905                                  ALvoid *srcp, ALuint size) {
1906        ALshort *src = (ALshort *) srcp;
1907        ALshort *dst0 = dsts[0];
1908        ALshort *dst1 = dsts[1];
1909        ALshort *dst2 = dsts[2];
1910        ALshort *dst3 = dsts[3];
1911
1912        int len      = size / sizeof *src;
1913        int i;
1914
1915        offset /= sizeof **dsts;
1916        dst0 += offset;
1917        dst1 += offset;
1918        dst2 += offset;
1919        dst3 += offset;
1920
1921        for(i = 0; i < len; i++) {
1922                dst0[i] = src[0];
1923                dst1[i] = src[0];
1924                dst2[i] = src[0];
1925                dst3[i] = src[0];
1926
1927                src++;
1928        }
1929
1930        return;
1931}
1932
1933
1934
1935static void _alMonoifyOffset2to4( ALshort **dsts, ALuint offset,
1936                                  ALvoid *srcp, ALuint size) {
1937        ALshort *src = (ALshort *) srcp;
1938        ALshort *dst0 = dsts[0];
1939        ALshort *dst1 = dsts[1];
1940        ALshort *dst2 = dsts[2];
1941        ALshort *dst3 = dsts[3];
1942
1943        int len      = size / sizeof *src;
1944        int i;
1945
1946        offset /= sizeof **dsts;
1947        dst0 += offset;
1948        dst1 += offset;
1949        dst2 += offset;
1950        dst3 += offset;
1951
1952        for(i = 0; i < len; i++) {
1953                dst0[i] = src[0];
1954                dst1[i] = src[1];
1955                dst2[i] = src[0];
1956                dst3[i] = src[1];
1957
1958                src += 2;
1959        }
1960
1961        return;
1962}
1963
1964
1965
1966static void _alMonoifyOffset4to4( ALshort **dsts, ALuint offset,
1967                                  ALvoid *srcp, ALuint size) {
1968        ALshort *src = (ALshort *) srcp;
1969        ALshort *dst0 = dsts[0];
1970        ALshort *dst1 = dsts[1];
1971        ALshort *dst2 = dsts[2];
1972        ALshort *dst3 = dsts[3];
1973
1974        int len      = size / sizeof *src;
1975        int i;
1976
1977        offset /= sizeof **dsts;
1978        dst0 += offset;
1979        dst1 += offset;
1980        dst2 += offset;
1981        dst3 += offset;
1982
1983        for(i = 0; i < len; i++) {
1984                dst0[i] = src[0];
1985                dst1[i] = src[1];
1986                dst2[i] = src[2];
1987                dst3[i] = src[3];
1988
1989                src += 4;
1990        }
1991
1992        return;
1993}
1994
1995
1996/*
1997 * _alMonoifyOffset1to2( ALshort **dsts, ALuint offset,
1998 *                       ALvoid *srcp, ALuint size)
1999 *
2000 * Helper function for _alMonoifyOffset.  Converts from stereo to 2 channels
2001 * of buffer data.
2002 */
2003static void _alMonoifyOffset1to2( ALshort **dsts, ALuint offset,
2004                                  ALvoid *srcp, ALuint size) {
2005        ALshort *src = (ALshort *) srcp;
2006        ALshort *dst0 = dsts[0];
2007        ALshort *dst1 = dsts[1];
2008        int len      = size / sizeof *src;
2009        int i;
2010
2011        offset /= sizeof **dsts;
2012        dst0 += offset;
2013        dst1 += offset;
2014
2015        for(i = 0; i < len; i++) {
2016                dst0[i] = src[0];
2017                dst1[i] = src[0];
2018
2019                src++;
2020        }
2021
2022        return;
2023}
2024
2025/*
2026 * _alMonoifyOffset2to2( ALshort **dsts, ALuint offset,
2027 *                       ALvoid *srcp, ALuint size )
2028 *
2029 * Helper function for _alMonoifyOffset.  Converts from stereo to 2 channels
2030 * of buffer data.
2031 */
2032static void _alMonoifyOffset2to2( ALshort **dsts, ALuint offset,
2033                                  ALvoid *srcp, ALuint size) {
2034        ALshort *src = (ALshort *) srcp;
2035        ALshort *dst0 = dsts[0];
2036        ALshort *dst1 = dsts[1];
2037        int len      = size / sizeof *src;
2038        int i;
2039
2040        offset /= sizeof **dsts;
2041
2042        dst0 += offset;
2043        dst1 += offset;
2044
2045        for(i = 0; i < len; i++) {
2046                dst0[i] = src[0];
2047                dst1[i] = src[1];
2048
2049                src += 2;
2050        }
2051
2052        return;
2053}
2054
2055/*
2056 * _alChannelifyOffset( ALshort *dst, ALuint offset,
2057 *                      ALshort **srcs, ALuint size, ALuint nc )
2058 *
2059 * This function is sort of the complement of _alMonoifyOffset.  Data is
2060 * copied from srcs[0..nc-1][offset/2..(offset + size)/2-1] into an
2061 * interleaved array dst.
2062 *
2063 * assumes locked context
2064 *
2065 *  FIXME: handle cases with > 2 channels
2066 */
2067void _alChannelifyOffset( ALshort *dst, ALuint offset,
2068                          ALshort **srcs, ALuint size, ALuint nc )
2069{
2070        switch( nc )
2071        {
2072                case 4:
2073                        _alChannelify4Offset(dst, offset, srcs, size);
2074                        break;
2075                case 2:
2076                        _alChannelify2Offset(dst, offset, srcs, size);
2077                        break;
2078                case 1:
2079                        memcpy( dst, srcs[0] + offset/sizeof *srcs, size );
2080                        break;
2081                default:
2082                        break;
2083        }
2084
2085        return;
2086}
2087
2088/*
2089 *  _alChannelify2Offset( ALshort *dst, ALuint offset,
2090 *                        ALshort **srcs, ALuint size )
2091 *
2092 * This function is like ChannelifyOffset, but specificly for those cases
2093 * where the number of channels in srcs is 2.
2094 *
2095 * assumes locked context
2096 */
2097void _alChannelify2Offset( ALshort *dst, ALuint offset,
2098                           ALshort **srcs, ALuint size ) {
2099        ALshort *src0 = &srcs[0][offset / sizeof *srcs];
2100        ALshort *src1 = &srcs[1][offset / sizeof *srcs];
2101        ALuint k;
2102
2103        size /= sizeof *dst; /* we need sample offsets */
2104
2105        for( k = 0; k < size; k++ ) {
2106                dst[0] = src0[k];
2107                dst[1] = src1[k];
2108
2109                dst += 2;
2110        }
2111
2112        return;
2113}
2114
2115/*
2116 *  _alChannelify4Offset( ALshort *dst, ALuint offset,
2117 *                        ALshort **srcs, ALuint size )
2118 *
2119 * This function is like ChannelifyOffset, but specificly for those cases
2120 * where the number of channels in srcs is 4.
2121 *
2122 * assumes locked context
2123 */
2124void _alChannelify4Offset( ALshort *dst, ALuint offset,
2125                           ALshort **srcs, ALuint size ) {
2126        ALshort *src0 = &srcs[0][offset / sizeof *srcs];
2127        ALshort *src1 = &srcs[1][offset / sizeof *srcs];
2128        ALshort *src2 = &srcs[2][offset / sizeof *srcs];
2129        ALshort *src3 = &srcs[3][offset / sizeof *srcs];
2130        ALuint k;
2131
2132        size /= sizeof *dst; /* we need sample offsets */
2133
2134        for( k = 0; k < size; k++ ) {
2135                dst[0] = src0[k];
2136                dst[1] = src1[k];
2137                dst[2] = src2[k];
2138                dst[3] = src3[k];
2139
2140                dst += 4;
2141        }
2142
2143        return;
2144}
2145
2146
2147
2148/*
2149 * alDeleteSources( ALsizei n, ALuint *sources )
2150 *
2151 * Delete n sources, with sids located in sources[0..n-1].  Only full
2152 * deallocations are possible, and if one of sources[0..n-1] is not a
2153 * valid source id (or is currently in an active state), and error is
2154 * set and no deallocation occurs.
2155 *
2156 * If n is 0, this is a legal nop.  If n < 0, INVALID_VALUE is set
2157 * and this is a nop.
2158 */
2159void alDeleteSources( ALsizei n, const ALuint *sources ) {
2160        AL_source *src;
2161        AL_context *cc;
2162        int i;
2163
2164        if(n == 0) {
2165                /* silently return */
2166                return;
2167        }
2168
2169        if(n < 0) {
2170                _alDebug(ALD_BUFFER, __FILE__, __LINE__,
2171                      "alDeleteSources: invalid n %d\n", n);
2172
2173                _alDCSetError(AL_INVALID_VALUE);
2174                return;
2175        }
2176
2177        _alcDCLockContext();
2178
2179        cc = _alcDCGetContext();
2180        if(cc == NULL) {
2181                /*
2182                 * No current context with which to evaluate the
2183                 * validity of the sources
2184                 */
2185                _alcDCUnlockContext();
2186                return;
2187        }
2188
2189        for(i = 0; i < n; i++) {
2190                src = _alDCGetSource( sources[i] );
2191                if(src == NULL) {
2192                        /* invalid source id, return. */
2193                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
2194                              "alDeleteSources: invalid source %d",
2195                              sources[i]);
2196
2197                        _alDCSetError( AL_INVALID_NAME );
2198                        _alcDCUnlockContext();
2199
2200                        return;
2201                }
2202
2203                if((src->state == AL_PLAYING) || (src->state == AL_PAUSED)) {
2204                        /*
2205                         * FIXME: illegal to delete playing source?
2206                         */
2207                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
2208                              "alDeleteSources: tried to delete playing/paused source %d",
2209                              sources[i]);
2210
2211                        _alDCSetError(AL_INVALID_OPERATION);
2212                        _alcDCUnlockContext();
2213                        return;
2214                }
2215
2216        }
2217
2218        for(i = 0; i < n; i++) {
2219                src = _alDCGetSource(sources[i]);
2220                if(src == NULL) {
2221                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
2222                              "alDeleteSources: invalid source %d",
2223                              sources[i]);
2224
2225                        _alDCSetError(AL_INVALID_NAME);
2226                        continue;
2227                }
2228
2229                if(src->state == AL_PLAYING) {
2230                        /*
2231                         * FIXME: illegal to delete playing source?
2232                         */
2233                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
2234                              "alDeleteSources: tried to del playing source %d",
2235                              sources[i]);
2236
2237                        _alDCSetError(AL_INVALID_OPERATION);
2238                        continue;
2239                }
2240
2241                spool_dealloc(&cc->source_pool, sources[i],
2242                                                _alDestroySource);
2243        }
2244
2245        _alcDCUnlockContext();
2246        return;
2247}
2248
2249/*
2250 * _alDestroySources
2251 *
2252 * This destructor is responsible for deallocating source data structures
2253 * after openal has finished.
2254 */
2255void _alDestroySources(spool_t *spool) {
2256        ALuint i;
2257
2258        for( i = 0; i < spool->size; i++ ) {
2259                _alDestroyMutex( spool->smutexen[i] );
2260        }
2261
2262
2263        spool_free( spool, _alDestroySource );
2264
2265        free( spool->smutexen );
2266        free( stereoptr );
2267
2268        spool->smutexen = NULL;
2269        stereoptr = NULL;
2270
2271        return;
2272}
2273
2274/*
2275 * _alDestroySource
2276 *
2277 * Deallocates the memory associated with an AL_source, passed as a void *
2278 * to this function.
2279 *
2280 * assumes locked context
2281 */
2282void _alDestroySource( void *srcp ) {
2283        AL_source *src = (AL_source *) srcp;
2284        ALuint *bidp;
2285        int i;
2286
2287        /*
2288         * if we have a callback buffer, call the
2289         * destructor with the "free one source" args
2290         */
2291        bidp = _alGetSourceParam(src, AL_BUFFER);
2292        if(bidp != NULL) {
2293                if(_alBidIsCallback(*bidp) == AL_TRUE) {
2294                        _alBidCallDestroyCallbackSource(src->sid);
2295                }
2296        }
2297
2298        /* deallocation per source scratch space */
2299        free(src->srcParams.outbuf);
2300        src->srcParams.outbuf = NULL;
2301
2302        for(i = _alcDCGetNumSpeakers() - 1; i >= 0; i--) {
2303                if(src->reverb_buf[i] != NULL) {
2304                        /* deallocation reverb scratch space */
2305                        free( src->reverb_buf[i] );
2306                        src->reverb_buf[i] = NULL;
2307                }
2308        }
2309
2310        free( src->bid_queue.queuestate );
2311        free( src->bid_queue.queue );
2312
2313        src->bid_queue.queue = NULL;
2314        src->bid_queue.queuestate = NULL;
2315        src->bid_queue.size = 0;
2316
2317        return;
2318}
2319
2320/*
2321 * alSourcePause( ALuint sid )
2322 *
2323 * If sid is a valid source name, then if the source associated with it has
2324 * the state AL_PLAYING, it will be taken to the state AL_PAUSED.
2325 *
2326 * If sid is not a valid source name, set AL_INVALID_NAME.
2327 */
2328void alSourcePause( ALuint sid ) {
2329        alSourcePausev( 1, &sid );
2330
2331        return;
2332}
2333
2334/*
2335 * alSourcePlay( ALuint sid )
2336 *
2337 * If sid is a valid source name, then if the source associated with it has
2338 * the state AL_INITAL, AL_PAUSED, or AL_STOPPED, it will be taken to the
2339 * state AL_PLAYING.
2340 *
2341 * If sid is not a valid source name, set AL_INVALID_NAME.
2342 */
2343void alSourcePlay( ALuint sid ) {
2344        alSourcePlayv( 1, &sid );
2345
2346        return;
2347}
2348
2349/*
2350 * alSourceStop( ALuint sid )
2351 *
2352 * If sid is a valid source name, then if the source associated with it has
2353 * the state AL_PLAYING or AL_PAUSED it will be taken to the state AL_STOPPED.
2354 *
2355 * If sid is not a valid source name, set AL_INVALID_NAME.
2356 */
2357void alSourceStop( ALuint sid ) {
2358        alSourceStopv( 1, &sid );
2359
2360        return;
2361}
2362
2363/*
2364 * alSourceRewind( ALuint sid )
2365 *
2366 * If sid is a valid source name, then if the source associated with it has
2367 * the state AL_PLAYING, AL_PAUSED or AL_STOPPED, it will be taken to the
2368 * state AL_INITAL.
2369 *
2370 * If the source is playing or paused, it will first be stopped.
2371 *
2372 * If sid is not a valid source name, set AL_INVALID_NAME.
2373 */
2374void alSourceRewind( ALuint sid ) {
2375        alSourceRewindv( 1, &sid );
2376
2377        return;
2378}
2379
2380/*
2381 * alSourceRewindv( ALsizei ns, ALuint *sids )
2382 *
2383 * If ns == 0, legal NOP.
2384 * If ns < 0, sets AL_INVALID_VALUE.
2385 *
2386 * If sids[0..ns-1] are all valid source names, then for each source with
2387 * state AL_PLAYING, AL_PAUSED or AL_STOPPER change the state to AL_INITAL.
2388 * If sources are playing or paused, they will first be stopped.
2389 *
2390 * If any member of sids[0..ns-1] is not a valid source name, set
2391 * AL_INVALID_NAME.
2392 */
2393void alSourceRewindv( ALsizei ns, const ALuint *sids ) {
2394        AL_source *src;
2395        ALsizei i;
2396
2397        if( ns == 0 ) {
2398                /* legal NOP */
2399                return;
2400        }
2401
2402        if( ns < 0 ) {
2403                /* set error */
2404                _alcDCLockContext();
2405                _alDCSetError( AL_INVALID_VALUE );
2406                _alcDCUnlockContext();
2407
2408                return;
2409        }
2410
2411        SOURCELOCK();
2412
2413        /* validate */
2414        for( i = 0; i < ns; i++ ) {
2415                if( _alIsSource( sids[i] ) == AL_FALSE ) {
2416                        _alDCSetError( AL_INVALID_NAME );
2417
2418                        SOURCEUNLOCK();
2419
2420                        return;
2421                }
2422        }
2423
2424        _alLockMixBuf();
2425
2426        for( i = 0; i < ns; i++ ) {
2427                src = _alDCGetSource( sids[i] );
2428                if(src == NULL) {
2429                        /* shouldn't happen */
2430                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
2431                              "alSourceRewindv: source id %d is invalid",
2432                              sids[i] );
2433
2434                        _alDCSetError( AL_INVALID_NAME );
2435
2436                        SOURCEUNLOCK();
2437                        return;
2438                }
2439
2440
2441                switch( src->state ) {
2442                        case AL_INITIAL:
2443                                /* legal NOP */
2444                                break;
2445                        case AL_PAUSED:
2446                        case AL_PLAYING:
2447                                _alRemoveSourceFromMixer( sids[i] );
2448                        case AL_STOPPED:
2449                                src->state = AL_INITIAL;
2450                                src->srcParams.soundpos = 0;
2451                                break;
2452                }
2453        }
2454
2455        _alUnlockMixBuf();
2456
2457        SOURCEUNLOCK();
2458
2459        return;
2460}
2461
2462/*
2463 * alSourceStopv( ALsizei ns, ALuint *sids )
2464 *
2465 * If ns == 0, legal NOP.
2466 * If ns < 0, sets AL_INVALID_VALUE.
2467 *
2468 * If sids[0..ns-1] are all valid source names, then for each source with
2469 * state AL_PLAYING or AL_PAUSED change the state to AL_STOPPED.  Otherwise,
2470 * set AL_INVALID_NAME.
2471 */
2472void alSourceStopv( ALsizei ns, const ALuint *sids ) {
2473        ALsizei i;
2474
2475        if( ns == 0 ) {
2476                /* legal NOP */
2477                return;
2478        }
2479
2480        if( ns < 0 ) {
2481                /* set error */
2482                _alcDCLockContext();
2483                _alDCSetError( AL_INVALID_VALUE );
2484                _alcDCUnlockContext();
2485
2486                return;
2487        }
2488
2489        SOURCELOCK();
2490
2491        /* validate */
2492        for( i = 0; i < ns; i++ ) {
2493                if( _alIsSource( sids[i] ) == AL_FALSE ) {
2494                        _alDCSetError( AL_INVALID_NAME );
2495
2496                        SOURCEUNLOCK();
2497
2498                        return;
2499                }
2500        }
2501
2502        _alLockMixBuf();
2503
2504        for( i = 0; i < ns; i++ ) {
2505                _alRemoveSourceFromMixer( sids[i] );
2506        }
2507
2508        _alUnlockMixBuf();
2509
2510        SOURCEUNLOCK();
2511
2512        return;
2513}
2514
2515/*
2516 * alSourcePlayv( ALsizei ns, ALuint *sids )
2517 *
2518 * If ns == 0, legal NOP.
2519 * If ns < 0, sets AL_INVALID_VALUE.
2520 *
2521 * If sids[0..ns-1] are all valid source names, then for each source with
2522 * state AL_INITIAL, AL_STOPPED or AL_PAUSED, change the state to AL_PLAYING.
2523 * Otherwise, set AL_INVALID_NAME.
2524 */
2525void alSourcePlayv( ALsizei ns, const ALuint *sids ) {
2526        ALsizei i;
2527
2528        if( ns == 0 ) {
2529                /* legal NOP */
2530                return;
2531        }
2532
2533        if( ns < 0 ) {
2534                /* set error */
2535                _alcDCLockContext();
2536                _alDCSetError( AL_INVALID_VALUE );
2537                _alcDCUnlockContext();
2538
2539                return;
2540        }
2541
2542        SOURCELOCK();
2543
2544        /* validate */
2545        for( i = 0; i < ns; i++ ) {
2546                if( _alIsSource( sids[i] ) == AL_FALSE ) {
2547                        _alDCSetError( AL_INVALID_NAME );
2548
2549                        SOURCEUNLOCK();
2550
2551                        return;
2552                }
2553        }
2554
2555        _alLockMixBuf();
2556
2557        for(i = 0; i < ns; i++) {
2558                _alAddSourceToMixer( sids[i] );
2559        }
2560
2561        _alUnlockMixBuf();
2562
2563        SOURCEUNLOCK();
2564
2565        return;
2566}
2567
2568/*
2569 * alSourcePausev( ALsizei ns, ALuint *sids )
2570 *
2571 * If ns == 0, legal NOP.
2572 * If ns < 0, sets AL_INVALID_VALUE.
2573 *
2574 * If sids[0..ns-1] are all valid source names, then for each source with
2575 * state AL_PLAYING, change the state to AL_PAUSED.  Otherwise, set
2576 * AL_INVALID_NAME.
2577 *
2578 */
2579void alSourcePausev( ALsizei ns, const ALuint *sids ) {
2580        AL_source *src;
2581        ALsizei i;
2582
2583        if( ns == 0 ) {
2584                 /* legal NOP */
2585                return;
2586        }
2587
2588        if( ns < 0 ) {
2589                /* set error */
2590                _alcDCLockContext();
2591                _alDCSetError( AL_INVALID_VALUE );
2592                _alcDCUnlockContext();
2593
2594                return;
2595        }
2596
2597        SOURCELOCK();
2598
2599        /* validate */
2600        for( i = 0; i < ns; i++ ) {
2601                if( _alIsSource( sids[i] ) == AL_FALSE ) {
2602                        _alDCSetError( AL_INVALID_NAME );
2603
2604                        SOURCEUNLOCK();
2605
2606                        return;
2607                }
2608        }
2609
2610        /* set */
2611
2612        _alLockMixBuf();
2613
2614        for( i = 0; i < ns; i++ ) {
2615                src = _alDCGetSource( sids[i] );
2616
2617                /*
2618                 * If source is active, set it to be paused.  Otherwise,
2619                 * it's a legal NOP.
2620                 */
2621
2622                if( src->state == AL_PLAYING ) {
2623                        src->state = AL_PAUSED;
2624                }
2625        }
2626
2627        _alUnlockMixBuf();
2628
2629        SOURCEUNLOCK();
2630
2631        return;
2632}
2633
2634/*
2635 * _alCollapseSource( ALuint cid, ALuint sid,
2636 *                    ALuint nc, ALuint mixbuflen,
2637 *                    ALshort **buffers );
2638 *
2639 * Populates the scratch space associated with the source named by sid in the
2640 * context named by cid with interleaved data.  The data is interleaved using
2641 * alternating channels from buffers[0..nc-1].  Each member of the set
2642 * buffers[0..nc-1] is an indepedent channel's worth of data, 0..mixbuflen/2
2643 * long bytes long.
2644 *
2645 * assumes locked context
2646 */
2647void _alCollapseSource( ALuint cid, ALuint sid,
2648                        ALuint nc, ALuint mixbuflen,
2649                        ALshort **buffers ) {
2650        ALboolean islooping;
2651        ALboolean isqueued;
2652        AL_source *src;
2653        AL_buffer *smp;
2654        ALuint len;
2655
2656        len = mixbuflen / nc;
2657
2658        src = _alGetSource( cid, sid );
2659        if(src == NULL) {
2660                _alSetError( cid, AL_INVALID_NAME );
2661                return;
2662        }
2663
2664        smp = _alGetBufferFromSid( cid, sid );
2665        if(smp == NULL) {
2666                _alSetError( cid, AL_INVALID_NAME );
2667                return;
2668        }
2669
2670        islooping = _alSourceIsLooping(src);
2671        isqueued  = _alSourceGetPendingBids(src) > 0;
2672
2673        if(src->srcParams.outbuf == NULL) {
2674                src->srcParams.outbuf = malloc( mixbuflen );
2675
2676                if(src->srcParams.outbuf == NULL) {
2677                        _alSetError( cid, AL_OUT_OF_MEMORY );
2678                        return;
2679                }
2680        }
2681
2682        if(len > (smp->size - src->srcParams.soundpos)) {
2683                if( !isqueued  && !islooping )
2684                {
2685                        /* kludge.  dc->silence? */
2686                        memset(src->srcParams.outbuf, 0, mixbuflen);
2687
2688                        /*
2689                         * Non looping source get f_buffer truncated because
2690                         * they don't (potentially) posses enough data.
2691                         */
2692                        len = (smp->size - src->srcParams.soundpos);
2693                }
2694        }
2695
2696        _alChannelify(src->srcParams.outbuf, buffers, len, nc);
2697
2698        return;
2699}
2700
2701/*
2702 * _alInitSource( ALuint sid )
2703 *
2704 * Initialize an already allocated source.
2705 */
2706static void _alInitSource( ALuint sid ) {
2707        AL_source *src;
2708        AL_sourcestate *srcstate;
2709        int i;
2710
2711        src = _alDCGetSource( sid );
2712        if(src == NULL) {
2713                /* sid is invalid */
2714                return;
2715        }
2716
2717        /* set state */
2718        src->state = AL_INITIAL;
2719
2720        /* set identifier */
2721        src->sid = sid;
2722
2723        /* set data values */
2724        src->srcParams.outbuf   = NULL;
2725        src->srcParams.soundpos = 0;
2726        src->srcParams.new_soundpos = -1;
2727        src->srcParams.new_readindex = -1;
2728        src->flags              = ALS_NONE;
2729        src->reverbpos          = 0;
2730
2731        for(i = 0; i < _ALC_MAX_CHANNELS; i++) {
2732                src->reverb_buf[i] = NULL;
2733        }
2734
2735        /* Initialize the buffer queue */
2736        _alSourceQueueInit( src );
2737
2738        srcstate = _alSourceQueueGetCurrentState( src );
2739        assert( srcstate );
2740
2741        _alSourceStateInit( srcstate );
2742
2743        /*
2744         * initialize position, direction, velocity.
2745         */
2746        src->position.isset = AL_FALSE;
2747        _alSourceGetParamDefault( AL_POSITION, src->position.data );
2748
2749        src->direction.isset = AL_FALSE;
2750        _alSourceGetParamDefault( AL_DIRECTION, src->direction.data );
2751
2752        src->velocity.isset = AL_FALSE;
2753        _alSourceGetParamDefault( AL_VELOCITY, src->velocity.data );
2754
2755        /*
2756         * initialize reverb kludge
2757         */
2758        src->reverb_scale = 0.25;
2759        src->reverb_delay = 0.00;
2760
2761        /*
2762         * initialize default mix rate
2763         */
2764        src->mixrate = 1.0;
2765       
2766        /*
2767         * initialize gain
2768         */
2769        src->gain.isset = AL_FALSE;
2770        _alSourceGetParamDefault( AL_GAIN, &src->gain.data );
2771
2772        src->min_gain.isset = AL_FALSE;
2773        _alSourceGetParamDefault( AL_MIN_GAIN, &src->min_gain.data );
2774
2775        src->max_gain.isset = AL_FALSE;
2776        _alSourceGetParamDefault( AL_MAX_GAIN, &src->max_gain.data );
2777
2778        /* cone initializations */
2779        src->cone_inner_angle.isset = AL_FALSE;
2780        _alSourceGetParamDefault( AL_CONE_INNER_ANGLE,
2781                                  &src->cone_inner_angle.data );
2782
2783        src->cone_outer_angle.isset = AL_FALSE;
2784        _alSourceGetParamDefault( AL_CONE_OUTER_ANGLE,
2785                                  &src->cone_outer_angle.data );
2786
2787        src->cone_outer_gain.isset = AL_FALSE;
2788        _alSourceGetParamDefault( AL_CONE_OUTER_GAIN,
2789                                  &src->cone_outer_gain.data );
2790
2791        /*
2792         * initialize source relative, looping, pitch
2793         */
2794
2795        src->relative.isset = AL_FALSE;
2796        _alSourceGetParamDefault( AL_SOURCE_RELATIVE, &src->relative.data );
2797
2798        src->looping.isset = AL_FALSE;
2799        _alSourceGetParamDefault( AL_LOOPING, &src->looping.data );
2800
2801        src->pitch.isset = AL_FALSE;
2802        _alSourceGetParamDefault( AL_PITCH, &src->pitch.data );
2803
2804        /*
2805         * initialize reference distance, max distance, rolloff factor
2806         */
2807        src->reference_distance.isset = AL_FALSE;
2808        _alSourceGetParamDefault( AL_REFERENCE_DISTANCE,
2809                                  &src->reference_distance.data );
2810
2811        src->max_distance.isset = AL_FALSE;
2812        _alSourceGetParamDefault( AL_MAX_DISTANCE,
2813                                  &src->max_distance.data );
2814
2815        src->rolloff_factor.isset = AL_FALSE;
2816        _alSourceGetParamDefault( AL_ROLLOFF_FACTOR,
2817                                  &src->rolloff_factor.data );
2818
2819        return;
2820}
2821
2822/*
2823 * _alSourceTranslate( AL_source *src, ALfloat *delta )
2824 *
2825 * Translates the source (src) position attribute by delta.  Delta is a three
2826 * tuple x/y/z.
2827 *
2828 * assumes locked context
2829 */
2830void _alSourceTranslate( AL_source *src, ALfloat *delta ) {
2831        ALfloat *opos; /* original source position */
2832
2833        opos = _alGetSourceParam( src, AL_POSITION );
2834        if( opos == NULL ) {
2835                /* no translation possible or needed */
2836                return;
2837        }
2838
2839        _alVectorTranslate( opos, opos, delta );
2840
2841        return;
2842}
2843
2844/*
2845 * srcParam functions
2846 *
2847 * The use of srcParam settings is this: most filter operations break down
2848 * into applying a multiplier or delay to the raw PCM data copied in
2849 * SplitSources.  Since there operations are cumulative, this can be simplified
2850 * by simply collecting the coefficients of the operations and applying them
2851 * all at one.  So instead of actually performing a gain or delay operation on
2852 * the PCM data, the filter can change the srcParam setting, which is applied
2853 * in _alSourceParamApply.
2854 *
2855 */
2856
2857/*
2858 * _alSourceParamReset( AL_source *src )
2859 *
2860 * Resets the srcParam settings gain and delay.  Does not affect srcParam
2861 * settings associated with sound position or the temporary scratch space.
2862 *
2863 * assumes locked context
2864 */
2865void _alSourceParamReset( AL_source *src ) {
2866        AL_listener *lis;
2867        int i;
2868
2869        lis = _alcDCGetListener();
2870
2871        if(src == NULL) {
2872                return;
2873        }
2874
2875        for(i = 0; i < _ALC_MAX_CHANNELS; i++) {
2876                src->srcParams.delay[i] = 0;
2877                src->srcParams.gain[i]  = 1.0;
2878        }
2879
2880        return;
2881}
2882
2883/*
2884 * _alSourceParamApply( AL_source *src,
2885 *                      ALuint nc, ALuint len, ALshort **buffers)
2886 *
2887 * Applies the srcParam settings of src to buffers[0..nc-1][0..(len/2)-1].
2888 *
2889 * This function should be called before a source is collapsed, in
2890 * ApplyFilters.
2891 *
2892 * assumes locked context
2893 *
2894 * FIXME: ignores delay
2895 */
2896void _alSourceParamApply( AL_source *src,
2897                          ALuint nc, ALuint len, ALshort **buffers ) {
2898        ALuint sampLen;
2899        ALuint i;
2900        ALfloat gain;
2901
2902        sampLen = len / sizeof(ALshort); /* we pass sample length */
2903
2904        for(i = 0; i < nc; i++) {
2905                gain = src->srcParams.gain[i];
2906
2907                if(gain == 1.0) {
2908                        /* don't floatmul when gain is 1.0 */
2909                        continue;
2910                }
2911
2912                _alFloatMul( buffers[i], gain, sampLen );
2913        }
2914
2915        return;
2916}
2917
2918/*
2919 * _alSourceGetPendingBids( AL_source *src )
2920 *
2921 * Returns the number of buffers queued in the source, not including the
2922 * current one ( if any ).
2923 */
2924ALint _alSourceGetPendingBids(AL_source *src) {
2925        ALint retval =  (src->bid_queue.size - 1) - src->bid_queue.read_index;
2926
2927        return retval;
2928}
2929
2930/*
2931 * _alSourceShouldIncrement( AL_source *src )
2932 *
2933 * Usually, the top-level mixing function _alMixSources handles updating each
2934 * source's sound position ( a pointer into its associate buffer's raw PCM
2935 * data. )  Some attributes, like pitch, demand a more sophisticated approach
2936 * that can only be done by the filter which handles this attribute.
2937 *
2938 * _alSourceShouldIncrement returns AL_TRUE if the top-level mixing function
2939 * should update this sort of state information, and AL_FALSE if it should
2940 * leave it to another portion of the library.
2941 *
2942 * assumes locked context
2943 */
2944ALboolean _alSourceShouldIncrement(AL_source *src) {
2945        AL_sourcestate *srcstate;
2946
2947        srcstate =_alSourceQueueGetCurrentState(src);
2948
2949        if((srcstate == NULL) || (src->flags & ALS_NEEDPITCH)) {
2950                return AL_FALSE;
2951        }
2952
2953        return AL_TRUE;
2954}
2955
2956/*
2957 * _alSourceIncrement( AL_source *src, ALuint bytes )
2958 *
2959 * Increments the source's (src) offset into its current buffer's PCM data.
2960 */
2961void _alSourceIncrement(AL_source *src, ALuint bytes) {
2962        src->srcParams.soundpos += bytes;
2963
2964        return;
2965}
2966
2967/*
2968 * _alSourceGetBufptr( AL_source *src, AL_buffer *buf, ALuint index )
2969 *
2970 * Returns pointer to pcm data for buf, offset by src's soundpos.
2971 *
2972 * assumes locked context
2973 */
2974void *_alSourceGetBufptr( AL_source *src, AL_buffer *buf, ALuint ind ) {
2975        ALbyte *retval;
2976        ALuint pos = src->srcParams.soundpos;
2977
2978        retval = buf->orig_buffers[ind];
2979
2980        return retval + pos;
2981}
2982
2983/*
2984 * _alSourceBytesLeftByChannel( AL_source *src, AL_buffer *samp )
2985 *
2986 * Returns the byte length of the amount of data left before this source/samp
2987 * pair will either run out of data or be required to wrap.  This returns the
2988 * byte length of a simple array, with 1 channel's worth of data.
2989 */
2990ALint _alSourceBytesLeft(AL_source *src, AL_buffer *samp) {
2991        ALuint nc = samp->num_buffers;
2992
2993        return nc * _alSourceBytesLeftByChannel(src, samp);
2994}
2995
2996/*
2997 * _alSourceBytesLeft(AL_source *src, AL_buffer *samp)
2998 *
2999 * Returns the byte length of the amount of data left before this source/samp
3000 * pair will either run out of data or be required to wrap.  This returns the
3001 * byte length of an interleaved array, with periodic repetition equal to the
3002 * number of channels in the canonical format.
3003 */
3004ALint _alSourceBytesLeftByChannel(AL_source *src, AL_buffer *samp) {
3005        return samp->size - src->srcParams.soundpos;
3006}
3007
3008/*
3009 *
3010 * _alSourceIsQueue( AL_source * src )
3011 *
3012 * Returns AL_TRUE if source (src) has its queue set to AL_TRUE, AL_FALSE otherwise.
3013 */
3014ALboolean _alSourceIsQueue( AL_source * src ) {
3015
3016        if ( src->looping.isset == AL_TRUE &&
3017             src->looping.data == AL_TRUE &&
3018             src->bid_queue.size > 1 ) return AL_TRUE;
3019
3020        return AL_FALSE;
3021}
3022
3023/*
3024 * _alSourceIsLooping( AL_source *src )
3025 *
3026 * Returns AL_TRUE if the source (src) has its AL_LOOPING attribute set to
3027 * AL_TRUE, AL_FALSE otherwise.
3028 */
3029ALboolean _alSourceIsLooping( AL_source *src ) {
3030        ALboolean *boo = _alGetSourceParam( src, AL_LOOPING );
3031
3032        if( boo == NULL ) {
3033                return AL_FALSE;
3034        }
3035
3036        return *boo;
3037}
3038
3039/*
3040 * FL_alLockSource( UNUSED(const char *fn),
3041 *                  UNUSED(int ln),
3042 *                  ALuint cid,
3043 *                  ALuint sid )
3044 *
3045 * Locks source sid at cid.
3046 */
3047ALboolean FL_alLockSource( UNUSED(const char *fn),
3048                           UNUSED(int ln),
3049                           ALuint cid,
3050                           ALuint sid ) {
3051        ALint sindex;
3052        AL_context *cc;
3053
3054        cc = _alcGetContext( cid );
3055        if( cc == NULL ) {
3056                return AL_FALSE;
3057        }
3058
3059        _alLockPrintf("_alLockSource", fn, ln);
3060
3061        sindex = spool_sid_to_index( &cc->source_pool, sid );
3062        if( sindex < 0 ) {
3063                /* invalid sid */
3064                return AL_FALSE;
3065        }
3066
3067        if( cc->source_pool.smutexen[sindex] == NULL ) {
3068                return AL_FALSE;
3069        }
3070
3071        _alLockMutex( cc->source_pool.smutexen[sindex] );
3072
3073        return AL_TRUE;
3074}
3075
3076/*
3077 * FL_alUnlockSource( UNUSED(const char *fn),
3078 *                    UNUSED(int ln),
3079 *                    ALuint cid,
3080 *                    ALuint sid )
3081 *
3082 * Unlocks source mutex for sid at cid.
3083 */
3084ALboolean FL_alUnlockSource( UNUSED(const char *fn),
3085                             UNUSED(int ln),
3086                             ALuint cid,
3087                             ALuint sid ) {
3088        ALint sindex;
3089        AL_context *cc;
3090
3091        cc = _alcGetContext( cid );
3092        if( cc == NULL ) {
3093                return AL_FALSE;
3094        }
3095
3096        _alLockPrintf("_alUnlockSource", fn, ln);
3097
3098        sindex = spool_sid_to_index( &cc->source_pool, sid );
3099        if( sindex < 0 ) {
3100                /* invalid sid */
3101                return AL_FALSE;
3102        }
3103
3104        if( cc->source_pool.smutexen[sindex] == NULL ) {
3105                return AL_FALSE;
3106        }
3107
3108        _alUnlockMutex( cc->source_pool.smutexen[sindex] );
3109
3110        return AL_TRUE;
3111}
3112
3113/*
3114 * _alGetSourceParam( AL_source *source, ALenum param )
3115 *
3116 * Returns a pointer to the source attribute specified by param.  If the
3117 * attribute has not been set by the application, NULL is returned.
3118 *
3119 * NOTES:
3120 *  This returns NULL if the paramater specified by param hasn't
3121 *  been set, so that the calling function can determine what it
3122 *  thinks a sensible default should be.  Perhaps it would be
3123 *  best to have a set of default variables here and return their
3124 *  value when need be?
3125 */
3126void *_alGetSourceParam(AL_source *source, ALenum param )
3127{
3128        if( _alSourceIsParamSet( source, param ) == AL_FALSE )
3129        {
3130                if(param == AL_BUFFER)
3131                        assert(0);
3132
3133                return NULL;
3134        }
3135
3136        switch( param )
3137        {
3138                case AL_BUFFER:
3139                        if( source->bid_queue.read_index >=
3140                            source->bid_queue.size )
3141                        {
3142                                int size = source->bid_queue.size;
3143
3144                                /* often the case for size one queues */
3145                                return &source->bid_queue.queue[size - 1];
3146                        }
3147                        else
3148                        if( source->bid_queue.size > 0 )
3149                        {
3150                                int rind = source->bid_queue.read_index;
3151
3152                                assert(rind < source->bid_queue.size);
3153                                return &source->bid_queue.queue[rind];
3154                        }
3155                        else
3156                        {
3157                                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
3158                                        "_alGetSourceState: bid_queue.size == %d",
3159                                source->bid_queue.size);
3160                        }
3161                        break;
3162                case AL_CONE_INNER_ANGLE:
3163                        return &source->cone_inner_angle.data;
3164                        break;
3165                case AL_CONE_OUTER_ANGLE:
3166                        return &source->cone_outer_angle.data;
3167                        break;
3168                case AL_CONE_OUTER_GAIN:
3169                        return &source->cone_outer_gain.data;
3170                        break;
3171                case AL_DIRECTION:
3172                        return &source->direction.data;
3173                        break;
3174                case AL_GAIN:
3175                case AL_GAIN_LINEAR_LOKI:
3176                        return &source->gain.data;
3177                        break;
3178                case AL_LOOPING:
3179                        return &source->looping.data;
3180                        break;
3181                case AL_PITCH:
3182                        return &source->pitch.data;
3183                        break;
3184                case AL_POSITION:
3185                        return &source->position.data;
3186                        break;
3187                case AL_SOURCE_RELATIVE:
3188                        return &source->relative.data;
3189                        break;
3190                case AL_VELOCITY:
3191                        return &source->velocity.data;
3192                        break;
3193                case AL_MIN_GAIN:
3194                        return &source->min_gain.data;
3195                        break;
3196                case AL_MAX_GAIN:
3197                        return &source->max_gain.data;
3198                        break;
3199                case AL_SOURCE_STATE:
3200                        return &source->state;
3201                        break;
3202                case AL_REFERENCE_DISTANCE:
3203                        return &source->reference_distance.data;
3204                        break;
3205                case AL_MAX_DISTANCE:
3206                        return &source->max_distance.data;
3207                        break;
3208                case AL_ROLLOFF_FACTOR:
3209                        return &source->rolloff_factor.data;
3210                        break;
3211                default:
3212                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
3213                                "unknown source param 0x%x", param);
3214
3215                        assert( 0 );
3216
3217                        break;
3218        }
3219
3220                if(param == AL_BUFFER)
3221                        assert(0);
3222        return NULL;
3223}
3224
3225/*
3226 * _alSourceIsParamSet( AL_source *source, ALenum param )
3227 *
3228 * Returns AL_TRUE if param is set for source, AL_FALSE otherwise.
3229 */
3230ALboolean _alSourceIsParamSet( AL_source *source, ALenum param ) {
3231        switch( param ) {
3232                case AL_BUFFER:
3233                case AL_SOURCE_STATE:
3234                        return AL_TRUE;
3235                case AL_CONE_INNER_ANGLE:
3236                        return source->cone_inner_angle.isset;
3237                case AL_CONE_OUTER_ANGLE:
3238                        return source->cone_outer_angle.isset;
3239                case AL_CONE_OUTER_GAIN:
3240                        return source->cone_outer_gain.isset;
3241                case AL_DIRECTION:
3242                        return source->direction.isset;
3243                case AL_GAIN:
3244                case AL_GAIN_LINEAR_LOKI:
3245                        return source->gain.isset;
3246                case AL_LOOPING:
3247                        return source->looping.isset;
3248                case AL_PITCH:
3249                        return source->pitch.isset;
3250                case AL_POSITION:
3251                        return source->position.isset;
3252                case AL_SOURCE_RELATIVE:
3253                        return source->relative.isset;
3254                case AL_VELOCITY:
3255                        return source->velocity.isset;
3256                case AL_MIN_GAIN:
3257                        return source->min_gain.isset;
3258                case AL_MAX_GAIN:
3259                        return source->max_gain.isset;
3260                case AL_REFERENCE_DISTANCE:
3261                        return source->reference_distance.isset;
3262                case AL_MAX_DISTANCE:
3263                        return source->max_distance.isset;
3264                case AL_ROLLOFF_FACTOR:
3265                        return source->rolloff_factor.isset;
3266                default:
3267                        _alDebug(ALD_SOURCE, __FILE__, __LINE__,
3268                                "unknown source param 0x%x", param);
3269                        return AL_FALSE;
3270        }
3271}
3272
3273/*
3274 * _alSourceGetParamDefault( ALenum param, ALvoid *retref )
3275 *
3276 * Sets retref to the default value for param.
3277 */
3278void _alSourceGetParamDefault( ALenum param, ALvoid *retref ) {
3279        ALint *ip     = retref;
3280        ALboolean *bp = retref;
3281        ALfloat *fp   = retref;
3282        Rcvar pref    = NULL;
3283
3284        switch( param ) {
3285                case AL_BUFFER:
3286                        *ip = 0;
3287                        break;
3288                case AL_CONE_INNER_ANGLE:
3289                case AL_CONE_OUTER_ANGLE:
3290                        *fp = 360.0f;
3291                        break;
3292                case AL_MIN_GAIN:
3293                case AL_CONE_OUTER_GAIN:
3294                        *fp = 0.0f;
3295                        break;
3296                case AL_GAIN:
3297                case AL_GAIN_LINEAR_LOKI:
3298                case AL_MAX_GAIN:
3299                case AL_PITCH:
3300                case AL_REFERENCE_DISTANCE:
3301                        *fp = 1.0f;
3302                        break;
3303                case AL_ROLLOFF_FACTOR:
3304                        /*
3305                         * check user preference.  If set, use that.
3306                         * Otherwise, use the default of 1.0f
3307                         */
3308                        pref = rc_lookup( "source-rolloff-factor" );
3309                        if( pref != NULL ) {
3310                                *fp = rc_tofloat( pref );
3311                        }  else {
3312                                *fp = 1.0f;
3313                        }
3314                        break;
3315                case AL_DIRECTION:
3316                case AL_POSITION:
3317                case AL_VELOCITY:
3318                        fp[0] = 0.0f;
3319                        fp[1] = 0.0f;
3320                        fp[2] = 0.0f;
3321                        break;
3322                case AL_LOOPING:
3323                case AL_SOURCE_RELATIVE:
3324                        *bp = AL_FALSE;
3325                        break;
3326                case AL_MAX_DISTANCE:
3327                        *fp = FLT_MAX;
3328                        break;
3329                case AL_SOURCE_STATE:
3330                default:
3331                        assert( 0 );
3332                        break;
3333        }
3334}
3335
3336/*
3337 * _alSourceGetNextBuffer( AL_source *src )
3338 *
3339 * Returns the next buffer in a queue, or NULL if no next buffer exists.
3340 * Assumes locked source.
3341 *
3342 */
3343AL_buffer *_alSourceGetNextBuffer( AL_source *src )
3344{
3345        assert( src );
3346
3347        if(src->bid_queue.read_index < src->bid_queue.size - 1)
3348        {
3349                ALuint ri  = src->bid_queue.read_index;
3350                ALuint bid = src->bid_queue.queue[ri];
3351
3352                return _alGetBuffer(bid);
3353        }
3354
3355        return NULL;
3356}
3357
3358/*
3359 * _alSourceQueuedBuffers( AL_source *src )
3360 *
3361 * Returns the total number of buffers queued for the source,
3362 * without regard to the read or write pointer.
3363 */
3364ALint _alSourceQueuedBuffers( AL_source *src )
3365{
3366        assert( src );
3367
3368        return src->bid_queue.size;
3369}
Note: See TracBrowser for help on using the repository browser.