Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
352 lines (295 loc) · 9.7 KB

SDL_romaudio.c

File metadata and controls

352 lines (295 loc) · 9.7 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Feb 1, 2006
Feb 1, 2006
3
Copyright (C) 1997-2006 Sam Lantinga
Apr 26, 2001
Apr 26, 2001
4
5
This library is free software; you can redistribute it and/or
Feb 1, 2006
Feb 1, 2006
6
modify it under the terms of the GNU Lesser General Public
Apr 26, 2001
Apr 26, 2001
7
License as published by the Free Software Foundation; either
Feb 1, 2006
Feb 1, 2006
8
version 2.1 of the License, or (at your option) any later version.
Apr 26, 2001
Apr 26, 2001
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
Feb 1, 2006
Feb 1, 2006
13
Lesser General Public License for more details.
Apr 26, 2001
Apr 26, 2001
14
Feb 1, 2006
Feb 1, 2006
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
Apr 26, 2001
Apr 26, 2001
18
19
Sam Lantinga
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Apr 26, 2001
Apr 26, 2001
21
*/
Feb 21, 2006
Feb 21, 2006
22
#include "SDL_config.h"
Apr 26, 2001
Apr 26, 2001
23
Oct 1, 2006
Oct 1, 2006
24
25
/* This should work on PowerPC and Intel Mac OS X, and Carbonized Mac OS 9. */
Sep 8, 2005
Sep 8, 2005
26
#if defined(__APPLE__) && defined(__MACH__)
Oct 1, 2006
Oct 1, 2006
27
# define SDL_MACOS_NAME "Mac OS X"
Sep 8, 2005
Sep 8, 2005
28
29
# include <Carbon/Carbon.h>
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
Oct 1, 2006
Oct 1, 2006
30
# define SDL_MACOS_NAME "Mac OS 9"
Apr 26, 2001
Apr 26, 2001
31
32
# include <Carbon.h>
#else
Oct 1, 2006
Oct 1, 2006
33
# define SDL_MACOS_NAME "Mac OS 9"
Jul 10, 2006
Jul 10, 2006
34
# include <Sound.h> /* SoundManager interface */
Apr 26, 2001
Apr 26, 2001
35
# include <Gestalt.h>
Mar 30, 2002
Mar 30, 2002
36
# include <DriverServices.h>
Apr 26, 2001
Apr 26, 2001
37
38
#endif
Sep 8, 2005
Sep 8, 2005
39
#if !defined(NewSndCallBackUPP) && (UNIVERSAL_INTERFACES_VERSION < 0x0335)
Jul 10, 2006
Jul 10, 2006
40
#if !defined(NewSndCallBackProc) /* avoid circular redefinition... */
Sep 8, 2005
Sep 8, 2005
41
42
#define NewSndCallBackUPP NewSndCallBackProc
#endif
Sep 8, 2005
Sep 8, 2005
43
44
45
#if !defined(NewSndCallBackUPP)
#define NewSndCallBackUPP NewSndCallBackProc
#endif
Sep 8, 2005
Sep 8, 2005
46
47
#endif
Apr 26, 2001
Apr 26, 2001
48
#include "SDL_audio.h"
Feb 16, 2006
Feb 16, 2006
49
50
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
Apr 26, 2001
Apr 26, 2001
51
52
53
54
#include "SDL_romaudio.h"
/* Audio driver functions */
Oct 1, 2006
Oct 1, 2006
55
56
57
58
static void SNDMGR_CloseAudio(_THIS);
static int SNDMGR_OpenAudio(_THIS, const char *devname, int iscapture);
static void SNDMGR_LockAudio(_THIS);
static void SNDMGR_UnlockAudio(_THIS);
Apr 26, 2001
Apr 26, 2001
59
60
61
62
/* Audio driver bootstrap functions */
Jul 10, 2006
Jul 10, 2006
63
static int
Oct 1, 2006
Oct 1, 2006
64
SNDMGR_Available(void)
Apr 26, 2001
Apr 26, 2001
65
{
Jul 10, 2006
Jul 10, 2006
66
return (1);
Apr 26, 2001
Apr 26, 2001
67
68
69
}
Oct 1, 2006
Oct 1, 2006
70
71
static int
SNDMGR_Init(SDL_AudioDriverImpl *impl)
Apr 26, 2001
Apr 26, 2001
72
73
{
/* Set the function pointers */
Oct 1, 2006
Oct 1, 2006
74
75
76
77
impl->OpenAudio = SNDMGR_OpenAudio;
impl->CloseAudio = SNDMGR_CloseAudio;
impl->LockAudio = SNDMGR_LockAudio;
impl->UnlockAudio = SNDMGR_UnlockAudio;
Apr 26, 2001
Apr 26, 2001
78
Jul 10, 2006
Jul 10, 2006
79
#ifdef __MACOSX__ /* Mac OS X uses threaded audio, so normal thread code is okay */
Oct 1, 2006
Oct 1, 2006
80
81
impl->LockAudio = NULL;
impl->UnlockAudio = NULL;
Apr 13, 2002
Apr 13, 2002
82
#endif
Oct 1, 2006
Oct 1, 2006
83
84
return 1;
Apr 26, 2001
Apr 26, 2001
85
86
87
}
AudioBootStrap SNDMGR_bootstrap = {
Oct 1, 2006
Oct 1, 2006
88
"sndmgr", SDL_MACOS_NAME " SoundManager",
Oct 1, 2006
Oct 1, 2006
89
SNDMGR_Available, SNDMGR_Init
Apr 26, 2001
Apr 26, 2001
90
91
};
Mar 30, 2002
Mar 30, 2002
92
93
#pragma options align=power
Oct 1, 2006
Oct 1, 2006
94
static volatile int audio_is_opened = 0;
Mar 30, 2002
Mar 30, 2002
95
96
static volatile SInt32 audio_is_locked = 0;
static volatile SInt32 need_to_mix = 0;
Apr 26, 2001
Apr 26, 2001
97
Jul 10, 2006
Jul 10, 2006
98
static UInt8 *buffer[2];
Apr 26, 2001
Apr 26, 2001
99
100
static volatile UInt32 running = 0;
static CmpSoundHeader header;
Mar 30, 2002
Mar 30, 2002
101
102
static volatile Uint32 fill_me = 0;
Jul 10, 2006
Jul 10, 2006
103
104
static void
mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
Mar 30, 2002
Mar 30, 2002
105
{
Jul 10, 2006
Jul 10, 2006
106
if (!audio->paused) {
Feb 21, 2006
Feb 21, 2006
107
#ifdef __MACOSX__
Apr 13, 2002
Apr 13, 2002
108
109
SDL_mutexP(audio->mixer_lock);
#endif
Jul 10, 2006
Jul 10, 2006
110
if (audio->convert.needed) {
Apr 13, 2002
Apr 13, 2002
111
audio->spec.callback(audio->spec.userdata,
Jul 10, 2006
Jul 10, 2006
112
113
(Uint8 *) audio->convert.buf,
audio->convert.len);
Apr 13, 2002
Apr 13, 2002
114
SDL_ConvertAudio(&audio->convert);
Jul 10, 2006
Jul 10, 2006
115
116
if (audio->convert.len_cvt != audio->spec.size) {
/* Uh oh... probably crashes here */ ;
Mar 30, 2002
Mar 30, 2002
117
}
Feb 7, 2006
Feb 7, 2006
118
SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
Mar 30, 2002
Mar 30, 2002
119
} else {
Jul 10, 2006
Jul 10, 2006
120
121
audio->spec.callback(audio->spec.userdata, buffer,
audio->spec.size);
Mar 30, 2002
Mar 30, 2002
122
}
Feb 21, 2006
Feb 21, 2006
123
#ifdef __MACOSX__
Apr 13, 2002
Apr 13, 2002
124
125
SDL_mutexV(audio->mixer_lock);
#endif
Mar 30, 2002
Mar 30, 2002
126
127
}
Jul 10, 2006
Jul 10, 2006
128
DecrementAtomic((SInt32 *) & need_to_mix);
Mar 30, 2002
Mar 30, 2002
129
130
}
Jul 10, 2006
Jul 10, 2006
131
static void
Oct 1, 2006
Oct 1, 2006
132
SNDMGR_LockAudio(_THIS)
Mar 30, 2002
Mar 30, 2002
133
{
Jul 10, 2006
Jul 10, 2006
134
IncrementAtomic((SInt32 *) & audio_is_locked);
Mar 30, 2002
Mar 30, 2002
135
136
}
Jul 10, 2006
Jul 10, 2006
137
static void
Oct 1, 2006
Oct 1, 2006
138
SNDMGR_UnlockAudio(_THIS)
Mar 30, 2002
Mar 30, 2002
139
140
{
SInt32 oldval;
Jul 10, 2006
Jul 10, 2006
141
142
143
oldval = DecrementAtomic((SInt32 *) & audio_is_locked);
if (oldval != 1) /* != 1 means audio is still locked. */
Mar 30, 2002
Mar 30, 2002
144
145
146
return;
/* Did we miss the chance to mix in an interrupt? Do it now. */
Jul 10, 2006
Jul 10, 2006
147
if (BitAndAtomic(0xFFFFFFFF, (UInt32 *) & need_to_mix)) {
Mar 30, 2002
Mar 30, 2002
148
149
150
151
152
/*
* Note that this could be a problem if you missed an interrupt
* while the audio was locked, and get preempted by a second
* interrupt here, but that means you locked for way too long anyhow.
*/
Jul 10, 2006
Jul 10, 2006
153
mix_buffer(this, buffer[fill_me]);
Mar 30, 2002
Mar 30, 2002
154
155
}
}
Apr 26, 2001
Apr 26, 2001
156
Jul 10, 2006
Jul 10, 2006
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
static void
callBackProc(SndChannel * chan, SndCommand * cmd_passed)
{
UInt32 play_me;
SndCommand cmd;
SDL_AudioDevice *audio = (SDL_AudioDevice *) chan->userInfo;
IncrementAtomic((SInt32 *) & need_to_mix);
fill_me = cmd_passed->param2; /* buffer that has just finished playing, so fill it */
play_me = !fill_me; /* filled buffer to play _now_ */
if (!audio->enabled) {
return;
}
/* queue previously mixed buffer for playback. */
header.samplePtr = (Ptr) buffer[play_me];
cmd.cmd = bufferCmd;
cmd.param1 = 0;
cmd.param2 = (long) &header;
SndDoCommand(chan, &cmd, 0);
memset(buffer[fill_me], 0, audio->spec.size);
/*
* if audio device isn't locked, mix the next buffer to be queued in
* the memory block that just finished playing.
*/
if (!BitAndAtomic(0xFFFFFFFF, (UInt32 *) & audio_is_locked)) {
mix_buffer(audio, buffer[fill_me]);
}
/* set this callback to run again when current buffer drains. */
if (running) {
cmd.cmd = callBackCmd;
cmd.param1 = 0;
cmd.param2 = play_me;
SndDoCommand(chan, &cmd, 0);
}
Apr 26, 2001
Apr 26, 2001
198
199
}
Jul 10, 2006
Jul 10, 2006
200
static int
Oct 1, 2006
Oct 1, 2006
201
SNDMGR_OpenAudio(_THIS, const char *devname, int iscapture)
Jul 10, 2006
Jul 10, 2006
202
{
Oct 1, 2006
Oct 1, 2006
203
204
SDL_AudioSpec *spec = &this->spec;
SndChannelPtr channel = NULL;
Jul 10, 2006
Jul 10, 2006
205
206
207
208
SndCallBackUPP callback;
int sample_bits;
int i;
long initOptions;
Apr 26, 2001
Apr 26, 2001
209
Oct 1, 2006
Oct 1, 2006
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
if (audio_is_opened) {
SDL_SetError("SoundManager driver doesn't support multiple opens");
return 0;
}
if (iscapture) {
SDL_SetError("SoundManager driver doesn't support recording");
return 0;
}
/* !!! FIXME: ignore devname? */
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* !!! FIXME: check devname and iscapture... */
/* !!! FIXME: iterate through format matrix... */
Jul 10, 2006
Jul 10, 2006
234
/* Very few conversions are required, but... */
Apr 26, 2001
Apr 26, 2001
235
switch (spec->format) {
Jul 10, 2006
Jul 10, 2006
236
case AUDIO_S8:
Apr 26, 2001
Apr 26, 2001
237
238
spec->format = AUDIO_U8;
break;
Jul 10, 2006
Jul 10, 2006
239
case AUDIO_U16LSB:
Apr 26, 2001
Apr 26, 2001
240
241
spec->format = AUDIO_S16LSB;
break;
Jul 10, 2006
Jul 10, 2006
242
case AUDIO_U16MSB:
Apr 26, 2001
Apr 26, 2001
243
244
spec->format = AUDIO_S16MSB;
break;
Sep 1, 2006
Sep 1, 2006
245
246
247
case AUDIO_F32LSB:
spec->format = AUDIO_F32MSB;
break;
Apr 26, 2001
Apr 26, 2001
248
}
Oct 1, 2006
Oct 1, 2006
249
SDL_CalculateAudioSpec(&this->spec);
Jul 10, 2006
Jul 10, 2006
250
Apr 26, 2001
Apr 26, 2001
251
/* initialize bufferCmd header */
Jul 10, 2006
Jul 10, 2006
252
253
memset(&header, 0, sizeof(header));
callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc);
Apr 26, 2001
Apr 26, 2001
254
255
256
257
sample_bits = spec->size / spec->samples / spec->channels * 8;
#ifdef DEBUG_AUDIO
fprintf(stderr,
Jul 10, 2006
Jul 10, 2006
258
259
"Audio format 0x%x, channels = %d, sample_bits = %d, frequency = %d\n",
spec->format, spec->channels, sample_bits, spec->freq);
Apr 26, 2001
Apr 26, 2001
260
#endif /* DEBUG_AUDIO */
Jul 10, 2006
Jul 10, 2006
261
Apr 26, 2001
Apr 26, 2001
262
header.numChannels = spec->channels;
Jul 10, 2006
Jul 10, 2006
263
264
265
266
267
header.sampleSize = sample_bits;
header.sampleRate = spec->freq << 16;
header.numFrames = spec->samples;
header.encode = cmpSH;
Apr 26, 2001
Apr 26, 2001
268
/* Note that we install the 16bitLittleEndian Converter if needed. */
Sep 1, 2006
Sep 1, 2006
269
if (spec->format == AUDIO_S16LSB) {
Apr 26, 2001
Apr 26, 2001
270
271
header.compressionID = fixedCompression;
header.format = k16BitLittleEndianFormat;
Sep 1, 2006
Sep 1, 2006
272
273
274
275
276
277
278
279
280
} else if (spec->format == AUDIO_S32MSB) {
header.compressionID = fixedCompression;
header.format = k32BitFormat;
} else if (spec->format == AUDIO_S32LSB) {
header.compressionID = fixedCompression;
header.format = k32BitLittleEndianFormat;
} else if (spec->format == AUDIO_F32MSB) {
header.compressionID = fixedCompression;
header.format = kFloat32Format;
Apr 26, 2001
Apr 26, 2001
281
}
Jul 10, 2006
Jul 10, 2006
282
Apr 26, 2001
Apr 26, 2001
283
/* allocate 2 buffers */
Jul 10, 2006
Jul 10, 2006
284
285
286
for (i = 0; i < 2; i++) {
buffer[i] = (UInt8 *) malloc(sizeof(UInt8) * spec->size);
if (buffer[i] == NULL) {
Oct 1, 2006
Oct 1, 2006
287
SNDMGR_CloseAudio(this);
Jul 10, 2006
Jul 10, 2006
288
SDL_OutOfMemory();
Oct 1, 2006
Oct 1, 2006
289
return 0;
Jul 10, 2006
Jul 10, 2006
290
291
292
293
294
295
296
}
memset(buffer[i], 0, spec->size);
}
/* Create the sound manager channel */
channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
if (channel == NULL) {
Oct 1, 2006
Oct 1, 2006
297
SNDMGR_CloseAudio(this);
Apr 26, 2001
Apr 26, 2001
298
SDL_OutOfMemory();
Oct 1, 2006
Oct 1, 2006
299
return 0;
Apr 26, 2001
Apr 26, 2001
300
}
Oct 1, 2006
Oct 1, 2006
301
this->hidden->channel = channel;
Jul 10, 2006
Jul 10, 2006
302
if (spec->channels >= 2) {
Apr 26, 2001
Apr 26, 2001
303
304
305
306
initOptions = initStereo;
} else {
initOptions = initMono;
}
Jul 10, 2006
Jul 10, 2006
307
channel->userInfo = (long) this;
Apr 26, 2001
Apr 26, 2001
308
channel->qLength = 128;
Jul 10, 2006
Jul 10, 2006
309
if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
Oct 1, 2006
Oct 1, 2006
310
SNDMGR_CloseAudio(this);
Apr 26, 2001
Apr 26, 2001
311
SDL_SetError("Unable to create audio channel");
Oct 1, 2006
Oct 1, 2006
312
return 0;
Apr 26, 2001
Apr 26, 2001
313
}
Jul 10, 2006
Jul 10, 2006
314
315
316
317
318
319
320
321
322
323
/* start playback */
{
SndCommand cmd;
cmd.cmd = callBackCmd;
cmd.param2 = 0;
running = 1;
SndDoCommand(channel, &cmd, 0);
}
Oct 1, 2006
Oct 1, 2006
324
audio_is_opened = 1;
Jul 10, 2006
Jul 10, 2006
325
return 1;
Apr 26, 2001
Apr 26, 2001
326
327
}
Jul 10, 2006
Jul 10, 2006
328
static void
Oct 1, 2006
Oct 1, 2006
329
SNDMGR_CloseAudio(_THIS)
Jul 10, 2006
Jul 10, 2006
330
331
332
333
334
335
{
int i;
running = 0;
Oct 1, 2006
Oct 1, 2006
336
337
338
if (this->hidden->channel) {
SndDisposeChannel(this->hidden->channel, true);
this->hidden->channel = NULL;
Jul 10, 2006
Jul 10, 2006
339
340
341
342
}
for (i = 0; i < 2; ++i) {
if (buffer[i]) {
Feb 7, 2006
Feb 7, 2006
343
SDL_free(buffer[i]);
Apr 26, 2001
Apr 26, 2001
344
345
346
buffer[i] = NULL;
}
}
Oct 1, 2006
Oct 1, 2006
347
348
349
SDL_free(this->hidden);
this->hidden = NULL;
audio_is_opened = 0;
Apr 26, 2001
Apr 26, 2001
350
351
}
Jul 10, 2006
Jul 10, 2006
352
/* vi: set ts=4 sw=4 expandtab: */