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

Latest commit

 

History

History
398 lines (335 loc) · 12.5 KB

AudioFilePlayer.c

File metadata and controls

398 lines (335 loc) · 12.5 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
Jul 10, 2006
Jul 10, 2006
41
42
static void
PrintStreamDesc(AudioStreamBasicDescription * inDesc)
Jul 10, 2006
Jul 10, 2006
45
printf("Can't print a NULL desc!\n");
Jul 10, 2006
Jul 10, 2006
48
49
50
51
52
53
54
55
56
57
58
printf("- - - - - - - - - - - - - - - - - - - -\n");
printf(" Sample Rate:%f\n", inDesc->mSampleRate);
printf(" Format ID:%s\n", (char *) &inDesc->mFormatID);
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");
Jul 10, 2006
Jul 10, 2006
63
64
static int
AudioFilePlayer_SetDestination(AudioFilePlayer * afp, AudioUnit * inDestUnit)
Jul 10, 2006
Jul 10, 2006
66
/*if (afp->mConnected) throw static_cast<OSStatus>(-1); *//* can't set dest if already engaged */
Jul 10, 2006
Jul 10, 2006
68
return 0;
Jul 10, 2006
Jul 10, 2006
70
SDL_memcpy(&afp->mPlayUnit, inDestUnit, sizeof(afp->mPlayUnit));
71
72
73
OSStatus result = noErr;
Jul 10, 2006
Jul 10, 2006
74
75
/* we can "down" cast a component instance to a component */
76
ComponentDescription desc;
Jul 10, 2006
Jul 10, 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;
Jul 10, 2006
Jul 10, 2006
86
87
88
/*THROW_RESULT("BAD COMPONENT") */
if (result)
return 0;
89
90
91
}
/* Set the input format of the audio unit. */
Jul 10, 2006
Jul 10, 2006
92
93
94
95
96
97
98
99
100
result = AudioUnitSetProperty(*inDestUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&afp->mFileDescription,
sizeof(afp->mFileDescription));
/*THROW_RESULT("AudioUnitSetProperty") */
if (result)
return 0;
Jul 10, 2006
Jul 10, 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;
}
Jul 10, 2006
Jul 10, 2006
112
113
static int
AudioFilePlayer_IsConnected(AudioFilePlayer * afp)
114
115
116
117
{
return afp->mConnected;
}
Jul 10, 2006
Jul 10, 2006
118
119
static AudioUnit
AudioFilePlayer_GetDestUnit(AudioFilePlayer * afp)
Jul 10, 2006
Jul 10, 2006
121
return afp->mPlayUnit;
Jul 10, 2006
Jul 10, 2006
124
125
static void
AudioFilePlayer_Print(AudioFilePlayer * afp)
Jul 10, 2006
Jul 10, 2006
127
128
129
#if DEBUG
printf("Is Connected:%s\n", (IsConnected()? "true" : "false"));
printf("- - - - - - - - - - - - - - \n");
Jul 10, 2006
Jul 10, 2006
133
134
static void
AudioFilePlayer_SetStartFrame(AudioFilePlayer * afp, int frame)
135
136
137
138
{
SInt64 position = frame * 2352;
afp->mStartFrame = frame;
Jul 10, 2006
Jul 10, 2006
139
afp->mAudioFileManager->SetPosition(afp->mAudioFileManager, position);
Jul 10, 2006
Jul 10, 2006
142
143
144
static int
AudioFilePlayer_GetCurrentFrame(AudioFilePlayer * afp)
Jul 10, 2006
Jul 10, 2006
146
147
148
return afp->mStartFrame +
(afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) /
2352);
Jul 10, 2006
Jul 10, 2006
150
151
152
static void
AudioFilePlayer_SetStopFrame(AudioFilePlayer * afp, int frame)
Jul 10, 2006
Jul 10, 2006
154
155
156
SInt64 position = frame * 2352;
afp->mAudioFileManager->SetEndOfFile(afp->mAudioFileManager, position);
Jul 10, 2006
Jul 10, 2006
158
159
160
void
delete_AudioFilePlayer(AudioFilePlayer * afp)
Jul 10, 2006
Jul 10, 2006
162
if (afp != NULL) {
163
afp->Disconnect(afp);
Jul 10, 2006
Jul 10, 2006
164
165
166
167
168
if (afp->mAudioFileManager) {
delete_AudioFileManager(afp->mAudioFileManager);
afp->mAudioFileManager = 0;
}
Jul 10, 2006
Jul 10, 2006
169
170
if (afp->mForkRefNum) {
Jul 10, 2006
Jul 10, 2006
171
FSCloseFork(afp->mForkRefNum);
172
173
afp->mForkRefNum = 0;
}
Feb 7, 2006
Feb 7, 2006
174
SDL_free(afp);
Jul 10, 2006
Jul 10, 2006
178
179
static int
AudioFilePlayer_Connect(AudioFilePlayer * afp)
Jul 10, 2006
Jul 10, 2006
182
183
printf("Connect:%x, engaged=%d\n", (int) afp->mPlayUnit,
(afp->mConnected ? 1 : 0));
Jul 10, 2006
Jul 10, 2006
185
if (!afp->mConnected) {
186
187
188
if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager))
return 0;
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;
Jul 10, 2006
Jul 10, 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 */
Jul 10, 2006
Jul 10, 2006
209
210
static void
AudioFilePlayer_DoNotification(AudioFilePlayer * afp, OSStatus inStatus)
211
212
213
214
{
if (afp->mNotifier) {
(*afp->mNotifier) (afp->mRefCon, inStatus);
} else {
Jul 10, 2006
Jul 10, 2006
215
216
SDL_SetError("Notification posted with no notifier in place");
217
218
219
220
221
222
223
if (inStatus == kAudioFilePlay_FileIsFinished)
afp->Disconnect(afp);
else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun)
afp->Disconnect(afp);
}
}
Jul 10, 2006
Jul 10, 2006
224
225
static void
AudioFilePlayer_Disconnect(AudioFilePlayer * afp)
Jul 10, 2006
Jul 10, 2006
228
229
printf("Disconnect:%x,%ld, engaged=%d\n", (int) afp->mPlayUnit, 0,
(afp->mConnected ? 1 : 0));
Jul 10, 2006
Jul 10, 2006
231
if (afp->mConnected) {
232
afp->mConnected = 0;
Jul 10, 2006
Jul 10, 2006
233
234
235
afp->mInputCallback.inputProc = 0;
afp->mInputCallback.inputProcRefCon = 0;
Jul 10, 2006
Jul 10, 2006
236
237
238
239
240
241
242
243
244
OSStatus result = AudioUnitSetProperty(afp->mPlayUnit,
kAudioUnitProperty_SetInputCallback,
kAudioUnitScope_Input,
0,
&afp->mInputCallback,
sizeof(afp->mInputCallback));
if (result)
SDL_SetError("AudioUnitSetProperty:RemoveInputCallback:%ld",
result);
245
246
247
248
249
afp->mAudioFileManager->Disconnect(afp->mAudioFileManager);
}
}
Jul 10, 2006
Jul 10, 2006
250
251
typedef struct
{
252
253
254
255
UInt32 offset;
UInt32 blockSize;
} SSNDData;
Jul 10, 2006
Jul 10, 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 */
270
result = FSGetDataForkName(&dfName);
Jul 10, 2006
Jul 10, 2006
271
272
273
274
275
276
277
278
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 */
Jul 10, 2006
Jul 10, 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;
Jul 10, 2006
Jul 10, 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;
Jul 10, 2006
Jul 10, 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.
Jul 10, 2006
Jul 10, 2006
303
*/
Jul 10, 2006
Jul 10, 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;
Jul 10, 2006
Jul 10, 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. */
Jul 10, 2006
Jul 10, 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") */
324
325
result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset);
Jul 10, 2006
Jul 10, 2006
326
327
if (result)
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition") */
Mar 9, 2006
Mar 9, 2006
329
/* Data size */
330
331
*outFileDataSize = chunk.ckSize - ssndData.offset - 8;
Mar 9, 2006
Mar 9, 2006
332
/* File format */
333
334
afp->mFileDescription.mSampleRate = 44100;
afp->mFileDescription.mFormatID = kAudioFormatLinearPCM;
Jul 10, 2006
Jul 10, 2006
335
336
afp->mFileDescription.mFormatFlags =
kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
337
338
339
340
341
342
343
344
345
afp->mFileDescription.mBytesPerPacket = 4;
afp->mFileDescription.mFramesPerPacket = 1;
afp->mFileDescription.mBytesPerFrame = 4;
afp->mFileDescription.mChannelsPerFrame = 2;
afp->mFileDescription.mBitsPerChannel = 16;
return 1;
}
Jul 10, 2006
Jul 10, 2006
346
347
AudioFilePlayer *
new_AudioFilePlayer(const FSRef * inFileRef)
Jul 10, 2006
Jul 10, 2006
349
SInt64 fileDataSize = 0;
Jul 10, 2006
Jul 10, 2006
351
352
AudioFilePlayer *afp =
(AudioFilePlayer *) SDL_malloc(sizeof(AudioFilePlayer));
353
354
if (afp == NULL)
return NULL;
Jul 10, 2006
Jul 10, 2006
355
SDL_memset(afp, '\0', sizeof(*afp));
Jul 10, 2006
Jul 10, 2006
357
#define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m
358
359
360
361
362
363
364
365
366
367
368
369
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);
Jul 10, 2006
Jul 10, 2006
370
#undef SET_AUDIOFILEPLAYER_METHOD
Jul 10, 2006
Jul 10, 2006
372
if (!afp->OpenFile(afp, inFileRef, &fileDataSize)) {
Feb 7, 2006
Feb 7, 2006
373
SDL_free(afp);
Jul 10, 2006
Jul 10, 2006
376
Mar 9, 2006
Mar 9, 2006
377
/* we want about 4 seconds worth of data for the buffer */
Jul 10, 2006
Jul 10, 2006
378
379
380
381
int bytesPerSecond =
(UInt32) (4 * afp->mFileDescription.mSampleRate *
afp->mFileDescription.mBytesPerFrame);
382
383
#if DEBUG
printf("File format:\n");
Jul 10, 2006
Jul 10, 2006
384
PrintStreamDesc(&afp->mFileDescription);
Jul 10, 2006
Jul 10, 2006
386
387
388
389
afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum,
fileDataSize,
bytesPerSecond);
Jul 10, 2006
Jul 10, 2006
390
if (afp->mAudioFileManager == NULL) {
391
392
393
394
395
396
397
delete_AudioFilePlayer(afp);
return NULL;
}
return afp;
}
Jul 10, 2006
Jul 10, 2006
398
/* vi: set ts=4 sw=4 expandtab: */