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.
TS3Sound.c
/* |
* File: TS3Sound.c |
* |
* Contents: Handles some of the sound stuff. |
* |
* Copyright © 1996 Apple Computer, Inc. |
*/ |
#include <assert.h> |
#include <math.h> |
#include <stdio.h> |
#include <string.h> |
#include <Components.h> |
#include <Controls.h> |
#include <Dialogs.h> |
#include <Sound.h> |
#include <SoundComponents.h> |
#include <Resources.h> |
#include <Timer.h> |
#include <ToolUtils.h> |
#include <Types.h> |
#define __USING_OLD_SOUND_H__ 0 |
#include "SoundSprocket.h" |
#include "TS3Message.h" |
#include "TS3Resource.h" |
#include "TS3Sound.h" |
#include "TS3Utils.h" |
#include "TS3Window.h" |
static SndChannelPtr gSoundChannel = NULL; |
static SndListHandle gSoundResource = NULL; |
static DialogPtr gSoundDialog = NULL; |
static SSpLocalizationData gSoundPrev3DInfo; |
static Boolean CheckVersionNumber( |
const NumVersion* inVersion, |
UInt8 inMajor, |
UInt8 inMinor, |
UInt8 inBug); |
static WindowMethodPtr Sound_MetaHandler( |
WindowMethod inMethod); |
static void Sound_ConsumeEvent( |
WindowPtr inWindow, |
const EventRecord* inEvent, |
Boolean* outConsumed); |
static void Sound_Update( |
WindowPtr inWindow); |
static Boolean EventProc( |
EventRecord *inEvent); |
static pascal void Sound_BoxUserItem( |
DialogPtr inDialog, |
short inItem); |
/******************************************************************************* |
* CheckVersionNumber |
* |
* Returns true if the given version number is compatible with (i. e not older |
* than) version inMajor.inMinor.inBug. |
******************************************************************************/ |
Boolean CheckVersionNumber( |
const NumVersion* inVersion, |
UInt8 inMajor, |
UInt8 inMinor, |
UInt8 inBug) |
{ |
if (inVersion->majorRev != inMajor) |
{ |
return inVersion->majorRev > inMajor; |
} |
else |
{ |
return inVersion->minorAndBugRev >= inMinor << 4 | inBug; |
} |
} |
// **************************** GetSSpFilterVersion **************************** |
// Finds the manufacturer and version number of the SoundSprocket filter that |
// may be installed. inManufacturer should be the manufacturer code specified |
// at the installation time, which may be zero to allow any manufacturer. |
// If no error is encountered, outManufacturer is set to the actual manufacturer |
// code and outMajorVersion and outMinorVersion are set to the component |
// specification level and manufacturer's implementation revision, respectively. |
static OSStatus GetSSpFilterVersion( |
OSType inManufacturer, |
OSType* outManufacturer, |
UInt32* outMajorVersion, |
UInt32* outMinorVersion) |
{ |
OSStatus err; |
ComponentDescription description; |
Component componentRef; |
UInt32 vers; |
// Set up the component description |
description.componentType = kSoundEffectsType; |
description.componentSubType = kSSpLocalizationSubType; |
description.componentManufacturer = inManufacturer; |
description.componentFlags = 0; |
description.componentFlagsMask = 0; |
// Find a component matching the description |
componentRef = FindNextComponent(nil, &description); |
if (componentRef == nil) return couldntGetRequiredComponent; |
// Get the component description (for the manufacturer code) |
err = GetComponentInfo(componentRef, &description, nil, nil, nil); |
if (err != noErr) return err; |
// Get the version composite |
vers = (UInt32) GetComponentVersion((ComponentInstance) componentRef); |
// Return the results |
*outManufacturer = description.componentManufacturer; |
*outMajorVersion = HiWord(vers); |
*outMinorVersion = LoWord(vers); |
return noErr; |
} |
/* ============================================================================= |
* Sound_Init (external) |
* |
* Initializes the sound stuff. |
* ========================================================================== */ |
void Sound_Init( |
void) |
{ |
OSStatus err; |
SoundComponentLink link; |
NumVersion version; |
OSType manufacturer; |
UInt32 majorVersion; |
UInt32 minorVersion; |
assert(kFeedbackItem_COUNT == kFeedbackItem_ExpectedCount); |
// Check the sound manager version |
version = SndSoundManagerVersion(); //¥¥¥ WARNING ¥¥¥ |
//¥ IF YOU CAN'T COMPILE THE PREVIOUS LINE, YOU MUST UPGRADE TO ETO #20 OR |
//¥ EDIT YOUR Sound.h TO MAKE SndSoundManagerVersion RETURN THE TYPE NumVersion. |
if (!CheckVersionNumber(&version, 3, 2, 1)) |
{ |
StopAlert(kAlrtID_SoundMgrVersion, NULL); |
// Note: A normal application would bail on 3D sound here |
} |
// Allocate the sound channel |
err = SndNewChannel(&gSoundChannel, sampledSynth, initMono, NULL); |
Message_CheckError(err, "Sound_Init", "SndNewChannel"); |
assert(gSoundChannel != NULL); |
// Install the 3D sound filters |
link.description.componentType = kSoundEffectsType; |
link.description.componentSubType = kSSpLocalizationSubType; |
link.description.componentManufacturer = 0; |
link.description.componentFlags = 0; |
link.description.componentFlagsMask = 0; |
link.mixerID = nil; |
link.linkID = nil; |
SndSetInfo(gSoundChannel, siPreMixerSoundComponent, &link); |
Message_CheckError(err, "Sound_Init", "SndNewChannel"); |
// Verify that the right version filter was installed |
err = GetSSpFilterVersion( |
link.description.componentManufacturer, |
&manufacturer, |
&majorVersion, |
&minorVersion); |
if (err != noErr) |
{ |
// Filter must not be installed |
// Note: A normal application would bail on 3D sound here |
StopAlert(kAlrtID_FilterNotInstalled, NULL); |
} |
else |
{ |
// The major version represents the component specification level |
if (majorVersion < 1) |
{ |
//¥ if we couldn't handle some old version, we could bail here. |
StopAlert(kAlrtID_FilterVersion, NULL); |
// Note: A normal application would bail on 3D sound here |
} |
else |
{ |
// The minor version specifies the manufacturer's implementation revision |
//¥ could do something here is we needed to handle tweaks for specific |
//¥ manufacturers or versions. |
} |
} |
// Grab the dialog |
gSoundDialog = GetNewDialog(kDlogID_Feedback, NULL, (WindowPtr) -1); |
assert(gSoundDialog != NULL); |
// Set up our method table |
Window_New(gSoundDialog, Sound_MetaHandler); |
// Show the dialog |
ShowWindow(gSoundDialog); |
// Initialize the SSpLocalizationData state to garbage |
memset(&gSoundPrev3DInfo, 0x55, sizeof(SSpLocalizationData)); |
} |
/* ============================================================================= |
* Sound_Exit (external) |
* |
* Prepares for exit. |
* ========================================================================== */ |
void Sound_Exit( |
void) |
{ |
Sound_PlaySilence(); |
assert(gSoundResource == NULL); |
if (gSoundChannel != NULL) |
{ |
SndDisposeChannel(gSoundChannel, true); |
gSoundChannel = NULL; |
} |
if (gSoundDialog != NULL) |
{ |
DisposeDialog(gSoundDialog); |
gSoundDialog = NULL; |
} |
} |
/* ============================================================================= |
* Sound_MetaHandler (internal) |
* |
* Returns the method function pointer that corresponds to the given ID. |
* ========================================================================== */ |
WindowMethodPtr Sound_MetaHandler( |
WindowMethod inMethod) |
{ |
WindowMethodPtr result; |
result = NULL; |
switch (inMethod) |
{ |
case kWindowMethod_ConsumeEvent: |
result = (WindowMethodPtr) Sound_ConsumeEvent; |
break; |
case kWindowMethod_Update: |
result = (WindowMethodPtr) Sound_Update; |
break; |
} |
return result; |
} |
/* ============================================================================= |
* Sound_ConsumeEvent (internal) |
* |
* Called for each event when this is the front window. |
* ========================================================================== */ |
void Sound_ConsumeEvent( |
WindowPtr inWindow, |
const EventRecord* inEvent, |
Boolean* outConsumed) |
{ |
#pragma unused (inWindow) |
Boolean consumed; |
WindowPtr window; |
short item; |
assert(inEvent != NULL); |
assert(outConsumed != NULL); |
consumed = false; |
if (inEvent->what == activateEvt) |
{ |
// We need to look at the activate event here because it is |
// consumed by IsDialogEvent/DialogSelect below and so never |
// gets to the window stuff |
window = (WindowPtr) inEvent->message; |
if (inEvent->modifiers & activeFlag) |
{ |
Window_Activate(window); |
} |
else |
{ |
Window_Deactivate(window); |
} |
} |
// Do dialog stuff |
if (inEvent->what != keyDown || (inEvent->modifiers & cmdKey) == 0) |
{ |
consumed = IsDialogEvent(inEvent); |
if (consumed) |
{ |
DialogSelect(inEvent, &window, &item); |
} |
} |
// Return the result |
*outConsumed = consumed; |
} |
/* ============================================================================= |
* Sound_Update (internal) |
* |
* Updates the contents of the window. |
* ========================================================================== */ |
void Sound_Update( |
WindowPtr inWindow) |
{ |
DrawDialog(inWindow); |
} |
/* ============================================================================= |
* Sound_Configure (external) |
* |
* Stops the current sound, puts up the Configure dialog box, and resumes the |
* stopped sound. |
* ========================================================================== */ |
void Sound_Configure( |
void) |
{ |
OSStatus err; |
Boolean playing; |
short resID; |
ResType resType; |
Str255 resName; |
// Find out which sound to restore |
playing = gSoundResource != NULL; |
if (playing) |
{ |
GetResInfo((Handle) gSoundResource, &resID, &resType, resName); |
} |
// Quiet |
Sound_PlaySilence(); |
// Configure |
err = SSpConfigureSpeakerSetup(EventProc); |
Message_CheckError(err, "Sound_Configure", "SSpConfigureSpeakerSetup"); |
// Play it again, Sam |
if (playing) |
{ |
Sound_PlayResource(resName); |
} |
} |
/* ============================================================================= |
* EventProc (internal) |
* |
* Called to process events during the 3D sound Configure dialog. Returns |
* true if the event was handled (except for update events). |
* ========================================================================== */ |
Boolean EventProc( |
EventRecord *inEvent) |
{ |
WindowPtr wind; |
assert(inEvent != NULL); |
if (inEvent->what == updateEvt) |
{ |
wind = (WindowPtr) inEvent->message; |
if (Window_IsMine(wind)) |
{ |
SetPort(wind); |
BeginUpdate(wind); |
Window_Update(wind); |
EndUpdate(wind); |
} |
} |
return false; |
} |
/* ============================================================================= |
* Sound_PlaySilence (external) |
* |
* Stops any sound that is playing. |
* ========================================================================== */ |
void Sound_PlaySilence( |
void) |
{ |
OSStatus err; |
SndCommand sndCommand; |
sndCommand.cmd = quietCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = 0; |
err = SndDoImmediate(gSoundChannel, &sndCommand); |
Message_CheckError(err, "Sound_PlaySilence", "SndDoImmediate"); |
if (gSoundResource != NULL) |
{ |
ReleaseResource((Handle) gSoundResource); |
gSoundResource = NULL; |
} |
} |
/* ============================================================================= |
* Sound_PlayResource (external) |
* |
* Plays the 'snd ' resource that has the given name. Returns true if |
* successful; returns false if unsuccessful and therefore silence is happening. |
* ========================================================================== */ |
Boolean Sound_PlayResource( |
Str255 inSndName) |
{ |
OSStatus err; |
SndCommand sndCommand; |
long offset; |
// Silence the sound channel and get rid of the old resource |
Sound_PlaySilence(); |
// Grab the resource |
gSoundResource = (SndListHandle) GetNamedResource('snd ', inSndName); |
if (gSoundResource == NULL || ResError() != noErr) |
{ |
StopAlert(kAlrtID_BadSndLoad, NULL); |
goto bail; |
} |
// Lock it down |
HLockHi((Handle) gSoundResource); |
// Play it indefinitely |
GetSoundHeaderOffset(gSoundResource, &offset); |
sndCommand.cmd = soundCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = (long) *gSoundResource + offset; |
err = SndDoImmediate(gSoundChannel, &sndCommand); |
Message_CheckError(err, "Sound_PlayResource", "SndDoImmediate"); |
sndCommand.cmd = freqCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = 60; |
err = SndDoImmediate(gSoundChannel, &sndCommand); |
Message_CheckError(err, "Sound_PlayResource", "SndDoImmediate"); |
return true; |
// Error exit |
bail: |
if (gSoundResource != NULL) |
{ |
ReleaseResource((Handle) gSoundResource); |
gSoundResource = NULL; |
} |
return false; |
} |
/* ============================================================================= |
* Sound_Set3DInfo (external) |
* |
* Sends the given 3D info to the sound channel. |
* ========================================================================== */ |
void Sound_Set3DInfo( |
const SSpLocalizationData* in3DInfo) |
{ |
OSStatus err; |
Str255 str; |
UnsignedWide time; |
static UnsignedWide prevTime = {0, 0}; |
assert(in3DInfo != NULL); |
// Change the filter |
err = SndSetInfo(gSoundChannel, siSSpLocalization, (SSpLocalizationData*) in3DInfo); |
Message_CheckError(err, "Sound_Set3DInfo", "SndSetInfo"); |
// Update the dialog |
Microseconds(&time); |
Utils_SetUInt32Field( |
gSoundDialog, |
kFeedbackItem_Updates, |
1000000.0 / (time.lo-prevTime.lo), |
true); |
prevTime = time; |
if (gSoundPrev3DInfo.cpuLoad != in3DInfo->cpuLoad) |
{ |
Utils_SetUInt32Field( |
gSoundDialog, |
kFeedbackItem_CPULoad, |
in3DInfo->cpuLoad, |
true); |
gSoundPrev3DInfo.cpuLoad = in3DInfo->cpuLoad; |
} |
if (gSoundPrev3DInfo.medium != in3DInfo->medium) |
{ |
switch (in3DInfo->medium) |
{ |
case kSSpMedium_Air: |
strcpy((char*) str, (char*) "\pkSSpÉAir"); |
break; |
case kSSpMedium_Water: |
strcpy((char*) str, (char*) "\pkSSpÉWater"); |
break; |
default: |
sprintf((char*) str, "x<<%lu>>", (unsigned long) in3DInfo->medium); |
str[0] = strlen((char*) str) - 1; |
} |
Utils_SetStr255Field( |
gSoundDialog, |
kFeedbackItem_Medium, |
str, |
true); |
gSoundPrev3DInfo.medium = in3DInfo->medium; |
} |
if (gSoundPrev3DInfo.humidity != in3DInfo->humidity) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Humidity, |
in3DInfo->humidity, |
true); |
gSoundPrev3DInfo.humidity = in3DInfo->humidity; |
} |
if (gSoundPrev3DInfo.roomSize != in3DInfo->roomSize) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_RoomSize, |
in3DInfo->roomSize, |
true); |
gSoundPrev3DInfo.roomSize = in3DInfo->roomSize; |
} |
if (gSoundPrev3DInfo.roomReflectivity != in3DInfo->roomReflectivity) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_RoomReflectivity, |
in3DInfo->roomReflectivity, |
true); |
gSoundPrev3DInfo.roomReflectivity = in3DInfo->roomReflectivity; |
} |
if (gSoundPrev3DInfo.reverbAttenuation != in3DInfo->reverbAttenuation) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_ReverbAttenuation, |
in3DInfo->reverbAttenuation, |
true); |
gSoundPrev3DInfo.reverbAttenuation = in3DInfo->reverbAttenuation; |
} |
if (gSoundPrev3DInfo.sourceMode != in3DInfo->sourceMode) |
{ |
switch (in3DInfo->sourceMode) |
{ |
case kSSpSourceMode_Unfiltered: |
strcpy((char*) str, (char*) "\pkSSpÉUnfiltered"); |
break; |
case kSSpSourceMode_Localized: |
strcpy((char*) str, (char*) "\pkSSpÉLocalized"); |
break; |
case kSSpSourceMode_Ambient: |
strcpy((char*) str, (char*) "\pkSSpÉAmbient"); |
break; |
case kSSpSourceMode_Binaural: |
strcpy((char*) str, (char*) "\pkSSpÉBinaural"); |
break; |
default: |
sprintf((char*) str, "x<<%lu>>", (unsigned long) in3DInfo->sourceMode); |
str[0] = strlen((char*) str) - 1; |
} |
Utils_SetStr255Field( |
gSoundDialog, |
kFeedbackItem_SourceMode, |
str, |
true); |
gSoundPrev3DInfo.sourceMode = in3DInfo->sourceMode; |
} |
if (gSoundPrev3DInfo.referenceDistance != in3DInfo->referenceDistance) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_ReferenceDistance, |
in3DInfo->referenceDistance, |
true); |
gSoundPrev3DInfo.referenceDistance = in3DInfo->referenceDistance; |
} |
if (gSoundPrev3DInfo.coneAngleCos != in3DInfo->coneAngleCos) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_ConeAngleCos, |
in3DInfo->coneAngleCos, |
true); |
gSoundPrev3DInfo.coneAngleCos = in3DInfo->coneAngleCos; |
} |
if (gSoundPrev3DInfo.coneAttenuation != in3DInfo->coneAttenuation) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_ConeAttenuation, |
in3DInfo->coneAttenuation, |
true); |
gSoundPrev3DInfo.coneAttenuation = in3DInfo->coneAttenuation; |
} |
if (gSoundPrev3DInfo.currentLocation.elevation != in3DInfo->currentLocation.elevation) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Elevation, |
in3DInfo->currentLocation.elevation, |
true); |
gSoundPrev3DInfo.currentLocation.elevation = in3DInfo->currentLocation.elevation; |
} |
if (gSoundPrev3DInfo.currentLocation.azimuth != in3DInfo->currentLocation.azimuth) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Azimuth, |
in3DInfo->currentLocation.azimuth, |
true); |
gSoundPrev3DInfo.currentLocation.azimuth = in3DInfo->currentLocation.azimuth; |
} |
if (gSoundPrev3DInfo.currentLocation.distance != in3DInfo->currentLocation.distance) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Distance, |
in3DInfo->currentLocation.distance, |
true); |
gSoundPrev3DInfo.currentLocation.distance = in3DInfo->currentLocation.distance; |
} |
if (gSoundPrev3DInfo.currentLocation.projectionAngle != in3DInfo->currentLocation.projectionAngle) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_ProjectionAngle, |
in3DInfo->currentLocation.projectionAngle, |
true); |
gSoundPrev3DInfo.currentLocation.projectionAngle = in3DInfo->currentLocation.projectionAngle; |
} |
if (gSoundPrev3DInfo.currentLocation.sourceVelocity != in3DInfo->currentLocation.sourceVelocity) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_SourceVelocity, |
in3DInfo->currentLocation.sourceVelocity, |
true); |
gSoundPrev3DInfo.currentLocation.sourceVelocity = in3DInfo->currentLocation.sourceVelocity; |
} |
if (gSoundPrev3DInfo.currentLocation.listenerVelocity != in3DInfo->currentLocation.listenerVelocity) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_ListenerVelocity, |
in3DInfo->currentLocation.listenerVelocity, |
true); |
gSoundPrev3DInfo.currentLocation.listenerVelocity = in3DInfo->currentLocation.listenerVelocity; |
} |
if (gSoundPrev3DInfo.reserved0 != in3DInfo->reserved0) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Reserved0, |
in3DInfo->reserved0, |
true); |
gSoundPrev3DInfo.reserved0 = in3DInfo->reserved0; |
} |
if (gSoundPrev3DInfo.reserved1 != in3DInfo->reserved1) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Reserved1, |
in3DInfo->reserved1, |
true); |
gSoundPrev3DInfo.reserved1 = in3DInfo->reserved1; |
} |
if (gSoundPrev3DInfo.reserved2 != in3DInfo->reserved2) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Reserved2, |
in3DInfo->reserved2, |
true); |
gSoundPrev3DInfo.reserved2 = in3DInfo->reserved2; |
} |
if (gSoundPrev3DInfo.reserved3 != in3DInfo->reserved3) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_Reserved3, |
in3DInfo->reserved3, |
true); |
gSoundPrev3DInfo.reserved3 = in3DInfo->reserved3; |
} |
if (gSoundPrev3DInfo.virtualSourceCount != in3DInfo->virtualSourceCount) |
{ |
Utils_SetFloatField( |
gSoundDialog, |
kFeedbackItem_VirtualSourceCount, |
in3DInfo->virtualSourceCount, |
true); |
gSoundPrev3DInfo.virtualSourceCount = in3DInfo->virtualSourceCount; |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14