SDL-1.2.14
[sdl_omap.git] / src / audio / dmedia / SDL_irixaudio.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 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@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