src/cdrom/macosx/AudioFileReaderThread.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 27 Aug 2008 15:10:03 +0000
changeset 2735 204be4fc2726
parent 1895 c121d94672cb
child 2859 99210400e8b9
permissions -rw-r--r--
Final merge of Google Summer of Code 2008 work...

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