Mercurial > sdl-ios-xcode
comparison src/audio/ums/SDL_umsaudio.c @ 0:74212992fb08
Initial revision
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 16:45:43 +0000 |
parents | |
children | c9b51268668f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:74212992fb08 |
---|---|
1 /* | |
2 AIX support for the SDL - Simple DirectMedia Layer | |
3 Copyright (C) 2000 Carsten Griwodz | |
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 Carsten Griwodz | |
20 griff@kom.tu-darmstadt.de | |
21 | |
22 based on linux/SDL_dspaudio.c by Sam Lantinga | |
23 */ | |
24 | |
25 #ifdef SAVE_RCSID | |
26 static char rcsid = | |
27 "@(#) $Id$"; | |
28 #endif | |
29 | |
30 /* Allow access to a raw mixing buffer */ | |
31 | |
32 #include <stdlib.h> | |
33 #include <stdio.h> | |
34 #include <string.h> | |
35 #include <errno.h> | |
36 #include <unistd.h> | |
37 #include <fcntl.h> | |
38 #include <sys/types.h> | |
39 #include <sys/time.h> | |
40 #include <sys/ioctl.h> | |
41 #include <sys/stat.h> | |
42 #include <sys/mman.h> | |
43 | |
44 #include "SDL_audio.h" | |
45 #include "SDL_error.h" | |
46 #include "SDL_audio_c.h" | |
47 #include "SDL_audiodev_c.h" | |
48 #include "SDL_umsaudio.h" | |
49 | |
50 /* The tag name used by UMS audio */ | |
51 #define UMS_DRIVER_NAME "ums" | |
52 | |
53 #define DEBUG_AUDIO 1 | |
54 | |
55 /* Audio driver functions */ | |
56 static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec); | |
57 static void UMS_PlayAudio(_THIS); | |
58 static Uint8 *UMS_GetAudioBuf(_THIS); | |
59 static void UMS_CloseAudio(_THIS); | |
60 | |
61 static UMSAudioDevice_ReturnCode UADOpen(_THIS, string device, string mode, long flags); | |
62 static UMSAudioDevice_ReturnCode UADClose(_THIS); | |
63 static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits); | |
64 static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits); | |
65 static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate); | |
66 static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order); | |
67 static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt); | |
68 static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt); | |
69 static UMSAudioDevice_ReturnCode UADInitialize(_THIS); | |
70 static UMSAudioDevice_ReturnCode UADStart(_THIS); | |
71 static UMSAudioDevice_ReturnCode UADStop(_THIS); | |
72 static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS, UMSAudioTypes_TimeFormat fmt ); | |
73 static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS, long* buff_size ); | |
74 static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS, long* buff_size ); | |
75 static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS, long* buff_size ); | |
76 static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS, long bytes, long* bytes_ret ); | |
77 static UMSAudioDevice_ReturnCode UADSetVolume(_THIS, long volume ); | |
78 static UMSAudioDevice_ReturnCode UADSetBalance(_THIS, long balance ); | |
79 static UMSAudioDevice_ReturnCode UADSetChannels(_THIS, long channels ); | |
80 static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS, boolean block ); | |
81 static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS, string output, long* left_gain, long* right_gain); | |
82 static UMSAudioDevice_ReturnCode UADWrite(_THIS, UMSAudioTypes_Buffer* buff, long samples, long* samples_written); | |
83 | |
84 /* Audio driver bootstrap functions */ | |
85 static int Audio_Available(void) | |
86 { | |
87 return 1; | |
88 } | |
89 | |
90 static void Audio_DeleteDevice(_THIS) | |
91 { | |
92 if(this->hidden->playbuf._buffer) free(this->hidden->playbuf._buffer); | |
93 if(this->hidden->fillbuf._buffer) free(this->hidden->fillbuf._buffer); | |
94 _somFree( this->hidden->umsdev ); | |
95 free(this->hidden); | |
96 free(this); | |
97 } | |
98 | |
99 static SDL_AudioDevice *Audio_CreateDevice(int devindex) | |
100 { | |
101 SDL_AudioDevice *this; | |
102 | |
103 /* | |
104 * Allocate and initialize management storage and private management | |
105 * storage for this SDL-using library. | |
106 */ | |
107 this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); | |
108 if ( this ) { | |
109 memset(this, 0, (sizeof *this)); | |
110 this->hidden = (struct SDL_PrivateAudioData *)malloc((sizeof *this->hidden)); | |
111 } | |
112 if ( (this == NULL) || (this->hidden == NULL) ) { | |
113 SDL_OutOfMemory(); | |
114 if ( this ) { | |
115 free(this); | |
116 } | |
117 return(0); | |
118 } | |
119 memset(this->hidden, 0, (sizeof *this->hidden)); | |
120 #ifdef DEBUG_AUDIO | |
121 fprintf(stderr, "Creating UMS Audio device\n"); | |
122 #endif | |
123 | |
124 /* | |
125 * Calls for UMS env initialization and audio object construction. | |
126 */ | |
127 this->hidden->ev = somGetGlobalEnvironment(); | |
128 this->hidden->umsdev = UMSAudioDeviceNew(); | |
129 | |
130 /* | |
131 * Set the function pointers. | |
132 */ | |
133 this->OpenAudio = UMS_OpenAudio; | |
134 this->WaitAudio = NULL; /* we do blocking output */ | |
135 this->PlayAudio = UMS_PlayAudio; | |
136 this->GetAudioBuf = UMS_GetAudioBuf; | |
137 this->CloseAudio = UMS_CloseAudio; | |
138 this->free = Audio_DeleteDevice; | |
139 | |
140 #ifdef DEBUG_AUDIO | |
141 fprintf(stderr, "done\n"); | |
142 #endif | |
143 return this; | |
144 } | |
145 | |
146 AudioBootStrap UMS_bootstrap = { | |
147 UMS_DRIVER_NAME, "AUX UMS audio", | |
148 Audio_Available, Audio_CreateDevice | |
149 }; | |
150 | |
151 static Uint8 *UMS_GetAudioBuf(_THIS) | |
152 { | |
153 #ifdef DEBUG_AUDIO | |
154 fprintf(stderr, "enter UMS_GetAudioBuf\n"); | |
155 #endif | |
156 return this->hidden->fillbuf._buffer; | |
157 /* | |
158 long bufSize; | |
159 UMSAudioDevice_ReturnCode rc; | |
160 | |
161 rc = UADSetTimeFormat(this, UMSAudioTypes_Bytes ); | |
162 rc = UADWriteBuffSize(this, bufSize ); | |
163 */ | |
164 } | |
165 | |
166 static void UMS_CloseAudio(_THIS) | |
167 { | |
168 UMSAudioDevice_ReturnCode rc; | |
169 | |
170 #ifdef DEBUG_AUDIO | |
171 fprintf(stderr, "enter UMS_CloseAudio\n"); | |
172 #endif | |
173 rc = UADPlayRemainingData(this, TRUE); | |
174 rc = UADStop(this); | |
175 rc = UADClose(this); | |
176 } | |
177 | |
178 static void UMS_PlayAudio(_THIS) | |
179 { | |
180 UMSAudioDevice_ReturnCode rc; | |
181 long samplesToWrite; | |
182 long samplesWritten; | |
183 UMSAudioTypes_Buffer swpbuf; | |
184 | |
185 #ifdef DEBUG_AUDIO | |
186 fprintf(stderr, "enter UMS_PlayAudio\n"); | |
187 #endif | |
188 samplesToWrite = this->hidden->playbuf._length/this->hidden->bytesPerSample; | |
189 do | |
190 { | |
191 rc = UADWrite(this, &this->hidden->playbuf, | |
192 samplesToWrite, | |
193 &samplesWritten ); | |
194 samplesToWrite -= samplesWritten; | |
195 | |
196 /* rc values: UMSAudioDevice_Success | |
197 * UMSAudioDevice_Failure | |
198 * UMSAudioDevice_Preempted | |
199 * UMSAudioDevice_Interrupted | |
200 * UMSAudioDevice_DeviceError | |
201 */ | |
202 if ( rc == UMSAudioDevice_DeviceError ) { | |
203 #ifdef DEBUG_AUDIO | |
204 fprintf(stderr, "Returning from PlayAudio with devices error\n"); | |
205 #endif | |
206 return; | |
207 } | |
208 } | |
209 while(samplesToWrite>0); | |
210 | |
211 SDL_LockAudio(); | |
212 memcpy( &swpbuf, &this->hidden->playbuf, sizeof(UMSAudioTypes_Buffer) ); | |
213 memcpy( &this->hidden->playbuf, &this->hidden->fillbuf, sizeof(UMSAudioTypes_Buffer) ); | |
214 memcpy( &this->hidden->fillbuf, &swpbuf, sizeof(UMSAudioTypes_Buffer) ); | |
215 SDL_UnlockAudio(); | |
216 | |
217 #ifdef DEBUG_AUDIO | |
218 fprintf(stderr, "Wrote audio data and swapped buffer\n"); | |
219 #endif | |
220 } | |
221 | |
222 #if 0 | |
223 // /* Set the DSP frequency */ | |
224 // value = spec->freq; | |
225 // if ( ioctl(this->hidden->audio_fd, SOUND_PCM_WRITE_RATE, &value) < 0 ) { | |
226 // SDL_SetError("Couldn't set audio frequency"); | |
227 // return(-1); | |
228 // } | |
229 // spec->freq = value; | |
230 #endif | |
231 | |
232 static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec) | |
233 { | |
234 char* audiodev = "/dev/paud0"; | |
235 long lgain; | |
236 long rgain; | |
237 long outRate; | |
238 long outBufSize; | |
239 long bitsPerSample; | |
240 long samplesPerSec; | |
241 long success; | |
242 Uint16 test_format; | |
243 int frag_spec; | |
244 UMSAudioDevice_ReturnCode rc; | |
245 | |
246 #ifdef DEBUG_AUDIO | |
247 fprintf(stderr, "enter UMS_OpenAudio\n"); | |
248 #endif | |
249 rc = UADOpen(this, audiodev,"PLAY", UMSAudioDevice_BlockingIO); | |
250 if ( rc != UMSAudioDevice_Success ) { | |
251 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); | |
252 return -1; | |
253 } | |
254 | |
255 rc = UADSetAudioFormatType(this, "PCM"); | |
256 | |
257 success = 0; | |
258 test_format = SDL_FirstAudioFormat(spec->format); | |
259 do | |
260 { | |
261 #ifdef DEBUG_AUDIO | |
262 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | |
263 #endif | |
264 switch ( test_format ) | |
265 { | |
266 case AUDIO_U8: | |
267 /* from the mac code: better ? */ | |
268 /* sample_bits = spec->size / spec->samples / spec->channels * 8; */ | |
269 success = 1; | |
270 bitsPerSample = 8; | |
271 rc = UADSetSampleRate(this, spec->freq << 16, &outRate ); | |
272 rc = UADSetByteOrder(this, "MSB"); /* irrelevant */ | |
273 rc = UADSetNumberFormat(this, "UNSIGNED"); | |
274 break; | |
275 case AUDIO_S8: | |
276 success = 1; | |
277 bitsPerSample = 8; | |
278 rc = UADSetSampleRate(this, spec->freq << 16, &outRate ); | |
279 rc = UADSetByteOrder(this, "MSB"); /* irrelevant */ | |
280 rc = UADSetNumberFormat(this, "SIGNED"); | |
281 break; | |
282 case AUDIO_S16LSB: | |
283 success = 1; | |
284 bitsPerSample = 16; | |
285 rc = UADSetSampleRate(this, spec->freq << 16, &outRate ); | |
286 rc = UADSetByteOrder(this, "LSB"); | |
287 rc = UADSetNumberFormat(this, "SIGNED"); | |
288 break; | |
289 case AUDIO_S16MSB: | |
290 success = 1; | |
291 bitsPerSample = 16; | |
292 rc = UADSetSampleRate(this, spec->freq << 16, &outRate ); | |
293 rc = UADSetByteOrder(this, "MSB"); | |
294 rc = UADSetNumberFormat(this, "SIGNED"); | |
295 break; | |
296 case AUDIO_U16LSB: | |
297 success = 1; | |
298 bitsPerSample = 16; | |
299 rc = UADSetSampleRate(this, spec->freq << 16, &outRate ); | |
300 rc = UADSetByteOrder(this, "LSB"); | |
301 rc = UADSetNumberFormat(this, "UNSIGNED"); | |
302 break; | |
303 case AUDIO_U16MSB: | |
304 success = 1; | |
305 bitsPerSample = 16; | |
306 rc = UADSetSampleRate(this, spec->freq << 16, &outRate ); | |
307 rc = UADSetByteOrder(this, "MSB"); | |
308 rc = UADSetNumberFormat(this, "UNSIGNED"); | |
309 break; | |
310 default: | |
311 break; | |
312 } | |
313 if ( ! success ) { | |
314 test_format = SDL_NextAudioFormat(); | |
315 } | |
316 } | |
317 while ( ! success && test_format ); | |
318 | |
319 if ( success == 0 ) { | |
320 SDL_SetError("Couldn't find any hardware audio formats"); | |
321 return -1; | |
322 } | |
323 | |
324 spec->format = test_format; | |
325 | |
326 for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec ); | |
327 if ( (0x01<<frag_spec) != spec->size ) { | |
328 SDL_SetError("Fragment size must be a power of two"); | |
329 return -1; | |
330 } | |
331 if ( frag_spec > 2048 ) frag_spec = 2048; | |
332 | |
333 this->hidden->bytesPerSample = (bitsPerSample / 8) * spec->channels; | |
334 samplesPerSec = this->hidden->bytesPerSample * outRate; | |
335 | |
336 this->hidden->playbuf._length = 0; | |
337 this->hidden->playbuf._maximum = spec->size; | |
338 this->hidden->playbuf._buffer = (unsigned char*)malloc(spec->size); | |
339 this->hidden->fillbuf._length = 0; | |
340 this->hidden->fillbuf._maximum = spec->size; | |
341 this->hidden->fillbuf._buffer = (unsigned char*)malloc(spec->size); | |
342 | |
343 rc = UADSetBitsPerSample(this, bitsPerSample ); | |
344 rc = UADSetDMABufferSize(this, frag_spec, &outBufSize ); | |
345 rc = UADSetChannels(this, spec->channels); /* functions reduces to mono or stereo */ | |
346 | |
347 lgain = 100; /*maximum left input gain*/ | |
348 rgain = 100; /*maimum right input gain*/ | |
349 rc = UADEnableOutput(this, "LINE_OUT",&lgain,&rgain); | |
350 rc = UADInitialize(this); | |
351 rc = UADStart(this); | |
352 rc = UADSetVolume(this, 100); | |
353 rc = UADSetBalance(this, 0); | |
354 | |
355 /* We're ready to rock and roll. :-) */ | |
356 return 0; | |
357 } | |
358 | |
359 | |
360 static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits) | |
361 { | |
362 return UMSAudioDevice_get_bits_per_sample( this->hidden->umsdev, | |
363 this->hidden->ev, | |
364 bits ); | |
365 } | |
366 | |
367 static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits) | |
368 { | |
369 return UMSAudioDevice_set_bits_per_sample( this->hidden->umsdev, | |
370 this->hidden->ev, | |
371 bits ); | |
372 } | |
373 | |
374 static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate) | |
375 { | |
376 /* from the mac code: sample rate = spec->freq << 16; */ | |
377 return UMSAudioDevice_set_sample_rate( this->hidden->umsdev, | |
378 this->hidden->ev, | |
379 rate, | |
380 set_rate ); | |
381 } | |
382 | |
383 static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order) | |
384 { | |
385 return UMSAudioDevice_set_byte_order( this->hidden->umsdev, | |
386 this->hidden->ev, | |
387 byte_order ); | |
388 } | |
389 | |
390 static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt) | |
391 { | |
392 /* possible PCM, A_LAW or MU_LAW */ | |
393 return UMSAudioDevice_set_audio_format_type( this->hidden->umsdev, | |
394 this->hidden->ev, | |
395 fmt ); | |
396 } | |
397 | |
398 static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt) | |
399 { | |
400 /* possible SIGNED, UNSIGNED, or TWOS_COMPLEMENT */ | |
401 return UMSAudioDevice_set_number_format( this->hidden->umsdev, | |
402 this->hidden->ev, | |
403 fmt ); | |
404 } | |
405 | |
406 static UMSAudioDevice_ReturnCode UADInitialize(_THIS) | |
407 { | |
408 return UMSAudioDevice_initialize( this->hidden->umsdev, | |
409 this->hidden->ev ); | |
410 } | |
411 | |
412 static UMSAudioDevice_ReturnCode UADStart(_THIS) | |
413 { | |
414 return UMSAudioDevice_start( this->hidden->umsdev, | |
415 this->hidden->ev ); | |
416 } | |
417 | |
418 static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS, UMSAudioTypes_TimeFormat fmt ) | |
419 { | |
420 /* | |
421 * Switches the time format to the new format, immediately. | |
422 * possible UMSAudioTypes_Msecs, UMSAudioTypes_Bytes or UMSAudioTypes_Samples | |
423 */ | |
424 return UMSAudioDevice_set_time_format( this->hidden->umsdev, | |
425 this->hidden->ev, | |
426 fmt ); | |
427 } | |
428 | |
429 static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS, long* buff_size ) | |
430 { | |
431 /* | |
432 * returns write buffer size in the current time format | |
433 */ | |
434 return UMSAudioDevice_write_buff_size( this->hidden->umsdev, | |
435 this->hidden->ev, | |
436 buff_size ); | |
437 } | |
438 | |
439 static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS, long* buff_size ) | |
440 { | |
441 /* | |
442 * returns amount of available space in the write buffer | |
443 * in the current time format | |
444 */ | |
445 return UMSAudioDevice_write_buff_remain( this->hidden->umsdev, | |
446 this->hidden->ev, | |
447 buff_size ); | |
448 } | |
449 | |
450 static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS, long* buff_size ) | |
451 { | |
452 /* | |
453 * returns amount of filled space in the write buffer | |
454 * in the current time format | |
455 */ | |
456 return UMSAudioDevice_write_buff_used( this->hidden->umsdev, | |
457 this->hidden->ev, | |
458 buff_size ); | |
459 } | |
460 | |
461 static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS, long bytes, long* bytes_ret ) | |
462 { | |
463 /* | |
464 * Request a new DMA buffer size, maximum requested size 2048. | |
465 * Takes effect with next initialize() call. | |
466 * Devices may or may not support DMA. | |
467 */ | |
468 return UMSAudioDevice_set_DMA_buffer_size( this->hidden->umsdev, | |
469 this->hidden->ev, | |
470 bytes, | |
471 bytes_ret ); | |
472 } | |
473 | |
474 static UMSAudioDevice_ReturnCode UADSetVolume(_THIS, long volume ) | |
475 { | |
476 /* | |
477 * Set the volume. | |
478 * Takes effect immediately. | |
479 */ | |
480 return UMSAudioDevice_set_volume( this->hidden->umsdev, | |
481 this->hidden->ev, | |
482 volume ); | |
483 } | |
484 | |
485 static UMSAudioDevice_ReturnCode UADSetBalance(_THIS, long balance ) | |
486 { | |
487 /* | |
488 * Set the balance. | |
489 * Takes effect immediately. | |
490 */ | |
491 return UMSAudioDevice_set_balance( this->hidden->umsdev, | |
492 this->hidden->ev, | |
493 balance ); | |
494 } | |
495 | |
496 static UMSAudioDevice_ReturnCode UADSetChannels(_THIS, long channels ) | |
497 { | |
498 /* | |
499 * Set mono or stereo. | |
500 * Takes effect with next initialize() call. | |
501 */ | |
502 if ( channels != 1 ) channels = 2; | |
503 return UMSAudioDevice_set_number_of_channels( this->hidden->umsdev, | |
504 this->hidden->ev, | |
505 channels ); | |
506 } | |
507 | |
508 static UMSAudioDevice_ReturnCode UADOpen(_THIS, string device, string mode, long flags) | |
509 { | |
510 return UMSAudioDevice_open( this->hidden->umsdev, | |
511 this->hidden->ev, | |
512 device, | |
513 mode, | |
514 flags ); | |
515 } | |
516 | |
517 static UMSAudioDevice_ReturnCode UADWrite(_THIS, UMSAudioTypes_Buffer* buff, | |
518 long samples, | |
519 long* samples_written) | |
520 { | |
521 return UMSAudioDevice_write( this->hidden->umsdev, | |
522 this->hidden->ev, | |
523 buff, | |
524 samples, | |
525 samples_written ); | |
526 } | |
527 | |
528 static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS, boolean block ) | |
529 { | |
530 return UMSAudioDevice_play_remaining_data( this->hidden->umsdev, | |
531 this->hidden->ev, | |
532 block); | |
533 } | |
534 | |
535 static UMSAudioDevice_ReturnCode UADStop(_THIS) | |
536 { | |
537 return UMSAudioDevice_stop( this->hidden->umsdev, | |
538 this->hidden->ev ); | |
539 } | |
540 | |
541 static UMSAudioDevice_ReturnCode UADClose(_THIS) | |
542 { | |
543 return UMSAudioDevice_close( this->hidden->umsdev, | |
544 this->hidden->ev ); | |
545 } | |
546 | |
547 static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS, string output, long* left_gain, long* right_gain) | |
548 { | |
549 return UMSAudioDevice_enable_output( this->hidden->umsdev, | |
550 this->hidden->ev, | |
551 output, | |
552 left_gain, | |
553 right_gain ); | |
554 } | |
555 |