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