comparison ALmixer.c @ 3:a929285e1db0

Added CMake build system. There are problems with the SDL_sound module due to changes in CMake. Right now they just seem to be warnings, but I am unable to suppress them. Added license. Added README.
author Eric Wing <ewing . public |-at-| gmail . com>
date Wed, 27 Oct 2010 20:43:14 -0700
parents SDL_ALmixer.c@279d0427ef26
children 4b1048af7e55
comparison
equal deleted inserted replaced
2:279d0427ef26 3:a929285e1db0
1
2 /* Here's an OpenAL implementation modeled after
3 * the SDL_SoundMixer which was built ontop of SDL_Mixer
4 * and SDL_Sound.
5 * Eric Wing
6 */
7
8 #include "ALmixer.h"
9
10 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
11 #include "ALmixer_rwops.h"
12 #include "SoundDecoder.h"
13 #else
14 #include "SDL_sound.h"
15 #endif
16
17 #include "al.h" /* OpenAL */
18 #include "alc.h" /* For creating OpenAL contexts */
19
20 #ifdef __APPLE__
21 /* For performance things like ALC_CONVERT_DATA_UPON_LOADING */
22 /* Note: ALC_CONVERT_DATA_UPON_LOADING used to be in the alc.h header.
23 * But in the Tiger OpenAL 1.1 release (10.4.7 and Xcode 2.4), the
24 * define was moved to a new header file and renamed to
25 * ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING.
26 */
27 /*
28 #include <TargetConditionals.h>
29 #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
30
31 #else
32 #include <OpenAL/MacOSX_OALExtensions.h>
33 #endif
34 */
35
36 #endif
37
38 /* For malloc, bsearch, qsort */
39 #include <stdlib.h>
40
41 /* For memcpy */
42 #include <string.h>
43
44 #if 0
45 /* for toupper */
46 #include <ctype.h>
47 /* for strrchr */
48 #include <string.h>
49 #endif
50
51 /* Currently used in the output debug functions */
52 #include <stdio.h>
53
54 /* My own CircularQueue implementation needed
55 * to work around the Nvidia problem of the
56 * lack of a buffer query.
57 */
58 #include "CircularQueue.h"
59
60 #ifdef ENABLE_ALMIXER_THREADS
61 /* Needed for the Mutex locks (and threads if enabled) */
62 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
63 #include "SimpleMutex.h"
64 #include "SimpleThread.h"
65 typedef struct SimpleMutex SDL_mutex;
66 typedef struct SimpleThread SDL_Thread;
67 #define SDL_CreateMutex SimpleMutex_CreateMutex
68 #define SDL_DestroyMutex SimpleMutex_DestroyMutex
69 #define SDL_LockMutex SimpleMutex_LockMutex
70 #define SDL_UnlockMutex SimpleMutex_UnlockMutex
71 #define SDL_CreateThread SimpleThread_CreateThread
72 #define SDL_WaitThread SimpleThread_WaitThread
73
74 #else
75 #include "SDL_thread.h"
76 #endif
77 #endif
78
79 /* Because of the API differences between the Loki
80 * and Creative distributions, we need to know which
81 * version to use. The LOKI distribution currently
82 * has AL_BYTE_LOKI defined in altypes.h which
83 * I will use as a flag to identify the distributions.
84 * If this is ever removed, I might revert back to the
85 * if defined(_WIN32) or defined(__APPLE__) test to
86 * identify the Creative dist.
87 * I'm not sure if or how the Nvidia distribution differs
88 * from the Creative distribution. So for
89 * now, the Nvidia distribution gets lumped with the
90 * Creative dist and I hope nothing will break.
91 * My alGetString may be the most vulnerable.
92 */
93 #ifdef AL_BYTE_LOKI
94 #define USING_LOKI_AL_DIST
95 /* This is a short term fix to get around the
96 * queuing problem with non-power of two buffer sizes.
97 * Hopefully the maintainers will fix this before
98 * we're ready to ship.
99 */
100 #define ENABLE_LOKI_QUEUE_FIX_HACK
101
102 /* The AL_GAIN in the Loki dist doesn't seem to do
103 * what I want/expect it to do. I want to use it for
104 * Fading, but it seems to work like an off/on switch.
105 * 0 = off, >0 = on.
106 * The AL_GAIN_LINEAR_LOKI switch seems to do what
107 * I want, so I'll redefine it here so the code is consistent
108 */
109 /* Update: I've changed the source volume implementations
110 * to use AL_MAX_GAIN, so I don't think I need this block
111 * of code anymore. The listener uses AL_GAIN, but I
112 * hope they got this one right since there isn't a AL_MAX_GAIN
113 * for the listener.
114 */
115 /*
116 #undef AL_GAIN
117 #include "alexttypes.h"
118 #define AL_GAIN AL_GAIN_LINEAR_LOKI
119 */
120 #else
121 /* Might need to run other tests to figure out the DIST */
122 /* I've been told that Nvidia doesn't define constants
123 * in the headers like Creative. Instead of
124 * #define AL_REFERENCE_DISTANCE 0x1020,
125 * Nvidia prefers you query OpenAL for a value.
126 * int AL_REFERENCE_DISTANCE = alGetEnumValue(ALubyte*)"AL_REFERNECE_DISTANCE");
127 * So I'm assuming this means the Nvidia lacks this value.
128 * If this is the case,
129 * I guess we can use it to identify the Nvidia dist
130 */
131 #ifdef AL_REFERENCE_DISTANCE
132 #define USING_CREATIVE_AL_DIST
133 #else
134 #define USING_NVIDIA_AL_DIST
135 #endif
136 #endif
137
138 #ifdef ENABLE_LOKI_QUEUE_FIX_HACK
139 /* Need memset to zero out data */
140 #include <string.h>
141 #endif
142
143
144 /* Seek issues for predecoded samples:
145 * The problem is that OpenAL makes us copy an
146 * entire buffer if we want to use it. This
147 * means we potentially have two copies of the
148 * same data. For predecoded data, this can be a
149 * large amount of memory. However, for seek
150 * support, I need to be able to get access to
151 * the original data so I can set byte positions.
152 * The following flags let you disable seek support
153 * if you don't want the memory hit, keep everything,
154 * or let you try to minimize the memory wasted by
155 * fetching it from the OpenAL buffer if needed
156 * and making a copy of it.
157 * Update: I don't think I need this flag anymore. I've made the
158 * effects of this user customizable by the access_data flag on load.
159 * If set to true, then seek and data callbacks work, with the
160 * cost of more memory and possibly CPU for copying the data through
161 * the callbacks. If false, then the extra memory is freed, but
162 * you don't get the features.
163 */
164 /*
165 #define DISABLE_PREDECODED_SEEK
166 */
167 /* Problem: Even though alGetBufferi(., AL_DATA, .)
168 * is in the Creative Programmer's reference,
169 * it actually isn't in the dist. (Invalid enum
170 * in Creative, can't compile in Loki.)
171 * So we have to keep it disabled
172 */
173 #define DISABLE_SEEK_MEMORY_OPTIMIZATION
174
175 #ifndef DISABLE_SEEK_MEMORY_OPTIMIZATION
176 /* Needed for memcpy */
177 #include <string.h>
178 #endif
179
180 /* Old way of doing things:
181 #if defined(_WIN32) || defined(__APPLE__)
182 #define USING_CREATIVE_AL_DIST
183 #else
184 #define USING_LOKI_AL_DIST
185 #endif
186 */
187
188 /************ REMOVE ME (Don't need anymore) ********/
189 #if 0
190 /* Let's get fancy and see if triple buffering
191 * does anything good for us
192 * Must be 2 or more or things will probably break
193 */
194 #define NUMBER_OF_QUEUE_BUFFERS 5
195 /* This is the number of buffers that are queued up
196 * when play first starts up. This should be at least 1
197 * and no more than NUMBER_OF_QUEUE_BUFFERS
198 */
199 #define NUMBER_OF_START_UP_BUFFERS 2
200 #endif
201 /************ END REMOVE ME (Don't need anymore) ********/
202
203 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
204 #include "tErrorLib.h"
205 static TErrorPool* s_ALmixerErrorPool = NULL;
206 #endif
207
208 static ALboolean ALmixer_Initialized = 0;
209 /* This should be set correctly by Init */
210 static ALuint ALmixer_Frequency_global = ALMIXER_DEFAULT_FREQUENCY;
211
212 /* Will be initialized in Init */
213 static ALint Number_of_Channels_global = 0;
214 static ALint Number_of_Reserve_Channels_global = 0;
215 static ALuint Is_Playing_global = 0;
216
217 #ifdef ENABLE_ALMIXER_THREADS
218 /* This is for a simple lock system. It is not meant to be good,
219 * but just sufficient to minimize/avoid threading issues
220 */
221 static SDL_mutex* s_simpleLock;
222 static SDL_Thread* Stream_Thread_global = NULL;
223 #endif
224
225
226 #ifdef __APPLE__
227 static ALvoid Internal_alcMacOSXMixerOutputRate(const ALdouble sample_rate)
228 {
229 static void (*alcMacOSXMixerOutputRateProcPtr)(const ALdouble) = NULL;
230
231 if(NULL == alcMacOSXMixerOutputRateProcPtr)
232 {
233 alcMacOSXMixerOutputRateProcPtr = alGetProcAddress((const ALCchar*) "alcMacOSXMixerOutputRate");
234 }
235
236 if(NULL != alcMacOSXMixerOutputRateProcPtr)
237 {
238 alcMacOSXMixerOutputRateProcPtr(sample_rate);
239 }
240
241 return;
242 }
243
244 ALdouble Internal_alcMacOSXGetMixerOutputRate()
245 {
246 static ALdouble (*alcMacOSXGetMixerOutputRateProcPtr)(void) = NULL;
247
248 if(NULL == alcMacOSXGetMixerOutputRateProcPtr)
249 {
250 alcMacOSXGetMixerOutputRateProcPtr = alGetProcAddress((const ALCchar*) "alcMacOSXGetMixerOutputRate");
251 }
252
253 if(NULL != alcMacOSXGetMixerOutputRateProcPtr)
254 {
255 return alcMacOSXGetMixerOutputRateProcPtr();
256 }
257
258 return 0.0;
259 }
260 #endif
261
262 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
263
264 #if defined(__APPLE__)
265 #include <QuartzCore/QuartzCore.h>
266 #include <unistd.h>
267 static CFTimeInterval s_ticksBaseTime = 0.0;
268
269 #elif defined(_WIN32)
270 #define WIN32_LEAN_AND_MEAN
271 #include <windows.h>
272 #include <winbase.h>
273 LARGE_INTEGER s_hiResTicksPerSecond;
274 double s_hiResSecondsPerTick;
275 LARGE_INTEGER s_ticksBaseTime;
276 #else
277 #include <unistd.h>
278 #include <time.h>
279 static struct timespec s_ticksBaseTime;
280 #endif
281 static void ALmixer_InitTime()
282 {
283 #if defined(__APPLE__)
284 s_ticksBaseTime = CACurrentMediaTime();
285
286 #elif defined(_WIN32)
287 LARGE_INTEGER hi_res_ticks_per_second;
288 if(TRUE == QueryPerformanceFrequency(&hi_res_ticks_per_second))
289 {
290 QueryPerformanceCounter(&s_ticksBaseTime);
291 s_hiResSecondsPerTick = 1.0 / hi_res_ticks_per_second;
292 }
293 else
294 {
295 ALMixer_SetError("Windows error: High resolution clock failed.");
296 fprintf(stderr, "Windows error: High resolution clock failed. Audio will not work correctly.\n");
297 }
298 #else
299 /* clock_gettime is POSIX.1-2001 */
300 clock_gettime(CLOCK_MONOTONIC, &s_ticksBaseTime);
301 #endif
302
303 }
304 static ALuint ALmixer_GetTicks()
305 {
306 #if defined(__APPLE__)
307 return (ALuint)((CACurrentMediaTime()-s_ticksBaseTime)*1000.0);
308 #elif defined(_WIN32)
309 LARGE_INTEGER current_time;
310 QueryPerformanceCounter(&current_time);
311 return (ALuint)((current_time.QuadPart - s_ticksBaseTime.QuadPart) * 1000 * s_hiResSecondsPerTick);
312
313 #else /* assuming POSIX */
314 /* clock_gettime is POSIX.1-2001 */
315 struct timespec current_time;
316 clock_gettime(CLOCK_MONOTONIC, &current_time);
317 return (ALuint)((current_time.tv_sec - s_ticksBaseTime.tv_sec)*1000.0 + (current_time.tv_nec - s_ticksBaseTime.tv_nsec) / 1000000);
318 #endif
319 }
320 static void ALmixer_Delay(ALuint milliseconds_delay)
321 {
322 #if defined(_WIN32)
323 Sleep(milliseconds_delay);
324 #else
325 usleep(milliseconds_delay);
326 #endif
327 }
328 #else
329 #include "SDL.h" /* For SDL_GetTicks(), SDL_Delay */
330 #define ALmixer_GetTicks SDL_GetTicks
331 #define ALmixer_Delay SDL_Delay
332 #endif
333
334
335
336 /* If ENABLE_PARANOID_SIGNEDNESS_CHECK is used,
337 * these values will be reset on Init()
338 * Consider these values Read-Only.
339 */
340
341 #define ALMIXER_SIGNED_VALUE 127
342 #define ALMIXER_UNSIGNED_VALUE 255
343
344 #ifdef ENABLE_PARANOID_SIGNEDNESS_CHECK
345 static ALushort SIGN_TYPE_16_BIT_FORMAT = AUDIO_S16SYS;
346 static ALushort SIGN_TYPE_8_BIT_FORMAT = AUDIO_S8;
347 #else
348 static const ALushort SIGN_TYPE_16_BIT_FORMAT = AUDIO_S16SYS;
349 static const ALushort SIGN_TYPE_8_BIT_FORMAT = AUDIO_S8;
350 #endif
351
352
353 /* This can be private instead of being in the header now that I moved
354 * ALmixer_Data inside here.
355 */
356 typedef struct ALmixer_Buffer_Map ALmixer_Buffer_Map;
357
358
359 struct ALmixer_Data
360 {
361 ALboolean decoded_all; /* dictates different behaviors */
362 ALint total_time; /* total playing time of sample (msec) */
363
364 ALuint in_use; /* needed to prevent sharing for streams */
365 ALboolean eof; /* flag for eof, only used for streams */
366
367 ALuint total_bytes; /* For predecoded */
368 ALuint loaded_bytes; /* For predecoded (for seek) */
369
370 Sound_Sample* sample; /* SDL_Sound provides the data */
371 ALuint* buffer; /* array of OpenAL buffers (at least 1 for predecoded) */
372
373 /* Needed for streamed buffers */
374 ALuint max_queue_buffers; /* Max number of queue buffers */
375 ALuint num_startup_buffers; /* Number of ramp-up buffers */
376 ALuint num_buffers_in_use; /* number of buffers in use */
377
378 /* This stuff is for streamed buffers that require data access */
379 ALmixer_Buffer_Map* buffer_map_list; /* translate ALbuffer to index
380 and holds pointer to copy of data for
381 data access */
382 ALuint current_buffer; /* The current playing buffer */
383
384 /* Nvidia distribution refuses to recognize a simple buffer query command
385 * unlike all other distributions. It's forcing me to redo the code
386 * to accomodate this Nvidia flaw by making me maintain a "best guess"
387 * copy of what I think the buffer queue state looks like.
388 * A circular queue would a helpful data structure for this task,
389 * but I wanted to avoid making an additional header requirement,
390 * so I'm making it a void*
391 */
392 void* circular_buffer_queue;
393
394
395 };
396
397 static struct ALmixer_Channel
398 {
399 ALboolean channel_in_use;
400 ALboolean callback_update; /* For streaming determination */
401 ALboolean needs_stream; /* For streaming determination */
402 ALboolean halted;
403 ALboolean paused;
404 ALuint alsource;
405 ALmixer_Data* almixer_data;
406 ALint loops;
407 ALint expire_ticks;
408 ALuint start_time;
409
410 ALboolean fade_enabled;
411 ALuint fade_expire_ticks;
412 ALuint fade_start_time;
413 ALfloat fade_inv_time;
414 ALfloat fade_start_volume;
415 ALfloat fade_end_volume;
416 ALfloat max_volume;
417 ALfloat min_volume;
418
419 /* Do we need other flags?
420 ALbyte *samples;
421 int volume;
422 int looping;
423 int tag;
424 ALuint expire;
425 ALuint start_time;
426 Mix_Fading fading;
427 int fade_volume;
428 ALuint fade_length;
429 ALuint ticks_fade;
430 effect_info *effects;
431 */
432 } *ALmixer_Channel_List = NULL;
433
434 struct ALmixer_Buffer_Map
435 {
436 ALuint albuffer;
437 ALint index; /* might not need */
438 ALbyte* data;
439 ALuint num_bytes;
440 };
441
442 /* This will be used to find a channel if the user supplies a source */
443 typedef struct Source_Map
444 {
445 ALuint source;
446 ALint channel;
447 } Source_Map;
448 /* Keep an array of all sources with their associated channel */
449 static Source_Map* Source_Map_List;
450
451 static int Compare_Source_Map(const void* a, const void* b)
452 {
453 return ( ((Source_Map*)a)->source - ((Source_Map*)b)->source );
454 }
455
456 /* Sort by channel instead of source */
457 static int Compare_Source_Map_by_channel(const void* a, const void* b)
458 {
459 return ( ((Source_Map*)a)->channel - ((Source_Map*)b)->channel );
460 }
461
462 /* Compare by albuffer */
463 static int Compare_Buffer_Map(const void* a, const void* b)
464 {
465 return ( ((ALmixer_Buffer_Map*)a)->albuffer - ((ALmixer_Buffer_Map*)b)->albuffer );
466 }
467
468 /* This is for the user defined callback via
469 * ALmixer_ChannelFinished()
470 */
471 static void (*Channel_Done_Callback)(ALint which_channel, ALuint al_source, ALmixer_Data* almixer_data, ALboolean finished_naturally, void* user_data) = NULL;
472 static void* Channel_Done_Callback_Userdata = NULL;
473 static void (*Channel_Data_Callback)(ALint which_channel, ALuint al_source, ALbyte* data, ALuint num_bytes, ALuint frequency, ALubyte channels, ALubyte bit_depth, ALboolean is_unsigned, ALboolean decode_mode_is_predecoded, ALuint length_in_msec, void* user_data) = NULL;
474 static void* Channel_Data_Callback_Userdata = NULL;
475
476
477 static void PrintQueueStatus(ALuint source)
478 {
479 ALint buffers_queued = 0;
480 ALint buffers_processed = 0;
481 ALenum error;
482
483 /* Get the number of buffers still queued */
484 alGetSourcei(
485 source,
486 AL_BUFFERS_QUEUED,
487 &buffers_queued
488 );
489
490 if((error = alGetError()) != AL_NO_ERROR)
491 {
492 fprintf(stderr, "Error in PrintQueueStatus, Can't get buffers_queued: %s\n",
493 alGetString(error));
494 }
495 /* Get the number of buffers processed
496 * so we know if we need to refill
497 */
498 alGetSourcei(
499 source,
500 AL_BUFFERS_PROCESSED,
501 &buffers_processed
502 );
503 if((error = alGetError()) != AL_NO_ERROR)
504 {
505 fprintf(stderr, "Error in PrintQueueStatus, Can't get buffers_processed: %s\n",
506 alGetString(error));
507 }
508
509 fprintf(stderr, "For source: %d, buffers_queued=%d, buffers_processed=%d\n",
510 source,
511 buffers_queued,
512 buffers_processed);
513
514 }
515
516
517
518 static void Init_Channel(ALint channel)
519 {
520
521 fprintf(stderr, "Init channel %d\n", channel);
522 ALmixer_Channel_List[channel].channel_in_use = 0;
523 ALmixer_Channel_List[channel].callback_update = 0;
524 ALmixer_Channel_List[channel].needs_stream = 0;
525 ALmixer_Channel_List[channel].paused = 0;
526 ALmixer_Channel_List[channel].halted = 0;
527 ALmixer_Channel_List[channel].loops = 0;
528
529 ALmixer_Channel_List[channel].expire_ticks = 0;
530 ALmixer_Channel_List[channel].start_time = 0;
531
532 ALmixer_Channel_List[channel].fade_enabled = 0;
533 ALmixer_Channel_List[channel].fade_expire_ticks = 0;
534 ALmixer_Channel_List[channel].fade_start_time = 0;
535 ALmixer_Channel_List[channel].fade_inv_time = 0.0f;
536 ALmixer_Channel_List[channel].fade_start_volume = 0.0f;
537 ALmixer_Channel_List[channel].fade_end_volume = 0.0f;
538 ALmixer_Channel_List[channel].max_volume = 1.0f;
539 ALmixer_Channel_List[channel].min_volume = 0.0f;
540
541 ALmixer_Channel_List[channel].almixer_data = NULL;
542 }
543 /* Quick helper function to clean up a channel
544 * after it's done playing */
545 static void Clean_Channel(ALint channel)
546 {
547 ALenum error;
548 ALmixer_Channel_List[channel].channel_in_use = 0;
549 ALmixer_Channel_List[channel].callback_update = 0;
550 ALmixer_Channel_List[channel].needs_stream = 0;
551 ALmixer_Channel_List[channel].paused = 0;
552 ALmixer_Channel_List[channel].halted = 0;
553 ALmixer_Channel_List[channel].loops = 0;
554
555
556 ALmixer_Channel_List[channel].expire_ticks = 0;
557 ALmixer_Channel_List[channel].start_time = 0;
558
559 ALmixer_Channel_List[channel].fade_enabled = 0;
560 ALmixer_Channel_List[channel].fade_expire_ticks = 0;
561 ALmixer_Channel_List[channel].fade_start_time = 0;
562 ALmixer_Channel_List[channel].fade_inv_time = 0.0f;
563 ALmixer_Channel_List[channel].fade_start_volume = 0.0f;
564 ALmixer_Channel_List[channel].fade_end_volume = 0.0f;
565
566 alSourcef(ALmixer_Channel_List[channel].alsource, AL_MAX_GAIN,
567 ALmixer_Channel_List[channel].max_volume);
568
569 if((error = alGetError()) != AL_NO_ERROR)
570 {
571 fprintf(stderr, "10Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
572 alGetString(error));
573 }
574
575 alSourcef(ALmixer_Channel_List[channel].alsource, AL_MIN_GAIN,
576 ALmixer_Channel_List[channel].min_volume);
577 if((error = alGetError()) != AL_NO_ERROR)
578 {
579 fprintf(stderr, "11Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
580 alGetString(error));
581 }
582
583 if(ALmixer_Channel_List[channel].almixer_data != NULL)
584 {
585 if(ALmixer_Channel_List[channel].almixer_data->in_use > 0)
586 {
587 ALmixer_Channel_List[channel].almixer_data->in_use--;
588 }
589 }
590 /* Needed to determine if rewind is needed, can't reset */
591 /*
592 ALmixer_Channel_List[channel].almixer_data->eof = 0;
593 */
594
595 ALmixer_Channel_List[channel].almixer_data = NULL;
596 }
597
598
599 #if 0
600 /* Not needed anymore because not doing any fileext checks.
601 *
602 * Unfortunately, strcasecmp isn't portable so here's a
603 * reimplementation of it (taken from SDL_sound)
604 */
605 static int ALmixer_strcasecmp(const char* x, const char* y)
606 {
607 int ux, uy;
608
609 if (x == y) /* same pointer? Both NULL? */
610 return(0);
611
612 if (x == NULL)
613 return(-1);
614
615 if (y == NULL)
616 return(1);
617
618 do
619 {
620 ux = toupper((int) *x);
621 uy = toupper((int) *y);
622 if (ux > uy)
623 return(1);
624 else if (ux < uy)
625 return(-1);
626 x++;
627 y++;
628 } while ((ux) && (uy));
629
630 return(0);
631 }
632 #endif
633
634
635 /* What shoud this return?
636 * 127 for signed, 255 for unsigned
637 */
638 static ALubyte GetSignednessValue(ALushort format)
639 {
640 switch(format)
641 {
642 case AUDIO_U8:
643 case AUDIO_U16LSB:
644 case AUDIO_U16MSB:
645 return ALMIXER_UNSIGNED_VALUE;
646 break;
647 case AUDIO_S8:
648 case AUDIO_S16LSB:
649 case AUDIO_S16MSB:
650 return ALMIXER_SIGNED_VALUE;
651 break;
652 default:
653 return 0;
654 }
655 return 0;
656 }
657
658
659 static ALubyte GetBitDepth(ALushort format)
660 {
661 ALubyte bit_depth = 16;
662
663 switch(format)
664 {
665 case AUDIO_U8:
666 case AUDIO_S8:
667 bit_depth = 8;
668 break;
669
670 case AUDIO_U16LSB:
671 /*
672 case AUDIO_U16:
673 */
674 case AUDIO_S16LSB:
675 /*
676 case AUDIO_S16:
677 */
678 case AUDIO_U16MSB:
679 case AUDIO_S16MSB:
680 /*
681 case AUDIO_U16SYS:
682 case AUDIO_S16SYS:
683 */
684 bit_depth = 16;
685 break;
686 default:
687 bit_depth = 0;
688 }
689 return bit_depth;
690 }
691
692 /* Need to translate between SDL/SDL_Sound audiospec
693 * and OpenAL conventions */
694 static ALenum TranslateFormat(Sound_AudioInfo* info)
695 {
696 ALubyte bit_depth;
697
698 bit_depth = GetBitDepth(info->format);
699 if(0 == bit_depth)
700 {
701 fprintf(stderr, "Warning: Unknown bit depth. Setting to 16\n");
702 bit_depth = 16;
703 }
704
705 if(2 == info->channels)
706 {
707 if(16 == bit_depth)
708 {
709 return AL_FORMAT_STEREO16;
710 }
711 else
712 {
713 return AL_FORMAT_STEREO8;
714 }
715 }
716 else
717 {
718 if(16 == bit_depth)
719 {
720 return AL_FORMAT_MONO16;
721 }
722 else
723 {
724 return AL_FORMAT_MONO8;
725 }
726 }
727 /* Make compiler happy. Shouldn't get here */
728 return AL_FORMAT_STEREO16;
729 }
730
731
732 /* This will compute the total playing time
733 * based upon the number of bytes and audio info.
734 * (In prinicple, it should compute the time for any given length)
735 */
736 static ALuint Compute_Total_Time_Decomposed(ALuint bytes_per_sample, ALuint frequency, ALubyte channels, size_t total_bytes)
737 {
738 double total_sec;
739 ALuint total_msec;
740 ALuint bytes_per_sec;
741
742 if(0 == total_bytes)
743 {
744 return 0;
745 }
746 /* To compute Bytes per second, do
747 * samples_per_sec * bytes_per_sample * number_of_channels
748 */
749 bytes_per_sec = frequency * bytes_per_sample * channels;
750
751 /* Now to get total time (sec), do
752 * total_bytes / bytes_per_sec
753 */
754 total_sec = total_bytes / (double)bytes_per_sec;
755
756 /* Now convert seconds to milliseconds
757 * Add .5 to the float to do rounding before the final cast
758 */
759 total_msec = (ALuint) ( (total_sec * 1000) + 0.5 );
760 /*
761 fprintf(stderr, "freq=%d, bytes_per_sample=%d, channels=%d, total_msec=%d\n", frequency, bytes_per_sample, channels, total_msec);
762 */
763 return total_msec;
764 }
765
766 static ALuint Compute_Total_Time(Sound_AudioInfo *info, size_t total_bytes)
767 {
768 ALuint bytes_per_sample;
769
770 if(0 == total_bytes)
771 {
772 return 0;
773 }
774 /* SDL has a mask trick I was not aware of. Mask the upper bits
775 * of the format, and you get 8 or 16 which is the bits per sample.
776 * Divide by 8bits_per_bytes and you get bytes_per_sample
777 * I tested this under 32-bit and 64-bit and big and little endian
778 * to make sure this still works since I have since moved from
779 * Uint32 to unspecified size types like ALuint.
780 */
781 bytes_per_sample = (ALuint) ((info->format & 0xFF) / 8);
782
783 return Compute_Total_Time_Decomposed(bytes_per_sample, info->rate, info->channels, total_bytes);
784 } /* End Compute_Total_Time */
785
786
787 static size_t Compute_Total_Bytes_Decomposed(ALuint bytes_per_sample, ALuint frequency, ALubyte channels, ALuint total_msec)
788 {
789 double total_sec;
790 ALuint bytes_per_sec;
791 size_t total_bytes;
792
793 if(0 >= total_msec)
794 {
795 return 0;
796 }
797 /* To compute Bytes per second, do
798 * samples_per_sec * bytes_per_sample * number_of_channels
799 */
800 bytes_per_sec = frequency * bytes_per_sample * channels;
801
802 /* convert milliseconds to seconds */
803 total_sec = total_msec / 1000.0;
804
805 /* Now to get total bytes */
806 total_bytes = (size_t)(((double)bytes_per_sec * total_sec) + 0.5);
807
808 /* fprintf(stderr, "freq=%d, bytes_per_sample=%d, channels=%d, total_msec=%d, total_bytes=%d\n", frequency, bytes_per_sample, channels, total_msec, total_bytes);
809 */
810
811 return total_bytes;
812 }
813
814 static size_t Compute_Total_Bytes(Sound_AudioInfo *info, ALuint total_msec)
815 {
816 ALuint bytes_per_sample;
817
818 if(0 >= total_msec)
819 {
820 return 0;
821 }
822 /* SDL has a mask trick I was not aware of. Mask the upper bits
823 * of the format, and you get 8 or 16 which is the bits per sample.
824 * Divide by 8bits_per_bytes and you get bytes_per_sample
825 * I tested this under 32-bit and 64-bit and big and little endian
826 * to make sure this still works since I have since moved from
827 * Uint32 to unspecified size types like ALuint.
828 */
829 bytes_per_sample = (ALuint) ((info->format & 0xFF) / 8);
830
831 return Compute_Total_Bytes_Decomposed(bytes_per_sample, info->rate, info->channels, total_msec);
832 }
833
834 /* The back-end decoders seem to need to decode in quantized frame sizes.
835 * So if I can pad the bytes to the next quanta, things might go more smoothly.
836 */
837 static size_t Compute_Total_Bytes_With_Frame_Padding(Sound_AudioInfo *info, ALuint total_msec)
838 {
839 ALuint bytes_per_sample;
840 ALuint bytes_per_frame;
841 size_t evenly_divisible_frames;
842 size_t remainder_frames;
843 size_t return_bytes;
844
845 size_t total_bytes = Compute_Total_Bytes(info, total_msec);
846
847 bytes_per_sample = (ALuint) ((info->format & 0xFF) / 8);
848
849 bytes_per_frame = bytes_per_sample * info->channels;
850
851 evenly_divisible_frames = total_bytes / bytes_per_frame;
852 remainder_frames = total_bytes % bytes_per_frame;
853
854 return_bytes = (evenly_divisible_frames * bytes_per_frame) + (remainder_frames * bytes_per_frame);
855
856 /* Experimentally, some times I see to come up short in
857 * actual bytes decoded and I see a second pass is needed.
858 * I'm worried this may have additional performance implications.
859 * Sometimes in the second pass (depending on file),
860 * I have seen between 0 and 18 bytes.
861 * I'm tempted to pad the bytes by some arbitrary amount.
862 * However, I think currently the way SDL_sound is implemented,
863 * there is a big waste of memory up front instead of per-pass,
864 * so maybe I shouldn't worry about this.
865 */
866 /*
867 return_bytes += 64;
868 */
869 /*
870 fprintf(stderr, "remainder_frames=%d, padded_total_bytes=%d\n", remainder_frames, return_bytes);
871 */
872 return return_bytes;
873
874 }
875
876
877
878
879 /**************** REMOVED ****************************/
880 /* This was removed because I originally thought
881 * OpenAL could return a pointer to the buffer data,
882 * but I was wrong. If something like that is ever
883 * implemented, then this might become useful.
884 */
885 #if 0
886 /* Reconstruct_Sound_Sample and Set_AudioInfo only
887 * are needed if the Seek memory optimization is
888 * used. Also, the Loki dist doesn't seem to support
889 * AL_DATA which I need for it.
890 */
891 #ifndef DISABLE_SEEK_MEMORY_OPTIMIZATION
892
893 static void Set_AudioInfo(Sound_AudioInfo* info, ALint frequency, ALint bits, ALint channels)
894 {
895 info->rate = (ALuint)frequency;
896 info->channels = (ALubyte)channels;
897
898 /* Not sure if it should be signed or unsigned. Hopefully
899 * that detail won't be needed.
900 */
901 if(8 == bits)
902 {
903 info->format = AUDIO_U8;
904 }
905 else
906 {
907 info->format = AUDIO_U16SYS;
908 }
909 fprintf(stderr, "Audio info: freq=%d, chan=%d, format=%d\n",
910 info->rate, info->channels, info->format);
911
912 }
913
914
915 static ALint Reconstruct_Sound_Sample(ALmixer_Data* data)
916 {
917 ALenum error;
918 ALint* data_from_albuffer;
919 ALint freq;
920 ALint bits;
921 ALint channels;
922 ALint size;
923
924 /* Create memory all initiallized to 0. */
925 data->sample = (Sound_Sample*)calloc(1, sizeof(Sound_Sample));
926 if(NULL == data->sample)
927 {
928 ALmixer_SetError("Out of memory for Sound_Sample");
929 return -1;
930 }
931
932 /* Clear errors */
933 alGetError();
934
935 alGetBufferi(data->buffer[0], AL_FREQUENCY, &freq);
936 if((error = alGetError()) != AL_NO_ERROR)
937 {
938 ALmixer_SetError("alGetBufferi(AL_FREQUENCY): %s", alGetString(error) );
939 free(data->sample);
940 data->sample = NULL;
941 return -1;
942 }
943
944 alGetBufferi(data->buffer[0], AL_BITS, &bits);
945 if((error = alGetError()) != AL_NO_ERROR)
946 {
947 ALmixer_SetError("alGetBufferi(AL_BITS): %s", alGetString(error) );
948 free(data->sample);
949 data->sample = NULL;
950 return -1;
951 }
952
953 alGetBufferi(data->buffer[0], AL_CHANNELS, &channels);
954 if((error = alGetError()) != AL_NO_ERROR)
955 {
956 ALmixer_SetError("alGetBufferi(AL_CHANNELS): %s", alGetString(error) );
957 free(data->sample);
958 data->sample = NULL;
959 return -1;
960 }
961
962 alGetBufferi(data->buffer[0], AL_SIZE, &size);
963 if((error = alGetError()) != AL_NO_ERROR)
964 {
965 ALmixer_SetError("alGetBufferi(AL_SIZE): %s", alGetString(error) );
966 free(data->sample);
967 data->sample = NULL;
968 return -1;
969 }
970
971 alGetBufferi(data->buffer[0], AL_DATA, data_from_albuffer);
972 if((error = alGetError()) != AL_NO_ERROR)
973 {
974 ALmixer_SetError("alGetBufferi(AL_DATA): %s", alGetString(error) );
975 free(data->sample);
976 data->sample = NULL;
977 return -1;
978 }
979
980 if(size <= 0)
981 {
982 ALmixer_SetError("No data in al buffer");
983 free(data->sample);
984 data->sample = NULL;
985 return -1;
986 }
987
988 /* Now that we have all the attributes, we need to
989 * allocate memory for the buffer and reconstruct
990 * the AudioInfo attributes.
991 */
992 data->sample->buffer = malloc(size*sizeof(ALbyte));
993 if(NULL == data->sample->buffer)
994 {
995 ALmixer_SetError("Out of memory for sample->buffer");
996 free(data->sample);
997 data->sample = NULL;
998 return -1;
999 }
1000
1001 memcpy(data->sample->buffer, data_from_albuffer, size);
1002 data->sample->buffer_size = size;
1003
1004 /* Fill up the Sound_AudioInfo structures */
1005 Set_AudioInfo(&data->sample->desired, freq, bits, channels);
1006 Set_AudioInfo(&data->sample->actual, freq, bits, channels);
1007
1008 return 0;
1009 }
1010
1011 #endif /* End DISABLE_SEEK_MEMORY_OPTIMIZATION */
1012 #endif
1013 /*************** END REMOVED *************************/
1014
1015 static void Invoke_Channel_Done_Callback(ALint which_channel, ALboolean did_finish_naturally)
1016 {
1017 if(NULL == Channel_Done_Callback)
1018 {
1019 return;
1020 }
1021 Channel_Done_Callback(which_channel, ALmixer_Channel_List[which_channel].alsource, ALmixer_Channel_List[which_channel].almixer_data, did_finish_naturally, Channel_Done_Callback_Userdata);
1022 }
1023
1024 static ALint LookUpBuffer(ALuint buffer, ALmixer_Buffer_Map* buffer_map_list, ALuint num_items_in_list)
1025 {
1026 /* Only the first value is used for the key */
1027 ALmixer_Buffer_Map key = { 0, 0, NULL, 0 };
1028 ALmixer_Buffer_Map* found_item = NULL;
1029 key.albuffer = buffer;
1030
1031 /* Use the ANSI C binary search feature (yea!) */
1032 found_item = (ALmixer_Buffer_Map*)bsearch(&key, buffer_map_list, num_items_in_list, sizeof(ALmixer_Buffer_Map), Compare_Buffer_Map);
1033 if(NULL == found_item)
1034 {
1035 ALmixer_SetError("Can't find buffer");
1036 return -1;
1037 }
1038 return found_item->index;
1039 }
1040
1041
1042 /* FIXME: Need to pass back additional info to be useful.
1043 * Bit rate, stereo/mono (num chans), time in msec?
1044 * Precoded/streamed flag so user can plan for future data?
1045 */
1046 /*
1047 * channels: 1 for mono, 2 for stereo
1048 *
1049 */
1050 static void Invoke_Channel_Data_Callback(ALint which_channel, ALbyte* data, ALuint num_bytes, ALuint frequency, ALubyte channels, ALushort format, ALboolean decode_mode_is_predecoded)
1051 {
1052 ALboolean is_unsigned;
1053 ALubyte bits_per_sample = GetBitDepth(format);
1054 ALuint bytes_per_sample;
1055 ALuint length_in_msec;
1056
1057 if(GetSignednessValue(format) == ALMIXER_UNSIGNED_VALUE)
1058 {
1059 is_unsigned = 1;
1060 }
1061 else
1062 {
1063 is_unsigned = 0;
1064 }
1065
1066 bytes_per_sample = (ALuint) (bits_per_sample / 8);
1067
1068 length_in_msec = Compute_Total_Time_Decomposed(bytes_per_sample, frequency, channels, num_bytes);
1069
1070 /*
1071 fprintf(stderr, "%x %x %x %x, bytes=%d, whichchan=%d, freq=%d, channels=%d\n", data[0], data[1], data[2], data[3], num_bytes, channels, frequency, channels);
1072 */
1073 if(NULL == Channel_Data_Callback)
1074 {
1075 return;
1076 }
1077 /*
1078 * Channel_Data_Callback(which_channel, data, num_bytes, frequency, channels, GetBitDepth(format), format, decode_mode_is_predecoded);
1079 */
1080 Channel_Data_Callback(which_channel, ALmixer_Channel_List[which_channel].alsource, data, num_bytes, frequency, channels, bits_per_sample, is_unsigned, decode_mode_is_predecoded, length_in_msec, Channel_Data_Callback_Userdata);
1081 }
1082
1083 static void Invoke_Predecoded_Channel_Data_Callback(ALint channel, ALmixer_Data* data)
1084 {
1085 if(NULL == data->sample)
1086 {
1087 return;
1088 }
1089 /* The buffer position is complicated because if the current data was seeked,
1090 * we must adjust the buffer to the seek position
1091 */
1092 Invoke_Channel_Data_Callback(channel,
1093 (((ALbyte*) data->sample->buffer) + (data->total_bytes - data->loaded_bytes) ),
1094 data->loaded_bytes,
1095 data->sample->desired.rate,
1096 data->sample->desired.channels,
1097 data->sample->desired.format,
1098 AL_TRUE
1099 );
1100 }
1101
1102 static void Invoke_Streamed_Channel_Data_Callback(ALint channel, ALmixer_Data* data, ALuint buffer)
1103 {
1104 ALint index;
1105 if(NULL == data->buffer_map_list)
1106 {
1107 return;
1108 }
1109 index = LookUpBuffer(buffer, data->buffer_map_list, data->max_queue_buffers);
1110 /* This should catch the case where all buffers are unqueued
1111 * and the "current" buffer is id: 0
1112 */
1113 if(-1 == index)
1114 {
1115 return;
1116 }
1117 Invoke_Channel_Data_Callback(channel,
1118 data->buffer_map_list[index].data,
1119 data->buffer_map_list[index].num_bytes,
1120 data->sample->desired.rate,
1121 data->sample->desired.channels,
1122 data->sample->desired.format,
1123 AL_FALSE
1124 );
1125 }
1126
1127 /* From SDL_Sound's playsound. Converts milliseconds to byte positions.
1128 * This is needed for seeking on predecoded samples
1129 */
1130 static ALuint Convert_Msec_To_Byte_Pos(Sound_AudioInfo *info, ALuint ms)
1131 {
1132 float frames_per_ms;
1133 ALuint frame_offset;
1134 ALuint frame_size;
1135 fprintf(stderr, "In convert\n" );
1136 if(info == NULL)
1137 {
1138 fprintf(stderr, "Error, info is NULL\n");
1139 }
1140 else
1141 {
1142 fprintf(stderr, "Not an error: info is not NULL\n");
1143 }
1144 fprintf(stderr, "The rate=%d\n", info->rate);
1145
1146 /* "frames" == "sample frames" */
1147 frames_per_ms = ((float) info->rate) / 1000.0f;
1148 fprintf(stderr, "%f\n", frames_per_ms);
1149 frame_offset = (ALuint) (frames_per_ms * ((float) ms));
1150 fprintf(stderr, "%d\n", frame_offset);
1151 frame_size = (ALuint) ((info->format & 0xFF) / 8) * info->channels;
1152 fprintf(stderr, "%d\n", frame_size);
1153 return(frame_offset * frame_size);
1154 } /* cvtMsToBytePos */
1155
1156 static ALint Set_Predecoded_Seek_Position(ALmixer_Data* data, ALuint byte_position)
1157 {
1158 ALenum error;
1159 /* clear error */
1160 alGetError();
1161
1162 /* Is it greater than, or greater-than or equal to ?? */
1163 if(byte_position > data->total_bytes)
1164 {
1165 /* We can't go past the end, so set to end? */
1166 fprintf(stderr, "Error, can't seek past end\n");
1167
1168 /* In case the below thing doesn't work,
1169 * just rewind the whole thing.
1170 *
1171 alBufferData(data->buffer[0],
1172 TranslateFormat(&data->sample->desired),
1173 (ALbyte*) data->sample->buffer,
1174 data->total_bytes,
1175 data->sample->desired.rate
1176 );
1177 */
1178
1179 /* I was trying to set to the end, (1 byte remaining),
1180 * but I was getting freezes. I'm thinking it might be
1181 * another Power of 2 bug in the Loki dist. I tried 2,
1182 * and it still hung. 4 didn't hang, but I got a clip
1183 * artifact. 8 seemed to work okay.
1184 */
1185 alBufferData(data->buffer[0],
1186 TranslateFormat(&data->sample->desired),
1187 (((ALbyte*) data->sample->buffer) + (data->total_bytes - 8) ),
1188 8,
1189 data->sample->desired.rate
1190 );
1191 if( (error = alGetError()) != AL_NO_ERROR)
1192 {
1193 ALmixer_SetError("Can't seek past end and alBufferData failed: %s\n", alGetString(error));
1194 return -1;
1195 }
1196 /* Need to set the loaded_bytes field because I don't trust the OpenAL
1197 * query command to work because I don't know if it will mutilate the
1198 * size for its own purposes or return the original size
1199 */
1200 data->loaded_bytes = 8;
1201
1202 /* Not sure if this should be an error or not */
1203 /*
1204 ALmixer_SetError("Can't Seek past end");
1205 return -1;
1206 */
1207 return 0;
1208 }
1209
1210 alBufferData(data->buffer[0],
1211 TranslateFormat(&data->sample->desired),
1212 &(((ALbyte*)data->sample->buffer)[byte_position]),
1213 data->total_bytes - byte_position,
1214 data->sample->desired.rate
1215 );
1216 if( (error = alGetError()) != AL_NO_ERROR)
1217 {
1218 ALmixer_SetError("alBufferData failed: %s\n", alGetString(error));
1219 return -1;
1220 }
1221 /* Need to set the loaded_bytes field because I don't trust the OpenAL
1222 * query command to work because I don't know if it will mutilate the
1223 * size for its own purposes or return the original size
1224 */
1225 data->loaded_bytes = data->total_bytes - byte_position;
1226
1227 return 0;
1228 }
1229
1230 /* Because we have multiple queue buffers and OpenAL won't let
1231 * us access them, we need to keep copies of each buffer around
1232 */
1233 static ALint CopyDataToAccessBuffer(ALmixer_Data* data, ALuint num_bytes, ALuint buffer)
1234 {
1235 ALint index;
1236 /* We only want to copy if access_data is true.
1237 * This is determined by whether memory has been
1238 * allocated in the buffer_map_list or not
1239 */
1240 if(NULL == data->buffer_map_list)
1241 {
1242 return -1;
1243 }
1244 index = LookUpBuffer(buffer, data->buffer_map_list, data->max_queue_buffers);
1245 if(-1 == index)
1246 {
1247 fprintf(stderr, ">>>>>>>CopyData catch, albuffer=%d\n",buffer);
1248 return -1;
1249 }
1250 /* Copy the data to the access buffer */
1251 memcpy(data->buffer_map_list[index].data, data->sample->buffer, num_bytes);
1252 data->buffer_map_list[index].num_bytes = data->sample->buffer_size;
1253
1254 return 0;
1255 }
1256
1257
1258 /* For streamed data, gets more data
1259 * and prepares it in the active Mix_chunk
1260 */
1261 static ALuint GetMoreData(ALmixer_Data* data, ALuint buffer)
1262 {
1263 ALuint bytes_decoded;
1264 ALenum error;
1265 if(NULL == data)
1266 {
1267 ALmixer_SetError("Cannot GetMoreData() because ALmixer_Data* is NULL\n");
1268 return 0;
1269 }
1270
1271 bytes_decoded = Sound_Decode(data->sample);
1272 if(data->sample->flags & SOUND_SAMPLEFLAG_ERROR)
1273 {
1274 fprintf(stderr, "Sound_Decode triggered an ERROR>>>>>>\n");
1275 ALmixer_SetError(Sound_GetError());
1276 /* Force cleanup through FreeData
1277 Sound_FreeSample(data->sample);
1278 */
1279 return 0;
1280 }
1281
1282 /* fprintf(stderr, "GetMoreData bytes_decoded=%d\n", bytes_decoded); */
1283
1284 /* Don't forget to add check for EOF */
1285 /* Will return 0 bytes and pass the buck to check sample->flags */
1286 if(0 == bytes_decoded)
1287 {
1288 data->eof = 1;
1289
1290 #if 0
1291 fprintf(stderr, "Hit eof while trying to buffer\n");
1292 if(data->sample->flags & SOUND_SAMPLEFLAG_EOF)
1293 {
1294 fprintf(stderr, "\tEOF flag\n");
1295 }
1296 if(data->sample->flags & SOUND_SAMPLEFLAG_CANSEEK)
1297 {
1298 fprintf(stderr, "\tCanSeek flag\n");
1299 }
1300 if(data->sample->flags & SOUND_SAMPLEFLAG_EAGAIN)
1301 {
1302 fprintf(stderr, "\tEAGAIN flag\n");
1303 }
1304 if(data->sample->flags & SOUND_SAMPLEFLAG_NONE)
1305 {
1306 fprintf(stderr, "\tNONE flag\n");
1307 }
1308 #endif
1309 return 0;
1310 }
1311
1312 #ifdef ENABLE_LOKI_QUEUE_FIX_HACK
1313 /******* REMOVE ME ********************************/
1314 /***************** ANOTHER EXPERIEMENT *******************/
1315 /* The PROBLEM: It seems that the Loki distribution has problems
1316 * with Queuing when the buffer size is not a power of two
1317 * and additional buffers must come after it.
1318 * The behavior is inconsistent, but one of several things
1319 * usually happens:
1320 * Playback is normal
1321 * Playback immediately stops after the non-pow2 buffer
1322 * Playback gets distorted on the non-pow2 buffer
1323 * The entire program segfaults.
1324 * The workaround is to always specify a power of two buffer size
1325 * and hope that SDL_sound always fill it. (By lucky coincidence,
1326 * I already submitted the Ogg fix.) However, this won't catch
1327 * cases where a loop happens because the read at the end of the
1328 * file is typically less than the buffer size.
1329 *
1330 * This fix addresses this issue, however it may break in
1331 * other conditions. Always decode in buffer sizes of powers of 2.
1332 *
1333 * The HACK:
1334 * If the buffer is short, try filling it up with 0's
1335 * to meet the user requested buffer_size which
1336 * is probably a nice number OpenAL likes, in
1337 * hopes to avoid a possible Loki bug with
1338 * short buffers. If looping (which is the main
1339 * reason for this), the negative side effect is
1340 * that it may take longer for the loop to start
1341 * because it must play dead silence. Or if the decoder
1342 * doesn't guarantee to return the requested bytes
1343 * (like Ogg), then you will get breakup in between
1344 * packets.
1345 */
1346 if( (bytes_decoded) < data->sample->buffer_size)
1347 {
1348 ALubyte bit_depth;
1349 ALubyte signedness_value;
1350 int silence_value;
1351 /* Crap, memset value needs to be the "silent" value,
1352 * but it will differ for signed/unsigned and bit depth
1353 */
1354 bit_depth = GetBitDepth(data->sample->desired.format);
1355 signedness_value = GetSignednessValue(data->sample->desired.format);
1356 if(ALMIXER_SIGNED_VALUE == signedness_value)
1357 {
1358 /* I'm guessing that if it's signed, then 0 is the
1359 * "silent" value */
1360 silence_value = 0;
1361 }
1362 else
1363 {
1364 if(8 == bit_depth)
1365 {
1366 /* If 8 bit, I'm guessing it's (2^7)-1 = 127 */
1367 silence_value = 127;
1368 }
1369 else
1370 {
1371 /* For 16 bit, I'm guessing it's (2^15)-1 = 32767 */
1372 silence_value = 32767;
1373 }
1374 }
1375 /* Now fill up the rest of the data buffer with the
1376 * silence_value.
1377 * I don't think I have to worry about endian issues for
1378 * this part since the data is for internal use only
1379 * at this point.
1380 */
1381 memset( &( ((ALbyte*)(data->sample->buffer))[bytes_decoded] ), silence_value, data->sample->buffer_size - bytes_decoded);
1382 /* Now reset the bytes_decoded to reflect the entire
1383 * buffer to tell alBufferData what our full size is.
1384 */
1385 fprintf(stderr, "ALTERED bytes decoded for silence: Original end was %d\n", bytes_decoded);
1386 bytes_decoded = data->sample->buffer_size;
1387 }
1388 /*********** END EXPERIMENT ******************************/
1389 /******* END REMOVE ME ********************************/
1390 #endif
1391
1392 /* Now copy the data to the OpenAL buffer */
1393 /* We can't just set a pointer because the API needs
1394 * its own copy to assist hardware acceleration */
1395 alBufferData(buffer,
1396 TranslateFormat(&data->sample->desired),
1397 data->sample->buffer,
1398 bytes_decoded,
1399 data->sample->desired.rate
1400 );
1401 if( (error = alGetError()) != AL_NO_ERROR)
1402 {
1403 ALmixer_SetError("alBufferData failed: %s\n", alGetString(error));
1404 return 0;
1405 }
1406
1407 /* If we need to, copy the data also to the access area
1408 * (the function will do the check for us)
1409 */
1410 CopyDataToAccessBuffer(data, bytes_decoded, buffer);
1411 return bytes_decoded;
1412 }
1413
1414
1415
1416
1417 /******************** EXPERIEMENT ****************************
1418 * Test function to force maximum buffer filling during loops
1419 * REMOVE LATER
1420 *********************************************/
1421 #if 0
1422 static ALint GetMoreData2(ALmixer_Data* data, ALuint buffer)
1423 {
1424 ALint bytes_decoded;
1425 ALenum error;
1426 if(NULL == data)
1427 {
1428 ALmixer_SetError("Cannot GetMoreData() because ALmixer_Data* is NULL\n");
1429 return -1;
1430 }
1431
1432 if(AL_FALSE == alIsBuffer(buffer))
1433 {
1434 fprintf(stderr, "NOT A BUFFER>>>>>>>>>>>>>>>\n");
1435 return -1;
1436 }
1437 fprintf(stderr, "Entered GetMoreData222222: buffer id is %d\n", buffer);
1438
1439 /*
1440 fprintf(stderr, "Decode in GetMoreData\n");
1441 */
1442
1443 #if 0
1444 if(buffer%2 == 1)
1445 {
1446 fprintf(stderr, "Setting buffer size to 16384\n");
1447 Sound_SetBufferSize(data->sample, 16384);
1448 }
1449 else
1450 {
1451 fprintf(stderr, "Setting buffer size to 8192\n");
1452 Sound_SetBufferSize(data->sample, 8192);
1453 }
1454 #endif
1455
1456 bytes_decoded = Sound_Decode(data->sample);
1457 if(data->sample->flags & SOUND_SAMPLEFLAG_ERROR)
1458 {
1459 fprintf(stderr, "Sound_Decode triggered an ERROR>>>>>>\n");
1460 ALmixer_SetError(Sound_GetError());
1461 /*
1462 Sound_FreeSample(data->sample);
1463 */
1464 return -1;
1465 }
1466 /* Don't forget to add check for EOF */
1467 /* Will return 0 bytes and pass the buck to check sample->flags */
1468 if(0 == bytes_decoded)
1469 {
1470 #if 1
1471 fprintf(stderr, "Hit eof while trying to buffer\n");
1472 data->eof = 1;
1473 if(data->sample->flags & SOUND_SAMPLEFLAG_EOF)
1474 {
1475 fprintf(stderr, "\tEOF flag\n");
1476 }
1477 if(data->sample->flags & SOUND_SAMPLEFLAG_CANSEEK)
1478 {
1479 fprintf(stderr, "\tCanSeek flag\n");
1480 }
1481 if(data->sample->flags & SOUND_SAMPLEFLAG_EAGAIN)
1482 {
1483 fprintf(stderr, "\tEAGAIN flag\n");
1484 }
1485 if(data->sample->flags & SOUND_SAMPLEFLAG_NONE)
1486 {
1487 fprintf(stderr, "\tNONE flag\n");
1488 }
1489 #endif
1490 return 0;
1491 }
1492
1493 if(bytes_decoded < 16384)
1494 {
1495 char* tempbuffer1 = (char*)malloc(16384);
1496 char* tempbuffer2 = (char*)malloc(16384);
1497 int retval;
1498 memcpy(tempbuffer1, data->sample->buffer, bytes_decoded);
1499 retval = Sound_SetBufferSize(data->sample, 16384-bytes_decoded);
1500 if(retval == 1)
1501 {
1502 ALuint new_bytes;
1503 Sound_Rewind(data->sample);
1504 new_bytes = Sound_Decode(data->sample);
1505 fprintf(stderr, "Orig bytes: %d, Make up bytes_decoded=%d, total=%d\n", bytes_decoded, new_bytes, new_bytes+bytes_decoded);
1506
1507 memcpy(tempbuffer2, data->sample->buffer, new_bytes);
1508
1509 retval = Sound_SetBufferSize(data->sample, 16384);
1510 fprintf(stderr, "Finished reset...now danger copy\n");
1511 memcpy(data->sample->buffer, tempbuffer1,bytes_decoded);
1512
1513 fprintf(stderr, "Finished reset...now danger copy2\n");
1514 memcpy( &( ((char*)(data->sample->buffer))[bytes_decoded] ), tempbuffer2, new_bytes);
1515
1516 fprintf(stderr, "Finished \n");
1517
1518 free(tempbuffer1);
1519 free(tempbuffer2);
1520 bytes_decoded += new_bytes;
1521 fprintf(stderr, "ASSERT bytes should equal 16384: %d\n", bytes_decoded);
1522 }
1523 else
1524 {
1525 fprintf(stderr, "Experiment failed: %s\n", Sound_GetError());
1526 }
1527 }
1528
1529 /* Now copy the data to the OpenAL buffer */
1530 /* We can't just set a pointer because the API needs
1531 * its own copy to assist hardware acceleration */
1532 alBufferData(buffer,
1533 TranslateFormat(&data->sample->desired),
1534 data->sample->buffer,
1535 bytes_decoded,
1536 data->sample->desired.rate
1537 );
1538 if( (error = alGetError()) != AL_NO_ERROR)
1539 {
1540 ALmixer_SetError("alBufferData failed: %s\n", alGetString(error));
1541 return -1;
1542 }
1543
1544 fprintf(stderr, "GetMoreData2222 returning %d bytes decoded\n", bytes_decoded);
1545 return bytes_decoded;
1546 }
1547 #endif
1548
1549 /************ END EXPERIEMENT - REMOVE ME *************************/
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559 /* This function will look up the source for the corresponding channel */
1560 /* Must return 0 on error instead of -1 because of unsigned int */
1561 static ALuint Internal_GetSource(ALint channel)
1562 {
1563 ALint i;
1564 /* Make sure channel is in bounds */
1565 if(channel >= Number_of_Channels_global)
1566 {
1567 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
1568 return 0;
1569 }
1570 /* If the user specified -1, then return the an available source */
1571 if(channel < 0)
1572 {
1573 for(i=Number_of_Reserve_Channels_global; i<Number_of_Channels_global; i++)
1574 {
1575 if( ! ALmixer_Channel_List[i].channel_in_use )
1576 {
1577 return ALmixer_Channel_List[i].alsource;
1578 }
1579 }
1580 /* If we get here, all sources are in use */
1581 /* Error message seems too harsh
1582 ALmixer_SetError("All sources are in use");
1583 */
1584 return 0;
1585 }
1586 /* Last case: Return the source for the channel */
1587 return ALmixer_Channel_List[channel].alsource;
1588 }
1589
1590 /* This function will look up the channel for the corresponding source */
1591 static ALint Internal_GetChannel(ALuint source)
1592 {
1593 ALint i;
1594 /* Only the first value is used for the key */
1595 Source_Map key = { 0, 0 };
1596 Source_Map* found_item = NULL;
1597 key.source = source;
1598
1599 /* If the source is 0, look up the first available channel */
1600 if(0 == source)
1601 {
1602 for(i=Number_of_Reserve_Channels_global; i<Number_of_Channels_global; i++)
1603 {
1604 if( ! ALmixer_Channel_List[i].channel_in_use )
1605 {
1606 return i;
1607 }
1608 }
1609 /* If we get here, all sources are in use */
1610 /* Error message seems too harsh
1611 ALmixer_SetError("All channels are in use");
1612 */
1613 return -1;
1614 }
1615
1616
1617 /* Else, look up the source and return the channel */
1618 if(AL_FALSE == alIsSource(source))
1619 {
1620 ALmixer_SetError("Is not a source");
1621 return -1;
1622 }
1623
1624 /* Use the ANSI C binary search feature (yea!) */
1625 found_item = (Source_Map*)bsearch(&key, Source_Map_List, Number_of_Channels_global, sizeof(Source_Map), Compare_Source_Map);
1626 if(NULL == found_item)
1627 {
1628 ALmixer_SetError("Source is valid but not registered with ALmixer (to a channel)");
1629 return -1;
1630 }
1631 return found_item->channel;
1632 }
1633
1634
1635
1636 /* This function will find the first available channel (not in use)
1637 * from the specified start channel. Reserved channels to not qualify
1638 * as available.
1639 */
1640 static ALint Internal_FindFreeChannel(ALint start_channel)
1641 {
1642 /* Start at the number of reserved so we skip over
1643 * all the reserved channels.
1644 */
1645 ALint i = Number_of_Reserve_Channels_global;
1646 /* Quick check to see if we're out of bounds */
1647 if(start_channel >= Number_of_Channels_global)
1648 {
1649 return -1;
1650 }
1651
1652 /* If the start channel is even higher than the reserved,
1653 * then start at the higher value.
1654 */
1655 if(start_channel > Number_of_Reserve_Channels_global)
1656 {
1657 i = start_channel;
1658 }
1659
1660 /* i has already been set */
1661 for( ; i<Number_of_Channels_global; i++)
1662 {
1663 if( ! ALmixer_Channel_List[i].channel_in_use )
1664 {
1665 return i;
1666 }
1667 }
1668 /* If we get here, all sources are in use */
1669 return -1;
1670 }
1671
1672
1673
1674 /* Will return the number of channels halted
1675 * or 0 for error
1676 */
1677 static ALint Internal_HaltChannel(ALint channel, ALboolean did_finish_naturally)
1678 {
1679 ALint retval = 0;
1680 ALint counter = 0;
1681 ALenum error;
1682 ALint buffers_still_queued;
1683 ALint buffers_processed;
1684
1685 if(channel >= Number_of_Channels_global)
1686 {
1687 ALmixer_SetError("Cannot halt channel %d because it exceeds maximum number of channels (%d)\n", channel, Number_of_Channels_global);
1688 return -1;
1689 }
1690 /* If the user specified a specific channel */
1691 if(channel >= 0)
1692 {
1693 fprintf(stderr, "Halt on channel %d\n", channel);
1694 /* only need to process channel if in use */
1695 if(ALmixer_Channel_List[channel].channel_in_use)
1696 {
1697 alSourceStop(ALmixer_Channel_List[channel].alsource);
1698 if((error = alGetError()) != AL_NO_ERROR)
1699 {
1700 fprintf(stderr, "14Testing error: %s\n",
1701 alGetString(error));
1702 }
1703 /* Here's the situation. My old method of using
1704 * alSourceUnqueueBuffers() seemed to be invalid in light
1705 * of all the problems I suffered through with getting
1706 * the CoreData backend to work with this code.
1707 * As such, I'm changing all the code to set the buffer to
1708 * AL_NONE. Furthermore, the queued vs. non-queued issue
1709 * doesn't need to apply here. For non-queued, Loki,
1710 * Creative Windows, and CoreAudio seem to leave the
1711 * buffer queued (Old Mac didn't.) For queued, we need to
1712 * remove the processed buffers and force remove the
1713 * still-queued buffers.
1714 */
1715 fprintf(stderr, "Halt on channel %d, channel in use\n", channel);
1716 alGetSourcei(
1717 ALmixer_Channel_List[channel].alsource,
1718 AL_BUFFERS_QUEUED, &buffers_still_queued
1719 );
1720 if((error = alGetError()) != AL_NO_ERROR)
1721 {
1722 fprintf(stderr, "17Testing Error with buffers_still_queued: %s",
1723 alGetString(error));
1724 ALmixer_SetError("Failed detecting still queued buffers: %s",
1725 alGetString(error) );
1726 retval = -1;
1727 }
1728 alGetSourcei(
1729 ALmixer_Channel_List[channel].alsource,
1730 AL_BUFFERS_PROCESSED, &buffers_processed
1731 );
1732 if((error = alGetError()) != AL_NO_ERROR)
1733 {
1734 fprintf(stderr, "17Testing Error with buffers_processed: %s",
1735 alGetString(error));
1736 ALmixer_SetError("Failed detecting still processed buffers: %s",
1737 alGetString(error) );
1738 retval = -1;
1739 }
1740 /* If either of these is greater than 0, it means we need
1741 * to clear the source
1742 */
1743 if((buffers_still_queued > 0) || (buffers_processed > 0))
1744 {
1745 alSourcei(ALmixer_Channel_List[channel].alsource,
1746 AL_BUFFER,
1747 AL_NONE);
1748 if((error = alGetError()) != AL_NO_ERROR)
1749 {
1750 fprintf(stderr, "17Testing Error with clearing buffer from source: %s",
1751 alGetString(error));
1752 ALmixer_SetError("Failed to clear buffer from source: %s",
1753 alGetString(error) );
1754 retval = -1;
1755 }
1756 }
1757
1758 ALmixer_Channel_List[channel].almixer_data->num_buffers_in_use = 0;
1759
1760 Clean_Channel(channel);
1761 Is_Playing_global--;
1762 /* Launch callback for consistency? */
1763 Invoke_Channel_Done_Callback(channel, did_finish_naturally);
1764 counter++;
1765 }
1766 }
1767 /* The user wants to halt all channels */
1768 else
1769 {
1770 ALint i;
1771 for(i=0; i<Number_of_Channels_global; i++)
1772 {
1773 fprintf(stderr, "Halting channel %d\n", i);
1774 fprintf(stderr, "in use %d\n", ALmixer_Channel_List[i].channel_in_use );
1775 /* only need to process channel if in use */
1776 if(ALmixer_Channel_List[i].channel_in_use)
1777 {
1778 fprintf(stderr, "SourceStop %d\n", i);
1779 alSourceStop(ALmixer_Channel_List[i].alsource);
1780 if((error = alGetError()) != AL_NO_ERROR)
1781 {
1782 fprintf(stderr, "19Testing error: %s\n",
1783 alGetString(error));
1784 }
1785
1786 /* Here's the situation. My old method of using
1787 * alSourceUnqueueBuffers() seemed to be invalid in light
1788 * of all the problems I suffered through with getting
1789 * the CoreData backend to work with this code.
1790 * As such, I'm changing all the code to set the buffer to
1791 * AL_NONE. Furthermore, the queued vs. non-queued issue
1792 * doesn't need to apply here. For non-queued, Loki,
1793 * Creative Windows, and CoreAudio seem to leave the
1794 * buffer queued (Old Mac didn't.) For queued, we need to
1795 * remove the processed buffers and force remove the
1796 * still-queued buffers.
1797 */
1798 fprintf(stderr, "Halt on channel %d, channel in use\n", channel);
1799 alGetSourcei(
1800 ALmixer_Channel_List[i].alsource,
1801 AL_BUFFERS_QUEUED, &buffers_still_queued
1802 );
1803 if((error = alGetError()) != AL_NO_ERROR)
1804 {
1805 fprintf(stderr, "17Testing Error with buffers_still_queued: %s",
1806 alGetString(error));
1807 ALmixer_SetError("Failed detecting still queued buffers: %s",
1808 alGetString(error) );
1809 retval = -1;
1810 }
1811 alGetSourcei(
1812 ALmixer_Channel_List[i].alsource,
1813 AL_BUFFERS_PROCESSED, &buffers_processed
1814 );
1815 if((error = alGetError()) != AL_NO_ERROR)
1816 {
1817 fprintf(stderr, "17Testing Error with buffers_processed: %s",
1818 alGetString(error));
1819 ALmixer_SetError("Failed detecting still processed buffers: %s",
1820 alGetString(error) );
1821 retval = -1;
1822 }
1823 /* If either of these is greater than 0, it means we need
1824 * to clear the source
1825 */
1826 if((buffers_still_queued > 0) || (buffers_processed > 0))
1827 {
1828 alSourcei(ALmixer_Channel_List[i].alsource,
1829 AL_BUFFER,
1830 AL_NONE);
1831 if((error = alGetError()) != AL_NO_ERROR)
1832 {
1833 fprintf(stderr, "17Testing Error with clearing buffer from source: %s",
1834 alGetString(error));
1835 ALmixer_SetError("Failed to clear buffer from source: %s",
1836 alGetString(error) );
1837 retval = -1;
1838 }
1839 }
1840
1841 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0;
1842
1843 fprintf(stderr, "Clean channel %d\n", i);
1844 Clean_Channel(i);
1845 Is_Playing_global--;
1846 /* Launch callback for consistency? */
1847 fprintf(stderr, "Callback%d\n", i);
1848 Invoke_Channel_Done_Callback(i, did_finish_naturally);
1849
1850 /* Increment the counter */
1851 counter++;
1852 }
1853 /* Let's halt everything just in case there
1854 * are bugs.
1855 */
1856 /*
1857 else
1858 {
1859 alSourceStop(ALmixer_Channel_List[channel].alsource);
1860 / * Can't clean because the in_use counter for
1861 * data will get messed up * /
1862 Clean_Channel(channel);
1863 }
1864 */
1865 /* Just in case */
1866 Is_Playing_global = 0;
1867 }
1868 }
1869 if(-1 == retval)
1870 {
1871 return -1;
1872 }
1873 return counter;
1874 }
1875
1876
1877 /* Will return the source halted or the total number of channels
1878 * if all were halted or 0 for error
1879 */
1880 static ALint Internal_HaltSource(ALuint source, ALboolean did_finish_naturally)
1881 {
1882 ALint channel;
1883 if(0 == source)
1884 {
1885 /* Will return the number of sources halted */
1886 return Internal_HaltChannel(-1, did_finish_naturally);
1887 }
1888
1889 channel = Internal_GetChannel(source);
1890 if(-1 == channel)
1891 {
1892 ALmixer_SetError("Cannot halt source: %s", ALmixer_GetError());
1893 return -1;
1894 }
1895 return Internal_HaltChannel(channel, did_finish_naturally);
1896 }
1897
1898
1899
1900 /* Note: Behaves, almost like SDL_mixer, but keep in mind
1901 * that there is no "music" channel anymore, so 0
1902 * will remove everything. (Note, I no longer allow 0
1903 * so it gets set to the default number.)
1904 * Also, callbacks for deleted channels will not be called.
1905 * I really need to do error checking, for realloc and
1906 * GenSources, but reversing the damage is too painful
1907 * for me to think about at the moment, so it's not in here.
1908 */
1909 static ALint Internal_AllocateChannels(ALint numchans)
1910 {
1911 ALenum error;
1912 int i;
1913 /* Return info */
1914 if(numchans < 0)
1915 {
1916 return Number_of_Channels_global;
1917 }
1918 if(0 == numchans)
1919 {
1920 numchans = ALMIXER_DEFAULT_NUM_CHANNELS;
1921 }
1922 /* No change */
1923 if(numchans == Number_of_Channels_global)
1924 {
1925 return Number_of_Channels_global;
1926 }
1927 /* We need to increase the number of channels */
1928 if(numchans > Number_of_Channels_global)
1929 {
1930 /* Not sure how safe this is, but SDL_mixer does it
1931 * the same way */
1932 ALmixer_Channel_List = (struct ALmixer_Channel*) realloc( ALmixer_Channel_List, numchans * sizeof(struct ALmixer_Channel));
1933
1934 /* Allocate memory for the list of sources that map to the channels */
1935 Source_Map_List = (Source_Map*) realloc(Source_Map_List, numchans * sizeof(Source_Map));
1936
1937 for(i=Number_of_Channels_global; i<numchans; i++)
1938 {
1939 Init_Channel(i);
1940 /* Generate a new source and associate it with the channel */
1941 alGenSources(1, &ALmixer_Channel_List[i].alsource);
1942 if((error = alGetError()) != AL_NO_ERROR)
1943 {
1944 fprintf(stderr, "12Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
1945 alGetString(error));
1946 }
1947 /* Copy the source so the SourceMap has it too */
1948 Source_Map_List[i].source = ALmixer_Channel_List[i].alsource;
1949 Source_Map_List[i].channel = i;
1950 /* Clean the channel because there are some things that need to
1951 * be done that can't happen until the source is set
1952 */
1953 Clean_Channel(i);
1954 }
1955
1956 /* The Source_Map_List must be sorted by source for binary searches
1957 */
1958 qsort(Source_Map_List, numchans, sizeof(Source_Map), Compare_Source_Map);
1959
1960 Number_of_Channels_global = numchans;
1961 return numchans;
1962 }
1963 /* Need to remove channels. This might be dangerous */
1964 if(numchans < Number_of_Channels_global)
1965 {
1966 for(i=numchans; i<Number_of_Channels_global; i++)
1967 {
1968 /* Halt the channel */
1969 Internal_HaltChannel(i, AL_FALSE);
1970
1971 /* Delete source associated with the channel */
1972 alDeleteSources(1, &ALmixer_Channel_List[i].alsource);
1973 if((error = alGetError()) != AL_NO_ERROR)
1974 {
1975 fprintf(stderr, "13Testing error: %s\n",
1976 alGetString(error));
1977 }
1978 }
1979
1980
1981 /* Not sure how safe this is, but SDL_mixer does it
1982 * the same way */
1983 ALmixer_Channel_List = (struct ALmixer_Channel*) realloc( ALmixer_Channel_List, numchans * sizeof(struct ALmixer_Channel));
1984
1985 /* The tricky part is that we must remove the entries
1986 * in the source map that correspond to the deleted channels.
1987 * We'll resort the map by channels so we can pick them off
1988 * in order.
1989 */
1990 qsort(Source_Map_List, Number_of_Channels_global, sizeof(Source_Map), Compare_Source_Map_by_channel);
1991
1992 /* Deallocate memory for the list of sources that map to the channels */
1993 Source_Map_List = (Source_Map*) realloc(Source_Map_List, numchans * sizeof(Source_Map));
1994
1995 /* Now resort the map by source and the correct num of chans */
1996 qsort(Source_Map_List, numchans, sizeof(Source_Map), Compare_Source_Map);
1997
1998 /* Reset the number of channels */
1999 Number_of_Channels_global = numchans;
2000 return numchans;
2001 }
2002 /* Shouldn't ever reach here */
2003 return -1;
2004
2005 }
2006
2007 static ALint Internal_ReserveChannels(ALint num)
2008 {
2009 /* Can't reserve more than the max num of channels */
2010 /* Actually, I'll allow it for people who just want to
2011 * set the value really high to effectively disable
2012 * auto-assignment
2013 */
2014
2015 /* Return the current number of reserved channels */
2016 if(num < 0)
2017 {
2018 return Number_of_Reserve_Channels_global;
2019 }
2020 Number_of_Reserve_Channels_global = num;
2021 return Number_of_Reserve_Channels_global;
2022 }
2023
2024
2025 /* This will rewind the SDL_Sound sample for streamed
2026 * samples and start buffering up the data for the next
2027 * playback. This may require samples to be halted
2028 */
2029 static ALint Internal_RewindData(ALmixer_Data* data)
2030 {
2031 ALint retval = 0;
2032 /*
2033 ALint bytes_returned;
2034 ALint i;
2035 */
2036 if(NULL == data)
2037 {
2038 ALmixer_SetError("Cannot rewind because data is NULL\n");
2039 return -1;
2040 }
2041
2042
2043 /* Might have to require Halt */
2044 /* Okay, we assume Halt or natural stop has already
2045 * cleared the data buffers
2046 */
2047 if(data->in_use)
2048 {
2049 fprintf(stderr, "Warning sample is in use. May not be able to rewind\n");
2050 /*
2051 ALmixer_SetError("Data is in use. Cannot rewind unless all sources using the data are halted\n");
2052 return -1;
2053 */
2054 }
2055
2056
2057 /* Because Seek can alter things even in predecoded data,
2058 * decoded data must also be rewound
2059 */
2060 if(data->decoded_all)
2061 {
2062 data->eof = 0;
2063
2064 #if 0
2065 #if defined(DISABLE_PREDECODED_SEEK)
2066 /* Since we can't seek predecoded stuff, it should be rewound */
2067 return 0;
2068 #elif !defined(DISABLE_SEEK_MEMORY_OPTIMIZATION)
2069 /* This case is if the Sound_Sample has been deleted.
2070 * It assumes the data is already at the beginning.
2071 */
2072 if(NULL == data->sample)
2073 {
2074 return 0;
2075 }
2076 /* Else, the sample has already been reallocated,
2077 * and we can fall to normal behavior
2078 */
2079 #endif
2080 #endif
2081 /* If access_data, was enabled, the sound sample
2082 * still exists and we can do stuff.
2083 * If it's NULL, we can't do anything, but
2084 * it should already be "rewound".
2085 */
2086 if(NULL == data->sample)
2087 {
2088 return 0;
2089 }
2090 /* Else, the sample has already been reallocated,
2091 * and we can fall to normal behavior
2092 */
2093
2094 Set_Predecoded_Seek_Position(data, 0);
2095 /*
2096 return data->total_bytes;
2097 */
2098 return 0;
2099 }
2100
2101 /* Remaining stuff for streamed data */
2102
2103 fprintf(stderr, "Rewinding for stream\n");
2104 data->eof = 0;
2105 retval = Sound_Rewind(data->sample);
2106 if(0 == retval)
2107 {
2108 ALmixer_SetError( Sound_GetError() );
2109 return -1;
2110 }
2111 fprintf(stderr, "Rewinding succeeded\n");
2112 fprintf(stderr, "calling GetMoreData for Rewinding for stream\n");
2113 #if 0
2114 /* Clear error */
2115 alGetError();
2116 for(i=0; i<data->num_buffers; i++)
2117 {
2118 bytes_returned = GetMoreData(data, data->buffer[i]);
2119 if(-1 == bytes_returned)
2120 {
2121 return -1;
2122 }
2123 else if(0 == bytes_returned)
2124 {
2125 return -1;
2126 }
2127 retval += bytes_returned;
2128
2129 }
2130 #endif
2131
2132
2133 fprintf(stderr, "end Rewinding for stream\n");
2134
2135 return retval;
2136 }
2137
2138
2139
2140
2141 static ALint Internal_RewindChannel(ALint channel)
2142 {
2143 ALint retval = 0;
2144 ALenum error;
2145 ALint state;
2146
2147 if(channel >= Number_of_Channels_global)
2148 {
2149 ALmixer_SetError("Cannot rewind channel %d because it exceeds maximum number of channels (%d)\n", channel, Number_of_Channels_global);
2150 return -1;
2151 }
2152
2153 if((error = alGetError()) != AL_NO_ERROR)
2154 {
2155 fprintf(stderr, "24Testing error: %s\n",
2156 alGetString(error));
2157 }
2158 /* Clear error */
2159 alGetError();
2160
2161 /* If the user specified a specific channel */
2162 if(channel >= 0)
2163 {
2164 /* only need to process channel if in use */
2165 if(ALmixer_Channel_List[channel].channel_in_use)
2166 {
2167
2168 /* What should I do? Do I just rewind the channel
2169 * or also rewind the data? Since the data is
2170 * shared, let's make it the user's responsibility
2171 * to rewind the data.
2172 */
2173 if(ALmixer_Channel_List[channel].almixer_data->decoded_all)
2174 {
2175 alGetSourcei(
2176 ALmixer_Channel_List[channel].alsource,
2177 AL_SOURCE_STATE, &state
2178 );
2179 if((error = alGetError()) != AL_NO_ERROR)
2180 {
2181 fprintf(stderr, "25Testing error: %s\n",
2182 alGetString(error));
2183 }
2184 alSourceRewind(ALmixer_Channel_List[channel].alsource);
2185 if((error = alGetError()) != AL_NO_ERROR)
2186 {
2187 ALmixer_SetError("%s",
2188 alGetString(error) );
2189 retval = -1;
2190 }
2191 /* Need to resume playback if it was originally playing */
2192 if(AL_PLAYING == state)
2193 {
2194 alSourcePlay(ALmixer_Channel_List[channel].alsource);
2195 if((error = alGetError()) != AL_NO_ERROR)
2196 {
2197 ALmixer_SetError("%s",
2198 alGetString(error) );
2199 retval = -1;
2200 }
2201 }
2202 else if(AL_PAUSED == state)
2203 {
2204 /* HACK: The problem is that when paused, after
2205 * the Rewind, I can't get it off the INITIAL
2206 * state without restarting
2207 */
2208 alSourcePlay(ALmixer_Channel_List[channel].alsource);
2209 if((error = alGetError()) != AL_NO_ERROR)
2210 {
2211 fprintf(stderr, "25Testing error: %s\n",
2212 alGetString(error));
2213 }
2214 alSourcePause(ALmixer_Channel_List[channel].alsource);
2215 if((error = alGetError()) != AL_NO_ERROR)
2216 {
2217 ALmixer_SetError("%s",
2218 alGetString(error) );
2219 retval = -1;
2220 }
2221 }
2222 }
2223 else
2224 {
2225 /* Streamed data is different. Rewinding the channel
2226 * does no good. Rewinding the data will have an
2227 * effect, but it will be lagged based on how
2228 * much data is queued. Recommend users call Halt
2229 * before rewind if they want immediate results.
2230 */
2231 retval = Internal_RewindData(ALmixer_Channel_List[channel].almixer_data);
2232 }
2233 }
2234 }
2235 /* The user wants to rewind all channels */
2236 else
2237 {
2238 ALint i;
2239 for(i=0; i<Number_of_Channels_global; i++)
2240 {
2241 fprintf(stderr, "in use %d\n", ALmixer_Channel_List[i].channel_in_use );
2242 /* only need to process channel if in use */
2243 if(ALmixer_Channel_List[i].channel_in_use)
2244 {
2245 /* What should I do? Do I just rewind the channel
2246 * or also rewind the data? Since the data is
2247 * shared, let's make it the user's responsibility
2248 * to rewind the data.
2249 */
2250 if(ALmixer_Channel_List[i].almixer_data->decoded_all)
2251 {
2252 alGetSourcei(
2253 ALmixer_Channel_List[i].alsource,
2254 AL_SOURCE_STATE, &state
2255 );
2256 if((error = alGetError()) != AL_NO_ERROR)
2257 {
2258 fprintf(stderr, "26Testing error: %s\n",
2259 alGetString(error));
2260 }
2261 alSourceRewind(ALmixer_Channel_List[i].alsource);
2262 if((error = alGetError()) != AL_NO_ERROR)
2263 {
2264 ALmixer_SetError("%s",
2265 alGetString(error) );
2266 retval = -1;
2267 }
2268 /* Need to resume playback if it was originally playing */
2269 if(AL_PLAYING == state)
2270 {
2271 alSourcePlay(ALmixer_Channel_List[i].alsource);
2272 if((error = alGetError()) != AL_NO_ERROR)
2273 {
2274 ALmixer_SetError("%s",
2275 alGetString(error) );
2276 retval = -1;
2277 }
2278 }
2279 else if(AL_PAUSED == state)
2280 {
2281 /* HACK: The problem is that when paused, after
2282 * the Rewind, I can't get it off the INITIAL
2283 * state without restarting
2284 */
2285 alSourcePlay(ALmixer_Channel_List[i].alsource);
2286 if((error = alGetError()) != AL_NO_ERROR)
2287 {
2288 fprintf(stderr, "27Testing error: %s\n",
2289 alGetString(error));
2290 }
2291 alSourcePause(ALmixer_Channel_List[i].alsource);
2292 if((error = alGetError()) != AL_NO_ERROR)
2293 {
2294 ALmixer_SetError("%s",
2295 alGetString(error) );
2296 retval = -1;
2297 }
2298 }
2299 }
2300 else
2301 {
2302 /* Streamed data is different. Rewinding the channel
2303 * does no good. Rewinding the data will have an
2304 * effect, but it will be lagged based on how
2305 * much data is queued. Recommend users call Halt
2306 * before rewind if they want immediate results.
2307 */
2308 retval = Internal_RewindData(ALmixer_Channel_List[i].almixer_data);
2309 }
2310 }
2311 }
2312 }
2313 return retval;
2314 }
2315
2316
2317 static ALint Internal_RewindSource(ALuint source)
2318 {
2319 ALint channel;
2320 if(0 == source)
2321 {
2322 return Internal_RewindChannel(-1) + 1;
2323 }
2324
2325 channel = Internal_GetChannel(source);
2326 if(-1 == channel)
2327 {
2328 ALmixer_SetError("Cannot rewind source: %s", ALmixer_GetError());
2329 return 0;
2330 }
2331 return Internal_RewindChannel(channel) + 1;
2332 }
2333
2334
2335
2336
2337
2338 static ALint Internal_PlayChannelTimed(ALint channel, ALmixer_Data* data, ALint loops, ALint ticks)
2339 {
2340 ALenum error;
2341 int ret_flag = 0;
2342 if(NULL == data)
2343 {
2344 ALmixer_SetError("Can't play because data is NULL\n");
2345 return -1;
2346 }
2347
2348 /* There isn't a good way to share streamed files because
2349 * the decoded data doesn't stick around.
2350 * You must "Load" a brand new instance of
2351 * the data. If you try using the same data,
2352 * bad things may happen. This check will attempt
2353 * to prevent sharing
2354 */
2355 if(0 == data->decoded_all)
2356 {
2357 if(data->in_use)
2358 {
2359 ALmixer_SetError("Can't play shared streamed sample because it is already in use");
2360 return -1;
2361 }
2362
2363 /* Make sure SDL_sound sample is not at EOF.
2364 * This mainly affects streamed files,
2365 * so the check is placed here
2366 */
2367 if(data->eof)
2368 {
2369 if( -1 == Internal_RewindData(data) )
2370 {
2371 ALmixer_SetError("Can't play sample because it is at EOF and cannot rewind");
2372 return -1;
2373 }
2374 }
2375 }
2376 /* We need to provide the user with the first available channel */
2377 if(-1 == channel)
2378 {
2379 ALint i;
2380 for(i=Number_of_Reserve_Channels_global; i<Number_of_Channels_global; i++)
2381 {
2382 if(0 == ALmixer_Channel_List[i].channel_in_use)
2383 {
2384 channel = i;
2385 break;
2386 }
2387 }
2388 /* if we couldn't find a channel, return an error */
2389 if(i == Number_of_Channels_global)
2390 {
2391 ALmixer_SetError("No channels available for playing");
2392 return -1;
2393 }
2394 }
2395 /* If we didn't assign the channel number, make sure it's not
2396 * out of bounds or in use */
2397 else
2398 {
2399 if(channel >= Number_of_Channels_global)
2400 {
2401 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
2402 return -1;
2403 }
2404 else if(ALmixer_Channel_List[channel].channel_in_use)
2405 {
2406 ALmixer_SetError("Requested channel (%d) is in use", channel, Number_of_Channels_global-1, Number_of_Channels_global);
2407 return -1;
2408 }
2409 }
2410 /* Make sure the user doesn't enter some meaningless value */
2411 if(loops < -1)
2412 {
2413 loops = -1;
2414 }
2415
2416 /* loops will probably have to change to be controlled by SDL_Sound */
2417
2418 /* Set up the initial values for playing */
2419 ALmixer_Channel_List[channel].channel_in_use = 1;
2420 data->in_use++;
2421
2422 /* Shouldn't need updating until a callback is fired
2423 * (assuming that we call Play in this function
2424 */
2425 ALmixer_Channel_List[channel].needs_stream = 0;
2426 ALmixer_Channel_List[channel].almixer_data = data;
2427 ALmixer_Channel_List[channel].start_time = ALmixer_GetTicks();
2428
2429 /* If user entered -1 (or less), set to -1 */
2430 if(ticks < 0)
2431 {
2432 ALmixer_Channel_List[channel].expire_ticks = -1;
2433 }
2434 else
2435 {
2436 ALmixer_Channel_List[channel].expire_ticks = ticks;
2437 }
2438
2439
2440 ALmixer_Channel_List[channel].halted = 0;
2441 ALmixer_Channel_List[channel].paused = 0;
2442
2443 /* Ran just use OpenAL to control loops if predecoded and infinite */
2444 ALmixer_Channel_List[channel].loops = loops;
2445 if( (-1 == loops) && (data->decoded_all) )
2446 {
2447 alSourcei(ALmixer_Channel_List[channel].alsource, AL_LOOPING, AL_TRUE);
2448 }
2449 else
2450 {
2451 alSourcei(ALmixer_Channel_List[channel].alsource, AL_LOOPING, AL_FALSE);
2452 }
2453 if((error = alGetError()) != AL_NO_ERROR)
2454 {
2455 fprintf(stderr, "13Testing error: %s\n",
2456 alGetString(error));
2457 }
2458
2459 #if 0
2460 /* Because of the corner case, predecoded
2461 * files must add +1 to the loops.
2462 * Streams do not have this problem
2463 * because they can use the eof flag to
2464 * avoid the conflict.
2465 * Sharing data chunks prevents the use of the eof flag.
2466 * Since streams, cannot share, only predecoded
2467 * files are affected
2468 */
2469 if(data->decoded_all)
2470 {
2471 /* Corner Case: Now that play calls are pushed
2472 * off to update(), the start call must
2473 * also come through here. So, start loops
2474 * must be +1
2475 */
2476 if(-1 == loops)
2477 {
2478 /* -1 is a special case, and you don't want
2479 * to add +1 to it */
2480 ALmixer_Channel_List[channel].loops = -1;
2481 alSourcei(ALmixer_Channel_List[channel].alsource, AL_LOOPING, AL_TRUE);
2482 }
2483 else
2484 {
2485 ALmixer_Channel_List[channel].loops = loops+1;
2486 alSourcei(ALmixer_Channel_List[channel].alsource, AL_LOOPING, AL_FALSE);
2487 }
2488 }
2489 else
2490 {
2491 ALmixer_Channel_List[channel].loops = loops;
2492 /* Can we really loop on streamed data? */
2493 alSourcei(ALmixer_Channel_List[channel].alsource, AL_LOOPING, AL_TRUE);
2494 }
2495 #endif
2496
2497 /* Should I start playing here or pass the buck to update? */
2498 /* Unlike SDL_SoundMixer, I think I'll do it here because
2499 * this library isn't a *total* hack and OpenAL has more
2500 * built in functionality I need, so less needs to be
2501 * controlled and directed through the update function.
2502 * The downside is less functionality is centralized.
2503 * The upside is that the update function should be
2504 * easier to maintain.
2505 */
2506
2507 /* Clear the error flag */
2508 alGetError();
2509 if(data->decoded_all)
2510 {
2511 /* Bind the data to the source */
2512 alSourcei(
2513 ALmixer_Channel_List[channel].alsource,
2514 AL_BUFFER,
2515 data->buffer[0]);
2516 if((error = alGetError()) != AL_NO_ERROR)
2517 {
2518 ALmixer_SetError("Could not bind data to source: %s",
2519 alGetString(error) );
2520 Clean_Channel(channel);
2521 return -1;
2522 }
2523
2524 /* Make data available if access_data is enabled */
2525 Invoke_Predecoded_Channel_Data_Callback(channel, data);
2526 }
2527 else
2528 {
2529 /* Need to use the streaming buffer for binding */
2530
2531 ALuint bytes_returned;
2532 ALuint j;
2533 data->num_buffers_in_use=0;
2534 /****** MODIFICATION must go here *********/
2535 /* Since buffer queuing is pushed off until here to
2536 * avoid buffer conflicts, we must start reading
2537 * data here. First we make sure we have at least one
2538 * packet. Then we queue up until we hit our limit.
2539 */
2540 bytes_returned = GetMoreData(
2541 data,
2542 data->buffer[0]);
2543 if(0 == bytes_returned)
2544 {
2545 /* No data or error */
2546 ALmixer_SetError("Could not get data for streamed PlayChannel: %s", ALmixer_GetError());
2547 Clean_Channel(channel);
2548 return -1;
2549 }
2550 /* Increment the number of buffers in use */
2551 data->num_buffers_in_use++;
2552
2553
2554 /* Now we need to fill up the rest of the buffers.
2555 * There is a corner case where we run out of data
2556 * before the last buffer is filled.
2557 * Stop conditions are we run out of
2558 * data or we max out our preload buffers.
2559 */
2560
2561 fprintf(stderr, "Filling buffer #%d (AL id is %d)\n", 0, data->buffer[0]);
2562 for(j=1; j<data->num_startup_buffers; j++)
2563 {
2564 fprintf(stderr, "Filling buffer #%d (AL id is %d)\n", j, data->buffer[j]);
2565 /*
2566 fprintf(stderr, ">>>>>>>>>>>>>>>>>>HACK for GetMoreData2\n");
2567 */
2568 bytes_returned = GetMoreData(
2569 data,
2570 data->buffer[j]);
2571 /*
2572 * This might be a problem. I made a mistake with the types. I accidentally
2573 * made the bytes returned an ALint and returned -1 on error.
2574 * Bytes returned should be a ALuint, so now I no longer have a -1 case
2575 * to check. I hope I didn't break anything here
2576 */
2577 #if 0
2578 if(bytes_returned < 0)
2579 {
2580 /* Error found */
2581 ALmixer_SetError("Could not get data for additional startup buffers for PlayChannel: %s", ALmixer_GetError());
2582 /* We'll continue on because we do have some valid data */
2583 ret_flag = -1;
2584 break;
2585 }
2586 else if(0 == bytes_returned)
2587 #endif
2588 if(0 == bytes_returned)
2589 {
2590 /* No more data to buffer */
2591 /* Check for loops */
2592 if( ALmixer_Channel_List[channel].loops != 0 )
2593 {
2594 fprintf(stderr, "Need to rewind. In RAMPUP, handling loop\n");
2595 if(0 == Sound_Rewind(data->sample))
2596 {
2597 fprintf(stderr, "error in rewind\n");
2598 ALmixer_SetError( Sound_GetError() );
2599 ALmixer_Channel_List[channel].loops = 0;
2600 ret_flag = -1;
2601 /* We'll continue on because we do have some valid data */
2602 break;
2603 }
2604 /* Remember to reset the data->eof flag */
2605 data->eof = 0;
2606 if(ALmixer_Channel_List[channel].loops > 0)
2607 {
2608 ALmixer_Channel_List[channel].loops--;
2609 fprintf(stderr, "Inside 000 >>>>>>>>>>Loops=%d\n", ALmixer_Channel_List[channel].loops);
2610 }
2611 /* Would like to redo the loop, but due to
2612 * Sound_Rewind() bugs, we would risk falling
2613 * into an infinite loop
2614 */
2615 bytes_returned = GetMoreData(
2616 data,
2617 data->buffer[j]);
2618 if(bytes_returned <= 0)
2619 {
2620 ALmixer_SetError("Could not get data: %s", ALmixer_GetError());
2621 /* We'll continue on because we do have some valid data */
2622 ret_flag = -1;
2623 break;
2624 }
2625 }
2626 else
2627 {
2628 /* No loops to do so quit here */
2629 break;
2630 }
2631 }
2632 /* Increment the number of buffers in use */
2633 data->num_buffers_in_use++;
2634 }
2635 /*
2636 fprintf(stderr, "In PlayChannel, about to queue: source=%d, num_buffers_in_use=%d\n",
2637 ALmixer_Channel_List[channel].alsource,
2638 data->num_buffers_in_use);
2639 */
2640
2641 alSourceQueueBuffers(
2642 ALmixer_Channel_List[channel].alsource,
2643 data->num_buffers_in_use,
2644 data->buffer);
2645 if((error = alGetError()) != AL_NO_ERROR)
2646 {
2647 ALmixer_SetError("Could not bind data to source: %s",
2648 alGetString(error) );
2649 Clean_Channel(channel);
2650 return -1;
2651 }
2652 /* This is part of the hideous Nvidia workaround. In order to figure out
2653 * which buffer to show during callbacks (for things like
2654 * o-scopes), I must keep a copy of the buffers that are queued in my own
2655 * data structure. This code will be called only if
2656 * "access_data" was set, indicated by whether the queue is NULL.
2657 */
2658 if(data->circular_buffer_queue != NULL)
2659 {
2660 ALuint k;
2661 ALuint queue_ret_flag;
2662 for(k=0; k<data->num_buffers_in_use; k++)
2663 {
2664 // fprintf(stderr, "56c: CircularQueue_PushBack.\n");
2665 queue_ret_flag = CircularQueueUnsignedInt_PushBack(data->circular_buffer_queue, data->buffer[k]);
2666 if(0 == queue_ret_flag)
2667 {
2668 fprintf(stderr, "Serious internal error: CircularQueue could not push into queue.\n");
2669 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
2670 }
2671 /*
2672 else
2673 {
2674 fprintf(stderr, "Queue in PlayTimed\n");
2675 CircularQueueUnsignedInt_Print(data->circular_buffer_queue);
2676 }
2677 */
2678 }
2679 }
2680
2681
2682 /****** END **********/
2683 }
2684 /* We have finished loading the data (predecoded or queued)
2685 * so now we can play
2686 */
2687 alSourcePlay(ALmixer_Channel_List[channel].alsource);
2688 if((error = alGetError()) != AL_NO_ERROR)
2689 {
2690 ALmixer_SetError("Play failed: %s",
2691 alGetString(error) );
2692 Clean_Channel(channel);
2693 return -1;
2694 }
2695
2696 /* Add to the counter that something is playing */
2697 Is_Playing_global++;
2698 if(-1 == ret_flag)
2699 {
2700 fprintf(stderr, "BACKDOOR ERROR >>>>>>>>>>>>>>>>>>\n");
2701 return -1;
2702 }
2703 return channel;
2704 }
2705
2706
2707 /* In case the user wants to specify a source instead of a channel,
2708 * they may use this function. This function will look up the
2709 * source-to-channel map, and convert the call into a
2710 * PlayChannelTimed() function call.
2711 * Returns the channel it's being played on.
2712 * Note: If you are prefer this method, then you need to be careful
2713 * about using PlayChannel, particularly if you request the
2714 * first available channels because source and channels have
2715 * a one-to-one mapping in this API. It is quite easy for
2716 * a channel/source to already be in use because of this.
2717 * In this event, an error message will be returned to you.
2718 */
2719 static ALuint Internal_PlaySourceTimed(ALuint source, ALmixer_Data* data, ALint loops, ALint ticks)
2720 {
2721 ALint channel;
2722 ALint retval;
2723 if(0 == source)
2724 {
2725 retval = Internal_PlayChannelTimed(-1, data, loops, ticks);
2726 if(-1 == retval)
2727 {
2728 return 0;
2729 }
2730 else
2731 {
2732 return Internal_GetSource(retval);
2733 }
2734 }
2735
2736 channel = Internal_GetChannel(source);
2737 if(-1 == channel)
2738 {
2739 ALmixer_SetError("Cannot Play source: %s", ALmixer_GetError());
2740 return 0;
2741 }
2742 retval = Internal_PlayChannelTimed(channel, data, loops, ticks);
2743 if(-1 == retval)
2744 {
2745 return 0;
2746 }
2747 else
2748 {
2749 return source;
2750 }
2751 /* make compiler happy */
2752 return 0;
2753 }
2754
2755
2756
2757
2758 /* Returns the channel or number of channels actually paused */
2759
2760 static ALint Internal_PauseChannel(ALint channel)
2761 {
2762 ALenum error;
2763 ALint state;
2764 ALint retval = 0;
2765 ALint counter = 0;
2766
2767 if(channel >= Number_of_Channels_global)
2768 {
2769 ALmixer_SetError("Cannot pause channel %d because it exceeds maximum number of channels (%d)\n", channel, Number_of_Channels_global);
2770 return -1;
2771 }
2772
2773 if((error = alGetError()) != AL_NO_ERROR)
2774 {
2775 fprintf(stderr, "28Testing error: %s\n",
2776 alGetString(error));
2777 }
2778 /* Clear error */
2779 alGetError();
2780
2781 /* If the user specified a specific channel */
2782 if(channel >= 0)
2783 {
2784 fprintf(stderr, "Pause on channel %d\n", channel);
2785 /* only need to process channel if in use */
2786 if(ALmixer_Channel_List[channel].channel_in_use)
2787 {
2788 /* We don't want to repause if already
2789 * paused because the fadeout/expire
2790 * timing will get messed up
2791 */
2792 alGetSourcei(
2793 ALmixer_Channel_List[channel].alsource,
2794 AL_SOURCE_STATE, &state
2795 );
2796 if((error = alGetError()) != AL_NO_ERROR)
2797 {
2798 fprintf(stderr, "29Testing error: %s\n",
2799 alGetString(error));
2800 }
2801 if(AL_PLAYING == state)
2802 {
2803 /* Count the actual number of channels being paused */
2804 counter++;
2805
2806 alSourcePause(ALmixer_Channel_List[channel].alsource);
2807 if((error = alGetError()) != AL_NO_ERROR)
2808 {
2809 ALmixer_SetError("%s",
2810 alGetString(error) );
2811 retval = -1;
2812 }
2813 /* We need to pause the expire time count down */
2814 if(ALmixer_Channel_List[channel].expire_ticks != -1)
2815 {
2816 ALuint current_time = ALmixer_GetTicks();
2817 ALuint diff_time;
2818 diff_time = current_time -
2819 ALmixer_Channel_List[channel].start_time;
2820 /* When we unpause, we will want to reset
2821 * the start time so we can continue
2822 * to base calculations off GetTicks().
2823 * This means we need to subtract the amount
2824 * of time already used up from expire_ticks.
2825 */
2826 ALmixer_Channel_List[channel].expire_ticks =
2827 ALmixer_Channel_List[channel].expire_ticks -
2828 diff_time;
2829 /* Because -1 is a special value, we can't
2830 * allow the time to go negative
2831 */
2832 if(ALmixer_Channel_List[channel].expire_ticks < 0)
2833 {
2834 ALmixer_Channel_List[channel].expire_ticks = 0;
2835 }
2836 }
2837 /* Do the same as expire time for fading */
2838 if(ALmixer_Channel_List[channel].fade_enabled)
2839 {
2840 ALuint current_time = ALmixer_GetTicks();
2841 ALuint diff_time;
2842 diff_time = current_time -
2843 ALmixer_Channel_List[channel].fade_start_time;
2844 /* When we unpause, we will want to reset
2845 * the start time so we can continue
2846 * to base calculations off GetTicks().
2847 * This means we need to subtract the amount
2848 * of time already used up from expire_ticks.
2849 */
2850 ALmixer_Channel_List[channel].fade_expire_ticks =
2851 ALmixer_Channel_List[channel].fade_expire_ticks -
2852 diff_time;
2853 /* Don't allow the time to go negative */
2854 if(ALmixer_Channel_List[channel].expire_ticks < 0)
2855 {
2856 ALmixer_Channel_List[channel].expire_ticks = 0;
2857 }
2858 } /* End fade check */
2859 } /* End if PLAYING */
2860 } /* End If in use */
2861 } /* End specific channel */
2862 /* The user wants to halt all channels */
2863 else
2864 {
2865 ALint i;
2866 for(i=0; i<Number_of_Channels_global; i++)
2867 {
2868 fprintf(stderr, "Pausing channel %d\n", i);
2869 fprintf(stderr, "in use %d\n", ALmixer_Channel_List[i].channel_in_use );
2870 /* only need to process channel if in use */
2871 if(ALmixer_Channel_List[i].channel_in_use)
2872 {
2873 /* We don't want to repause if already
2874 * paused because the fadeout/expire
2875 * timing will get messed up
2876 */
2877 alGetSourcei(
2878 ALmixer_Channel_List[i].alsource,
2879 AL_SOURCE_STATE, &state
2880 );
2881 if((error = alGetError()) != AL_NO_ERROR)
2882 {
2883 fprintf(stderr, "30Testing error: %s\n",
2884 alGetString(error));
2885 }
2886 if(AL_PLAYING == state)
2887 {
2888 /* Count the actual number of channels being paused */
2889 counter++;
2890
2891 fprintf(stderr, "SourcePause %d\n", i);
2892 alSourcePause(ALmixer_Channel_List[i].alsource);
2893 if((error = alGetError()) != AL_NO_ERROR)
2894 {
2895 ALmixer_SetError("%s",
2896 alGetString(error) );
2897 retval = -1;
2898 }
2899 /* We need to pause the expire time count down */
2900 if(ALmixer_Channel_List[i].expire_ticks != -1)
2901 {
2902 ALuint current_time = ALmixer_GetTicks();
2903 ALuint diff_time;
2904 diff_time = current_time -
2905 ALmixer_Channel_List[i].start_time;
2906 /* When we unpause, we will want to reset
2907 * the start time so we can continue
2908 * to base calculations off GetTicks().
2909 * This means we need to subtract the amount
2910 * of time already used up from expire_ticks.
2911 */
2912 ALmixer_Channel_List[i].expire_ticks =
2913 ALmixer_Channel_List[i].expire_ticks -
2914 diff_time;
2915 /* Because -1 is a special value, we can't
2916 * allow the time to go negative
2917 */
2918 if(ALmixer_Channel_List[i].expire_ticks < 0)
2919 {
2920 ALmixer_Channel_List[i].expire_ticks = 0;
2921 }
2922 }
2923 /* Do the same as expire time for fading */
2924 if(ALmixer_Channel_List[i].fade_enabled)
2925 {
2926 ALuint current_time = ALmixer_GetTicks();
2927 ALuint diff_time;
2928 diff_time = current_time -
2929 ALmixer_Channel_List[i].fade_start_time;
2930 /* When we unpause, we will want to reset
2931 * the start time so we can continue
2932 * to base calculations off GetTicks().
2933 * This means we need to subtract the amount
2934 * of time already used up from expire_ticks.
2935 */
2936 ALmixer_Channel_List[i].fade_expire_ticks =
2937 ALmixer_Channel_List[i].fade_expire_ticks -
2938 diff_time;
2939 /* Don't allow the time to go negative */
2940 if(ALmixer_Channel_List[i].expire_ticks < 0)
2941 {
2942 ALmixer_Channel_List[i].expire_ticks = 0;
2943 }
2944 } /* End fade check */
2945 } /* End if PLAYING */
2946 } /* End channel in use */
2947 } /* End for-loop */
2948 }
2949 if(-1 == retval)
2950 {
2951 return -1;
2952 }
2953 return counter;
2954 }
2955
2956 /* Returns the channel or number of channels actually paused */
2957 static ALint Internal_PauseSource(ALuint source)
2958 {
2959 ALint channel;
2960 if(0 == source)
2961 {
2962 return Internal_PauseChannel(-1);
2963 }
2964
2965 channel = Internal_GetChannel(source);
2966 if(-1 == channel)
2967 {
2968 ALmixer_SetError("Cannot pause source: %s", ALmixer_GetError());
2969 return -1;
2970 }
2971 return Internal_PauseChannel(channel);
2972 }
2973
2974
2975
2976 static ALint Internal_ResumeChannel(ALint channel)
2977 {
2978 ALint state;
2979 ALenum error;
2980 ALint retval = 0;
2981 ALint counter = 0;
2982
2983 if(channel >= Number_of_Channels_global)
2984 {
2985 ALmixer_SetError("Cannot pause channel %d because it exceeds maximum number of channels (%d)\n", channel, Number_of_Channels_global);
2986 return -1;
2987 }
2988
2989 if((error = alGetError()) != AL_NO_ERROR)
2990 {
2991 fprintf(stderr, "31Testing error: %s\n",
2992 alGetString(error));
2993 }
2994 /* Clear error */
2995 alGetError();
2996
2997 /* If the user specified a specific channel */
2998 if(channel >= 0)
2999 {
3000 fprintf(stderr, "Pause on channel %d\n", channel);
3001 /* only need to process channel if in use */
3002 if(ALmixer_Channel_List[channel].channel_in_use)
3003 {
3004 alGetSourcei(
3005 ALmixer_Channel_List[channel].alsource,
3006 AL_SOURCE_STATE, &state
3007 );
3008 if((error = alGetError()) != AL_NO_ERROR)
3009 {
3010 fprintf(stderr, "32Testing error: %s\n",
3011 alGetString(error));
3012 }
3013 if(AL_PAUSED == state)
3014 {
3015 /* Count the actual number of channels resumed */
3016 counter++;
3017
3018 /* We need to resume the expire time count down */
3019 if(ALmixer_Channel_List[channel].expire_ticks != -1)
3020 {
3021 ALmixer_Channel_List[channel].start_time = ALmixer_GetTicks();
3022 }
3023 /* Do the same as expire time for fading */
3024 if(ALmixer_Channel_List[channel].fade_enabled)
3025 {
3026 ALmixer_Channel_List[channel].fade_start_time = ALmixer_GetTicks();
3027 }
3028
3029 alSourcePlay(ALmixer_Channel_List[channel].alsource);
3030 if((error = alGetError()) != AL_NO_ERROR)
3031 {
3032 ALmixer_SetError("%s",
3033 alGetString(error) );
3034 retval = -1;
3035 }
3036 }
3037 fprintf(stderr, "Pause on channel %d, channel in use\n", channel);
3038 }
3039 }
3040 /* The user wants to halt all channels */
3041 else
3042 {
3043 ALint i;
3044 for(i=0; i<Number_of_Channels_global; i++)
3045 {
3046 fprintf(stderr, "Pausing channel %d\n", i);
3047 fprintf(stderr, "in use %d\n", ALmixer_Channel_List[i].channel_in_use );
3048 /* only need to process channel if in use */
3049 if(ALmixer_Channel_List[i].channel_in_use)
3050 {
3051 fprintf(stderr, "SourcePause %d\n", i);
3052 alGetSourcei(
3053 ALmixer_Channel_List[i].alsource,
3054 AL_SOURCE_STATE, &state
3055 );
3056 if((error = alGetError()) != AL_NO_ERROR)
3057 {
3058 fprintf(stderr, "33Testing error: %s\n",
3059 alGetString(error));
3060 }
3061 if(AL_PAUSED == state)
3062 {
3063 /* Count the actual number of channels resumed */
3064 counter++;
3065
3066 /* We need to resume the expire time count down */
3067 if(ALmixer_Channel_List[i].expire_ticks != -1)
3068 {
3069 ALmixer_Channel_List[i].start_time = ALmixer_GetTicks();
3070 }
3071 /* Do the same as expire time for fading */
3072 if(ALmixer_Channel_List[i].fade_enabled)
3073 {
3074 ALmixer_Channel_List[i].fade_start_time = ALmixer_GetTicks();
3075 }
3076
3077 alSourcePlay(ALmixer_Channel_List[i].alsource);
3078 if((error = alGetError()) != AL_NO_ERROR)
3079 {
3080 ALmixer_SetError("%s",
3081 alGetString(error) );
3082 retval = -1;
3083 }
3084 }
3085 }
3086 }
3087 }
3088 if(-1 == retval)
3089 {
3090 return -1;
3091 }
3092 return counter;
3093 }
3094
3095
3096 static ALint Internal_ResumeSource(ALuint source)
3097 {
3098 ALint channel;
3099 if(0 == source)
3100 {
3101 return Internal_ResumeChannel(-1);
3102 }
3103
3104 channel = Internal_GetChannel(source);
3105 if(-1 == channel)
3106 {
3107 ALmixer_SetError("Cannot resume source: %s", ALmixer_GetError());
3108 return -1;
3109 }
3110 return Internal_ResumeChannel(channel);
3111 }
3112
3113
3114 /* Might consider setting eof to 0 as a "feature"
3115 * This will allow seek to end to stay there because
3116 * Play automatically rewinds if at the end */
3117 static ALint Internal_SeekData(ALmixer_Data* data, ALuint msec)
3118 {
3119 ALint retval;
3120
3121 if(NULL == data)
3122 {
3123 ALmixer_SetError("Cannot Seek because data is NULL");
3124 return -1;
3125 }
3126
3127 /* Seek for predecoded files involves moving the chunk pointer around */
3128 if(data->decoded_all)
3129 {
3130 ALuint byte_position;
3131
3132 /* OpenAL doesn't seem to like it if I change the buffer
3133 * while playing (crashes), so I must require that Seek only
3134 * be done when the data is not in use.
3135 * Since data may be shared among multiple sources,
3136 * I can't shut them down myself, so I have to return an error.
3137 */
3138 if(data->in_use)
3139 {
3140 ALmixer_SetError("Cannot seek on predecoded data while instances are playing");
3141 return -1;
3142 }
3143 #if 0
3144 #if defined(DISABLE_PREDECODED_SEEK)
3145 ALmixer_SetError("Seek support for predecoded samples was not compiled in");
3146 return -1;
3147
3148 #elif !defined(DISABLE_SEEK_MEMORY_OPTIMIZATION)
3149 /* By default, ALmixer frees the Sound_Sample for predecoded
3150 * samples because of the potential memory waste.
3151 * However, to seek a sample, we need to have a full
3152 * copy of the data around. So the strategy is to
3153 * recreate a hackish Sound_Sample to be used for seeking
3154 * purposes. If Sound_Sample is NULL, we will reallocate
3155 * memory for it and then procede as if everything
3156 * was normal.
3157 */
3158 if(NULL == data->sample)
3159 {
3160 if( -1 == Reconstruct_Sound_Sample(data) )
3161 {
3162 return -1;
3163 }
3164 }
3165 #endif
3166 #endif
3167 /* If access_data was set, then we still have the
3168 * Sound_Sample and we can move around in the data.
3169 * If it was not set, the data has been freed and we
3170 * cannot do anything because there is no way to
3171 * recover the data because OpenAL won't let us
3172 * get access to the buffers
3173 */
3174 if(NULL == data->sample)
3175 {
3176 ALmixer_SetError("Cannot seek because access_data flag was set false when data was initialized");
3177 return -1;
3178 }
3179
3180 fprintf(stderr, "Calling convert\n");
3181 byte_position = Convert_Msec_To_Byte_Pos(&data->sample->desired, msec);
3182 fprintf(stderr, "Calling Set_Predecoded_Seek...%d\n", byte_position);
3183 return( Set_Predecoded_Seek_Position(data, byte_position) );
3184 }
3185 else
3186 {
3187 /* Reset eof flag?? */
3188 data->eof = 0;
3189 retval = Sound_Seek(data->sample, msec);
3190 if(0 == retval)
3191 {
3192 ALmixer_SetError(Sound_GetError());
3193
3194 fprintf(stderr, "Sound seek error: %s\n", ALmixer_GetError());
3195 /* Try rewinding to clean up? */
3196 /*
3197 Internal_RewindData(data);
3198 */
3199 return -1;
3200 }
3201 return 0;
3202 }
3203
3204 return 0;
3205 }
3206
3207
3208
3209 static ALint Internal_FadeInChannelTimed(ALint channel, ALmixer_Data* data, ALint loops, ALuint fade_ticks, ALint expire_ticks)
3210 {
3211 ALfloat value;
3212 ALenum error;
3213 ALfloat original_value;
3214 ALuint current_time = ALmixer_GetTicks();
3215 ALint retval;
3216
3217
3218
3219 if(channel >= Number_of_Channels_global)
3220 {
3221 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
3222 return -1;
3223 }
3224 /* Let's call PlayChannelTimed to do the job.
3225 * There are two catches:
3226 * First is that we must set the volumes before the play call(s).
3227 * Second is that we must initialize the channel values
3228 */
3229
3230 if(channel < 0)
3231 {
3232 /* This might cause a problem for threads/race conditions.
3233 * We need to set the volume on an unknown channel,
3234 * so we need to request a channel first. Remember
3235 * that requesting a channel doesn't lock and it
3236 * could be surrendered to somebody else before we claim it.
3237 */
3238 channel = Internal_GetChannel(0);
3239 if(-1 == channel)
3240 {
3241 return -1;
3242 }
3243 }
3244 else if(ALmixer_Channel_List[channel].channel_in_use)
3245 {
3246 ALmixer_SetError("Channel %d is already in use", channel);
3247 return -1;
3248 }
3249
3250
3251 /* Get the original volume in case of a problem */
3252 alGetSourcef(ALmixer_Channel_List[channel].alsource,
3253 AL_GAIN, &original_value);
3254
3255 if((error = alGetError()) != AL_NO_ERROR)
3256 {
3257 fprintf(stderr, "35Testing error: %s\n",
3258 alGetString(error));
3259 }
3260 ALmixer_Channel_List[channel].fade_end_volume = original_value;
3261
3262 /* Get the Min volume */
3263 alGetSourcef(ALmixer_Channel_List[channel].alsource,
3264 AL_MIN_GAIN, &value);
3265 if((error = alGetError()) != AL_NO_ERROR)
3266 {
3267 fprintf(stderr, "36Testing error: %s\n",
3268 alGetString(error));
3269 }
3270 ALmixer_Channel_List[channel].fade_start_volume = value;
3271 fprintf(stderr, "MIN gain: %f\n", value);
3272
3273 /* Set the actual volume */
3274 alSourcef(ALmixer_Channel_List[channel].alsource,
3275 AL_GAIN, value);
3276 if((error = alGetError()) != AL_NO_ERROR)
3277 {
3278 fprintf(stderr, "37Testing error: %s\n",
3279 alGetString(error));
3280 }
3281
3282
3283 /* Now call PlayChannelTimed */
3284 retval = Internal_PlayChannelTimed(channel, data, loops, expire_ticks);
3285 if(-1 == retval)
3286 {
3287 /* Chance of failure is actually pretty high since
3288 * a channel might already be in use or streamed
3289 * data can be shared
3290 */
3291 /* Restore the original value to avoid accidental
3292 * distruption of playback
3293 */
3294 alSourcef(ALmixer_Channel_List[channel].alsource,
3295 AL_GAIN, original_value);
3296 if((error = alGetError()) != AL_NO_ERROR)
3297 {
3298 fprintf(stderr, "38Testing error: %s\n",
3299 alGetString(error));
3300 }
3301 return retval;
3302 }
3303
3304 /* We can't accept 0 as a value because of div-by-zero.
3305 * If zero, just call PlayChannelTimed at normal
3306 * volume
3307 */
3308 if(0 == fade_ticks)
3309 {
3310 alSourcef(ALmixer_Channel_List[channel].alsource,
3311 AL_GAIN,
3312 ALmixer_Channel_List[channel].fade_end_volume
3313 );
3314 if((error = alGetError()) != AL_NO_ERROR)
3315 {
3316 fprintf(stderr, "39Testing error: %s\n",
3317 alGetString(error));
3318 }
3319
3320 return retval;
3321 }
3322
3323 /* Enable fading effects via the flag */
3324 ALmixer_Channel_List[channel].fade_enabled = 1;
3325 /* Set fade start time */
3326 ALmixer_Channel_List[channel].fade_start_time
3327 = ALmixer_Channel_List[channel].start_time;
3328 fprintf(stderr, "Current time =%d\n", current_time);
3329 /* Set the fade expire ticks */
3330 ALmixer_Channel_List[channel].fade_expire_ticks = fade_ticks;
3331
3332 /* Set 1/(endtime-starttime) or 1/deltaT */
3333 ALmixer_Channel_List[channel].fade_inv_time = 1.0f / fade_ticks;
3334
3335 return retval;
3336
3337 }
3338
3339
3340 static ALuint Internal_FadeInSourceTimed(ALuint source, ALmixer_Data* data, ALint loops, ALuint fade_ticks, ALint expire_ticks)
3341 {
3342 ALint channel;
3343 ALint retval;
3344 if(0 == source)
3345 {
3346 retval = Internal_FadeInChannelTimed(-1, data, loops, fade_ticks, expire_ticks);
3347 if(-1 == retval)
3348 {
3349 return 0;
3350 }
3351 else
3352 {
3353 return Internal_GetSource(retval);
3354 }
3355 }
3356
3357 channel = Internal_GetChannel(source);
3358 if(-1 == channel)
3359 {
3360 ALmixer_SetError("Cannot FadeIn source: %s", ALmixer_GetError());
3361 return 0;
3362 }
3363 retval = Internal_FadeInChannelTimed(channel, data, loops, fade_ticks, expire_ticks);
3364 if(-1 == retval)
3365 {
3366 return 0;
3367 }
3368 else
3369 {
3370 return source;
3371 }
3372 /* make compiler happy */
3373 return 0;
3374 }
3375
3376
3377
3378
3379 /* Will fade out currently playing channels.
3380 * It starts at the current volume level and goes down */
3381 static ALint Internal_FadeOutChannel(ALint channel, ALuint ticks)
3382 {
3383 ALfloat value;
3384 ALenum error;
3385 ALuint current_time = ALmixer_GetTicks();
3386 ALuint counter = 0;
3387
3388 /* We can't accept 0 as a value because of div-by-zero.
3389 * If zero, just call Halt at normal
3390 * volume
3391 */
3392 if(0 == ticks)
3393 {
3394 return Internal_HaltChannel(channel, AL_TRUE);
3395 }
3396
3397
3398 if(channel >= Number_of_Channels_global)
3399 {
3400 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
3401 return -1;
3402 }
3403
3404 if(channel >= 0)
3405 {
3406 if(ALmixer_Channel_List[channel].channel_in_use)
3407 {
3408 /* Get the current volume */
3409 alGetSourcef(ALmixer_Channel_List[channel].alsource,
3410 AL_GAIN, &value);
3411 ALmixer_Channel_List[channel].fade_start_volume = value;
3412 if((error = alGetError()) != AL_NO_ERROR)
3413 {
3414 fprintf(stderr, "40Testing error: %s\n",
3415 alGetString(error));
3416 }
3417
3418 /* Get the Min volume */
3419 alGetSourcef(ALmixer_Channel_List[channel].alsource,
3420 AL_MIN_GAIN, &value);
3421 if((error = alGetError()) != AL_NO_ERROR)
3422 {
3423 fprintf(stderr, "41Testing error: %s\n",
3424 alGetString(error));
3425 }
3426 ALmixer_Channel_List[channel].fade_end_volume = value;
3427 fprintf(stderr, "MIN gain: %f\n", value);
3428
3429 /* Set expire start time */
3430 ALmixer_Channel_List[channel].start_time = current_time;
3431 /* Set the expire ticks */
3432 ALmixer_Channel_List[channel].expire_ticks = ticks;
3433 /* Set fade start time */
3434 ALmixer_Channel_List[channel].fade_start_time = current_time;
3435 /* Set the fade expire ticks */
3436 ALmixer_Channel_List[channel].fade_expire_ticks = ticks;
3437 /* Enable fading effects via the flag */
3438 ALmixer_Channel_List[channel].fade_enabled = 1;
3439
3440 /* Set 1/(endtime-starttime) or 1/deltaT */
3441 ALmixer_Channel_List[channel].fade_inv_time = 1.0f / ticks;
3442
3443 counter++;
3444 }
3445 }
3446 /* Else need to fade out all channels */
3447 else
3448 {
3449 ALint i;
3450 for(i=0; i<Number_of_Channels_global; i++)
3451 {
3452 if(ALmixer_Channel_List[i].channel_in_use)
3453 {
3454 /* Get the current volume */
3455 alGetSourcef(ALmixer_Channel_List[i].alsource,
3456 AL_GAIN, &value);
3457 ALmixer_Channel_List[i].fade_start_volume = value;
3458 if((error = alGetError()) != AL_NO_ERROR)
3459 {
3460 fprintf(stderr, "42Testing error: %s\n",
3461 alGetString(error));
3462 }
3463
3464 /* Get the Min volume */
3465 alGetSourcef(ALmixer_Channel_List[i].alsource,
3466 AL_MIN_GAIN, &value);
3467 if((error = alGetError()) != AL_NO_ERROR)
3468 {
3469 fprintf(stderr, "43Testing error: %s\n",
3470 alGetString(error));
3471 }
3472 ALmixer_Channel_List[i].fade_end_volume = value;
3473 fprintf(stderr, "MIN gain: %f\n", value);
3474
3475 /* Set expire start time */
3476 ALmixer_Channel_List[i].start_time = current_time;
3477 /* Set the expire ticks */
3478 ALmixer_Channel_List[i].expire_ticks = ticks;
3479 /* Set fade start time */
3480 ALmixer_Channel_List[i].fade_start_time = current_time;
3481 /* Set the fade expire ticks */
3482 ALmixer_Channel_List[i].fade_expire_ticks = ticks;
3483 /* Enable fading effects via the flag */
3484 ALmixer_Channel_List[i].fade_enabled = 1;
3485
3486 /* Set 1/(endtime-starttime) or 1/deltaT */
3487 ALmixer_Channel_List[i].fade_inv_time = 1.0f / ticks;
3488
3489 counter++;
3490 }
3491 } /* End for loop */
3492 }
3493 return counter;
3494 }
3495
3496
3497 static ALint Internal_FadeOutSource(ALuint source, ALuint ticks)
3498 {
3499 ALint channel;
3500 if(0 == source)
3501 {
3502 return Internal_FadeOutChannel(-1, ticks);
3503 }
3504
3505 channel = Internal_GetChannel(source);
3506 if(-1 == channel)
3507 {
3508 ALmixer_SetError("Cannot FadeOut source: %s", ALmixer_GetError());
3509 return -1;
3510 }
3511 return Internal_FadeOutChannel(channel, ticks);
3512 }
3513
3514
3515 /* Will fade currently playing channels.
3516 * It starts at the current volume level and go to target
3517 * Only affects channels that are playing
3518 */
3519 static ALint Internal_FadeChannel(ALint channel, ALuint ticks, ALfloat volume)
3520 {
3521 ALfloat value;
3522 ALenum error;
3523 ALuint current_time = ALmixer_GetTicks();
3524 ALuint counter = 0;
3525
3526 if(channel >= Number_of_Channels_global)
3527 {
3528 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
3529 return -1;
3530 }
3531
3532 if(channel >= 0)
3533 {
3534 if(volume < ALmixer_Channel_List[channel].min_volume)
3535 {
3536 volume = ALmixer_Channel_List[channel].min_volume;
3537 }
3538 else if(volume > ALmixer_Channel_List[channel].max_volume)
3539 {
3540 volume = ALmixer_Channel_List[channel].max_volume;
3541 }
3542
3543 if(ALmixer_Channel_List[channel].channel_in_use)
3544 {
3545 if(ticks > 0)
3546 {
3547 /* Get the current volume */
3548 alGetSourcef(ALmixer_Channel_List[channel].alsource,
3549 AL_GAIN, &value);
3550 if((error = alGetError()) != AL_NO_ERROR)
3551 {
3552 fprintf(stderr, "44Testing error: %s\n",
3553 alGetString(error));
3554 }
3555 ALmixer_Channel_List[channel].fade_start_volume = value;
3556
3557 /* Set the target volume */
3558 ALmixer_Channel_List[channel].fade_end_volume = volume;
3559
3560 /* Set fade start time */
3561 ALmixer_Channel_List[channel].fade_start_time = current_time;
3562 /* Set the fade expire ticks */
3563 ALmixer_Channel_List[channel].fade_expire_ticks = ticks;
3564 /* Enable fading effects via the flag */
3565 ALmixer_Channel_List[channel].fade_enabled = 1;
3566
3567 /* Set 1/(endtime-starttime) or 1/deltaT */
3568 ALmixer_Channel_List[channel].fade_inv_time = 1.0f / ticks;
3569 }
3570 else
3571 {
3572 alSourcef(ALmixer_Channel_List[channel].alsource,
3573 AL_GAIN, volume);
3574 if((error = alGetError()) != AL_NO_ERROR)
3575 {
3576 fprintf(stderr, "45Testing error: %s\n",
3577 alGetString(error));
3578 }
3579 }
3580 counter++;
3581 }
3582 }
3583 /* Else need to fade out all channels */
3584 else
3585 {
3586 ALint i;
3587 for(i=0; i<Number_of_Channels_global; i++)
3588 {
3589 if(volume < ALmixer_Channel_List[i].min_volume)
3590 {
3591 volume = ALmixer_Channel_List[i].min_volume;
3592 }
3593 else if(volume > ALmixer_Channel_List[i].max_volume)
3594 {
3595 volume = ALmixer_Channel_List[i].max_volume;
3596 }
3597
3598 if(ALmixer_Channel_List[i].channel_in_use)
3599 {
3600 if(ticks > 0)
3601 {
3602 /* Get the current volume */
3603 alGetSourcef(ALmixer_Channel_List[i].alsource,
3604 AL_GAIN, &value);
3605 if((error = alGetError()) != AL_NO_ERROR)
3606 {
3607 fprintf(stderr, "46Testing error: %s\n",
3608 alGetString(error));
3609 }
3610 ALmixer_Channel_List[i].fade_start_volume = value;
3611
3612 /* Set target volume */
3613 ALmixer_Channel_List[i].fade_end_volume = volume;
3614
3615 /* Set fade start time */
3616 ALmixer_Channel_List[i].fade_start_time = current_time;
3617 /* Set the fade expire ticks */
3618 ALmixer_Channel_List[i].fade_expire_ticks = ticks;
3619 /* Enable fading effects via the flag */
3620 ALmixer_Channel_List[i].fade_enabled = 1;
3621
3622 /* Set 1/(endtime-starttime) or 1/deltaT */
3623 ALmixer_Channel_List[i].fade_inv_time = 1.0f / ticks;
3624 }
3625 else
3626 {
3627 alSourcef(ALmixer_Channel_List[i].alsource,
3628 AL_GAIN, volume);
3629 if((error = alGetError()) != AL_NO_ERROR)
3630 {
3631 fprintf(stderr, "47Testing error: %s\n",
3632 alGetString(error));
3633 }
3634 }
3635 counter++;
3636 }
3637 } /* End for loop */
3638 }
3639 return counter;
3640 }
3641
3642 static ALint Internal_FadeSource(ALuint source, ALuint ticks, ALfloat volume)
3643 {
3644 ALint channel;
3645 if(0 == source)
3646 {
3647 return Internal_FadeChannel(-1, ticks, volume);
3648 }
3649
3650 channel = Internal_GetChannel(source);
3651 if(-1 == channel)
3652 {
3653 ALmixer_SetError("Cannot Fade source: %s", ALmixer_GetError());
3654 return -1;
3655 }
3656 return Internal_FadeChannel(channel, ticks, volume);
3657 }
3658
3659
3660
3661
3662 /* Set a volume regardless if it's in use or not.
3663 */
3664 static ALboolean Internal_SetVolumeChannel(ALint channel, ALfloat volume)
3665 {
3666 ALenum error;
3667 ALboolean retval = AL_TRUE;
3668
3669 if(channel >= Number_of_Channels_global)
3670 {
3671 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
3672 return AL_FALSE;
3673 }
3674
3675 if(channel >= 0)
3676 {
3677 if(volume < 0.0f)
3678 {
3679 volume = 0.0f;
3680 }
3681 else if(volume > 1.0f)
3682 {
3683 volume = 1.0f;
3684 }
3685 alSourcef(ALmixer_Channel_List[channel].alsource,
3686 AL_GAIN, volume);
3687 if((error = alGetError()) != AL_NO_ERROR)
3688 {
3689 ALmixer_SetError("%s",
3690 alGetString(error) );
3691 retval = AL_FALSE;
3692 }
3693 }
3694 else
3695 {
3696 ALint i;
3697 for(i=0; i<Number_of_Channels_global; i++)
3698 {
3699 if(volume < 0.0f)
3700 {
3701 volume = 0.0f;
3702 }
3703 else if(volume > 1.0f)
3704 {
3705 volume = 1.0f;
3706 }
3707 alSourcef(ALmixer_Channel_List[i].alsource,
3708 AL_GAIN, volume);
3709 if((error = alGetError()) != AL_NO_ERROR)
3710 {
3711 ALmixer_SetError("%s",
3712 alGetString(error) );
3713 retval = AL_FALSE;
3714 }
3715 }
3716 }
3717 return retval;
3718 }
3719
3720 static ALboolean Internal_SetVolumeSource(ALuint source, ALfloat volume)
3721 {
3722 ALint channel;
3723 if(0 == source)
3724 {
3725 return Internal_SetVolumeChannel(-1, volume);
3726 }
3727
3728 channel = Internal_GetChannel(source);
3729 if(-1 == channel)
3730 {
3731 ALmixer_SetError("Cannot SetMaxVolume: %s", ALmixer_GetError());
3732 return AL_FALSE;
3733 }
3734 return Internal_SetVolumeChannel(channel, volume);
3735 }
3736
3737
3738 static ALfloat Internal_GetVolumeChannel(ALint channel)
3739 {
3740 ALfloat value;
3741 ALenum error;
3742 ALfloat running_total = 0.0f;
3743 ALfloat retval = 0.0f;
3744
3745 if(channel >= Number_of_Channels_global)
3746 {
3747 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
3748 return -1.0f;
3749 }
3750
3751 if(channel >= 0)
3752 {
3753 alGetSourcef(ALmixer_Channel_List[channel].alsource,
3754 AL_GAIN, &value);
3755 if((error = alGetError()) != AL_NO_ERROR)
3756 {
3757 ALmixer_SetError("%s", alGetString(error) );
3758 retval = -1.0f;
3759 }
3760 else
3761 {
3762 retval = value;
3763 }
3764 }
3765 else
3766 {
3767 ALint i;
3768 for(i=0; i<Number_of_Channels_global; i++)
3769 {
3770 alGetSourcef(ALmixer_Channel_List[i].alsource,
3771 AL_GAIN, &value);
3772 if((error = alGetError()) != AL_NO_ERROR)
3773 {
3774 ALmixer_SetError("%s", alGetString(error) );
3775 retval = -1;
3776 }
3777 else
3778 {
3779 running_total += value;
3780 }
3781 }
3782 if(0 == Number_of_Channels_global)
3783 {
3784 ALmixer_SetError("No channels are allocated");
3785 retval = -1.0f;
3786 }
3787 else
3788 {
3789 retval = running_total / Number_of_Channels_global;
3790 }
3791 }
3792 return retval;
3793 }
3794
3795 static ALfloat Internal_GetVolumeSource(ALuint source)
3796 {
3797 ALint channel;
3798 if(0 == source)
3799 {
3800 return Internal_GetVolumeChannel(-1);
3801 }
3802
3803 channel = Internal_GetChannel(source);
3804 if(-1 == channel)
3805 {
3806 ALmixer_SetError("Cannot GetVolume: %s", ALmixer_GetError());
3807 return -1.0f;
3808 }
3809
3810 return Internal_GetVolumeChannel(channel);
3811 }
3812
3813
3814
3815 /* Set a volume regardless if it's in use or not.
3816 */
3817 static ALboolean Internal_SetMaxVolumeChannel(ALint channel, ALfloat volume)
3818 {
3819 ALenum error;
3820 ALboolean retval = AL_TRUE;
3821
3822 if(channel >= Number_of_Channels_global)
3823 {
3824 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
3825 return AL_FALSE;
3826 }
3827
3828 if(channel >= 0)
3829 {
3830 if(volume < 0.0f)
3831 {
3832 volume = 0.0f;
3833 }
3834 else if(volume > 1.0f)
3835 {
3836 volume = 1.0f;
3837 }
3838 ALmixer_Channel_List[channel].max_volume = volume;
3839 alSourcef(ALmixer_Channel_List[channel].alsource,
3840 AL_MAX_GAIN, volume);
3841 if((error = alGetError()) != AL_NO_ERROR)
3842 {
3843 ALmixer_SetError("%s",
3844 alGetString(error) );
3845 retval = AL_FALSE;
3846 }
3847 if(ALmixer_Channel_List[channel].max_volume < ALmixer_Channel_List[channel].min_volume)
3848 {
3849 ALmixer_Channel_List[channel].min_volume = volume;
3850 alSourcef(ALmixer_Channel_List[channel].alsource,
3851 AL_MIN_GAIN, volume);
3852 if((error = alGetError()) != AL_NO_ERROR)
3853 {
3854 ALmixer_SetError("%s",
3855 alGetString(error) );
3856 retval = AL_FALSE;
3857 }
3858 }
3859 }
3860 else
3861 {
3862 ALint i;
3863 for(i=0; i<Number_of_Channels_global; i++)
3864 {
3865 if(volume < 0.0f)
3866 {
3867 volume = 0.0f;
3868 }
3869 else if(volume > 1.0f)
3870 {
3871 volume = 1.0f;
3872 }
3873 ALmixer_Channel_List[i].max_volume = volume;
3874 alSourcef(ALmixer_Channel_List[i].alsource,
3875 AL_MAX_GAIN, volume);
3876 if((error = alGetError()) != AL_NO_ERROR)
3877 {
3878 ALmixer_SetError("%s",
3879 alGetString(error) );
3880 retval = AL_FALSE;
3881 }
3882 if(ALmixer_Channel_List[i].max_volume < ALmixer_Channel_List[i].min_volume)
3883 {
3884 ALmixer_Channel_List[i].min_volume = volume;
3885 alSourcef(ALmixer_Channel_List[i].alsource,
3886 AL_MIN_GAIN, volume);
3887 if((error = alGetError()) != AL_NO_ERROR)
3888 {
3889 ALmixer_SetError("%s",
3890 alGetString(error) );
3891 retval = AL_FALSE;
3892 }
3893 }
3894 }
3895 }
3896 return retval;
3897 }
3898
3899 static ALint Internal_SetMaxVolumeSource(ALuint source, ALfloat volume)
3900 {
3901 ALint channel;
3902 if(0 == source)
3903 {
3904 return Internal_SetMaxVolumeChannel(-1, volume);
3905 }
3906
3907 channel = Internal_GetChannel(source);
3908 if(-1 == channel)
3909 {
3910 ALmixer_SetError("Cannot SetMaxVolume: %s", ALmixer_GetError());
3911 return AL_FALSE;
3912 }
3913 return Internal_SetMaxVolumeChannel(channel, volume);
3914 }
3915
3916 static ALfloat Internal_GetMaxVolumeChannel(ALint channel)
3917 {
3918 /*
3919 ALfloat value;
3920 ALenum error;
3921 */
3922 ALfloat running_total = 0.0f;
3923 ALfloat retval = 0.0f;
3924
3925 if(channel >= Number_of_Channels_global)
3926 {
3927 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
3928 return -1.0f;
3929 }
3930
3931 if(channel >= 0)
3932 {
3933 /*
3934 alGetSourcef(ALmixer_Channel_List[channel].alsource,
3935 AL_GAIN, &value);
3936 if((error = alGetError()) != AL_NO_ERROR)
3937 {
3938 ALmixer_SetError("%s",
3939 alGetString(error) );
3940 retval = -1.0f;
3941 }
3942 else
3943 {
3944 retval = value;
3945 }
3946 */
3947 retval = ALmixer_Channel_List[channel].max_volume;
3948
3949 }
3950 else
3951 {
3952 ALint i;
3953 for(i=0; i<Number_of_Channels_global; i++)
3954 {
3955 /*
3956 alGetSourcef(ALmixer_Channel_List[i].alsource,
3957 AL_GAIN, &value);
3958 if((error = alGetError()) != AL_NO_ERROR)
3959 {
3960 ALmixer_SetError("%s",
3961 alGetString(error) );
3962 retval = -1;
3963 }
3964 else
3965 {
3966 running_total += value;
3967 }
3968 */
3969 running_total += ALmixer_Channel_List[i].max_volume;
3970 }
3971 if(0 == Number_of_Channels_global)
3972 {
3973 ALmixer_SetError("No channels are allocated");
3974 retval = -1.0f;
3975 }
3976 else
3977 {
3978 retval = running_total / Number_of_Channels_global;
3979 }
3980 }
3981 return retval;
3982 }
3983
3984 static ALfloat Internal_GetMaxVolumeSource(ALuint source)
3985 {
3986 ALint channel;
3987 if(0 == source)
3988 {
3989 return Internal_GetMaxVolumeChannel(-1);
3990 }
3991
3992 channel = Internal_GetChannel(source);
3993 if(-1 == channel)
3994 {
3995 ALmixer_SetError("Cannot GetVolume: %s", ALmixer_GetError());
3996 return -1.0f;
3997 }
3998
3999 return Internal_GetMaxVolumeChannel(channel);
4000 }
4001
4002
4003 /* Set a volume regardless if it's in use or not.
4004 */
4005 static ALboolean Internal_SetMinVolumeChannel(ALint channel, ALfloat volume)
4006 {
4007 ALenum error;
4008 ALboolean retval = AL_TRUE;
4009
4010 if(channel >= Number_of_Channels_global)
4011 {
4012 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
4013 return AL_FALSE;
4014 }
4015
4016 if(channel >= 0)
4017 {
4018 if(volume < 0.0f)
4019 {
4020 volume = 0.0f;
4021 }
4022 else if(volume > 1.0f)
4023 {
4024 volume = 1.0f;
4025 }
4026 ALmixer_Channel_List[channel].min_volume = volume;
4027 alSourcef(ALmixer_Channel_List[channel].alsource,
4028 AL_MIN_GAIN, volume);
4029 if((error = alGetError()) != AL_NO_ERROR)
4030 {
4031 ALmixer_SetError("%s",
4032 alGetString(error) );
4033 retval = AL_FALSE;
4034 }
4035 if(ALmixer_Channel_List[channel].max_volume < ALmixer_Channel_List[channel].min_volume)
4036 {
4037 ALmixer_Channel_List[channel].max_volume = volume;
4038 alSourcef(ALmixer_Channel_List[channel].alsource,
4039 AL_MAX_GAIN, volume);
4040 if((error = alGetError()) != AL_NO_ERROR)
4041 {
4042 ALmixer_SetError("%s",
4043 alGetString(error) );
4044 retval = AL_FALSE;
4045 }
4046 }
4047 }
4048 else
4049 {
4050 ALint i;
4051 for(i=0; i<Number_of_Channels_global; i++)
4052 {
4053 if(volume < 0.0f)
4054 {
4055 volume = 0.0f;
4056 }
4057 else if(volume > 1.0f)
4058 {
4059 volume = 1.0f;
4060 }
4061 ALmixer_Channel_List[i].min_volume = volume;
4062 alSourcef(ALmixer_Channel_List[i].alsource,
4063 AL_MIN_GAIN, volume);
4064 if((error = alGetError()) != AL_NO_ERROR)
4065 {
4066 ALmixer_SetError("%s",
4067 alGetString(error) );
4068 retval = AL_FALSE;
4069 }
4070 if(ALmixer_Channel_List[i].max_volume < ALmixer_Channel_List[i].min_volume)
4071 {
4072 ALmixer_Channel_List[i].max_volume = volume;
4073 alSourcef(ALmixer_Channel_List[i].alsource,
4074 AL_MAX_GAIN, volume);
4075 if((error = alGetError()) != AL_NO_ERROR)
4076 {
4077 ALmixer_SetError("%s",
4078 alGetString(error) );
4079 retval = AL_FALSE;
4080 }
4081 }
4082 }
4083 }
4084 return retval;
4085 }
4086
4087 static ALboolean Internal_SetMinVolumeSource(ALuint source, ALfloat volume)
4088 {
4089 ALint channel;
4090 if(0 == source)
4091 {
4092 return Internal_SetMinVolumeChannel(-1, volume);
4093 }
4094
4095 channel = Internal_GetChannel(source);
4096 if(-1 == channel)
4097 {
4098 ALmixer_SetError("Cannot SetMaxVolume: %s", ALmixer_GetError());
4099 return AL_FALSE;
4100 }
4101 return Internal_SetMinVolumeChannel(channel, volume);
4102 }
4103
4104 static ALfloat Internal_GetMinVolumeChannel(ALint channel)
4105 {
4106 /*
4107 ALfloat value;
4108 ALenum error;
4109 */
4110 ALfloat running_total = 0.0f;
4111 ALfloat retval = 0.0f;
4112
4113 if(channel >= Number_of_Channels_global)
4114 {
4115 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
4116 return -1.0f;
4117 }
4118
4119 if(channel >= 0)
4120 {
4121 /*
4122 alGetSourcef(ALmixer_Channel_List[channel].alsource,
4123 AL_GAIN, &value);
4124 if((error = alGetError()) != AL_NO_ERROR)
4125 {
4126 ALmixer_SetError("%s",
4127 alGetString(error) );
4128 retval = -1.0f;
4129 }
4130 else
4131 {
4132 retval = value;
4133 }
4134 */
4135 retval = ALmixer_Channel_List[channel].min_volume;
4136
4137 }
4138 else
4139 {
4140 ALint i;
4141 for(i=0; i<Number_of_Channels_global; i++)
4142 {
4143 /*
4144 alGetSourcef(ALmixer_Channel_List[i].alsource,
4145 AL_GAIN, &value);
4146 if((error = alGetError()) != AL_NO_ERROR)
4147 {
4148 ALmixer_SetError("%s",
4149 alGetString(error) );
4150 retval = -1;
4151 }
4152 else
4153 {
4154 running_total += value;
4155 }
4156 */
4157 running_total += ALmixer_Channel_List[i].min_volume;
4158 }
4159 if(0 == Number_of_Channels_global)
4160 {
4161 ALmixer_SetError("No channels are allocated");
4162 retval = -1.0f;
4163 }
4164 else
4165 {
4166 retval = running_total / Number_of_Channels_global;
4167 }
4168 }
4169 return retval;
4170 }
4171
4172 static ALfloat Internal_GetMinVolumeSource(ALuint source)
4173 {
4174 ALint channel;
4175 if(0 == source)
4176 {
4177 return Internal_GetMinVolumeChannel(-1);
4178 }
4179
4180 channel = Internal_GetChannel(source);
4181 if(-1 == channel)
4182 {
4183 ALmixer_SetError("Cannot GetVolume: %s", ALmixer_GetError());
4184 return -1.0f;
4185 }
4186
4187 return Internal_GetMinVolumeChannel(channel);
4188 }
4189
4190
4191 /* Changes the listener volume */
4192 static ALboolean Internal_SetMasterVolume(ALfloat volume)
4193 {
4194 ALenum error;
4195 alListenerf(AL_GAIN, volume);
4196 if((error = alGetError()) != AL_NO_ERROR)
4197 {
4198 ALmixer_SetError("%s",
4199 alGetString(error) );
4200 return AL_FALSE;
4201 }
4202 return AL_TRUE;
4203 }
4204
4205 static ALfloat Internal_GetMasterVolume()
4206 {
4207 ALenum error;
4208 ALfloat volume;
4209 alGetListenerf(AL_GAIN, &volume);
4210 if((error = alGetError()) != AL_NO_ERROR)
4211 {
4212 ALmixer_SetError("%s",
4213 alGetString(error) );
4214 return -1.0f;
4215 }
4216 return volume;
4217 }
4218
4219
4220
4221
4222 /* Will fade out currently playing channels.
4223 * It starts at the current volume level and goes down */
4224 static ALint Internal_ExpireChannel(ALint channel, ALint ticks)
4225 {
4226 ALuint current_time = ALmixer_GetTicks();
4227 ALuint counter = 0;
4228
4229 /* We can't accept 0 as a value because of div-by-zero.
4230 * If zero, just call Halt at normal
4231 * volume
4232 */
4233 if(0 == ticks)
4234 {
4235 return Internal_HaltChannel(channel, AL_TRUE);
4236 }
4237 if(ticks < -1)
4238 {
4239 ticks = -1;
4240 }
4241
4242
4243 if(channel >= Number_of_Channels_global)
4244 {
4245 ALmixer_SetError("Requested channel (%d) exceeds maximum channel (%d) because only %d channels are allocated", channel, Number_of_Channels_global-1, Number_of_Channels_global);
4246 return -1;
4247 }
4248
4249 if(channel >= 0)
4250 {
4251 if(ALmixer_Channel_List[channel].channel_in_use)
4252 {
4253 /* Set expire start time */
4254 ALmixer_Channel_List[channel].start_time = current_time;
4255 /* Set the expire ticks */
4256 ALmixer_Channel_List[channel].expire_ticks = ticks;
4257
4258 counter++;
4259 }
4260 }
4261 /* Else need to fade out all channels */
4262 else
4263 {
4264 ALint i;
4265 for(i=0; i<Number_of_Channels_global; i++)
4266 {
4267 if(ALmixer_Channel_List[i].channel_in_use)
4268 {
4269 /* Set expire start time */
4270 ALmixer_Channel_List[i].start_time = current_time;
4271 /* Set the expire ticks */
4272 ALmixer_Channel_List[i].expire_ticks = ticks;
4273
4274 counter++;
4275 }
4276 } /* End for loop */
4277 }
4278 return counter;
4279 }
4280
4281
4282 static ALint Internal_ExpireSource(ALuint source, ALint ticks)
4283 {
4284 ALint channel;
4285 if(0 == source)
4286 {
4287 return Internal_ExpireChannel(-1, ticks);
4288 }
4289
4290 channel = Internal_GetChannel(source);
4291 if(-1 == channel)
4292 {
4293 ALmixer_SetError("Cannot Expire source: %s", ALmixer_GetError());
4294 return -1;
4295 }
4296 return Internal_ExpireChannel(channel, ticks);
4297 }
4298
4299
4300 static ALint Internal_QueryChannel(ALint channel)
4301 {
4302 ALint i;
4303 ALint counter = 0;
4304 if(channel >= Number_of_Channels_global)
4305 {
4306 ALmixer_SetError("Invalid channel: %d", channel);
4307 return -1;
4308 }
4309
4310 if(channel >= 0)
4311 {
4312 return ALmixer_Channel_List[channel].channel_in_use;
4313 }
4314
4315 /* Else, return the number of channels in use */
4316 for(i=0; i<Number_of_Channels_global; i++)
4317 {
4318 if(ALmixer_Channel_List[i].channel_in_use)
4319 {
4320 counter++;
4321 }
4322 }
4323 return counter;
4324 }
4325
4326
4327 static ALint Internal_QuerySource(ALuint source)
4328 {
4329 ALint channel;
4330 if(0 == source)
4331 {
4332 return Internal_QueryChannel(-1);
4333 }
4334
4335 channel = Internal_GetChannel(source);
4336 if(-1 == channel)
4337 {
4338 ALmixer_SetError("Cannot query source: %s", ALmixer_GetError());
4339 return -1;
4340 }
4341
4342 return Internal_QueryChannel(channel);
4343 }
4344
4345
4346 static ALuint Internal_CountUnreservedUsedChannels()
4347 {
4348 ALint i;
4349 ALuint counter = 0;
4350
4351
4352 /* Else, return the number of channels in use */
4353 for(i=Number_of_Reserve_Channels_global; i<Number_of_Channels_global; i++)
4354 {
4355 if(ALmixer_Channel_List[i].channel_in_use)
4356 {
4357 counter++;
4358 }
4359 }
4360 return counter;
4361 }
4362
4363 static ALuint Internal_CountUnreservedFreeChannels()
4364 {
4365 ALint i;
4366 ALuint counter = 0;
4367
4368
4369 /* Else, return the number of channels in use */
4370 for(i=Number_of_Reserve_Channels_global; i<Number_of_Channels_global; i++)
4371 {
4372 if( ! ALmixer_Channel_List[i].channel_in_use)
4373 {
4374 counter++;
4375 }
4376 }
4377 return counter;
4378 }
4379
4380 static ALuint Internal_CountAllUsedChannels()
4381 {
4382 ALint i;
4383 ALuint counter = 0;
4384
4385
4386 /* Else, return the number of channels in use */
4387 for(i=0; i<Number_of_Channels_global; i++)
4388 {
4389 if(ALmixer_Channel_List[i].channel_in_use)
4390 {
4391 counter++;
4392 }
4393 }
4394 return counter;
4395 }
4396
4397 static ALuint Internal_CountAllFreeChannels()
4398 {
4399 ALint i;
4400 ALuint counter = 0;
4401
4402
4403 /* Else, return the number of channels in use */
4404 for(i=0; i<Number_of_Channels_global; i++)
4405 {
4406 if( ! ALmixer_Channel_List[i].channel_in_use)
4407 {
4408 counter++;
4409 }
4410 }
4411 return counter;
4412 }
4413
4414
4415 static ALint Internal_PlayingChannel(ALint channel)
4416 {
4417 ALint i;
4418 ALint counter = 0;
4419 ALint state;
4420
4421 if(channel >= Number_of_Channels_global)
4422 {
4423 ALmixer_SetError("Invalid channel: %d", channel);
4424 return -1;
4425 }
4426
4427 if(channel >= 0)
4428 {
4429 if(ALmixer_Channel_List[channel].channel_in_use)
4430 {
4431 alGetSourcei(
4432 ALmixer_Channel_List[channel].alsource,
4433 AL_SOURCE_STATE, &state
4434 );
4435 if(AL_PLAYING == state)
4436 {
4437 return 1;
4438 }
4439 }
4440 return 0;
4441 }
4442
4443 /* Else, return the number of channels in use */
4444 for(i=0; i<Number_of_Channels_global; i++)
4445 {
4446 if(ALmixer_Channel_List[i].channel_in_use)
4447 {
4448 alGetSourcei(
4449 ALmixer_Channel_List[i].alsource,
4450 AL_SOURCE_STATE, &state
4451 );
4452 if(AL_PLAYING == state)
4453 {
4454 counter++;
4455 }
4456 }
4457 }
4458 return counter;
4459 }
4460
4461
4462 static ALint Internal_PlayingSource(ALuint source)
4463 {
4464 ALint channel;
4465 if(0 == source)
4466 {
4467 return Internal_PlayingChannel(-1);
4468 }
4469
4470 channel = Internal_GetChannel(source);
4471 if(-1 == channel)
4472 {
4473 ALmixer_SetError("Cannot query source: %s", ALmixer_GetError());
4474 return -1;
4475 }
4476
4477 return Internal_PlayingChannel(channel);
4478 }
4479
4480
4481 static ALint Internal_PausedChannel(ALint channel)
4482 {
4483 ALint i;
4484 ALint counter = 0;
4485 ALint state;
4486
4487 if(channel >= Number_of_Channels_global)
4488 {
4489 ALmixer_SetError("Invalid channel: %d", channel);
4490 return -1;
4491 }
4492
4493 if(channel >= 0)
4494 {
4495 if(ALmixer_Channel_List[channel].channel_in_use)
4496 {
4497 alGetSourcei(
4498 ALmixer_Channel_List[channel].alsource,
4499 AL_SOURCE_STATE, &state
4500 );
4501 if(AL_PAUSED == state)
4502 {
4503 return 1;
4504 }
4505 }
4506 return 0;
4507 }
4508
4509 /* Else, return the number of channels in use */
4510 for(i=0; i<Number_of_Channels_global; i++)
4511 {
4512 if(ALmixer_Channel_List[i].channel_in_use)
4513 {
4514 alGetSourcei(
4515 ALmixer_Channel_List[i].alsource,
4516 AL_SOURCE_STATE, &state
4517 );
4518 if(AL_PAUSED == state)
4519 {
4520 counter++;
4521 }
4522 }
4523 }
4524 return counter;
4525 }
4526
4527
4528 static ALint Internal_PausedSource(ALuint source)
4529 {
4530 ALint channel;
4531 if(0 == source)
4532 {
4533 return Internal_PausedChannel(-1);
4534 }
4535
4536 channel = Internal_GetChannel(source);
4537 if(-1 == channel)
4538 {
4539 ALmixer_SetError("Cannot query source: %s", ALmixer_GetError());
4540 return -1;
4541 }
4542
4543 return Internal_PausedChannel(channel);
4544 }
4545
4546
4547
4548
4549
4550
4551 /* Private function for Updating ALmixer.
4552 * This is a very big and ugly function.
4553 * It should return the number of buffers that were
4554 * queued during the call. The value might be
4555 * used to guage how long you might wait to
4556 * call the next update loop in case you are worried
4557 * about preserving CPU cycles. The idea is that
4558 * when a buffer is queued, there was probably some
4559 * CPU intensive looping which took awhile.
4560 * It's mainly provided as a convenience.
4561 * Timing the call with ALmixer_GetTicks() would produce
4562 * more accurate information.
4563 * Returns a negative value if there was an error,
4564 * the value being the number of errors.
4565 */
4566 static ALint Update_ALmixer(void* data)
4567 {
4568 ALint retval = 0;
4569 ALint error_flag = 0;
4570 ALenum error;
4571 ALint state;
4572 ALint i=0;
4573
4574 #ifdef ENABLE_ALMIXER_THREADS
4575 SDL_LockMutex(s_simpleLock);
4576 #endif
4577 if(0 == ALmixer_Initialized)
4578 {
4579 #ifdef ENABLE_ALMIXER_THREADS
4580 SDL_UnlockMutex(s_simpleLock);
4581 #endif
4582 return 0;
4583 }
4584
4585 /* Check the quick flag to see if anything needs updating */
4586 /* If anything is playing, then we have to do work */
4587 if( 0 == Is_Playing_global)
4588 {
4589 #ifdef ENABLE_ALMIXER_THREADS
4590 SDL_UnlockMutex(s_simpleLock);
4591 #endif
4592 return 0;
4593 }
4594 /* Clear error */
4595 if((error = alGetError()) != AL_NO_ERROR)
4596 {
4597 fprintf(stderr, "08Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4598 alGetString(error));
4599 }
4600 alGetError();
4601
4602 for(i=0; i<Number_of_Channels_global; i++)
4603 {
4604 if( ALmixer_Channel_List[i].channel_in_use )
4605 {
4606
4607 /* For simplicity, before we do anything else,
4608 * we can check the timeout and fading values
4609 * and do the appropriate things
4610 */
4611 ALuint current_time = ALmixer_GetTicks();
4612
4613 /* Check to see if we need to halt due to Timed play */
4614 if(ALmixer_Channel_List[i].expire_ticks != -1)
4615 {
4616 ALuint target_time = (ALuint)ALmixer_Channel_List[i].expire_ticks
4617 + ALmixer_Channel_List[i].start_time;
4618 alGetSourcei(ALmixer_Channel_List[i].alsource,
4619 AL_SOURCE_STATE, &state);
4620 if((error = alGetError()) != AL_NO_ERROR)
4621 {
4622 fprintf(stderr, "06Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4623 alGetString(error));
4624 }
4625
4626 /* Check the time, and also make sure that it is not
4627 * paused (if paused, we don't want to make the
4628 * evaluation because when resumed, we will adjust
4629 * the times to compensate for the pause).
4630 */
4631 if( (current_time >= target_time)
4632 && (state != AL_PAUSED) )
4633 {
4634 /* Stop the playback */
4635 Internal_HaltChannel(i, AL_TRUE);
4636 if((error = alGetError()) != AL_NO_ERROR)
4637 {
4638 fprintf(stderr, "07Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4639 alGetString(error));
4640 }
4641
4642 /* Everything should be done so go on to the next loop */
4643 continue;
4644 }
4645 } /* End if time expired check */
4646
4647 /* Check to see if we need to adjust the volume for fading */
4648 if( ALmixer_Channel_List[i].fade_enabled )
4649 {
4650 ALuint target_time = ALmixer_Channel_List[i].fade_expire_ticks
4651 + ALmixer_Channel_List[i].fade_start_time;
4652 alGetSourcei(ALmixer_Channel_List[i].alsource,
4653 AL_SOURCE_STATE, &state);
4654 if((error = alGetError()) != AL_NO_ERROR)
4655 {
4656 fprintf(stderr, "05Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4657 alGetString(error));
4658 }
4659
4660 /* Check the time, and also make sure that it is not
4661 * paused (if paused, we don't want to make the
4662 * evaluation because when resumed, we will adjust
4663 * the times to compensate for the pause).
4664 */
4665 if(state != AL_PAUSED)
4666 {
4667 ALfloat t;
4668 ALuint delta_time;
4669 ALfloat current_volume;
4670 if(current_time >= target_time)
4671 {
4672 /* Need to constrain value to the end time
4673 * (can't go pass the value for calculations)
4674 */
4675 current_time = target_time;
4676 /* We can disable the fade flag now */
4677 ALmixer_Channel_List[i].fade_enabled = 0;
4678 }
4679 /* Use the linear interpolation formula:
4680 * X = (1-t)x0 + tx1
4681 * where x0 would be the start value
4682 * and x1 is the final value
4683 * and t is delta_time*inv_time (adjusts 0 <= time <= 1)
4684 * delta_time = current_time-start_time
4685 * inv_time = 1/ (end_time-start_time)
4686 * so t = current_time-start_time / (end_time-start_time)
4687 *
4688 */
4689 delta_time = current_time - ALmixer_Channel_List[i].fade_start_time;
4690 t = (ALfloat) delta_time * ALmixer_Channel_List[i].fade_inv_time;
4691
4692 current_volume = (1.0f-t) * ALmixer_Channel_List[i].fade_start_volume
4693 + t * ALmixer_Channel_List[i].fade_end_volume;
4694
4695 /* Set the volume */
4696 alSourcef(ALmixer_Channel_List[i].alsource,
4697 AL_MAX_GAIN, current_volume);
4698 if((error = alGetError()) != AL_NO_ERROR)
4699 {
4700 fprintf(stderr, "04Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4701 alGetString(error));
4702 }
4703
4704 /*
4705 fprintf(stderr, "Current time =%d\n", current_time);
4706 fprintf(stderr, "Current vol=%f on channel %d\n", current_volume, i);
4707 */
4708 } /* End if not PAUSED */
4709 } /* End if fade_enabled */
4710
4711
4712 /* Okay, now that the time expired and fading stuff
4713 * is done, do the rest of the hard stuff
4714 */
4715
4716
4717 /* For predecoded, check to see if done */
4718 if( ALmixer_Channel_List[i].almixer_data->decoded_all )
4719 {
4720
4721 #if 0
4722 /********* Remove this **********/
4723 ALint buffers_processed;
4724 ALint buffers_still_queued;
4725 fprintf(stderr, "For Predecoded\n");
4726
4727 alGetSourcei(
4728 ALmixer_Channel_List[i].alsource,
4729 AL_SOURCE_STATE, &state
4730 );
4731 switch(state) {
4732 case AL_PLAYING:
4733 fprintf(stderr, "Channel '%d' is PLAYING\n", i);
4734 break;
4735 case AL_PAUSED:
4736 fprintf(stderr, "Channel '%d' is PAUSED\n",i);
4737 break;
4738 case AL_STOPPED:
4739 fprintf(stderr, "Channel '%d' is STOPPED\n",i);
4740 break;
4741 case AL_INITIAL:
4742 fprintf(stderr, "Channel '%d' is INITIAL\n",i);
4743 break;
4744 default:
4745 fprintf(stderr, "Channel '%d' is UNKNOWN\n",i);
4746 break;
4747 }
4748
4749 alGetSourcei(
4750 ALmixer_Channel_List[i].alsource,
4751 AL_BUFFERS_PROCESSED, &buffers_processed
4752 );
4753 fprintf(stderr, "Buffers processed = %d\n", buffers_processed);
4754
4755 alGetSourcei(
4756 ALmixer_Channel_List[i].alsource,
4757 AL_BUFFERS_QUEUED, &buffers_still_queued
4758 );
4759
4760 /******** END REMOVE *******/
4761 #endif
4762 /* FIXME: Ugh! Somewhere an alError is being thrown ("Invalid Enum Value"), but I can't
4763 * find it. It only seems to be thrown for OS X. I placed error messages after every al*
4764 * command I could find in the above loops, but the error doesn't seem to show
4765 * up until around here. I mistook it for a get queued buffers
4766 * error in OS X. I don't think there's an error down there.
4767 * For now, I'm clearing the error here.
4768 */
4769
4770 if((error = alGetError()) != AL_NO_ERROR)
4771 {
4772 fprintf(stderr, "03Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4773 alGetString(error));
4774 }
4775
4776
4777 alGetSourcei(
4778 ALmixer_Channel_List[i].alsource,
4779 AL_SOURCE_STATE, &state
4780 );
4781 if((error = alGetError()) != AL_NO_ERROR)
4782 {
4783 fprintf(stderr, "02Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4784 alGetString(error));
4785 }
4786
4787
4788 if(AL_STOPPED == state)
4789 {
4790 /* Playback has ended.
4791 * Loop if necessary, or launch callback
4792 * and clear channel (or clear channel and
4793 * then launch callback?)
4794 */
4795
4796
4797 /* Need to check for loops */
4798 if(ALmixer_Channel_List[i].loops != 0)
4799 {
4800 /* Corner Case: If the buffer has
4801 * been modified using Seek,
4802 * the loop will start at the seek
4803 * position.
4804 */
4805 if(ALmixer_Channel_List[i].loops != -1)
4806 {
4807 ALmixer_Channel_List[i].loops--;
4808 }
4809 alSourcePlay(ALmixer_Channel_List[i].alsource);
4810 if((error = alGetError()) != AL_NO_ERROR)
4811 {
4812 fprintf(stderr, "50Testing error: %s\n",
4813 alGetString(error));
4814 }
4815 continue;
4816 }
4817 /* No loops. End play. */
4818 else
4819 {
4820 /* Problem: It seems that when mixing
4821 * streamed and predecoded sources,
4822 * the previous instance lingers,
4823 * so we need to force remove
4824 * the data from the source.
4825 * The sharing problem
4826 * occurs when a previous predecoded buffer is played on
4827 * a source, and then a streamed source is played later
4828 * on that same source. OpenAL isn't consistently
4829 * removing the previous buffer so both get played.
4830 * (Different dists seem to have different quirks.
4831 * The problem might lead to crashes in the worst case.)
4832 */
4833 /* Additional problem: There is another
4834 * inconsistency among OpenAL distributions.
4835 * Both Loki and Creative Windows seem to keep
4836 * the buffer queued which requires removing.
4837 * But the Creative Macintosh version does
4838 * not have any buffer queued after play
4839 * and it returns the error: Invalid Enum Value
4840 * if I try to unqueue it.
4841 * So I'm going to put in a check to see if I
4842 * can detect any buffers queued first
4843 * and then unqueue them if I can see them.
4844 * Additional note: The new CoreAudio based
4845 * implementation leaves it's buffer queued
4846 * like Loki and Creative Windows. But
4847 * considering all the problems I'm having
4848 * with the different distributions, this
4849 * check seems reasonable.
4850 */
4851 ALint buffers_still_queued;
4852 if((error = alGetError()) != AL_NO_ERROR)
4853 {
4854 fprintf(stderr, "01Testing errpr before unqueue because getting stuff, for OS X this is expected: %s\n",
4855 alGetString(error));
4856 }
4857
4858 alGetSourcei(
4859 ALmixer_Channel_List[i].alsource,
4860 AL_BUFFERS_QUEUED, &buffers_still_queued
4861 );
4862 if((error = alGetError()) != AL_NO_ERROR)
4863 {
4864 fprintf(stderr, "Error with unqueue, for OS X this is expected: %s\n",
4865 alGetString(error));
4866 ALmixer_SetError("Failed detecting unqueued predecoded buffer (expected with OS X): %s",
4867 alGetString(error) );
4868 error_flag--;
4869 }
4870 if(buffers_still_queued > 0)
4871 {
4872
4873 #if 0 /* This triggers an error in OS X Core Audio. */
4874 alSourceUnqueueBuffers(
4875 ALmixer_Channel_List[i].alsource,
4876 1,
4877 ALmixer_Channel_List[i].almixer_data->buffer
4878 );
4879 #else
4880 /* fprintf(stderr, "In the Bob Aron section...about to clear source\n");
4881 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
4882 */
4883 /* Rather than force unqueuing the buffer, let's see if
4884 * setting the buffer to none works (the OpenAL 1.0
4885 * Reference Annotation suggests this should work).
4886 */
4887 alSourcei(ALmixer_Channel_List[i].alsource,
4888 AL_BUFFER, AL_NONE);
4889 /*
4890 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
4891 */
4892 #endif
4893 if((error = alGetError()) != AL_NO_ERROR)
4894 {
4895 fprintf(stderr, "Error with unqueue, after alSourceUnqueueBuffers, buffers_still_queued=%d, error is: %s", buffers_still_queued,
4896 alGetString(error));
4897 ALmixer_SetError("Predecoded Unqueue buffer failed: %s",
4898 alGetString(error) );
4899 error_flag--;
4900 }
4901
4902 }
4903
4904 Clean_Channel(i);
4905 /* Subtract counter */
4906 Is_Playing_global--;
4907
4908 /* Launch callback */
4909 Invoke_Channel_Done_Callback(i, AL_TRUE);
4910
4911 /* We're done for this loop.
4912 * Go to next channel
4913 */
4914 continue;
4915 }
4916 continue;
4917 }
4918 } /* End if decoded_all */
4919 /* For streamed */
4920 else
4921 {
4922 ALint buffers_processed;
4923 ALint buffers_still_queued;
4924 ALint current_buffer_id;
4925
4926 ALuint unqueued_buffer_id;
4927 #if 0
4928 /********* Remove this **********/
4929 fprintf(stderr, "For Streamed\n");
4930
4931 alGetSourcei(
4932 ALmixer_Channel_List[i].alsource,
4933 AL_SOURCE_STATE, &state
4934 );
4935 switch(state) {
4936 case AL_PLAYING:
4937 fprintf(stderr, "Channel '%d' is PLAYING\n", i);
4938 break;
4939 case AL_PAUSED:
4940 fprintf(stderr, "Channel '%d' is PAUSED\n",i);
4941 break;
4942 case AL_STOPPED:
4943 fprintf(stderr, "Channel '%d' is STOPPED\n",i);
4944 break;
4945 case AL_INITIAL:
4946 fprintf(stderr, "Channel '%d' is INITIAL\n",i);
4947 break;
4948 default:
4949 fprintf(stderr, "Channel '%d' is UNKNOWN\n",i);
4950 break;
4951 }
4952 /******** END REMOVE *******/
4953 #endif
4954 /* Get the number of buffers still queued */
4955 alGetSourcei(
4956 ALmixer_Channel_List[i].alsource,
4957 AL_BUFFERS_QUEUED, &buffers_still_queued
4958 );
4959 if((error = alGetError()) != AL_NO_ERROR)
4960 {
4961 fprintf(stderr, "51Testing error: %s\n",
4962 alGetString(error));
4963 }
4964 /* Get the number of buffers processed
4965 * so we know if we need to refill
4966 */
4967 /* WARNING: It looks like Snow Leopard some times crashes on this call under x86_64
4968 * typically when I suffer a lot of buffer underruns.
4969 */
4970 // fprintf(stderr, "calling AL_BUFFERS_PROCESSED on source:%d", ALmixer_Channel_List[i].alsource);
4971 alGetSourcei(
4972 ALmixer_Channel_List[i].alsource,
4973 AL_BUFFERS_PROCESSED, &buffers_processed
4974 );
4975 if((error = alGetError()) != AL_NO_ERROR)
4976 {
4977 fprintf(stderr, "52Testing error: %s\n",
4978 alGetString(error));
4979 }
4980 // fprintf(stderr, "finished AL_BUFFERS_PROCESSED, buffers_processed=%d", buffers_processed);
4981
4982 /* WTF!!! The Nvidia distribution is failing on the alGetSourcei(source, AL_BUFFER, buf_id) call.
4983 * I need this call to figure out which buffer OpenAL is currently playing.
4984 * It keeps returning an "Invalid Enum" error.
4985 * This is totally inane! It's a basic query.
4986 * By the spec, this functionality is not explicitly defined so Nvidia refuses to
4987 * fix this behavior, even though all other distributions work fine with this.
4988 * The only workaround for this is for
4989 * a significant rewrite of my code which requires me to
4990 * duplicate the OpenAL queued buffers state with my own
4991 * code and try to derive what the current playing buffer is by indirect observation of
4992 * looking at buffers_processed. But of course this has a ton of downsides since my
4993 * queries do not give me perfect timing of what OpenAL is actually doing and
4994 * the fact that some of the distributions seem to have buffer queuing problems
4995 * with their query results (CoreAudio). This also means a ton of extra code
4996 * on my side. The lack of support of a 1 line call has required me to
4997 * implement yet another entire state machine. <sigh>
4998 */
4999 #if 0 /* This code will not work until possibly OpenAL 1.1 because of Nvidia */
5000 /* Get the id to the current buffer playing */
5001 alGetSourcei(
5002 ALmixer_Channel_List[i].alsource,
5003 AL_BUFFER, &current_buffer_id
5004 );
5005 if((error = alGetError()) != AL_NO_ERROR)
5006 {
5007 fprintf(stderr, "53Testing error: %s\n",
5008 alGetString(error));
5009 }
5010
5011 /* Before the hard stuff, check to see if the
5012 * current queued AL buffer has changed.
5013 * If it has, we should launch a data callback if
5014 * necessary
5015 */
5016 if( ((ALuint)current_buffer_id) !=
5017 ALmixer_Channel_List[i].almixer_data->current_buffer)
5018 {
5019 ALmixer_Channel_List[i].almixer_data->current_buffer
5020 = (ALuint)current_buffer_id;
5021
5022 Invoke_Streamed_Channel_Data_Callback(i, ALmixer_Channel_List[i].almixer_data, current_buffer_id);
5023 }
5024 #else
5025 /* Only do this if "access_data" was requested (i.e. the circular_buffer!=NULL)
5026 * And if one of the two are true:
5027 * Either buffers_processed > 0 (because the current_buffer might have changed)
5028 * or if the current_buffer==0 (because we are in an initial state or recovering from
5029 * a buffer underrun)
5030 */
5031 if((ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5032 && (
5033 (buffers_processed > 0) || (0 == ALmixer_Channel_List[i].almixer_data->current_buffer)
5034 )
5035 )
5036 {
5037 ALint k;
5038 ALuint queue_ret_flag;
5039 ALubyte is_out_of_sync = 0;
5040 ALuint my_queue_size = CircularQueueUnsignedInt_Size(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5041 /* Ugh, I have to deal with signed/unsigned mismatch here. */
5042 ALint buffers_unplayed_int = buffers_still_queued - buffers_processed;
5043 ALuint unplayed_buffers;
5044 if(buffers_unplayed_int < 0)
5045 {
5046 unplayed_buffers = 0;
5047 }
5048 else
5049 {
5050 unplayed_buffers = (ALuint)buffers_unplayed_int;
5051 }
5052 /*
5053 fprintf(stderr, "Queue in processed check, before pop, buffers_processed=%d\n", buffers_processed);
5054 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5055 */
5056 /* We can't make any determinations solely based on the number of buffers_processed
5057 * because currently, we only unqueue 1 buffer per loop. That means if 2 or more
5058 * buffers became processed in one loop, the following loop, we would have
5059 * at least that_many-1 buffers_processed (plus possible new processed).
5060 * If we tried to just remove 1 buffer from our queue, we would be incorrect
5061 * because we would not actually reflect the current playing buffer.
5062 * So the solution seems to be to make sure our queue is the same size
5063 * as the number of buffers_queued-buffers_processed, and return the head of our queue
5064 * as the current playing buffer.
5065 */
5066 /* Also, we have a corner case. When we first start playing or if we have
5067 * a buffer underrun, we have not done a data callback.
5068 * In this case, we need to see if there is any new data in our queue
5069 * and if so, launch that data callback.
5070 */
5071 /* Warning, this code risks the possibility of no data callback being fired if
5072 * the system is really late (or skipped buffers).
5073 */
5074
5075 /* First, let's syncronize our queue with the OpenAL queue */
5076 #if 0
5077 fprintf(stderr, "inside, Buffers processed=%d, Buffers queued=%d, my queue=%d\n",
5078 buffers_processed, buffers_still_queued, my_queue_size);
5079 #endif
5080 is_out_of_sync = 1;
5081 for(k=0; k<buffers_processed; k++)
5082 {
5083 queue_ret_flag = CircularQueueUnsignedInt_PopFront(
5084 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5085 if(0 == queue_ret_flag)
5086 {
5087 fprintf(stderr, "53 Error popping queue\n");
5088 }
5089 }
5090 my_queue_size = CircularQueueUnsignedInt_Size(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5091 /* We have several possibilities we need to handle:
5092 * 1) We are in an initial state or underrun and need to do a data callback on the head.
5093 * 2) We were out of sync and need to do a new data callback on the new head.
5094 * 3) We were not out of sync but just had left over processed buffers which caused us to
5095 * fall in this block of code. (Don't do anything.)
5096 */
5097 if( (0 == ALmixer_Channel_List[i].almixer_data->current_buffer) || (1 == is_out_of_sync) )
5098 {
5099 if(my_queue_size > 0)
5100 {
5101 current_buffer_id = CircularQueueUnsignedInt_Front(
5102 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5103 if(0 == current_buffer_id)
5104 {
5105 fprintf(stderr, "53a Internal Error, current_buffer_id=0 when it shouldn't be 0\n");
5106 }
5107 /*
5108 else
5109 {
5110 fprintf(stderr, "Queue in processed check, after pop\n");
5111 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5112 }
5113 */
5114 ALmixer_Channel_List[i].almixer_data->current_buffer
5115 = (ALuint)current_buffer_id;
5116
5117 #if 0
5118 /* Remove me...only for checking...doesn't work on Nvidia */
5119 {
5120 ALuint real_id;
5121 alGetSourcei(
5122 ALmixer_Channel_List[i].alsource,
5123 AL_BUFFER, &real_id
5124 );
5125 alGetError();
5126 fprintf(stderr, "Callback fired on data buffer=%d, real_id shoud be=%d\n", current_buffer_id, real_id);
5127 }
5128 #endif
5129 Invoke_Streamed_Channel_Data_Callback(i, ALmixer_Channel_List[i].almixer_data, current_buffer_id);
5130 }
5131 else
5132 {
5133 /*
5134 fprintf(stderr, "53b, Notice/Warning:, OpenAL queue has been depleted.\n");
5135 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5136 */
5137 /* In this case, we might either be in an underrun or finished with playback */
5138 ALmixer_Channel_List[i].almixer_data->current_buffer = 0;
5139 }
5140 }
5141 }
5142 #endif
5143
5144
5145
5146 /* Just a test - remove
5147 if( ALmixer_Channel_List[i].loops > 0)
5148 {
5149 fprintf(stderr, ">>>>>>>>>>>>>>>Loops = %d\n",
5150 ALmixer_Channel_List[i].loops);
5151 }
5152 */
5153 #if 0
5154 fprintf(stderr, "Buffers processed = %d\n", buffers_processed);
5155 fprintf(stderr, "Buffers queued= %d\n", buffers_still_queued);
5156 #endif
5157 /* We've used up a buffer so we need to unqueue and replace */
5158 /* Okay, it gets more complicated here:
5159 * We need to Queue more data
5160 * if buffers_processed > 0 or
5161 * if num_of_buffers_in_use < NUMBER_OF_QUEUE_BUFFERS
5162 * but we don't do this if at EOF,
5163 * except when there is looping
5164 */
5165 /* For this to work, we must rely on EVERYTHING
5166 * else to unset the EOF if there is looping.
5167 * Remember, even Play() must do this
5168 */
5169
5170 /* If not EOF, then we are still playing.
5171 * Inside, we might find num_of_buffers < NUM...QUEUE_BUF..
5172 * or buffers_process > 0
5173 * in which case we queue up.
5174 * We also might find no buffers we need to fill,
5175 * in which case we just keep going
5176 */
5177 if( ! ALmixer_Channel_List[i].almixer_data->eof)
5178 {
5179 ALuint bytes_returned;
5180 /* We have a priority. We first must assign
5181 * unused buffers in reserve. If there is nothing
5182 * left, then we may unqueue buffers. We can't
5183 * do it the other way around because we will
5184 * lose the pointer to the unqueued buffer
5185 */
5186 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5187 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5188 {
5189 #if 0
5190 fprintf(stderr, "Getting more data in NOT_EOF and num_buffers_in_use (%d) < max_queue (%d)\n",
5191 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use,
5192 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5193 #endif
5194 /* Going to add an unused packet.
5195 * Grab next packet */
5196 bytes_returned = GetMoreData(
5197 ALmixer_Channel_List[i].almixer_data,
5198 ALmixer_Channel_List[i].almixer_data->buffer[
5199 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5200 );
5201 }
5202 /* For processed > 0 */
5203 else if(buffers_processed > 0)
5204 {
5205 /* Unqueue only 1 buffer for now.
5206 * If there are more than one,
5207 * let the next Update pass deal with it
5208 * so we don't stall the program for too long.
5209 */
5210 #if 0
5211 fprintf(stderr, "About to Unqueue, Buffers processed = %d\n", buffers_processed);
5212 fprintf(stderr, "Buffers queued= %d\n", buffers_still_queued);
5213 fprintf(stderr, "Unqueuing a buffer\n");
5214 #endif
5215 alSourceUnqueueBuffers(
5216 ALmixer_Channel_List[i].alsource,
5217 1, &unqueued_buffer_id
5218 );
5219 if((error = alGetError()) != AL_NO_ERROR)
5220 {
5221 fprintf(stderr, "Error with unqueue: %s",
5222 alGetString(error));
5223 ALmixer_SetError("Unqueue buffer failed: %s",
5224 alGetString(error) );
5225 error_flag--;
5226 }
5227 /*
5228 fprintf(stderr, "Right after unqueue...");
5229 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5230 fprintf(stderr, "Getting more data for NOT_EOF, max_buffers filled\n");
5231 */
5232 /* Grab unqueued packet */
5233 bytes_returned = GetMoreData(
5234 ALmixer_Channel_List[i].almixer_data,
5235 unqueued_buffer_id);
5236 }
5237 /* We are still streaming, but currently
5238 * don't need to fill any buffers */
5239 else
5240 {
5241 /* Might want to check state */
5242 /* In case the playback stopped,
5243 * we need to resume
5244 * a.k.a. buffer underrun
5245 */
5246 #if 1
5247 /* Try not refetching the state here because I'm getting a duplicate
5248 buffer playback (hiccup) */
5249 alGetSourcei(
5250 ALmixer_Channel_List[i].alsource,
5251 AL_SOURCE_STATE, &state
5252 );
5253 if((error = alGetError()) != AL_NO_ERROR)
5254 {
5255 fprintf(stderr, "54bTesting error: %s\n",
5256 alGetString(error));
5257 }
5258 /* Get the number of buffers processed
5259 */
5260 alGetSourcei(
5261 ALmixer_Channel_List[i].alsource,
5262 AL_BUFFERS_PROCESSED,
5263 &buffers_processed
5264 );
5265 if((error = alGetError()) != AL_NO_ERROR)
5266 {
5267 fprintf(stderr, "54cError, Can't get buffers_processed: %s\n",
5268 alGetString(error));
5269 }
5270 #endif
5271 if(AL_STOPPED == state)
5272 {
5273 /* Resuming in not eof, but nothing to buffer */
5274
5275 /* Okay, here's another lately discovered problem:
5276 * I can't find it in the spec, but for at least some of the
5277 * implementations, if I call play on a stopped source that
5278 * has processed buffers, all those buffers get marked as unprocessed
5279 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers
5280 * processed, on resume, the earlier 24 buffers will get replayed,
5281 * causing a "hiccup" like sound in the playback.
5282 * To avoid this, I must unqueue all processed buffers before
5283 * calling play. But to complicate things, I need to worry about resyncing
5284 * the circular queue with this since I designed this thing
5285 * with some correlation between the two. However, I might
5286 * have already handled this, so I will try writing this code without
5287 * syncing for now.
5288 * There is currently an assumption that a buffer
5289 * was queued above so I actually have something
5290 * to play.
5291 */
5292 ALint temp_count;
5293 #if 0
5294 fprintf(stderr, "STOPPED1, need to clear processed=%d, status is:\n", buffers_processed);
5295 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5296 #endif
5297 for(temp_count=0; temp_count<buffers_processed; temp_count++)
5298 {
5299 alSourceUnqueueBuffers(
5300 ALmixer_Channel_List[i].alsource,
5301 1, &unqueued_buffer_id
5302 );
5303 if((error = alGetError()) != AL_NO_ERROR)
5304 {
5305 fprintf(stderr, "55aTesting error: %s\n",
5306 alGetString(error));
5307 error_flag--;
5308 }
5309 }
5310 #if 0
5311 fprintf(stderr, "After unqueue clear...:\n");
5312 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5313 #endif
5314 /* My assertion: We are STOPPED but not EOF.
5315 * This means we have a buffer underrun.
5316 * We just cleared out the unqueued buffers.
5317 * So we need to reset the mixer_data to reflect we have
5318 * no buffers in queue.
5319 * We need to GetMoreData and then queue up the data.
5320 * Then we need to resume playing.
5321 */
5322 #if 0
5323 int buffers_queued;
5324 alGetSourcei(
5325 ALmixer_Channel_List[i].alsource,
5326 AL_BUFFERS_QUEUED,
5327 &buffers_queued
5328 );
5329
5330 if((error = alGetError()) != AL_NO_ERROR)
5331 {
5332 fprintf(stderr, "Error in PrintQueueStatus, Can't get buffers_queued: %s\n",
5333 alGetString(error));
5334 }
5335 assert(buffers_queued == 0);
5336 fprintf(stderr, "buffer underrun: buffers_queued:%d\n", buffers_queued);
5337 #endif
5338
5339 /* Reset the number of buffers in use to 0 */
5340 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0;
5341
5342 /* Get more data and put it in the first buffer */
5343 bytes_returned = GetMoreData(
5344 ALmixer_Channel_List[i].almixer_data,
5345 ALmixer_Channel_List[i].almixer_data->buffer[0]
5346 );
5347 /* NOTE: We might want to look for EOF and handle it here.
5348 * Currently, I just let the next loop handle it which seems to be working.
5349 */
5350 if(bytes_returned > 0)
5351 {
5352 /* Queue up the new data */
5353 alSourceQueueBuffers(
5354 ALmixer_Channel_List[i].alsource,
5355 1,
5356 &ALmixer_Channel_List[i].almixer_data->buffer[0]
5357 );
5358 if((error = alGetError()) != AL_NO_ERROR)
5359 {
5360 fprintf(stderr, "56e alSourceQueueBuffers error: %s\n",
5361 alGetString(error));
5362 }
5363 /* Increment the number of buffers in use */
5364 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++;
5365
5366
5367 /* We need to empty and update the circular buffer queue if it is in use */
5368 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5369 {
5370 ALuint queue_ret_flag;
5371 CircularQueueUnsignedInt_Clear(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5372 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5373 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5374 ALmixer_Channel_List[i].almixer_data->buffer[0]
5375 );
5376 if(0 == queue_ret_flag)
5377 {
5378 fprintf(stderr, "56fSerious internal error: CircularQueue could not push into queue.\n");
5379 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5380 }
5381 }
5382
5383
5384
5385
5386 /* Resume playback from underrun */
5387 alSourcePlay(ALmixer_Channel_List[i].alsource);
5388 if((error = alGetError()) != AL_NO_ERROR)
5389 {
5390 fprintf(stderr, "55Tbesting error: %s\n",
5391 alGetString(error));
5392 }
5393 }
5394
5395 }
5396 /* Let's escape to the next loop.
5397 * All code below this point is for queuing up
5398 */
5399 /*
5400 fprintf(stderr, "Entry: Nothing to do...continue\n\n");
5401 */
5402 continue;
5403 }
5404 /* We now know we have to fill an available
5405 * buffer.
5406 */
5407
5408 /* In the previous branch, we just grabbed more data.
5409 * Let's check it to make sure it's okay,
5410 * and then queue it up
5411 */
5412 /* This check doesn't work anymore because it is now ALuint */
5413 #if 0
5414 if(-1 == bytes_returned)
5415 {
5416 /* Problem occurred...not sure what to do */
5417 /* Go to next loop? */
5418 error_flag--;
5419 /* Set the eof flag to force a quit so
5420 * we don't get stuck in an infinite loop
5421 */
5422 ALmixer_Channel_List[i].almixer_data->eof = 1;
5423 continue;
5424 }
5425 #endif
5426 /* This is a special case where we've run
5427 * out of data. We should check for loops
5428 * and get more data. If there is no loop,
5429 * then do nothing and wait for future
5430 * update passes to handle the EOF.
5431 * The advantage of handling the loop here
5432 * instead of waiting for play to stop is
5433 * that we should be able to keep the buffer
5434 * filled.
5435 */
5436 #if 0
5437 else if(0 == bytes_returned)
5438 #endif
5439 if(0 == bytes_returned)
5440 {
5441 fprintf(stderr, "We got 0 bytes from reading. Checking for loops\n");
5442 /* Check for loops */
5443 if( ALmixer_Channel_List[i].loops != 0 )
5444 {
5445 /* We have to loop, so rewind
5446 * and fetch more data
5447 */
5448 fprintf(stderr, "Rewinding data\n");
5449 if(0 == Sound_Rewind(
5450 ALmixer_Channel_List[i].almixer_data->sample))
5451 {
5452 fprintf(stderr, "Rewinding failed\n");
5453 ALmixer_SetError( Sound_GetError() );
5454 ALmixer_Channel_List[i].loops = 0;
5455 error_flag--;
5456 /* We'll continue on because we do have some valid data */
5457 continue;
5458 }
5459 /* Remember to reset the data->eof flag */
5460 ALmixer_Channel_List[i].almixer_data->eof = 0;
5461 if(ALmixer_Channel_List[i].loops > 0)
5462 {
5463 ALmixer_Channel_List[i].loops--;
5464 }
5465 /* Try grabbing another packet now.
5466 * Since we may have already unqueued a
5467 * buffer, we don't want to lose it.
5468 */
5469 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5470 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5471 {
5472 fprintf(stderr, "We got %d bytes from reading loop. Filling unused packet\n", bytes_returned);
5473 /* Grab next packet */
5474 bytes_returned = GetMoreData(
5475 ALmixer_Channel_List[i].almixer_data,
5476 ALmixer_Channel_List[i].almixer_data->buffer[
5477 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5478 );
5479 fprintf(stderr, "We reread %d bytes into unused packet\n", bytes_returned);
5480 }
5481 /* Refilling unqueued packet */
5482 else
5483 {
5484 fprintf(stderr, "We got %d bytes from reading loop. Filling unqueued packet\n", bytes_returned);
5485 /* Grab next packet */
5486 bytes_returned = GetMoreData(
5487 ALmixer_Channel_List[i].almixer_data,
5488 unqueued_buffer_id);
5489 fprintf(stderr, "We reread %d bytes into unqueued packet\n", bytes_returned);
5490 }
5491 /* Another error check */
5492 /*
5493 if(bytes_returned <= 0)
5494 */
5495 if(0 == bytes_returned)
5496 {
5497 fprintf(stderr, "??????????ERROR\n");
5498 ALmixer_SetError("Could not loop because after rewind, no data could be retrieved");
5499 /* Problem occurred...not sure what to do */
5500 /* Go to next loop? */
5501 error_flag--;
5502 /* Set the eof flag to force a quit so
5503 * we don't get stuck in an infinite loop
5504 */
5505 ALmixer_Channel_List[i].almixer_data->eof = 1;
5506 continue;
5507 }
5508 /* We made it to the end. We still need
5509 * to BufferData, so let this branch
5510 * fall into the next piece of
5511 * code below which will handle that
5512 */
5513
5514
5515 } /* END loop check */
5516 else
5517 {
5518 /* No more loops to do.
5519 * EOF flag should be set.
5520 * Just go to next loop and
5521 * let things be handled correctly
5522 * in future update calls
5523 */
5524 /*
5525 fprintf(stderr, "SHOULD BE EOF\n");
5526
5527 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5528 */
5529 continue;
5530 }
5531 } /* END if bytes_returned == 0 */
5532 /********* Possible trouble point. I might be queueing empty buffers on the mac.
5533 * This check doesn't say if the buffer is valid. Only the EOF assumption is a clue at this point
5534 */
5535 /* Fall here */
5536 /* Everything is normal. We aren't
5537 * at an EOF, but need to simply
5538 * queue more data. The data is already checked for good,
5539 * so queue it up */
5540 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5541 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5542 {
5543 /* Keep count of how many buffers we have
5544 * to queue so we can return the value
5545 */
5546 retval++;
5547 /*
5548 fprintf(stderr, "NOT_EOF???, about to Queue more data for num_buffers (%d) < max_queue (%d)\n",
5549 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use,
5550 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5551 */
5552 alSourceQueueBuffers(
5553 ALmixer_Channel_List[i].alsource,
5554 1,
5555 &ALmixer_Channel_List[i].almixer_data->buffer[
5556 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5557 );
5558 if((error = alGetError()) != AL_NO_ERROR)
5559 {
5560 fprintf(stderr, "56Testing error: %s\n",
5561 alGetString(error));
5562 }
5563 /* This is part of the hideous Nvidia workaround. In order to figure out
5564 * which buffer to show during callbacks (for things like
5565 * o-scopes), I must keep a copy of the buffers that are queued in my own
5566 * data structure. This code will be called only if
5567 * "access_data" was set, indicated by whether the queue is NULL.
5568 */
5569 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5570 {
5571 ALuint queue_ret_flag;
5572 // fprintf(stderr, "56d: CircularQueue_PushBack.\n");
5573 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5574 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5575 ALmixer_Channel_List[i].almixer_data->buffer[ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5576 );
5577 if(0 == queue_ret_flag)
5578 {
5579 fprintf(stderr, "56aSerious internal error: CircularQueue could not push into queue.\n");
5580 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5581 }
5582 /*
5583 else
5584 {
5585 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5586 }
5587 */
5588 }
5589 }
5590 /* for processed > 0 */
5591 else
5592 {
5593 /* Keep count of how many buffers we have
5594 * to queue so we can return the value
5595 */
5596 retval++;
5597 /*
5598 fprintf(stderr, "NOT_EOF, about to Queue more data for filled max_queue (%d)\n",
5599 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5600 */
5601 alSourceQueueBuffers(
5602 ALmixer_Channel_List[i].alsource,
5603 1, &unqueued_buffer_id);
5604 if((error = alGetError()) != AL_NO_ERROR)
5605 {
5606 ALmixer_SetError("Could not QueueBuffer: %s",
5607 alGetString(error) );
5608 error_flag--;
5609 continue;
5610 }
5611 /* This is part of the hideous Nvidia workaround. In order to figure out
5612 * which buffer to show during callbacks (for things like
5613 * o-scopes), I must keep a copy of the buffers that are queued in my own
5614 * data structure. This code will be called only if
5615 * "access_data" was set, indicated by whether the queue is NULL.
5616 */
5617 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5618 {
5619 ALuint queue_ret_flag;
5620 // fprintf(stderr, "56e: CircularQueue_PushBack.\n");
5621 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5622 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5623 unqueued_buffer_id
5624 );
5625 if(0 == queue_ret_flag)
5626 {
5627 fprintf(stderr, "56bSerious internal error: CircularQueue could not push into queue.\n");
5628 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5629 }
5630 #if 0
5631 else
5632 {
5633 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5634 }
5635 #endif
5636 }
5637 }
5638 /* If we used an available buffer queue,
5639 * then we need to update the number of them in use
5640 */
5641 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5642 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5643 {
5644 /* Increment the number of buffers in use */
5645 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++;
5646 }
5647 /* Might want to check state */
5648 /* In case the playback stopped,
5649 * we need to resume */
5650 #if 1
5651 /* Try not refetching the state here because I'm getting a duplicate
5652 buffer playback (hiccup) */
5653 alGetSourcei(
5654 ALmixer_Channel_List[i].alsource,
5655 AL_SOURCE_STATE, &state
5656 );
5657 if((error = alGetError()) != AL_NO_ERROR)
5658 {
5659 fprintf(stderr, "57bTesting error: %s\n",
5660 alGetString(error));
5661 }
5662 /* Get the number of buffers processed
5663 */
5664 alGetSourcei(
5665 ALmixer_Channel_List[i].alsource,
5666 AL_BUFFERS_PROCESSED,
5667 &buffers_processed
5668 );
5669 if((error = alGetError()) != AL_NO_ERROR)
5670 {
5671 fprintf(stderr, "57cError, Can't get buffers_processed: %s\n",
5672 alGetString(error));
5673 }
5674 #endif
5675 if(AL_STOPPED == state)
5676 {
5677 /*
5678 fprintf(stderr, "Resuming in not eof\n");
5679 */
5680 /* Okay, here's another lately discovered problem:
5681 * I can't find it in the spec, but for at least some of the
5682 * implementations, if I call play on a stopped source that
5683 * has processed buffers, all those buffers get marked as unprocessed
5684 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers
5685 * processed, on resume, the earlier 24 buffers will get replayed,
5686 * causing a "hiccup" like sound in the playback.
5687 * To avoid this, I must unqueue all processed buffers before
5688 * calling play. But to complicate things, I need to worry about resyncing
5689 * the circular queue with this since I designed this thing
5690 * with some correlation between the two. However, I might
5691 * have already handled this, so I will try writing this code without
5692 * syncing for now.
5693 * There is currently an assumption that a buffer
5694 * was queued above so I actually have something
5695 * to play.
5696 */
5697 ALint temp_count;
5698 /*
5699 fprintf(stderr, "STOPPED2, need to clear processed, status is:\n");
5700 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5701 */
5702
5703 for(temp_count=0; temp_count<buffers_processed; temp_count++)
5704 {
5705 alSourceUnqueueBuffers(
5706 ALmixer_Channel_List[i].alsource,
5707 1, &unqueued_buffer_id
5708 );
5709 if((error = alGetError()) != AL_NO_ERROR)
5710 {
5711 fprintf(stderr, "58aTesting error: %s\n",
5712 alGetString(error));
5713 error_flag--;
5714 }
5715 }
5716 /*
5717 fprintf(stderr, "After unqueue clear...:\n");
5718 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5719 */
5720
5721 alSourcePlay(ALmixer_Channel_List[i].alsource);
5722 if((error = alGetError()) != AL_NO_ERROR)
5723 {
5724 fprintf(stderr, "55Tbesting 8rror: %s\n",
5725 alGetString(error));
5726 }
5727 }
5728 continue;
5729 } /* END if( ! eof) */
5730 /* We have hit EOF in the SDL_Sound sample and there
5731 * are no more loops. However, there may still be
5732 * buffers in the OpenAL queue which still need to
5733 * be played out. The following body of code will
5734 * determine if play is still happening or
5735 * initiate the stop/cleanup sequenece.
5736 */
5737 else
5738 {
5739 /* Let's continue to remove the used up
5740 * buffers as they come in. */
5741 if(buffers_processed > 0)
5742 {
5743 ALint temp_count;
5744 /* Do as a for-loop because I don't want
5745 * to have to create an array for the
5746 * unqueued_buffer_id's
5747 */
5748 for(temp_count=0; temp_count<buffers_processed; temp_count++)
5749 {
5750 fprintf(stderr, "unqueuing remainder, %d\n", temp_count);
5751 alSourceUnqueueBuffers(
5752 ALmixer_Channel_List[i].alsource,
5753 1, &unqueued_buffer_id
5754 );
5755 if((error = alGetError()) != AL_NO_ERROR)
5756 {
5757 fprintf(stderr, "59Testing error: %s\n",
5758 alGetString(error));
5759 }
5760 }
5761 fprintf(stderr, "done unqueuing remainder for this loop, %d\n", temp_count);
5762
5763 /* Need to update counts since we removed everything.
5764 * If we don't update the counts here, we end up in the
5765 * "Shouldn't be here section, but maybe it's okay due to race conditions"
5766 */
5767 alGetSourcei(
5768 ALmixer_Channel_List[i].alsource,
5769 AL_BUFFERS_QUEUED, &buffers_still_queued
5770 );
5771 if((error = alGetError()) != AL_NO_ERROR)
5772 {
5773 fprintf(stderr, "5100Testing error: %s\n",
5774 alGetString(error));
5775 }
5776 /* Get the number of buffers processed
5777 * so we know if we need to refill
5778 */
5779 alGetSourcei(
5780 ALmixer_Channel_List[i].alsource,
5781 AL_BUFFERS_PROCESSED, &buffers_processed
5782 );
5783 if((error = alGetError()) != AL_NO_ERROR)
5784 {
5785 fprintf(stderr, "5200Testing error: %s\n",
5786 alGetString(error));
5787 }
5788 }
5789
5790
5791 /* Else if buffers_processed == 0
5792 * and buffers_still_queued == 0.
5793 * then we check to see if the source
5794 * is still playing. Quit if stopped
5795 * We shouldn't need to worry about
5796 * looping because that should have
5797 * been handled above.
5798 */
5799 if(0 == buffers_still_queued)
5800 {
5801 /* Make sure playback has stopped before
5802 * we shutdown.
5803 */
5804 alGetSourcei(
5805 ALmixer_Channel_List[i].alsource,
5806 AL_SOURCE_STATE, &state
5807 );
5808 if((error = alGetError()) != AL_NO_ERROR)
5809 {
5810 fprintf(stderr, "60Testing error: %s\n",
5811 alGetString(error));
5812 }
5813 if(AL_STOPPED == state)
5814 {
5815 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0;
5816 /* Playback has ended.
5817 * Loop if necessary, or launch callback
5818 * and clear channel (or clear channel and
5819 * then launch callback?)
5820 */
5821 Clean_Channel(i);
5822 /* Subtract counter */
5823 Is_Playing_global--;
5824
5825 /* Launch callback */
5826 Invoke_Channel_Done_Callback(i, AL_TRUE);
5827
5828 /* We're done for this loop.
5829 * Go to next channel
5830 */
5831 continue;
5832 }
5833 } /* End end-playback */
5834 else
5835 {
5836 /* Need to run out buffer */
5837 #if 1
5838 /* Might want to check state */
5839 /* In case the playback stopped,
5840 * we need to resume */
5841 alGetSourcei(
5842 ALmixer_Channel_List[i].alsource,
5843 AL_SOURCE_STATE, &state
5844 );
5845 if((error = alGetError()) != AL_NO_ERROR)
5846 {
5847 fprintf(stderr, "61Testing error: %s\n",
5848 alGetString(error));
5849 }
5850 if(AL_STOPPED == state)
5851 {
5852 fprintf(stderr, "Shouldn't be here. %d Buffers still in queue, but play stopped. This might be correct though because race conditions could have caused the STOP to happen right after our other tests...Checking queue status...\n", buffers_still_queued);
5853 /*
5854 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5855 */
5856 /* Rather than force unqueuing the buffer, let's see if
5857 * setting the buffer to none works (the OpenAL 1.0
5858 * Reference Annotation suggests this should work).
5859 */
5860 alSourcei(ALmixer_Channel_List[i].alsource,
5861 AL_BUFFER, AL_NONE);
5862 /*
5863 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5864 */
5865 /* This doesn't work because in some cases, I think
5866 * it causes the sound to be replayed
5867 */
5868 /*
5869 fprintf(stderr, "Resuming in eof (trying to run out buffers\n");
5870 alSourcePlay(ALmixer_Channel_List[i].alsource);
5871 */
5872 }
5873 #endif
5874 } /* End trap section */
5875 } /* End POST-EOF use-up buffer section */
5876 } /* END Streamed section */
5877 } /* END channel in use */
5878 } /* END for-loop for each channel */
5879
5880 #ifdef ENABLE_ALMIXER_ALC_SYNC
5881 alcProcessContext(alcGetCurrentContext());
5882 if((error = alGetError()) != AL_NO_ERROR)
5883 {
5884 fprintf(stderr, "62Testing error: %s\n",
5885 alGetString(error));
5886 }
5887 #endif
5888
5889 #ifdef ENABLE_ALMIXER_THREADS
5890 SDL_UnlockMutex(s_simpleLock);
5891 #endif
5892 /* Return the number of errors */
5893 if(error_flag < 0)
5894 {
5895 return error_flag;
5896 }
5897 /* Return the number of buffers that were queued */
5898 return retval;
5899 }
5900
5901 #ifdef ENABLE_PARANOID_SIGNEDNESS_CHECK
5902 /* This is only here so we can call SDL_OpenAudio() */
5903 static void my_dummy_audio_callback(void* userdata, ALbyte* stream, int len)
5904 {
5905 }
5906 #endif
5907
5908
5909
5910
5911 #ifdef ENABLE_ALMIXER_THREADS
5912 /* We might need threads. We
5913 * must constantly poll OpenAL to find out
5914 * if sound is being streamed, if play has
5915 * ended, etc. Without threads, this must
5916 * be explicitly done by the user.
5917 * We could try to do it for them if we
5918 * finish the threads.
5919 */
5920
5921 static int Stream_Data_Thread_Callback(void* data)
5922 {
5923 ALint retval;
5924
5925 while(ALmixer_Initialized)
5926 {
5927 retval = Update_ALmixer(data);
5928 /* 0 means that nothing needed updating and
5929 * the function returned quickly
5930 */
5931 if(0 == retval)
5932 {
5933 /* Let's be nice and make the thread sleep since
5934 * little work was done in update
5935 */
5936 /* Make sure times are multiples of 10
5937 * for optimal performance and accuracy in Linux
5938 */
5939 ALmixer_Delay(10);
5940 }
5941 else
5942 {
5943 /* should I also be sleeping/yielding here? */
5944 ALmixer_Delay(0);
5945 }
5946 }
5947 fprintf(stderr, "Thread is closing\n");
5948 return 0;
5949 }
5950 #endif /* End of ENABLE_ALMIXER_THREADS */
5951
5952
5953 /* SDL/SDL_mixer returns -1 on error and 0 on success.
5954 * I actually prefer false/true conventions (SDL_Sound/OpenAL/GL)
5955 * so SDL_mixer porting people beware.
5956 * Warning: SDL_QuitSubSystem(SDL_INIT_AUDIO) is called which
5957 * means the SDL audio system will be disabled. It will not
5958 * be restored (in case SDL is not actually being used) so
5959 * the user will need to restart it if they need it after
5960 * OpenAL shuts down.
5961 */
5962 ALboolean ALmixer_Init(ALuint frequency, ALint num_sources, ALuint refresh)
5963 {
5964 ALCdevice* dev;
5965 ALCcontext* context;
5966 ALint i;
5967 ALenum error;
5968 ALuint* source;
5969
5970 #ifdef USING_LOKI_AL_DIST
5971 /* The Loki dist requires that I set both the
5972 * device and context frequency values separately
5973 */
5974 /* Hope this won't overflow */
5975 char device_string[256];
5976 #endif
5977
5978 /* (Venting frustration) Damn it! Nobody bothered
5979 * documenting how you're supposed to use an attribute
5980 * list. In fact, the not even the Loki test program
5981 * writers seem to know because they use it inconsistently.
5982 * For example, how do you terminate that attribute list?
5983 * The Loki test code does it 3 different ways. They
5984 * set the last value to 0, or they set it to ALC_INVALID,
5985 * or they set two final values: ALC_INVALID, 0
5986 * In Loki, 0 and ALC_INVALID happen to be the same,
5987 * but with Creative Labs ALC_INVALID is -1.
5988 * So something's going to break. Loki's source
5989 * code says to terminate with ALC_INVALID. But I
5990 * don't know if that's really true, or it happens
5991 * to be a coinicidence because it's defined to 0.
5992 * Creative provides no source code, so I can't look at how
5993 * they terminate it.
5994 * So this is really, really ticking me off...
5995 * For now, I'm going to use ALC_INVALID.
5996 * (Update...after further review of the API spec,
5997 * it seems that a NULL terminated string is the correct
5998 * termination value to use, so 0 it is.)
5999 */
6000 #if 0
6001 ALint attrlist[] = {
6002 ALC_FREQUENCY, ALMIXER_DEFAULT_FREQUENCY,
6003 /* Don't know anything about these values.
6004 * Trust defaults? */
6005 /* Supposed to be the refresh rate in Hz.
6006 * I think 15-120 are supposed to be good
6007 * values. Though I haven't gotten any effect except
6008 * for one strange instance on a Mac. But it was
6009 * unrepeatable.
6010 */
6011 #if 0
6012 ALC_REFRESH, 15,
6013 #endif
6014 /* Sync requires a alcProcessContext() call
6015 * for every cycle. By default, this is
6016 * not used and the value is AL_FALSE
6017 * because it will probably perform
6018 * pretty badly for me.
6019 */
6020 #ifdef ENABLE_ALMIXER_ALC_SYNC
6021 ALC_SYNC, AL_TRUE,
6022 #else
6023 ALC_SYNC, AL_FALSE,
6024 #endif
6025 /* Looking at the API spec, it implies
6026 * that the list be a NULL terminated string
6027 * so it's probably not safe to use ALC_INVALID
6028 */
6029 /*
6030 ALC_INVALID };
6031 */
6032 '\0'};
6033 #endif
6034 /* Redo: I'm going to allow ALC_REFRESH to be set.
6035 * However, if no value is specified, I don't
6036 * want it in the list so I can get the OpenAL defaults
6037 */
6038 ALint attrlist[7];
6039 ALsizei current_attrlist_index = 0;
6040
6041 #ifdef ENABLE_PARANOID_SIGNEDNESS_CHECK
6042 /* More problems: I'm getting bit by endian/signedness issues on
6043 * different platforms. I can find the endianess easily enough,
6044 * but I don't know how to determine what the correct signedness
6045 * is (if such a thing exists). I do know that if I try using
6046 * unsigned on OSX with an originally signed sample, I get
6047 * distortion. However, I don't have any native unsigned samples
6048 * to test. But I'm assuming that the platform must be in the
6049 * correct signedness no matter what.
6050 * I can either assume everybody is signed, or I can try to
6051 * determine the value. If I try to determine the values,
6052 * I think my only ability to figure it out will be to open
6053 * SDL_Audio, and read what the obtained settings were.
6054 * Then shutdown everything. However, I don't even know how
6055 * reliable this is.
6056 * Update: I think I resolved the issues...forgot to update
6057 * these comments when it happened. I should check the revision control
6058 * log... Anyway, I think the issue was partly related to me not
6059 * doing something correctly with the AudioInfo or some kind
6060 * of stupid endian bug in my code, and weirdness ensued. Looking at the
6061 * revision control, I think I might have assumed that SDL_Sound would
6062 * do the right thing with a NULL AudioInfo, but I was incorrect,
6063 * and had to fill one out myself.
6064 */
6065 SDL_AudioSpec desired;
6066 SDL_AudioSpec obtained;
6067 #endif
6068
6069
6070 /* Make sure ALmixer isn't already initialized */
6071 if(ALmixer_Initialized)
6072 {
6073 return AL_FALSE;
6074 }
6075 #ifdef USING_LOKI_AL_DIST
6076 fprintf(stderr, "Found Loki dist\n");
6077 #elif defined(USING_CREATIVE_AL_DIST)
6078 fprintf(stderr, "Found Creative dist\n");
6079
6080 #elif defined(USING_NVIDIA_AL_DIST)
6081 fprintf(stderr, "Found Nvidia dist\n");
6082 #endif
6083
6084 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
6085 ALmixer_InitTime();
6086
6087 /* Note: The pool may have been created on previous Init's */
6088 /* I leave the pool allocated allocated in case the user wants
6089 * to read the pool in case of a failure (such as in this function).
6090 * This is not actually a leak.
6091 */
6092 if(NULL == s_ALmixerErrorPool)
6093 {
6094 s_ALmixerErrorPool = TError_CreateErrorPool();
6095 }
6096 if(NULL == s_ALmixerErrorPool)
6097 {
6098 return AL_FALSE;
6099 }
6100 fprintf(stderr, "tError Test0\n");
6101 ALmixer_SetError("Initing (and testing SetError)");
6102 fprintf(stderr, "tError Test1: %s\n", ALmixer_GetError());
6103 fprintf(stderr, "tError Test2: %s\n", ALmixer_GetError());
6104 #endif
6105
6106
6107 /* Set the defaults */
6108 /*
6109 attrlist[0] = ALC_FREQUENCY;
6110 attrlist[1] = ALMIXER_DEFAULT_FREQUENCY;
6111 attrlist[2] = ALC_SYNC;
6112 #ifdef ENABLE_ALMIXER_ALC_SYNC
6113 attrlist[3] = ALC_TRUE;
6114 #else
6115 attrlist[3] = ALC_FALSE;
6116 #endif
6117 */
6118 /* Set frequency value if it is not 0 */
6119 if(0 != frequency)
6120 {
6121 attrlist[current_attrlist_index] = ALC_FREQUENCY;
6122 current_attrlist_index++;
6123 attrlist[current_attrlist_index] = (ALint)frequency;
6124 current_attrlist_index++;
6125 }
6126
6127 #ifdef ENABLE_ALMIXER_ALC_SYNC
6128 attrlist[current_attrlist_index] = ALC_SYNC;
6129 current_attrlist_index++;
6130 attrlist[current_attrlist_index] = ALC_TRUE;
6131 current_attrlist_index++;
6132 #endif
6133
6134 /* If the user specifies a refresh value,
6135 * make room for it
6136 */
6137 if(0 != refresh)
6138 {
6139 attrlist[current_attrlist_index] = (ALint)ALC_REFRESH;
6140 current_attrlist_index++;
6141 attrlist[current_attrlist_index] = refresh;
6142 current_attrlist_index++;
6143 }
6144
6145 /* End attribute list */
6146 attrlist[current_attrlist_index] = '\0';
6147
6148
6149 /* Initialize SDL_Sound */
6150 if(! Sound_Init() )
6151 {
6152 ALmixer_SetError(Sound_GetError());
6153 return AL_FALSE;
6154 }
6155 #ifdef ENABLE_PARANOID_SIGNEDNESS_CHECK
6156 /* Here is the paranoid check that opens
6157 * SDL audio in an attempt to find the correct
6158 * system values.
6159 */
6160 /* Doesn't have to be the actual value I think
6161 * (as long as it doesn't influence format, in
6162 * which case I'm probably screwed anyway because OpenAL
6163 * may easily choose to do something else).
6164 */
6165 desired.freq = 44100;
6166 desired.channels = 2;
6167 desired.format = AUDIO_S16SYS;
6168 desired.callback = my_dummy_audio_callback;
6169 if(SDL_OpenAudio(&desired, &obtained) >= 0)
6170 {
6171 SIGN_TYPE_16BIT_FORMAT = obtained.format;
6172 /* Now to get really paranoid, we should probably
6173 * also assume that the 8bit format is also the
6174 * same sign type and set that value
6175 */
6176 if(AUDIO_S16SYS == obtained.format)
6177 {
6178 SIGN_TYPE_8BIT_FORMAT = AUDIO_S8;
6179 }
6180 /* Should be AUDIO_U16SYS */
6181 else
6182 {
6183 SIGN_TYPE_8BIT_FORMAT = AUDIO_U8;
6184 }
6185 SDL_CloseAudio();
6186 fprintf(stderr, "Obtained format = %d", obtained.format);
6187 }
6188 else
6189 {
6190 /* Well, I guess I'm in trouble. I guess it's my best guess
6191 */
6192 SIGN_TYPE_16_BIT_FORMAT = AUDIO_S16SYS;
6193 SIGN_TYPE_8_BIT_FORMAT = AUDIO_S8;
6194 }
6195 #endif
6196
6197 #ifndef ALMIXER_COMPILE_WITHOUT_SDL
6198 /* Weirdness: It seems that SDL_Init(SDL_INIT_AUDIO)
6199 * causes OpenAL and SMPEG to conflict. For some reason
6200 * if SDL_Init on audio is active, then all the SMPEG
6201 * decoded sound comes out silent. Unfortunately,
6202 * Sound_Init() invokes SDL_Init on audio. I'm
6203 * not sure why it actually needs it...
6204 * But we'll attempt to disable it here after the
6205 * SDL_Sound::Init call and hope it doesn't break SDL_Sound.
6206 */
6207 SDL_QuitSubSystem(SDL_INIT_AUDIO);
6208 #endif
6209
6210 /* I'm told NULL will call the default string
6211 * and hopefully do the right thing for each platform
6212 */
6213 /*
6214 dev = alcOpenDevice( NULL );
6215 */
6216 /* Now I'm told I need to set both the device and context
6217 * to have the same sampling rate, so I must pass a string
6218 * to OpenDevice(). I don't know how portable these strings are.
6219 * I don't even know if the format for strings is
6220 * compatible
6221 * From the testattrib.c in the Loki test section
6222 * dev = alcOpenDevice( (const ALubyte *) "'((sampling-rate 22050))" );
6223 */
6224
6225 #ifdef USING_LOKI_AL_DIST
6226 sprintf(device_string, "'((sampling-rate %d))", attrlist[1]);
6227 dev = alcOpenDevice( (const ALubyte *) device_string );
6228 #else
6229 dev = alcOpenDevice( NULL );
6230 #endif
6231 fprintf(stderr,"sampling-rate is %d\n", attrlist[1]);
6232 if(NULL == dev)
6233 {
6234 ALmixer_SetError("Cannot open sound device for OpenAL");
6235 return AL_FALSE;
6236 }
6237
6238 #ifdef __APPLE__
6239 /* The ALC_FREQUENCY attribute is ignored with Apple's implementation. */
6240 /* This extension must be called before the context is created. */
6241 if(0 != frequency)
6242 {
6243 Internal_alcMacOSXMixerOutputRate((ALdouble)frequency);
6244 }
6245 ALmixer_Frequency_global = (ALuint)Internal_alcMacOSXGetMixerOutputRate();
6246 fprintf(stderr, "Internal_alcMacOSXMixerOutputRate is: %lf", Internal_alcMacOSXGetMixerOutputRate());
6247 #endif
6248
6249 context = alcCreateContext(dev, attrlist);
6250 if(NULL == context)
6251 {
6252 ALmixer_SetError("Cannot create a context OpenAL");
6253 alcCloseDevice(dev);
6254 return AL_FALSE;
6255 }
6256 fprintf(stderr, "Context checking...\n");
6257
6258
6259 /* Hmmm, OSX is returning 1 on alcMakeContextCurrent,
6260 * but ALC_NO_ERROR is defined to ALC_FALSE.
6261 * According to Garin Hiebert, this is actually an inconsistency
6262 * in the Loki version. The function should return a boolean.
6263 * instead of ALC_NO_ERROR. Garin suggested I check via
6264 * alcGetError().
6265 */
6266 /* clear the error */
6267 alcGetError(dev);
6268 alcMakeContextCurrent(context);
6269
6270 error = alcGetError(dev);
6271 if( (ALC_NO_ERROR != error) )
6272 {
6273 ALmixer_SetError("Could not MakeContextCurrent");
6274 alcDestroyContext(context);
6275 alcCloseDevice(dev);
6276 return AL_FALSE;
6277 }
6278
6279 /* It looks like OpenAL won't let us ask it what
6280 * the set frequency is, so we need to save our
6281 * own copy. Yuck.
6282 * Update: J. Valenzuela just updated the Loki
6283 * dist (2003/01/02) to handle this.
6284 * The demo is in testattrib.c.
6285 */
6286 /*
6287 ALmixer_Frequency_global = frequency;
6288 */
6289 #ifndef __APPLE__
6290 alcGetIntegerv(dev, ALC_FREQUENCY, 1, &ALmixer_Frequency_global);
6291 fprintf(stderr, "alcGetIntegerv ALC_FREQUENCY is: %d", ALmixer_Frequency_global);
6292 #endif
6293
6294
6295 #if 0
6296 /* OSX is failing on alcMakeContextCurrent(). Try checking it first? */
6297 if(alcGetCurrentContext() != context)
6298 {
6299 /* Hmmm, OSX is returning 1 on alcMakeContextCurrent,
6300 * but ALC_NO_ERROR is defined to ALC_FALSE.
6301 * I think this is a bug in the OpenAL implementation.
6302 */
6303 fprintf(stderr,"alcMakeContextCurrent returns %d\n", alcMakeContextCurrent(context));
6304
6305 fprintf(stderr, "Making context current\n");
6306 #ifndef __APPLE__
6307 if(alcMakeContextCurrent(context) != ALC_NO_ERROR)
6308 #else
6309 if(!alcMakeContextCurrent(context))
6310 #endif
6311 {
6312 ALmixer_SetError("Could not MakeContextCurrent");
6313 alcDestroyContext(context);
6314 alcCloseDevice(dev);
6315 return AL_FALSE;
6316 }
6317 }
6318 #endif
6319
6320
6321 /* #endif */
6322 fprintf(stderr, "done Context\n");
6323 /* Saw this in the README with the OS X OpenAL distribution.
6324 * It looked interesting and simple, so I thought I might
6325 * try it out.
6326 * ***** ALC_CONVERT_DATA_UPON_LOADING
6327 * This extension allows the caller to tell OpenAL to preconvert to the native Core
6328 * Audio format, the audio data passed to the
6329 * library with the alBufferData() call. Preconverting the audio data, reduces CPU
6330 * usage by removing an audio data conversion
6331 * (per source) at render timem at the expense of a larger memory footprint.
6332 *
6333 * This feature is toggled on/off by using the alDisable() & alEnable() APIs. This
6334 * setting will be applied to all subsequent
6335 * calls to alBufferData().
6336 */
6337 #ifdef __APPLE__
6338 /*
6339 #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
6340
6341 #else
6342 #endif
6343 */
6344 ALenum convert_data_enum = alcGetEnumValue(dev, "ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING");
6345 fprintf(stderr, "ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING=0x%x", convert_data_enum);
6346 if(0 != convert_data_enum)
6347 {
6348 alEnable(convert_data_enum);
6349 }
6350 if( (AL_NO_ERROR != alGetError()) )
6351 {
6352 ALmixer_SetError("ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING attempted but failed");
6353 }
6354
6355 #endif
6356
6357
6358
6359
6360 ALmixer_Initialized = 1;
6361
6362 if(num_sources <= 0)
6363 {
6364 Number_of_Channels_global = ALMIXER_DEFAULT_NUM_CHANNELS;
6365 }
6366 else
6367 {
6368 Number_of_Channels_global = num_sources;
6369 }
6370 Number_of_Reserve_Channels_global = 0;
6371 Is_Playing_global = 0;
6372 /* Set to Null in case system quit and was reinitialized */
6373 Channel_Done_Callback = NULL;
6374 Channel_Done_Callback_Userdata = NULL;
6375 Channel_Data_Callback = NULL;
6376 Channel_Data_Callback_Userdata = NULL;
6377
6378 /* Allocate memory for the list of channels */
6379 ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel));
6380 if(NULL == ALmixer_Channel_List)
6381 {
6382 ALmixer_SetError("Out of Memory for Channel List");
6383 alcDestroyContext(context);
6384 alcCloseDevice(dev);
6385 ALmixer_Initialized = 0;
6386 Number_of_Channels_global = 0;
6387 return AL_FALSE;
6388 }
6389
6390 /* Allocate memory for the list of sources that map to the channels */
6391 Source_Map_List = (Source_Map*) malloc(Number_of_Channels_global * sizeof(Source_Map));
6392 if(NULL == Source_Map_List)
6393 {
6394 ALmixer_SetError("Out of Memory for Source Map List");
6395 free(ALmixer_Channel_List);
6396 alcDestroyContext(context);
6397 alcCloseDevice(dev);
6398 ALmixer_Initialized = 0;
6399 Number_of_Channels_global = 0;
6400 return AL_FALSE;
6401 }
6402
6403 /* Create array that will hold the sources */
6404 source = (ALuint*)malloc(Number_of_Channels_global * sizeof(ALuint));
6405 if(NULL == source)
6406 {
6407 ALmixer_SetError("Out of Memory for sources");
6408 free(Source_Map_List);
6409 free(ALmixer_Channel_List);
6410 alcDestroyContext(context);
6411 alcCloseDevice(dev);
6412 ALmixer_Initialized = 0;
6413 Number_of_Channels_global = 0;
6414 return AL_FALSE;
6415 }
6416
6417 /* Clear the error state */
6418 alGetError();
6419 /* Generate the OpenAL sources */
6420 alGenSources(Number_of_Channels_global, source);
6421 if( (error=alGetError()) != AL_NO_ERROR)
6422 {
6423 ALmixer_SetError("Couldn't generate sources: %s\n", alGetString(error));
6424 free(ALmixer_Channel_List);
6425 free(Source_Map_List);
6426 alcDestroyContext(context);
6427 alcCloseDevice(dev);
6428 ALmixer_Initialized = 0;
6429 Number_of_Channels_global = 0;
6430 return AL_FALSE;
6431 }
6432
6433 /* Initialize each channel and associate one source to one channel */
6434 for(i=0; i<Number_of_Channels_global; i++)
6435 {
6436 if(0 == source[i])
6437 {
6438 fprintf(stderr, "SDL_ALmixer serious problem. This OpenAL implementation allowed 0 to be a valid source id which is in conflict with assumptions made in this library.\n");
6439 }
6440
6441 Init_Channel(i);
6442 /* Keeping the source allocation out of the Init function
6443 * in case I want to reuse the Init
6444 * function for resetting data
6445 */
6446 ALmixer_Channel_List[i].alsource = source[i];
6447 /* Now also keep a copy of the source to channel mapping
6448 * in case we need to look up a channel from the source
6449 * instead of a source from a channel
6450 */
6451 Source_Map_List[i].source = source[i];
6452 Source_Map_List[i].channel = i;
6453 /* Clean the channel because there are some things that need to
6454 * be done that can't happen until the source is set
6455 */
6456 Clean_Channel(i);
6457 }
6458
6459 /* The Source_Map_List must be sorted by source for binary searches
6460 */
6461 qsort(Source_Map_List, Number_of_Channels_global, sizeof(Source_Map), Compare_Source_Map);
6462
6463 fprintf(stderr, "Sorted Source_Map_List is:\n");
6464 for(i=0; i<Number_of_Channels_global; i++)
6465 {
6466 fprintf(stderr, "Source: %d, Channel: %d\n", Source_Map_List[i].source, Source_Map_List[i].channel);
6467 }
6468 fprintf(stderr, "\n");
6469 ALmixer_OutputDecoders();
6470
6471 #ifdef ENABLE_ALMIXER_THREADS
6472 s_simpleLock = SDL_CreateMutex();
6473 if(NULL == s_simpleLock)
6474 {
6475 /* SDL sets the error message already? */
6476 free(source);
6477 free(ALmixer_Channel_List);
6478 free(Source_Map_List);
6479 alcDestroyContext(context);
6480 alcCloseDevice(dev);
6481 ALmixer_Initialized = 0;
6482 Number_of_Channels_global = 0;
6483 return AL_FALSE;
6484 }
6485
6486
6487 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL);
6488 if(NULL == Stream_Thread_global)
6489 {
6490 /* SDL sets the error message already? */
6491 SDL_DestroyMutex(s_simpleLock);
6492 free(source);
6493 free(ALmixer_Channel_List);
6494 free(Source_Map_List);
6495 alcDestroyContext(context);
6496 alcCloseDevice(dev);
6497 ALmixer_Initialized = 0;
6498 Number_of_Channels_global = 0;
6499 return AL_FALSE;
6500 }
6501
6502 fprintf(stderr, "Using threads\n");
6503 #endif /* End of ENABLE_ALMIXER_THREADS */
6504
6505 /* We don't need this array any more because all the sources
6506 * are connected to channels
6507 */
6508 free(source);
6509 return AL_TRUE;
6510 }
6511
6512
6513 ALboolean ALmixer_InitContext(ALuint frequency, ALuint refresh)
6514 {
6515 ALCdevice* dev;
6516 ALCcontext* context;
6517 ALCenum error;
6518
6519 #ifdef USING_LOKI_AL_DIST
6520 /* The Loki dist requires that I set both the
6521 * device and context frequency values separately
6522 */
6523 /* Hope this won't overflow */
6524 char device_string[256];
6525 #endif
6526
6527 /* (Venting frustration) Damn it! Nobody bothered
6528 * documenting how you're supposed to use an attribute
6529 * list. In fact, the not even the Loki test program
6530 * writers seem to know because they use it inconsistently.
6531 * For example, how do you terminate that attribute list?
6532 * The Loki test code does it 3 different ways. They
6533 * set the last value to 0, or they set it to ALC_INVALID,
6534 * or they set two final values: ALC_INVALID, 0
6535 * In Loki, 0 and ALC_INVALID happen to be the same,
6536 * but with Creative Labs ALC_INVALID is -1.
6537 * So something's going to break. Loki's source
6538 * code says to terminate with ALC_INVALID. But I
6539 * don't know if that's really true, or it happens
6540 * to be a coinicidence because it's defined to 0.
6541 * Creative provides no source code, so I can't look at how
6542 * they terminate it.
6543 * So this is really, really ticking me off...
6544 * For now, I'm going to use ALC_INVALID.
6545 * (Update...after further review of the API spec,
6546 * it seems that a NULL terminated string is the correct
6547 * termination value to use, so 0 it is.)
6548 */
6549 #if 0
6550 ALint attrlist[] = {
6551 ALC_FREQUENCY, ALMIXER_DEFAULT_FREQUENCY,
6552 /* Don't know anything about these values.
6553 * Trust defaults? */
6554 /* Supposed to be the refresh rate in Hz.
6555 * I think 15-120 are supposed to be good
6556 * values. Though I haven't gotten any effect except
6557 * for one strange instance on a Mac. But it was
6558 * unrepeatable.
6559 */
6560 #if 0
6561 ALC_REFRESH, 15,
6562 #endif
6563 /* Sync requires a alcProcessContext() call
6564 * for every cycle. By default, this is
6565 * not used and the value is AL_FALSE
6566 * because it will probably perform
6567 * pretty badly for me.
6568 */
6569 #ifdef ENABLE_ALMIXER_ALC_SYNC
6570 ALC_SYNC, AL_TRUE,
6571 #else
6572 ALC_SYNC, AL_FALSE,
6573 #endif
6574 /* Looking at the API spec, it implies
6575 * that the list be a NULL terminated string
6576 * so it's probably not safe to use ALC_INVALID
6577 */
6578 /*
6579 ALC_INVALID };
6580 */
6581 '\0'};
6582 #endif
6583 /* Redo: I'm going to allow ALC_REFRESH to be set.
6584 * However, if no value is specified, I don't
6585 * want it in the list so I can get the OpenAL defaults
6586 */
6587 ALint attrlist[7];
6588 ALsizei current_attrlist_index = 0;
6589
6590 #ifdef ENABLE_PARANOID_SIGNEDNESS_CHECK
6591 /* More problems: I'm getting bit by endian/signedness issues on
6592 * different platforms. I can find the endianess easily enough,
6593 * but I don't know how to determine what the correct signedness
6594 * is (if such a thing exists). I do know that if I try using
6595 * unsigned on OSX with an originally signed sample, I get
6596 * distortion. However, I don't have any native unsigned samples
6597 * to test. But I'm assuming that the platform must be in the
6598 * correct signedness no matter what.
6599 * I can either assume everybody is signed, or I can try to
6600 * determine the value. If I try to determine the values,
6601 * I think my only ability to figure it out will be to open
6602 * SDL_Audio, and read what the obtained settings were.
6603 * Then shutdown everything. However, I don't even know how
6604 * reliable this is.
6605 * Update: I think I resolved the issues...forgot to update
6606 * these comments when it happened. I should check the revision control
6607 * log... Anyway, I think the issue was partly related to me not
6608 * doing something correctly with the AudioInfo or some kind
6609 * of stupid endian bug in my code, and weirdness ensued. Looking at the
6610 * revision control, I think I might have assumed that SDL_Sound would
6611 * do the right thing with a NULL AudioInfo, but I was incorrect,
6612 * and had to fill one out myself.
6613 */
6614 SDL_AudioSpec desired;
6615 SDL_AudioSpec obtained;
6616 #endif
6617
6618
6619
6620
6621 /* Make sure ALmixer isn't already initialized */
6622 if(ALmixer_Initialized)
6623 {
6624 return AL_FALSE;
6625 }
6626 #ifdef USING_LOKI_AL_DIST
6627 fprintf(stderr, "Found Loki dist\n");
6628 #elif defined(USING_CREATIVE_AL_DIST)
6629 fprintf(stderr, "Found Creative dist\n");
6630
6631 #elif defined(USING_NVIDIA_AL_DIST)
6632 fprintf(stderr, "Found Nvidia dist\n");
6633 #endif
6634
6635 /* Set the defaults */
6636 attrlist[0] = ALC_FREQUENCY;
6637 attrlist[1] = ALMIXER_DEFAULT_FREQUENCY;
6638 attrlist[2] = ALC_SYNC;
6639 #ifdef ENABLE_ALMIXER_ALC_SYNC
6640 attrlist[3] = ALC_TRUE;
6641 #else
6642 attrlist[3] = ALC_FALSE;
6643 #endif
6644 /* Set frequency value if it is not 0 */
6645 if(0 != frequency)
6646 {
6647 attrlist[current_attrlist_index] = ALC_FREQUENCY;
6648 current_attrlist_index++;
6649 attrlist[current_attrlist_index] = (ALint)frequency;
6650 current_attrlist_index++;
6651 }
6652
6653 #ifdef ENABLE_ALMIXER_ALC_SYNC
6654 attrlist[current_attrlist_index] = ALC_SYNC;
6655 current_attrlist_index++;
6656 attrlist[current_attrlist_index] = ALC_TRUE;
6657 current_attrlist_index++;
6658 #endif
6659
6660 /* If the user specifies a refresh value,
6661 * make room for it
6662 */
6663 if(0 != refresh)
6664 {
6665 attrlist[current_attrlist_index] = (ALint)ALC_REFRESH;
6666 current_attrlist_index++;
6667 attrlist[current_attrlist_index] = refresh;
6668 current_attrlist_index++;
6669 }
6670
6671 /* End attribute list */
6672 attrlist[current_attrlist_index] = '\0';
6673
6674
6675
6676 /* Initialize SDL_Sound */
6677 if(! Sound_Init() )
6678 {
6679 ALmixer_SetError(Sound_GetError());
6680 return AL_FALSE;
6681 }
6682 #ifdef ENABLE_PARANOID_SIGNEDNESS_CHECK
6683 /* Here is the paranoid check that opens
6684 * SDL audio in an attempt to find the correct
6685 * system values.
6686 */
6687 /* Doesn't have to be the actual value I think
6688 * (as long as it doesn't influence format, in
6689 * which case I'm probably screwed anyway because OpenAL
6690 * may easily choose to do something else).
6691 */
6692 desired.freq = 44100;
6693 desired.channels = 2;
6694 desired.format = AUDIO_S16SYS;
6695 desired.callback = my_dummy_audio_callback;
6696 if(SDL_OpenAudio(&desired, &obtained) >= 0)
6697 {
6698 SIGN_TYPE_16BIT_FORMAT = obtained.format;
6699 /* Now to get really paranoid, we should probably
6700 * also assume that the 8bit format is also the
6701 * same sign type and set that value
6702 */
6703 if(AUDIO_S16SYS == obtained.format)
6704 {
6705 SIGN_TYPE_8BIT_FORMAT = AUDIO_S8;
6706 }
6707 /* Should be AUDIO_U16SYS */
6708 else
6709 {
6710 SIGN_TYPE_8BIT_FORMAT = AUDIO_U8;
6711 }
6712 SDL_CloseAudio();
6713 fprintf(stderr, "Obtained format = %d", obtained.format);
6714 }
6715 else
6716 {
6717 /* Well, I guess I'm in trouble. I guess it's my best guess
6718 */
6719 SIGN_TYPE_16_BIT_FORMAT = AUDIO_S16SYS;
6720 SIGN_TYPE_8_BIT_FORMAT = AUDIO_S8;
6721 }
6722 #endif
6723
6724 #ifndef ALMIXER_COMPILE_WITHOUT_SDL
6725 /* Weirdness: It seems that SDL_Init(SDL_INIT_AUDIO)
6726 * causes OpenAL and SMPEG to conflict. For some reason
6727 * if SDL_Init on audio is active, then all the SMPEG
6728 * decoded sound comes out silent. Unfortunately,
6729 * Sound_Init() invokes SDL_Init on audio. I'm
6730 * not sure why it actually needs it...
6731 * But we'll attempt to disable it here after the
6732 * SDL_Sound::Init call and hope it doesn't break SDL_Sound.
6733 */
6734 SDL_QuitSubSystem(SDL_INIT_AUDIO);
6735 #endif
6736
6737 /* I'm told NULL will call the default string
6738 * and hopefully do the right thing for each platform
6739 */
6740 /*
6741 dev = alcOpenDevice( NULL );
6742 */
6743 /* Now I'm told I need to set both the device and context
6744 * to have the same sampling rate, so I must pass a string
6745 * to OpenDevice(). I don't know how portable these strings are.
6746 * I don't even know if the format for strings is
6747 * compatible
6748 * From the testattrib.c in the Loki test section
6749 * dev = alcOpenDevice( (const ALubyte *) "'((sampling-rate 22050))" );
6750 */
6751
6752 #ifdef USING_LOKI_AL_DIST
6753 sprintf(device_string, "'((sampling-rate %d))", attrlist[1]);
6754 dev = alcOpenDevice( (const ALubyte *) device_string );
6755 #else
6756 dev = alcOpenDevice( NULL );
6757 #endif
6758 fprintf(stderr,"sampling-rate is %d\n", attrlist[1]);
6759 if(NULL == dev)
6760 {
6761 ALmixer_SetError("Cannot open sound device for OpenAL");
6762 return AL_FALSE;
6763 }
6764
6765 #ifdef __APPLE__
6766 /* The ALC_FREQUENCY attribute is ignored with Apple's implementation. */
6767 /* This extension must be called before the context is created. */
6768 if(0 != frequency)
6769 {
6770 Internal_alcMacOSXMixerOutputRate((ALdouble)frequency);
6771 }
6772 ALmixer_Frequency_global = (ALuint)Internal_alcMacOSXGetMixerOutputRate();
6773 fprintf(stderr, "Internal_alcMacOSXMixerOutputRate is: %lf", Internal_alcMacOSXGetMixerOutputRate());
6774 #endif
6775
6776
6777 context = alcCreateContext(dev, attrlist);
6778 if(NULL == context)
6779 {
6780 ALmixer_SetError("Cannot create a context OpenAL");
6781 alcCloseDevice(dev);
6782 return AL_FALSE;
6783 }
6784
6785
6786 /* Hmmm, OSX is returning 1 on alcMakeContextCurrent,
6787 * but ALC_NO_ERROR is defined to ALC_FALSE.
6788 * According to Garin Hiebert, this is actually an inconsistency
6789 * in the Loki version. The function should return a boolean.
6790 * instead of ALC_NO_ERROR. Garin suggested I check via
6791 * alcGetError().
6792 */
6793 /* clear the error */
6794 alcGetError(dev);
6795 alcMakeContextCurrent(context);
6796
6797 error = alcGetError(dev);
6798 if( (ALC_NO_ERROR != error) )
6799 {
6800 ALmixer_SetError("Could not MakeContextCurrent");
6801 alcDestroyContext(context);
6802 alcCloseDevice(dev);
6803 return AL_FALSE;
6804 }
6805
6806
6807 #if 0
6808 /* OSX is failing on alcMakeContextCurrent(). Try checking it first? */
6809 if(alcGetCurrentContext() != context)
6810 {
6811 /* Hmmm, OSX is returning 1 on alcMakeContextCurrent,
6812 * but ALC_NO_ERROR is defined to ALC_FALSE.
6813 * I think this is a bug in the OpenAL implementation.
6814 */
6815 fprintf(stderr,"alcMakeContextCurrent returns %d\n", alcMakeContextCurrent(context));
6816
6817 fprintf(stderr, "Making context current\n");
6818 #ifndef __APPLE__
6819 if(alcMakeContextCurrent(context) != ALC_NO_ERROR)
6820 #else
6821 if(!alcMakeContextCurrent(context))
6822 #endif
6823 {
6824 ALmixer_SetError("Could not MakeContextCurrent");
6825 alcDestroyContext(context);
6826 alcCloseDevice(dev);
6827 return AL_FALSE;
6828 }
6829
6830 }
6831 #endif
6832
6833 /* It looks like OpenAL won't let us ask it what
6834 * the set frequency is, so we need to save our
6835 * own copy. Yuck.
6836 * Update: J. Valenzuela just updated the Loki
6837 * dist (2003/01/02) to handle this.
6838 * The demo is in testattrib.c.
6839 */
6840 #ifndef __APPLE__
6841 alcGetIntegerv(dev, ALC_FREQUENCY, 1, &ALmixer_Frequency_global);
6842 fprintf(stderr, "alcGetIntegerv ALC_FREQUENCY is: %d", ALmixer_Frequency_global);
6843 #endif
6844
6845
6846 fprintf(stderr, "done Context\n");
6847
6848 /* Saw this in the README with the OS X OpenAL distribution.
6849 * It looked interesting and simple, so I thought I might
6850 * try it out.
6851 * ***** ALC_CONVERT_DATA_UPON_LOADING
6852 * This extension allows the caller to tell OpenAL to preconvert to the native Core
6853 * Audio format, the audio data passed to the
6854 * library with the alBufferData() call. Preconverting the audio data, reduces CPU
6855 * usage by removing an audio data conversion
6856 * (per source) at render timem at the expense of a larger memory footprint.
6857 *
6858 * This feature is toggled on/off by using the alDisable() & alEnable() APIs. This
6859 * setting will be applied to all subsequent
6860 * calls to alBufferData().
6861 */
6862 #ifdef __APPLE__
6863 /*
6864 #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
6865
6866 #else
6867 #endif
6868 */
6869 ALenum convert_data_enum = alcGetEnumValue(dev, "ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING");
6870 fprintf(stderr, "ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING=0x%x", convert_data_enum);
6871 if(0 != convert_data_enum)
6872 {
6873 alEnable(convert_data_enum);
6874 }
6875 if( (AL_NO_ERROR != alGetError()) )
6876 {
6877 ALmixer_SetError("ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING attempted but failed");
6878 }
6879 #endif
6880
6881 return AL_TRUE;
6882 }
6883
6884
6885 ALboolean ALmixer_InitMixer(ALint num_sources)
6886 {
6887 ALint i;
6888 ALenum error;
6889 ALuint* source;
6890
6891
6892 ALmixer_Initialized = 1;
6893
6894
6895 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
6896 ALmixer_InitTime();
6897
6898 /* Note: The pool may have been created on previous Init's */
6899 /* I leave the pool allocated allocated in case the user wants
6900 * to read the pool in case of a failure (such as in this function).
6901 * This is not actually a leak.
6902 */
6903 if(NULL == s_ALmixerErrorPool)
6904 {
6905 s_ALmixerErrorPool = TError_CreateErrorPool();
6906 }
6907 if(NULL == s_ALmixerErrorPool)
6908 {
6909 return AL_FALSE;
6910 }
6911 /*
6912 fprintf(stderr, "tError Test0\n");
6913 ALmixer_SetError("Initing (and testing SetError)");
6914 fprintf(stderr, "tError Test1: %s\n", ALmixer_GetError());
6915 fprintf(stderr, "tError Test2: %s\n", ALmixer_GetError());
6916 */
6917 #endif
6918
6919 if(num_sources <= 0)
6920 {
6921 Number_of_Channels_global = ALMIXER_DEFAULT_NUM_CHANNELS;
6922 }
6923 else
6924 {
6925 Number_of_Channels_global = num_sources;
6926 }
6927 Number_of_Reserve_Channels_global = 0;
6928 Is_Playing_global = 0;
6929 /* Set to Null in case system quit and was reinitialized */
6930 Channel_Done_Callback = NULL;
6931 Channel_Done_Callback_Userdata = NULL;
6932 Channel_Data_Callback = NULL;
6933 Channel_Data_Callback_Userdata = NULL;
6934
6935 /* Allocate memory for the list of channels */
6936 ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel));
6937 if(NULL == ALmixer_Channel_List)
6938 {
6939 ALmixer_SetError("Out of Memory for Channel List");
6940 ALmixer_Initialized = 0;
6941 Number_of_Channels_global = 0;
6942 return AL_FALSE;
6943 }
6944
6945 /* Allocate memory for the list of sources that map to the channels */
6946 Source_Map_List = (Source_Map*) malloc(Number_of_Channels_global * sizeof(Source_Map));
6947 if(NULL == Source_Map_List)
6948 {
6949 ALmixer_SetError("Out of Memory for Source Map List");
6950 free(ALmixer_Channel_List);
6951 ALmixer_Initialized = 0;
6952 Number_of_Channels_global = 0;
6953 return AL_FALSE;
6954 }
6955
6956 /* Create array that will hold the sources */
6957 source = (ALuint*)malloc(Number_of_Channels_global * sizeof(ALuint));
6958 if(NULL == source)
6959 {
6960 ALmixer_SetError("Out of Memory for sources");
6961 free(Source_Map_List);
6962 free(ALmixer_Channel_List);
6963 ALmixer_Initialized = 0;
6964 Number_of_Channels_global = 0;
6965 return AL_FALSE;
6966 }
6967
6968 /* Clear the error state */
6969 alGetError();
6970 /* Generate the OpenAL sources */
6971 alGenSources(Number_of_Channels_global, source);
6972 if( (error=alGetError()) != AL_NO_ERROR)
6973 {
6974 ALmixer_SetError("Couldn't generate sources: %s\n", alGetString(error));
6975 free(ALmixer_Channel_List);
6976 free(Source_Map_List);
6977 ALmixer_Initialized = 0;
6978 Number_of_Channels_global = 0;
6979 return AL_FALSE;
6980 }
6981
6982 /* Initialize each channel and associate one source to one channel */
6983 for(i=0; i<Number_of_Channels_global; i++)
6984 {
6985 Init_Channel(i);
6986 /* Keeping the source allocation out of the Init function
6987 * in case I want to reuse the Init
6988 * function for resetting data
6989 */
6990 ALmixer_Channel_List[i].alsource = source[i];
6991 /* Now also keep a copy of the source to channel mapping
6992 * in case we need to look up a channel from the source
6993 * instead of a source from a channel
6994 */
6995 Source_Map_List[i].source = source[i];
6996 Source_Map_List[i].channel = i;
6997 /* Clean the channel because there are some things that need to
6998 * be done that can't happen until the source is set
6999 */
7000 Clean_Channel(i);
7001 }
7002
7003 /* The Source_Map_List must be sorted by source for binary searches
7004 */
7005 qsort(Source_Map_List, Number_of_Channels_global, sizeof(Source_Map), Compare_Source_Map);
7006
7007 fprintf(stderr, "Sorted Source_Map_List is:\n");
7008 for(i=0; i<Number_of_Channels_global; i++)
7009 {
7010 fprintf(stderr, "Source: %d, Channel: %d\n", Source_Map_List[i].source, Source_Map_List[i].channel);
7011 }
7012 fprintf(stderr, "\n");
7013
7014
7015
7016 #ifdef ENABLE_ALMIXER_THREADS
7017 s_simpleLock = SDL_CreateMutex();
7018 if(NULL == s_simpleLock)
7019 {
7020 /* SDL sets the error message already? */
7021 free(source);
7022 free(ALmixer_Channel_List);
7023 free(Source_Map_List);
7024 ALmixer_Initialized = 0;
7025 Number_of_Channels_global = 0;
7026 return AL_FALSE;
7027 }
7028
7029
7030 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL);
7031 if(NULL == Stream_Thread_global)
7032 {
7033 /* SDL sets the error message already? */
7034 SDL_DestroyMutex(s_simpleLock);
7035 free(source);
7036 free(ALmixer_Channel_List);
7037 free(Source_Map_List);
7038 ALmixer_Initialized = 0;
7039 Number_of_Channels_global = 0;
7040 return AL_FALSE;
7041 }
7042
7043 fprintf(stderr, "Using threads\n");
7044 #endif /* End of ENABLE_ALMIXER_THREADS */
7045
7046 /* We don't need this array any more because all the sources
7047 * are connected to channels
7048 */
7049 free(source);
7050 return AL_TRUE;
7051 }
7052
7053
7054
7055 /* Keep the return value void to allow easy use with
7056 * atexit()
7057 */
7058 void ALmixer_Quit()
7059 {
7060 ALCcontext* context;
7061 ALCdevice* dev;
7062 ALint i;
7063
7064 if( ! ALmixer_Initialized)
7065 {
7066 return;
7067 }
7068 #ifdef ENABLE_ALMIXER_THREADS
7069 SDL_LockMutex(s_simpleLock);
7070 #endif
7071 /* Shutdown everything before closing context */
7072 fprintf(stderr, "Halting channels\n");
7073 Internal_HaltChannel(-1, AL_FALSE);
7074
7075 /* This flag will cause the thread to terminate */
7076 ALmixer_Initialized = 0;
7077 #ifdef ENABLE_ALMIXER_THREADS
7078 SDL_UnlockMutex(s_simpleLock);
7079 fprintf(stderr, "Closing thread\n");
7080 SDL_WaitThread(Stream_Thread_global, NULL);
7081
7082 fprintf(stderr, "Destroying mutex\n");
7083 SDL_DestroyMutex(s_simpleLock);
7084 #endif
7085
7086 fprintf(stderr, "Deleting OpenAL sources\n");
7087 /* Delete all the OpenAL sources */
7088 for(i=0; i<Number_of_Channels_global; i++)
7089 {
7090 fprintf(stderr, "Deleting OpenAL source: %d\n", ALmixer_Channel_List[i].alsource);
7091 alDeleteSources(1, &ALmixer_Channel_List[i].alsource);
7092 }
7093 /* Delete all the channels */
7094 free(ALmixer_Channel_List);
7095 free(Source_Map_List);
7096
7097 /* Reset the Number_of_Channels just in case somebody
7098 * tries using a ALmixer function.
7099 * I probably should put "Initialized" checks everywhere,
7100 * but I'm too lazy at the moment.
7101 */
7102 Number_of_Channels_global = 0;
7103
7104 context = alcGetCurrentContext();
7105 if(NULL == context)
7106 {
7107 return;
7108 }
7109 /* Need to get the device before I close the context */
7110 dev = alcGetContextsDevice(context);
7111 alcDestroyContext(context);
7112
7113 if(NULL == dev)
7114 {
7115 return;
7116 }
7117 alcCloseDevice(dev);
7118
7119 Sound_Quit();
7120
7121 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
7122 /* Remember: ALmixer_SetError/GetError calls will not work while this is gone. */
7123 TError_FreeErrorPool(s_ALmixerErrorPool);
7124 s_ALmixerErrorPool = NULL;
7125 #endif
7126 return;
7127 }
7128
7129 ALboolean ALmixer_IsInitialized()
7130 {
7131 return ALmixer_Initialized;
7132 }
7133
7134 ALuint ALmixer_GetFrequency()
7135 {
7136 return ALmixer_Frequency_global;
7137 }
7138
7139 const ALmixer_version* ALmixer_GetLinkedVersion()
7140 {
7141 static ALmixer_version linked_mixver;
7142 ALMIXER_GET_COMPILED_VERSION(&linked_mixver);
7143 return(&linked_mixver);
7144 }
7145
7146 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
7147
7148 const char* ALmixer_GetError()
7149 {
7150 const char* error_string = NULL;
7151 if(NULL == s_ALmixerErrorPool)
7152 {
7153 return "Error: You should not call ALmixer_GetError while ALmixer is not initialized";
7154 }
7155 error_string = TError_GetLastErrorStr(s_ALmixerErrorPool);
7156 /* SDL returns empty strings instead of NULL */
7157 if(NULL == error_string)
7158 {
7159 return "";
7160 }
7161 else
7162 {
7163 return error_string;
7164 }
7165 }
7166
7167 void ALmixer_SetError(const char* err_str, ...)
7168 {
7169 if(NULL == s_ALmixerErrorPool)
7170 {
7171 fprintf(stderr, "Error: You should not call ALmixer_SetError while ALmixer is not initialized\n");
7172 return;
7173 }
7174 va_list argp;
7175 va_start(argp, err_str);
7176 // SDL_SetError which I'm emulating has no number parameter.
7177 TError_SetErrorv(s_ALmixerErrorPool, 1, err_str, argp);
7178 va_end(argp);
7179 }
7180
7181 #endif
7182
7183
7184
7185
7186 #if 0
7187 void ALmixer_OutputAttributes()
7188 {
7189 ALint num_flags = 0;
7190 ALint* flags = 0;
7191 int i;
7192 ALCdevice* dev = alcGetContextsDevice( alcGetCurrentContext() );
7193
7194
7195 printf("custom context\n");
7196
7197 alcGetIntegerv(dev, ALC_ATTRIBUTES_SIZE,
7198 sizeof num_flags, &num_flags );
7199
7200 printf("Number of Flags: %d\n", num_flags);
7201
7202 if(num_flags)
7203 {
7204 flags = malloc(sizeof(num_flags) * sizeof(ALint));
7205
7206 alcGetIntegerv(dev, ALC_ALL_ATTRIBUTES,
7207 sizeof num_flags * sizeof(ALint),
7208 flags );
7209 }
7210 for(i = 0; i < num_flags-1; i += 2)
7211 {
7212 printf("key 0x%x : value %d\n",
7213 flags[i], flags[i+1]);
7214 }
7215 free(flags);
7216 }
7217 #endif
7218
7219
7220 void ALmixer_OutputDecoders()
7221 {
7222 Sound_Version sound_compile_version;
7223 Sound_Version sound_link_version;
7224
7225 const Sound_DecoderInfo **rc = Sound_AvailableDecoders();
7226 const Sound_DecoderInfo **i;
7227 const char **ext;
7228 FILE* stream = stdout;
7229
7230
7231 fprintf(stream, "SDL_sound Information:\n");
7232
7233 SOUND_VERSION(&sound_compile_version);
7234 fprintf(stream, "\tCompiled with SDL_sound version: %d.%d.%d\n",
7235 sound_compile_version.major,
7236 sound_compile_version.minor,
7237 sound_compile_version.patch);
7238
7239 Sound_GetLinkedVersion(&sound_link_version);
7240 fprintf(stream, "\tRunning (linked) with SDL_sound version: %d.%d.%d\n",
7241 sound_link_version.major,
7242 sound_link_version.minor,
7243 sound_link_version.patch);
7244
7245 fprintf(stream, "Supported sound formats:\n");
7246 if (rc == NULL)
7247 fprintf(stream, " * Apparently, NONE!\n");
7248 else
7249 {
7250 for (i = rc; *i != NULL; i++)
7251 {
7252 fprintf(stream, " * %s\n", (*i)->description);
7253
7254 for (ext = (*i)->extensions; *ext != NULL; ext++)
7255 fprintf(stream, " File extension \"%s\"\n", *ext);
7256
7257 fprintf(stream, " Written by %s.\n %s\n\n",
7258 (*i)->author, (*i)->url);
7259 } /* for */
7260 } /* else */
7261
7262 fprintf(stream, "\n");
7263 }
7264
7265 void ALmixer_OutputOpenALInfo()
7266 {
7267 ALmixer_version mixer_compile_version;
7268 const ALmixer_version * mixer_link_version=ALmixer_GetLinkedVersion();
7269 FILE* stream = stdout;
7270
7271 fprintf(stream, "OpenAL Information:\n");
7272 fprintf(stream, "\tAL_VENDOR: %s\n", alGetString( AL_VENDOR ) );
7273 fprintf(stream, "\tAL_VERSION: %s\n", alGetString( AL_VERSION ) );
7274 fprintf(stream, "\tAL_RENDERER: %s\n", alGetString( AL_RENDERER ) );
7275 fprintf(stream, "\tAL_EXTENSIONS: %s\n", alGetString( AL_EXTENSIONS ) );
7276
7277 ALMIXER_GET_COMPILED_VERSION(&mixer_compile_version);
7278 fprintf(stream, "\nSDL_ALmixer Information:\n");
7279 fprintf(stream, "\tCompiled with SDL_ALmixer version: %d.%d.%d\n",
7280 mixer_compile_version.major,
7281 mixer_compile_version.minor,
7282 mixer_compile_version.patch);
7283
7284 fprintf(stream, "\tRunning (linked) with SDL_ALmixer version: %d.%d.%d\n",
7285 mixer_link_version->major,
7286 mixer_link_version->minor,
7287 mixer_link_version->patch);
7288
7289 fprintf(stream, "\tCompile flags: ");
7290 #ifdef ENABLE_LOKI_QUEUE_FIX_HACK
7291 fprintf(stream, "ENABLE_LOKI_QUEUE_FIX_HACK ");
7292 #endif
7293 #ifdef ENABLE_ALMIXER_THREADS
7294 fprintf(stream, "ENABLE_ALMIXER_THREADS ");
7295 #endif
7296 #ifdef ENABLE_ALC_SYNC
7297 fprintf(stream, "ENABLE_ALC_SYNC ");
7298 #endif
7299 fprintf(stream, "\n");
7300 }
7301
7302
7303 ALint ALmixer_AllocateChannels(ALint numchans)
7304 {
7305 ALint retval;
7306 #ifdef ENABLE_ALMIXER_THREADS
7307 SDL_LockMutex(s_simpleLock);
7308 #endif
7309 retval = Internal_AllocateChannels(numchans);
7310 #ifdef ENABLE_ALMIXER_THREADS
7311 SDL_UnlockMutex(s_simpleLock);
7312 #endif
7313 return retval;
7314 }
7315
7316
7317 ALint ALmixer_ReserveChannels(ALint num)
7318 {
7319 ALint retval;
7320 #ifdef ENABLE_ALMIXER_THREADS
7321 SDL_LockMutex(s_simpleLock);
7322 #endif
7323 retval = Internal_ReserveChannels(num);
7324 #ifdef ENABLE_ALMIXER_THREADS
7325 SDL_UnlockMutex(s_simpleLock);
7326 #endif
7327 return retval;
7328 }
7329
7330
7331
7332
7333 static ALmixer_Data* DoLoad(Sound_Sample* sample, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data)
7334 {
7335 ALuint bytes_decoded;
7336 ALmixer_Data* ret_data;
7337 ALenum error;
7338
7339 /* Allocate memory */
7340 ret_data = (ALmixer_Data *)malloc(sizeof(ALmixer_Data));
7341 if (NULL == ret_data)
7342 {
7343 ALmixer_SetError("Out of memory");
7344 return(NULL);
7345 }
7346
7347 /* Initialize the data fields */
7348
7349 /* Set the Sound_Sample pointer */
7350 ret_data->sample = sample;
7351
7352 /* Flag the data to note that it is not in use */
7353 ret_data->in_use = 0;
7354
7355 /* Initialize remaining flags */
7356 ret_data->total_time = -1;
7357 ret_data->eof = 0;
7358
7359 /* Just initialize */
7360 ret_data->num_buffers_in_use = 0;
7361
7362 /* Just initialize */
7363 ret_data->total_bytes = 0;
7364
7365 /* Just initialize */
7366 ret_data->loaded_bytes = 0;
7367
7368 /* Set the max queue buffers (minimum must be 2) */
7369 if(max_queue_buffers < 2)
7370 {
7371 max_queue_buffers = ALMIXER_DEFAULT_QUEUE_BUFFERS;
7372 }
7373 ret_data->max_queue_buffers = max_queue_buffers;
7374 /* Set up the start up buffers */
7375 if(0 == num_startup_buffers)
7376 {
7377 num_startup_buffers = ALMIXER_DEFAULT_STARTUP_BUFFERS;
7378 }
7379 /* Make sure start up buffers is less or equal to max_queue_buffers */
7380 if(num_startup_buffers > max_queue_buffers)
7381 {
7382 num_startup_buffers = max_queue_buffers;
7383 }
7384 ret_data->num_startup_buffers = num_startup_buffers;
7385
7386 ret_data->buffer_map_list = NULL;
7387 ret_data->current_buffer = 0;
7388
7389 ret_data->circular_buffer_queue = NULL;
7390
7391 /* Now decode and load the data into a data chunk */
7392 /* Different cases for Streamed and Predecoded
7393 * Streamed might turn into a predecoded if buffersize
7394 * is large enough */
7395 if(AL_FALSE == decode_mode_is_predecoded)
7396 {
7397 bytes_decoded = Sound_Decode(sample);
7398 if(sample->flags & SOUND_SAMPLEFLAG_ERROR)
7399 {
7400 ALmixer_SetError(Sound_GetError());
7401 Sound_FreeSample(sample);
7402 free(ret_data);
7403 return NULL;
7404 }
7405
7406 /* If no data, return an error */
7407 if(0 == bytes_decoded)
7408 {
7409 ALmixer_SetError("File has no data");
7410 Sound_FreeSample(sample);
7411 free(ret_data);
7412 return NULL;
7413 }
7414
7415 /* Note, currently, my Ogg conservative modifications
7416 * prevent EOF from being detected in the first read
7417 * because of the weird packet behavior of ov_read().
7418 * The EAGAIN will get set, but not the EOF.
7419 * I don't know the best way to handle this,
7420 * so for now, Ogg's can only be explicitly
7421 * predecoded.
7422 */
7423
7424 /* Correction: Since we no longer actually keep the
7425 * streamed data we read here (we rewind and throw
7426 * it away, and start over on Play), it is
7427 * safe to read another chunk to see if we've hit EOF
7428 */
7429 if(sample->flags & SOUND_SAMPLEFLAG_EAGAIN)
7430 {
7431 bytes_decoded = Sound_Decode(sample);
7432 if(sample->flags & SOUND_SAMPLEFLAG_ERROR)
7433 {
7434 ALmixer_SetError(Sound_GetError());
7435 Sound_FreeSample(sample);
7436 free(ret_data);
7437 return NULL;
7438 }
7439 }
7440
7441
7442 /* If we found an EOF, the entire file was
7443 * decoded, so we can treat it like one.
7444 */
7445
7446 if(sample->flags & SOUND_SAMPLEFLAG_EOF)
7447 {
7448 fprintf(stderr, "We got LUCKY! File is predecoded even though STREAM was requested\n");
7449
7450 ret_data->decoded_all = 1;
7451 /* Need to keep this information around for
7452 * seek and rewind abilities.
7453 */
7454 ret_data->total_bytes = bytes_decoded;
7455 /* For now, the loaded bytes is the same as total bytes, but
7456 * this could change during a seek operation
7457 */
7458 ret_data->loaded_bytes = bytes_decoded;
7459
7460 /* Let's compute the total playing time
7461 * SDL_sound does not yet provide this (we're working on
7462 * that at the moment...)
7463 */
7464 ret_data->total_time = Compute_Total_Time(&sample->desired, bytes_decoded);
7465
7466 /* Create one element in the buffer array for data for OpanAL */
7467 ret_data->buffer = (ALuint*)malloc( sizeof(ALuint) );
7468 if(NULL == ret_data->buffer)
7469 {
7470 ALmixer_SetError("Out of Memory");
7471 Sound_FreeSample(sample);
7472 free(ret_data);
7473 return NULL;
7474 }
7475 /* Clear the error code */
7476 alGetError();
7477 /* Now generate an OpenAL buffer using that first element */
7478 alGenBuffers(1, ret_data->buffer);
7479 if( (error = alGetError()) != AL_NO_ERROR)
7480 {
7481 ALmixer_SetError("alGenBuffers failed: %s\n", alGetString(error));
7482 Sound_FreeSample(sample);
7483 free(ret_data->buffer);
7484 free(ret_data);
7485 return NULL;
7486 }
7487
7488
7489 /* Now copy the data to the OpenAL buffer */
7490 /* We can't just set a pointer because the API needs
7491 * its own copy to assist hardware acceleration */
7492 alBufferData(ret_data->buffer[0],
7493 TranslateFormat(&sample->desired),
7494 sample->buffer,
7495 bytes_decoded,
7496 sample->desired.rate
7497 );
7498 if( (error = alGetError()) != AL_NO_ERROR)
7499 {
7500 ALmixer_SetError("alBufferData failed: %s\n", alGetString(error));
7501 Sound_FreeSample(sample);
7502 alDeleteBuffers(1, ret_data->buffer);
7503 free(ret_data->buffer);
7504 free(ret_data);
7505 return NULL;
7506 }
7507
7508 /* We should be done with the sample since it's all
7509 * predecoded. So we can free the memory */
7510
7511 /* Additional notes:
7512 * We need to keep data around in case Seek() is needed
7513 * or other Sound_AudioInfo is needed.
7514 * This can either be done by not deleting the sample,
7515 * or it can be done by dynamically recreating it
7516 * when we need it.
7517 */
7518 /* Since OpenAL won't let us retrieve it
7519 * (aka dynamically), we have to keep the Sample
7520 * around because since the user requested
7521 * streamed and we offered predecoded,
7522 * we don't want to mess up the user who
7523 * was expecting seek support
7524 * So Don't Do anything
7525 */
7526 /*
7527 if(0 == access_data)
7528 {
7529 Sound_FreeSample(sample);
7530 ret_data->sample = NULL;
7531 }
7532 */
7533 /* Else, We keep a copy of the sample around.
7534 * so don't do anything.
7535 */
7536
7537 #if 0
7538 #if defined(DISABLE_PREDECODED_SEEK)
7539 Sound_FreeSample(sample);
7540 ret_data->sample = NULL;
7541 #elif !defined(DISABLE_SEEK_MEMORY_OPTIMIZATION)
7542 Sound_FreeSample(sample);
7543 ret_data->sample = NULL;
7544 #else
7545 /* We keep a copy of the sample around.
7546 * so don't do anything.
7547 */
7548 #endif
7549 #endif
7550 /* okay we're done here */
7551
7552 }
7553 /* Else, we need to stream the data, so we'll
7554 * create multple buffers for queuing */
7555 else
7556 {
7557 fprintf(stderr, "Loading streamed data (not lucky)\n");
7558 ret_data->decoded_all = 0;
7559
7560 /* This information is for predecoded.
7561 * Set to 0, since we don't know.
7562 */
7563 ret_data->total_bytes = 0;
7564
7565 /* Create buffers for data
7566 */
7567 ret_data->buffer = (ALuint*)malloc( sizeof(ALuint) * max_queue_buffers);
7568 if(NULL == ret_data->buffer)
7569 {
7570 ALmixer_SetError("Out of Memory");
7571 Sound_FreeSample(sample);
7572 free(ret_data);
7573 return NULL;
7574 }
7575
7576 /* Clear the error code */
7577 alGetError();
7578 /* Now generate an OpenAL buffer using that first element */
7579 alGenBuffers(max_queue_buffers, ret_data->buffer);
7580 if( (error = alGetError()) != AL_NO_ERROR)
7581 {
7582 ALmixer_SetError("alGenBuffers failed: %s\n", alGetString(error));
7583 Sound_FreeSample(sample);
7584 free(ret_data->buffer);
7585 free(ret_data);
7586 return NULL;
7587 }
7588
7589 /* Redesign: Okay, because of the unqueuing problems and such,
7590 * I've decided to redesign where and how queuing is handled.
7591 * Before, everything was queued up here. However, this
7592 * placed a penalty on load and made performance inconsistent
7593 * when samples had to be rewound. It did make things easier
7594 * to queue because I could let OpenAL decide which buffer
7595 * needed to be queued next.
7596 * Now, I'm going to push off the queuing to the actual
7597 * Play() command. I'm going to add some book keeping,
7598 * and allow for additional buffers to be filled at later
7599 * times.
7600 */
7601
7602
7603 /* So first of all, because of I already decoded the sample
7604 * for testing, I need to decide what to do with it.
7605 * The best thing would be be to alBufferData() it.
7606 * The problem is it may conflict with the rest of
7607 * the system because everything now assumes buffers
7608 * are entirely stripped (because of the unqueing
7609 * problem).
7610 * So it looks like I have to do the crappy thing
7611 * and throw away the data, and rewind.
7612 */
7613
7614 if(0 == Sound_Rewind(ret_data->sample))
7615 {
7616 ALmixer_SetError("Cannot use sample for streamed data because it must be rewindable: %s", Sound_GetError() );
7617 Sound_FreeSample(sample);
7618 free(ret_data->buffer);
7619 free(ret_data);
7620 return NULL;
7621 }
7622
7623
7624 /* If the user has selected access_data, we need to
7625 * keep copies of the queuing buffers around because
7626 * OpenAL won't let us access the data.
7627 * Allocate the memory for the buffers here
7628 * and initialize the albuffer-index map
7629 */
7630 if(access_data)
7631 {
7632 ALuint j;
7633 /* Create buffers for data access
7634 * Should be the same number as the number of queue buffers
7635 */
7636 ret_data->buffer_map_list = (ALmixer_Buffer_Map*)malloc( sizeof(ALmixer_Buffer_Map) * max_queue_buffers);
7637 if(NULL == ret_data->buffer_map_list)
7638 {
7639 ALmixer_SetError("Out of Memory");
7640 Sound_FreeSample(sample);
7641 free(ret_data->buffer);
7642 free(ret_data);
7643 return NULL;
7644 }
7645
7646 ret_data->circular_buffer_queue = CircularQueueUnsignedInt_CreateQueue(max_queue_buffers);
7647 if(NULL == ret_data->circular_buffer_queue)
7648 {
7649 ALmixer_SetError("Out of Memory");
7650 free(ret_data->buffer_map_list);
7651 Sound_FreeSample(sample);
7652 free(ret_data->buffer);
7653 free(ret_data);
7654 return NULL;
7655 }
7656
7657
7658 for(j=0; j<max_queue_buffers; j++)
7659 {
7660 ret_data->buffer_map_list[j].albuffer = ret_data->buffer[j];
7661 ret_data->buffer_map_list[j].index = j;
7662 ret_data->buffer_map_list[j].num_bytes = 0;
7663 ret_data->buffer_map_list[j].data = (ALbyte*)malloc( sizeof(ALbyte) * buffersize);
7664 if(NULL == ret_data->buffer_map_list[j].data)
7665 {
7666 ALmixer_SetError("Out of Memory");
7667 break;
7668 }
7669 }
7670 /* If an error happened, we have to clean up the memory */
7671 if(j < max_queue_buffers)
7672 {
7673 fprintf(stderr, "################## Buffer allocation failed\n");
7674 for( ; j>=0; j--)
7675 {
7676 free(ret_data->buffer_map_list[j].data);
7677 }
7678 free(ret_data->buffer_map_list);
7679 CircularQueueUnsignedInt_FreeQueue(ret_data->circular_buffer_queue);
7680 Sound_FreeSample(sample);
7681 free(ret_data->buffer);
7682 free(ret_data);
7683 return NULL;
7684 }
7685
7686 /* The Buffer_Map_List must be sorted by albuffer for binary searches
7687 */
7688 qsort(ret_data->buffer_map_list, max_queue_buffers, sizeof(ALmixer_Buffer_Map), Compare_Buffer_Map);
7689 } /* End if access_data==true */
7690
7691
7692 } /* End of do stream */
7693 } /* end of DECODE_STREAM */
7694 /* User requested decode all (easy, nothing to figure out) */
7695 else if(AL_TRUE == decode_mode_is_predecoded)
7696 {
7697 #ifndef ALMIXER_DISABLE_PREDECODED_PRECOMPUTE_BUFFER_SIZE_OPTIMIZATION
7698 /* SDL_sound (behind the scenes) seems to loop on buffer_size chunks
7699 * until the buffer is filled. It seems like we can
7700 * do much better and precompute the size of the buffer
7701 * so looping isn't needed.
7702 * WARNING: Due to the way SDL_sound is currently implemented,
7703 * this may waste a lot of memory up front.
7704 * SDL_sound seems to pre-create a buffer of the requested size,
7705 * but on DecodeAll, an entirely new buffer is created and
7706 * everything is memcpy'd into the new buffer in read chunks
7707 * of the buffer_size. This means we need roughly twice the memory
7708 * to load a file.
7709 */
7710 ALint sound_duration = Sound_GetDuration(sample);
7711 if(sound_duration > 0)
7712 {
7713 size_t total_bytes = Compute_Total_Bytes_With_Frame_Padding(&sample->desired, (ALuint)sound_duration);
7714 int buffer_resize_succeeded = Sound_SetBufferSize(sample, total_bytes);
7715 if(0 == buffer_resize_succeeded)
7716 {
7717 ALmixer_SetError(Sound_GetError());
7718 Sound_FreeSample(sample);
7719 free(ret_data);
7720 return NULL;
7721 }
7722 }
7723 #endif /* ALMIXER_DISABLE_PREDECODED_PRECOMPUTE_BUFFER_SIZE_OPTIMIZATION */
7724 bytes_decoded = Sound_DecodeAll(sample);
7725 if(sample->flags & SOUND_SAMPLEFLAG_ERROR)
7726 {
7727 ALmixer_SetError(Sound_GetError());
7728 Sound_FreeSample(sample);
7729 free(ret_data);
7730 return NULL;
7731 }
7732
7733 /* If no data, return an error */
7734 if(0 == bytes_decoded)
7735 {
7736 ALmixer_SetError("File has no data");
7737 Sound_FreeSample(sample);
7738 free(ret_data);
7739 return NULL;
7740 }
7741
7742
7743 ret_data->decoded_all = 1;
7744 /* Need to keep this information around for
7745 * seek and rewind abilities.
7746 */
7747 ret_data->total_bytes = bytes_decoded;
7748 /* For now, the loaded bytes is the same as total bytes, but
7749 * this could change during a seek operation
7750 */
7751 ret_data->loaded_bytes = bytes_decoded;
7752
7753 /* Let's compute the total playing time
7754 * SDL_sound does not yet provide this (we're working on
7755 * that at the moment...)
7756 */
7757 ret_data->total_time = Compute_Total_Time(&sample->desired, bytes_decoded);
7758
7759 /* Create one element in the buffer array for data for OpanAL */
7760 ret_data->buffer = (ALuint*)malloc( sizeof(ALuint) );
7761 if(NULL == ret_data->buffer)
7762 {
7763 ALmixer_SetError("Out of Memory");
7764 Sound_FreeSample(sample);
7765 free(ret_data);
7766 return NULL;
7767 }
7768 /* Clear the error code */
7769 alGetError();
7770 /* Now generate an OpenAL buffer using that first element */
7771 alGenBuffers(1, ret_data->buffer);
7772 if( (error = alGetError()) != AL_NO_ERROR)
7773 {
7774 ALmixer_SetError("alGenBuffers failed: %s\n", alGetString(error));
7775 Sound_FreeSample(sample);
7776 free(ret_data->buffer);
7777 free(ret_data);
7778 return NULL;
7779 }
7780 fprintf(stderr, "Actual rate=%d, desired=%d\n", sample->actual.rate, sample->desired.rate);
7781
7782 /* Now copy the data to the OpenAL buffer */
7783 /* We can't just set a pointer because the API needs
7784 * its own copy to assist hardware acceleration */
7785 alBufferData(ret_data->buffer[0],
7786 TranslateFormat(&sample->desired),
7787 sample->buffer,
7788 bytes_decoded,
7789 sample->desired.rate
7790 );
7791 if( (error = alGetError()) != AL_NO_ERROR)
7792 {
7793 ALmixer_SetError("alBufferData failed: %s\n", alGetString(error));
7794 Sound_FreeSample(sample);
7795 alDeleteBuffers(1, ret_data->buffer);
7796 free(ret_data->buffer);
7797 free(ret_data);
7798 return NULL;
7799 }
7800
7801 /* We should be done with the sample since it's all
7802 * predecoded. So we can free the memory */
7803 /* Need to keep around because Seek() needs it */
7804
7805 /* Additional notes:
7806 * We need to keep data around in case Seek() is needed
7807 * or other Sound_AudioInfo is needed.
7808 * This can either be done by not deleting the sample,
7809 * or it can be done by dynamically recreating it
7810 * when we need it.
7811 * Update: I think now it's up to the user by passing the
7812 * access_data flag. If they set the flag, then they get
7813 * data callbacks and seek support. If not, then they can
7814 * get all that stuff at the expense of keeping extra memory
7815 * around.
7816 */
7817 if(0 == access_data)
7818 {
7819 Sound_FreeSample(sample);
7820 ret_data->sample = NULL;
7821 }
7822
7823 /* Else, We keep a copy of the sample around.
7824 * so don't do anything.
7825 */
7826 #if 0
7827 #if defined(DISABLE_PREDECODED_SEEK)
7828 Sound_FreeSample(sample);
7829 ret_data->sample = NULL;
7830 #elif !defined(DISABLE_SEEK_MEMORY_OPTIMIZATION)
7831 Sound_FreeSample(sample);
7832 ret_data->sample = NULL;
7833 #else
7834 /* We keep a copy of the sample around.
7835 * so don't do anything.
7836 */
7837 #endif
7838 #endif
7839
7840 fprintf(stderr, "Made it\n");
7841 /* okay we're done here */
7842 }
7843 else
7844 {
7845 /* Shouldn't get here */
7846 ALmixer_SetError("Unknown decode mode");
7847 Sound_FreeSample(sample);
7848 free(ret_data);
7849 return NULL;
7850 }
7851
7852 fprintf(stderr, "Returning data\n");
7853 return ret_data;
7854 }
7855
7856
7857 /* This will load a sample for us. Most of the uglyness is
7858 * error checking and the fact that streamed/predecoded files
7859 * must be treated differently.
7860 * I don't like the AudioInfo parameter. I removed it once,
7861 * but the system will fail on RAW samples because the user
7862 * must specify it, so I had to bring it back.
7863 * Remember I must close the rwops if there is an error before NewSample()
7864 */
7865 ALmixer_Data* ALmixer_LoadSample_RW(ALmixer_RWops* rwops, const char* fileext, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data)
7866 {
7867 Sound_Sample* sample = NULL;
7868 Sound_AudioInfo target;
7869
7870 /* Initialize target values to defaults
7871 * 0 tells SDL_sound to use the "actual" values
7872 */
7873 target.channels = 0;
7874 target.rate = 0;
7875 #if 0
7876 /* This requires my new additions to SDL_sound. It will
7877 * convert the sample to the proper endian order.
7878 * If the actual is 8-bit, it will do unsigned, if
7879 * the actual is 16-bit, it will do signed.
7880 * I'm told by Ryan Gordon that OpenAL prefers the signedness
7881 * in this way.
7882 */
7883 target.format = AUDIO_U8S16SYS;
7884 #else
7885 target.format = AUDIO_S16SYS;
7886 #endif
7887
7888 /* Set a default buffersize if needed */
7889 if(0 == buffersize)
7890 {
7891 buffersize = ALMIXER_DEFAULT_BUFFERSIZE;
7892 }
7893
7894 sample = Sound_NewSample(rwops, fileext, &target, buffersize);
7895 if(NULL == sample)
7896 {
7897 ALmixer_SetError(Sound_GetError());
7898 return NULL;
7899 }
7900
7901 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
7902 }
7903
7904
7905
7906 /* This will load a sample for us from
7907 * a file (instead of RWops). Most of the uglyness is
7908 * error checking and the fact that streamed/predecoded files
7909 * must be treated differently.
7910 */
7911 ALmixer_Data* ALmixer_LoadSample(const char* filename, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data)
7912 {
7913 Sound_Sample* sample = NULL;
7914 Sound_AudioInfo target;
7915
7916 /* Initialize target values to defaults
7917 * 0 tells SDL_sound to use the "actual" values
7918 */
7919 target.channels = 0;
7920 target.rate = 0;
7921
7922 #if 0
7923 /* This requires my new additions to SDL_sound. It will
7924 * convert the sample to the proper endian order.
7925 * If the actual is 8-bit, it will do unsigned, if
7926 * the actual is 16-bit, it will do signed.
7927 * I'm told by Ryan Gordon that OpenAL prefers the signedness
7928 * in this way.
7929 */
7930 target.format = AUDIO_U8S16SYS;
7931 #else
7932 target.format = AUDIO_S16SYS;
7933 #endif
7934
7935 #if 0
7936 /* Okay, here's a messy hack. The problem is that we need
7937 * to convert the sample to have the correct bitdepth,
7938 * endian order, and signedness values.
7939 * The bit depth is 8 or 16.
7940 * The endian order is the native order of the system.
7941 * The signedness depends on what the original value
7942 * of the sample. Unfortunately, we can't specify these
7943 * values until we after we already know what the original
7944 * values were for bitdepth and signedness.
7945 * So we must open the file once to get the values,
7946 * then close it, and then reopen it with the
7947 * correct desired target values.
7948 * I tried changing the sample->desired field after
7949 * the NewSample call, but it had no effect, so
7950 * it looks like it must be set on open.
7951 */
7952 /* Pick a small buffersize for the first open to not
7953 * waste much time allocating memory */
7954 sample = Sound_NewSampleFromFile(filename, NULL, 512);
7955 if(NULL == sample)
7956 {
7957 ALmixer_SetError(Sound_GetError());
7958 return NULL;
7959 }
7960
7961 bit_depth = GetBitDepth(sample->actual.format);
7962 signedness_value = GetSignednessValue(sample->actual.format);
7963 if(8 == bit_depth)
7964 {
7965 /* If 8 bit, then we don't have to worry about
7966 * endian issues. We can just use the actual format
7967 * value and it should do the right thing
7968 */
7969 target.format = sample->actual.format;
7970 }
7971 else
7972 {
7973 /* We'll assume it's 16-bit, and if it's not
7974 * hopefully SDL_sound will return an error,
7975 * or let us convert to 16-bit
7976 */
7977 /* Now we need to get the correct signedness */
7978 if(ALMIXER_UNSIGNED_VALUE == signedness_value)
7979 {
7980 /* Set to Unsigned 16-bit, system endian order */
7981 target.format = AUDIO_U16SYS;
7982 }
7983 else
7984 {
7985 /* Again, we'll assume it's Signed 16-bit system order
7986 * or force the conversion and hope it works out
7987 */
7988 target.format = AUDIO_S16SYS;
7989 }
7990 }
7991
7992 /* Now we have the correct info. We need to close and reopen */
7993 Sound_FreeSample(sample);
7994 #endif
7995
7996 sample = Sound_NewSampleFromFile(filename, &target, buffersize);
7997 if(NULL == sample)
7998 {
7999 ALmixer_SetError(Sound_GetError());
8000 return NULL;
8001 }
8002
8003 fprintf(stderr, "Correction test: Actual rate=%d, desired=%d, actual format=%d, desired format=%d\n", sample->actual.rate, sample->desired.rate, sample->actual.format, sample->desired.format);
8004
8005 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
8006 }
8007
8008
8009 /* This is a back door for RAW samples or if you need the
8010 * AudioInfo field. Use at your own risk.
8011 */
8012 ALmixer_Data* ALmixer_LoadSample_RAW_RW(ALmixer_RWops* rwops, const char* fileext, ALmixer_AudioInfo* desired, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data)
8013 {
8014 Sound_Sample* sample = NULL;
8015 Sound_AudioInfo sound_desired;
8016 /* Rather than copying the data from struct to struct, I could just
8017 * cast the thing since the structs are meant to be identical.
8018 * But if SDL_sound changes it's implementation, bad things
8019 * will probably happen. (Or if I change my implementation and
8020 * forget about the cast, same bad scenario.) Since this is a load
8021 * function, performance of this is negligible.
8022 */
8023 if(NULL == desired)
8024 {
8025 sample = Sound_NewSample(rwops, fileext, NULL, buffersize);
8026 }
8027 else
8028 {
8029 sound_desired.format = desired->format;
8030 sound_desired.channels = desired->channels;
8031 sound_desired.rate = desired->rate;
8032 sample = Sound_NewSample(rwops, fileext, &sound_desired, buffersize);
8033 }
8034 if(NULL == sample)
8035 {
8036 ALmixer_SetError(Sound_GetError());
8037 return NULL;
8038 }
8039 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
8040 }
8041
8042
8043
8044
8045 /* This is a back door for RAW samples or if you need the
8046 * AudioInfo field. Use at your own risk.
8047 */
8048 ALmixer_Data* ALmixer_LoadSample_RAW(const char* filename, ALmixer_AudioInfo* desired, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data)
8049 {
8050 Sound_Sample* sample = NULL;
8051 Sound_AudioInfo sound_desired;
8052 /* Rather than copying the data from struct to struct, I could just
8053 * cast the thing since the structs are meant to be identical.
8054 * But if SDL_sound changes it's implementation, bad things
8055 * will probably happen. (Or if I change my implementation and
8056 * forget about the cast, same bad scenario.) Since this is a load
8057 * function, performance of this is negligible.
8058 */
8059 if(NULL == desired)
8060 {
8061 sample = Sound_NewSampleFromFile(filename, NULL, buffersize);
8062 }
8063 else
8064 {
8065 sound_desired.format = desired->format;
8066 sound_desired.channels = desired->channels;
8067 sound_desired.rate = desired->rate;
8068 sample = Sound_NewSampleFromFile(filename, &sound_desired, buffersize);
8069 }
8070
8071 if(NULL == sample)
8072 {
8073 ALmixer_SetError(Sound_GetError());
8074 return NULL;
8075 }
8076 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
8077 }
8078
8079
8080
8081
8082 void ALmixer_FreeData(ALmixer_Data* data)
8083 {
8084 ALenum error;
8085 if(NULL == data)
8086 {
8087 return;
8088 }
8089
8090 if(data->decoded_all)
8091 {
8092 /* If access_data was enabled, then the Sound_Sample*
8093 * still exists. We need to free it
8094 */
8095 if(data->sample != NULL)
8096 {
8097 Sound_FreeSample(data->sample);
8098 }
8099 alDeleteBuffers(1, data->buffer);
8100 if((error = alGetError()) != AL_NO_ERROR)
8101 {
8102 fprintf(stderr, "70Testing error: %s\n",
8103 alGetString(error));
8104 }
8105
8106 }
8107 else
8108 {
8109 ALuint i;
8110
8111 /* Delete buffer copies if access_data was enabled */
8112 if(data->buffer_map_list != NULL)
8113 {
8114 for(i=0; i<data->max_queue_buffers; i++)
8115 {
8116 free(data->buffer_map_list[i].data);
8117 }
8118 free(data->buffer_map_list);
8119 }
8120 if(data->circular_buffer_queue != NULL)
8121 {
8122 CircularQueueUnsignedInt_FreeQueue(data->circular_buffer_queue);
8123 }
8124
8125 Sound_FreeSample(data->sample);
8126 alDeleteBuffers(data->max_queue_buffers, data->buffer);
8127 if((error = alGetError()) != AL_NO_ERROR)
8128 {
8129 fprintf(stderr, "71Testing error: %s\n",
8130 alGetString(error));
8131 }
8132 }
8133 free(data->buffer);
8134 free(data);
8135 }
8136
8137 ALint ALmixer_GetTotalTime(ALmixer_Data* data)
8138 {
8139 if(NULL == data)
8140 {
8141 return -1;
8142 }
8143 return data->total_time;
8144 }
8145
8146 /* This function will look up the source for the corresponding channel */
8147 /* Must return 0 on error instead of -1 because of unsigned int */
8148 ALuint ALmixer_GetSource(ALint channel)
8149 {
8150 ALuint retval;
8151 #ifdef ENABLE_ALMIXER_THREADS
8152 SDL_LockMutex(s_simpleLock);
8153 #endif
8154 retval = Internal_GetSource(channel);
8155 #ifdef ENABLE_ALMIXER_THREADS
8156 SDL_UnlockMutex(s_simpleLock);
8157 #endif
8158 return retval;
8159 }
8160
8161 /* This function will look up the channel for the corresponding source */
8162 ALint ALmixer_GetChannel(ALuint source)
8163 {
8164 ALint retval;
8165 #ifdef ENABLE_ALMIXER_THREADS
8166 SDL_LockMutex(s_simpleLock);
8167 #endif
8168 retval = Internal_GetChannel(source);
8169 #ifdef ENABLE_ALMIXER_THREADS
8170 SDL_UnlockMutex(s_simpleLock);
8171 #endif
8172 return retval;
8173 }
8174
8175 ALint ALmixer_FindFreeChannel(ALint start_channel)
8176 {
8177 ALint retval;
8178 #ifdef ENABLE_ALMIXER_THREADS
8179 SDL_LockMutex(s_simpleLock);
8180 #endif
8181 retval = Internal_FindFreeChannel(start_channel);
8182 #ifdef ENABLE_ALMIXER_THREADS
8183 SDL_UnlockMutex(s_simpleLock);
8184 #endif
8185 return retval;
8186 }
8187
8188
8189
8190 /* API update function.
8191 * It should return the number of buffers that were
8192 * queued during the call. The value might be
8193 * used to guage how long you might wait to
8194 * call the next update loop in case you are worried
8195 * about preserving CPU cycles. The idea is that
8196 * when a buffer is queued, there was probably some
8197 * CPU intensive looping which took awhile.
8198 * It's mainly provided as a convenience.
8199 * Timing the call with ALmixer_GetTicks() would produce
8200 * more accurate information.
8201 * Returns a negative value if there was an error,
8202 * the value being the number of errors.
8203 */
8204 ALint ALmixer_Update()
8205 {
8206 #ifdef ENABLE_ALMIXER_THREADS
8207 /* The thread will handle all updates by itself.
8208 * Don't allow the user to explicitly call update.
8209 */
8210 return 0;
8211 #else
8212 return( Update_ALmixer(NULL) );
8213 #endif
8214 }
8215
8216
8217
8218 void ALmixer_SetPlaybackFinishedCallback(void (*playback_finished_callback)(ALint which_channel, ALuint al_source, ALmixer_Data* almixer_data, ALboolean finished_naturally, void* user_data), void* user_data)
8219 {
8220 #ifdef ENABLE_ALMIXER_THREADS
8221 SDL_LockMutex(s_simpleLock);
8222 #endif
8223 Channel_Done_Callback = playback_finished_callback;
8224 Channel_Done_Callback_Userdata = user_data;
8225 #ifdef ENABLE_ALMIXER_THREADS
8226 SDL_UnlockMutex(s_simpleLock);
8227 #endif
8228 }
8229
8230
8231 void ALmixer_SetPlaybackDataCallback(void (*playback_data_callback)(ALint which_chan, ALuint al_source, ALbyte* data, ALuint num_bytes, ALuint frequency, ALubyte channels, ALubyte bit_depth, ALboolean is_unsigned, ALboolean decode_mode_is_predecoded, ALuint length_in_msec, void* user_data), void* user_data)
8232 {
8233 #ifdef ENABLE_ALMIXER_THREADS
8234 SDL_LockMutex(s_simpleLock);
8235 #endif
8236 Channel_Data_Callback = playback_data_callback;
8237 Channel_Data_Callback_Userdata = user_data;
8238 #ifdef ENABLE_ALMIXER_THREADS
8239 SDL_UnlockMutex(s_simpleLock);
8240 #endif
8241 }
8242
8243
8244
8245
8246
8247 ALint ALmixer_PlayChannelTimed(ALint channel, ALmixer_Data* data, ALint loops, ALint ticks)
8248 {
8249 ALint retval;
8250 #ifdef ENABLE_ALMIXER_THREADS
8251 SDL_LockMutex(s_simpleLock);
8252 #endif
8253 retval = Internal_PlayChannelTimed(channel, data, loops, ticks);
8254 #ifdef ENABLE_ALMIXER_THREADS
8255 SDL_UnlockMutex(s_simpleLock);
8256 #endif
8257 return retval;
8258 }
8259
8260
8261 /* In case the user wants to specify a source instead of a channel,
8262 * they may use this function. This function will look up the
8263 * source-to-channel map, and convert the call into a
8264 * PlayChannelTimed() function call.
8265 * Returns the channel it's being played on.
8266 * Note: If you are prefer this method, then you need to be careful
8267 * about using PlayChannel, particularly if you request the
8268 * first available channels because source and channels have
8269 * a one-to-one mapping in this API. It is quite easy for
8270 * a channel/source to already be in use because of this.
8271 * In this event, an error message will be returned to you.
8272 */
8273 ALuint ALmixer_PlaySourceTimed(ALuint source, ALmixer_Data* data, ALint loops, ALint ticks)
8274 {
8275 ALuint retval;
8276 #ifdef ENABLE_ALMIXER_THREADS
8277 SDL_LockMutex(s_simpleLock);
8278 #endif
8279 retval = Internal_PlaySourceTimed(source, data, loops, ticks);
8280 #ifdef ENABLE_ALMIXER_THREADS
8281 SDL_UnlockMutex(s_simpleLock);
8282 #endif
8283 return retval;
8284 }
8285
8286
8287 /* Will return the number of channels halted
8288 * or 0 for error
8289 */
8290 ALint ALmixer_HaltChannel(ALint channel)
8291 {
8292 ALint retval;
8293 #ifdef ENABLE_ALMIXER_THREADS
8294 SDL_LockMutex(s_simpleLock);
8295 #endif
8296 retval = Internal_HaltChannel(channel, AL_FALSE);
8297 #ifdef ENABLE_ALMIXER_THREADS
8298 SDL_UnlockMutex(s_simpleLock);
8299 #endif
8300 return retval;
8301 }
8302
8303 /* Will return the number of channels halted
8304 * or 0 for error
8305 */
8306 ALint ALmixer_HaltSource(ALuint source)
8307 {
8308 ALint retval;
8309 #ifdef ENABLE_ALMIXER_THREADS
8310 SDL_LockMutex(s_simpleLock);
8311 #endif
8312 retval = Internal_HaltSource(source, AL_FALSE);
8313 #ifdef ENABLE_ALMIXER_THREADS
8314 SDL_UnlockMutex(s_simpleLock);
8315 #endif
8316 return retval;
8317 }
8318
8319
8320 /* This will rewind the SDL_Sound sample for streamed
8321 * samples and start buffering up the data for the next
8322 * playback. This may require samples to be halted
8323 */
8324 ALint ALmixer_RewindData(ALmixer_Data* data)
8325 {
8326 ALint retval;
8327 #ifdef ENABLE_ALMIXER_THREADS
8328 SDL_LockMutex(s_simpleLock);
8329 #endif
8330 retval = Internal_RewindData(data);
8331 #ifdef ENABLE_ALMIXER_THREADS
8332 SDL_UnlockMutex(s_simpleLock);
8333 #endif
8334 return retval;
8335 }
8336
8337 ALint ALmixer_RewindChannel(ALint channel)
8338 {
8339 ALint retval;
8340 #ifdef ENABLE_ALMIXER_THREADS
8341 SDL_LockMutex(s_simpleLock);
8342 #endif
8343 retval = Internal_RewindChannel(channel);
8344 #ifdef ENABLE_ALMIXER_THREADS
8345 SDL_UnlockMutex(s_simpleLock);
8346 #endif
8347 return retval;
8348 }
8349
8350 ALint ALmixer_RewindSource(ALuint source)
8351 {
8352 ALint retval;
8353 #ifdef ENABLE_ALMIXER_THREADS
8354 SDL_LockMutex(s_simpleLock);
8355 #endif
8356 retval = Internal_RewindSource(source);
8357 #ifdef ENABLE_ALMIXER_THREADS
8358 SDL_UnlockMutex(s_simpleLock);
8359 #endif
8360 return retval;
8361 }
8362
8363 ALint ALmixer_PauseChannel(ALint channel)
8364 {
8365 ALint retval;
8366 #ifdef ENABLE_ALMIXER_THREADS
8367 SDL_LockMutex(s_simpleLock);
8368 #endif
8369 retval = Internal_PauseChannel(channel);
8370 #ifdef ENABLE_ALMIXER_THREADS
8371 SDL_UnlockMutex(s_simpleLock);
8372 #endif
8373 return retval;
8374 }
8375
8376 ALint ALmixer_PauseSource(ALuint source)
8377 {
8378 ALint retval;
8379 #ifdef ENABLE_ALMIXER_THREADS
8380 SDL_LockMutex(s_simpleLock);
8381 #endif
8382 retval = Internal_PauseSource(source);
8383 #ifdef ENABLE_ALMIXER_THREADS
8384 SDL_UnlockMutex(s_simpleLock);
8385 #endif
8386 return retval;
8387 }
8388
8389 ALint ALmixer_ResumeChannel(ALint channel)
8390 {
8391 ALint retval;
8392 #ifdef ENABLE_ALMIXER_THREADS
8393 SDL_LockMutex(s_simpleLock);
8394 #endif
8395 retval = Internal_ResumeChannel(channel);
8396 #ifdef ENABLE_ALMIXER_THREADS
8397 SDL_UnlockMutex(s_simpleLock);
8398 #endif
8399 return retval;
8400 }
8401
8402 ALint ALmixer_ResumeSource(ALuint source)
8403 {
8404 ALint retval;
8405 #ifdef ENABLE_ALMIXER_THREADS
8406 SDL_LockMutex(s_simpleLock);
8407 #endif
8408 retval = Internal_ResumeSource(source);
8409 #ifdef ENABLE_ALMIXER_THREADS
8410 SDL_UnlockMutex(s_simpleLock);
8411 #endif
8412 return retval;
8413 }
8414
8415 /* Might consider setting eof to 0 as a "feature"
8416 * This will allow seek to end to stay there because
8417 * Play automatically rewinds if at the end */
8418 ALint ALmixer_SeekData(ALmixer_Data* data, ALuint msec)
8419 {
8420 ALint retval;
8421 #ifdef ENABLE_ALMIXER_THREADS
8422 SDL_LockMutex(s_simpleLock);
8423 #endif
8424 retval = Internal_SeekData(data, msec);
8425 #ifdef ENABLE_ALMIXER_THREADS
8426 SDL_UnlockMutex(s_simpleLock);
8427 #endif
8428 return retval;
8429 }
8430
8431 ALint ALmixer_FadeInChannelTimed(ALint channel, ALmixer_Data* data, ALint loops, ALuint fade_ticks, ALint expire_ticks)
8432 {
8433 ALint retval;
8434 #ifdef ENABLE_ALMIXER_THREADS
8435 SDL_LockMutex(s_simpleLock);
8436 #endif
8437 retval = Internal_FadeInChannelTimed(channel, data, loops, fade_ticks, expire_ticks);
8438 #ifdef ENABLE_ALMIXER_THREADS
8439 SDL_UnlockMutex(s_simpleLock);
8440 #endif
8441 return retval;
8442 }
8443
8444 ALuint ALmixer_FadeInSourceTimed(ALuint source, ALmixer_Data* data, ALint loops, ALuint fade_ticks, ALint expire_ticks)
8445 {
8446 ALuint retval;
8447 #ifdef ENABLE_ALMIXER_THREADS
8448 SDL_LockMutex(s_simpleLock);
8449 #endif
8450 retval = Internal_FadeInSourceTimed(source, data, loops, fade_ticks, expire_ticks);
8451 #ifdef ENABLE_ALMIXER_THREADS
8452 SDL_UnlockMutex(s_simpleLock);
8453 #endif
8454 return retval;
8455 }
8456
8457 ALint ALmixer_FadeOutChannel(ALint channel, ALuint ticks)
8458 {
8459 ALint retval;
8460 #ifdef ENABLE_ALMIXER_THREADS
8461 SDL_LockMutex(s_simpleLock);
8462 #endif
8463 retval = Internal_FadeOutChannel(channel, ticks);
8464 #ifdef ENABLE_ALMIXER_THREADS
8465 SDL_UnlockMutex(s_simpleLock);
8466 #endif
8467 return retval;
8468 }
8469
8470 ALint ALmixer_FadeOutSource(ALuint source, ALuint ticks)
8471 {
8472 ALint retval;
8473 #ifdef ENABLE_ALMIXER_THREADS
8474 SDL_LockMutex(s_simpleLock);
8475 #endif
8476 retval = Internal_FadeOutSource(source, ticks);
8477 #ifdef ENABLE_ALMIXER_THREADS
8478 SDL_UnlockMutex(s_simpleLock);
8479 #endif
8480 return retval;
8481 }
8482
8483 ALint ALmixer_FadeChannel(ALint channel, ALuint ticks, ALfloat volume)
8484 {
8485 ALint retval;
8486 #ifdef ENABLE_ALMIXER_THREADS
8487 SDL_LockMutex(s_simpleLock);
8488 #endif
8489 retval = Internal_FadeChannel(channel, ticks, volume);
8490 #ifdef ENABLE_ALMIXER_THREADS
8491 SDL_UnlockMutex(s_simpleLock);
8492 #endif
8493 return retval;
8494 }
8495
8496 ALint ALmixer_FadeSource(ALuint source, ALuint ticks, ALfloat volume)
8497 {
8498 ALint retval;
8499 #ifdef ENABLE_ALMIXER_THREADS
8500 SDL_LockMutex(s_simpleLock);
8501 #endif
8502 retval = Internal_FadeSource(source, ticks, volume);
8503 #ifdef ENABLE_ALMIXER_THREADS
8504 SDL_UnlockMutex(s_simpleLock);
8505 #endif
8506 return retval;
8507 }
8508
8509
8510 ALboolean ALmixer_SetVolumeChannel(ALint channel, ALfloat volume)
8511 {
8512 ALboolean retval;
8513 #ifdef ENABLE_ALMIXER_THREADS
8514 SDL_LockMutex(s_simpleLock);
8515 #endif
8516 retval = Internal_SetVolumeChannel(channel, volume);
8517 #ifdef ENABLE_ALMIXER_THREADS
8518 SDL_UnlockMutex(s_simpleLock);
8519 #endif
8520 return retval;
8521 }
8522
8523 ALboolean ALmixer_SetVolumeSource(ALuint source, ALfloat volume)
8524 {
8525 ALboolean retval;
8526 #ifdef ENABLE_ALMIXER_THREADS
8527 SDL_LockMutex(s_simpleLock);
8528 #endif
8529 retval = Internal_SetVolumeSource(source, volume);
8530 #ifdef ENABLE_ALMIXER_THREADS
8531 SDL_UnlockMutex(s_simpleLock);
8532 #endif
8533 return retval;
8534 }
8535
8536 ALfloat ALmixer_GetVolumeChannel(ALint channel)
8537 {
8538 ALfloat retval;
8539 #ifdef ENABLE_ALMIXER_THREADS
8540 SDL_LockMutex(s_simpleLock);
8541 #endif
8542 retval = Internal_GetVolumeChannel(channel);
8543 #ifdef ENABLE_ALMIXER_THREADS
8544 SDL_UnlockMutex(s_simpleLock);
8545 #endif
8546 return retval;
8547 }
8548
8549 ALfloat ALmixer_GetVolumeSource(ALuint source)
8550 {
8551 ALfloat retval;
8552 #ifdef ENABLE_ALMIXER_THREADS
8553 SDL_LockMutex(s_simpleLock);
8554 #endif
8555 retval = Internal_GetVolumeSource(source);
8556 #ifdef ENABLE_ALMIXER_THREADS
8557 SDL_UnlockMutex(s_simpleLock);
8558 #endif
8559 return retval;
8560 }
8561
8562 ALboolean ALmixer_SetMaxVolumeChannel(ALint channel, ALfloat volume)
8563 {
8564 ALboolean retval;
8565 #ifdef ENABLE_ALMIXER_THREADS
8566 SDL_LockMutex(s_simpleLock);
8567 #endif
8568 retval = Internal_SetMaxVolumeChannel(channel, volume);
8569 #ifdef ENABLE_ALMIXER_THREADS
8570 SDL_UnlockMutex(s_simpleLock);
8571 #endif
8572 return retval;
8573 }
8574
8575 ALboolean ALmixer_SetMaxVolumeSource(ALuint source, ALfloat volume)
8576 {
8577 ALboolean retval;
8578 #ifdef ENABLE_ALMIXER_THREADS
8579 SDL_LockMutex(s_simpleLock);
8580 #endif
8581 retval = Internal_SetMaxVolumeSource(source, volume);
8582 #ifdef ENABLE_ALMIXER_THREADS
8583 SDL_UnlockMutex(s_simpleLock);
8584 #endif
8585 return retval;
8586 }
8587
8588 ALfloat ALmixer_GetMaxVolumeChannel(ALint channel)
8589 {
8590 ALfloat retval;
8591 #ifdef ENABLE_ALMIXER_THREADS
8592 SDL_LockMutex(s_simpleLock);
8593 #endif
8594 retval = Internal_GetMaxVolumeChannel(channel);
8595 #ifdef ENABLE_ALMIXER_THREADS
8596 SDL_UnlockMutex(s_simpleLock);
8597 #endif
8598 return retval;
8599 }
8600
8601 ALfloat ALmixer_GetMaxVolumeSource(ALuint source)
8602 {
8603 ALfloat retval;
8604 #ifdef ENABLE_ALMIXER_THREADS
8605 SDL_LockMutex(s_simpleLock);
8606 #endif
8607 retval = Internal_GetMaxVolumeSource(source);
8608 #ifdef ENABLE_ALMIXER_THREADS
8609 SDL_UnlockMutex(s_simpleLock);
8610 #endif
8611 return retval;
8612 }
8613
8614
8615 ALboolean ALmixer_SetMinVolumeChannel(ALint channel, ALfloat volume)
8616 {
8617 ALboolean retval;
8618 #ifdef ENABLE_ALMIXER_THREADS
8619 SDL_LockMutex(s_simpleLock);
8620 #endif
8621 retval = Internal_SetMinVolumeChannel(channel, volume);
8622 #ifdef ENABLE_ALMIXER_THREADS
8623 SDL_UnlockMutex(s_simpleLock);
8624 #endif
8625 return retval;
8626 }
8627
8628 ALboolean ALmixer_SetMinVolumeSource(ALuint source, ALfloat volume)
8629 {
8630 ALboolean retval;
8631 #ifdef ENABLE_ALMIXER_THREADS
8632 SDL_LockMutex(s_simpleLock);
8633 #endif
8634 retval = Internal_SetMinVolumeSource(source, volume);
8635 #ifdef ENABLE_ALMIXER_THREADS
8636 SDL_UnlockMutex(s_simpleLock);
8637 #endif
8638 return retval;
8639 }
8640
8641 ALfloat ALmixer_GetMinVolumeChannel(ALint channel)
8642 {
8643 ALfloat retval;
8644 #ifdef ENABLE_ALMIXER_THREADS
8645 SDL_LockMutex(s_simpleLock);
8646 #endif
8647 retval = Internal_GetMinVolumeChannel(channel);
8648 #ifdef ENABLE_ALMIXER_THREADS
8649 SDL_UnlockMutex(s_simpleLock);
8650 #endif
8651 return retval;
8652 }
8653
8654 ALfloat ALmixer_GetMinVolumeSource(ALuint source)
8655 {
8656 ALfloat retval;
8657 #ifdef ENABLE_ALMIXER_THREADS
8658 SDL_LockMutex(s_simpleLock);
8659 #endif
8660 retval = Internal_GetMinVolumeSource(source);
8661 #ifdef ENABLE_ALMIXER_THREADS
8662 SDL_UnlockMutex(s_simpleLock);
8663 #endif
8664 return retval;
8665 }
8666
8667
8668
8669 ALboolean ALmixer_SetMasterVolume(ALfloat volume)
8670 {
8671 ALboolean retval;
8672 #ifdef ENABLE_ALMIXER_THREADS
8673 SDL_LockMutex(s_simpleLock);
8674 #endif
8675 retval = Internal_SetMasterVolume(volume);
8676 #ifdef ENABLE_ALMIXER_THREADS
8677 SDL_UnlockMutex(s_simpleLock);
8678 #endif
8679 return retval;
8680 }
8681
8682 ALfloat ALmixer_GetMasterVolume()
8683 {
8684 ALfloat retval;
8685 #ifdef ENABLE_ALMIXER_THREADS
8686 SDL_LockMutex(s_simpleLock);
8687 #endif
8688 retval = Internal_GetMasterVolume();
8689 #ifdef ENABLE_ALMIXER_THREADS
8690 SDL_UnlockMutex(s_simpleLock);
8691 #endif
8692 return retval;
8693 }
8694
8695 ALint ALmixer_ExpireChannel(ALint channel, ALint ticks)
8696 {
8697 ALint retval;
8698 #ifdef ENABLE_ALMIXER_THREADS
8699 SDL_LockMutex(s_simpleLock);
8700 #endif
8701 retval = Internal_ExpireChannel(channel, ticks);
8702 #ifdef ENABLE_ALMIXER_THREADS
8703 SDL_UnlockMutex(s_simpleLock);
8704 #endif
8705 return retval;
8706 }
8707
8708 ALint ALmixer_ExpireSource(ALuint source, ALint ticks)
8709 {
8710 ALint retval;
8711 #ifdef ENABLE_ALMIXER_THREADS
8712 SDL_LockMutex(s_simpleLock);
8713 #endif
8714 retval = Internal_ExpireSource(source, ticks);
8715 #ifdef ENABLE_ALMIXER_THREADS
8716 SDL_UnlockMutex(s_simpleLock);
8717 #endif
8718 return retval;
8719 }
8720
8721 ALint ALmixer_IsActiveChannel(ALint channel)
8722 {
8723 ALint retval;
8724 #ifdef ENABLE_ALMIXER_THREADS
8725 SDL_LockMutex(s_simpleLock);
8726 #endif
8727 retval = Internal_QueryChannel(channel);
8728 #ifdef ENABLE_ALMIXER_THREADS
8729 SDL_UnlockMutex(s_simpleLock);
8730 #endif
8731 return retval;
8732 }
8733
8734 ALint ALmixer_IsActiveSource(ALuint source)
8735 {
8736 ALint retval;
8737 #ifdef ENABLE_ALMIXER_THREADS
8738 SDL_LockMutex(s_simpleLock);
8739 #endif
8740 retval = Internal_QuerySource(source);
8741 #ifdef ENABLE_ALMIXER_THREADS
8742 SDL_UnlockMutex(s_simpleLock);
8743 #endif
8744 return retval;
8745 }
8746
8747
8748 ALint ALmixer_IsPlayingChannel(ALint channel)
8749 {
8750 ALint retval;
8751 #ifdef ENABLE_ALMIXER_THREADS
8752 SDL_LockMutex(s_simpleLock);
8753 #endif
8754 retval = Internal_PlayingChannel(channel);
8755 #ifdef ENABLE_ALMIXER_THREADS
8756 SDL_UnlockMutex(s_simpleLock);
8757 #endif
8758 return retval;
8759 }
8760
8761 ALint ALmixer_IsPlayingSource(ALuint source)
8762 {
8763 ALint retval;
8764 #ifdef ENABLE_ALMIXER_THREADS
8765 SDL_LockMutex(s_simpleLock);
8766 #endif
8767 retval = Internal_PlayingSource(source);
8768 #ifdef ENABLE_ALMIXER_THREADS
8769 SDL_UnlockMutex(s_simpleLock);
8770 #endif
8771 return retval;
8772 }
8773
8774
8775 ALint ALmixer_IsPausedChannel(ALint channel)
8776 {
8777 ALint retval;
8778 #ifdef ENABLE_ALMIXER_THREADS
8779 SDL_LockMutex(s_simpleLock);
8780 #endif
8781 retval = Internal_PausedChannel(channel);
8782 #ifdef ENABLE_ALMIXER_THREADS
8783 SDL_UnlockMutex(s_simpleLock);
8784 #endif
8785 return retval;
8786 }
8787
8788 ALint ALmixer_IsPausedSource(ALuint source)
8789 {
8790 ALint retval;
8791 #ifdef ENABLE_ALMIXER_THREADS
8792 SDL_LockMutex(s_simpleLock);
8793 #endif
8794 retval = Internal_PausedSource(source);
8795 #ifdef ENABLE_ALMIXER_THREADS
8796 SDL_UnlockMutex(s_simpleLock);
8797 #endif
8798 return retval;
8799 }
8800
8801
8802 ALuint ALmixer_CountAllFreeChannels()
8803 {
8804 ALuint retval;
8805 #ifdef ENABLE_ALMIXER_THREADS
8806 SDL_LockMutex(s_simpleLock);
8807 #endif
8808 retval = Internal_CountAllFreeChannels();
8809 #ifdef ENABLE_ALMIXER_THREADS
8810 SDL_UnlockMutex(s_simpleLock);
8811 #endif
8812 return retval;
8813 }
8814
8815 ALuint ALmixer_CountUnreservedFreeChannels()
8816 {
8817 ALuint retval;
8818 #ifdef ENABLE_ALMIXER_THREADS
8819 SDL_LockMutex(s_simpleLock);
8820 #endif
8821 retval = Internal_CountUnreservedFreeChannels();
8822 #ifdef ENABLE_ALMIXER_THREADS
8823 SDL_UnlockMutex(s_simpleLock);
8824 #endif
8825 return retval;
8826 }
8827
8828 ALuint ALmixer_CountAllUsedChannels()
8829 {
8830 ALuint retval;
8831 #ifdef ENABLE_ALMIXER_THREADS
8832 SDL_LockMutex(s_simpleLock);
8833 #endif
8834 retval = Internal_CountAllUsedChannels();
8835 #ifdef ENABLE_ALMIXER_THREADS
8836 SDL_UnlockMutex(s_simpleLock);
8837 #endif
8838 return retval;
8839 }
8840
8841 ALuint ALmixer_CountUnreservedUsedChannels()
8842 {
8843 ALuint retval;
8844 #ifdef ENABLE_ALMIXER_THREADS
8845 SDL_LockMutex(s_simpleLock);
8846 #endif
8847 retval = Internal_CountUnreservedUsedChannels();
8848 #ifdef ENABLE_ALMIXER_THREADS
8849 SDL_UnlockMutex(s_simpleLock);
8850 #endif
8851 return retval;
8852 }
8853
8854 ALboolean ALmixer_IsPredecoded(ALmixer_Data* data)
8855 {
8856 if(NULL == data)
8857 {
8858 return AL_FALSE;
8859 }
8860 return data->decoded_all;
8861 }
8862
8863 ALboolean ALmixer_CompiledWithThreadBackend()
8864 {
8865 #ifdef ENABLE_ALMIXER_THREADS
8866 return AL_TRUE;
8867 #else
8868 return AL_FALSE;
8869 #endif
8870 }
8871
8872
8873
8874