home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-02-08 | 16.7 KB | 665 lines | [TEXT/CWIE] |
- ///--------------------------------------------------------------------------------------
- // SWSounds.c
- //
- // Created 11/13/96
- ///--------------------------------------------------------------------------------------
-
- #include "SWSounds.h"
-
-
- #define kNonZeroValue 1 // used to avoid a bug in the Sound Manager
-
-
- typedef struct ChanStruct
- {
- SndChannelPtr channelP; // Pointer to the sound channel
- short curSoundID; // The ID of the sound currently playing in this channel.
- short volume; // current volume for this channel
- short stereoPos; // stereo position of this channel
- Boolean isDone; // Is this channel done playing the last sound?
- Boolean isAvailable; // Used by SetChannelAvailability.
- } ChanStruct, *ChanStructPtr;
-
-
- short gNumSounds;
- short gNumChannels; // Number of sound channels
- ChanStruct *gChanArray; // Channel array that's allocated at run-time
- Handle *gSoundHArray; // Array of handles to all our sounds
- Boolean gStereoMode = true; // Whether to use stereo or mono
- long gOldSystemSoundVolume = -1; // used by SaveSystemVolume and RestoreSystemVolume
-
- SndCallBackUPP gSoundCallBackUPP; // Needed for PPC
-
-
- ///--------------------------------------------------------------------------------------
- // IsNewSoundManagerInstalled
- ///--------------------------------------------------------------------------------------
-
- Boolean IsNewSoundManagerInstalled( void )
- {
- NumVersion theVersion;
- void *trap1;
- void *trap2;
- Boolean installed;
-
- installed = FALSE;
- trap1 = (void *)GetToolTrapAddress(_SoundDispatch); // SndSoundManagerVersion Trap
- trap2 = (void *)GetToolTrapAddress(_Unimplemented); // Unimplemented Trap
-
- if (trap1 != trap2)
- {
- theVersion = SndSoundManagerVersion();
- if (theVersion.majorRev >= 3)
- {
- installed = TRUE;
- }
- }
-
- return installed;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SetSystemVolume
- ///--------------------------------------------------------------------------------------
-
- void SetSystemVolume(short volume)
- {
- if (volume < 0)
- volume = 0;
- else if (volume > 7)
- volume = 7;
-
- // Convert from 0-7 to 0-256
- volume = (256 * volume + 6) / 7; // the + 6 avoids rounding errors
-
- // We set the left and right speaker volume to the same value.
- SetDefaultOutputVolume((long)((long)volume << 16L | (volume & 0xFFFF)));
- }
-
-
- ///--------------------------------------------------------------------------------------
- // GetSystemVolume
- ///--------------------------------------------------------------------------------------
-
- void GetSystemVolume(short *volume)
- {
- short leftVol, rightVol, combinedVol, result;
- long totalVol;
-
- // We set the left and right speaker volume to the same value.
- GetDefaultOutputVolume(&totalVol);
-
- rightVol = totalVol >> 16L;
- leftVol = totalVol & 0xFFFF;
-
- // Get the combined volume of the left and right speakers
- combinedVol = (rightVol + leftVol) / 2;
-
- // Convert from 0-256 to 0-7
- result = (combinedVol * 7) / 256;
- if (result == 0 && combinedVol > 0) // Any value above 0 has volume
- result = 1;
-
- *volume = result;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SaveSystemVolume
- ///--------------------------------------------------------------------------------------
-
- void SaveSystemVolume( void )
- {
- GetDefaultOutputVolume(&gOldSystemSoundVolume);
- }
-
-
- ///--------------------------------------------------------------------------------------
- // RestoreSystemVolume
- ///--------------------------------------------------------------------------------------
-
- void RestoreSystemVolume( void )
- {
- // We set the left and right speaker volume to the same value.
- if (gOldSystemSoundVolume != -1)
- SetDefaultOutputVolume(gOldSystemSoundVolume);
- }
-
-
- ///--------------------------------------------------------------------------------------
- // CreateSoundChannels
- ///--------------------------------------------------------------------------------------
-
- OSErr CreateSoundChannels(short numChannels)
- {
- Size arraySize;
- short n;
- OSErr err = noErr;
-
- gSoundCallBackUPP = NewSndCallBackProc(SoundCallBack);
-
- gNumChannels = numChannels;
- if (numChannels <= 0)
- return -1;
-
- // Allocate memory for gChanArray
- arraySize = (Size)numChannels * sizeof(ChanStruct);
- gChanArray = (ChanStruct *)NewPtrClear(arraySize);
- err = MemError();
-
-
- if (err == noErr)
- {
- // Create the sound channels
- for (n=0; n < numChannels; n++)
- {
- err = SndNewChannel(&gChanArray[n].channelP, sampledSynth, initMono, gSoundCallBackUPP);
- gChanArray[n].channelP->userInfo = SetCurrentA5();
- gChanArray[n].isDone = true;
- gChanArray[n].curSoundID = -1;
- gChanArray[n].volume = kFullVolume;
- gChanArray[n].stereoPos = 0;
- gChanArray[n].isAvailable = true;
-
- if (err)
- break;
- }
-
- if (err != noErr) // Dispose what we created
- {
- while (n)
- {
- SndDisposeChannel(gChanArray[--n].channelP, true);
- }
-
- DisposePtr((Ptr)gChanArray);
- }
- }
-
- if (err != noErr)
- {
- // Get rid of our UPPs
- DisposeRoutineDescriptor( gSoundCallBackUPP );
- }
-
- return err;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // DisposeSoundChannels
- ///--------------------------------------------------------------------------------------
-
- void DisposeSoundChannels( void )
- {
- while (gNumChannels)
- {
- SndDisposeChannel(gChanArray[--gNumChannels].channelP, true);
- }
-
- DisposePtr((Ptr)gChanArray);
-
- // Get rid of our UPPs
- DisposeRoutineDescriptor( gSoundCallBackUPP );
- }
-
-
- ///--------------------------------------------------------------------------------------
- // LoadSounds
- ///--------------------------------------------------------------------------------------
-
- OSErr LoadSounds( short startResID, short numSounds )
- {
- short index;
- Size arraySize;
- OSErr err = noErr;
-
- gNumSounds = numSounds;
-
- // Allocate memory for gSoundHArray
- arraySize = (Size)numSounds * sizeof(Handle);
- gSoundHArray = (Handle *)NewPtrClear(arraySize);
- err = MemError();
-
- if (err == noErr)
- {
- // Load the sounds
- for (index = 0; index < numSounds && err != memFullErr; index++)
- {
- gSoundHArray[index] = GetResource('snd ', startResID + index);
-
- if (gSoundHArray[index] != NULL)
- {
- HLock(gSoundHArray[index]);
- }
- else
- {
- // If old err was a memory error, don't replace it with resNotFound
- if (err == noErr || err == resNotFound)
- err = ResError() ? ResError() : resNotFound;
- }
- }
- }
-
- return err;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // DisposeSounds
- ///--------------------------------------------------------------------------------------
-
- void DisposeSounds( void )
- {
- short index;
-
- for (index = 0; index < gNumSounds; index++)
- {
- ReleaseResource(gSoundHArray[index]);
- }
-
- DisposePtr((Ptr)gSoundHArray);
-
- }
-
-
- ///--------------------------------------------------------------------------------------
- // PlaySound - starts playing a sound in the appropriate channel
- ///--------------------------------------------------------------------------------------
-
- void PlaySound(
- short soundID,
- short channelNum,
- PlayType playType)
- {
- PlaySound2(soundID, channelNum, playType, 256, 0, k22khz, false);
- }
-
-
- ///--------------------------------------------------------------------------------------
- // PlaySound2 - starts playing a sound in the appropriate channel
- ///--------------------------------------------------------------------------------------
-
- void PlaySound2(
- short soundID,
- short channelNum,
- PlayType playType,
- short volume,
- short stereoPosition,
- UnsignedFixed rate,
- Boolean doLoopingSound)
- {
- #pragma unused(rate, doLoopingSound)
-
- if (soundID < 0 || soundID >= gNumSounds || gSoundHArray[soundID] == NULL)
- return;
-
- channelNum = FindChannel(soundID, channelNum, playType);
-
- SetChannelVolume(channelNum, volume);
- SetStereoPosition(channelNum, stereoPosition);
- PlayMySound(soundID, channelNum);
- }
-
-
- ///--------------------------------------------------------------------------------------
- // FindChannel - used by PlaySound2
- ///--------------------------------------------------------------------------------------
-
- short FindChannel(short soundID, short channelNum, PlayType playType)
- {
- Boolean allChannelsAreBusy;
- short emptyChannelNum;
- short n;
-
- if (channelNum < 0 || channelNum >= gNumChannels)
- channelNum = 0;
-
-
- if (playType == kPlaySoundInChannel)
- {
- return channelNum;
- }
- else if (playType == kReplaceSameSound)
- {
- for (n=0; n < gNumChannels; n++) // Look for our sound in all channels
- {
- if (gChanArray[n].curSoundID == soundID)
- {
- return n;
- }
- }
- }
-
- // The following code is executed if playType is kFindEmptyChannel or if
- // playType was kReplaceSameSound and the sound was not found in any channel.
-
-
- // Determine if all channels are busy
- allChannelsAreBusy = true;
- for (n=0; n < gNumChannels; n++)
- {
- if (gChanArray[n].isDone && gChanArray[n].isAvailable)
- {
- allChannelsAreBusy = false;
- emptyChannelNum = n;
- break;
- }
- }
-
-
- if (gChanArray[channelNum].isDone)
- {
- return channelNum; // The requested channel is free
- }
- else if (allChannelsAreBusy)
- {
- // First search all other channels for our sound
- for (n=0; n < gNumChannels; n++)
- {
- if (gChanArray[n].curSoundID == soundID)
- {
- return n;
- }
- }
-
- // If none are found, return the requested channel
- return channelNum;
- }
- else
- {
- return emptyChannelNum; // Return an empty channel
- }
- }
-
-
- ///--------------------------------------------------------------------------------------
- // PlayMySound - called by PlaySound
- ///--------------------------------------------------------------------------------------
-
- void PlayMySound(short soundID, short channelNum)
- {
- SndCommand theCommand;
-
- // Stop any sound already playing in this channel
- StopChannel(channelNum);
-
- // Play the sound
- gChanArray[channelNum].isDone = false;
- gChanArray[channelNum].curSoundID = soundID;
- SndPlay(gChanArray[channelNum].channelP, (SndListHandle)gSoundHArray[soundID], true);
-
- // Install the callBack
- theCommand.cmd = callBackCmd;
- theCommand.param1 = kNonZeroValue;
- theCommand.param2 = channelNum;
- SndDoCommand(gChanArray[channelNum].channelP, &theCommand, false);
- }
-
-
- ///--------------------------------------------------------------------------------------
- // StopSound
- ///--------------------------------------------------------------------------------------
-
- void StopSound(short soundID)
- {
- short n;
-
- if (soundID < 0 || soundID >= gNumSounds)
- return;
-
- for (n=0; n < gNumChannels; n++)
- {
- if (gChanArray[n].curSoundID == soundID)
- {
- StopChannel(n);
- }
- }
- }
-
-
- ///--------------------------------------------------------------------------------------
- // StopChannel
- ///--------------------------------------------------------------------------------------
-
- void StopChannel(short channelNum)
- {
- SndCommand theCommand;
-
- if (channelNum < 0 || channelNum >= gNumChannels)
- return;
-
- // Stop the sound already playing in this channel
- if (!gChanArray[channelNum].isDone)
- {
- theCommand.cmd = quietCmd;
- SndDoImmediate(gChanArray[channelNum].channelP, &theCommand);
- theCommand.cmd = flushCmd;
- SndDoImmediate(gChanArray[channelNum].channelP, &theCommand);
- gChanArray[channelNum].isDone = true;
- gChanArray[channelNum].curSoundID = -1;
- }
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SetChannelVolume
- ///--------------------------------------------------------------------------------------
-
- void SetChannelVolume(short channelNum, short newVolume)
- {
- if (channelNum < 0 || channelNum >= gNumChannels)
- return;
-
- if (gChanArray[channelNum].volume != newVolume)
- {
- SetVolumeAndStereoPosition(channelNum, newVolume, gChanArray[channelNum].stereoPos);
- }
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SetStereoPosition
- ///--------------------------------------------------------------------------------------
-
- void SetStereoPosition(short channelNum, short stereoPosition)
- {
- if (channelNum < 0 || channelNum >= gNumChannels)
- return;
-
- if (gChanArray[channelNum].stereoPos != stereoPosition)
- {
- SetVolumeAndStereoPosition(channelNum, gChanArray[channelNum].volume, stereoPosition);
- }
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SetVolumeAndStereoPosition - used internally.
- ///--------------------------------------------------------------------------------------
-
- void SetVolumeAndStereoPosition(short channelNum, short newVolume, short stereoPosition)
- {
- short leftVolume, rightVolume, stereoOffset;
- SndCommand theCommand;
-
- if (channelNum < 0 || channelNum >= gNumChannels)
- return;
-
- if (newVolume < 0)
- newVolume = 0;
-
- if (stereoPosition < -256)
- stereoPosition = -256;
- else if (stereoPosition > 256)
- stereoPosition = 256;
-
- gChanArray[channelNum].volume = newVolume;
- gChanArray[channelNum].stereoPos = stereoPosition;
-
- if (gStereoMode == true)
- {
- // Calculate stereoOffset based on stereoPosition and the current volume
- stereoOffset = (newVolume * stereoPosition) / 256;
-
- leftVolume = newVolume - stereoOffset;
- rightVolume = newVolume + stereoOffset;
- }
- else
- {
- // Mono sound
- leftVolume = newVolume;
- rightVolume = newVolume;
- }
-
- // Issue the command
- theCommand.param1 = 0;
- theCommand.param2 = (long)((long)rightVolume << 16L | (leftVolume & 0xFFFF));
- theCommand.cmd = volumeCmd;
- SndDoImmediate(gChanArray[channelNum].channelP, &theCommand);
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SetChannelAvailability
- ///--------------------------------------------------------------------------------------
-
- void SetChannelAvailability(short channelNum, Boolean isAvailable)
- {
- if (channelNum < 0 || channelNum >= gNumChannels)
- return;
-
- gChanArray[channelNum].isAvailable = isAvailable;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SetStereoMode
- ///--------------------------------------------------------------------------------------
-
- void SetStereoMode(Boolean mode)
- {
- short n;
-
- gStereoMode = mode;
-
- // Update all channels for the current mode
- for (n = 0; n < gNumChannels; n++)
- {
- SetVolumeAndStereoPosition(n, gChanArray[n].volume, gChanArray[n].stereoPos);
- }
- }
-
-
- ///--------------------------------------------------------------------------------------
- // GetStereoPositionOfSprite
- ///--------------------------------------------------------------------------------------
-
- short GetStereoPositionOfSprite(SpritePtr srcSpriteP, Rect *destRectP)
- {
- short col, stereoPos;
-
- col = srcSpriteP->destFrameRect.left + SW_RECT_WIDTH(srcSpriteP->destFrameRect) / 2;
-
- stereoPos = GetStereoPositionOfColumn(col, destRectP);
-
- return stereoPos;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // GetStereoPositionOfColumn
- ///--------------------------------------------------------------------------------------
-
- short GetStereoPositionOfColumn(long col, Rect *backRectP)
- {
- Rect backRect = *backRectP;
- long screenMidCol;
- short offset, stereoPos;
-
- // Make sure the left side starts at 0
- if (backRect.left != 0)
- {
- offset = backRect.left;
- backRect.left -= offset;
- backRect.right -= offset;
- col -= offset;
- }
-
- screenMidCol = backRect.right / 2;
-
- // Fix col if out of bounds
- if (col < 0)
- col = 0;
- else if (col > backRect.right)
- col = backRect.right;
-
- // Calculate it
- col -= screenMidCol;
- stereoPos = (col * 256) / screenMidCol;
-
- return stereoPos;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // FindSound - searches all channels for soundID. Returns channel number, or -1.
- ///--------------------------------------------------------------------------------------
-
- short FindSound(short soundID)
- {
- short channel;
- Boolean foundSound;
-
- foundSound = false;
- for (channel = 0; channel < gNumChannels; channel++)
- {
- if (gChanArray[channel].curSoundID == soundID)
- {
- foundSound = true;
- break;
- }
- }
-
- if (foundSound)
- return channel;
- else
- return -1;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SoundCallBack - called when a channel is done playing a sound
- ///--------------------------------------------------------------------------------------
-
- pascal void SoundCallBack(SndChannelPtr theChannel, SndCommand *theCommand)
- {
- short channelNum;
- long saveA5;
-
- #if SW_PPC
- #pragma unused(saveA5, theChannel)
- #else
- saveA5 = SetA5(theChannel->userInfo);
- #endif
-
- // We check for kNonZeroValue to avoid a bug in some versions of the Sound Manager.
- if (theCommand->param1 == kNonZeroValue)
- {
- channelNum = theCommand->param2;
-
- if (channelNum >= 0 && channelNum < gNumChannels)
- {
- gChanArray[channelNum].isDone = true;
- gChanArray[channelNum].curSoundID = -1;
- }
- }
-
-
- #if !SW_PPC
- SetA5(saveA5);
- #endif
- }
-
-