Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
_source/DoubleBufferFromFile.c
/* |
File: DoubleBufferFromFile.c |
Contains: Routines demonstrating how to play a sound from disk using SndPlayDoubleBuffer. |
Written by: Mark Cookson |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
8/31/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include "MyAIFF.h" |
#include "DoubleBufferFromFile.h" |
/* Purpose: This creates a new SoundInfo structure and initializes |
it by calling the private function ASoundInit. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
SoundInfoPtr ASoundNew (OSErr *theErr) |
/*-----------------------------------------------------------------------*/ |
{ |
SoundInfoPtr theSoundInfo = nil; |
*theErr = noErr; |
theSoundInfo = (SoundInfoPtr)NewPtrClear (sizeof (SoundInfo)); |
if (MemError () != noErr || theSoundInfo == nil) { |
*theErr = kInitErr; |
} |
else { |
*theErr = ASoundInit (theSoundInfo); |
} |
if (*theErr != noErr) { |
DebugPrint ("\pError in ASoundNew"); |
} |
return theSoundInfo; |
} |
/* |
Purpose: Display a StandardFile dialog to select a file. |
Opens the file selected by the user. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundGetFileToPlay (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
FileFilterUPP myFilterUPP = nil; |
OSErr theErr = noErr; |
short i = 0; |
Boolean good = false; |
if (IsValid (theSoundInfo)) { |
myFilterUPP = NewFileFilterProc (ASoundFileFilter); |
if ((theSoundInfo->globals.ggestaltStandardFileAttr & gestaltStandardFile58) == false) { |
StandardFileReply theSFReply; |
short showTypes; |
if ((theSoundInfo->globals.ggestaltTranslationAttr & (1 << gestaltTranslationMgrExists)) == true) { |
showTypes = kUseOpenResourceTypes; |
} |
else { |
showTypes = kNoFirstFiltering; |
} |
StandardGetFile (myFilterUPP, showTypes, nil, &theSFReply); |
theSoundInfo->vRefNum = theSFReply.sfFile.vRefNum; |
if (theSFReply.sfGood == true) { |
switch (theSFReply.sfType) { |
case kSNDResource: |
case kResource: |
theErr = FSpOpenRF (&theSFReply.sfFile, fsCurPerm, &(theSoundInfo->refNum)); |
break; |
case kCompressedAIFFFile: |
case kUncompressedAIFFFile: |
case kWAVEFile: |
case kWAVFile: |
case kAUFile: |
theErr = FSpOpenDF (&theSFReply.sfFile, fsCurPerm, &(theSoundInfo->refNum)); |
break; |
default: |
DebugPrint ("\pASoundGetFileToPlay should have never executed this line"); |
} |
if (theErr != noErr) { |
DebugPrint ("\pCouldn't open file"); |
} |
else { |
theSoundInfo->fileType = theSFReply.sfType; |
for (i = 0; i <= theSFReply.sfFile.name[0]+1; i++) |
theSoundInfo->theName[i] = theSFReply.sfFile.name[i]; |
} |
} |
else { |
theErr = userCanceledErr; |
} |
} |
else { |
SFReply theSFReply; |
Point where = {kInit, kInit}; |
Rect screenRect = GetMainScreenRect(); |
long dirID = kInit, |
procID = kInit; |
where.h = screenRect.right / kHorizAdjust; /* This will put the SFGetFile dialog in the same place */ |
where.v = screenRect.bottom / kVertAdjust; /* as the StandardGetFile dialog (or really close). */ |
if ((GetMBarHeight() + kOne) > where.h) { |
where.h = GetMBarHeight() + kOne; |
} |
SFGetFile (where, nil, myFilterUPP, kNoFirstFiltering, nil, nil, &theSFReply); |
good = theSFReply.good; |
if (theSFReply.good == true) { |
theErr = GetWDInfo (theSFReply.vRefNum, &(theSoundInfo->vRefNum), &dirID, &procID); |
if (theErr == noErr) { |
switch (theSFReply.fType) { |
case kSNDResource: |
case kResource: |
theErr = HOpenRF (theSoundInfo->vRefNum, dirID, theSFReply.fName, fsCurPerm, &(theSoundInfo->refNum)); |
break; |
case kCompressedAIFFFile: |
case kUncompressedAIFFFile: |
case kWAVEFile: |
case kWAVFile: |
case kAUFile: |
theErr = HOpenDF (theSoundInfo->vRefNum, dirID, theSFReply.fName, fsCurPerm, &(theSoundInfo->refNum)); |
break; |
default: |
DebugPrint ("\pASoundGetFileToPlay should have never executed this line"); |
} |
if (theErr != noErr) { |
DebugPrint ("\pCouldn't open file"); |
} |
else { |
theSoundInfo->fileType = theSFReply.fType; |
for (i = 0; i <= theSFReply.fName[0]+1; i++) |
theSoundInfo->theName[i] = theSFReply.fName[i]; |
} |
} |
else { |
theErr = kFileErr; |
DebugPrint ("\pCouldn't translate working directory"); |
} |
} |
else { |
theErr = userCanceledErr; |
} |
} |
DisposeRoutineDescriptor (myFilterUPP); |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr && theErr != userCanceledErr) { |
DebugPrint ("\pError in ASoundGetFileToPlay"); |
} |
return theErr; |
} |
/* |
Purpose: Checks a file to see if its header can be parsed |
and the file can be played. |
This will return an error if the sound will not play, |
returning noErr means that sound will play. |
Parsing a header can take some time, this routine |
is a canidate for speed improvements. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundCanThisPlay (CInfoPBPtr theFileInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
SoundInfoPtr theSoundInfo = nil; |
long dataStart = kInit, |
sndLength = kInit; |
OSErr theErr = noErr, |
closeErr = noErr; |
if (theFileInfo != nil) { |
theSoundInfo = ASoundNew (&theErr); |
if (theErr == noErr) { |
theSoundInfo->vRefNum = theFileInfo->hFileInfo.ioVRefNum; |
theSoundInfo->fileType = theFileInfo->hFileInfo.ioFlFndrInfo.fdType; |
theErr = HOpenDF (theFileInfo->hFileInfo.ioVRefNum, theFileInfo->hFileInfo.ioFlParID, theFileInfo->hFileInfo.ioNamePtr, fsRdPerm, &theSoundInfo->refNum); |
if (theErr == noErr) { |
switch (theSoundInfo->fileType) { |
case kCompressedAIFFFile: |
case kUncompressedAIFFFile: |
theErr = ASoundGetAIFFHeader (theSoundInfo, &dataStart, &sndLength); |
break; |
case kWAVEFile: |
case kWAVFile: |
theErr = ASoundGetWAVEHeader (theSoundInfo, &dataStart, &sndLength); |
break; |
case kAUFile: |
theErr = ASoundGetULAWHeader (theSoundInfo, &dataStart, &sndLength); |
break; |
case kSNDResource: |
case kResource: |
theErr = noErr; |
break; |
default: |
/* The file type is not one that we can even parse. */ |
theErr = kUnknownFormat; |
break; |
} |
} |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
closeErr = FSClose (theSoundInfo->refNum); |
DisposeRoutineDescriptor (ASoundGetSoundCallBack (theSoundInfo)); |
DisposePtr ((Ptr)theSoundInfo); |
if (closeErr != noErr) { |
theErr = closeErr; |
} |
if (theErr != noErr && theErr != kUnknownFormat) { |
DebugPrint ("\pError in ASoundCanThisPlay"); |
} |
return theErr; |
} |
/* |
Purpose: This function is called to get ready to play a sound. |
Use this if you want to make sure that there is enough |
memory to play the sound. |
Side Effects: This will call routines that will allocate memory needed |
to all of the various structures needed by the Sound Manager |
and memory to be used as the sounds' buffers. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundReadyForPlaying (SoundInfoPtr theSoundInfo, |
unsigned long bufferSize) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
if (theSoundInfo->globals.gSupportsSPDB == false) { |
DebugPrint ("\pThis machine doesn't support SoundPlayDoubleBuffer, can't play!"); |
theErr = kNoSPDBErr; |
} |
else { |
/* do we want to start at the begining of the file? */ |
if ((ASoundGetBytesCopied (theSoundInfo) <= kMaxAIFFHeaderSize) && theSoundInfo->paused == false) { |
theSoundInfo->soundDone = false; |
theErr = SndNewChannel (&(theSoundInfo->chan), sampledSynth, nil, ASoundGetSoundCallBack (theSoundInfo)); |
if (theErr != noErr) { |
DebugPrint ("\pSndNewChannel error!"); |
} |
else { |
theErr = SetUpSoundHeader (theSoundInfo, bufferSize); |
if (theErr == noErr) { |
theErr = ASoundPrimeBuffers (theSoundInfo); |
ASoundSetCurBuffer (theSoundInfo, kStart); |
} |
} |
} |
else { |
theErr = ASoundPrimeBuffers (theSoundInfo); |
} |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundReadyForPlaying!"); |
(void)ASoundDonePlaying (theSoundInfo, kCloseFile + kFreeMem); |
} |
return theErr; |
} |
/* |
Purpose: Call this after you have called ASoundReadyForPlaying to |
start playing the sound you prepaired. |
Side Effects: Starts the sound playing. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundPlay (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
if (theSoundInfo->playing == false || theSoundInfo->paused == true) { |
if (theSoundInfo->globals.gSupportsSPDB == false) { |
theErr = kNoSPDBErr; |
DebugPrint ("\pThis machine doesn't support SoundPlayDoubleBuffer, can't play!"); |
} |
else { |
if (theSoundInfo->paused == false) { |
theErr = SndPlayDoubleBuffer (theSoundInfo->chan, (SndDoubleBufferHeaderPtr)&(theSoundInfo->doubleHeader)); |
if (theErr == noErr) { |
theErr = InstallCallBack (theSoundInfo); |
} |
if (theErr == noErr) { |
theSoundInfo->playing = true; |
} |
} |
} |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundPlay!"); |
(void)ASoundDonePlaying (theSoundInfo, kCloseFile + kFreeMem); |
} |
return theErr; |
} |
/* |
Purpose: Wrapper function called to start playing a sound. |
Use this if you are pretty sure the sound will play, or |
just don't care specifically what goes wrong. |
Side Effects: This will call routines that will allocate memory needed |
for all of the various structures needed by the Sound Manager |
and memory to be used as the sounds' buffers. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundStartPlaying (SoundInfoPtr theSoundInfo, |
unsigned long bufferSize) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
theErr = ASoundReadyForPlaying (theSoundInfo, bufferSize); |
if (theErr == noErr) { |
theErr = ASoundPlay (theSoundInfo); |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundStartPlaying!"); |
(void)ASoundDonePlaying (theSoundInfo, kCloseFile + kFreeMem); |
} |
return theErr; |
} |
/* |
Purpose: Stops the currently playing sound. |
Side Effects: Stopping the currently playing sound will cause the |
sound completion routine to run. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundStop (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCommand theCmd = {quietCmd, kInit, kInit}; |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
/* So that ASoundDoubleBackProc knows that it doesn't have to |
actually read any data */ |
theSoundInfo->stopping = true; |
theErr = SndDoImmediate (theSoundInfo->chan, &theCmd); |
if (theErr == noErr) { |
theSoundInfo->playing = false; |
theSoundInfo->paused = false; |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundStop"); |
} |
return theErr; |
} |
/* |
Purpose: Wrapper so the user doesn't have to keep track of if |
the sound is playing or not. |
Side Effects: If resuming a sound and the user had also called |
ASoundPauseForAdjust this will reinstall the sound |
completion callback. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundPause (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
if (theSoundInfo->paused == false) { |
theErr = PauseSound (theSoundInfo); |
} |
else { |
theErr = ResumeSound (theSoundInfo); |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundPause"); |
} |
return theErr; |
} |
/* |
Purpose: If the sound is paused, resume playing. If the sound is |
playing, pause playing. |
This differs from ASoundPause because it actually stops |
the sound instead of pausing it. When the sound is |
paused for adjusting you can reset where the sound will |
next start playing from without having to play the |
remainder of the current buffer. This routine is used |
for the QuickTime style playing. |
Side Effects: Removes the callback from the sound channel because |
otherwise while adjusting the sound the Sound Manager |
would call our clean up routine. |
When resuming a sound ASoundStartPlaying will install |
our callback routine if necessary (if the sound wasn't |
already paused). |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundPauseForAdjust (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCommand theCmd = {kInit, kInit, kInit}; |
OSErr theErr = noErr; |
static Fixed oldRate = kInit; |
if (StrictIsValid (theSoundInfo)) { |
if (theSoundInfo->adjusting == false) { |
theCmd.cmd = flushCmd; /* so the sound completion callback doesn't get called */ |
theErr = SndDoImmediate (theSoundInfo->chan, &theCmd); |
if (theErr == noErr) { |
theSoundInfo->adjusting = true; |
theCmd.cmd = quietCmd; |
theErr = SndDoImmediate (theSoundInfo->chan, &theCmd); |
if (theErr == noErr) { |
theSoundInfo->hasBeenAdjusted = true; |
theSoundInfo->playing = false; |
} |
} |
} |
else { |
theSoundInfo->adjusting = false; |
ASoundStartPlaying (theSoundInfo, nil); |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundPauseForAdjust"); |
} |
return theErr; |
} |
/* |
Purpose: Sound is done playing, dispose of the memory we no |
longer need. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundDonePlaying (SoundInfoPtr theSoundInfo, |
unsigned long options) |
/*-----------------------------------------------------------------------*/ |
{ |
myParamBlockRec *myPB = nil; |
OSErr theErr = noErr; |
short i = kInit, |
savedVRefNum = kInit, |
savedRefNum = kInit; |
if (IsValid (theSoundInfo)) { |
theSoundInfo->soundDone = false; /* so we don't get called multiple times */ |
theSoundInfo->playing = false; |
savedVRefNum = theSoundInfo->vRefNum; |
savedRefNum = theSoundInfo->refNum; |
if ((options == kCloseFile) || (options > kCloseFile + kFreeMem)) { |
DebugPrint ("\pInvalid selector passed to ASoundDonePlaying"); |
theErr = kBadValue; |
} |
else { |
theSoundInfo->stopping = false; /* Sound is done stopping, hopefully... */ |
if (options > kNoOptions) { |
myPB = (myParamBlockRec*)theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufOne]->dbUserInfo[kPBPtr]; |
if (myPB != nil) { |
if (options == kCloseFile + kFreeMem) { |
theErr = FSClose (myPB->pb.ioParam.ioRefNum); |
} |
if (theErr == noErr) { |
for (i = kInit; i <= kOne; i++) { |
DisposeRoutineDescriptor (((myParamBlockRec*)theSoundInfo->doubleHeader.dbhBufferPtr[i]->dbUserInfo[kPBPtr])->pb.ioParam.ioCompletion); |
DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]->dbUserInfo[kPBPtr]); |
/* Have to unhold memory that was held */ |
UnholdMemory ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i], sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo)); |
DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]); |
} |
} |
else { |
DebugPrint ("\pFSClose error!"); |
} |
theErr = SndDisposeChannel (theSoundInfo->chan, true); |
DisposeRoutineDescriptor (ASoundGetSoundCallBack (theSoundInfo)); |
DisposeRoutineDescriptor (theSoundInfo->doubleHeader.dbhDoubleBack); |
if (theErr != noErr) { |
DebugPrint ("\pSndDisposeChannel error!"); |
} |
} |
} |
if (options == kNoOptions) { |
ASoundSetBytesCopied (theSoundInfo, theSoundInfo->dataStart); |
ASoundSetCurBuffer (theSoundInfo, kStart); |
theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufOne]->dbFlags = nil; |
theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufTwo]->dbFlags = nil; |
theErr = ASoundPrimeBuffers (theSoundInfo); |
} |
if (options == kFreeMem) { |
ASoundInit (theSoundInfo); |
theSoundInfo->vRefNum = savedVRefNum; |
theSoundInfo->refNum = savedRefNum; |
} |
else { |
if (options == kCloseFile + kFreeMem) { |
ASoundInit (theSoundInfo); |
} |
} |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundDonePlaying"); |
} |
return theErr; |
} |
/* |
Purpose: Returns the channel for the sound in case you want to |
send it specific commands. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
SndChannelPtr ASoundGetChan (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
SndChannelPtr returnValue; |
if (StrictIsValid (theSoundInfo)) { |
returnValue = theSoundInfo->chan; |
} else { |
returnValue = nil; |
} |
return returnValue; |
} |
/* |
Purpose: Returns the name of the file containing the currently |
playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundGetSoundName (SoundInfoPtr theSoundInfo, |
Str63 theName) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
short i = 0; |
if (StrictIsValid (theSoundInfo) && theName != nil) { |
/* This should probably be a BlockMoveData */ |
for (i = 0; i <= theSoundInfo->theName[0]+1; i++) |
theName[i] = theSoundInfo->theName[i]; |
} |
return theErr; |
} |
/* |
Purpose: Gets the number of the current buffer |
(in the range 1 to ASoundGetNumBuffers()) of the |
currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
long ASoundGetCurBuffer (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
long returnValue = kInit; |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
returnValue = theSoundInfo->currentBuffer; |
} |
else { |
theErr = kNilPtrErr; |
returnValue = nil; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetCurBuffer"); |
} |
return returnValue; |
} |
/* |
Purpose: Sets which buffer should be the next buffer to play |
from (in the range 1 to ASoundGetNumBuffers()) |
for the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundSetCurBuffer (SoundInfoPtr theSoundInfo, |
long newValue) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
if ((newValue >= kStart) && (newValue <= ASoundGetNumBuffers (theSoundInfo))) { |
theSoundInfo->currentBuffer = newValue; |
ASoundSetBytesCopied (theSoundInfo, newValue * ASoundGetBufferSize (theSoundInfo) + theSoundInfo->dataStart); |
} |
else { |
theErr = kBadRange; |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
return theErr; |
} |
/* |
Purpose: Gets the number of buffers that the currently playing |
sound will need to play in its entirety. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
long ASoundGetNumBuffers (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
long returnValue = kInit; |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
returnValue = theSoundInfo->numBuffers; |
} |
else { |
theErr = kNilPtrErr; |
returnValue = nil; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetNumBuffers"); |
} |
return returnValue; |
} |
/* |
Purpose: Gets the length (in bytes) of the currently playing |
sound. This number does not include any header bytes. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
long ASoundGetNumTotalBytes (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
long returnValue = kInit; |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
returnValue = theSoundInfo->bytesTotal; |
} |
else { |
theErr = kNilPtrErr; |
returnValue = nil; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetNumTotalBytes"); |
} |
return returnValue; |
} |
/* |
Purpose: Gets the number of bytes that will be played by the end |
of the current buffer of the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
long ASoundGetBytesCopied (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
long returnValue = kInit; |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
returnValue = theSoundInfo->bytesCopied; |
} |
else { |
theErr = kNilPtrErr; |
returnValue = nil; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetBytesCopied"); |
} |
return returnValue; |
} |
/* |
Purpose: Sets the location in the file where the next buffer |
should be filled from for the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundSetBytesCopied (SoundInfoPtr theSoundInfo, |
long newValue) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
if (newValue >= theSoundInfo->dataStart || newValue == kInit) { |
theSoundInfo->bytesCopied = newValue; |
} |
else { |
theErr = kBadValue; |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundSetBytesCopied"); |
} |
return theErr; |
} |
/* |
Purpose: Gets the size of a buffer of the currently playing |
sound. Multiply by two to know how much memory is |
reserved for buffering the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
long ASoundGetBufferSize (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
long returnValue = kInit; |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
returnValue = theSoundInfo->doubleBufferSize; |
} |
else { |
theErr = kNilPtrErr; |
returnValue = nil; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetBufferSize"); |
} |
return returnValue; |
} |
/* |
Purpose: Gets the UPP for the function that should be called when |
the currently playing sound finishes. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
SndCallBackUPP ASoundGetSoundCallBack (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCallBackUPP returnValue = nil; |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
returnValue = theSoundInfo->theSoundCallBackUPP; |
} |
else { |
theErr = kNilPtrErr; |
returnValue = nil; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetSoundCallBack"); |
} |
return returnValue; |
} |
/* |
Purpose: Sets the function that should be called when the the |
currently playing sound finishes. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundSetSoundCallBack (SoundInfoPtr theSoundInfo, |
void* newValue) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
if (IsValid (theSoundInfo)) { |
if (theSoundInfo->theSoundCallBackUPP != nil) { |
DisposeRoutineDescriptor (theSoundInfo->theSoundCallBackUPP); |
} |
if (newValue != nil) { |
theSoundInfo->theSoundCallBackUPP = NewSndCallBackProc(newValue); |
} |
else { |
theSoundInfo->theSoundCallBackUPP = NewSndCallBackProc(ASoundDoneCallBack); |
DebugPrint ("\pDid you really want the default sound callback?"); |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundSetSoundCallBack"); |
} |
return theErr; |
} |
/* |
Purpose: Says whether to play the currently playing sound backwards |
(it actually reverses the sound in the buffer). |
Side Effects: Takes effect when the next sound buffer gets filled. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundPlayBackwards (SoundInfoPtr theSoundInfo, |
Boolean newValue) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
theSoundInfo->backwards = newValue; |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundPlayBackwards"); |
} |
return theErr; |
} |
/* |
Purpose: Returns true if the currently playing sound's buffer |
is set to be reversed. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
Boolean ASoundIsBackwards (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
Boolean returnValue = false; |
if (StrictIsValid (theSoundInfo)) { |
returnValue = theSoundInfo->backwards; |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundIsBackwards"); |
} |
return returnValue; |
} |
/* |
Purpose: Returns true if the sound has finished playing. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
Boolean ASoundIsDone (SoundInfoPtr theSoundInfo) |
/*-----------------------------------------------------------------------*/ |
{ |
OSErr theErr = noErr; |
Boolean returnValue = false; |
if (StrictIsValid (theSoundInfo)) { |
returnValue = theSoundInfo->soundDone; |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundIsDone"); |
} |
return returnValue; |
} |
/* |
Purpose: Changes the volume of the currently playing sound. |
The values you pass in are added to the current values. |
Negitive values will decrease the volume, positive values |
will increase the volume. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundChangeVolume (SoundInfoPtr theSoundInfo, |
unsigned short leftVol, |
unsigned short rightVol) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCommand theCmd = {volumeCmd, kInit, kInit}; |
OSErr theErr = noErr; |
unsigned short tempLeft = kInit, |
tempRight = kInit; |
if (StrictIsValid (theSoundInfo)) { |
theErr = ASoundGetVolume (theSoundInfo, &tempLeft, &tempRight); |
if (theErr == noErr) { |
if ((tempLeft + leftVol) > kMaxVolume) leftVol = kMaxVolume - tempLeft; |
if ((tempRight + rightVol) > kMaxVolume) rightVol = kMaxVolume - tempRight; |
if ((tempLeft + leftVol) < kMinVolume) leftVol = -tempLeft; |
if ((tempRight + rightVol) < kMinVolume) rightVol = -tempRight; |
theErr = ASoundSetVolume (theSoundInfo, tempLeft+leftVol, tempRight+rightVol); |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundChangeVolume"); |
} |
return theErr; |
} |
/* |
Purpose: Gets the volume of the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundGetVolume (SoundInfoPtr theSoundInfo, |
unsigned short *leftVol, |
unsigned short *rightVol) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCommand theCmd = {getVolumeCmd, kInit, kInit}; |
unsigned long theVol = kInit; |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
theCmd.param2 = (long)&theVol; |
theErr = SndDoImmediate(theSoundInfo->chan, &theCmd); |
if (theErr == noErr) { |
*leftVol = theVol & kLeftMask; |
*rightVol = theVol >> kSixteen; |
} |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetVolume"); |
} |
return theErr; |
} |
/* |
Purpose: Sets the volume of the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundSetVolume (SoundInfoPtr theSoundInfo, |
unsigned short leftVol, |
unsigned short rightVol) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCommand theCmd = {volumeCmd, kInit, kInit}; |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
theCmd.param2 = (rightVol << kSixteen) | leftVol; |
theErr = SndDoImmediate(theSoundInfo->chan, &theCmd); |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundSetVolume"); |
} |
return theErr; |
} |
/* |
Purpose: Gets the rate multiplier of the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundGetRateMul (SoundInfoPtr theSoundInfo, |
UnsignedFixed *theRateMul) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCommand theCmd = {getRateMultiplierCmd, kInit, kInit}; |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
theCmd.param2 = (long)theRateMul; |
theErr = SndDoImmediate(theSoundInfo->chan, &theCmd); |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundGetRateMul"); |
} |
return theErr; |
} |
/* |
Purpose: Gets the rate multiplier of the currently playing sound. |
Side Effects: None. |
*/ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundSetRateMul (SoundInfoPtr theSoundInfo, |
UnsignedFixed theRateMul) |
/*-----------------------------------------------------------------------*/ |
{ |
SndCommand theCmd = {rateMultiplierCmd, kInit, kInit}; |
OSErr theErr = noErr; |
if (StrictIsValid (theSoundInfo)) { |
theCmd.param2 = (long)theRateMul; |
theErr = SndDoImmediate(theSoundInfo->chan, &theCmd); |
} |
else { |
theErr = kNilPtrErr; |
} |
if (theErr != noErr) { |
DebugPrint ("\pError in ASoundSetRateMul"); |
} |
return theErr; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-14