aboutsummaryrefslogtreecommitdiffstats
path: root/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c
diff options
context:
space:
mode:
Diffstat (limited to 'distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c')
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c
new file mode 100644
index 0000000..97cb9b2
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c
@@ -0,0 +1,360 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+#include "SDL_endian.h"
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 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 != kAudioUnitType_Output) {
+ 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) {
+ FSCloseFork (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_SetRenderCallback,
+ 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_SetRenderCallback,
+ 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 (SDL_SwapBE32(chunkHeader.ckID) != 'FORM') {
+ result = -1;
+ if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");*/
+ }
+
+ if (SDL_SwapBE32(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")*/
+
+ chunk.ckID = SDL_SwapBE32(chunk.ckID);
+ chunk.ckSize = SDL_SwapBE32(chunk.ckSize);
+
+ /* 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")*/
+
+ ssndData.offset = SDL_SwapBE32(ssndData.offset);
+
+ 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;
+}
+