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