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

Latest commit

 

History

History
399 lines (336 loc) · 12.7 KB

AudioFilePlayer.c

File metadata and controls

399 lines (336 loc) · 12.7 KB
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
This file based on Apple sample code. We haven't changed the file name,
so if you want to see the original search for it on apple.com/developer
*/
Feb 21, 2006
Feb 21, 2006
25
#include "SDL_config.h"
Mar 9, 2006
Mar 9, 2006
27
28
29
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AudioFilePlayer.cpp
*/
30
31
32
33
34
35
36
37
38
39
40
#include "AudioFilePlayer.h"
/*
void ThrowResult (OSStatus result, const char* str)
{
SDL_SetError ("Error: %s %d", str, result);
throw result;
}
*/
#if DEBUG
May 28, 2006
May 28, 2006
41
42
static void
PrintStreamDesc (AudioStreamBasicDescription * inDesc)
43
44
45
46
47
{
if (!inDesc) {
printf ("Can't print a NULL desc!\n");
return;
}
May 28, 2006
May 28, 2006
48
49
50
printf ("- - - - - - - - - - - - - - - - - - - -\n");
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
May 28, 2006
May 28, 2006
51
printf (" Format ID:%s\n", (char *) &inDesc->mFormatID);
52
53
54
55
56
57
58
59
60
61
62
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
printf ("- - - - - - - - - - - - - - - - - - - -\n");
}
#endif
May 28, 2006
May 28, 2006
63
64
static int
AudioFilePlayer_SetDestination (AudioFilePlayer * afp, AudioUnit * inDestUnit)
May 28, 2006
May 28, 2006
66
/*if (afp->mConnected) throw static_cast<OSStatus>(-1); *//* can't set dest if already engaged */
May 28, 2006
May 28, 2006
68
return 0;
May 28, 2006
May 28, 2006
70
SDL_memcpy (&afp->mPlayUnit, inDestUnit, sizeof (afp->mPlayUnit));
71
72
73
OSStatus result = noErr;
May 28, 2006
May 28, 2006
74
75
/* we can "down" cast a component instance to a component */
76
ComponentDescription desc;
May 28, 2006
May 28, 2006
77
78
79
80
81
82
83
result = GetComponentInfo ((Component) * inDestUnit, &desc, 0, 0, 0);
if (result)
return 0; /*THROW_RESULT("GetComponentInfo") */
/* we're going to use this to know which convert routine to call
a v1 audio unit will have a type of 'aunt'
a v2 audio unit will have one of several different types. */
84
85
if (desc.componentType != kAudioUnitComponentType) {
result = badComponentInstance;
May 28, 2006
May 28, 2006
86
87
88
/*THROW_RESULT("BAD COMPONENT") */
if (result)
return 0;
89
90
91
92
}
/* Set the input format of the audio unit. */
result = AudioUnitSetProperty (*inDestUnit,
May 28, 2006
May 28, 2006
93
94
95
96
97
98
99
100
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&afp->mFileDescription,
sizeof (afp->mFileDescription));
/*THROW_RESULT("AudioUnitSetProperty") */
if (result)
return 0;
May 28, 2006
May 28, 2006
104
105
106
static void
AudioFilePlayer_SetNotifier (AudioFilePlayer * afp,
AudioFilePlayNotifier inNotifier, void *inRefCon)
107
108
109
110
111
{
afp->mNotifier = inNotifier;
afp->mRefCon = inRefCon;
}
May 28, 2006
May 28, 2006
112
113
static int
AudioFilePlayer_IsConnected (AudioFilePlayer * afp)
114
115
116
117
{
return afp->mConnected;
}
May 28, 2006
May 28, 2006
118
119
static AudioUnit
AudioFilePlayer_GetDestUnit (AudioFilePlayer * afp)
May 28, 2006
May 28, 2006
121
return afp->mPlayUnit;
May 28, 2006
May 28, 2006
124
125
static void
AudioFilePlayer_Print (AudioFilePlayer * afp)
May 28, 2006
May 28, 2006
127
128
#if DEBUG
printf ("Is Connected:%s\n", (IsConnected ()? "true" : "false"));
129
130
131
132
printf ("- - - - - - - - - - - - - - \n");
#endif
}
May 28, 2006
May 28, 2006
133
134
static void
AudioFilePlayer_SetStartFrame (AudioFilePlayer * afp, int frame)
135
136
137
138
139
140
141
{
SInt64 position = frame * 2352;
afp->mStartFrame = frame;
afp->mAudioFileManager->SetPosition (afp->mAudioFileManager, position);
}
May 28, 2006
May 28, 2006
142
143
144
static int
AudioFilePlayer_GetCurrentFrame (AudioFilePlayer * afp)
May 28, 2006
May 28, 2006
146
147
148
return afp->mStartFrame +
(afp->mAudioFileManager->GetByteCounter (afp->mAudioFileManager) /
2352);
May 28, 2006
May 28, 2006
150
151
152
static void
AudioFilePlayer_SetStopFrame (AudioFilePlayer * afp, int frame)
May 28, 2006
May 28, 2006
154
155
SInt64 position = frame * 2352;
156
157
afp->mAudioFileManager->SetEndOfFile (afp->mAudioFileManager, position);
}
May 28, 2006
May 28, 2006
158
159
160
void
delete_AudioFilePlayer (AudioFilePlayer * afp)
May 28, 2006
May 28, 2006
162
163
164
if (afp != NULL) {
afp->Disconnect (afp);
165
if (afp->mAudioFileManager) {
May 28, 2006
May 28, 2006
166
delete_AudioFileManager (afp->mAudioFileManager);
167
168
afp->mAudioFileManager = 0;
}
May 28, 2006
May 28, 2006
169
170
if (afp->mForkRefNum) {
May 17, 2006
May 17, 2006
171
FSCloseFork (afp->mForkRefNum);
172
173
afp->mForkRefNum = 0;
}
May 28, 2006
May 28, 2006
174
SDL_free (afp);
May 28, 2006
May 28, 2006
178
179
static int
AudioFilePlayer_Connect (AudioFilePlayer * afp)
May 28, 2006
May 28, 2006
182
183
printf ("Connect:%x, engaged=%d\n", (int) afp->mPlayUnit,
(afp->mConnected ? 1 : 0));
May 28, 2006
May 28, 2006
185
186
if (!afp->mConnected) {
if (!afp->mAudioFileManager->DoConnect (afp->mAudioFileManager))
Mar 9, 2006
Mar 9, 2006
189
/* set the render callback for the file data to be supplied to the sound converter AU */
190
191
192
afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc;
afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager;
May 28, 2006
May 28, 2006
193
194
195
196
197
198
199
200
OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
kAudioUnitProperty_SetInputCallback,
kAudioUnitScope_Input,
0,
&afp->mInputCallback,
sizeof (afp->mInputCallback));
if (result)
return 0; /*THROW_RESULT("AudioUnitSetProperty") */
201
202
203
204
205
206
afp->mConnected = 1;
}
return 1;
}
Mar 9, 2006
Mar 9, 2006
207
208
/* warning noted, now please go away ;-) */
/* #warning This should redirect the calling of notification code to some other thread */
May 28, 2006
May 28, 2006
209
210
static void
AudioFilePlayer_DoNotification (AudioFilePlayer * afp, OSStatus inStatus)
211
212
213
214
215
{
if (afp->mNotifier) {
(*afp->mNotifier) (afp->mRefCon, inStatus);
} else {
SDL_SetError ("Notification posted with no notifier in place");
May 28, 2006
May 28, 2006
216
217
if (inStatus == kAudioFilePlay_FileIsFinished)
May 28, 2006
May 28, 2006
218
afp->Disconnect (afp);
219
else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun)
May 28, 2006
May 28, 2006
220
afp->Disconnect (afp);
May 28, 2006
May 28, 2006
224
225
static void
AudioFilePlayer_Disconnect (AudioFilePlayer * afp)
May 28, 2006
May 28, 2006
228
229
printf ("Disconnect:%x,%ld, engaged=%d\n", (int) afp->mPlayUnit, 0,
(afp->mConnected ? 1 : 0));
May 28, 2006
May 28, 2006
231
if (afp->mConnected) {
232
afp->mConnected = 0;
May 28, 2006
May 28, 2006
233
234
235
afp->mInputCallback.inputProc = 0;
afp->mInputCallback.inputProcRefCon = 0;
May 28, 2006
May 28, 2006
236
237
238
239
240
241
242
243
244
245
246
OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
kAudioUnitProperty_SetInputCallback,
kAudioUnitScope_Input,
0,
&afp->mInputCallback,
sizeof (afp->mInputCallback));
if (result)
SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld",
result);
afp->mAudioFileManager->Disconnect (afp->mAudioFileManager);
May 28, 2006
May 28, 2006
250
251
typedef struct
{
252
253
254
255
UInt32 offset;
UInt32 blockSize;
} SSNDData;
May 28, 2006
May 28, 2006
256
257
258
static int
AudioFilePlayer_OpenFile (AudioFilePlayer * afp, const FSRef * inRef,
SInt64 * outFileDataSize)
259
260
261
262
263
264
265
266
267
268
{
ContainerChunk chunkHeader;
ChunkHeader chunk;
SSNDData ssndData;
OSErr result;
HFSUniStr255 dfName;
ByteCount actual;
SInt64 offset;
Mar 9, 2006
Mar 9, 2006
269
/* Open the data fork of the input file */
May 28, 2006
May 28, 2006
270
271
272
273
274
275
276
277
278
result = FSGetDataForkName (&dfName);
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName") */
result =
FSOpenFork (inRef, dfName.length, dfName.unicode, fsRdPerm,
&afp->mForkRefNum);
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork") */
Mar 9, 2006
Mar 9, 2006
280
/* Read the file header, and check if it's indeed an AIFC file */
May 28, 2006
May 28, 2006
281
282
283
284
285
result =
FSReadFork (afp->mForkRefNum, fsAtMark, 0, sizeof (chunkHeader),
&chunkHeader, &actual);
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") */
286
287
288
if (chunkHeader.ckID != 'FORM') {
result = -1;
May 28, 2006
May 28, 2006
289
290
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'"); */
291
292
293
294
}
if (chunkHeader.formType != 'AIFC') {
result = -1;
May 28, 2006
May 28, 2006
295
296
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'"); */
Mar 9, 2006
Mar 9, 2006
299
300
301
302
/* Search for the SSND chunk. We ignore all compression etc. information
in other chunks. Of course that is kind of evil, but for now we are lazy
and rely on the cdfs to always give us the same fixed format.
TODO: Parse the COMM chunk we currently skip to fill in mFileDescription.
May 28, 2006
May 28, 2006
303
*/
May 28, 2006
May 28, 2006
306
307
308
309
310
311
result =
FSReadFork (afp->mForkRefNum, fsFromMark, offset,
sizeof (chunk), &chunk, &actual);
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") */
Mar 9, 2006
Mar 9, 2006
312
/* Skip the chunk data */
313
offset = chunk.ckSize;
May 28, 2006
May 28, 2006
314
315
}
while (chunk.ckID != 'SSND');
Mar 9, 2006
Mar 9, 2006
317
318
/* Read the header of the SSND chunk. After this, we are positioned right
at the start of the audio data. */
May 28, 2006
May 28, 2006
319
320
321
322
323
result =
FSReadFork (afp->mForkRefNum, fsAtMark, 0, sizeof (ssndData),
&ssndData, &actual);
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") */
May 28, 2006
May 28, 2006
325
326
327
328
result =
FSSetForkPosition (afp->mForkRefNum, fsFromMark, ssndData.offset);
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition") */
Mar 9, 2006
Mar 9, 2006
330
/* Data size */
331
332
*outFileDataSize = chunk.ckSize - ssndData.offset - 8;
Mar 9, 2006
Mar 9, 2006
333
/* File format */
334
335
afp->mFileDescription.mSampleRate = 44100;
afp->mFileDescription.mFormatID = kAudioFormatLinearPCM;
May 28, 2006
May 28, 2006
336
337
afp->mFileDescription.mFormatFlags =
kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
338
339
340
341
342
343
344
345
346
afp->mFileDescription.mBytesPerPacket = 4;
afp->mFileDescription.mFramesPerPacket = 1;
afp->mFileDescription.mBytesPerFrame = 4;
afp->mFileDescription.mChannelsPerFrame = 2;
afp->mFileDescription.mBitsPerChannel = 16;
return 1;
}
May 28, 2006
May 28, 2006
347
348
AudioFilePlayer *
new_AudioFilePlayer (const FSRef * inFileRef)
May 28, 2006
May 28, 2006
350
SInt64 fileDataSize = 0;
May 28, 2006
May 28, 2006
352
353
AudioFilePlayer *afp =
(AudioFilePlayer *) SDL_malloc (sizeof (AudioFilePlayer));
354
355
if (afp == NULL)
return NULL;
May 28, 2006
May 28, 2006
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
SDL_memset (afp, '\0', sizeof (*afp));
#define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m
SET_AUDIOFILEPLAYER_METHOD (SetDestination);
SET_AUDIOFILEPLAYER_METHOD (SetNotifier);
SET_AUDIOFILEPLAYER_METHOD (SetStartFrame);
SET_AUDIOFILEPLAYER_METHOD (GetCurrentFrame);
SET_AUDIOFILEPLAYER_METHOD (SetStopFrame);
SET_AUDIOFILEPLAYER_METHOD (Connect);
SET_AUDIOFILEPLAYER_METHOD (Disconnect);
SET_AUDIOFILEPLAYER_METHOD (DoNotification);
SET_AUDIOFILEPLAYER_METHOD (IsConnected);
SET_AUDIOFILEPLAYER_METHOD (GetDestUnit);
SET_AUDIOFILEPLAYER_METHOD (Print);
SET_AUDIOFILEPLAYER_METHOD (OpenFile);
#undef SET_AUDIOFILEPLAYER_METHOD
if (!afp->OpenFile (afp, inFileRef, &fileDataSize)) {
SDL_free (afp);
May 28, 2006
May 28, 2006
377
Mar 9, 2006
Mar 9, 2006
378
/* we want about 4 seconds worth of data for the buffer */
May 28, 2006
May 28, 2006
379
380
381
382
int bytesPerSecond =
(UInt32) (4 * afp->mFileDescription.mSampleRate *
afp->mFileDescription.mBytesPerFrame);
May 28, 2006
May 28, 2006
384
printf ("File format:\n");
385
386
PrintStreamDesc (&afp->mFileDescription);
#endif
May 28, 2006
May 28, 2006
387
388
389
390
391
392
afp->mAudioFileManager = new_AudioFileManager (afp, afp->mForkRefNum,
fileDataSize,
bytesPerSecond);
if (afp->mAudioFileManager == NULL) {
delete_AudioFilePlayer (afp);
393
394
395
396
397
398
return NULL;
}
return afp;
}
May 28, 2006
May 28, 2006
399
/* vi: set ts=4 sw=4 expandtab: */