mirror of
https://github.com/yawut/SDL.git
synced 2026-04-24 15:26:55 -05:00
Max has been reworking this code so it works on MacOS X 10.1
This commit is contained in:
parent
ddc06286af
commit
6510cc9eff
|
|
@ -2430,11 +2430,9 @@ case "$target" in
|
|||
# Set up files for the cdrom library
|
||||
if test x$enable_cdrom = xyes; then
|
||||
# The CD-ROM code won't work on old versions of MacOS X yet...
|
||||
#CDROM_SUBDIRS="$CDROM_SUBDIRS macosx"
|
||||
#CDROM_DRIVERS="$CDROM_DRIVERS macosx/libcdrom_macosx.la"
|
||||
#SYSTEM_LIBS="$SYSTEM_LIBS -framework AudioToolbox -framework AudioUnit -lstdc++"
|
||||
CDROM_SUBDIRS="$CDROM_SUBDIRS dummy"
|
||||
CDROM_DRIVERS="$CDROM_DRIVERS dummy/libcdrom_dummy.la"
|
||||
CDROM_SUBDIRS="$CDROM_SUBDIRS macosx"
|
||||
CDROM_DRIVERS="$CDROM_DRIVERS macosx/libcdrom_macosx.la"
|
||||
SYSTEM_LIBS="$SYSTEM_LIBS -framework AudioToolbox -framework AudioUnit -lstdc++"
|
||||
fi
|
||||
# Set up files for the thread library
|
||||
if test x$enable_threads = xyes; then
|
||||
|
|
|
|||
|
|
@ -28,31 +28,9 @@
|
|||
//
|
||||
#include "AudioFilePlayer.h"
|
||||
|
||||
extern const char* AudioFilePlayerErrorStr (OSStatus error)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
switch (error) {
|
||||
case kAudioFileUnspecifiedError: str = "wht?"; break;
|
||||
case kAudioFileUnsupportedFileTypeError: str = "typ?"; break;
|
||||
case kAudioFileUnsupportedDataFormatError: str = "fmt?"; break;
|
||||
case kAudioFileUnsupportedPropertyError: str = "pty?"; break;
|
||||
case kAudioFileBadPropertySizeError: str = "!siz"; break;
|
||||
case kAudioFileNotOptimizedError: str = "optm"; break;
|
||||
case kAudioFilePermissionsError: str = "prm?"; break;
|
||||
case kAudioFileFormatNameUnavailableError: str = "nme?"; break;
|
||||
case kAudioFileInvalidChunkError: str = "chk?"; break;
|
||||
case kAudioFileDoesNotAllow64BitDataSizeError: str = "off?"; break;
|
||||
default: str = "error unspecified";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void ThrowResult (OSStatus result, const char* str)
|
||||
{
|
||||
SDL_SetError ("Error: %s %d (%s)",
|
||||
str, result, AudioFilePlayerErrorStr(result));
|
||||
SDL_SetError ("Error: %s %d", str, result);
|
||||
throw result;
|
||||
}
|
||||
|
||||
|
|
@ -133,31 +111,25 @@ AudioFilePlayer::AudioFilePlayer (const FSRef *inFileRef)
|
|||
OpenFile (inFileRef, fileDataSize);
|
||||
|
||||
// we want about a seconds worth of data for the buffer
|
||||
int secsBytes = UInt32 (mFileDescription.mSampleRate * mFileDescription.mBytesPerFrame);
|
||||
int bytesPerSecond = UInt32 (mFileDescription.mSampleRate * mFileDescription.mBytesPerFrame);
|
||||
|
||||
#if DEBUG
|
||||
printf("File format:\n");
|
||||
PrintStreamDesc (&mFileDescription);
|
||||
#endif
|
||||
|
||||
//round to a 32K boundary
|
||||
//if ((secsBytes & 0xFFFF8000) > (128 * 1024))
|
||||
//secsBytes &= 0xFFFF8000;
|
||||
//else
|
||||
//secsBytes = (secsBytes + 0x7FFF) & 0xFFFF8000;
|
||||
|
||||
mAudioFileManager = new AudioFileReaderThread (*this,
|
||||
mAudioFileID,
|
||||
mAudioFileManager = new AudioFileManager (*this,
|
||||
mForkRefNum,
|
||||
fileDataSize,
|
||||
secsBytes);
|
||||
bytesPerSecond);
|
||||
}
|
||||
|
||||
// you can put a rate scalar here to play the file faster or slower
|
||||
// by multiplying the same rate by the desired factor
|
||||
// eg fileSampleRate * 2 -> twice as fast
|
||||
// before you create the AudioConverter
|
||||
void AudioFilePlayer::SetDestination (AudioUnit &inDestUnit,
|
||||
int inBusNumber)
|
||||
void AudioFilePlayer::SetDestination (AudioUnit &inDestUnit,
|
||||
int inBusNumber)
|
||||
{
|
||||
if (mConnected) throw static_cast<OSStatus>(-1); //can't set dest if already engaged
|
||||
|
||||
|
|
@ -194,43 +166,15 @@ void AudioFilePlayer::SetDestination (AudioUnit &inDestUnit,
|
|||
// 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.
|
||||
mIsAUNTUnit = (desc.componentType == kAudioUnitComponentType);
|
||||
|
||||
if (!mIsAUNTUnit) {
|
||||
if (desc.componentType != kAudioUnitComponentType) {
|
||||
result = badComponentInstance;
|
||||
THROW_RESULT("BAD COMPONENT")
|
||||
}
|
||||
|
||||
|
||||
// HACK - the AIFF files on CDs are in little endian order!
|
||||
if (mFileDescription.mFormatFlags == 0xE)
|
||||
mFileDescription.mFormatFlags &= ~kAudioFormatFlagIsBigEndian;
|
||||
|
||||
|
||||
result = AudioConverterNew (&mFileDescription, &destDesc, &mConverter);
|
||||
THROW_RESULT("AudioConverterNew")
|
||||
|
||||
|
||||
/*
|
||||
// if we have a mono source, we're going to copy each channel into
|
||||
// the destination's channel source...
|
||||
if (mFileDescription.mChannelsPerFrame == 1) {
|
||||
|
||||
SInt32* channelMap = new SInt32 [destDesc.mChannelsPerFrame];
|
||||
for (unsigned int i = 0; i < destDesc.mChannelsPerFrame; ++i)
|
||||
channelMap[i] = 0; //set first channel to all output channels
|
||||
|
||||
result = AudioConverterSetProperty(mConverter,
|
||||
kAudioConverterChannelMap,
|
||||
(sizeof(SInt32) * destDesc.mChannelsPerFrame),
|
||||
channelMap);
|
||||
THROW_RESULT("AudioConverterSetProperty")
|
||||
|
||||
delete [] channelMap;
|
||||
}
|
||||
*/
|
||||
assert (mFileDescription.mChannelsPerFrame == 2);
|
||||
|
||||
#if 0
|
||||
// this uses the better quality SRC
|
||||
UInt32 srcID = kAudioUnitSRCAlgorithm_Polyphase;
|
||||
|
|
@ -272,9 +216,9 @@ AudioFilePlayer::~AudioFilePlayer()
|
|||
mAudioFileManager = 0;
|
||||
}
|
||||
|
||||
if (mAudioFileID) {
|
||||
::AudioFileClose (mAudioFileID);
|
||||
mAudioFileID = 0;
|
||||
if (mForkRefNum) {
|
||||
FSClose (mForkRefNum);
|
||||
mForkRefNum = 0;
|
||||
}
|
||||
|
||||
if (mConverter) {
|
||||
|
|
@ -293,18 +237,16 @@ void AudioFilePlayer::Connect()
|
|||
mAudioFileManager->Connect(mConverter);
|
||||
|
||||
// set the render callback for the file data to be supplied to the sound converter AU
|
||||
if (mIsAUNTUnit) {
|
||||
mInputCallback.inputProc = AudioFileManager::FileInputProc;
|
||||
mInputCallback.inputProcRefCon = mAudioFileManager;
|
||||
mInputCallback.inputProc = AudioFileManager::FileInputProc;
|
||||
mInputCallback.inputProcRefCon = mAudioFileManager;
|
||||
|
||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
mBusNumber,
|
||||
&mInputCallback,
|
||||
sizeof(mInputCallback));
|
||||
THROW_RESULT("AudioUnitSetProperty")
|
||||
}
|
||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
mBusNumber,
|
||||
&mInputCallback,
|
||||
sizeof(mInputCallback));
|
||||
THROW_RESULT("AudioUnitSetProperty")
|
||||
mConnected = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -317,9 +259,7 @@ void AudioFilePlayer::DoNotification (OSStatus inStatus) const
|
|||
|
||||
if (mNotifier) {
|
||||
(*mNotifier) (mRefCon, inStatus);
|
||||
}
|
||||
|
||||
else {
|
||||
} else {
|
||||
SDL_SetError ("Notification posted with no notifier in place");
|
||||
|
||||
if (inStatus == kAudioFilePlay_FileIsFinished)
|
||||
|
|
@ -338,40 +278,89 @@ void AudioFilePlayer::Disconnect ()
|
|||
{
|
||||
mConnected = false;
|
||||
|
||||
if (mIsAUNTUnit) {
|
||||
mInputCallback.inputProc = 0;
|
||||
mInputCallback.inputProcRefCon = 0;
|
||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
mBusNumber,
|
||||
&mInputCallback,
|
||||
sizeof(mInputCallback));
|
||||
if (result)
|
||||
SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result);
|
||||
mInputCallback.inputProc = 0;
|
||||
mInputCallback.inputProcRefCon = 0;
|
||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
mBusNumber,
|
||||
&mInputCallback,
|
||||
sizeof(mInputCallback));
|
||||
if (result)
|
||||
SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result);
|
||||
|
||||
}
|
||||
|
||||
mAudioFileManager->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
struct SSNDData {
|
||||
UInt32 offset;
|
||||
UInt32 blockSize;
|
||||
};
|
||||
|
||||
void AudioFilePlayer::OpenFile (const FSRef *inRef, SInt64& outFileDataSize)
|
||||
{
|
||||
OSStatus result = AudioFileOpen (inRef, fsRdPerm, 0, &mAudioFileID);
|
||||
THROW_RESULT("AudioFileOpen")
|
||||
|
||||
UInt32 dataSize = sizeof(AudioStreamBasicDescription);
|
||||
result = AudioFileGetProperty (mAudioFileID,
|
||||
kAudioFilePropertyDataFormat,
|
||||
&dataSize,
|
||||
&mFileDescription);
|
||||
THROW_RESULT("AudioFileGetProperty")
|
||||
|
||||
dataSize = sizeof (SInt64);
|
||||
result = AudioFileGetProperty (mAudioFileID,
|
||||
kAudioFilePropertyAudioDataByteCount,
|
||||
&dataSize,
|
||||
&outFileDataSize);
|
||||
THROW_RESULT("AudioFileGetProperty")
|
||||
}
|
||||
{
|
||||
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);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName")
|
||||
|
||||
result = FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm, &mForkRefNum);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork")
|
||||
|
||||
// Read the file header, and check if it's indeed an AIFC file
|
||||
result = FSReadFork(mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
if (chunkHeader.ckID != 'FORM') {
|
||||
result = -1;
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");
|
||||
}
|
||||
|
||||
if (chunkHeader.formType != 'AIFC') {
|
||||
result = -1;
|
||||
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(mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual);
|
||||
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(mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
result = FSSetForkPosition(mForkRefNum, fsFromMark, ssndData.offset);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition")
|
||||
|
||||
// Data size
|
||||
outFileDataSize = chunk.ckSize - ssndData.offset;
|
||||
|
||||
// File format
|
||||
mFileDescription.mSampleRate = 44100;
|
||||
mFileDescription.mFormatID = kAudioFormatLinearPCM;
|
||||
mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
|
||||
mFileDescription.mBytesPerPacket = 4;
|
||||
mFileDescription.mFramesPerPacket = 1;
|
||||
mFileDescription.mBytesPerFrame = 4;
|
||||
mFileDescription.mChannelsPerFrame = 2;
|
||||
mFileDescription.mBitsPerChannel = 16;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <AudioToolbox/AudioConverter.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
#include "SDL_error.h"
|
||||
|
|
@ -97,12 +97,9 @@ public:
|
|||
#if DEBUG
|
||||
void Print() const
|
||||
{
|
||||
CAShow (mAudioFileID);
|
||||
printf ("Destination Bus:%ld\n", GetBusNumber());
|
||||
printf ("Is 'aunt' unit:%s\n", (mIsAUNTUnit ? "true" : "false"));
|
||||
printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false"));
|
||||
if (mConverter) CAShow (mConverter);
|
||||
printf ("- - - - - - - - - - - - - - \n");
|
||||
printf ("- - - - - - - - - - - - - - \n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -111,14 +108,13 @@ public:
|
|||
private:
|
||||
AudioUnit mPlayUnit;
|
||||
UInt32 mBusNumber;
|
||||
AudioFileID mAudioFileID;
|
||||
SInt16 mForkRefNum;
|
||||
|
||||
AudioUnitInputCallback mInputCallback;
|
||||
|
||||
AudioStreamBasicDescription mFileDescription;
|
||||
|
||||
bool mConnected;
|
||||
bool mIsAUNTUnit;
|
||||
|
||||
AudioFileManager* mAudioFileManager;
|
||||
AudioConverterRef mConverter;
|
||||
|
|
@ -137,14 +133,12 @@ private:
|
|||
class AudioFileManager
|
||||
{
|
||||
public:
|
||||
AudioFileManager (AudioFilePlayer& inParent, AudioFileID inFile)
|
||||
: mParent (inParent),
|
||||
mAudioFileID (inFile),
|
||||
mFileBuffer (0),
|
||||
mByteCounter (0)
|
||||
{}
|
||||
AudioFileManager (AudioFilePlayer &inParent,
|
||||
SInt16 inForkRefNum,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize);
|
||||
|
||||
virtual ~AudioFileManager();
|
||||
~AudioFileManager();
|
||||
|
||||
|
||||
void Connect (AudioConverterRef inConverter)
|
||||
|
|
@ -155,36 +149,51 @@ public:
|
|||
|
||||
// this method should NOT be called by an object of this class
|
||||
// as it is called by the parent's Disconnect() method
|
||||
virtual void Disconnect () {}
|
||||
void Disconnect ();
|
||||
|
||||
const AudioFileID& GetFileID() const { return mAudioFileID; }
|
||||
OSStatus Read(char *buffer, UInt32 *len);
|
||||
|
||||
const char* GetFileBuffer () { return mFileBuffer; }
|
||||
|
||||
const AudioFilePlayer& GetParent () const { return mParent; }
|
||||
|
||||
virtual void SetPosition (SInt64 pos) = 0; // seek/rewind in the file
|
||||
void SetPosition (SInt64 pos); // seek/rewind in the file
|
||||
|
||||
virtual int GetByteCounter () { return mByteCounter; } // return actual bytes streamed to audio hardware
|
||||
int GetByteCounter () { return mByteCounter; } // return actual bytes streamed to audio hardware
|
||||
|
||||
virtual void SetEndOfFile (SInt64 pos) = 0; // set the "EOF" (will behave just like it reached eof)
|
||||
void SetEndOfFile (SInt64 pos); // set the "EOF" (will behave just like it reached eof)
|
||||
|
||||
protected:
|
||||
AudioFilePlayer& mParent;
|
||||
AudioConverterRef mParentConverter;
|
||||
const AudioFileID mAudioFileID;
|
||||
AudioFilePlayer& mParent;
|
||||
AudioConverterRef mParentConverter;
|
||||
SInt16 mForkRefNum;
|
||||
SInt64 mAudioDataOffset;
|
||||
|
||||
char* mFileBuffer;
|
||||
char* mFileBuffer;
|
||||
|
||||
int mByteCounter;
|
||||
|
||||
bool mReadFromFirstBuffer;
|
||||
bool mLockUnsuccessful;
|
||||
bool mIsEngaged;
|
||||
|
||||
int mNumTimesAskedSinceFinished;
|
||||
|
||||
public:
|
||||
const UInt32 mChunkSize;
|
||||
SInt64 mFileLength;
|
||||
SInt64 mReadFilePosition;
|
||||
bool mWriteToFirstBuffer;
|
||||
bool mFinishedReadingData;
|
||||
|
||||
protected:
|
||||
OSStatus Render (AudioBuffer &ioData);
|
||||
|
||||
int mByteCounter;
|
||||
|
||||
virtual OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize) = 0;
|
||||
OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize);
|
||||
|
||||
virtual void DoConnect () = 0;
|
||||
void DoConnect ();
|
||||
|
||||
virtual void AfterRender () = 0;
|
||||
void AfterRender ();
|
||||
|
||||
public:
|
||||
static OSStatus FileInputProc (void *inRefCon,
|
||||
|
|
@ -199,42 +208,4 @@ public:
|
|||
};
|
||||
|
||||
|
||||
#pragma mark __________ AudioFileReaderThread
|
||||
class AudioFileReaderThread
|
||||
: public AudioFileManager
|
||||
{
|
||||
public:
|
||||
const UInt32 mChunkSize;
|
||||
SInt64 mFileLength;
|
||||
SInt64 mReadFilePosition;
|
||||
bool mWriteToFirstBuffer;
|
||||
bool mFinishedReadingData;
|
||||
|
||||
AudioFileReaderThread (AudioFilePlayer &inParent,
|
||||
AudioFileID &inFile,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize);
|
||||
|
||||
virtual void Disconnect ();
|
||||
|
||||
virtual void SetPosition (SInt64 pos); // seek/rewind in the file
|
||||
|
||||
virtual void SetEndOfFile (SInt64 pos); // set the "EOF" (will behave just like it reached eof)
|
||||
|
||||
protected:
|
||||
virtual void DoConnect ();
|
||||
|
||||
virtual OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize);
|
||||
|
||||
virtual void AfterRender ();
|
||||
|
||||
private:
|
||||
bool mReadFromFirstBuffer;
|
||||
bool mLockUnsuccessful;
|
||||
bool mIsEngaged;
|
||||
|
||||
int mNumTimesAskedSinceFinished;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
*/
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AudioFileReaderThread.cpp
|
||||
// AudioFileManager.cpp
|
||||
//
|
||||
#include "AudioFilePlayer.h"
|
||||
#include <mach/mach.h> //used for setting policy of thread
|
||||
|
|
@ -35,115 +35,110 @@
|
|||
|
||||
class FileReaderThread {
|
||||
public:
|
||||
FileReaderThread ();
|
||||
FileReaderThread ();
|
||||
|
||||
CAGuard& GetGuard() { return mGuard; }
|
||||
CAGuard& GetGuard() { return mGuard; }
|
||||
|
||||
void AddReader();
|
||||
|
||||
void RemoveReader (const AudioFileReaderThread* inItem);
|
||||
|
||||
// returns true if succeeded
|
||||
bool TryNextRead (AudioFileReaderThread* inItem)
|
||||
{
|
||||
bool didLock = false;
|
||||
bool succeeded = false;
|
||||
if (mGuard.Try (didLock))
|
||||
{
|
||||
mFileData.push_back (inItem);
|
||||
mGuard.Notify();
|
||||
succeeded = true;
|
||||
void AddReader();
|
||||
|
||||
void RemoveReader (AudioFileManager* inItem);
|
||||
|
||||
// returns true if succeeded
|
||||
bool TryNextRead (AudioFileManager* inItem)
|
||||
{
|
||||
bool didLock = false;
|
||||
bool succeeded = false;
|
||||
if (mGuard.Try (didLock))
|
||||
{
|
||||
mFileData.push_back (inItem);
|
||||
mGuard.Notify();
|
||||
succeeded = true;
|
||||
|
||||
if (didLock)
|
||||
mGuard.Unlock();
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
int mThreadShouldDie;
|
||||
if (didLock)
|
||||
mGuard.Unlock();
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
int mThreadShouldDie;
|
||||
|
||||
private:
|
||||
typedef std::list<AudioFileReaderThread*> FileData;
|
||||
typedef std::list<AudioFileManager*> FileData;
|
||||
|
||||
CAGuard mGuard;
|
||||
UInt32 mThreadPriority;
|
||||
|
||||
int mNumReaders;
|
||||
FileData mFileData;
|
||||
|
||||
|
||||
void ReadNextChunk ();
|
||||
|
||||
void StartFixedPriorityThread ();
|
||||
static UInt32 GetThreadBasePriority (pthread_t inThread);
|
||||
CAGuard mGuard;
|
||||
UInt32 mThreadPriority;
|
||||
|
||||
static void* DiskReaderEntry (void *inRefCon);
|
||||
int mNumReaders;
|
||||
FileData mFileData;
|
||||
|
||||
|
||||
void ReadNextChunk ();
|
||||
|
||||
void StartFixedPriorityThread ();
|
||||
static UInt32 GetThreadBasePriority (pthread_t inThread);
|
||||
|
||||
static void* DiskReaderEntry (void *inRefCon);
|
||||
};
|
||||
|
||||
FileReaderThread::FileReaderThread ()
|
||||
: mThreadPriority (62),
|
||||
mNumReaders (0)
|
||||
: mThreadPriority (62),
|
||||
mNumReaders (0)
|
||||
{
|
||||
}
|
||||
|
||||
void FileReaderThread::AddReader()
|
||||
void FileReaderThread::AddReader()
|
||||
{
|
||||
if (mNumReaders == 0)
|
||||
{
|
||||
mThreadShouldDie = false;
|
||||
|
||||
StartFixedPriorityThread ();
|
||||
}
|
||||
mNumReaders++;
|
||||
}
|
||||
|
||||
void FileReaderThread::RemoveReader (const AudioFileReaderThread* inItem)
|
||||
{
|
||||
if (mNumReaders > 0)
|
||||
{
|
||||
CAGuard::Locker fileReadLock (mGuard);
|
||||
|
||||
for (FileData::iterator iter = mFileData.begin(); iter != mFileData.end(); ++iter)
|
||||
{
|
||||
if ((*iter) == inItem) {
|
||||
mFileData.erase (iter);
|
||||
}
|
||||
}
|
||||
|
||||
if (--mNumReaders == 0) {
|
||||
mThreadShouldDie = true;
|
||||
mGuard.Notify(); // wake up thread so it will quit
|
||||
mGuard.Wait(); // wait for thread to die
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileReaderThread::StartFixedPriorityThread ()
|
||||
{
|
||||
pthread_attr_t theThreadAttrs;
|
||||
pthread_t pThread;
|
||||
|
||||
OSStatus result = pthread_attr_init(&theThreadAttrs);
|
||||
THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")
|
||||
|
||||
result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
|
||||
THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")
|
||||
|
||||
result = pthread_create (&pThread, &theThreadAttrs, DiskReaderEntry, this);
|
||||
THROW_RESULT("pthread_create - Create and start the thread.")
|
||||
|
||||
pthread_attr_destroy(&theThreadAttrs);
|
||||
if (mNumReaders == 0)
|
||||
{
|
||||
mThreadShouldDie = false;
|
||||
|
||||
// we've now created the thread and started it
|
||||
// we'll now set the priority of the thread to the nominated priority
|
||||
// and we'll also make the thread fixed
|
||||
thread_extended_policy_data_t theFixedPolicy;
|
||||
thread_precedence_policy_data_t thePrecedencePolicy;
|
||||
SInt32 relativePriority;
|
||||
StartFixedPriorityThread ();
|
||||
}
|
||||
mNumReaders++;
|
||||
}
|
||||
|
||||
void FileReaderThread::RemoveReader (AudioFileManager* inItem)
|
||||
{
|
||||
if (mNumReaders > 0)
|
||||
{
|
||||
CAGuard::Locker fileReadLock (mGuard);
|
||||
|
||||
mFileData.remove (inItem);
|
||||
|
||||
if (--mNumReaders == 0) {
|
||||
mThreadShouldDie = true;
|
||||
mGuard.Notify(); // wake up thread so it will quit
|
||||
mGuard.Wait(); // wait for thread to die
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileReaderThread::StartFixedPriorityThread ()
|
||||
{
|
||||
pthread_attr_t theThreadAttrs;
|
||||
pthread_t pThread;
|
||||
|
||||
OSStatus result = pthread_attr_init(&theThreadAttrs);
|
||||
THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")
|
||||
|
||||
result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
|
||||
THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")
|
||||
|
||||
result = pthread_create (&pThread, &theThreadAttrs, DiskReaderEntry, this);
|
||||
THROW_RESULT("pthread_create - Create and start the thread.")
|
||||
|
||||
pthread_attr_destroy(&theThreadAttrs);
|
||||
|
||||
// we've now created the thread and started it
|
||||
// we'll now set the priority of the thread to the nominated priority
|
||||
// and we'll also make the thread fixed
|
||||
thread_extended_policy_data_t theFixedPolicy;
|
||||
thread_precedence_policy_data_t thePrecedencePolicy;
|
||||
SInt32 relativePriority;
|
||||
|
||||
// make thread fixed
|
||||
theFixedPolicy.timeshare = false; // set to true for a non-fixed thread
|
||||
theFixedPolicy.timeshare = false; // set to true for a non-fixed thread
|
||||
result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
|
||||
THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")
|
||||
// set priority
|
||||
|
|
@ -155,26 +150,26 @@ void FileReaderThread::StartFixedPriorityThread ()
|
|||
THROW_RESULT("thread_policy - Couldn't set thread priority.")
|
||||
}
|
||||
|
||||
UInt32 FileReaderThread::GetThreadBasePriority (pthread_t inThread)
|
||||
UInt32 FileReaderThread::GetThreadBasePriority (pthread_t inThread)
|
||||
{
|
||||
thread_basic_info_data_t threadInfo;
|
||||
policy_info_data_t thePolicyInfo;
|
||||
unsigned int count;
|
||||
thread_basic_info_data_t threadInfo;
|
||||
policy_info_data_t thePolicyInfo;
|
||||
unsigned int count;
|
||||
|
||||
// get basic info
|
||||
count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count);
|
||||
|
||||
switch (threadInfo.policy) {
|
||||
case POLICY_TIMESHARE:
|
||||
count = POLICY_TIMESHARE_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
|
||||
return thePolicyInfo.ts.base_priority;
|
||||
switch (threadInfo.policy) {
|
||||
case POLICY_TIMESHARE:
|
||||
count = POLICY_TIMESHARE_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
|
||||
return thePolicyInfo.ts.base_priority;
|
||||
break;
|
||||
|
||||
case POLICY_FIFO:
|
||||
count = POLICY_FIFO_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
|
||||
count = POLICY_FIFO_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
|
||||
if (thePolicyInfo.fifo.depressed) {
|
||||
return thePolicyInfo.fifo.depress_priority;
|
||||
} else {
|
||||
|
|
@ -182,225 +177,233 @@ UInt32 FileReaderThread::GetThreadBasePriority (pthread_t inThread)
|
|||
}
|
||||
break;
|
||||
|
||||
case POLICY_RR:
|
||||
count = POLICY_RR_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
|
||||
if (thePolicyInfo.rr.depressed) {
|
||||
case POLICY_RR:
|
||||
count = POLICY_RR_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
|
||||
if (thePolicyInfo.rr.depressed) {
|
||||
return thePolicyInfo.rr.depress_priority;
|
||||
} else {
|
||||
return thePolicyInfo.rr.base_priority;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *FileReaderThread::DiskReaderEntry (void *inRefCon)
|
||||
void *FileReaderThread::DiskReaderEntry (void *inRefCon)
|
||||
{
|
||||
FileReaderThread *This = (FileReaderThread *)inRefCon;
|
||||
This->ReadNextChunk();
|
||||
#if DEBUG
|
||||
printf ("finished with reading file\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
FileReaderThread *This = (FileReaderThread *)inRefCon;
|
||||
This->ReadNextChunk();
|
||||
#if DEBUG
|
||||
printf ("finished with reading file\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FileReaderThread::ReadNextChunk ()
|
||||
void FileReaderThread::ReadNextChunk ()
|
||||
{
|
||||
OSStatus result;
|
||||
UInt32 dataChunkSize;
|
||||
AudioFileReaderThread* theItem = 0;
|
||||
OSStatus result;
|
||||
UInt32 dataChunkSize;
|
||||
AudioFileManager* theItem = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
{ // this is a scoped based lock
|
||||
CAGuard::Locker fileReadLock (mGuard);
|
||||
|
||||
if (this->mThreadShouldDie) {
|
||||
for (;;)
|
||||
{
|
||||
{ // this is a scoped based lock
|
||||
CAGuard::Locker fileReadLock (mGuard);
|
||||
|
||||
if (this->mThreadShouldDie) {
|
||||
|
||||
mGuard.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFileData.empty())
|
||||
{
|
||||
mGuard.Wait();
|
||||
}
|
||||
|
||||
// kill thread
|
||||
if (this->mThreadShouldDie) {
|
||||
|
||||
if (mFileData.empty())
|
||||
{
|
||||
mGuard.Wait();
|
||||
}
|
||||
|
||||
// kill thread
|
||||
if (this->mThreadShouldDie) {
|
||||
|
||||
mGuard.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
theItem = mFileData.front();
|
||||
mFileData.pop_front();
|
||||
}
|
||||
|
||||
if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
|
||||
dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = theItem->mChunkSize;
|
||||
|
||||
// this is the exit condition for the thread
|
||||
if (dataChunkSize == 0) {
|
||||
theItem->mFinishedReadingData = true;
|
||||
continue;
|
||||
}
|
||||
// construct pointer
|
||||
char* writePtr = const_cast<char*>(theItem->GetFileBuffer() +
|
||||
(theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
|
||||
|
||||
theItem = mFileData.front();
|
||||
mFileData.pop_front();
|
||||
}
|
||||
|
||||
if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
|
||||
dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = theItem->mChunkSize;
|
||||
|
||||
// this is the exit condition for the thread
|
||||
if (dataChunkSize == 0) {
|
||||
theItem->mFinishedReadingData = true;
|
||||
continue;
|
||||
}
|
||||
// construct pointer
|
||||
char* writePtr = const_cast<char*>(theItem->GetFileBuffer() +
|
||||
(theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
|
||||
|
||||
/*
|
||||
printf ("AudioFileReadBytes: theItem=%.8X fileID=%.8X pos=%.8X sz=%.8X flen=%.8X ptr=%.8X\n",
|
||||
(unsigned int)theItem, (unsigned int)theItem->GetFileID(),
|
||||
(unsigned int)theItem->mReadFilePosition, (unsigned int)dataChunkSize,
|
||||
(unsigned int)theItem->mFileLength, (unsigned int)writePtr);
|
||||
*/
|
||||
result = AudioFileReadBytes (theItem->GetFileID(),
|
||||
false,
|
||||
theItem->mReadFilePosition,
|
||||
&dataChunkSize,
|
||||
writePtr);
|
||||
if (result) {
|
||||
theItem->GetParent().DoNotification(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataChunkSize != theItem->mChunkSize)
|
||||
{
|
||||
writePtr += dataChunkSize;
|
||||
result = theItem->Read(writePtr, &dataChunkSize);
|
||||
if (result) {
|
||||
theItem->GetParent().DoNotification(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataChunkSize != theItem->mChunkSize)
|
||||
{
|
||||
writePtr += dataChunkSize;
|
||||
|
||||
// can't exit yet.. we still have to pass the partial buffer back
|
||||
memset (writePtr, 0, (theItem->mChunkSize - dataChunkSize));
|
||||
}
|
||||
|
||||
theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; // switch buffers
|
||||
|
||||
theItem->mReadFilePosition += dataChunkSize; // increment count
|
||||
}
|
||||
|
||||
theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; // switch buffers
|
||||
|
||||
theItem->mReadFilePosition += dataChunkSize; // increment count
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FileReaderThread sReaderThread;
|
||||
|
||||
AudioFileReaderThread::AudioFileReaderThread (AudioFilePlayer &inParent,
|
||||
AudioFileID &inFile,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize)
|
||||
: AudioFileManager (inParent, inFile),
|
||||
mChunkSize (inChunkSize),
|
||||
mFileLength (inFileLength),
|
||||
mReadFilePosition (0),
|
||||
mWriteToFirstBuffer (false),
|
||||
mFinishedReadingData (false),
|
||||
AudioFileManager::AudioFileManager (AudioFilePlayer &inParent,
|
||||
SInt16 inForkRefNum,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize)
|
||||
: mParent (inParent),
|
||||
mForkRefNum (inForkRefNum),
|
||||
mFileBuffer (0),
|
||||
mByteCounter (0),
|
||||
mLockUnsuccessful (false),
|
||||
mIsEngaged (false),
|
||||
|
||||
mChunkSize (inChunkSize),
|
||||
mFileLength (inFileLength),
|
||||
mReadFilePosition (0),
|
||||
mWriteToFirstBuffer (false),
|
||||
mFinishedReadingData (false)
|
||||
|
||||
mLockUnsuccessful (false),
|
||||
mIsEngaged (false)
|
||||
{
|
||||
mFileBuffer = (char*) malloc (mChunkSize * 2);
|
||||
mFileBuffer = (char*) malloc (mChunkSize * 2);
|
||||
FSGetForkPosition(mForkRefNum, &mAudioDataOffset);
|
||||
assert (mFileBuffer != NULL);
|
||||
}
|
||||
|
||||
void AudioFileReaderThread::DoConnect ()
|
||||
void AudioFileManager::DoConnect ()
|
||||
{
|
||||
if (!mIsEngaged)
|
||||
{
|
||||
//mReadFilePosition = 0;
|
||||
mFinishedReadingData = false;
|
||||
if (!mIsEngaged)
|
||||
{
|
||||
//mReadFilePosition = 0;
|
||||
mFinishedReadingData = false;
|
||||
|
||||
mNumTimesAskedSinceFinished = -1;
|
||||
mLockUnsuccessful = false;
|
||||
|
||||
UInt32 dataChunkSize;
|
||||
mNumTimesAskedSinceFinished = -1;
|
||||
mLockUnsuccessful = false;
|
||||
|
||||
OSStatus result;
|
||||
UInt32 dataChunkSize;
|
||||
|
||||
if ((mFileLength - mReadFilePosition) < mChunkSize)
|
||||
dataChunkSize = mFileLength - mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = mChunkSize;
|
||||
dataChunkSize = mFileLength - mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = mChunkSize;
|
||||
|
||||
OSStatus result = AudioFileReadBytes ( mAudioFileID,
|
||||
false,
|
||||
mReadFilePosition,
|
||||
&dataChunkSize,
|
||||
mFileBuffer);
|
||||
THROW_RESULT("AudioFileReadBytes")
|
||||
|
||||
mReadFilePosition += dataChunkSize;
|
||||
|
||||
mWriteToFirstBuffer = false;
|
||||
mReadFromFirstBuffer = true;
|
||||
result = Read(mFileBuffer, &dataChunkSize);
|
||||
THROW_RESULT("AudioFileManager::DoConnect(): Read")
|
||||
|
||||
sReaderThread.AddReader();
|
||||
|
||||
mIsEngaged = true;
|
||||
}
|
||||
else
|
||||
throw static_cast<OSStatus>(-1); //thread has already been started
|
||||
mReadFilePosition += dataChunkSize;
|
||||
|
||||
mWriteToFirstBuffer = false;
|
||||
mReadFromFirstBuffer = true;
|
||||
|
||||
sReaderThread.AddReader();
|
||||
|
||||
mIsEngaged = true;
|
||||
}
|
||||
else
|
||||
throw static_cast<OSStatus>(-1); //thread has already been started
|
||||
}
|
||||
|
||||
void AudioFileReaderThread::Disconnect ()
|
||||
void AudioFileManager::Disconnect ()
|
||||
{
|
||||
if (mIsEngaged)
|
||||
{
|
||||
sReaderThread.RemoveReader (this);
|
||||
mIsEngaged = false;
|
||||
}
|
||||
if (mIsEngaged)
|
||||
{
|
||||
sReaderThread.RemoveReader (this);
|
||||
mIsEngaged = false;
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus AudioFileReaderThread::GetFileData (void** inOutData, UInt32 *inOutDataSize)
|
||||
OSStatus AudioFileManager::Read(char *buffer, UInt32 *len)
|
||||
{
|
||||
if (mFinishedReadingData)
|
||||
{
|
||||
++mNumTimesAskedSinceFinished;
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
if (mReadFromFirstBuffer == mWriteToFirstBuffer) {
|
||||
#if DEBUG
|
||||
printf ("* * * * * * * Can't keep up with reading file:%ld\n", mParent.GetBusNumber());
|
||||
#endif
|
||||
|
||||
mParent.DoNotification (kAudioFilePlayErr_FilePlayUnderrun);
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
} else {
|
||||
*inOutDataSize = mChunkSize;
|
||||
*inOutData = mReadFromFirstBuffer ? mFileBuffer : (mFileBuffer + mChunkSize);
|
||||
}
|
||||
|
||||
mLockUnsuccessful = !sReaderThread.TryNextRead (this);
|
||||
|
||||
mReadFromFirstBuffer = !mReadFromFirstBuffer;
|
||||
|
||||
return noErr;
|
||||
return FSReadFork (mForkRefNum,
|
||||
fsFromStart,
|
||||
mReadFilePosition + mAudioDataOffset,
|
||||
*len,
|
||||
buffer,
|
||||
len);
|
||||
}
|
||||
|
||||
void AudioFileReaderThread::AfterRender ()
|
||||
OSStatus AudioFileManager::GetFileData (void** inOutData, UInt32 *inOutDataSize)
|
||||
{
|
||||
if (mNumTimesAskedSinceFinished > 0)
|
||||
{
|
||||
bool didLock = false;
|
||||
if (sReaderThread.GetGuard().Try (didLock)) {
|
||||
mParent.DoNotification (kAudioFilePlay_FileIsFinished);
|
||||
if (didLock)
|
||||
sReaderThread.GetGuard().Unlock();
|
||||
}
|
||||
}
|
||||
if (mFinishedReadingData)
|
||||
{
|
||||
++mNumTimesAskedSinceFinished;
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
if (mReadFromFirstBuffer == mWriteToFirstBuffer) {
|
||||
#if DEBUG
|
||||
printf ("* * * * * * * Can't keep up with reading file:%ld\n", mParent.GetBusNumber());
|
||||
#endif
|
||||
|
||||
mParent.DoNotification (kAudioFilePlayErr_FilePlayUnderrun);
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
} else {
|
||||
*inOutDataSize = mChunkSize;
|
||||
*inOutData = mReadFromFirstBuffer ? mFileBuffer : (mFileBuffer + mChunkSize);
|
||||
}
|
||||
|
||||
if (mLockUnsuccessful)
|
||||
mLockUnsuccessful = !sReaderThread.TryNextRead (this);
|
||||
mLockUnsuccessful = !sReaderThread.TryNextRead (this);
|
||||
|
||||
mReadFromFirstBuffer = !mReadFromFirstBuffer;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void AudioFileReaderThread::SetPosition (SInt64 pos)
|
||||
void AudioFileManager::AfterRender ()
|
||||
{
|
||||
if (mNumTimesAskedSinceFinished > 0)
|
||||
{
|
||||
bool didLock = false;
|
||||
if (sReaderThread.GetGuard().Try (didLock)) {
|
||||
mParent.DoNotification (kAudioFilePlay_FileIsFinished);
|
||||
if (didLock)
|
||||
sReaderThread.GetGuard().Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (mLockUnsuccessful)
|
||||
mLockUnsuccessful = !sReaderThread.TryNextRead (this);
|
||||
}
|
||||
|
||||
void AudioFileManager::SetPosition (SInt64 pos)
|
||||
{
|
||||
if (pos < 0 || pos >= mFileLength) {
|
||||
SDL_SetError ("AudioFileReaderThread::SetPosition - position invalid: %d filelen=%d\n",
|
||||
SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n",
|
||||
(unsigned int)pos, (unsigned int)mFileLength);
|
||||
pos = 0;
|
||||
}
|
||||
|
|
@ -408,10 +411,10 @@ void AudioFileReaderThread::SetPosition (SInt64 pos)
|
|||
mReadFilePosition = pos;
|
||||
}
|
||||
|
||||
void AudioFileReaderThread::SetEndOfFile (SInt64 pos)
|
||||
void AudioFileManager::SetEndOfFile (SInt64 pos)
|
||||
{
|
||||
if (pos <= 0 || pos > mFileLength) {
|
||||
SDL_SetError ("AudioFileReaderThread::SetEndOfFile - position beyond actual eof\n");
|
||||
SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
|
||||
pos = mFileLength;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#define NDEBUG 1
|
||||
//#define NDEBUG 1
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -114,9 +114,7 @@ int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes)
|
|||
for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++)
|
||||
{
|
||||
FSVolumeRefNum actualVolume;
|
||||
HFSUniStr255 volumeName;
|
||||
FSVolumeInfo volumeInfo;
|
||||
FSRef rootDirectory;
|
||||
|
||||
memset (&volumeInfo, 0, sizeof(volumeInfo));
|
||||
|
||||
|
|
@ -125,13 +123,13 @@ int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes)
|
|||
&actualVolume,
|
||||
kFSVolInfoFSInfo,
|
||||
&volumeInfo,
|
||||
&volumeName,
|
||||
&rootDirectory);
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (result == noErr)
|
||||
{
|
||||
if (volumeInfo.filesystemID == kAudioCDFilesystemID) // It's an audio CD
|
||||
{
|
||||
{
|
||||
if (volumes != NULL && cdVolumeCount < numVolumes)
|
||||
volumes[cdVolumeCount] = actualVolume;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
#include "SDL.h"
|
||||
|
|
|
|||
|
|
@ -265,19 +265,25 @@ void SDL_SYS_CDQuit(void)
|
|||
/* Get the Unix disk name of the volume */
|
||||
static const char *SDL_SYS_CDName (int drive)
|
||||
{
|
||||
CFStringRef diskID;
|
||||
OSStatus err = noErr;
|
||||
|
||||
HParamBlockRec pb;
|
||||
GetVolParmsInfoBuffer volParmsInfo;
|
||||
|
||||
if (fakeCD)
|
||||
return "Fake CD-ROM Device";
|
||||
|
||||
err = FSCopyDiskIDForVolume (volumes[drive], &diskID);
|
||||
|
||||
pb.ioParam.ioNamePtr = NULL;
|
||||
pb.ioParam.ioVRefNum = volumes[drive];
|
||||
pb.ioParam.ioBuffer = (Ptr)&volParmsInfo;
|
||||
pb.ioParam.ioReqCount = (SInt32)sizeof(volParmsInfo);
|
||||
err = PBHGetVolParmsSync(&pb);
|
||||
|
||||
if (err != noErr) {
|
||||
SDL_SetError ("FSCopyDiskIDForVolume returned %d", err);
|
||||
SDL_SetError ("PBHGetVolParmsSync returned %d", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return CFStringGetCStringPtr (diskID, 0);
|
||||
|
||||
return volParmsInfo.vMDeviceID;
|
||||
}
|
||||
|
||||
/* Open the "device" */
|
||||
|
|
@ -318,14 +324,15 @@ static int SDL_SYS_CDGetTOC (SDL_CD *cdrom)
|
|||
/* Get CD-ROM status */
|
||||
static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position)
|
||||
{
|
||||
int trackFrame;
|
||||
if (position) {
|
||||
int trackFrame;
|
||||
|
||||
Lock ();
|
||||
trackFrame = GetCurrentFrame ();
|
||||
Unlock ();
|
||||
|
||||
Lock ();
|
||||
trackFrame = GetCurrentFrame ();
|
||||
Unlock ();
|
||||
|
||||
if (position)
|
||||
*position = cdrom->track[currentTrack].offset + trackFrame;
|
||||
*position = cdrom->track[currentTrack].offset + trackFrame;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -383,8 +390,10 @@ static int SDL_SYS_CDPause(SDL_CD *cdrom)
|
|||
|
||||
Lock ();
|
||||
|
||||
if (PauseFile () < 0)
|
||||
if (PauseFile () < 0) {
|
||||
Unlock ();
|
||||
return -2;
|
||||
}
|
||||
|
||||
status = CD_PAUSED;
|
||||
|
||||
|
|
@ -403,8 +412,10 @@ static int SDL_SYS_CDResume(SDL_CD *cdrom)
|
|||
|
||||
Lock ();
|
||||
|
||||
if (PlayFile () < 0)
|
||||
if (PauseFile () < 0) {
|
||||
Unlock ();
|
||||
return -2;
|
||||
}
|
||||
|
||||
status = CD_PLAYING;
|
||||
|
||||
|
|
@ -423,11 +434,15 @@ static int SDL_SYS_CDStop(SDL_CD *cdrom)
|
|||
|
||||
Lock ();
|
||||
|
||||
if (PauseFile () < 0)
|
||||
if (PauseFile () < 0) {
|
||||
Unlock ();
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ReleaseFile () < 0)
|
||||
if (ReleaseFile () < 0) {
|
||||
Unlock ();
|
||||
return -3;
|
||||
}
|
||||
|
||||
status = CD_STOPPED;
|
||||
|
||||
|
|
@ -440,6 +455,7 @@ static int SDL_SYS_CDStop(SDL_CD *cdrom)
|
|||
static int SDL_SYS_CDEject(SDL_CD *cdrom)
|
||||
{
|
||||
OSStatus err;
|
||||
HParamBlockRec pb;
|
||||
|
||||
if (fakeCD) {
|
||||
SDL_SetError (kErrorFakeDevice);
|
||||
|
|
@ -448,20 +464,28 @@ static int SDL_SYS_CDEject(SDL_CD *cdrom)
|
|||
|
||||
Lock ();
|
||||
|
||||
if (PauseFile () < 0)
|
||||
if (PauseFile () < 0) {
|
||||
Unlock ();
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ReleaseFile () < 0)
|
||||
if (ReleaseFile () < 0) {
|
||||
Unlock ();
|
||||
return -3;
|
||||
}
|
||||
|
||||
status = CD_STOPPED;
|
||||
|
||||
err = FSEjectVolumeSync (volumes[cdrom->id], 0, NULL);
|
||||
|
||||
if (err != noErr) {
|
||||
SDL_SetError ("FSEjectVolumeSync returned %d", err);
|
||||
return -4;
|
||||
}
|
||||
// Eject the volume
|
||||
pb.ioParam.ioNamePtr = NULL;
|
||||
pb.ioParam.ioVRefNum = volumes[cdrom->id];
|
||||
err = PBUnmountVol((ParamBlockRec *) &pb);
|
||||
|
||||
if (err != noErr) {
|
||||
Unlock ();
|
||||
SDL_SetError ("PBUnmountVol returned %d", err);
|
||||
return -4;
|
||||
}
|
||||
|
||||
status = CD_TRAYEMPTY;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
/* This is the Mac OS X / CoreAudio specific header for the SDL CD-ROM API
|
||||
Contributed by Darrell Walisser and Max Horn
|
||||
*/
|
||||
|
||||
/***********************************************************************************
|
||||
Implementation Notes
|
||||
|
|
|
|||
|
|
@ -1365,7 +1365,7 @@ static void QZ_DrawResizeIcon (_THIS, RgnHandle dirtyRegion) {
|
|||
SDL_RWops *rw;
|
||||
SDL_Surface *tmp;
|
||||
|
||||
rw = SDL_RWFromMem (QZ_ResizeIcon, sizeof(QZ_ResizeIcon));
|
||||
rw = SDL_RWFromConstMem (QZ_ResizeIcon, sizeof(QZ_ResizeIcon));
|
||||
tmp = SDL_LoadBMP_RW (rw, SDL_TRUE);
|
||||
|
||||
resize_icon = SDL_ConvertSurface (tmp, SDL_VideoSurface->format, SDL_SRCCOLORKEY);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user