diff options
author | Franklin Wei <git@fwei.tk> | 2017-01-21 15:18:31 -0500 |
---|---|---|
committer | Franklin Wei <git@fwei.tk> | 2017-12-23 21:01:26 -0500 |
commit | a855d6202536ff28e5aae4f22a0f31d8f5b325d0 (patch) | |
tree | 8c75f224dd64ed360505afa8843d016b0d75000b /apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c | |
parent | 01c6dcf6c7b9bb1ad2fa0450f99bacc5f3d3e04b (diff) | |
download | rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.tar.gz rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.zip |
Port of Duke Nukem 3D
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL
for Rockbox.
Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
Diffstat (limited to 'apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c')
-rw-r--r-- | apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c new file mode 100644 index 0000000000..97cb9b2874 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | |||
22 | This file based on Apple sample code. We haven't changed the file name, | ||
23 | so if you want to see the original search for it on apple.com/developer | ||
24 | */ | ||
25 | #include "SDL_config.h" | ||
26 | #include "SDL_endian.h" | ||
27 | |||
28 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
29 | AudioFilePlayer.cpp | ||
30 | */ | ||
31 | #include "AudioFilePlayer.h" | ||
32 | |||
33 | /* | ||
34 | void ThrowResult (OSStatus result, const char* str) | ||
35 | { | ||
36 | SDL_SetError ("Error: %s %d", str, result); | ||
37 | throw result; | ||
38 | } | ||
39 | */ | ||
40 | |||
41 | #if DEBUG | ||
42 | static void PrintStreamDesc (AudioStreamBasicDescription *inDesc) | ||
43 | { | ||
44 | if (!inDesc) { | ||
45 | printf ("Can't print a NULL desc!\n"); | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | printf ("- - - - - - - - - - - - - - - - - - - -\n"); | ||
50 | printf (" Sample Rate:%f\n", inDesc->mSampleRate); | ||
51 | printf (" Format ID:%s\n", (char*)&inDesc->mFormatID); | ||
52 | printf (" Format Flags:%lX\n", inDesc->mFormatFlags); | ||
53 | printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket); | ||
54 | printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket); | ||
55 | printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame); | ||
56 | printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame); | ||
57 | printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel); | ||
58 | printf ("- - - - - - - - - - - - - - - - - - - -\n"); | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | |||
63 | static int AudioFilePlayer_SetDestination (AudioFilePlayer *afp, AudioUnit *inDestUnit) | ||
64 | { | ||
65 | /*if (afp->mConnected) throw static_cast<OSStatus>(-1);*/ /* can't set dest if already engaged */ | ||
66 | if (afp->mConnected) | ||
67 | return 0 ; | ||
68 | |||
69 | SDL_memcpy(&afp->mPlayUnit, inDestUnit, sizeof (afp->mPlayUnit)); | ||
70 | |||
71 | OSStatus result = noErr; | ||
72 | |||
73 | |||
74 | /* we can "down" cast a component instance to a component */ | ||
75 | ComponentDescription desc; | ||
76 | result = GetComponentInfo ((Component)*inDestUnit, &desc, 0, 0, 0); | ||
77 | if (result) return 0; /*THROW_RESULT("GetComponentInfo")*/ | ||
78 | |||
79 | /* we're going to use this to know which convert routine to call | ||
80 | a v1 audio unit will have a type of 'aunt' | ||
81 | a v2 audio unit will have one of several different types. */ | ||
82 | if (desc.componentType != kAudioUnitType_Output) { | ||
83 | result = badComponentInstance; | ||
84 | /*THROW_RESULT("BAD COMPONENT")*/ | ||
85 | if (result) return 0; | ||
86 | } | ||
87 | |||
88 | /* Set the input format of the audio unit. */ | ||
89 | result = AudioUnitSetProperty (*inDestUnit, | ||
90 | kAudioUnitProperty_StreamFormat, | ||
91 | kAudioUnitScope_Input, | ||
92 | 0, | ||
93 | &afp->mFileDescription, | ||
94 | sizeof (afp->mFileDescription)); | ||
95 | /*THROW_RESULT("AudioUnitSetProperty")*/ | ||
96 | if (result) return 0; | ||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | static void AudioFilePlayer_SetNotifier(AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon) | ||
101 | { | ||
102 | afp->mNotifier = inNotifier; | ||
103 | afp->mRefCon = inRefCon; | ||
104 | } | ||
105 | |||
106 | static int AudioFilePlayer_IsConnected(AudioFilePlayer *afp) | ||
107 | { | ||
108 | return afp->mConnected; | ||
109 | } | ||
110 | |||
111 | static AudioUnit AudioFilePlayer_GetDestUnit(AudioFilePlayer *afp) | ||
112 | { | ||
113 | return afp->mPlayUnit; | ||
114 | } | ||
115 | |||
116 | static void AudioFilePlayer_Print(AudioFilePlayer *afp) | ||
117 | { | ||
118 | #if DEBUG | ||
119 | printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false")); | ||
120 | printf ("- - - - - - - - - - - - - - \n"); | ||
121 | #endif | ||
122 | } | ||
123 | |||
124 | static void AudioFilePlayer_SetStartFrame (AudioFilePlayer *afp, int frame) | ||
125 | { | ||
126 | SInt64 position = frame * 2352; | ||
127 | |||
128 | afp->mStartFrame = frame; | ||
129 | afp->mAudioFileManager->SetPosition (afp->mAudioFileManager, position); | ||
130 | } | ||
131 | |||
132 | |||
133 | static int AudioFilePlayer_GetCurrentFrame (AudioFilePlayer *afp) | ||
134 | { | ||
135 | return afp->mStartFrame + (afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) / 2352); | ||
136 | } | ||
137 | |||
138 | static void AudioFilePlayer_SetStopFrame (AudioFilePlayer *afp, int frame) | ||
139 | { | ||
140 | SInt64 position = frame * 2352; | ||
141 | |||
142 | afp->mAudioFileManager->SetEndOfFile (afp->mAudioFileManager, position); | ||
143 | } | ||
144 | |||
145 | void delete_AudioFilePlayer(AudioFilePlayer *afp) | ||
146 | { | ||
147 | if (afp != NULL) | ||
148 | { | ||
149 | afp->Disconnect(afp); | ||
150 | |||
151 | if (afp->mAudioFileManager) { | ||
152 | delete_AudioFileManager(afp->mAudioFileManager); | ||
153 | afp->mAudioFileManager = 0; | ||
154 | } | ||
155 | |||
156 | if (afp->mForkRefNum) { | ||
157 | FSCloseFork (afp->mForkRefNum); | ||
158 | afp->mForkRefNum = 0; | ||
159 | } | ||
160 | SDL_free(afp); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static int AudioFilePlayer_Connect(AudioFilePlayer *afp) | ||
165 | { | ||
166 | #if DEBUG | ||
167 | printf ("Connect:%x, engaged=%d\n", (int)afp->mPlayUnit, (afp->mConnected ? 1 : 0)); | ||
168 | #endif | ||
169 | if (!afp->mConnected) | ||
170 | { | ||
171 | if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager)) | ||
172 | return 0; | ||
173 | |||
174 | /* set the render callback for the file data to be supplied to the sound converter AU */ | ||
175 | afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc; | ||
176 | afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager; | ||
177 | |||
178 | OSStatus result = AudioUnitSetProperty (afp->mPlayUnit, | ||
179 | kAudioUnitProperty_SetRenderCallback, | ||
180 | kAudioUnitScope_Input, | ||
181 | 0, | ||
182 | &afp->mInputCallback, | ||
183 | sizeof(afp->mInputCallback)); | ||
184 | if (result) return 0; /*THROW_RESULT("AudioUnitSetProperty")*/ | ||
185 | afp->mConnected = 1; | ||
186 | } | ||
187 | |||
188 | return 1; | ||
189 | } | ||
190 | |||
191 | /* warning noted, now please go away ;-) */ | ||
192 | /* #warning This should redirect the calling of notification code to some other thread */ | ||
193 | static void AudioFilePlayer_DoNotification (AudioFilePlayer *afp, OSStatus inStatus) | ||
194 | { | ||
195 | if (afp->mNotifier) { | ||
196 | (*afp->mNotifier) (afp->mRefCon, inStatus); | ||
197 | } else { | ||
198 | SDL_SetError ("Notification posted with no notifier in place"); | ||
199 | |||
200 | if (inStatus == kAudioFilePlay_FileIsFinished) | ||
201 | afp->Disconnect(afp); | ||
202 | else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun) | ||
203 | afp->Disconnect(afp); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | static void AudioFilePlayer_Disconnect (AudioFilePlayer *afp) | ||
208 | { | ||
209 | #if DEBUG | ||
210 | printf ("Disconnect:%x,%ld, engaged=%d\n", (int)afp->mPlayUnit, 0, (afp->mConnected ? 1 : 0)); | ||
211 | #endif | ||
212 | if (afp->mConnected) | ||
213 | { | ||
214 | afp->mConnected = 0; | ||
215 | |||
216 | afp->mInputCallback.inputProc = 0; | ||
217 | afp->mInputCallback.inputProcRefCon = 0; | ||
218 | OSStatus result = AudioUnitSetProperty (afp->mPlayUnit, | ||
219 | kAudioUnitProperty_SetRenderCallback, | ||
220 | kAudioUnitScope_Input, | ||
221 | 0, | ||
222 | &afp->mInputCallback, | ||
223 | sizeof(afp->mInputCallback)); | ||
224 | if (result) | ||
225 | SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result); | ||
226 | |||
227 | afp->mAudioFileManager->Disconnect(afp->mAudioFileManager); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | typedef struct { | ||
232 | UInt32 offset; | ||
233 | UInt32 blockSize; | ||
234 | } SSNDData; | ||
235 | |||
236 | static int AudioFilePlayer_OpenFile (AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileDataSize) | ||
237 | { | ||
238 | ContainerChunk chunkHeader; | ||
239 | ChunkHeader chunk; | ||
240 | SSNDData ssndData; | ||
241 | |||
242 | OSErr result; | ||
243 | HFSUniStr255 dfName; | ||
244 | ByteCount actual; | ||
245 | SInt64 offset; | ||
246 | |||
247 | /* Open the data fork of the input file */ | ||
248 | result = FSGetDataForkName(&dfName); | ||
249 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName")*/ | ||
250 | |||
251 | result = FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm, &afp->mForkRefNum); | ||
252 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork")*/ | ||
253 | |||
254 | /* Read the file header, and check if it's indeed an AIFC file */ | ||
255 | result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual); | ||
256 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/ | ||
257 | |||
258 | if (SDL_SwapBE32(chunkHeader.ckID) != 'FORM') { | ||
259 | result = -1; | ||
260 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");*/ | ||
261 | } | ||
262 | |||
263 | if (SDL_SwapBE32(chunkHeader.formType) != 'AIFC') { | ||
264 | result = -1; | ||
265 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'");*/ | ||
266 | } | ||
267 | |||
268 | /* Search for the SSND chunk. We ignore all compression etc. information | ||
269 | in other chunks. Of course that is kind of evil, but for now we are lazy | ||
270 | and rely on the cdfs to always give us the same fixed format. | ||
271 | TODO: Parse the COMM chunk we currently skip to fill in mFileDescription. | ||
272 | */ | ||
273 | offset = 0; | ||
274 | do { | ||
275 | result = FSReadFork(afp->mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual); | ||
276 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/ | ||
277 | |||
278 | chunk.ckID = SDL_SwapBE32(chunk.ckID); | ||
279 | chunk.ckSize = SDL_SwapBE32(chunk.ckSize); | ||
280 | |||
281 | /* Skip the chunk data */ | ||
282 | offset = chunk.ckSize; | ||
283 | } while (chunk.ckID != 'SSND'); | ||
284 | |||
285 | /* Read the header of the SSND chunk. After this, we are positioned right | ||
286 | at the start of the audio data. */ | ||
287 | result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual); | ||
288 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/ | ||
289 | |||
290 | ssndData.offset = SDL_SwapBE32(ssndData.offset); | ||
291 | |||
292 | result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset); | ||
293 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition")*/ | ||
294 | |||
295 | /* Data size */ | ||
296 | *outFileDataSize = chunk.ckSize - ssndData.offset - 8; | ||
297 | |||
298 | /* File format */ | ||
299 | afp->mFileDescription.mSampleRate = 44100; | ||
300 | afp->mFileDescription.mFormatID = kAudioFormatLinearPCM; | ||
301 | afp->mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; | ||
302 | afp->mFileDescription.mBytesPerPacket = 4; | ||
303 | afp->mFileDescription.mFramesPerPacket = 1; | ||
304 | afp->mFileDescription.mBytesPerFrame = 4; | ||
305 | afp->mFileDescription.mChannelsPerFrame = 2; | ||
306 | afp->mFileDescription.mBitsPerChannel = 16; | ||
307 | |||
308 | return 1; | ||
309 | } | ||
310 | |||
311 | AudioFilePlayer *new_AudioFilePlayer (const FSRef *inFileRef) | ||
312 | { | ||
313 | SInt64 fileDataSize = 0; | ||
314 | |||
315 | AudioFilePlayer *afp = (AudioFilePlayer *) SDL_malloc(sizeof (AudioFilePlayer)); | ||
316 | if (afp == NULL) | ||
317 | return NULL; | ||
318 | SDL_memset(afp, '\0', sizeof (*afp)); | ||
319 | |||
320 | #define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m | ||
321 | SET_AUDIOFILEPLAYER_METHOD(SetDestination); | ||
322 | SET_AUDIOFILEPLAYER_METHOD(SetNotifier); | ||
323 | SET_AUDIOFILEPLAYER_METHOD(SetStartFrame); | ||
324 | SET_AUDIOFILEPLAYER_METHOD(GetCurrentFrame); | ||
325 | SET_AUDIOFILEPLAYER_METHOD(SetStopFrame); | ||
326 | SET_AUDIOFILEPLAYER_METHOD(Connect); | ||
327 | SET_AUDIOFILEPLAYER_METHOD(Disconnect); | ||
328 | SET_AUDIOFILEPLAYER_METHOD(DoNotification); | ||
329 | SET_AUDIOFILEPLAYER_METHOD(IsConnected); | ||
330 | SET_AUDIOFILEPLAYER_METHOD(GetDestUnit); | ||
331 | SET_AUDIOFILEPLAYER_METHOD(Print); | ||
332 | SET_AUDIOFILEPLAYER_METHOD(OpenFile); | ||
333 | #undef SET_AUDIOFILEPLAYER_METHOD | ||
334 | |||
335 | if (!afp->OpenFile (afp, inFileRef, &fileDataSize)) | ||
336 | { | ||
337 | SDL_free(afp); | ||
338 | return NULL; | ||
339 | } | ||
340 | |||
341 | /* we want about 4 seconds worth of data for the buffer */ | ||
342 | int bytesPerSecond = (UInt32) (4 * afp->mFileDescription.mSampleRate * afp->mFileDescription.mBytesPerFrame); | ||
343 | |||
344 | #if DEBUG | ||
345 | printf("File format:\n"); | ||
346 | PrintStreamDesc (&afp->mFileDescription); | ||
347 | #endif | ||
348 | |||
349 | afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum, | ||
350 | fileDataSize, | ||
351 | bytesPerSecond); | ||
352 | if (afp->mAudioFileManager == NULL) | ||
353 | { | ||
354 | delete_AudioFilePlayer(afp); | ||
355 | return NULL; | ||
356 | } | ||
357 | |||
358 | return afp; | ||
359 | } | ||
360 | |||