Mercurial > sdl-ios-xcode
annotate src/audio/sun/SDL_sunaudio.c @ 571:8e3ce997621c
Date: Thu, 16 Jan 2003 13:48:31 +0200
From: "Mike Gorchak"
Subject: All QNX patches
whole patches concerning QNX. Almost all code has been rewritten by Julian
and me. Added initial support for hw overlays in QNX and many many others
fixes.
P.S. This patches has been reviewed by Dave Rempel from QSSL and included in
SDL 1.2.5 distribution, which coming on 3rd party CD for newest 6.2.1
version of QNX, which will be available soon.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 20 Jan 2003 01:38:37 +0000 |
parents | f6ffac90895c |
children | b8d311d90021 |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
297
f6ffac90895c
Updated copyright information for 2002
Sam Lantinga <slouken@libsdl.org>
parents:
252
diff
changeset
|
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 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 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
148
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* Allow access to a raw mixing buffer */ | |
29 | |
30 #include <stdlib.h> | |
31 #include <stdio.h> | |
32 #include <fcntl.h> | |
33 #include <errno.h> | |
34 #include <string.h> | |
35 #ifdef __NetBSD__ | |
36 #include <sys/ioctl.h> | |
37 #include <sys/audioio.h> | |
38 #endif | |
39 #ifdef __SVR4 | |
40 #include <sys/audioio.h> | |
41 #else | |
42 #include <sys/time.h> | |
43 #include <sys/types.h> | |
44 #endif | |
45 #include <unistd.h> | |
46 | |
47 #include "SDL_endian.h" | |
48 #include "SDL_audio.h" | |
49 #include "SDL_audiomem.h" | |
50 #include "SDL_audiodev_c.h" | |
51 #include "SDL_sunaudio.h" | |
52 #include "SDL_audio_c.h" | |
53 #include "SDL_timer.h" | |
54 | |
55 /* Open the audio device for playback, and don't block if busy */ | |
56 #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) | |
57 | |
58 /* Audio driver functions */ | |
59 static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec); | |
60 static void DSP_WaitAudio(_THIS); | |
61 static void DSP_PlayAudio(_THIS); | |
62 static Uint8 *DSP_GetAudioBuf(_THIS); | |
63 static void DSP_CloseAudio(_THIS); | |
64 | |
65 /* Audio driver bootstrap functions */ | |
66 | |
67 static int Audio_Available(void) | |
68 { | |
69 int fd; | |
70 int available; | |
71 | |
72 available = 0; | |
73 fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 1); | |
74 if ( fd >= 0 ) { | |
75 available = 1; | |
76 close(fd); | |
77 } | |
78 return(available); | |
79 } | |
80 | |
81 static void Audio_DeleteDevice(SDL_AudioDevice *device) | |
82 { | |
83 free(device->hidden); | |
84 free(device); | |
85 } | |
86 | |
87 static SDL_AudioDevice *Audio_CreateDevice(int devindex) | |
88 { | |
89 SDL_AudioDevice *this; | |
90 | |
91 /* Initialize all variables that we clean on shutdown */ | |
92 this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); | |
93 if ( this ) { | |
94 memset(this, 0, (sizeof *this)); | |
95 this->hidden = (struct SDL_PrivateAudioData *) | |
96 malloc((sizeof *this->hidden)); | |
97 } | |
98 if ( (this == NULL) || (this->hidden == NULL) ) { | |
99 SDL_OutOfMemory(); | |
100 if ( this ) { | |
101 free(this); | |
102 } | |
103 return(0); | |
104 } | |
105 memset(this->hidden, 0, (sizeof *this->hidden)); | |
106 audio_fd = -1; | |
107 | |
108 /* Set the function pointers */ | |
109 this->OpenAudio = DSP_OpenAudio; | |
110 this->WaitAudio = DSP_WaitAudio; | |
111 this->PlayAudio = DSP_PlayAudio; | |
112 this->GetAudioBuf = DSP_GetAudioBuf; | |
113 this->CloseAudio = DSP_CloseAudio; | |
114 | |
115 this->free = Audio_DeleteDevice; | |
116 | |
117 return this; | |
118 } | |
119 | |
148
8758b8d42cd9
Audio subsystem no longer assumes sun audio API on UNIX systems
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
120 AudioBootStrap SUNAUDIO_bootstrap = { |
0 | 121 "audio", "UNIX /dev/audio interface", |
122 Audio_Available, Audio_CreateDevice | |
123 }; | |
124 | |
125 #ifdef DEBUG_AUDIO | |
126 void CheckUnderflow(_THIS) | |
127 { | |
128 #ifdef AUDIO_GETINFO | |
129 audio_info_t info; | |
130 int left; | |
131 | |
132 ioctl(audio_fd, AUDIO_GETINFO, &info); | |
133 left = (written - info.play.samples); | |
134 if ( written && (left == 0) ) { | |
135 fprintf(stderr, "audio underflow!\n"); | |
136 } | |
137 #endif | |
138 } | |
139 #endif | |
140 | |
141 void DSP_WaitAudio(_THIS) | |
142 { | |
143 #ifdef AUDIO_GETINFO | |
144 #define SLEEP_FUDGE 10 /* 10 ms scheduling fudge factor */ | |
145 audio_info_t info; | |
146 Sint32 left; | |
147 | |
148 ioctl(audio_fd, AUDIO_GETINFO, &info); | |
149 left = (written - info.play.samples); | |
150 if ( left > fragsize ) { | |
151 Sint32 sleepy; | |
152 | |
153 sleepy = ((left - fragsize)/frequency); | |
154 sleepy -= SLEEP_FUDGE; | |
155 if ( sleepy > 0 ) { | |
156 SDL_Delay(sleepy); | |
157 } | |
158 } | |
159 #else | |
160 fd_set fdset; | |
161 | |
162 FD_ZERO(&fdset); | |
163 FD_SET(audio_fd, &fdset); | |
164 select(audio_fd+1, NULL, &fdset, NULL, NULL); | |
165 #endif | |
166 } | |
167 | |
168 void DSP_PlayAudio(_THIS) | |
169 { | |
170 static Uint8 snd2au(int sample); | |
171 /* Write the audio data */ | |
172 if ( ulaw_only ) { | |
173 /* Assuming that this->spec.freq >= 8000 Hz */ | |
174 int accum, incr, pos; | |
175 Uint8 *aubuf; | |
176 | |
177 accum = 0; | |
178 incr = this->spec.freq/8; | |
179 aubuf = ulaw_buf; | |
180 switch (audio_fmt & 0xFF) { | |
181 case 8: { | |
182 Uint8 *sndbuf; | |
183 | |
184 sndbuf = mixbuf; | |
185 for ( pos=0; pos < fragsize; ++pos ) { | |
186 *aubuf = snd2au((0x80-*sndbuf)*64); | |
187 accum += incr; | |
188 while ( accum > 0 ) { | |
189 accum -= 1000; | |
190 sndbuf += 1; | |
191 } | |
192 aubuf += 1; | |
193 } | |
194 } | |
195 break; | |
196 case 16: { | |
197 Sint16 *sndbuf; | |
198 | |
199 sndbuf = (Sint16 *)mixbuf; | |
200 for ( pos=0; pos < fragsize; ++pos ) { | |
201 *aubuf = snd2au(*sndbuf/4); | |
202 accum += incr; | |
203 while ( accum > 0 ) { | |
204 accum -= 1000; | |
205 sndbuf += 1; | |
206 } | |
207 aubuf += 1; | |
208 } | |
209 } | |
210 break; | |
211 } | |
212 #ifdef DEBUG_AUDIO | |
213 CheckUnderflow(this); | |
214 #endif | |
215 if ( write(audio_fd, ulaw_buf, fragsize) < 0 ) { | |
216 /* Assume fatal error, for now */ | |
217 this->enabled = 0; | |
218 } | |
219 written += fragsize; | |
220 } else { | |
221 #ifdef DEBUG_AUDIO | |
222 CheckUnderflow(this); | |
223 #endif | |
224 if ( write(audio_fd, mixbuf, this->spec.size) < 0 ) { | |
225 /* Assume fatal error, for now */ | |
226 this->enabled = 0; | |
227 } | |
228 written += fragsize; | |
229 } | |
230 } | |
231 | |
232 Uint8 *DSP_GetAudioBuf(_THIS) | |
233 { | |
234 return(mixbuf); | |
235 } | |
236 | |
237 void DSP_CloseAudio(_THIS) | |
238 { | |
239 if ( mixbuf != NULL ) { | |
240 SDL_FreeAudioMem(mixbuf); | |
241 mixbuf = NULL; | |
242 } | |
243 if ( ulaw_buf != NULL ) { | |
244 free(ulaw_buf); | |
245 ulaw_buf = NULL; | |
246 } | |
247 close(audio_fd); | |
248 } | |
249 | |
250 int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec) | |
251 { | |
252 char audiodev[1024]; | |
253 #ifdef AUDIO_SETINFO | |
254 int enc; | |
255 #endif | |
256 int desired_freq = spec->freq; | |
257 | |
258 /* Initialize our freeable variables, in case we fail*/ | |
259 audio_fd = -1; | |
260 mixbuf = NULL; | |
261 ulaw_buf = NULL; | |
262 | |
263 /* Determine the audio parameters from the AudioSpec */ | |
264 switch ( spec->format & 0xFF ) { | |
265 | |
266 case 8: { /* Unsigned 8 bit audio data */ | |
267 spec->format = AUDIO_U8; | |
268 #ifdef AUDIO_SETINFO | |
269 enc = AUDIO_ENCODING_LINEAR8; | |
270 #endif | |
271 } | |
272 break; | |
273 | |
274 case 16: { /* Signed 16 bit audio data */ | |
275 spec->format = AUDIO_S16SYS; | |
276 #ifdef AUDIO_SETINFO | |
277 enc = AUDIO_ENCODING_LINEAR; | |
278 #endif | |
279 } | |
280 break; | |
281 | |
282 default: { | |
283 SDL_SetError("Unsupported audio format"); | |
284 return(-1); | |
285 } | |
286 } | |
287 audio_fmt = spec->format; | |
288 | |
289 /* Open the audio device */ | |
290 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 1); | |
291 if ( audio_fd < 0 ) { | |
292 SDL_SetError("Couldn't open %s: %s", audiodev, | |
293 strerror(errno)); | |
294 return(-1); | |
295 } | |
296 | |
297 ulaw_only = 0; /* modern Suns do support linear audio */ | |
298 #ifdef AUDIO_SETINFO | |
299 for(;;) { | |
300 audio_info_t info; | |
301 AUDIO_INITINFO(&info); /* init all fields to "no change" */ | |
302 | |
303 /* Try to set the requested settings */ | |
304 info.play.sample_rate = spec->freq; | |
305 info.play.channels = spec->channels; | |
306 info.play.precision = (enc == AUDIO_ENCODING_ULAW) | |
307 ? 8 : spec->format & 0xff; | |
308 info.play.encoding = enc; | |
309 if( ioctl(audio_fd, AUDIO_SETINFO, &info) == 0 ) { | |
310 | |
311 /* Check to be sure we got what we wanted */ | |
312 if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) { | |
313 SDL_SetError("Error getting audio parameters: %s", | |
314 strerror(errno)); | |
315 return -1; | |
316 } | |
317 if(info.play.encoding == enc | |
318 && info.play.precision == (spec->format & 0xff) | |
319 && info.play.channels == spec->channels) { | |
320 /* Yow! All seems to be well! */ | |
321 spec->freq = info.play.sample_rate; | |
322 break; | |
323 } | |
324 } | |
325 | |
326 switch(enc) { | |
327 case AUDIO_ENCODING_LINEAR8: | |
328 /* unsigned 8bit apparently not supported here */ | |
329 enc = AUDIO_ENCODING_LINEAR; | |
330 spec->format = AUDIO_S16SYS; | |
331 break; /* try again */ | |
332 | |
333 case AUDIO_ENCODING_LINEAR: | |
334 /* linear 16bit didn't work either, resort to µ-law */ | |
335 enc = AUDIO_ENCODING_ULAW; | |
336 spec->channels = 1; | |
337 spec->freq = 8000; | |
338 spec->format = AUDIO_U8; | |
339 ulaw_only = 1; | |
340 break; | |
341 | |
342 default: | |
343 /* oh well... */ | |
344 SDL_SetError("Error setting audio parameters: %s", | |
345 strerror(errno)); | |
346 return -1; | |
347 } | |
348 } | |
349 #endif /* AUDIO_SETINFO */ | |
350 written = 0; | |
351 | |
352 /* We can actually convert on-the-fly to U-Law */ | |
353 if ( ulaw_only ) { | |
354 spec->freq = desired_freq; | |
355 fragsize = (spec->samples*1000)/(spec->freq/8); | |
356 frequency = 8; | |
357 ulaw_buf = (Uint8 *)malloc(fragsize); | |
358 if ( ulaw_buf == NULL ) { | |
359 SDL_OutOfMemory(); | |
360 return(-1); | |
361 } | |
362 spec->channels = 1; | |
363 } else { | |
364 fragsize = spec->samples; | |
365 frequency = spec->freq/1000; | |
366 } | |
367 #ifdef DEBUG_AUDIO | |
368 fprintf(stderr, "Audio device %s U-Law only\n", | |
369 ulaw_only ? "is" : "is not"); | |
370 fprintf(stderr, "format=0x%x chan=%d freq=%d\n", | |
371 spec->format, spec->channels, spec->freq); | |
372 #endif | |
373 | |
374 /* Update the fragment size as size in bytes */ | |
375 SDL_CalculateAudioSpec(spec); | |
376 | |
377 /* Allocate mixing buffer */ | |
378 mixbuf = (Uint8 *)SDL_AllocAudioMem(spec->size); | |
379 if ( mixbuf == NULL ) { | |
380 SDL_OutOfMemory(); | |
381 return(-1); | |
382 } | |
383 memset(mixbuf, spec->silence, spec->size); | |
384 | |
385 /* We're ready to rock and roll. :-) */ | |
386 return(0); | |
387 } | |
388 | |
389 /************************************************************************/ | |
390 /* This function (snd2au()) copyrighted: */ | |
391 /************************************************************************/ | |
392 /* Copyright 1989 by Rich Gopstein and Harris Corporation */ | |
393 /* */ | |
394 /* Permission to use, copy, modify, and distribute this software */ | |
395 /* and its documentation for any purpose and without fee is */ | |
396 /* hereby granted, provided that the above copyright notice */ | |
397 /* appears in all copies and that both that copyright notice and */ | |
398 /* this permission notice appear in supporting documentation, and */ | |
399 /* that the name of Rich Gopstein and Harris Corporation not be */ | |
400 /* used in advertising or publicity pertaining to distribution */ | |
401 /* of the software without specific, written prior permission. */ | |
402 /* Rich Gopstein and Harris Corporation make no representations */ | |
403 /* about the suitability of this software for any purpose. It */ | |
404 /* provided "as is" without express or implied warranty. */ | |
405 /************************************************************************/ | |
406 | |
407 static Uint8 snd2au(int sample) | |
408 { | |
409 | |
410 int mask; | |
411 | |
412 if (sample < 0) { | |
413 sample = -sample; | |
414 mask = 0x7f; | |
415 } else { | |
416 mask = 0xff; | |
417 } | |
418 | |
419 if (sample < 32) { | |
420 sample = 0xF0 | (15 - sample / 2); | |
421 } else if (sample < 96) { | |
422 sample = 0xE0 | (15 - (sample - 32) / 4); | |
423 } else if (sample < 224) { | |
424 sample = 0xD0 | (15 - (sample - 96) / 8); | |
425 } else if (sample < 480) { | |
426 sample = 0xC0 | (15 - (sample - 224) / 16); | |
427 } else if (sample < 992) { | |
428 sample = 0xB0 | (15 - (sample - 480) / 32); | |
429 } else if (sample < 2016) { | |
430 sample = 0xA0 | (15 - (sample - 992) / 64); | |
431 } else if (sample < 4064) { | |
432 sample = 0x90 | (15 - (sample - 2016) / 128); | |
433 } else if (sample < 8160) { | |
434 sample = 0x80 | (15 - (sample - 4064) / 256); | |
435 } else { | |
436 sample = 0x80; | |
437 } | |
438 return (mask & sample); | |
439 } |