e14743d1 |
1 | /* |
2 | SDL - Simple DirectMedia Layer |
3 | Copyright (C) 1997-2009 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 | |
27 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
28 | AudioFileManager.cpp |
29 | */ |
30 | #include "AudioFilePlayer.h" |
31 | #include <mach/mach.h> /* used for setting policy of thread */ |
32 | #include "SDLOSXCAGuard.h" |
33 | #include <pthread.h> |
34 | |
35 | /*#include <list>*/ |
36 | |
37 | /*typedef void *FileData;*/ |
38 | typedef struct S_FileData |
39 | { |
40 | AudioFileManager *obj; |
41 | struct S_FileData *next; |
42 | } FileData; |
43 | |
44 | |
45 | typedef struct S_FileReaderThread { |
46 | /*public:*/ |
47 | SDLOSXCAGuard* (*GetGuard)(struct S_FileReaderThread *frt); |
48 | void (*AddReader)(struct S_FileReaderThread *frt); |
49 | void (*RemoveReader)(struct S_FileReaderThread *frt, AudioFileManager* inItem); |
50 | int (*TryNextRead)(struct S_FileReaderThread *frt, AudioFileManager* inItem); |
51 | |
52 | int mThreadShouldDie; |
53 | |
54 | /*private:*/ |
55 | /*typedef std::list<AudioFileManager*> FileData;*/ |
56 | |
57 | SDLOSXCAGuard *mGuard; |
58 | UInt32 mThreadPriority; |
59 | |
60 | int mNumReaders; |
61 | FileData *mFileData; |
62 | |
63 | |
64 | void (*ReadNextChunk)(struct S_FileReaderThread *frt); |
65 | int (*StartFixedPriorityThread)(struct S_FileReaderThread *frt); |
66 | /*static*/ |
67 | UInt32 (*GetThreadBasePriority)(pthread_t inThread); |
68 | /*static*/ |
69 | void* (*DiskReaderEntry)(void *inRefCon); |
70 | } FileReaderThread; |
71 | |
72 | |
73 | static SDLOSXCAGuard* FileReaderThread_GetGuard(FileReaderThread *frt) |
74 | { |
75 | return frt->mGuard; |
76 | } |
77 | |
78 | /* returns 1 if succeeded */ |
79 | static int FileReaderThread_TryNextRead (FileReaderThread *frt, AudioFileManager* inItem) |
80 | { |
81 | int didLock = 0; |
82 | int succeeded = 0; |
83 | if (frt->mGuard->Try(frt->mGuard, &didLock)) |
84 | { |
85 | /*frt->mFileData.push_back (inItem);*/ |
86 | /* !!! FIXME: this could be faster with a "tail" member. --ryan. */ |
87 | FileData *i = frt->mFileData; |
88 | FileData *prev = NULL; |
89 | |
90 | FileData *newfd = (FileData *) SDL_malloc(sizeof (FileData)); |
91 | newfd->obj = inItem; |
92 | newfd->next = NULL; |
93 | |
94 | while (i != NULL) { prev = i; i = i->next; } |
95 | if (prev == NULL) |
96 | frt->mFileData = newfd; |
97 | else |
98 | prev->next = newfd; |
99 | |
100 | frt->mGuard->Notify(frt->mGuard); |
101 | succeeded = 1; |
102 | |
103 | if (didLock) |
104 | frt->mGuard->Unlock(frt->mGuard); |
105 | } |
106 | |
107 | return succeeded; |
108 | } |
109 | |
110 | static void FileReaderThread_AddReader(FileReaderThread *frt) |
111 | { |
112 | if (frt->mNumReaders == 0) |
113 | { |
114 | frt->mThreadShouldDie = 0; |
115 | frt->StartFixedPriorityThread (frt); |
116 | } |
117 | frt->mNumReaders++; |
118 | } |
119 | |
120 | static void FileReaderThread_RemoveReader (FileReaderThread *frt, AudioFileManager* inItem) |
121 | { |
122 | if (frt->mNumReaders > 0) |
123 | { |
124 | int bNeedsRelease = frt->mGuard->Lock(frt->mGuard); |
125 | |
126 | /*frt->mFileData.remove (inItem);*/ |
127 | FileData *i = frt->mFileData; |
128 | FileData *prev = NULL; |
129 | while (i != NULL) |
130 | { |
131 | FileData *next = i->next; |
132 | if (i->obj != inItem) |
133 | prev = i; |
134 | else |
135 | { |
136 | if (prev == NULL) |
137 | frt->mFileData = next; |
138 | else |
139 | prev->next = next; |
140 | SDL_free(i); |
141 | } |
142 | i = next; |
143 | } |
144 | |
145 | if (--frt->mNumReaders == 0) { |
146 | frt->mThreadShouldDie = 1; |
147 | frt->mGuard->Notify(frt->mGuard); /* wake up thread so it will quit */ |
148 | frt->mGuard->Wait(frt->mGuard); /* wait for thread to die */ |
149 | } |
150 | |
151 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); |
152 | } |
153 | } |
154 | |
155 | static int FileReaderThread_StartFixedPriorityThread (FileReaderThread *frt) |
156 | { |
157 | pthread_attr_t theThreadAttrs; |
158 | pthread_t pThread; |
159 | |
160 | OSStatus result = pthread_attr_init(&theThreadAttrs); |
161 | if (result) return 0; /*THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")*/ |
162 | |
163 | result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED); |
164 | if (result) return 0; /*THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")*/ |
165 | |
166 | result = pthread_create (&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt); |
167 | if (result) return 0; /*THROW_RESULT("pthread_create - Create and start the thread.")*/ |
168 | |
169 | pthread_attr_destroy(&theThreadAttrs); |
170 | |
171 | /* we've now created the thread and started it |
172 | we'll now set the priority of the thread to the nominated priority |
173 | and we'll also make the thread fixed */ |
174 | thread_extended_policy_data_t theFixedPolicy; |
175 | thread_precedence_policy_data_t thePrecedencePolicy; |
176 | SInt32 relativePriority; |
177 | |
178 | /* make thread fixed */ |
179 | theFixedPolicy.timeshare = 0; /* set to 1 for a non-fixed thread */ |
180 | result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); |
181 | if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")*/ |
182 | /* set priority */ |
183 | /* precedency policy's "importance" value is relative to spawning thread's priority */ |
184 | relativePriority = frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self()); |
185 | |
186 | thePrecedencePolicy.importance = relativePriority; |
187 | result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT); |
188 | if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread priority.")*/ |
189 | |
190 | return 1; |
191 | } |
192 | |
193 | static UInt32 FileReaderThread_GetThreadBasePriority (pthread_t inThread) |
194 | { |
195 | thread_basic_info_data_t threadInfo; |
196 | policy_info_data_t thePolicyInfo; |
197 | unsigned int count; |
198 | |
199 | /* get basic info */ |
200 | count = THREAD_BASIC_INFO_COUNT; |
201 | thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count); |
202 | |
203 | switch (threadInfo.policy) { |
204 | case POLICY_TIMESHARE: |
205 | count = POLICY_TIMESHARE_INFO_COUNT; |
206 | thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count); |
207 | return thePolicyInfo.ts.base_priority; |
208 | break; |
209 | |
210 | case POLICY_FIFO: |
211 | count = POLICY_FIFO_INFO_COUNT; |
212 | thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count); |
213 | if (thePolicyInfo.fifo.depressed) { |
214 | return thePolicyInfo.fifo.depress_priority; |
215 | } else { |
216 | return thePolicyInfo.fifo.base_priority; |
217 | } |
218 | break; |
219 | |
220 | case POLICY_RR: |
221 | count = POLICY_RR_INFO_COUNT; |
222 | thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count); |
223 | if (thePolicyInfo.rr.depressed) { |
224 | return thePolicyInfo.rr.depress_priority; |
225 | } else { |
226 | return thePolicyInfo.rr.base_priority; |
227 | } |
228 | break; |
229 | } |
230 | |
231 | return 0; |
232 | } |
233 | |
234 | static void *FileReaderThread_DiskReaderEntry (void *inRefCon) |
235 | { |
236 | FileReaderThread *frt = (FileReaderThread *)inRefCon; |
237 | frt->ReadNextChunk(frt); |
238 | #if DEBUG |
239 | printf ("finished with reading file\n"); |
240 | #endif |
241 | |
242 | return 0; |
243 | } |
244 | |
245 | static void FileReaderThread_ReadNextChunk (FileReaderThread *frt) |
246 | { |
247 | OSStatus result; |
248 | ByteCount dataChunkSize; |
249 | AudioFileManager* theItem = 0; |
250 | |
251 | for (;;) |
252 | { |
253 | { /* this is a scoped based lock */ |
254 | int bNeedsRelease = frt->mGuard->Lock(frt->mGuard); |
255 | |
256 | if (frt->mThreadShouldDie) { |
257 | frt->mGuard->Notify(frt->mGuard); |
258 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); |
259 | return; |
260 | } |
261 | |
262 | /*if (frt->mFileData.empty())*/ |
263 | if (frt->mFileData == NULL) |
264 | { |
265 | frt->mGuard->Wait(frt->mGuard); |
266 | } |
267 | |
268 | /* kill thread */ |
269 | if (frt->mThreadShouldDie) { |
270 | |
271 | frt->mGuard->Notify(frt->mGuard); |
272 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); |
273 | return; |
274 | } |
275 | |
276 | /*theItem = frt->mFileData.front();*/ |
277 | /*frt->mFileData.pop_front();*/ |
278 | theItem = NULL; |
279 | if (frt->mFileData != NULL) |
280 | { |
281 | FileData *next = frt->mFileData->next; |
282 | theItem = frt->mFileData->obj; |
283 | SDL_free(frt->mFileData); |
284 | frt->mFileData = next; |
285 | } |
286 | |
287 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); |
288 | } |
289 | |
290 | if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize) |
291 | dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition; |
292 | else |
293 | dataChunkSize = theItem->mChunkSize; |
294 | |
295 | /* this is the exit condition for the thread */ |
296 | if (dataChunkSize <= 0) { |
297 | theItem->mFinishedReadingData = 1; |
298 | continue; |
299 | } |
300 | /* construct pointer */ |
301 | char* writePtr = (char *) (theItem->GetFileBuffer(theItem) + |
302 | (theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize)); |
303 | |
304 | /* read data */ |
305 | result = theItem->Read(theItem, writePtr, &dataChunkSize); |
306 | if (result != noErr && result != eofErr) { |
307 | AudioFilePlayer *afp = (AudioFilePlayer *) theItem->GetParent(theItem); |
308 | afp->DoNotification(afp, result); |
309 | continue; |
310 | } |
311 | |
312 | if (dataChunkSize != theItem->mChunkSize) |
313 | { |
314 | writePtr += dataChunkSize; |
315 | |
316 | /* can't exit yet.. we still have to pass the partial buffer back */ |
317 | SDL_memset(writePtr, 0, (theItem->mChunkSize - dataChunkSize)); |
318 | } |
319 | |
320 | theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; /* switch buffers */ |
321 | |
322 | if (result == eofErr) |
323 | theItem->mReadFilePosition = theItem->mFileLength; |
324 | else |
325 | theItem->mReadFilePosition += dataChunkSize; /* increment count */ |
326 | } |
327 | } |
328 | |
329 | void delete_FileReaderThread(FileReaderThread *frt) |
330 | { |
331 | if (frt != NULL) |
332 | { |
333 | delete_SDLOSXCAGuard(frt->mGuard); |
334 | SDL_free(frt); |
335 | } |
336 | } |
337 | |
338 | FileReaderThread *new_FileReaderThread () |
339 | { |
340 | FileReaderThread *frt = (FileReaderThread *) SDL_malloc(sizeof (FileReaderThread)); |
341 | if (frt == NULL) |
342 | return NULL; |
343 | SDL_memset(frt, '\0', sizeof (*frt)); |
344 | |
345 | frt->mGuard = new_SDLOSXCAGuard(); |
346 | if (frt->mGuard == NULL) |
347 | { |
348 | SDL_free(frt); |
349 | return NULL; |
350 | } |
351 | |
352 | #define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m |
353 | SET_FILEREADERTHREAD_METHOD(GetGuard); |
354 | SET_FILEREADERTHREAD_METHOD(AddReader); |
355 | SET_FILEREADERTHREAD_METHOD(RemoveReader); |
356 | SET_FILEREADERTHREAD_METHOD(TryNextRead); |
357 | SET_FILEREADERTHREAD_METHOD(ReadNextChunk); |
358 | SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread); |
359 | SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority); |
360 | SET_FILEREADERTHREAD_METHOD(DiskReaderEntry); |
361 | #undef SET_FILEREADERTHREAD_METHOD |
362 | |
363 | frt->mThreadPriority = 62; |
364 | return frt; |
365 | } |
366 | |
367 | |
368 | static FileReaderThread *sReaderThread; |
369 | |
370 | |
371 | static int AudioFileManager_DoConnect (AudioFileManager *afm) |
372 | { |
373 | if (!afm->mIsEngaged) |
374 | { |
375 | OSStatus result; |
376 | |
377 | /*afm->mReadFilePosition = 0;*/ |
378 | afm->mFinishedReadingData = 0; |
379 | |
380 | afm->mNumTimesAskedSinceFinished = 0; |
381 | afm->mLockUnsuccessful = 0; |
382 | |
383 | ByteCount dataChunkSize; |
384 | |
385 | if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize) |
386 | dataChunkSize = afm->mFileLength - afm->mReadFilePosition; |
387 | else |
388 | dataChunkSize = afm->mChunkSize; |
389 | |
390 | result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize); |
391 | if (result) return 0; /*THROW_RESULT("AudioFileManager::DoConnect(): Read")*/ |
392 | |
393 | afm->mReadFilePosition += dataChunkSize; |
394 | |
395 | afm->mWriteToFirstBuffer = 0; |
396 | afm->mReadFromFirstBuffer = 1; |
397 | |
398 | sReaderThread->AddReader(sReaderThread); |
399 | |
400 | afm->mIsEngaged = 1; |
401 | } |
402 | /* |
403 | else |
404 | throw static_cast<OSStatus>(-1); */ /* thread has already been started */ |
405 | |
406 | return 1; |
407 | } |
408 | |
409 | static void AudioFileManager_Disconnect (AudioFileManager *afm) |
410 | { |
411 | if (afm->mIsEngaged) |
412 | { |
413 | sReaderThread->RemoveReader (sReaderThread, afm); |
414 | afm->mIsEngaged = 0; |
415 | } |
416 | } |
417 | |
418 | static OSStatus AudioFileManager_Read(AudioFileManager *afm, char *buffer, ByteCount *len) |
419 | { |
420 | return FSReadFork (afm->mForkRefNum, |
421 | fsFromStart, |
422 | afm->mReadFilePosition + afm->mAudioDataOffset, |
423 | *len, |
424 | buffer, |
425 | len); |
426 | } |
427 | |
428 | static OSStatus AudioFileManager_GetFileData (AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize) |
429 | { |
430 | if (afm->mFinishedReadingData) |
431 | { |
432 | ++afm->mNumTimesAskedSinceFinished; |
433 | *inOutDataSize = 0; |
434 | *inOutData = 0; |
435 | return noErr; |
436 | } |
437 | |
438 | if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) { |
439 | #if DEBUG |
440 | printf ("* * * * * * * Can't keep up with reading file\n"); |
441 | #endif |
442 | |
443 | afm->mParent->DoNotification (afm->mParent, kAudioFilePlayErr_FilePlayUnderrun); |
444 | *inOutDataSize = 0; |
445 | *inOutData = 0; |
446 | } else { |
447 | *inOutDataSize = afm->mChunkSize; |
448 | *inOutData = afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer + afm->mChunkSize); |
449 | } |
450 | |
451 | afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm); |
452 | |
453 | afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer; |
454 | |
455 | return noErr; |
456 | } |
457 | |
458 | static void AudioFileManager_AfterRender (AudioFileManager *afm) |
459 | { |
460 | if (afm->mNumTimesAskedSinceFinished > 0) |
461 | { |
462 | int didLock = 0; |
463 | SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread); |
464 | if (guard->Try(guard, &didLock)) { |
465 | afm->mParent->DoNotification (afm->mParent, kAudioFilePlay_FileIsFinished); |
466 | if (didLock) |
467 | guard->Unlock(guard); |
468 | } |
469 | } |
470 | |
471 | if (afm->mLockUnsuccessful) |
472 | afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm); |
473 | } |
474 | |
475 | static void AudioFileManager_SetPosition (AudioFileManager *afm, SInt64 pos) |
476 | { |
477 | if (pos < 0 || pos >= afm->mFileLength) { |
478 | SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n", |
479 | (unsigned int)pos, (unsigned int)afm->mFileLength); |
480 | pos = 0; |
481 | } |
482 | |
483 | afm->mReadFilePosition = pos; |
484 | } |
485 | |
486 | static void AudioFileManager_SetEndOfFile (AudioFileManager *afm, SInt64 pos) |
487 | { |
488 | if (pos <= 0 || pos > afm->mFileLength) { |
489 | SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n"); |
490 | pos = afm->mFileLength; |
491 | } |
492 | |
493 | afm->mFileLength = pos; |
494 | } |
495 | |
496 | static const char *AudioFileManager_GetFileBuffer(AudioFileManager *afm) |
497 | { |
498 | return afm->mFileBuffer; |
499 | } |
500 | |
501 | const AudioFilePlayer *AudioFileManager_GetParent(AudioFileManager *afm) |
502 | { |
503 | return afm->mParent; |
504 | } |
505 | |
506 | static int AudioFileManager_GetByteCounter(AudioFileManager *afm) |
507 | { |
508 | return afm->mByteCounter; |
509 | } |
510 | |
511 | static OSStatus AudioFileManager_FileInputProc (void *inRefCon, |
512 | AudioUnitRenderActionFlags *ioActionFlags, |
513 | const AudioTimeStamp *inTimeStamp, |
514 | UInt32 inBusNumber, |
515 | UInt32 inNumberFrames, |
516 | AudioBufferList *ioData) |
517 | { |
518 | AudioFileManager* afm = (AudioFileManager*)inRefCon; |
519 | return afm->Render(afm, ioData); |
520 | } |
521 | |
522 | static OSStatus AudioFileManager_Render (AudioFileManager *afm, AudioBufferList *ioData) |
523 | { |
524 | OSStatus result = noErr; |
525 | AudioBuffer *abuf; |
526 | UInt32 i; |
527 | |
528 | for (i = 0; i < ioData->mNumberBuffers; i++) { |
529 | abuf = &ioData->mBuffers[i]; |
530 | if (afm->mBufferOffset >= afm->mBufferSize) { |
531 | result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize); |
532 | if (result) { |
533 | SDL_SetError ("AudioConverterFillBuffer:%ld\n", result); |
534 | afm->mParent->DoNotification(afm->mParent, result); |
535 | return result; |
536 | } |
537 | |
538 | afm->mBufferOffset = 0; |
539 | } |
540 | |
541 | if (abuf->mDataByteSize > afm->mBufferSize - afm->mBufferOffset) |
542 | abuf->mDataByteSize = afm->mBufferSize - afm->mBufferOffset; |
543 | abuf->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset; |
544 | afm->mBufferOffset += abuf->mDataByteSize; |
545 | |
546 | afm->mByteCounter += abuf->mDataByteSize; |
547 | afm->AfterRender(afm); |
548 | } |
549 | return result; |
550 | } |
551 | |
552 | |
553 | void delete_AudioFileManager (AudioFileManager *afm) |
554 | { |
555 | if (afm != NULL) { |
556 | if (afm->mFileBuffer) { |
557 | free(afm->mFileBuffer); |
558 | } |
559 | |
560 | SDL_free(afm); |
561 | } |
562 | } |
563 | |
564 | |
565 | AudioFileManager *new_AudioFileManager(AudioFilePlayer *inParent, |
566 | SInt16 inForkRefNum, |
567 | SInt64 inFileLength, |
568 | UInt32 inChunkSize) |
569 | { |
570 | AudioFileManager *afm; |
571 | |
572 | if (sReaderThread == NULL) |
573 | { |
574 | sReaderThread = new_FileReaderThread(); |
575 | if (sReaderThread == NULL) |
576 | return NULL; |
577 | } |
578 | |
579 | afm = (AudioFileManager *) SDL_malloc(sizeof (AudioFileManager)); |
580 | if (afm == NULL) |
581 | return NULL; |
582 | SDL_memset(afm, '\0', sizeof (*afm)); |
583 | |
584 | #define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m |
585 | SET_AUDIOFILEMANAGER_METHOD(Disconnect); |
586 | SET_AUDIOFILEMANAGER_METHOD(DoConnect); |
587 | SET_AUDIOFILEMANAGER_METHOD(Read); |
588 | SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer); |
589 | SET_AUDIOFILEMANAGER_METHOD(GetParent); |
590 | SET_AUDIOFILEMANAGER_METHOD(SetPosition); |
591 | SET_AUDIOFILEMANAGER_METHOD(GetByteCounter); |
592 | SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile); |
593 | SET_AUDIOFILEMANAGER_METHOD(Render); |
594 | SET_AUDIOFILEMANAGER_METHOD(GetFileData); |
595 | SET_AUDIOFILEMANAGER_METHOD(AfterRender); |
596 | SET_AUDIOFILEMANAGER_METHOD(FileInputProc); |
597 | #undef SET_AUDIOFILEMANAGER_METHOD |
598 | |
599 | afm->mParent = inParent; |
600 | afm->mForkRefNum = inForkRefNum; |
601 | afm->mBufferSize = inChunkSize; |
602 | afm->mBufferOffset = inChunkSize; |
603 | afm->mChunkSize = inChunkSize; |
604 | afm->mFileLength = inFileLength; |
605 | afm->mFileBuffer = (char*) SDL_malloc(afm->mChunkSize * 2); |
606 | FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset); |
607 | assert (afm->mFileBuffer != NULL); |
608 | return afm; |
609 | } |
610 | |