Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added openal

File size: 36.4 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * al_buffer.c
5 *
6 * Stuff related to the management and use of buffers.
7 *
8 */
9#include "al_siteconfig.h"
10
11#include <AL/al.h>
12
13/* for alutLoadVorbis_LOKI and alBufferAppendData_LOKI */
14#include <AL/alext.h>
15
16#include <stdio.h>
17#include <stddef.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include "al_buffer.h"
22#include "al_bpool.h"
23#include "al_debug.h"
24#include "al_error.h"
25#include "al_main.h"
26#include "al_source.h"
27#include "al_types.h"
28#include "alc/alc_context.h"
29#include "alc/alc_speaker.h"
30
31#include "audioconvert/audioconvert.h"
32
33#include "al_threadlib.h"
34#include "al_mutexlib.h"
35
36#ifndef elementsof
37#define elementsof(a) ((sizeof(a)) / (sizeof *(a)))
38#endif
39
40/*
41 * buf_pool is a the bpool_t structure which we use to slab allocate
42 * AL_buffers.
43 */
44static bpool_t buf_pool;
45
46/*
47 * Mutex guarding buf_pool.
48 */
49static MutexID buf_mutex;
50
51/*
52 * _alDestroyBuffer(void *buf)
53 *
54 * _alDestroyBuffer is passed an AL_buffer pointer, masquerading as a void
55 * pointer, and frees the data structures internal to the AL_buffer, but
56 * not the buffer itself.
57 *
58 * This is called by bpool_dealloc.
59 */
60static void _alDestroyBuffer( void *buf );
61
62/*
63 * ALvoid *_alConvert( const ALvoid *data,
64 *                      ALenum f_format, ALuint f_size, ALuint f_freq,
65 *                      ALenum t_format, ALuint t_freq, ALuint *retsize,
66 *                      ALenum should_use_passed_data);
67 *
68 * _alConvert takes the passed data and converts it from it's current
69 * format (f_format) to the desired format (t_format), etc, returning
70 * the converted data and setting retsize to the new size of the
71 * converted data.  The passed data must either be raw PCM data or
72 * must correspond with one of the headered extension formats.
73 *
74 * If should_use_passed_data is set to AL_TRUE, then _alConvert will
75 * attempt to do the conversion in place.  Otherwise, new data will
76 * be allocated for the purpose.
77 *
78 * Returns NULL on error.
79 */
80static ALvoid *_alConvert(const ALvoid *data,
81                        ALenum f_format, ALuint f_size, ALuint f_freq,
82                        ALenum t_format, ALuint t_freq, ALuint *retsize,
83                        ALenum should_use_passed_data);
84
85/*
86 * _alBufferDestroyCallbackBuffer( AL_buffer *buf )
87 *
88 * Executes the buffer completion callback associated with buf, if there is
89 * one.
90 */
91static void _alBufferDestroyCallbackBuffer( AL_buffer *buf );
92
93/*
94 * buffer source state
95 */
96
97/*
98 * _alBufferAddQueueRef( AL_buffer *buf, ALuint sid )
99 *
100 * adds a queue reference to the AL_buffer *buf.  The queue reference
101 * refers to the source named by sid.
102 *
103 * If no current reference is added, and this queue reference is not deleted,
104 * _alGet{Bid,Buffer}State will return AL_PENDING.
105 *
106 */
107static void _alBufferAddQueueRef( AL_buffer *buf, ALuint sid );
108
109/*
110 * _alBufferRemoveQueueRef( AL_buffer *buf, ALuint sid )
111 *
112 * removes a queue reference to the AL_buffer *buf.  The first queue
113 * reference refering to sid will be removed.
114 */
115static void _alBufferRemoveQueueRef( AL_buffer *buf, ALuint sid );
116
117/*
118 * _alBufferAddCurrentRef( AL_buffer *buf, ALuint sid )
119 *
120 * adds a current reference to the AL_buffer *buf.  The reference refers
121 * to the source named by sid.
122 *
123 * If this reference is not removed, _alGet{Bid,Buffer}state will return
124 * AL_PROCESSED.
125 */
126static void _alBufferAddCurrentRef( AL_buffer *buf, ALuint sid );
127
128/*
129 * _alBufferRemoveCurrentRef( AL_buffer *buf, ALuint sid )
130 *
131 * removes a current reference to the AL_buffer *buf.  The first current
132 * reference refering to sid will be removed.
133 */
134static void _alBufferRemoveCurrentRef( AL_buffer *buf, ALuint sid );
135
136/*
137 * alGenBuffers( ALsizei n, ALuint *buffer )
138 *
139 * Perform full allocation of n-1 buffer ids.  Fails and nops
140 * if n-1 buffers could not be created.
141 *
142 * If n is 0, legal nop.  If n < 0, set INVALID_VALUE and nop.
143 */
144void alGenBuffers( ALsizei n, ALuint *buffer ) {
145        ALuint *temp;
146        int bindex;
147        int i;
148
149        if(n == 0) {
150                return; /* silently return */
151        }
152
153        if(n < 0) {
154                _alDebug(ALD_BUFFER, __FILE__, __LINE__,
155                      "alGenBuffers: invalid n %d\n", n);
156
157                _alcDCLockContext();
158                _alDCSetError( AL_INVALID_VALUE );
159                _alcDCUnlockContext();
160                return;
161        }
162
163        temp = malloc(n * sizeof *temp);
164        if(temp == NULL) {
165                /*
166                 * Could not reserve memory for temporary
167                 * ALuint *buffer.
168                 */
169                _alcDCLockContext();
170                _alDCSetError( AL_OUT_OF_MEMORY );
171                _alcDCUnlockContext();
172                return;
173        }
174
175        _alLockBuffer();
176
177        for(i = 0; i < n; i++) {
178                bindex = bpool_alloc(&buf_pool);
179
180                if(bindex == -1) {
181                        /*
182                         * Could not honor request in full.  We
183                         * unlock, dealloc, set error, return.
184                         *
185                         * FIXME: Should we have a non-locking
186                         * version of DeleteBuffers and maintain this
187                         * lock as long as possible?
188                         */
189                        _alUnlockBuffer();
190
191                        if(i > 0) {
192                                /*
193                                 * Only delete buffers that have
194                                 * been created.
195                                 */
196                                alDeleteBuffers(i, temp);
197                        }
198
199                        _alcDCLockContext();
200                        _alDCSetError(AL_OUT_OF_MEMORY);
201                        _alcDCUnlockContext();
202
203                        free( temp );
204
205                        return;
206                }
207
208                temp[i] = bindex;
209        }
210
211        _alUnlockBuffer();
212
213        /*
214         * temp[0..n-1] now populated with n valid buffer names,
215         * so copy it.
216         */
217        memcpy( buffer, temp, n * sizeof *buffer );
218
219        free( temp );
220
221        return;
222}
223
224/*
225 * alDeleteBuffers( ALsizei n, ALuint *buffers )
226 *
227 * Perform full deallocation of buffers[0..n-1].  If a member
228 * of buffers[0..n-1] is not a valid buffer id, set INVALID_NAME
229 * and return without deallocating any member.
230 *
231 * If n is 0, legal nop.  If n < 0, set INVALID_VALUE and nop.
232 *
233 * FIXME: not well tested
234 *
235 * Well, that's not totally true.  I've tested deleting
236 * buffers (obviously!) but there's a whole set of mojo where it
237 * becomes possible to delete buffers in playing sources, which
238 * is bad bad bad.
239 *
240 * The ref counting system is made to avoid that bad mojo by never
241 * deleting buffers associated with playing sources.  *That* is
242 * what is not well tested.
243 *
244 * Of course, the behaviour of deleting buffers which are currently
245 * associated with sources (especially playing sources!) needs to
246 * be specified.  It's not at-the-moment.
247 */
248void alDeleteBuffers( ALsizei n, const ALuint* buffers ) {
249        AL_buffer *buf;
250        ALenum bufstate;
251        int i;
252
253        if(n == 0) {
254                /* silently return */
255                return;
256        }
257
258        _alLockBuffer();
259
260        if(n < 0) {
261                _alUnlockBuffer();
262
263                _alcDCLockContext();
264                _alDCSetError( AL_INVALID_VALUE );
265                _alcDCUnlockContext();
266
267                return;
268        }
269
270        /*
271         * test each buffer to ensure we don't have any
272         * invalid names in there.
273         */
274        for(i = 0; i < n; i++) {
275                if(_alIsBuffer(buffers[i]) == AL_FALSE) {
276                        /* not a buffer */
277                        _alcDCLockContext();
278                        _alDCSetError( AL_INVALID_NAME );
279                        _alcDCUnlockContext();
280
281                        _alUnlockBuffer();
282                        return;
283                }
284        }
285
286        while(n--) {
287                bufstate = _alGetBidState( buffers[n] );
288
289                if(bufstate == AL_UNUSED) {
290                        bpool_dealloc(&buf_pool, buffers[n],
291                                _alDestroyBuffer);
292                } else {
293                        buf = _alGetBuffer( buffers[n] );
294                        if(buf == NULL) {
295                                /* should never happen */
296                                _alcDCLockContext();
297                                _alDCSetError( AL_INVALID_NAME );
298                                _alcDCUnlockContext();
299
300                                continue;
301                        }
302
303                        /* still in use */
304                        buf->flags |= ALB_PENDING_DELETE;
305                }
306        }
307        _alUnlockBuffer();
308
309        return;
310}
311
312/*
313 * alIsBuffer( ALuint bid )
314 *
315 * Returns AL_TRUE if bid is a valid buffer name, AL_FALSE otherwise.
316 *
317 */
318ALboolean alIsBuffer( ALuint bid ) {
319        ALboolean retval;
320
321        _alLockBuffer();
322
323        retval = _alIsBuffer( bid );
324
325        _alUnlockBuffer();
326
327        return retval;
328}
329
330/*
331 * alBufferData( ALuint  bid,
332 *               ALenum  format,
333 *               ALvoid  *data,
334 *               ALsizei size,
335 *               ALsizei freq );
336 *
337 * associates data with bid.
338 *
339 * If format is invalid, set AL_INVALID_ENUM.  If bid is not a valid buffer
340 * name, set AL_INVALID_NAME.  If not enough memory is available to make a
341 * copy of this data, set AL_OUT_OF_MEMORY.
342 */
343void alBufferData( ALuint  bid,
344                   ALenum  format,
345                   const ALvoid* data,
346                   ALsizei size,
347                   ALsizei freq ) {
348        AL_buffer *buf;
349        ALvoid *cdata;
350        ALuint i;
351        ALuint retsize;
352        ALenum tformat;
353        ALint tfreq;
354
355        if((data == NULL) || (size == 0))
356        {
357                _alcDCLockContext();
358                _alDCSetError(AL_INVALID_VALUE);
359                _alcDCUnlockContext();
360
361                return;
362        }
363
364        switch(format) {
365#ifdef ENABLE_EXTENSION_AL_EXT_VORBIS
366                /*
367                 * If compiled with the vorbis extension, and we get passed
368                 * vorbis data, then pass that to the correct extension.
369                 */
370                case AL_FORMAT_VORBIS_EXT:
371                        if(alutLoadVorbis_LOKI(bid, data, size) == AL_FALSE) {
372                                _alcDCLockContext();
373                                _alDCSetError(AL_INVALID_OPERATION);
374                                _alcDCUnlockContext();
375                        }
376                        return;
377                        break;
378#endif /* ENABLE_EXTENSION_AL_EXT_VORBIS */
379                case AL_FORMAT_WAVE_EXT:
380                case AL_FORMAT_MONO8:
381                case AL_FORMAT_MONO16:
382                case AL_FORMAT_STEREO8:
383                case AL_FORMAT_STEREO16:
384                case AL_FORMAT_QUAD8_LOKI:
385                case AL_FORMAT_QUAD16_LOKI:
386                case AL_FORMAT_IMA_ADPCM_MONO16_EXT:
387                case AL_FORMAT_IMA_ADPCM_STEREO16_EXT:
388                        break;
389                default:
390                        _alDebug(ALD_BUFFER, __FILE__, __LINE__,
391                                "alBufferData: unknown format 0x%x", format);
392                        _alcDCLockContext();
393                        _alDCSetError(AL_INVALID_VALUE);
394                        _alcDCUnlockContext();
395                        return;
396                        break;
397        }
398
399        _alLockBuffer();
400
401        buf = _alGetBuffer(bid);
402        if(buf == NULL) {
403                _alDebug(ALD_BUFFER, __FILE__, __LINE__,
404                      "alBufferData: buffer id %d not valid",
405                      bid);
406
407                _alcDCLockContext();
408                _alDCSetError(AL_INVALID_NAME);
409                _alcDCUnlockContext();
410
411                _alUnlockBuffer();
412                return;
413        }
414
415        if(buf->flags & ALB_STREAMING) {
416                /* Streaming buffers cannot use alBufferData */
417                _alcDCLockContext();
418                _alDCSetError(AL_INVALID_OPERATION);
419                _alcDCUnlockContext();
420
421                _alUnlockBuffer();
422
423                return;
424        }
425
426        if(buf->flags & ALB_CALLBACK) {
427                /* If this was previously a callback buffer,
428                 * reset it.
429                 */
430                buf->flags &= ~ALB_CALLBACK;
431        }
432
433        tformat = buf->format;
434        tfreq   = buf->frequency;
435
436        _alUnlockBuffer();
437
438        cdata = _alBufferCanonizeData(format,
439                                      data,
440                                      size,
441                                      freq,
442                                      tformat,
443                                      tfreq,
444                                      &retsize,
445                                      AL_FALSE);
446
447        if(cdata == NULL) {
448                /*  _alBufferCanonize Data should set error */
449                return;
450        }
451
452        /*
453         * alter buffer's data.
454         */
455        _alLockBuffer();
456
457        if(buf->size < retsize)
458        {
459                void *temp_copies[_ALC_MAX_CHANNELS] = { NULL };
460                ALboolean success = AL_TRUE;
461
462                /* don't use realloc */
463                _alBufferFreeOrigBuffers(buf);
464
465                for(i = 0; i < _alGetChannelsFromFormat(buf->format); i++)
466                {
467                        temp_copies[i] = malloc(retsize);
468                        success = (temp_copies[i] != NULL) ? AL_TRUE : AL_FALSE;
469                }
470
471                if(!success)
472                {
473                        free(cdata);
474
475                        for(i = 0; i < _alGetChannelsFromFormat(buf->format); i++)
476                        {
477                                free(temp_copies[i]);
478                        }
479
480                        /* JIV FIXME: lock context */
481                        _alcDCLockContext();
482                        _alDCSetError(AL_OUT_OF_MEMORY);
483                        _alcDCUnlockContext();
484
485                        _alUnlockBuffer();
486
487                        return;
488                }
489
490                switch(_alGetChannelsFromFormat(buf->format))
491                {
492                        case 1:
493                          for(i = 0; i < elementsof(buf->orig_buffers); i++)
494                          {
495                                  buf->orig_buffers[i] = temp_copies[0];
496                          }
497
498                          break;
499                        case 2:
500                          for(i = 0; i < elementsof(buf->orig_buffers); i += 2)
501                          {
502                                  buf->orig_buffers[i]   = temp_copies[0];
503                                  buf->orig_buffers[i+1] = temp_copies[1];
504                          }
505
506                          break;
507                        case 4:
508                          assert(elementsof(buf->orig_buffers) >= 4);
509                          for(i = 0; i < elementsof(buf->orig_buffers); i += 4)
510                          {
511                                  buf->orig_buffers[i]   = temp_copies[0];
512                                  buf->orig_buffers[i+1] = temp_copies[1];
513                                  buf->orig_buffers[i+2] = temp_copies[2];
514                                  buf->orig_buffers[i+3] = temp_copies[3];
515                          }
516                          break;
517                        case 6:
518                          assert(elementsof(buf->orig_buffers) >= 6);
519                          for(i = 0; i < elementsof(buf->orig_buffers); i += 6)
520                          {
521                                  buf->orig_buffers[i]   = temp_copies[0];
522                                  buf->orig_buffers[i+1] = temp_copies[1];
523                                  buf->orig_buffers[i+2] = temp_copies[2];
524                                  buf->orig_buffers[i+3] = temp_copies[3];
525                                  buf->orig_buffers[i+4] = temp_copies[4];
526                                  buf->orig_buffers[i+5] = temp_copies[5];
527                          }
528
529                          break;
530                        default:
531                          /* well this is weird */
532                          assert(0);
533                          break;
534                }
535        }
536
537        _alMonoify((ALshort **) buf->orig_buffers,
538                   cdata,
539                   retsize / _alGetChannelsFromFormat(tformat),
540                   buf->num_buffers, _alGetChannelsFromFormat(tformat));
541
542        buf->size = retsize / _alGetChannelsFromFormat(tformat);
543
544        _alUnlockBuffer();
545
546        free(cdata);
547
548        return;
549}
550
551/*
552 * _alIsBuffer( ALuint bid )
553 *
554 * Non locking version of alIsBuffer.
555 *
556 * assumes locked buffers
557 */
558ALboolean _alIsBuffer( ALuint bid ) {
559        AL_buffer *buf;
560        ALboolean retval = AL_TRUE;
561
562        buf = _alGetBuffer( bid );
563        if ( !buf || (buf->flags & ALB_PENDING_DELETE) ) {
564                retval = AL_FALSE;
565        }
566
567        return retval;
568}
569
570/*
571 *_alGetBuffer( ALuint bid ).
572 *
573 * Returns pointer to the AL_buffer with buffer name bid, or NULL if bid in
574 * invalid.
575 *
576 * assumes that buffers are locked
577 */
578AL_buffer *_alGetBuffer( ALuint bid ) {
579        int bindex;
580
581        bindex = bpool_bid_to_index( &buf_pool, bid );
582        if(bindex < 0) {
583                /* invalid bid */
584                return NULL;
585        }
586
587        if(bindex >= (int) buf_pool.size) {
588                /* buffer id too big */
589                return NULL;
590        }
591
592        if(buf_pool.pool[bindex].inuse == AL_FALSE) {
593                return NULL;
594        }
595
596        return bpool_index(&buf_pool, bid);
597}
598
599/*
600 * _alInitBuffers( void )
601 *
602 * Performs global initialization of buffer specific data
603 * structures.
604 *
605 * Doesn't do much.  No default size, so we just initialize
606 * the mutex.
607 */
608ALboolean _alInitBuffers( void )
609{
610        buf_mutex = _alCreateMutex();
611
612        return AL_TRUE;
613}
614
615/*
616 * _alGetBufferFromSid( ALuint cid, ALuint sid )
617 *
618 * Retrieves a pointer to the AL_buffer (not the buffer id) associated with
619 * the source with name sid ( from context with name cid), or NULL if cid, sid
620 * are invalid or if sid does not have its buffer attribute set.
621 *
622 * assumes locked context
623 */
624AL_buffer *_alGetBufferFromSid( ALuint cid, ALuint sid ) {
625        AL_buffer *retval;
626        AL_source *src;
627        ALuint *buffid;
628
629        src = _alGetSource( cid, sid );
630        if(src == NULL) {
631                return NULL;
632        }
633
634        buffid = _alGetSourceParam( src, AL_BUFFER );
635        if( buffid == NULL ) {
636                return NULL;
637        }
638
639        _alLockBuffer();
640
641        retval = _alGetBuffer( *buffid );
642
643        _alUnlockBuffer();
644
645        return retval;
646}
647
648/*
649 * ALvoid *_alBufferCanonizeData( ALenum format,
650 *                              const ALvoid *data, ALuint size, ALuint freq,
651 *                              ALenum t_format, ALuint t_freq,
652 *                              ALuint *retsize,
653 *                              ALenum should_use_passed_data )
654 *
655 * Put data in canonical format, setting retsize and returning a newly
656 * alloced memory.
657 *
658 * If should_use_passed_data is set to AL_TRUE, the data will
659 * be converted (if possible) in place.
660 *
661 * Returns NULL on error.
662 *
663 * assumes locked buffers.
664 */
665ALvoid *_alBufferCanonizeData( ALenum format,
666                             const ALvoid *data, ALuint size, ALuint freq,
667                             ALenum t_format, ALuint t_freq,
668                             ALuint *retsize,
669                             ALenum should_use_passed_data ) {
670        if(format < 0) {
671                return NULL;
672        }
673
674        return _alConvert(data, format, size, freq, t_format, t_freq,
675                          retsize, should_use_passed_data);
676}
677
678/*
679 * _alDestroyBuffer( void *bufp )
680 *
681 * _alDestroyBuffer is passed an AL_buffer pointer, masquerading as a void
682 * pointer, and frees the data structures internal to the AL_buffer, but
683 * not the buffer itself.
684 *
685 * This is called by bpool_dealloc.  It shouldn't be called my anything else.
686 */
687static void _alDestroyBuffer( void *bufp ) {
688        AL_buffer *buf = (AL_buffer *) bufp;
689
690        if(_alBufferIsCallback( buf ) == AL_TRUE) {
691                /*
692                 * alut decoders need to be informed of
693                 * buffer destruction
694                 */
695                _alBufferDestroyCallbackBuffer(buf);
696                buf->destroy_buffer_callback = NULL;
697        }
698
699        _alBufferFreeOrigBuffers(buf);
700
701        free( buf->queue_list.sids );
702        free( buf->current_list.sids );
703
704        buf->queue_list.sids = NULL;
705        buf->current_list.sids = NULL;
706
707        buf->queue_list.size   = buf->queue_list.items = 0;
708        buf->current_list.size = buf->current_list.items = 0;
709
710        /* don't free bufp, let the caller do it if needed */
711
712        return;
713}
714
715/*
716 * _alDestroyBuffers( void )
717 *
718 *  Destroy all buffers, freeing all data associated with
719 *  each buffer.
720 */
721void _alDestroyBuffers( void ) {
722        bpool_free( &buf_pool, _alDestroyBuffer );
723        bpool_init( &buf_pool );
724
725        _alDestroyMutex( buf_mutex );
726
727        buf_mutex = NULL;
728
729        return;
730}
731
732/*
733 * FL_alLockBuffer(UNUSED(const char *fn), UNUSED(int ln))
734 *
735 * Locks the buffer mutex, passing fn and ln to _alLockPrintf for debugging
736 * purposes.
737 */
738ALboolean FL_alLockBuffer(UNUSED(const char *fn), UNUSED(int ln)) {
739        _alLockPrintf("_alLockBuffer", fn, ln);
740
741        if( buf_mutex == NULL ) {
742                return AL_FALSE;
743        }
744
745        _alLockMutex( buf_mutex );
746
747        return AL_TRUE;
748}
749
750/*
751 * FL_alUnlockBuffer(UNUSED(const char *fn), UNUSED(int ln))
752 *
753 * Unlocks the buffer mutex, passing fn and ln to _alLockPrintf for debugging
754 * purposes.
755 */
756ALboolean FL_alUnlockBuffer(UNUSED(const char *fn), UNUSED(int ln)) {
757        _alLockPrintf("_alUnlockBuffer", fn, ln);
758
759        if(buf_mutex == NULL) {
760                return AL_FALSE;
761        }
762
763        _alUnlockMutex(buf_mutex);
764
765        return AL_TRUE;
766}
767
768/*
769 * _alNumBufferHint( ALuint nb )
770 *
771 * Resize buf_pool to contain space for at least nb buffers.  A performance
772 * hint best excercised before creating buffers.
773 */
774void _alNumBufferHint( ALuint nb ) {
775        _alLockBuffer();
776
777        bpool_resize( &buf_pool, nb );
778
779        _alUnlockBuffer();
780
781        return;
782}
783
784/*
785 * _alBidIsStreaming( ALuint bid )
786 *
787 * Returns AL_TRUE if the buffer named by bid was generated by
788 * alGenStreamingBuffers_LOKI, AL_FALSE otherwise.
789 *
790 * assumes locked buffer
791 */
792ALboolean _alBidIsStreaming( ALuint bid ) {
793        AL_buffer *buf;
794        ALboolean retval = AL_FALSE;
795
796        buf = _alGetBuffer( bid );
797        if(buf != NULL) {
798                if(buf->flags & ALB_STREAMING) {
799                        retval = AL_TRUE;
800                }
801        }
802
803        return retval;
804}
805
806/*
807 * _alBidIsCallback( ALuint bid )
808 *
809 * Returns AL_TRUE if the buffer named by bid has been used with
810 * alBufferDataWithCallback_LOKI, AL_FALSE if bid does not refer to a valid
811 * bid or has not been used with such a call.
812 *
813 * assumes locked buffer
814 */
815ALboolean _alBidIsCallback( ALuint bid ) {
816        AL_buffer *buf;
817
818        buf = _alGetBuffer(bid);
819
820        return _alBufferIsCallback(buf);
821}
822
823/*
824 * _alBufferIsCallback( AL_buffer *buf )
825 *
826 * Returns AL_TRUE if the AL_buffer *buf been used with
827 * alBufferDataWithCallback_LOKI, AL_FALSE otherwise.
828 *
829 * assumes locked buffer
830 */
831ALboolean _alBufferIsCallback( AL_buffer *buf ) {
832        ALboolean retval = AL_FALSE;
833
834        if(buf != NULL) {
835                if(buf->flags & ALB_CALLBACK) {
836                        retval = AL_TRUE;
837                }
838        }
839
840        return retval;
841}
842
843/*
844 * _alBufferDataWithCallback_LOKI( ALuint bid,
845 *                                 int (*callback)( ALuint sid,
846 *                                                  ALuint bid,
847 *                                 ALshort *outdata,
848 *                                 ALenum format,
849 *                                 ALint freq,
850 *                                 ALint samples ),
851 *                                 DestroyCallback_LOKI d_sid,
852 *                                 DestroyCallback_LOKI d_bid )
853 *
854 * Associates the AL_buffer named by bid with a callback.  This is somewhat
855 * equivilant to calling alBufferData( bid, ... ), except that instead of
856 * getting all the data at once, whenever the buffer is required to provide
857 * data, it relies on the callback.
858 *
859 * The destroyer callbacks are used to update data structures.  They are not
860 * available publically, and are only used by internal functions ( in alut,
861 * mostly ).
862 */
863void _alBufferDataWithCallback_LOKI( ALuint bid,
864                                     int (*callback)( ALuint sid,
865                                                      ALuint bid,
866                                                      ALshort *outdata,
867                                                      ALenum format,
868                                                      ALint freq,
869                                                      ALint samples ),
870                                     DestroyCallback_LOKI d_sid,
871                                     DestroyCallback_LOKI d_bid ) {
872        AL_buffer *buf;
873
874        _alLockBuffer();
875        buf = _alGetBuffer( bid );
876
877        if(buf == NULL) {
878                /* bid was invalid */
879                _alDebug(ALD_BUFFER, __FILE__, __LINE__,
880                        "Invalid buffer id %d", bid);
881
882                _alcDCLockContext();
883                _alDCSetError( AL_INVALID_NAME );
884                _alcDCUnlockContext();
885
886                _alUnlockBuffer();
887
888                return;
889        }
890
891        _alBufferFreeOrigBuffers(buf);
892
893
894        buf->size     = 0;
895        buf->callback = callback;
896        buf->flags    |= ALB_CALLBACK;
897
898        buf->destroy_buffer_callback = d_bid;
899        buf->destroy_source_callback = d_sid;
900
901        _alUnlockBuffer();
902
903        return;
904}
905
906/*
907 * _alBufferDestroyCallbackBuffer( AL_buffer *buf )
908 *
909 * Executes the buffer completion callback associated with buf, if there is
910 * one.
911 *
912 * assumes locked buffers
913 */
914static void _alBufferDestroyCallbackBuffer( AL_buffer *buf ) {
915        if(buf == NULL) {
916                return;
917        }
918
919        if(buf->destroy_buffer_callback != NULL) {
920                buf->destroy_buffer_callback(buf->bid);
921        }
922
923        return;
924}
925
926/*
927 * _alBidCallDestroyCallbackSource( ALuint sid )
928 *
929 * Executes the source completion callback from the buffer associated with
930 * sid, if there is one.
931 *
932 * assumes locked context
933 */
934void _alBidCallDestroyCallbackSource( ALuint sid ) {
935        AL_buffer *buf;
936        AL_source *src;
937        ALuint *bid;
938
939        src = _alDCGetSource( sid );
940        if(src == NULL) {
941                return;
942        }
943
944        bid = _alGetSourceParam( src, AL_BUFFER );
945        if(bid == NULL) {
946                return;
947        }
948
949        _alLockBuffer();
950
951        buf = _alGetBuffer( *bid );
952        if(buf == NULL) {
953                _alUnlockBuffer();
954                return;
955        }
956
957        if(buf->destroy_source_callback != NULL) {
958                buf->destroy_source_callback( sid );
959        }
960
961        _alUnlockBuffer();
962
963        return;
964}
965
966/*
967 * ALvoid *_alConvert( const ALvoid *data,
968 *                      ALenum f_format, ALuint f_size, ALuint f_freq,
969 *                      ALenum t_format, ALuint t_freq, ALuint *retsize,
970 *                      ALenum should_use_passed_data);
971 *
972 * _alConvert takes the passed data and converts it from it's current
973 * format (f_format) to the desired format (t_format), etc, returning
974 * the converted data and setting retsize to the new size of the
975 * converted data.  The passed data must either be raw PCM data or
976 * must correspond with one of the headered extension formats.
977 *
978 * If should_use_passed_data is set to AL_TRUE, then _alConvert will
979 * attempt to do the conversion in place.  Otherwise, new data will
980 * be allocated for the purpose.
981 *
982 * Returns NULL on error.
983 *
984 * assumes locked buffers
985 */
986static ALvoid *_alConvert( const ALvoid *data,
987                         ALenum f_format, ALuint f_size, ALuint f_freq,
988                         ALenum t_format, ALuint t_freq, ALuint *retsize,
989                         ALenum should_use_passed_data ) {
990        ALvoid *compressed = NULL;
991        ALvoid *retval = NULL;
992        acAudioCVT s16le;
993
994        if((f_format == t_format) && (f_freq == t_freq)) {
995                /*
996                 * no conversion needed.
997                 */
998                *retsize = f_size;
999
1000                if( should_use_passed_data == AL_TRUE ) {
1001                        _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1002                                 "_alConvert: no conversion needed: %p", data);
1003
1004                        return (ALvoid *)data;
1005                }
1006
1007                retval = malloc( f_size );
1008                if( retval == NULL ) {
1009                        _alcDCLockContext();
1010                        _alDCSetError( AL_OUT_OF_MEMORY );
1011                        _alcDCUnlockContext();
1012
1013                        return NULL;
1014                }
1015
1016                memcpy( retval, data, f_size );
1017
1018                return retval;
1019        }
1020
1021        /*
1022         * Compressed auto formats like IMA_ADPCM get converted in
1023         * full here.
1024         */
1025        if(_al_RAWFORMAT(f_format) == AL_FALSE) {
1026                ALushort acfmt;
1027                ALushort achan;
1028                ALushort acfreq;
1029
1030                switch(f_format) {
1031                        case AL_FORMAT_IMA_ADPCM_MONO16_EXT:
1032                        case AL_FORMAT_IMA_ADPCM_STEREO16_EXT:
1033                        case AL_FORMAT_WAVE_EXT:
1034                                acLoadWAV(data, &f_size, &retval, &acfmt, &achan, &acfreq);
1035
1036                                f_format = _al_AC2ALFMT(acfmt, achan);
1037                                f_freq   = acfreq;
1038                                break;
1039                        default:
1040                        break;
1041                }
1042
1043                data = compressed = retval;
1044        }
1045
1046        _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1047                "_alConvert [f_size|f_channels|f_freq] [%d|%d|%d]",
1048                f_size, _alGetChannelsFromFormat(f_format), f_freq);
1049
1050        if(_alGetChannelsFromFormat(f_format) != 0) {
1051                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1052                        "_alConvert [t_channels|f_channels|t/f] [%d|%d|%d]",
1053                        _alGetChannelsFromFormat(t_format),
1054                        _alGetChannelsFromFormat(f_format),
1055                        _alGetChannelsFromFormat(t_format) /
1056                        _alGetChannelsFromFormat(f_format));
1057        }
1058
1059        if(f_freq != 0) {
1060                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1061                        "_alConvert [t_freq|f_freq|t/f] [%d|%d|%d]",
1062                        t_freq, f_freq, t_freq/f_freq);
1063        }
1064
1065        if(f_format != 0) {
1066                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1067                        "_alConvert [t_bits|f_bits|t/f] [%d|%d|%d]",
1068                        _alGetBitsFromFormat(t_format),
1069                        _alGetBitsFromFormat(f_format),
1070                        (_alGetBitsFromFormat(t_format) / _alGetBitsFromFormat(f_format)));
1071        }
1072
1073        _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1074                "_alConvert f|c|s [0x%x|%d|%d] -> [0x%x|%d|%d]",
1075                /* from */
1076                f_format, _alGetChannelsFromFormat(f_format), f_freq,
1077                /* to */
1078                t_format,
1079                _alGetChannelsFromFormat(t_format),
1080                t_freq);
1081
1082        if(acBuildAudioCVT(&s16le,
1083                /* from */
1084                _al_AL2ACFMT(f_format),
1085                _alGetChannelsFromFormat(f_format),
1086                f_freq,
1087
1088                /* to */
1089                _al_AL2ACFMT(t_format),
1090                _alGetChannelsFromFormat(t_format),
1091                t_freq) < 0) {
1092                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1093                        "Couldn't build audio convertion data structure.");
1094
1095                free(compressed);
1096
1097                return NULL;
1098        }
1099
1100        _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1101                "_alConvert [len|newlen] [%d|%d]",
1102                f_size, f_size * s16le.len_mult);
1103
1104        if(should_use_passed_data == AL_TRUE) {
1105                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1106                        "Converting with passed data = %p", data);
1107                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1108                        "len_multi = %d", s16le.len_mult);
1109
1110                s16le.buf = retval = (ALvoid *)data;
1111        } else {
1112                /* alloc space for buffer if we aren't using the original */
1113
1114                s16le.buf = retval = malloc(f_size * s16le.len_mult);
1115                if(retval == NULL) {
1116                        _alDCSetError(AL_OUT_OF_MEMORY);
1117
1118                        free( compressed );
1119                        return NULL;
1120                }
1121                memcpy(retval, data, f_size);
1122        }
1123
1124        s16le.len = f_size;
1125
1126        if(acConvertAudio(&s16le) < 0) {
1127                _alDebug( ALD_CONVERT, __FILE__, __LINE__,
1128                        "Couldn't execute conversion into canon.");
1129
1130                free( compressed );
1131
1132                return NULL;
1133        }
1134
1135        /* set return size */
1136        *retsize = s16le.len_cvt;
1137
1138        if( s16le.buf != compressed ) {
1139                /*
1140                 * this comparison is false iff we are using a
1141                 * compressed/headered format that requires us to allocate
1142                 * a temporary buffer.
1143                 */
1144                free( compressed );
1145        }
1146
1147        return s16le.buf;
1148}
1149
1150/*
1151 * _alBidRemoveQueueRef( ALuint bid, ALuint sid )
1152 *
1153 * removes a queue reference to the buffer named by bid.  The first queue
1154 * reference refering to sid will be removed.
1155 *
1156 */
1157void _alBidRemoveQueueRef( ALuint bid, ALuint sid ) {
1158        AL_buffer *buf;
1159
1160        _alLockBuffer();
1161
1162        buf = _alGetBuffer( bid );
1163        if( buf == NULL ) {
1164                /* invalid name */
1165                _alUnlockBuffer();
1166                return;
1167        }
1168
1169        _alBufferRemoveQueueRef( buf, sid );
1170
1171        if( buf->flags & ALB_PENDING_DELETE ) {
1172                /* do deffered deletion */
1173                if( _alGetBidState(bid) == AL_UNUSED ) {
1174                        bpool_dealloc(&buf_pool, bid, _alDestroyBuffer);
1175                }
1176        }
1177
1178        _alUnlockBuffer();
1179
1180        return;
1181}
1182
1183/*
1184 * _alBidRemoveCurrentRef( ALuint bid, ALuint sid )
1185 *
1186 * removes a current reference to the buffer named by bid.  The first current
1187 * reference refering to sid will be removed.
1188 */
1189void _alBidRemoveCurrentRef(ALuint bid, ALuint sid) {
1190        AL_buffer *buf;
1191
1192        _alLockBuffer();
1193
1194        buf = _alGetBuffer(bid);
1195        if(buf == NULL) {
1196                /* invalid name */
1197                _alUnlockBuffer();
1198                return;
1199        }
1200
1201        _alBufferRemoveCurrentRef( buf, sid );
1202
1203        if( buf->flags & ALB_PENDING_DELETE ) {
1204                /* do deffered deletion */
1205                if( _alGetBidState(bid) == AL_UNUSED ) {
1206                        bpool_dealloc(&buf_pool, bid, _alDestroyBuffer);
1207                }
1208        }
1209
1210        _alUnlockBuffer();
1211
1212        return;
1213}
1214
1215/*
1216 * _alBidAddQueueRef( ALuint bid, ALuint sid )
1217 *
1218 * adds a queue reference to the buffer named by bid.  The queue reference
1219 * refers to the source named by sid.
1220 *
1221 * If no current reference is added, and this queue reference is not deleted,
1222 * _alGet{Bid,Buffer}State will return AL_PENDING.
1223 *
1224 */
1225void _alBidAddQueueRef(ALuint bid, ALuint sid) {
1226        AL_buffer *buf;
1227
1228        _alLockBuffer();
1229
1230        buf = _alGetBuffer( bid );
1231        if(buf == NULL) {
1232                /* invalid name, set error elsewhere? */
1233                _alUnlockBuffer();
1234
1235                return;
1236        }
1237
1238        _alBufferAddQueueRef( buf, sid );
1239
1240        _alUnlockBuffer();
1241
1242        return;
1243}
1244
1245/*
1246 * _alBidAddCurrentRef( ALuint bid, ALuint sid )
1247 *
1248 * adds a current reference to the buffer named by bid.  The reference refers
1249 * to the source named by sid.
1250 *
1251 * If this reference is not removed, _alGet{Bid,Buffer}state will return
1252 * AL_PROCESSED.
1253 */
1254void _alBidAddCurrentRef( ALuint bid, ALuint sid ) {
1255        AL_buffer *buf;
1256
1257        _alLockBuffer();
1258
1259        buf = _alGetBuffer( bid );
1260        if(buf == NULL) {
1261                /* invalid name */
1262                _alUnlockBuffer();
1263                return;
1264        }
1265
1266        _alBufferAddCurrentRef( buf, sid );
1267
1268        _alUnlockBuffer();
1269
1270        return;
1271}
1272
1273/*
1274 * _alBufferAddQueueRef( AL_buffer *buf, ALuint sid )
1275 *
1276 * adds a queue reference to the AL_buffer *buf.  The queue reference refers
1277 * to the source named by sid.
1278 *
1279 * If no current reference is added, and this queue reference is not deleted,
1280 * _alGet{Bid,Buffer}State will return AL_PENDING.
1281 *
1282 * assumes locked context, buffers
1283 */
1284static void _alBufferAddQueueRef( AL_buffer *buf, ALuint sid ) {
1285        ALvoid *temp;
1286        ALuint newsize = buf->queue_list.size;
1287
1288        if(buf->queue_list.size <= buf->queue_list.items) {
1289                /* resize */
1290                newsize *= 2;
1291                newsize += 1;
1292                temp = realloc(buf->queue_list.sids, newsize * sizeof *buf->queue_list.sids);
1293                if(temp == NULL) {
1294                        /* well la-di-da */
1295                        return;
1296                }
1297
1298                buf->queue_list.sids = temp;
1299                buf->queue_list.size = newsize;
1300        }
1301
1302        buf->queue_list.sids[buf->queue_list.items++] = sid;
1303
1304        return;
1305}
1306
1307/*
1308 * _alBufferAddCurrentRef( AL_buffer *buf, ALuint sid )
1309 *
1310 * adds a current reference to the AL_buffer *buf.  The current reference refers
1311 * to the source named by sid.
1312 *
1313 * If this current reference is not removed, _alGet{Bid,Buffer}State will
1314 * return AL_PENDING.
1315 *
1316 * assumes locked context, buffers
1317 */
1318static void _alBufferAddCurrentRef( AL_buffer *buf, ALuint sid ) {
1319        ALvoid *temp;
1320        ALuint newsize = buf->current_list.size;
1321
1322        if( buf->current_list.size <= buf->current_list.items ) {
1323                /* resize */
1324                newsize *= 2;
1325                newsize += 1;
1326
1327                temp = realloc( buf->current_list.sids, newsize * sizeof *buf->current_list.sids );
1328                if(temp == NULL) {
1329                        /* well la-di-da */
1330                        return;
1331                }
1332
1333                buf->current_list.sids = temp;
1334                buf->current_list.size = newsize;
1335        }
1336
1337        buf->current_list.sids[buf->current_list.items++] = sid;
1338
1339        return;
1340}
1341
1342/*
1343 * _alBufferRemoveQueueRef( AL_buffer *buf, ALuint sid )
1344 *
1345 * removes the first queue reference from the AL_buffer *buf that refers to
1346 * sid.
1347 *
1348 * assumes locked context, buffer
1349 */
1350static void _alBufferRemoveQueueRef( AL_buffer *buf, ALuint sid ) {
1351        ALuint i;
1352
1353        for(i = 0; i < buf->queue_list.items; i++) {
1354                if(buf->queue_list.sids[i] == sid) {
1355                        buf->queue_list.items--;
1356                        buf->queue_list.sids[i] = buf->queue_list.sids[buf->queue_list.items];
1357
1358                        return;
1359                }
1360        }
1361
1362        return;
1363}
1364
1365/*
1366 * _alBufferRemoveCurrentRef( AL_buffer *buf, ALuint sid )
1367 *
1368 * removes the first current reference from the AL_buffer *buf that refers to
1369 * sid.
1370 *
1371 * assumes locked context, buffers
1372 */
1373static void _alBufferRemoveCurrentRef( AL_buffer *buf, ALuint sid ) {
1374        ALuint i;
1375
1376        for(i = 0; i < buf->current_list.items; i++) {
1377                if(buf->current_list.sids[i] == sid) {
1378                        buf->current_list.items--;
1379                        buf->current_list.sids[i] = buf->current_list.sids[buf->current_list.items];
1380
1381                        return;
1382                }
1383        }
1384
1385        return;
1386}
1387
1388/*
1389 * _alGetBidState( ALuint bid )
1390 *
1391 * Returns the state (one of AL_UNUSED, AL_PROCESSED, AL_PENDING) associated
1392 * with a buffer.
1393 *
1394 * assumes locked buffers
1395 */
1396ALenum _alGetBidState( ALuint bid ) {
1397        ALenum retval = AL_UNUSED;
1398        AL_buffer *buf;
1399
1400        buf = _alGetBuffer( bid );
1401        if(buf != NULL) {
1402                retval = _alGetBufferState( buf );
1403        }
1404
1405        return retval;
1406}
1407
1408/*
1409 * _alGetBufferState( AL_buffer *buffer )
1410 *
1411 * Returns the state associated with the AL_buffer *buffer.  If there is even
1412 * one current ref, AL_PROCESED is returned.  If there are no current
1413 * references and one queued ref, AL_PENDING is returned.  If there are no
1414 * current or queued references, AL_UNUSED is returned.
1415 *
1416 * assumes locked buffers.
1417 */
1418ALenum _alGetBufferState( AL_buffer *buffer )
1419{
1420        if(buffer->current_list.items > 0)
1421        {
1422                return AL_PROCESSED;
1423        }
1424
1425        if(buffer->queue_list.items > 0)
1426        {
1427                return AL_PENDING;
1428        }
1429
1430        return AL_UNUSED;
1431}
1432
1433
1434void _alBufferFreeOrigBuffers(AL_buffer *buf)
1435{
1436        ALuint i, j;
1437        ALvoid *temp;
1438
1439        /* sort */
1440        for(i = 0; i < elementsof(buf->orig_buffers); i++)
1441        {
1442                for(j = i+1; j < elementsof(buf->orig_buffers); j++)
1443                {
1444                        if(buf->orig_buffers[i] > buf->orig_buffers[j])
1445                        {
1446                                temp = buf->orig_buffers[i];
1447                                buf->orig_buffers[i] = buf->orig_buffers[j];
1448                                buf->orig_buffers[j] = temp;
1449                        }
1450                }
1451        }
1452
1453        /* uniq */
1454        for(i = 0; i < elementsof(buf->orig_buffers) - 1; i++)
1455        {
1456                if(buf->orig_buffers[i] == buf->orig_buffers[i+1])
1457                {
1458                        buf->orig_buffers[i] = NULL;
1459                }
1460        }
1461
1462
1463        /* free */
1464        for(i = 0; i < elementsof(buf->orig_buffers); i++)
1465        {
1466                free(buf->orig_buffers[i]);
1467                buf->orig_buffers[i] = NULL;
1468        }
1469}
1470
1471/* binary compatibility function */
1472ALsizei alBufferAppendData( ALuint   buffer,
1473                            ALenum   format,
1474                            void*    data,
1475                            ALsizei  osamps,
1476                            ALsizei  freq) {
1477        return alBufferAppendData_LOKI(buffer, format, data, osamps, freq);
1478}
1479
1480#define MAX_BUFFER_NUM_VALUES 1
1481
1482static ALint
1483numValuesForAttribute( ALenum param )
1484{
1485        switch (param) {
1486        case AL_FREQUENCY:
1487        case AL_SIZE:
1488        case AL_BITS:
1489        case AL_CHANNELS:
1490                return 1;
1491        default:
1492                return 0;
1493        }
1494}
1495
1496static void
1497setBufferAttributef( ALuint bid, ALenum param, const ALfloat *values, ALint numValues)
1498{
1499        _alLockBuffer();
1500
1501        if (!alIsBuffer(bid)) {
1502                _alcDCLockContext();
1503                _alDCSetError( AL_INVALID_NAME );
1504                _alcDCUnlockContext();
1505                _alUnlockBuffer();
1506                return;
1507        }
1508
1509        if (numValues != numValuesForAttribute(param)) {
1510                _alcDCLockContext();
1511                _alDCSetError(AL_INVALID_ENUM);
1512                _alcDCUnlockContext();
1513                _alUnlockBuffer();
1514                return;
1515        }
1516
1517        if( values == NULL ) {
1518                _alcDCLockContext();
1519                _alDCSetError(AL_INVALID_VALUE);
1520                _alcDCUnlockContext();
1521                _alUnlockBuffer();
1522                return;
1523        }
1524
1525        switch (param) {
1526        default:
1527                _alcDCLockContext();
1528                _alDCSetError( AL_INVALID_ENUM );
1529                _alcDCUnlockContext();
1530                break;
1531        }
1532
1533        _alUnlockBuffer();
1534}
1535
1536static void
1537setBufferAttributei( ALuint bid, ALenum param, const ALint *intValues, ALint numValues)
1538{
1539        ALfloat floatValues[MAX_BUFFER_NUM_VALUES];
1540        int i;
1541        for (i = 0; i < numValues; i++) {
1542                floatValues[i] = (ALfloat)intValues[i];
1543        }
1544        setBufferAttributef(bid, param, floatValues, numValues);
1545}
1546
1547void
1548alBufferf( ALuint bid, ALenum param, ALfloat value )
1549{
1550        setBufferAttributef(bid, param, &value, 1);
1551}
1552
1553void
1554alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 )
1555{
1556        ALfloat values[3];
1557        values[0] = value1;
1558        values[1] = value2;
1559        values[2] = value3;
1560        setBufferAttributef(bid, param, values, 3);
1561}
1562
1563void
1564alBufferfv( ALuint bid, ALenum param, const ALfloat *values )
1565{
1566        setBufferAttributef(bid, param, values, numValuesForAttribute(param));
1567}
1568
1569void
1570alBufferi( ALuint bid, ALenum param, ALint value )
1571{
1572        setBufferAttributei(bid, param, &value, 1);
1573}
1574
1575void
1576alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 )
1577{
1578        ALint values[3];
1579        values[0] = value1;
1580        values[1] = value2;
1581        values[2] = value3;
1582        setBufferAttributei(bid, param, values, 3);
1583}
1584
1585void
1586alBufferiv( ALuint bid, ALenum param, const ALint *values )
1587{
1588        setBufferAttributei(bid, param, values, numValuesForAttribute(param));
1589}
1590
1591static ALboolean
1592getBufferAttribute( ALuint bid, ALenum param, ALfloat *values, ALint numValues )
1593{
1594        ALboolean ok = AL_FALSE;
1595        AL_buffer *buf;
1596
1597        _alLockBuffer();
1598
1599        buf = _alGetBuffer(bid);
1600        if (buf == NULL) {
1601                _alcDCLockContext();
1602                _alDCSetError( AL_INVALID_NAME );
1603                _alcDCUnlockContext();
1604                _alUnlockBuffer();
1605                return ok;
1606        }
1607
1608        if (numValues != numValuesForAttribute(param)) {
1609                _alcDCLockContext();
1610                _alDCSetError(AL_INVALID_ENUM);
1611                _alcDCUnlockContext();
1612                _alUnlockBuffer();
1613                return ok;
1614        }
1615
1616        if( values == NULL ) {
1617                _alcDCLockContext();
1618                _alDCSetError(AL_INVALID_VALUE);
1619                _alcDCUnlockContext();
1620                _alUnlockBuffer();
1621                return ok;
1622        }
1623
1624        switch( param ) {
1625
1626        case AL_FREQUENCY:
1627                values[0] = (ALfloat)buf->frequency;
1628                ok = AL_TRUE;
1629                break;
1630
1631        case AL_SIZE:
1632                values[0] = (ALfloat)buf->size;
1633                ok = AL_TRUE;
1634                break;
1635
1636        case AL_BITS:
1637                values[0] = _alGetBitsFromFormat( buf->format );
1638                ok = AL_TRUE;
1639                break;
1640
1641        case AL_CHANNELS:
1642                values[0] = _alGetChannelsFromFormat( buf->format );
1643                ok = AL_TRUE;
1644                break;
1645
1646        default:
1647                _alcDCLockContext();
1648                _alDCSetError( AL_INVALID_ENUM );
1649                _alcDCUnlockContext();
1650                break;
1651        }
1652
1653        _alUnlockBuffer();
1654        return ok;
1655}
1656
1657void
1658alGetBufferf( ALuint bid, ALenum param, ALfloat *value )
1659{
1660        getBufferAttribute(bid, param, value, 1);
1661}
1662
1663void
1664alGetBuffer3f( ALuint bid, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1665{
1666        ALfloat floatValues[3];
1667        if (getBufferAttribute(bid, param, floatValues, 3)) {
1668                *value1 = floatValues[0];
1669                *value2 = floatValues[1];
1670                *value3 = floatValues[2];
1671        }
1672}
1673
1674void
1675alGetBufferfv( ALuint bid, ALenum param, ALfloat *values )
1676{
1677        getBufferAttribute(bid, param, values, numValuesForAttribute(param));
1678}
1679
1680void
1681alGetBufferi( ALuint bid, ALenum param, ALint *value )
1682{
1683        ALfloat floatValues[1];
1684        if (getBufferAttribute(bid, param, floatValues, 1)) {
1685                *value = floatValues[0];
1686        }
1687}
1688
1689void
1690alGetBuffer3i( ALuint bid, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1691{
1692        ALfloat floatValues[3];
1693        if (getBufferAttribute(bid, param, floatValues, 3)) {
1694                *value1 = (ALint)floatValues[0];
1695                *value2 = (ALint)floatValues[1];
1696                *value3 = (ALint)floatValues[2];
1697        }
1698}
1699
1700void
1701alGetBufferiv( ALuint bid, ALenum param, ALint *values )
1702{
1703        ALfloat floatValues[MAX_BUFFER_NUM_VALUES];
1704        int i;
1705        int n = numValuesForAttribute(param);
1706        if (getBufferAttribute(bid, param, floatValues, n)) {
1707                for (i = 0; i < n; i++) {
1708                        values[i] = (ALint)floatValues[i];
1709                }
1710        }
1711}
Note: See TracBrowser for help on using the repository browser.