home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: DZFake3DSound.c
- * Author: Dan Venolia
- *
- * Contents: Diverts off the calls to SndSetInfo that are destined for the
- * 3D sound localization component. A useful debugging tool.
- *
- * Copyright © 1996 Apple Computer, Inc.
- */
-
- #include <assert.h>
- #include <math.h>
- #include <Resources.h>
-
- #include <Sound.h>
-
- #include "SoundSprocket.h"
-
- #include "DZFake3DSound.h"
-
- #if FAKE_3D_SOUND
-
- #undef SndSetInfo
- #undef SndGetInfo
-
-
- static SpeakerKind gSpeakerKind = kSpeakerKindStereo;
- static float gSpeakerAngle = 3.14159*0.16667; // 30°
-
-
- static OSErr FakeGet3DCPULoadLimit(
- SndChannelPtr inSndChannel,
- UInt32* outCPULoadLimit);
-
- static OSErr FakeSet3DSetup(
- SndChannelPtr inSndChannel,
- const Snd3DSetup* in3DSetup);
-
- static OSErr FakeGet3DSetup(
- SndChannelPtr inSndChannel,
- Snd3DSetup* out3DSetup);
-
- static OSErr FakeSet3DInfo(
- SndChannelPtr inSndChannel,
- const Snd3DInfo* in3DInfo);
-
-
- /* =============================================================================
- * FakeSndSetInfo
- *
- * Overrides the behavior of SndSetInfo for selected messages.
- * ========================================================================== */
- OSErr FakeSndSetInfo(
- SndChannelPtr inSndChannel,
- OSType inSelector,
- void* inData)
- {
- OSErr err;
-
- switch (inSelector)
- {
-
- #ifdef FAKE_3D_INSTALL_ONLY
- case si3DInstall:
- {
-
- #ifdef REAL_3D_INSTALL
- SoundComponentLink link;
-
- link.description.componentType = kSoundEffectsType;
- link.description.componentSubType = 'snd3';
- link.description.componentManufacturer = 'appl'; // set to zero for default/any
- link.description.componentFlags = 0;
- link.description.componentFlagsMask = 0;
- link.mixerID = nil;
- err = SndSetInfo(inSndChannel, siPreMixerSoundComponent, &link);
- #else
-
- SndListHandle sndHdl = (SndListHandle)GetResource(soundListRsrc, 1000);
- if (sndHdl)
- {
- HLock((Handle)sndHdl);
- err = SndPlay(inSndChannel, sndHdl, false);
- ReleaseResource((Handle)sndHdl);
- HUnlock((Handle)sndHdl);
- }
- else err = ResError();
- #endif
-
- }
- break;
- #else
- case si3DInstall:
- err = noErr;
- break;
-
- case si3DSetup:
- err = FakeSet3DSetup(inSndChannel, (const Snd3DSetup*) inData);
- break;
-
- case si3DInfo:
- err = FakeSet3DInfo(inSndChannel, (const Snd3DInfo*) inData);
- break;
- #endif
-
- default:
- err = SndSetInfo(inSndChannel, inSelector, inData);
- }
-
- return err;
- }
-
-
- /* =============================================================================
- * FakeSndGetInfo
- *
- * Overrides the behavior of SndGetInfo for selected messages.
- * ========================================================================== */
- OSErr FakeSndGetInfo(
- SndChannelPtr inSndChannel,
- OSType inSelector,
- void* outData)
- {
- OSErr err;
-
- switch (inSelector)
- {
- #ifndef FAKE_3D_INSTALL_ONLY
- case si3DCPULoadLimit:
- err = FakeGet3DCPULoadLimit(inSndChannel, (UInt32*) outData);
- break;
-
- case si3DSetup:
- err = FakeGet3DSetup(inSndChannel, (Snd3DSetup*) outData);
- break;
- #endif
-
- default:
- err = SndGetInfo(inSndChannel, inSelector, outData);
- }
-
- return err;
- }
-
-
- /* =============================================================================
- * FakeGet3DCPULoadLimit(internal)
- *
- * Returns the CPU load limit.
- * ========================================================================== */
- OSErr FakeGet3DCPULoadLimit(
- SndChannelPtr inSndChannel,
- UInt32* outCPULoadLimit)
- {
- assert(outCPULoadLimit != NULL);
-
- *outCPULoadLimit = 6; //• or whatever
-
- return noErr;
- }
-
-
- /* =============================================================================
- * FakeSet3DSetup (internal)
- *
- * Salts away the info in globals.
- * ========================================================================== */
- OSErr FakeSet3DSetup(
- SndChannelPtr inSndChannel,
- const Snd3DSetup* in3DSetup)
- {
- assert(in3DSetup != NULL);
- assert(in3DSetup->version == 1);
-
- gSpeakerKind = in3DSetup->speakerKind;
- gSpeakerAngle = in3DSetup->speakerAngle;
-
- return noErr;
- }
-
-
- /* =============================================================================
- * FakeSet3DSetup (internal)
- *
- * Returns the global storage for the speaker setup.
- * ========================================================================== */
- OSErr FakeGet3DSetup(
- SndChannelPtr inSndChannel,
- Snd3DSetup* out3DSetup)
- {
- assert(out3DSetup != NULL);
-
- out3DSetup->version = 1;
- out3DSetup->speakerKind = gSpeakerKind;
- out3DSetup->speakerAngle = gSpeakerAngle;
- out3DSetup->reserved0 = 0;
- out3DSetup->reserved1 = 0;
-
- return noErr;
- }
-
-
- /* =============================================================================
- * FakeSet3DInfo (internal)
- *
- * Sends volumeCmd and rateMultiplierCmd to the sound channel for a cheesy
- * version of localized sound. Note: this is incompatible with an app that
- * uses the volumeCmd or rateMultiplierCmd itself since we stomp them.
- * ========================================================================== */
- OSErr FakeSet3DInfo(
- SndChannelPtr inSndChannel,
- const Snd3DInfo* in3DInfo)
- {
- #define kMinVolume 0.0 // Lowest volume setting
- #define kMaxVolume 4.0 // Highest volume setting -- must be less than 256!
- #define kSpeedOfSound 344.0 // Speed of sound
-
- OSErr err;
- float amplitude;
- float speakerAngle;
- float norm;
- float leftAmplitude;
- float rightAmplitude;
- float coneAttenuation;
- float rateMultiplier;
- SndCommand sndCommand;
-
- // Validate parameters
- assert(inSndChannel != NULL);
- assert(in3DInfo != NULL);
-
- if (in3DInfo->sourceMode == kSourceModeLocalized)
- {
- // Find the distance attenuation
- amplitude = (in3DInfo->referenceDistance / in3DInfo->currentLocation.distance);
-
- // Do the angular attenuation
- coneAttenuation = in3DInfo->coneAttenuation;
- if (coneAttenuation != 0.0)
- {
- // Check whether we're inside the cone
- if (in3DInfo->currentLocation.projectionAngle >
- in3DInfo->coneAngleCos)
- {
- // Inside the cone -- blend the attenuation
- coneAttenuation *=
- (1.0-in3DInfo->currentLocation.projectionAngle) /
- (1.0-in3DInfo->coneAngleCos);
- }
-
- amplitude *= powf(10.0, 0.05*coneAttenuation);
- }
-
- // Compute the left and right speaker amplitudes
- if (gSpeakerKind == kSpeakerKindMono)
- {
- leftAmplitude = amplitude;
- rightAmplitude = amplitude;
- }
- else
- {
- // Find the speaker spread
- if (gSpeakerKind == kSpeakerKindStereo)
- {
- speakerAngle = gSpeakerAngle;
- }
- else
- {
- // Headphones -- 180°
- speakerAngle = _PI;
- }
-
- // Compute the panned amplitudes
- norm = in3DInfo->currentLocation.latitude/(0.5*speakerAngle);
-
- if (norm <= -1.0)
- {
- // To the left
- leftAmplitude = amplitude;
- rightAmplitude = 0.0;
- }
- else if (norm >= 1.0)
- {
- // To the right
- leftAmplitude = 0.0;
- rightAmplitude = amplitude;
- }
- else
- {
- // In the center
- leftAmplitude = amplitude * cosf((norm + 1.0) * (0.25*_PI));
- rightAmplitude = amplitude * cosf((1.0 - norm) * (0.25*_PI));
- }
- }
-
- // Pin the amplitude within the acceptable range
- if (leftAmplitude < kMinVolume) leftAmplitude = kMinVolume;
- if (leftAmplitude > kMaxVolume) leftAmplitude = kMaxVolume;
-
- if (rightAmplitude < kMinVolume) rightAmplitude = kMinVolume;
- if (rightAmplitude > kMaxVolume) rightAmplitude = kMaxVolume;
-
- // Compute the Doppler shift
- rateMultiplier = (kSpeedOfSound + in3DInfo->currentLocation.listenerVelocity) /
- (kSpeedOfSound - in3DInfo->currentLocation.sourceVelocity);
-
- //• TODO: fail gracefully when over mach 1
- //• TODO: pin to a reasonable range (?)
- }
- else
- {
- // Just play the sound
- leftAmplitude = 1.0;
- rightAmplitude = 1.0;
-
- rateMultiplier = 1.0;
- }
-
- // Change the left and right amplitudes
- sndCommand.cmd = volumeCmd;
- sndCommand.param1 = 0;
- sndCommand.param2 = ((long) (rightAmplitude * 0x0100)) << 16 |
- ((long) (leftAmplitude * 0x0100));
- err = SndDoImmediate(inSndChannel, &sndCommand);
-
- if (err != noErr)
- {
- return err;
- }
-
- // Change the rate multiplier
- sndCommand.cmd = rateMultiplierCmd;
- sndCommand.param1 = 0;
- sndCommand.param2 = (long)(rateMultiplier*65536.0 + 0.5);
- err = SndDoImmediate(inSndChannel, &sndCommand);
-
- if (err != noErr)
- {
- return err;
- }
-
- return noErr;
- }
-
-
- #endif /* FAKE_3D_SOUND */
-
-
-