From a855d6202536ff28e5aae4f22a0f31d8f5b325d0 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 21 Jan 2017 15:18:31 -0500 Subject: Port of Duke Nukem 3D This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9 --- .../plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c | 360 +++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c (limited to 'apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c') 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 @@ +/* + 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(-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; +} + -- cgit v1.2.3