home *** CD-ROM | disk | FTP | other *** search
- /*
- File: Private_DBFFFunctions.c
-
- Contains: Routines demonstrating how to set up for 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 "Private_DBFFFunctions.h"
-
- /********************************************************************************************
- ** YOU SHOULD NEVER NEED TO CALL ANY OF THE FOLLOWING ROUTINES DIRECTLY **
- ********************************************************************************************/
-
- /* Purpose: This sets all of local and global variables to safe values.
- This routine is called by ASoundNew, and is called by the
- ASoundDone function after it has cleaned up to reset things.
- Side Effects: None.
- */
- /*-----------------------------------------------------------------------*/
- OSErr ASoundInit (SoundInfoPtr theSoundInfo)
- /*-----------------------------------------------------------------------*/
- {
- NumVersion SndManagerVer;
- OSErr theErr = noErr;
-
- theSoundInfo->globals.gSupports16Bit = true;
- theSoundInfo->globals.gSupportsSPDB = true;
-
- theSoundInfo->signature = kDBFFSignature;
- theSoundInfo->chan = kInit;
- theSoundInfo->rateForResume = kInit;
- /* create a Universal Procedure Pointer (UPP) for our sound callback */
- theSoundInfo->theSoundCallBackUPP = NewSndCallBackProc(ASoundDoneCallBack);
- theSoundInfo->fileType = kInit;
- (void)ASoundSetNumBuffers (theSoundInfo, kStart);
- theSoundInfo->dataStart = kInit;
- (void)ASoundSetSoundLength (theSoundInfo, kInit);
- ASoundSetBytesCopied (theSoundInfo, kInit);
- ASoundSetCurBuffer (theSoundInfo, kStart);
- (void)ASoundSetBufferSize (theSoundInfo, kInit);
- theSoundInfo->bytesPerFrame = kInit;
- theSoundInfo->refNum = kInit;
- theSoundInfo->vRefNum = nil;
- theSoundInfo->compFactor = kNoCompression;
- theSoundInfo->paused = false;
- theSoundInfo->playing = false;
- theSoundInfo->adjusting = false;
- theSoundInfo->soundDone = false;
- theSoundInfo->backwards = false;
- theSoundInfo->hasBeenAdjusted = false;
- theSoundInfo->needsMasking = false;
- theSoundInfo->stopping = false;
-
- SndManagerVer = SndSoundManagerVersion ();
- theErr = InterrogateSystem (&(theSoundInfo->globals));
- if (theErr == noErr) {
- if (SndManagerVer.majorRev >= kMinSndMgrVer) {
- if ((theSoundInfo->globals.ggestaltSoundAttr & (1 << gestaltSndPlayDoubleBuffer)) == false) {
- DebugPrint ("\pSndPlayDoubleBuffer isn't supported!");
- theSoundInfo->globals.gSupportsSPDB = false;
- theErr = kNoSPDBErr;
- }
- if ((theSoundInfo->globals.ggestaltSoundAttr & (1<< gestalt16BitAudioSupport)) == false) {
- DebugPrint ("\pThis machine doesn't support 16 bit audio!");
- theSoundInfo->globals.gSupports16Bit = false;
- theErr = notEnoughHardwareErr; /* This doesn't have to be a fatal error */
- }
- }
- else {
- theErr = kOldSndMgrErr;
- }
- }
- else {
- theErr = kInitErr;
- }
-
- return theErr;
- }
-
- /*-----------------------------------------------------------------------*/
- Boolean IsValid (SoundInfoPtr theSoundInfo)
- /*-----------------------------------------------------------------------*/
- {
- return CheckValididity (theSoundInfo, false);
- }
-
- /*-----------------------------------------------------------------------*/
- Boolean StrictIsValid (SoundInfoPtr theSoundInfo)
- /*-----------------------------------------------------------------------*/
- {
- return CheckValididity (theSoundInfo, true);
- }
-
-
- /*-----------------------------------------------------------------------*/
- Boolean CheckValididity (SoundInfoPtr theSoundInfo,
- Boolean strict)
- /*-----------------------------------------------------------------------*/
- {
- Boolean returnValue = true; /* Assume success */
-
- if (theSoundInfo == nil) {
- returnValue = false;
- }
- else {
- if (strict == true) {
- if (theSoundInfo->signature != kDBFFSignature) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->signature is invalid");
- }
- else {
- if (theSoundInfo->doubleHeader.dbhNumChannels <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->doubleHeader.dbhNumChannels is invalid");
- }
- if (theSoundInfo->doubleHeader.dbhSampleSize <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->doubleHeader.dbhSampleSize is invalid");
- }
- if (theSoundInfo->doubleHeader.dbhPacketSize < kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->doubleHeader.dbhPacketSize is invalid");
- }
- if (theSoundInfo->theSoundCallBackUPP == nil) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->theSoundCallBackUPP is invalid");
- }
- if (theSoundInfo->rateForResume < kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->rateForResume is invalid");
- }
- if (theSoundInfo->numBuffers <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->numBuffers is invalid");
- }
- if (theSoundInfo->dataStart < kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->dataStart is invalid");
- }
- if (theSoundInfo->bytesTotal <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->bytesTotal is invalid");
- }
- if (theSoundInfo->bytesCopied <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->bytesCopied is invalid");
- }
- if (theSoundInfo->currentBuffer <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->currentBuffer is invalid");
- }
- if (theSoundInfo->doubleBufferSize <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->doubleBufferSize is invalid");
- }
- if (theSoundInfo->bytesPerFrame <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->bytesPerFrame is invalid");
- }
- if (theSoundInfo->compFactor <= kInit) {
- returnValue = false;
- DebugPrint ("\pStrictIsValid theSoundInfo->compFactor is invalid");
- }
- }
- }
- else {
- if (theSoundInfo->signature != kDBFFSignature) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->signature is invalid");
- }
- else {
- if (theSoundInfo->doubleHeader.dbhNumChannels < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->doubleHeader.dbhNumChannels is invalid");
- }
- if (theSoundInfo->doubleHeader.dbhSampleSize < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->doubleHeader.dbhSampleSize is invalid");
- }
- if (theSoundInfo->doubleHeader.dbhPacketSize < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->doubleHeader.dbhPacketSize is invalid");
- }
- if (theSoundInfo->theSoundCallBackUPP == nil) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->theSoundCallBackUPP is invalid");
- }
- if (theSoundInfo->rateForResume < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->rateForResume is invalid");
- }
- if (theSoundInfo->numBuffers < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->numBuffers is invalid");
- }
- if (theSoundInfo->dataStart < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->dataStart is invalid");
- }
- if (theSoundInfo->bytesTotal < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->bytesTotal is invalid");
- }
- if (theSoundInfo->bytesCopied < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->bytesCopied is invalid");
- }
- if (theSoundInfo->currentBuffer < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->currentBuffer is invalid");
- }
- if (theSoundInfo->doubleBufferSize < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->doubleBufferSize is invalid");
- }
- if (theSoundInfo->bytesPerFrame < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->bytesPerFrame is invalid");
- }
- if (theSoundInfo->compFactor < kInit) {
- returnValue = false;
- DebugPrint ("\pIsValid theSoundInfo->compFactor is invalid");
- }
- }
- }
- }
-
- return returnValue;
- }
-
- /*
- Purpose: Called by StandardFile for every file in a folder to
- see if we want to display that file in the open file
- dialog. Return false (don't filter) if you want the
- file displayed, true (do filter) if you don't want
- it displayed.
-
- This calls ASoundCanThisPlay() which calls the header
- parsing routines. If we can parse the header we
- should be able to play the file.
- Side Effects: None.
- */
- /*-----------------------------------------------------------------------*/
- pascal Boolean ASoundFileFilter (CInfoPBPtr theFileInfo)
- /*-----------------------------------------------------------------------*/
- {
- OSErr theErr = noErr;
- Boolean returnValue = true; /* by default don't display the file */
-
- theErr = ASoundCanThisPlay (theFileInfo);
- if (theErr == noErr) { /* We can play this file. */
- returnValue = false; /* Display this file */
- }
-
- if (theErr != noErr && theErr != kUnknownFormat) {
- DebugPrint ("\pError in ASoundFileFilter");
- }
-
- return returnValue;
- }
-
- /*
- Purpose: Sets how many buffers will be needed to play the entire
- sound.
- Side Effects: None.
- */
- /*-----------------------------------------------------------------------*/
- OSErr ASoundSetNumBuffers (SoundInfoPtr theSoundInfo,
- long newValue)
- /*-----------------------------------------------------------------------*/
- {
- OSErr theErr = noErr;
-
- if (newValue >= kInit) {
- theSoundInfo->numBuffers = newValue;
- }
- else {
- theErr = kBadValue;
- }
-
- return theErr;
- }
-
- /*
- Purpose: To install a callback command into the current sound
- channel.
- Side Effects: None.
- */
- /*-----------------------------------------------------------------------*/
- OSErr InstallCallBack (SoundInfoPtr theSoundInfo)
- /*-----------------------------------------------------------------------*/
- {
- SndCommand mycmd = {callBackCmd, kInit, kInit};
- OSErr theErr = noErr;
-
- mycmd.param2 = SetCurrentA5();
- theErr = SndDoCommand (theSoundInfo->chan, &mycmd, true);
-
- if (theErr != noErr) {
- DebugPrint ("\pError in InstallCallBack");
- }
-
- return theErr;
- }
-
- /*
- Purpose: Gather the information needed (from the sound's header)
- to setup the structures the Sound Manager will need to
- play the sound.
- Side Effects: This will allocate memory for the sound header strucure
- that will be disposed of by ASoundDonePlaying.
- */
- /*-----------------------------------------------------------------------*/
- OSErr SetUpSoundHeader (SoundInfoPtr theSoundInfo,
- unsigned long bufferSize)
- /*-----------------------------------------------------------------------*/
- {
- long double sampleRate = kInit;
- long dataStart = kInit,
- sndLength = kInit,
- numBuffers = kInit;
- short remainder = kInit;
- OSErr theErr = noErr;
-
- theSoundInfo->chan->userInfo = (long)theSoundInfo; /* So we know who we are in the SoundCompletion routines */
-
- 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 = ASoundGetSNDHeader (theSoundInfo, &dataStart, &sndLength);
- break;
- default:
- theErr = kUnknownFormat;
- break;
- }
-
- theSoundInfo->dataStart = dataStart;
- if (theErr != noErr) {
- DebugPrint ("\pASoundGetAIFFHeader error!");
- (void)SndDisposeChannel (theSoundInfo->chan, true);
- }
- else {
- if ((theSoundInfo->doubleHeader.dbhSampleSize == kSixteen) && (theSoundInfo->globals.gSupports16Bit == false)) {
- DebugPrint ("\pThis is a 16 bit sound, this is not a 16 bit capable machine.");
- theErr = notEnoughHardwareErr;
- }
- else {
- theErr = ASoundSetSoundLength (theSoundInfo, sndLength);
- ASoundSetBytesCopied (theSoundInfo, dataStart); /* skip the header of the file */
-
- sampleRate = ASoundFixToLongDouble (theSoundInfo->doubleHeader.dbhSampleRate);
-
- if (bufferSize > kInit) {
- theErr = ASoundSetBufferSize (theSoundInfo, bufferSize);
- }
- else {
- theErr = ASoundSetBufferSize (theSoundInfo, (((theSoundInfo->doubleHeader.dbhSampleSize / kBitsPerByte) * theSoundInfo->doubleHeader.dbhNumChannels * sampleRate) / kBufLen) / theSoundInfo->compFactor);
- }
-
- if (ASoundGetBufferSize (theSoundInfo) > kInit) {
- numBuffers = (ASoundGetNumTotalBytes (theSoundInfo) / ASoundGetBufferSize (theSoundInfo));
- remainder = (ASoundGetNumTotalBytes (theSoundInfo) % ASoundGetBufferSize (theSoundInfo));
- if (remainder != 0) { /* Is the last buffer only a partial buffer? */
- numBuffers++; /* Don't forget to account for it! */
- }
- theErr = ASoundSetNumBuffers (theSoundInfo, numBuffers);
- }
- else {
- DebugPrint ("\pThe buffer size is zero, this is bad.");
- theErr = dsZeroDivErr;
- }
-
- theSoundInfo->doubleHeader.dbhDoubleBack = NewSndDoubleBackProc (ASoundDoubleBackProc);
- theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufOne] = nil;
- theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufTwo] = nil;
- }
- }
-
- if (theErr != noErr) {
- DebugPrint ("\pError in SetUpSoundHeader");
- }
-
- return theErr;
- }
-
- /*
- Purpose: Pause the playing of the sound.
- Side Effects: None.
- */
- /*-----------------------------------------------------------------------*/
- OSErr PauseSound (SoundInfoPtr theSoundInfo)
- /*-----------------------------------------------------------------------*/
- {
- OSErr theErr = noErr;
- UnsignedFixed rateMul;
-
- rateMul = 0;
- theErr = SndSetInfo (theSoundInfo->chan, siRateMultiplier, (void*)rateMul);
-
- if (theErr == noErr) {
- theSoundInfo->paused = true;
- }
-
- if (theErr != noErr) {
- DebugPrint ("\pError in PauseSound");
- }
-
- return theErr;
- }
-
- /*
- Purpose: Resume the playing of the sound.
- Side Effects: This will reinstall the sound completion callback
- if it was removed by the ASoundPauseForAdjust function.
- */
- /*-----------------------------------------------------------------------*/
- OSErr ResumeSound (SoundInfoPtr theSoundInfo)
- /*-----------------------------------------------------------------------*/
- {
- OSErr theErr = noErr;
- UnsignedFixed rateMul;
-
- rateMul = (1<<16);
- theErr = SndSetInfo (theSoundInfo->chan, siRateMultiplier, (void*)rateMul);
-
- if (theErr == noErr) {
- theSoundInfo->paused = false;
- if (theSoundInfo->hasBeenAdjusted == true) {
- theErr = SndPlayDoubleBuffer (theSoundInfo->chan, (SndDoubleBufferHeaderPtr)&(theSoundInfo->doubleHeader));
- theErr = InstallCallBack (theSoundInfo);
- theSoundInfo->hasBeenAdjusted = false;
- }
- }
-
- if (theErr != noErr) {
- DebugPrint ("\pError in ResumeSound");
- }
-
- return theErr;
- }
-
- /*-----------------------------------------------------------------------*/
- OSErr ASoundSetBufferSize (SoundInfoPtr theSoundInfo,
- long newValue)
- /*-----------------------------------------------------------------------*/
- {
- OSErr theErr = noErr;
-
- if (newValue >= nil) {
- /* Make sure the buffer is an integer multiple of the packet size,
- otherwise IMA will be VERY upset, and WAVE files might not sound
- too good either. */
- if (theSoundInfo->doubleHeader.dbhPacketSize > kInit) {
- newValue /= theSoundInfo->bytesPerFrame;
- // newValue /= theSoundInfo->doubleHeader.dbhPacketSize * theSoundInfo->doubleHeader.dbhNumChannels;
- }
- newValue *= theSoundInfo->bytesPerFrame;
- // newValue *= theSoundInfo->doubleHeader.dbhPacketSize * theSoundInfo->doubleHeader.dbhNumChannels;
- theSoundInfo->doubleBufferSize = newValue;
- }
- else {
- theSoundInfo->doubleBufferSize = kInit;
- DebugPrint ("\pBad value passed to ASoundSetBufferSize");
- theErr = kBadValue;
- }
-
- if (theErr != noErr) {
- DebugPrint ("\pError in ASoundSetBufferSize");
- }
-
- return theErr;
- }
-
- /*-----------------------------------------------------------------------*/
- OSErr ASoundSetSoundLength (SoundInfoPtr theSoundInfo,
- long newValue)
- /*-----------------------------------------------------------------------*/
- {
- OSErr theErr = noErr;
-
- if (newValue >= nil) {
- theSoundInfo->bytesTotal = newValue;
- }
- else {
- theSoundInfo->bytesTotal = kInit;
- theErr = kBadValue;
- }
-
- if (theErr != noErr) {
- DebugPrint ("\pError in ASoundSetSoundLength");
- }
-
- return theErr;
- }
-
- /*
- Purpose: The purpose of this routine is to fill out the
- SndDoubleBufferHeader structure with the information the
- Sound Manager will need, and to fill out the
- myParamBlockRec structure with the information the
- ASoundDoubleBackProc interrupt routine will need. It
- then calls ASoundDoubleBackProc to fill the first two
- buffers.
- Side effects: This routine allocates two pointers as buffers for the
- sound that will be playing.
- This routine allocates two custom paramBlockRecs for
- the ASoundDoubleBackProc (interrupt routine) to use.
- */
- /*-----------------------------------------------------------------------*/
- OSErr ASoundPrimeBuffers (SoundInfoPtr theSoundInfo)
- /*-----------------------------------------------------------------------*/
- {
- myParmBlkPtr myPB = nil;
- SndDoubleBufferPtr doubleBuffer = nil;
- IOCompletionUPP myIOCompletion = nil;
- OSErr theErr = noErr;
- short i = kInit;
-
- for (i = kInit; i <= kOne; ++i) {
- if (theSoundInfo->doubleHeader.dbhBufferPtr[i] == nil) {
- doubleBuffer = (SndDoubleBufferPtr)NewPtrClear (sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo));
- if (doubleBuffer == nil || MemError() != noErr) {
- DebugPrint("\pNo memory for double buffers!");
- theErr = memFullErr;
- }
- else {
- /* Hold the memory in case VM is on, this will help to ensure that we have no sound
- drop outs caused by the paging of our buffers. */
- HoldMemory (doubleBuffer, sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo));
- /* dbNumFrames gets set in the ASoundDoubleBackProc() routine */
- doubleBuffer->dbFlags = nil;
- doubleBuffer->dbUserInfo[kSndInfoPtr] = (long)theSoundInfo; /* Make this point at our SoundInfo struct */
- myPB = (myParamBlockRec *)NewPtrClear(sizeof(myParamBlockRec)); /* Make one for each buffer so */
- if (myPB == nil || MemError() != noErr) { /* we don't reuse the same paramBlock in */
- DebugPrint("\pNo memory for a new paramBlockRec!"); /* the ioCompletion routine. */
- theErr = memFullErr;
- }
- else {
- myPB->myA5 = SetCurrentA5 ();
- myPB->theSoundInfo = theSoundInfo;
- myIOCompletion = NewIOCompletionProc (ASoundFileCallBack);
- myPB->pb.ioParam.ioCompletion = myIOCompletion;
- myPB->pb.ioParam.ioVRefNum = theSoundInfo->vRefNum;
- myPB->pb.ioParam.ioRefNum = theSoundInfo->refNum;
- myPB->pb.ioParam.ioPosMode = fsFromStart | noCacheMask; /* Set the noCacheBit since we probably won't be reading this again */
- doubleBuffer->dbUserInfo[kPBPtr] = (long)myPB;
-
- theSoundInfo->doubleHeader.dbhBufferPtr[i] = doubleBuffer;
- }
- }
- }
- else {
- doubleBuffer = theSoundInfo->doubleHeader.dbhBufferPtr[i];
- }
-
- ASoundDoubleBackProc (theSoundInfo->chan, doubleBuffer); /* prime the buffers */
-
- }
-
- if (theErr != noErr) {
- DebugPrint ("\pError in ASoundPrimeBuffers");
- for (i = kInit; i <= kOne; ++i) {
- if (!theSoundInfo->doubleHeader.dbhBufferPtr[i]) {
- DisposePtr ((Ptr)myIOCompletion);
- DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]->dbUserInfo[kSndInfoPtr]);
- DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]);
- }
- }
- }
-
- return theErr;
- }
-
- /* This routine is used to calculate where to put the SFGetFile Dialog */
- /*-----------------------------------------------------------------------*/
- Rect GetMainScreenRect (void)
- /*-----------------------------------------------------------------------*/
- {
- GDHandle mainDevice;
- GrafPtr mainPort;
- Rect returnRect;
- long response;
-
- Gestalt (gestaltQuickdrawVersion, &response);
-
- if (response == gestaltOriginalQD) {
- GetWMgrPort (&mainPort);
- returnRect = mainPort->portRect;
- }
- else {
- mainDevice = GetMainDevice();
- returnRect = (*mainDevice)->gdRect;
- }
-
- return returnRect;
- }
-