comparison SDL_ALmixer.c @ 0:01e39f9f58d5

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