Mercurial > almixer_isolated
comparison SDL_ALmixer.c @ 1:a8a8fe374984
Subversion era
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Wed, 27 Oct 2010 16:51:16 -0700 |
parents | 01e39f9f58d5 |
children | 279d0427ef26 |
comparison
equal
deleted
inserted
replaced
0:01e39f9f58d5 | 1:a8a8fe374984 |
---|---|
6 */ | 6 */ |
7 | 7 |
8 #include "SDL_ALmixer.h" | 8 #include "SDL_ALmixer.h" |
9 | 9 |
10 #include "SDL.h" /* For SDL_GetTicks(), SDL_Delay */ | 10 #include "SDL.h" /* For SDL_GetTicks(), SDL_Delay */ |
11 #include "SDL_sound.h" | |
11 #include "al.h" /* OpenAL */ | 12 #include "al.h" /* OpenAL */ |
12 #include "alc.h" /* For creating OpenAL contexts */ | 13 #include "alc.h" /* For creating OpenAL contexts */ |
14 | |
15 #ifdef __APPLE__ | |
16 /* For performance things like ALC_CONVERT_DATA_UPON_LOADING */ | |
17 /* Note: ALC_CONVERT_DATA_UPON_LOADING used to be in the alc.h header. | |
18 * But in the Tiger OpenAL 1.1 release (10.4.7 and Xcode 2.4), the | |
19 * define was moved to a new header file and renamed to | |
20 * ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING. | |
21 */ | |
22 #include <OpenAL/MacOSX_OALExtensions.h> | |
23 #endif | |
13 | 24 |
14 /* For malloc, bsearch, qsort */ | 25 /* For malloc, bsearch, qsort */ |
15 #include <stdlib.h> | 26 #include <stdlib.h> |
16 | 27 |
17 /* For memcpy */ | 28 /* For memcpy */ |
158 */ | 169 */ |
159 #define NUMBER_OF_START_UP_BUFFERS 2 | 170 #define NUMBER_OF_START_UP_BUFFERS 2 |
160 #endif | 171 #endif |
161 /************ END REMOVE ME (Don't need anymore) ********/ | 172 /************ END REMOVE ME (Don't need anymore) ********/ |
162 | 173 |
163 static Uint8 ALmixer_Initialized = 0; | 174 static SDL_bool ALmixer_Initialized = 0; |
164 /* This should be set correctly by Init */ | 175 /* This should be set correctly by Init */ |
165 static Uint32 ALmixer_Frequency_global = ALMIXER_DEFAULT_FREQUENCY; | 176 static Uint32 ALmixer_Frequency_global = ALMIXER_DEFAULT_FREQUENCY; |
166 | 177 |
167 /* Will be initialized in Init */ | 178 /* Will be initialized in Init */ |
168 static Sint32 Number_of_Channels_global = 0; | 179 static Sint32 Number_of_Channels_global = 0; |
193 #else | 204 #else |
194 static const Uint16 SIGN_TYPE_16_BIT_FORMAT = AUDIO_S16SYS; | 205 static const Uint16 SIGN_TYPE_16_BIT_FORMAT = AUDIO_S16SYS; |
195 static const Uint16 SIGN_TYPE_8_BIT_FORMAT = AUDIO_S8; | 206 static const Uint16 SIGN_TYPE_8_BIT_FORMAT = AUDIO_S8; |
196 #endif | 207 #endif |
197 | 208 |
209 | |
210 /* This can be private instead of being in the header now that I moved | |
211 * ALmixer_Data inside here. | |
212 */ | |
213 typedef struct ALmixer_Buffer_Map ALmixer_Buffer_Map; | |
214 | |
215 | |
216 struct ALmixer_Data | |
217 { | |
218 SDL_bool decoded_all; /* dictates different behaviors */ | |
219 Sint32 total_time; /* total playing time of sample (msec) */ | |
220 | |
221 Uint32 in_use; /* needed to prevent sharing for streams */ | |
222 SDL_bool eof; /* flag for eof, only used for streams */ | |
223 | |
224 Uint32 total_bytes; /* For predecoded */ | |
225 Uint32 loaded_bytes; /* For predecoded (for seek) */ | |
226 | |
227 Sound_Sample* sample; /* SDL_Sound provides the data */ | |
228 ALuint* buffer; /* array of OpenAL buffers (at least 1 for predecoded) */ | |
229 | |
230 /* Needed for streamed buffers */ | |
231 Uint32 max_queue_buffers; /* Max number of queue buffers */ | |
232 Uint32 num_startup_buffers; /* Number of ramp-up buffers */ | |
233 Uint32 num_buffers_in_use; /* number of buffers in use */ | |
234 | |
235 /* This stuff is for streamed buffers that require data access */ | |
236 ALmixer_Buffer_Map* buffer_map_list; /* translate ALbuffer to index | |
237 and holds pointer to copy of data for | |
238 data access */ | |
239 ALuint current_buffer; /* The current playing buffer */ | |
240 | |
241 /* Nvidia distribution refuses to recognize a simple buffer query command | |
242 * unlike all other distributions. It's forcing me to redo the code | |
243 * to accomodate this Nvidia flaw by making me maintain a "best guess" | |
244 * copy of what I think the buffer queue state looks like. | |
245 * A circular queue would a helpful data structure for this task, | |
246 * but I wanted to avoid making an additional header requirement, | |
247 * so I'm making it a void* | |
248 */ | |
249 void* circular_buffer_queue; | |
250 | |
251 | |
252 }; | |
253 | |
198 static struct ALmixer_Channel | 254 static struct ALmixer_Channel |
199 { | 255 { |
200 Uint8 channel_in_use; | 256 SDL_bool channel_in_use; |
201 Uint8 callback_update; /* For streaming determination */ | 257 SDL_bool callback_update; /* For streaming determination */ |
202 Uint8 needs_stream; /* For streaming determination */ | 258 SDL_bool needs_stream; /* For streaming determination */ |
203 Uint8 halted; | 259 SDL_bool halted; |
204 Uint8 paused; | 260 SDL_bool paused; |
205 ALuint alsource; | 261 ALuint alsource; |
206 ALmixer_Data* almixer_data; | 262 ALmixer_Data* almixer_data; |
207 Sint32 loops; | 263 Sint32 loops; |
208 Sint32 expire_ticks; | 264 Sint32 expire_ticks; |
209 Uint32 start_time; | 265 Uint32 start_time; |
210 | 266 |
211 Uint8 fade_enabled; | 267 SDL_bool fade_enabled; |
212 Uint32 fade_expire_ticks; | 268 Uint32 fade_expire_ticks; |
213 Uint32 fade_start_time; | 269 Uint32 fade_start_time; |
214 ALfloat fade_inv_time; | 270 ALfloat fade_inv_time; |
215 ALfloat fade_start_volume; | 271 ALfloat fade_start_volume; |
216 ALfloat fade_end_volume; | 272 ALfloat fade_end_volume; |
230 Uint32 ticks_fade; | 286 Uint32 ticks_fade; |
231 effect_info *effects; | 287 effect_info *effects; |
232 */ | 288 */ |
233 } *ALmixer_Channel_List = NULL; | 289 } *ALmixer_Channel_List = NULL; |
234 | 290 |
291 struct ALmixer_Buffer_Map | |
292 { | |
293 ALuint albuffer; | |
294 Sint32 index; /* might not need */ | |
295 Uint8* data; | |
296 Uint32 num_bytes; | |
297 }; | |
298 | |
235 /* This will be used to find a channel if the user supplies a source */ | 299 /* This will be used to find a channel if the user supplies a source */ |
236 typedef struct Source_Map | 300 typedef struct Source_Map |
237 { | 301 { |
238 ALuint source; | 302 ALuint source; |
239 Sint32 channel; | 303 Sint32 channel; |
253 } | 317 } |
254 | 318 |
255 /* Compare by albuffer */ | 319 /* Compare by albuffer */ |
256 static int Compare_Buffer_Map(const void* a, const void* b) | 320 static int Compare_Buffer_Map(const void* a, const void* b) |
257 { | 321 { |
258 return ( ((Buffer_Map*)a)->albuffer - ((Buffer_Map*)b)->albuffer ); | 322 return ( ((ALmixer_Buffer_Map*)a)->albuffer - ((ALmixer_Buffer_Map*)b)->albuffer ); |
259 } | 323 } |
260 | 324 |
261 /* This is for the user defined callback via | 325 /* This is for the user defined callback via |
262 * ALmixer_ChannelFinished() | 326 * ALmixer_ChannelFinished() |
263 */ | 327 */ |
264 static void (*Channel_Done_Callback)(Sint32 channel, void* userdata) = NULL; | 328 static void (*Channel_Done_Callback)(Sint32 channel, void* userdata) = NULL; |
265 static void* Channel_Done_Callback_Userdata = NULL; | 329 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; | 330 static void (*Channel_Data_Callback)(Sint32 which_channel, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bit_depth, SDL_bool is_unsigned, SDL_bool decode_mode_is_predecoded, Uint32 length_in_msec, void* user_data) = NULL; |
267 | 331 static void* Channel_Data_Callback_Userdata = NULL; |
268 | 332 |
269 /* I thought OpenAL seemed to lack an error number to string converter... | 333 /* I thought OpenAL seemed to lack an error number to string converter... |
270 * but I was wrong. Apparently they call it alGetString() which | 334 * but I was wrong. Apparently they call it alGetString() which |
271 * breaks from the OpenGL gluGetErrorString() convention. | 335 * breaks from the OpenGL gluGetErrorString() convention. |
272 * (And since the documentation for OpenAL is so bad, I didn't see | 336 * (And since the documentation for OpenAL is so bad, I didn't see |
364 | 428 |
365 fprintf(stderr, "For source: %d, buffers_queued=%d, buffers_processed=%d\n", | 429 fprintf(stderr, "For source: %d, buffers_queued=%d, buffers_processed=%d\n", |
366 source, | 430 source, |
367 buffers_queued, | 431 buffers_queued, |
368 buffers_processed); | 432 buffers_processed); |
433 | |
369 } | 434 } |
370 | 435 |
371 | 436 |
372 | 437 |
373 static void Init_Channel(Sint32 channel) | 438 static void Init_Channel(Sint32 channel) |
581 } | 646 } |
582 /* Make compiler happy. Shouldn't get here */ | 647 /* Make compiler happy. Shouldn't get here */ |
583 return AL_FORMAT_STEREO16; | 648 return AL_FORMAT_STEREO16; |
584 } | 649 } |
585 | 650 |
651 | |
652 /* This will compute the total playing time | |
653 * based upon the number of bytes and audio info. | |
654 * (In prinicple, it should compute the time for any given length) | |
655 */ | |
656 static Uint32 Compute_Total_Time_Decomposed(Uint32 bytes_per_sample, Uint32 frequency, Uint8 channels, Uint32 total_bytes) | |
657 { | |
658 double total_sec; | |
659 Uint32 total_msec; | |
660 Uint32 bytes_per_sec; | |
661 | |
662 if(0 == total_bytes) | |
663 { | |
664 return 0; | |
665 } | |
666 /* To compute Bytes per second, do | |
667 * samples_per_sec * bytes_per_sample * number_of_channels | |
668 */ | |
669 bytes_per_sec = frequency * bytes_per_sample * channels; | |
670 | |
671 /* Now to get total time (sec), do | |
672 * total_bytes / bytes_per_sec | |
673 */ | |
674 total_sec = total_bytes / (double)bytes_per_sec; | |
675 | |
676 /* Now convert seconds to milliseconds | |
677 * Add .5 to the float to do rounding before the final cast | |
678 */ | |
679 total_msec = (Uint32) ( (total_sec * 1000) + 0.5 ); | |
680 /* | |
681 fprintf(stderr, "freq=%d, bytes_per_sample=%d, channels=%d, total_msec=%d\n", frequency, bytes_per_sample, channels, total_msec); | |
682 */ | |
683 return total_msec; | |
684 } | |
685 | |
686 static Uint32 Compute_Total_Time(Sound_AudioInfo *info, Uint32 total_bytes) | |
687 { | |
688 Uint32 bytes_per_sample; | |
689 | |
690 if(0 == total_bytes) | |
691 { | |
692 return 0; | |
693 } | |
694 /* SDL has a mask trick I was not aware of. Mask the upper bits | |
695 * of the format, and you get 8 or 16 which is the bits per sample. | |
696 * Divide by 8bits_per_bytes and you get bytes_per_sample | |
697 */ | |
698 bytes_per_sample = (Uint32) ((info->format & 0xFF) / 8); | |
699 | |
700 return Compute_Total_Time_Decomposed(bytes_per_sample, info->rate, info->channels, total_bytes); | |
701 } /* End Compute_Total_Time */ | |
702 | |
703 | |
704 | |
586 /**************** REMOVED ****************************/ | 705 /**************** REMOVED ****************************/ |
587 /* This was removed because I originally thought | 706 /* This was removed because I originally thought |
588 * OpenAL could return a pointer to the buffer data, | 707 * OpenAL could return a pointer to the buffer data, |
589 * but I was wrong. If something like that is ever | 708 * but I was wrong. If something like that is ever |
590 * implemented, then this might become useful. | 709 * implemented, then this might become useful. |
726 return; | 845 return; |
727 } | 846 } |
728 Channel_Done_Callback(channel, Channel_Done_Callback_Userdata); | 847 Channel_Done_Callback(channel, Channel_Done_Callback_Userdata); |
729 } | 848 } |
730 | 849 |
731 static Sint32 LookUpBuffer(ALuint buffer, Buffer_Map* buffer_map_list, Uint32 num_items_in_list) | 850 static Sint32 LookUpBuffer(ALuint buffer, ALmixer_Buffer_Map* buffer_map_list, Uint32 num_items_in_list) |
732 { | 851 { |
733 /* Only the first value is used for the key */ | 852 /* Only the first value is used for the key */ |
734 Buffer_Map key = { 0, 0, NULL, 0 }; | 853 ALmixer_Buffer_Map key = { 0, 0, NULL, 0 }; |
735 Buffer_Map* found_item = NULL; | 854 ALmixer_Buffer_Map* found_item = NULL; |
736 key.albuffer = buffer; | 855 key.albuffer = buffer; |
737 | 856 |
738 /* Use the ANSI C binary search feature (yea!) */ | 857 /* 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); | 858 found_item = (ALmixer_Buffer_Map*)bsearch(&key, buffer_map_list, num_items_in_list, sizeof(ALmixer_Buffer_Map), Compare_Buffer_Map); |
740 if(NULL == found_item) | 859 if(NULL == found_item) |
741 { | 860 { |
742 ALmixer_SetError("Can't find buffer"); | 861 ALmixer_SetError("Can't find buffer"); |
743 return -1; | 862 return -1; |
744 } | 863 } |
748 | 867 |
749 /* FIXME: Need to pass back additional info to be useful. | 868 /* FIXME: Need to pass back additional info to be useful. |
750 * Bit rate, stereo/mono (num chans), time in msec? | 869 * Bit rate, stereo/mono (num chans), time in msec? |
751 * Precoded/streamed flag so user can plan for future data? | 870 * Precoded/streamed flag so user can plan for future data? |
752 */ | 871 */ |
753 static void Invoke_Channel_Data_Callback(Sint32 which_channel, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint16 format, Uint8 decode_mode) | 872 /* |
754 { | 873 * channels: 1 for mono, 2 for stereo |
874 * | |
875 */ | |
876 static void Invoke_Channel_Data_Callback(Sint32 which_channel, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint16 format, SDL_bool decode_mode_is_predecoded) | |
877 { | |
878 SDL_bool is_unsigned; | |
879 Uint8 bits_per_sample = GetBitDepth(format); | |
880 Uint32 bytes_per_sample; | |
881 Uint32 length_in_msec; | |
882 | |
883 if(GetSignednessValue(format) == ALMIXER_UNSIGNED_VALUE) | |
884 { | |
885 is_unsigned = 1; | |
886 } | |
887 else | |
888 { | |
889 is_unsigned = 0; | |
890 } | |
891 | |
892 bytes_per_sample = (Uint32) (bits_per_sample / 8); | |
893 | |
894 length_in_msec = Compute_Total_Time_Decomposed(bytes_per_sample, frequency, channels, num_bytes); | |
895 | |
755 /* | 896 /* |
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); | 897 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 */ | 898 */ |
758 if(NULL == Channel_Data_Callback) | 899 if(NULL == Channel_Data_Callback) |
759 { | 900 { |
760 return; | 901 return; |
761 } | 902 } |
762 Channel_Data_Callback(which_channel, data, num_bytes, frequency, channels, GetBitDepth(format), format, decode_mode); | 903 /* |
904 * Channel_Data_Callback(which_channel, data, num_bytes, frequency, channels, GetBitDepth(format), format, decode_mode_is_predecoded); | |
905 */ | |
906 Channel_Data_Callback(which_channel, data, num_bytes, frequency, channels, bits_per_sample, is_unsigned, decode_mode_is_predecoded, length_in_msec, Channel_Data_Callback_Userdata); | |
763 } | 907 } |
764 | 908 |
765 static void Invoke_Predecoded_Channel_Data_Callback(Sint32 channel, ALmixer_Data* data) | 909 static void Invoke_Predecoded_Channel_Data_Callback(Sint32 channel, ALmixer_Data* data) |
766 { | 910 { |
767 if(NULL == data->sample) | 911 if(NULL == data->sample) |
775 (((Uint8*) data->sample->buffer) + (data->total_bytes - data->loaded_bytes) ), | 919 (((Uint8*) data->sample->buffer) + (data->total_bytes - data->loaded_bytes) ), |
776 data->loaded_bytes, | 920 data->loaded_bytes, |
777 data->sample->desired.rate, | 921 data->sample->desired.rate, |
778 data->sample->desired.channels, | 922 data->sample->desired.channels, |
779 data->sample->desired.format, | 923 data->sample->desired.format, |
780 ALMIXER_DECODE_ALL | 924 SDL_TRUE |
781 ); | 925 ); |
782 } | 926 } |
783 | 927 |
784 static void Invoke_Streamed_Channel_Data_Callback(Sint32 channel, ALmixer_Data* data, ALuint buffer) | 928 static void Invoke_Streamed_Channel_Data_Callback(Sint32 channel, ALmixer_Data* data, ALuint buffer) |
785 { | 929 { |
800 data->buffer_map_list[index].data, | 944 data->buffer_map_list[index].data, |
801 data->buffer_map_list[index].num_bytes, | 945 data->buffer_map_list[index].num_bytes, |
802 data->sample->desired.rate, | 946 data->sample->desired.rate, |
803 data->sample->desired.channels, | 947 data->sample->desired.channels, |
804 data->sample->desired.format, | 948 data->sample->desired.format, |
805 ALMIXER_DECODE_STREAM | 949 SDL_FALSE |
806 ); | 950 ); |
807 } | 951 } |
808 | 952 |
809 /* From SDL_Sound's playsound. Converts milliseconds to byte positions. | 953 /* From SDL_Sound's playsound. Converts milliseconds to byte positions. |
810 * This is needed for seeking on predecoded samples | 954 * This is needed for seeking on predecoded samples |
906 */ | 1050 */ |
907 data->loaded_bytes = data->total_bytes - byte_position; | 1051 data->loaded_bytes = data->total_bytes - byte_position; |
908 | 1052 |
909 return 0; | 1053 return 0; |
910 } | 1054 } |
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 | 1055 |
954 /* Because we have multiple queue buffers and OpenAL won't let | 1056 /* Because we have multiple queue buffers and OpenAL won't let |
955 * us access them, we need to keep copies of each buffer around | 1057 * us access them, we need to keep copies of each buffer around |
956 */ | 1058 */ |
957 static Sint32 CopyDataToAccessBuffer(ALmixer_Data* data, Uint32 num_bytes, ALuint buffer) | 1059 static Sint32 CopyDataToAccessBuffer(ALmixer_Data* data, Uint32 num_bytes, ALuint buffer) |
2981 /* Get the Max volume */ | 3083 /* Get the Max volume */ |
2982 /* | 3084 /* |
2983 alGetSourcef(ALmixer_Channel_List[channel].alsource, | 3085 alGetSourcef(ALmixer_Channel_List[channel].alsource, |
2984 AL_MAX_GAIN, &value); | 3086 AL_MAX_GAIN, &value); |
2985 ALmixer_Channel_List[channel].fade_end_volume = value; | 3087 ALmixer_Channel_List[channel].fade_end_volume = value; |
3088 fprintf(stderr, "MAX gain: %f\n", value); | |
2986 */ | 3089 */ |
2987 ALmixer_Channel_List[channel].fade_end_volume = | 3090 ALmixer_Channel_List[channel].fade_end_volume = |
2988 ALmixer_Channel_List[channel].max_volume; | 3091 ALmixer_Channel_List[channel].max_volume; |
2989 | 3092 |
2990 fprintf(stderr, "MAX gain: %f\n", value); | |
2991 /* Get the Min volume */ | 3093 /* Get the Min volume */ |
2992 alGetSourcef(ALmixer_Channel_List[channel].alsource, | 3094 alGetSourcef(ALmixer_Channel_List[channel].alsource, |
2993 AL_MIN_GAIN, &value); | 3095 AL_MIN_GAIN, &value); |
2994 if((error = alGetError()) != AL_NO_ERROR) | 3096 if((error = alGetError()) != AL_NO_ERROR) |
2995 { | 3097 { |
4437 aluGetErrorString(error) ); | 4539 aluGetErrorString(error) ); |
4438 error_flag--; | 4540 error_flag--; |
4439 } | 4541 } |
4440 if(buffers_still_queued > 0) | 4542 if(buffers_still_queued > 0) |
4441 { | 4543 { |
4442 /* | 4544 |
4545 #if 0 /* This triggers an error in OS X Core Audio. */ | |
4546 alSourceUnqueueBuffers( | |
4547 ALmixer_Channel_List[i].alsource, | |
4548 1, | |
4549 ALmixer_Channel_List[i].almixer_data->buffer | |
4550 ); | |
4551 #else | |
4552 /* fprintf(stderr, "In the Bob Aron section...about to clear source\n"); | |
4443 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | 4553 PrintQueueStatus(ALmixer_Channel_List[i].alsource); |
4444 */ | 4554 */ |
4445 | |
4446 /* Rather than force unqueuing the buffer, let's see if | 4555 /* Rather than force unqueuing the buffer, let's see if |
4447 * setting the buffer to none works (the OpenAL 1.0 | 4556 * setting the buffer to none works (the OpenAL 1.0 |
4448 * Reference Annotation suggests this should work). | 4557 * Reference Annotation suggests this should work). |
4449 */ | 4558 */ |
4450 alSourcei(ALmixer_Channel_List[i].alsource, | 4559 alSourcei(ALmixer_Channel_List[i].alsource, |
4451 AL_BUFFER, AL_NONE); | 4560 AL_BUFFER, AL_NONE); |
4452 /* | 4561 /* |
4453 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | 4562 PrintQueueStatus(ALmixer_Channel_List[i].alsource); |
4454 */ | 4563 */ |
4564 #endif | |
4455 if((error = alGetError()) != AL_NO_ERROR) | 4565 if((error = alGetError()) != AL_NO_ERROR) |
4456 { | 4566 { |
4457 fprintf(stderr, "Error with unqueue, after alSourceUnqueueBuffers, buffers_still_queued=%d, error is: %s", buffers_still_queued, | 4567 fprintf(stderr, "Error with unqueue, after alSourceUnqueueBuffers, buffers_still_queued=%d, error is: %s", buffers_still_queued, |
4458 aluGetErrorString(error)); | 4568 aluGetErrorString(error)); |
4459 ALmixer_SetError("Predecoded Unqueue buffer failed: %s", | 4569 ALmixer_SetError("Predecoded Unqueue buffer failed: %s", |
4593 { | 4703 { |
4594 Uint32 k; | 4704 Uint32 k; |
4595 Uint32 queue_ret_flag; | 4705 Uint32 queue_ret_flag; |
4596 Uint8 is_out_of_sync = 0; | 4706 Uint8 is_out_of_sync = 0; |
4597 Uint32 my_queue_size = CircularQueueUnsignedInt_Size(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue); | 4707 Uint32 my_queue_size = CircularQueueUnsignedInt_Size(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue); |
4708 /* Ugh, I have to deal with signed/unsigned mismatch here. */ | |
4709 ALint buffers_unplayed_int = buffers_still_queued - buffers_processed; | |
4710 Uint32 unplayed_buffers; | |
4711 if(buffers_unplayed_int < 0) | |
4712 { | |
4713 unplayed_buffers = 0; | |
4714 } | |
4715 else | |
4716 { | |
4717 unplayed_buffers = (Uint32)buffers_unplayed_int; | |
4718 } | |
4598 /* | 4719 /* |
4599 fprintf(stderr, "Queue in processed check, before pop, buffers_processed=%d\n", buffers_processed); | 4720 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); | 4721 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue); |
4601 */ | 4722 */ |
4602 /* We can't make any determinations solely based on the number of buffers_processed | 4723 /* We can't make any determinations solely based on the number of buffers_processed |
4620 | 4741 |
4621 /* First, let's syncronize our queue with the OpenAL queue */ | 4742 /* First, let's syncronize our queue with the OpenAL queue */ |
4622 #if 0 | 4743 #if 0 |
4623 fprintf(stderr, "inside, Buffers processed=%d, Buffers queued=%d, my queue=%d\n", | 4744 fprintf(stderr, "inside, Buffers processed=%d, Buffers queued=%d, my queue=%d\n", |
4624 buffers_processed, buffers_still_queued, my_queue_size); | 4745 buffers_processed, buffers_still_queued, my_queue_size); |
4625 #endif | 4746 #endif |
4626 if(my_queue_size > (buffers_still_queued - buffers_processed)) | 4747 if(my_queue_size > unplayed_buffers) |
4627 { | 4748 { |
4628 is_out_of_sync = 1; | 4749 is_out_of_sync = 1; |
4629 for(k=0; k<(my_queue_size - (buffers_still_queued - buffers_processed)); k++) | 4750 for(k=0; k<(my_queue_size - unplayed_buffers); k++) |
4630 { | 4751 { |
4631 queue_ret_flag = CircularQueueUnsignedInt_PopFront( | 4752 queue_ret_flag = CircularQueueUnsignedInt_PopFront( |
4632 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue); | 4753 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue); |
4633 if(0 == queue_ret_flag) | 4754 if(0 == queue_ret_flag) |
4634 { | 4755 { |
4677 #endif | 4798 #endif |
4678 Invoke_Streamed_Channel_Data_Callback(i, ALmixer_Channel_List[i].almixer_data, current_buffer_id); | 4799 Invoke_Streamed_Channel_Data_Callback(i, ALmixer_Channel_List[i].almixer_data, current_buffer_id); |
4679 } | 4800 } |
4680 else | 4801 else |
4681 { | 4802 { |
4803 /* | |
4682 fprintf(stderr, "53b, Notice/Warning:, OpenAL queue has been depleted.\n"); | 4804 fprintf(stderr, "53b, Notice/Warning:, OpenAL queue has been depleted.\n"); |
4805 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | |
4806 */ | |
4683 /* In this case, we might either be in an underrun or finished with playback */ | 4807 /* In this case, we might either be in an underrun or finished with playback */ |
4684 ALmixer_Channel_List[i].almixer_data->current_buffer = 0; | 4808 ALmixer_Channel_List[i].almixer_data->current_buffer = 0; |
4685 } | 4809 } |
4686 } | 4810 } |
4687 } | 4811 } |
4730 * lose the pointer to the unqueued buffer | 4854 * lose the pointer to the unqueued buffer |
4731 */ | 4855 */ |
4732 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use | 4856 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use |
4733 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers) | 4857 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers) |
4734 { | 4858 { |
4735 /* | 4859 #if 0 |
4736 fprintf(stderr, "Getting more data in NOT_EOF and num_buffers_in_use (%d) < max_queue (%d)\n", | 4860 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, | 4861 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use, |
4738 ALmixer_Channel_List[i].almixer_data->max_queue_buffers); | 4862 ALmixer_Channel_List[i].almixer_data->max_queue_buffers); |
4739 */ | 4863 #endif |
4740 /* Going to add an unused packet. | 4864 /* Going to add an unused packet. |
4741 * Grab next packet */ | 4865 * Grab next packet */ |
4742 bytes_returned = GetMoreData( | 4866 bytes_returned = GetMoreData( |
4743 ALmixer_Channel_List[i].almixer_data, | 4867 ALmixer_Channel_List[i].almixer_data, |
4744 ALmixer_Channel_List[i].almixer_data->buffer[ | 4868 ALmixer_Channel_List[i].almixer_data->buffer[ |
4785 else | 4909 else |
4786 { | 4910 { |
4787 /* Might want to check state */ | 4911 /* Might want to check state */ |
4788 /* In case the playback stopped, | 4912 /* In case the playback stopped, |
4789 * we need to resume */ | 4913 * we need to resume */ |
4914 #if 1 | |
4915 /* Try not refetching the state here because I'm getting a duplicate | |
4916 buffer playback (hiccup) */ | |
4790 alGetSourcei( | 4917 alGetSourcei( |
4791 ALmixer_Channel_List[i].alsource, | 4918 ALmixer_Channel_List[i].alsource, |
4792 AL_SOURCE_STATE, &state | 4919 AL_SOURCE_STATE, &state |
4793 ); | 4920 ); |
4794 if((error = alGetError()) != AL_NO_ERROR) | 4921 if((error = alGetError()) != AL_NO_ERROR) |
4795 { | 4922 { |
4796 fprintf(stderr, "54Testing error: %s\n", | 4923 fprintf(stderr, "54bTesting error: %s\n", |
4797 aluGetErrorString(error)); | 4924 aluGetErrorString(error)); |
4798 } | 4925 } |
4926 /* Get the number of buffers processed | |
4927 */ | |
4928 alGetSourcei( | |
4929 ALmixer_Channel_List[i].alsource, | |
4930 AL_BUFFERS_PROCESSED, | |
4931 &buffers_processed | |
4932 ); | |
4933 if((error = alGetError()) != AL_NO_ERROR) | |
4934 { | |
4935 fprintf(stderr, "54cError, Can't get buffers_processed: %s\n", | |
4936 aluGetErrorString(error)); | |
4937 } | |
4938 #endif | |
4799 if(AL_STOPPED == state) | 4939 if(AL_STOPPED == state) |
4800 { | 4940 { |
4801 /* Resuming in not eof, but nothing to buffer */ | 4941 /* Resuming in not eof, but nothing to buffer */ |
4942 | |
4943 /* Okay, here's another lately discovered problem: | |
4944 * I can't find it in the spec, but for at least some of the | |
4945 * implementations, if I call play on a stopped source that | |
4946 * has processed buffers, all those buffers get marked as unprocessed | |
4947 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers | |
4948 * processed, on resume, the earlier 24 buffers will get replayed, | |
4949 * causing a "hiccup" like sound in the playback. | |
4950 * To avoid this, I must unqueue all processed buffers before | |
4951 * calling play. But to complicate things, I need to worry about resyncing | |
4952 * the circular queue with this since I designed this thing | |
4953 * with some correlation between the two. However, I might | |
4954 * have already handled this, so I will try writing this code without | |
4955 * syncing for now. | |
4956 * There is currently an assumption that a buffer | |
4957 * was queued above so I actually have something | |
4958 * to play. | |
4959 */ | |
4960 ALint temp_count; | |
4961 /* | |
4962 fprintf(stderr, "STOPPED1, need to clear processed, status is:\n"); | |
4963 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | |
4964 */ | |
4965 for(temp_count=0; temp_count<buffers_processed; temp_count++) | |
4966 { | |
4967 alSourceUnqueueBuffers( | |
4968 ALmixer_Channel_List[i].alsource, | |
4969 1, &unqueued_buffer_id | |
4970 ); | |
4971 if((error = alGetError()) != AL_NO_ERROR) | |
4972 { | |
4973 fprintf(stderr, "55aTesting error: %s\n", | |
4974 aluGetErrorString(error)); | |
4975 error_flag--; | |
4976 } | |
4977 } | |
4978 /* | |
4979 fprintf(stderr, "After unqueue clear...:\n"); | |
4980 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | |
4981 */ | |
4802 alSourcePlay(ALmixer_Channel_List[i].alsource); | 4982 alSourcePlay(ALmixer_Channel_List[i].alsource); |
4803 if((error = alGetError()) != AL_NO_ERROR) | 4983 if((error = alGetError()) != AL_NO_ERROR) |
4804 { | 4984 { |
4805 fprintf(stderr, "55Testing error: %s\n", | 4985 fprintf(stderr, "55Tbesting error: %s\n", |
4806 aluGetErrorString(error)); | 4986 aluGetErrorString(error)); |
4807 } | 4987 } |
4808 } | 4988 } |
4809 /* Let's escape to the next loop. | 4989 /* Let's escape to the next loop. |
4810 * All code below this point is for queuing up | 4990 * All code below this point is for queuing up |
4811 */ | 4991 */ |
4812 /* | 4992 /* |
4813 fprintf(stderr, "Entry: Nothing to do...continue\n\n"); | 4993 fprintf(stderr, "Entry: Nothing to do...continue\n\n"); |
4814 */ | 4994 */ |
4815 continue; | 4995 continue; |
4816 } | 4996 } |
4817 /* We now know we have to fill an available | 4997 /* We now know we have to fill an available |
4818 * buffer. | 4998 * buffer. |
4819 */ | 4999 */ |
4932 * EOF flag should be set. | 5112 * EOF flag should be set. |
4933 * Just go to next loop and | 5113 * Just go to next loop and |
4934 * let things be handled correctly | 5114 * let things be handled correctly |
4935 * in future update calls | 5115 * in future update calls |
4936 */ | 5116 */ |
5117 /* | |
4937 fprintf(stderr, "SHOULD BE EOF\n"); | 5118 fprintf(stderr, "SHOULD BE EOF\n"); |
4938 | 5119 |
4939 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | 5120 PrintQueueStatus(ALmixer_Channel_List[i].alsource); |
4940 | 5121 */ |
4941 continue; | 5122 continue; |
4942 } | 5123 } |
4943 } /* END if bytes_returned == 0 */ | 5124 } /* END if bytes_returned == 0 */ |
4944 /********* Possible trouble point. I might be queueing empty buffers on the mac. | 5125 /********* 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 | 5126 * This check doesn't say if the buffer is valid. Only the EOF assumption is a clue at this point |
4954 { | 5135 { |
4955 /* Keep count of how many buffers we have | 5136 /* Keep count of how many buffers we have |
4956 * to queue so we can return the value | 5137 * to queue so we can return the value |
4957 */ | 5138 */ |
4958 retval++; | 5139 retval++; |
5140 /* | |
4959 fprintf(stderr, "NOT_EOF???, about to Queue more data for num_buffers (%d) < max_queue (%d)\n", | 5141 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, | 5142 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use, |
4961 ALmixer_Channel_List[i].almixer_data->max_queue_buffers); | 5143 ALmixer_Channel_List[i].almixer_data->max_queue_buffers); |
4962 | 5144 */ |
4963 alSourceQueueBuffers( | 5145 alSourceQueueBuffers( |
4964 ALmixer_Channel_List[i].alsource, | 5146 ALmixer_Channel_List[i].alsource, |
4965 1, | 5147 1, |
4966 &ALmixer_Channel_List[i].almixer_data->buffer[ | 5148 &ALmixer_Channel_List[i].almixer_data->buffer[ |
4967 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use] | 5149 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use] |
5054 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++; | 5236 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++; |
5055 } | 5237 } |
5056 /* Might want to check state */ | 5238 /* Might want to check state */ |
5057 /* In case the playback stopped, | 5239 /* In case the playback stopped, |
5058 * we need to resume */ | 5240 * we need to resume */ |
5241 #if 1 | |
5242 /* Try not refetching the state here because I'm getting a duplicate | |
5243 buffer playback (hiccup) */ | |
5059 alGetSourcei( | 5244 alGetSourcei( |
5060 ALmixer_Channel_List[i].alsource, | 5245 ALmixer_Channel_List[i].alsource, |
5061 AL_SOURCE_STATE, &state | 5246 AL_SOURCE_STATE, &state |
5062 ); | 5247 ); |
5063 if((error = alGetError()) != AL_NO_ERROR) | 5248 if((error = alGetError()) != AL_NO_ERROR) |
5064 { | 5249 { |
5065 fprintf(stderr, "57Testing error: %s\n", | 5250 fprintf(stderr, "57bTesting error: %s\n", |
5066 aluGetErrorString(error)); | 5251 aluGetErrorString(error)); |
5067 } | 5252 } |
5253 /* Get the number of buffers processed | |
5254 */ | |
5255 alGetSourcei( | |
5256 ALmixer_Channel_List[i].alsource, | |
5257 AL_BUFFERS_PROCESSED, | |
5258 &buffers_processed | |
5259 ); | |
5260 if((error = alGetError()) != AL_NO_ERROR) | |
5261 { | |
5262 fprintf(stderr, "57cError, Can't get buffers_processed: %s\n", | |
5263 aluGetErrorString(error)); | |
5264 } | |
5265 #endif | |
5068 if(AL_STOPPED == state) | 5266 if(AL_STOPPED == state) |
5069 { | 5267 { |
5268 /* | |
5070 fprintf(stderr, "Resuming in not eof\n"); | 5269 fprintf(stderr, "Resuming in not eof\n"); |
5071 alSourcePlay(ALmixer_Channel_List[i].alsource); | 5270 */ |
5072 if((error = alGetError()) != AL_NO_ERROR) | 5271 /* Okay, here's another lately discovered problem: |
5073 { | 5272 * I can't find it in the spec, but for at least some of the |
5074 fprintf(stderr, "58Testing error: %s\n", | 5273 * implementations, if I call play on a stopped source that |
5075 aluGetErrorString(error)); | 5274 * has processed buffers, all those buffers get marked as unprocessed |
5076 } | 5275 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers |
5276 * processed, on resume, the earlier 24 buffers will get replayed, | |
5277 * causing a "hiccup" like sound in the playback. | |
5278 * To avoid this, I must unqueue all processed buffers before | |
5279 * calling play. But to complicate things, I need to worry about resyncing | |
5280 * the circular queue with this since I designed this thing | |
5281 * with some correlation between the two. However, I might | |
5282 * have already handled this, so I will try writing this code without | |
5283 * syncing for now. | |
5284 * There is currently an assumption that a buffer | |
5285 * was queued above so I actually have something | |
5286 * to play. | |
5287 */ | |
5288 ALint temp_count; | |
5289 /* | |
5290 fprintf(stderr, "STOPPED2, need to clear processed, status is:\n"); | |
5291 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | |
5292 */ | |
5293 | |
5294 for(temp_count=0; temp_count<buffers_processed; temp_count++) | |
5295 { | |
5296 alSourceUnqueueBuffers( | |
5297 ALmixer_Channel_List[i].alsource, | |
5298 1, &unqueued_buffer_id | |
5299 ); | |
5300 if((error = alGetError()) != AL_NO_ERROR) | |
5301 { | |
5302 fprintf(stderr, "58aTesting error: %s\n", | |
5303 aluGetErrorString(error)); | |
5304 error_flag--; | |
5305 } | |
5306 } | |
5307 /* | |
5308 fprintf(stderr, "After unqueue clear...:\n"); | |
5309 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | |
5310 */ | |
5311 | |
5312 alSourcePlay(ALmixer_Channel_List[i].alsource); | |
5313 if((error = alGetError()) != AL_NO_ERROR) | |
5314 { | |
5315 fprintf(stderr, "55Tbesting 8rror: %s\n", | |
5316 aluGetErrorString(error)); | |
5317 } | |
5077 } | 5318 } |
5078 continue; | 5319 continue; |
5079 } /* END if( ! eof) */ | 5320 } /* END if( ! eof) */ |
5080 /* We have hit EOF in the SDL_Sound sample and there | 5321 /* We have hit EOF in the SDL_Sound sample and there |
5081 * are no more loops. However, there may still be | 5322 * are no more loops. However, there may still be |
5198 aluGetErrorString(error)); | 5439 aluGetErrorString(error)); |
5199 } | 5440 } |
5200 if(AL_STOPPED == state) | 5441 if(AL_STOPPED == state) |
5201 { | 5442 { |
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); | 5443 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 | 5444 /* |
5204 PrintQueueStatus(ALmixer_Channel_List[i].alsource); | 5445 PrintQueueStatus(ALmixer_Channel_List[i].alsource); |
5205 | 5446 */ |
5206 /* Rather than force unqueuing the buffer, let's see if | 5447 /* Rather than force unqueuing the buffer, let's see if |
5207 * setting the buffer to none works (the OpenAL 1.0 | 5448 * setting the buffer to none works (the OpenAL 1.0 |
5208 * Reference Annotation suggests this should work). | 5449 * Reference Annotation suggests this should work). |
5209 */ | 5450 */ |
5210 alSourcei(ALmixer_Channel_List[i].alsource, | 5451 alSourcei(ALmixer_Channel_List[i].alsource, |
5630 * This feature is toggled on/off by using the alDisable() & alEnable() APIs. This | 5871 * This feature is toggled on/off by using the alDisable() & alEnable() APIs. This |
5631 * setting will be applied to all subsequent | 5872 * setting will be applied to all subsequent |
5632 * calls to alBufferData(). | 5873 * calls to alBufferData(). |
5633 */ | 5874 */ |
5634 #ifdef __APPLE__ | 5875 #ifdef __APPLE__ |
5635 alEnable(ALC_CONVERT_DATA_UPON_LOADING); | 5876 alEnable(ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING); |
5636 #endif | 5877 #endif |
5637 | 5878 |
5638 | 5879 |
5639 | 5880 |
5640 | 5881 |
5652 Is_Playing_global = 0; | 5893 Is_Playing_global = 0; |
5653 /* Set to Null in case system quit and was reinitialized */ | 5894 /* Set to Null in case system quit and was reinitialized */ |
5654 Channel_Done_Callback = NULL; | 5895 Channel_Done_Callback = NULL; |
5655 Channel_Done_Callback_Userdata = NULL; | 5896 Channel_Done_Callback_Userdata = NULL; |
5656 Channel_Data_Callback = NULL; | 5897 Channel_Data_Callback = NULL; |
5898 Channel_Data_Callback_Userdata = NULL; | |
5657 | 5899 |
5658 /* Allocate memory for the list of channels */ | 5900 /* Allocate memory for the list of channels */ |
5659 ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel)); | 5901 ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel)); |
5660 if(NULL == ALmixer_Channel_List) | 5902 if(NULL == ALmixer_Channel_List) |
5661 { | 5903 { |
6110 * This feature is toggled on/off by using the alDisable() & alEnable() APIs. This | 6352 * This feature is toggled on/off by using the alDisable() & alEnable() APIs. This |
6111 * setting will be applied to all subsequent | 6353 * setting will be applied to all subsequent |
6112 * calls to alBufferData(). | 6354 * calls to alBufferData(). |
6113 */ | 6355 */ |
6114 #ifdef __APPLE__ | 6356 #ifdef __APPLE__ |
6115 alEnable(ALC_CONVERT_DATA_UPON_LOADING); | 6357 alEnable(ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING); |
6116 #endif | 6358 #endif |
6117 | 6359 |
6118 return 0; | 6360 return 0; |
6119 } | 6361 } |
6120 | 6362 |
6140 Is_Playing_global = 0; | 6382 Is_Playing_global = 0; |
6141 /* Set to Null in case system quit and was reinitialized */ | 6383 /* Set to Null in case system quit and was reinitialized */ |
6142 Channel_Done_Callback = NULL; | 6384 Channel_Done_Callback = NULL; |
6143 Channel_Done_Callback_Userdata = NULL; | 6385 Channel_Done_Callback_Userdata = NULL; |
6144 Channel_Data_Callback = NULL; | 6386 Channel_Data_Callback = NULL; |
6387 Channel_Data_Callback_Userdata = NULL; | |
6145 | 6388 |
6146 /* Allocate memory for the list of channels */ | 6389 /* Allocate memory for the list of channels */ |
6147 ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel)); | 6390 ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel)); |
6148 if(NULL == ALmixer_Channel_List) | 6391 if(NULL == ALmixer_Channel_List) |
6149 { | 6392 { |
6328 Sound_Quit(); | 6571 Sound_Quit(); |
6329 | 6572 |
6330 return; | 6573 return; |
6331 } | 6574 } |
6332 | 6575 |
6333 Uint8 ALmixer_IsInitialized() | 6576 SDL_bool ALmixer_IsInitialized() |
6334 { | 6577 { |
6335 return ALmixer_Initialized; | 6578 return ALmixer_Initialized; |
6336 } | 6579 } |
6337 | 6580 |
6338 Uint32 ALmixer_GetFrequency() | 6581 Uint32 ALmixer_GetFrequency() |
6488 } | 6731 } |
6489 | 6732 |
6490 | 6733 |
6491 | 6734 |
6492 | 6735 |
6493 static ALmixer_Data* DoLoad(Sound_Sample* sample, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data) | 6736 static ALmixer_Data* DoLoad(Sound_Sample* sample, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data) |
6494 { | 6737 { |
6495 Uint32 bytes_decoded; | 6738 Uint32 bytes_decoded; |
6496 ALmixer_Data* ret_data; | 6739 ALmixer_Data* ret_data; |
6497 ALenum error; | 6740 ALenum error; |
6498 | 6741 |
6550 | 6793 |
6551 /* Now decode and load the data into a data chunk */ | 6794 /* Now decode and load the data into a data chunk */ |
6552 /* Different cases for Streamed and Predecoded | 6795 /* Different cases for Streamed and Predecoded |
6553 * Streamed might turn into a predecoded if buffersize | 6796 * Streamed might turn into a predecoded if buffersize |
6554 * is large enough */ | 6797 * is large enough */ |
6555 if(ALMIXER_DECODE_STREAM == decode_mode) | 6798 if(SDL_FALSE == decode_mode_is_predecoded) |
6556 { | 6799 { |
6557 bytes_decoded = Sound_Decode(sample); | 6800 bytes_decoded = Sound_Decode(sample); |
6558 if(sample->flags & SOUND_SAMPLEFLAG_ERROR) | 6801 if(sample->flags & SOUND_SAMPLEFLAG_ERROR) |
6559 { | 6802 { |
6560 ALmixer_SetError(Sound_GetError()); | 6803 ALmixer_SetError(Sound_GetError()); |
6791 { | 7034 { |
6792 Uint32 j; | 7035 Uint32 j; |
6793 /* Create buffers for data access | 7036 /* Create buffers for data access |
6794 * Should be the same number as the number of queue buffers | 7037 * Should be the same number as the number of queue buffers |
6795 */ | 7038 */ |
6796 ret_data->buffer_map_list = (Buffer_Map*)malloc( sizeof(Buffer_Map) * max_queue_buffers); | 7039 ret_data->buffer_map_list = (ALmixer_Buffer_Map*)malloc( sizeof(ALmixer_Buffer_Map) * max_queue_buffers); |
6797 if(NULL == ret_data->buffer_map_list) | 7040 if(NULL == ret_data->buffer_map_list) |
6798 { | 7041 { |
6799 ALmixer_SetError("Out of Memory"); | 7042 ALmixer_SetError("Out of Memory"); |
6800 Sound_FreeSample(sample); | 7043 Sound_FreeSample(sample); |
6801 free(ret_data->buffer); | 7044 free(ret_data->buffer); |
6843 return NULL; | 7086 return NULL; |
6844 } | 7087 } |
6845 | 7088 |
6846 /* The Buffer_Map_List must be sorted by albuffer for binary searches | 7089 /* The Buffer_Map_List must be sorted by albuffer for binary searches |
6847 */ | 7090 */ |
6848 qsort(ret_data->buffer_map_list, max_queue_buffers, sizeof(Buffer_Map), Compare_Buffer_Map); | 7091 qsort(ret_data->buffer_map_list, max_queue_buffers, sizeof(ALmixer_Buffer_Map), Compare_Buffer_Map); |
6849 } /* End if access_data==true */ | 7092 } /* End if access_data==true */ |
6850 | 7093 |
6851 | 7094 |
6852 } /* End of do stream */ | 7095 } /* End of do stream */ |
6853 } /* end of DECODE_STREAM */ | 7096 } /* end of DECODE_STREAM */ |
6854 /* User requested decode all (easy, nothing to figure out) */ | 7097 /* User requested decode all (easy, nothing to figure out) */ |
6855 else if(ALMIXER_DECODE_ALL == decode_mode) | 7098 else if(SDL_TRUE == decode_mode_is_predecoded) |
6856 { | 7099 { |
6857 bytes_decoded = Sound_DecodeAll(sample); | 7100 bytes_decoded = Sound_DecodeAll(sample); |
6858 if(sample->flags & SOUND_SAMPLEFLAG_ERROR) | 7101 if(sample->flags & SOUND_SAMPLEFLAG_ERROR) |
6859 { | 7102 { |
6860 ALmixer_SetError(Sound_GetError()); | 7103 ALmixer_SetError(Sound_GetError()); |
6993 * I don't like the AudioInfo parameter. I removed it once, | 7236 * I don't like the AudioInfo parameter. I removed it once, |
6994 * but the system will fail on RAW samples because the user | 7237 * but the system will fail on RAW samples because the user |
6995 * must specify it, so I had to bring it back. | 7238 * must specify it, so I had to bring it back. |
6996 * Remember I must close the rwops if there is an error before NewSample() | 7239 * Remember I must close the rwops if there is an error before NewSample() |
6997 */ | 7240 */ |
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) | 7241 ALmixer_Data* ALmixer_LoadSample_RW(SDL_RWops* rwops, const char* fileext, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data) |
6999 { | 7242 { |
7000 Sound_Sample* sample = NULL; | 7243 Sound_Sample* sample = NULL; |
7001 Sound_AudioInfo target; | 7244 Sound_AudioInfo target; |
7002 | 7245 |
7003 /* Initialize target values to defaults | 7246 /* Initialize target values to defaults |
7029 { | 7272 { |
7030 ALmixer_SetError(Sound_GetError()); | 7273 ALmixer_SetError(Sound_GetError()); |
7031 return NULL; | 7274 return NULL; |
7032 } | 7275 } |
7033 | 7276 |
7034 return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data)); | 7277 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); |
7035 } | 7278 } |
7036 | 7279 |
7037 | 7280 |
7038 | 7281 |
7039 /* This will load a sample for us from | 7282 /* This will load a sample for us from |
7040 * a file (instead of RWops). Most of the uglyness is | 7283 * a file (instead of RWops). Most of the uglyness is |
7041 * error checking and the fact that streamed/predecoded files | 7284 * error checking and the fact that streamed/predecoded files |
7042 * must be treated differently. | 7285 * must be treated differently. |
7043 */ | 7286 */ |
7044 ALmixer_Data* ALmixer_LoadSample(const char* filename, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data) | 7287 ALmixer_Data* ALmixer_LoadSample(const char* filename, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data) |
7045 { | 7288 { |
7046 Sound_Sample* sample = NULL; | 7289 Sound_Sample* sample = NULL; |
7047 Sound_AudioInfo target; | 7290 Sound_AudioInfo target; |
7048 | 7291 |
7049 /* Initialize target values to defaults | 7292 /* Initialize target values to defaults |
7133 return NULL; | 7376 return NULL; |
7134 } | 7377 } |
7135 | 7378 |
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); | 7379 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 | 7380 |
7138 return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data)); | 7381 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); |
7139 } | 7382 } |
7140 | 7383 |
7141 | 7384 |
7142 /* This is a back door for RAW samples or if you need the | 7385 /* This is a back door for RAW samples or if you need the |
7143 * AudioInfo field. Use at your own risk. | 7386 * AudioInfo field. Use at your own risk. |
7144 */ | 7387 */ |
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) | 7388 ALmixer_Data* ALmixer_LoadSample_RAW_RW(SDL_RWops* rwops, const char* fileext, ALmixer_AudioInfo* desired, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data) |
7146 { | 7389 { |
7147 Sound_Sample* sample = NULL; | 7390 Sound_Sample* sample = NULL; |
7148 sample = Sound_NewSample(rwops, fileext, desired, buffersize); | 7391 Sound_AudioInfo sound_desired; |
7392 /* Rather than copying the data from struct to struct, I could just | |
7393 * cast the thing since the structs are meant to be identical. | |
7394 * But if SDL_sound changes it's implementation, bad things | |
7395 * will probably happen. (Or if I change my implementation and | |
7396 * forget about the cast, same bad scenario.) Since this is a load | |
7397 * function, performance of this is negligible. | |
7398 */ | |
7399 if(NULL == desired) | |
7400 { | |
7401 sample = Sound_NewSample(rwops, fileext, NULL, buffersize); | |
7402 } | |
7403 else | |
7404 { | |
7405 sound_desired.format = desired->format; | |
7406 sound_desired.channels = desired->channels; | |
7407 sound_desired.rate = desired->rate; | |
7408 sample = Sound_NewSample(rwops, fileext, &sound_desired, buffersize); | |
7409 } | |
7149 if(NULL == sample) | 7410 if(NULL == sample) |
7150 { | 7411 { |
7151 ALmixer_SetError(Sound_GetError()); | 7412 ALmixer_SetError(Sound_GetError()); |
7152 return NULL; | 7413 return NULL; |
7153 } | 7414 } |
7154 return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data)); | 7415 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); |
7155 } | 7416 } |
7156 | 7417 |
7157 | 7418 |
7158 | 7419 |
7159 | 7420 |
7160 /* This is a back door for RAW samples or if you need the | 7421 /* This is a back door for RAW samples or if you need the |
7161 * AudioInfo field. Use at your own risk. | 7422 * AudioInfo field. Use at your own risk. |
7162 */ | 7423 */ |
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) | 7424 ALmixer_Data* ALmixer_LoadSample_RAW(const char* filename, ALmixer_AudioInfo* desired, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data) |
7164 { | 7425 { |
7165 Sound_Sample* sample = NULL; | 7426 Sound_Sample* sample = NULL; |
7166 sample = Sound_NewSampleFromFile(filename, desired, buffersize); | 7427 Sound_AudioInfo sound_desired; |
7428 /* Rather than copying the data from struct to struct, I could just | |
7429 * cast the thing since the structs are meant to be identical. | |
7430 * But if SDL_sound changes it's implementation, bad things | |
7431 * will probably happen. (Or if I change my implementation and | |
7432 * forget about the cast, same bad scenario.) Since this is a load | |
7433 * function, performance of this is negligible. | |
7434 */ | |
7435 if(NULL == desired) | |
7436 { | |
7437 sample = Sound_NewSampleFromFile(filename, NULL, buffersize); | |
7438 } | |
7439 else | |
7440 { | |
7441 sound_desired.format = desired->format; | |
7442 sound_desired.channels = desired->channels; | |
7443 sound_desired.rate = desired->rate; | |
7444 sample = Sound_NewSampleFromFile(filename, &sound_desired, buffersize); | |
7445 } | |
7446 | |
7167 if(NULL == sample) | 7447 if(NULL == sample) |
7168 { | 7448 { |
7169 ALmixer_SetError(Sound_GetError()); | 7449 ALmixer_SetError(Sound_GetError()); |
7170 return NULL; | 7450 return NULL; |
7171 } | 7451 } |
7172 return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data)); | 7452 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); |
7173 } | 7453 } |
7174 | 7454 |
7175 | 7455 |
7176 | 7456 |
7177 | 7457 |
7302 Channel_Done_Callback_Userdata = userdata; | 7582 Channel_Done_Callback_Userdata = userdata; |
7303 SDL_UnlockMutex(simple_lock); | 7583 SDL_UnlockMutex(simple_lock); |
7304 } | 7584 } |
7305 | 7585 |
7306 | 7586 |
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)) | 7587 void ALmixer_ChannelData(void (*channel_data)(Sint32 which_chan, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bit_depth, SDL_bool is_unsigned, SDL_bool decode_mode_is_predecoded, Uint32 length_in_msec, void* user_data), void* user_data) |
7308 { | 7588 { |
7309 SDL_LockMutex(simple_lock); | 7589 SDL_LockMutex(simple_lock); |
7310 Channel_Data_Callback = channel_data; | 7590 Channel_Data_Callback = channel_data; |
7591 Channel_Data_Callback_Userdata = user_data; | |
7311 SDL_UnlockMutex(simple_lock); | 7592 SDL_UnlockMutex(simple_lock); |
7312 } | 7593 } |
7313 | 7594 |
7314 | 7595 |
7315 | 7596 |
7707 retval = Internal_CountUnreservedUsedChannels(); | 7988 retval = Internal_CountUnreservedUsedChannels(); |
7708 SDL_UnlockMutex(simple_lock); | 7989 SDL_UnlockMutex(simple_lock); |
7709 return retval; | 7990 return retval; |
7710 } | 7991 } |
7711 | 7992 |
7712 | 7993 SDL_bool ALmixer_IsPredecoded(ALmixer_Data* data) |
7713 | 7994 { |
7714 | 7995 if(NULL == data) |
7715 | 7996 { |
7997 return SDL_FALSE; | |
7998 } | |
7999 return data->decoded_all; | |
8000 } | |
8001 | |
8002 | |
8003 | |
8004 | |
8005 |