1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 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
Audio_Available(void)56 static int Audio_Available(void)
57 {
58 return 1;
59 }
60
Audio_DeleteDevice(SDL_AudioDevice * device)61 static void Audio_DeleteDevice(SDL_AudioDevice *device)
62 {
63 SDL_free(device->hidden);
64 SDL_free(device);
65 }
66
Audio_CreateDevice(int devindex)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
AL_WaitAudio(_THIS)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
AL_PlayAudio(_THIS)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
AL_GetAudioBuf(_THIS)125 static Uint8 *AL_GetAudioBuf(_THIS)
126 {
127 return(mixbuf);
128 }
129
AL_CloseAudio(_THIS)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
AL_OpenAudio(_THIS,SDL_AudioSpec * spec)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