1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* Allow access to a raw mixing buffer (For IRIX 6.5 and higher) */ 25 /* patch for IRIX 5 by Georg Schwarz 18/07/2004 */ 26 27 #include "SDL_timer.h" 28 #include "SDL_audio.h" 29 #include "../SDL_audiomem.h" 30 #include "../SDL_audio_c.h" 31 #include "SDL_irixaudio.h" 32 33 34 #ifndef AL_RESOURCE /* as a test whether we use the old IRIX audio libraries */ 35 #define OLD_IRIX_AUDIO 36 #define alClosePort(x) ALcloseport(x) 37 #define alFreeConfig(x) ALfreeconfig(x) 38 #define alGetFillable(x) ALgetfillable(x) 39 #define alNewConfig() ALnewconfig() 40 #define alOpenPort(x,y,z) ALopenport(x,y,z) 41 #define alSetChannels(x,y) ALsetchannels(x,y) 42 #define alSetQueueSize(x,y) ALsetqueuesize(x,y) 43 #define alSetSampFmt(x,y) ALsetsampfmt(x,y) 44 #define alSetWidth(x,y) ALsetwidth(x,y) 45 #endif 46 47 /* Audio driver functions */ 48 static int AL_OpenAudio(_THIS, SDL_AudioSpec *spec); 49 static void AL_WaitAudio(_THIS); 50 static void AL_PlayAudio(_THIS); 51 static Uint8 *AL_GetAudioBuf(_THIS); 52 static void AL_CloseAudio(_THIS); 53 54 /* Audio driver bootstrap functions */ 55 56 static int Audio_Available(void) 57 { 58 return 1; 59 } 60 61 static void Audio_DeleteDevice(SDL_AudioDevice *device) 62 { 63 SDL_free(device->hidden); 64 SDL_free(device); 65 } 66 67 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 68 { 69 SDL_AudioDevice *this; 70 71 /* Initialize all variables that we clean on shutdown */ 72 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 73 if ( this ) { 74 SDL_memset(this, 0, (sizeof *this)); 75 this->hidden = (struct SDL_PrivateAudioData *) 76 SDL_malloc((sizeof *this->hidden)); 77 } 78 if ( (this == NULL) || (this->hidden == NULL) ) { 79 SDL_OutOfMemory(); 80 if ( this ) { 81 SDL_free(this); 82 } 83 return(0); 84 } 85 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 86 87 /* Set the function pointers */ 88 this->OpenAudio = AL_OpenAudio; 89 this->WaitAudio = AL_WaitAudio; 90 this->PlayAudio = AL_PlayAudio; 91 this->GetAudioBuf = AL_GetAudioBuf; 92 this->CloseAudio = AL_CloseAudio; 93 94 this->free = Audio_DeleteDevice; 95 96 return this; 97 } 98 99 AudioBootStrap DMEDIA_bootstrap = { 100 "AL", "IRIX DMedia audio", 101 Audio_Available, Audio_CreateDevice 102 }; 103 104 105 void static AL_WaitAudio(_THIS) 106 { 107 Sint32 timeleft; 108 109 timeleft = this->spec.samples - alGetFillable(audio_port); 110 if ( timeleft > 0 ) { 111 timeleft /= (this->spec.freq/1000); 112 SDL_Delay((Uint32)timeleft); 113 } 114 } 115 116 static void AL_PlayAudio(_THIS) 117 { 118 /* Write the audio data out */ 119 if ( alWriteFrames(audio_port, mixbuf, this->spec.samples) < 0 ) { 120 /* Assume fatal error, for now */ 121 this->enabled = 0; 122 } 123 } 124 125 static Uint8 *AL_GetAudioBuf(_THIS) 126 { 127 return(mixbuf); 128 } 129 130 static void AL_CloseAudio(_THIS) 131 { 132 if ( mixbuf != NULL ) { 133 SDL_FreeAudioMem(mixbuf); 134 mixbuf = NULL; 135 } 136 if ( audio_port != NULL ) { 137 alClosePort(audio_port); 138 audio_port = NULL; 139 } 140 } 141 142 static int AL_OpenAudio(_THIS, SDL_AudioSpec * spec) 143 { 144 Uint16 test_format = SDL_FirstAudioFormat(spec->format); 145 long width = 0; 146 long fmt = 0; 147 int valid = 0; 148 149 #ifdef OLD_IRIX_AUDIO 150 { 151 long audio_param[2]; 152 audio_param[0] = AL_OUTPUT_RATE; 153 audio_param[1] = spec->freq; 154 valid = (ALsetparams(AL_DEFAULT_DEVICE, audio_param, 2) < 0); 155 } 156 #else 157 { 158 ALpv audio_param; 159 audio_param.param = AL_RATE; 160 audio_param.value.i = spec->freq; 161 valid = (alSetParams(AL_DEFAULT_OUTPUT, &audio_param, 1) < 0); 162 } 163 #endif 164 165 while ((!valid) && (test_format)) { 166 valid = 1; 167 spec->format = test_format; 168 169 switch (test_format) { 170 case AUDIO_S8: 171 width = AL_SAMPLE_8; 172 fmt = AL_SAMPFMT_TWOSCOMP; 173 break; 174 175 case AUDIO_S16SYS: 176 width = AL_SAMPLE_16; 177 fmt = AL_SAMPFMT_TWOSCOMP; 178 break; 179 180 default: 181 valid = 0; 182 test_format = SDL_NextAudioFormat(); 183 break; 184 } 185 186 if (valid) { 187 ALconfig audio_config = alNewConfig(); 188 valid = 0; 189 if (audio_config) { 190 if (alSetChannels(audio_config, spec->channels) < 0) { 191 if (spec->channels > 2) { /* can't handle > stereo? */ 192 spec->channels = 2; /* try again below. */ 193 } 194 } 195 196 if ((alSetSampFmt(audio_config, fmt) >= 0) && 197 ((!width) || (alSetWidth(audio_config, width) >= 0)) && 198 (alSetQueueSize(audio_config, spec->samples * 2) >= 0) && 199 (alSetChannels(audio_config, spec->channels) >= 0)) { 200 201 audio_port = alOpenPort("SDL audio", "w", audio_config); 202 if (audio_port == NULL) { 203 /* docs say AL_BAD_CHANNELS happens here, too. */ 204 int err = oserror(); 205 if (err == AL_BAD_CHANNELS) { 206 spec->channels = 2; 207 alSetChannels(audio_config, spec->channels); 208 audio_port = alOpenPort("SDL audio", "w", 209 audio_config); 210 } 211 } 212 213 if (audio_port != NULL) { 214 valid = 1; 215 } 216 } 217 218 alFreeConfig(audio_config); 219 } 220 } 221 } 222 223 if (!valid) { 224 SDL_SetError("Unsupported audio format"); 225 return (-1); 226 } 227 228 /* Update the fragment size as size in bytes */ 229 SDL_CalculateAudioSpec(spec); 230 231 /* Allocate mixing buffer */ 232 mixbuf = (Uint8 *) SDL_AllocAudioMem(spec->size); 233 if (mixbuf == NULL) { 234 SDL_OutOfMemory(); 235 return (-1); 236 } 237 SDL_memset(mixbuf, spec->silence, spec->size); 238 239 /* We're ready to rock and roll. :-) */ 240 return (0); 241 } 242 243