Mercurial > sdl-ios-xcode
view src/cdrom/macosx/AudioFilePlayer.c @ 1359:1e4ba2e063b4
*** empty log message ***
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Fri, 10 Feb 2006 07:03:22 +0000 |
parents | 3692456e7b0f |
children | d910939febfa |
line wrap: on
line source
/* 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 */ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AudioFilePlayer.cpp // #include "AudioFilePlayer.h" /* void ThrowResult (OSStatus result, const char* str) { SDL_SetError ("Error: %s %d", str, result); throw result; } */ #if DEBUG static void PrintStreamDesc (AudioStreamBasicDescription *inDesc) { if (!inDesc) { printf ("Can't print a NULL desc!\n"); return; } 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"); } #endif static int AudioFilePlayer_SetDestination (AudioFilePlayer *afp, AudioUnit *inDestUnit) { //if (afp->mConnected) throw static_cast<OSStatus>(-1); //can't set dest if already engaged if (afp->mConnected) return 0 ; SDL_memcpy(&afp->mPlayUnit, inDestUnit, sizeof (afp->mPlayUnit)); OSStatus result = noErr; //we can "down" cast a component instance to a component ComponentDescription desc; 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. if (desc.componentType != kAudioUnitComponentType) { result = badComponentInstance; //THROW_RESULT("BAD COMPONENT") if (result) return 0; } /* Set the input format of the audio unit. */ result = AudioUnitSetProperty (*inDestUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &afp->mFileDescription, sizeof (afp->mFileDescription)); //THROW_RESULT("AudioUnitSetProperty") if (result) return 0; return 1; } static void AudioFilePlayer_SetNotifier(AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon) { afp->mNotifier = inNotifier; afp->mRefCon = inRefCon; } static int AudioFilePlayer_IsConnected(AudioFilePlayer *afp) { return afp->mConnected; } static AudioUnit AudioFilePlayer_GetDestUnit(AudioFilePlayer *afp) { return afp->mPlayUnit; } static void AudioFilePlayer_Print(AudioFilePlayer *afp) { #if DEBUG printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false")); printf ("- - - - - - - - - - - - - - \n"); #endif } static void AudioFilePlayer_SetStartFrame (AudioFilePlayer *afp, int frame) { SInt64 position = frame * 2352; afp->mStartFrame = frame; afp->mAudioFileManager->SetPosition (afp->mAudioFileManager, position); } static int AudioFilePlayer_GetCurrentFrame (AudioFilePlayer *afp) { return afp->mStartFrame + (afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) / 2352); } static void AudioFilePlayer_SetStopFrame (AudioFilePlayer *afp, int frame) { SInt64 position = frame * 2352; afp->mAudioFileManager->SetEndOfFile (afp->mAudioFileManager, position); } void delete_AudioFilePlayer(AudioFilePlayer *afp) { if (afp != NULL) { afp->Disconnect(afp); if (afp->mAudioFileManager) { delete_AudioFileManager(afp->mAudioFileManager); afp->mAudioFileManager = 0; } if (afp->mForkRefNum) { FSClose (afp->mForkRefNum); afp->mForkRefNum = 0; } SDL_free(afp); } } static int AudioFilePlayer_Connect(AudioFilePlayer *afp) { #if DEBUG printf ("Connect:%x, engaged=%d\n", (int)afp->mPlayUnit, (afp->mConnected ? 1 : 0)); #endif if (!afp->mConnected) { if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager)) return 0; // set the render callback for the file data to be supplied to the sound converter AU afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc; afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager; OSStatus result = AudioUnitSetProperty (afp->mPlayUnit, kAudioUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &afp->mInputCallback, sizeof(afp->mInputCallback)); if (result) return 0; //THROW_RESULT("AudioUnitSetProperty") afp->mConnected = 1; } return 1; } // warning noted, now please go away ;-) // #warning This should redirect the calling of notification code to some other thread static void AudioFilePlayer_DoNotification (AudioFilePlayer *afp, OSStatus inStatus) { if (afp->mNotifier) { (*afp->mNotifier) (afp->mRefCon, inStatus); } else { SDL_SetError ("Notification posted with no notifier in place"); if (inStatus == kAudioFilePlay_FileIsFinished) afp->Disconnect(afp); else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun) afp->Disconnect(afp); } } static void AudioFilePlayer_Disconnect (AudioFilePlayer *afp) { #if DEBUG printf ("Disconnect:%x,%ld, engaged=%d\n", (int)afp->mPlayUnit, 0, (afp->mConnected ? 1 : 0)); #endif if (afp->mConnected) { afp->mConnected = 0; afp->mInputCallback.inputProc = 0; afp->mInputCallback.inputProcRefCon = 0; 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); } } typedef struct { UInt32 offset; UInt32 blockSize; } SSNDData; static int AudioFilePlayer_OpenFile (AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileDataSize) { ContainerChunk chunkHeader; ChunkHeader chunk; SSNDData ssndData; OSErr result; HFSUniStr255 dfName; ByteCount actual; SInt64 offset; // Open the data fork of the input file 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") // Read the file header, and check if it's indeed an AIFC file result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual); if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") if (chunkHeader.ckID != 'FORM') { result = -1; if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'"); } if (chunkHeader.formType != 'AIFC') { result = -1; if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'"); } // 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. offset = 0; do { result = FSReadFork(afp->mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual); if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") // Skip the chunk data offset = chunk.ckSize; } while (chunk.ckID != 'SSND'); // Read the header of the SSND chunk. After this, we are positioned right // at the start of the audio data. result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual); if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset); if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition") // Data size *outFileDataSize = chunk.ckSize - ssndData.offset - 8; // File format afp->mFileDescription.mSampleRate = 44100; afp->mFileDescription.mFormatID = kAudioFormatLinearPCM; afp->mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; afp->mFileDescription.mBytesPerPacket = 4; afp->mFileDescription.mFramesPerPacket = 1; afp->mFileDescription.mBytesPerFrame = 4; afp->mFileDescription.mChannelsPerFrame = 2; afp->mFileDescription.mBitsPerChannel = 16; return 1; } AudioFilePlayer *new_AudioFilePlayer (const FSRef *inFileRef) { SInt64 fileDataSize = 0; AudioFilePlayer *afp = (AudioFilePlayer *) SDL_malloc(sizeof (AudioFilePlayer)); if (afp == NULL) return NULL; 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); return NULL; } // we want about 4 seconds worth of data for the buffer int bytesPerSecond = (UInt32) (4 * afp->mFileDescription.mSampleRate * afp->mFileDescription.mBytesPerFrame); #if DEBUG printf("File format:\n"); PrintStreamDesc (&afp->mFileDescription); #endif afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum, fileDataSize, bytesPerSecond); if (afp->mAudioFileManager == NULL) { delete_AudioFilePlayer(afp); return NULL; } return afp; }