/*============================================================================= Name : SoundEventPlay.c Purpose : Sound Event Play functions Created 5/8/98 by salfreds Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include "SoundEventPrivate.h" #include "soundevent.h" #include "gun.h" #include "matrix.h" #define OBJ_None -1 #define OBJ_Gun -2 #define EFFECT_SIZE 500.0f extern real32 volSFX; typedef struct { sdword max; sdword handle[2]; } effectHandles; effectHandles effectHandle[NUM_HIT_EVENTS]; void SEinitHandles(void) { sdword i; for (i = 0; i < NUM_HIT_EVENTS; i++) { if ((i == Hit_Nick) || (i == Hit_Ricochet)) { effectHandle[i].max = 1; } else { effectHandle[i].max = 2; } effectHandle[i].handle[0] = SOUND_NOTINITED; effectHandle[i].handle[1] = SOUND_NOTINITED; } } /*----------------------------------------------------------------------------- Name : soundEventPlay Description : Inputs : object - pointer to a spaceobj, ie a Ship or an Effect event - the sound event to play gun - pointer to a gun if this is a gun event Outputs : Return : handle to the sound, this can be used to turn off the sound later ----------------------------------------------------------------------------*/ sdword soundEventPlay(void *object, sdword event, Gun *gun) { sdword handle = SOUND_NOTINITED; #if SOUND Ship *ship; sword vol; sword pan; sdword i; real32 dist; real32 velocity = 0.0f; real32 velratio = 1.0f; sdword priority = SOUND_PRIORITY_MIN; SpaceObj *spaceobject; Effect *effect; ObjType objtype; real32 tempEQ[SOUND_EQ_SIZE]; sdword eventflag; ShipClass shipclass; if (!enableSFX) { return (SOUND_OK); } if (object != NULL) { spaceobject = (SpaceObj *)object; if (!univSpaceObjInRenderList(spaceobject) && (event != Ship_Hyperdrive) && (event != Ship_HyperdriveOff) && (event != Ship_SinglePlayerHyperspace)) { return (handle); // only do sound events for viewable objects } if (gun != NULL) { objtype = OBJ_Gun; } else { objtype = spaceobject->objtype; } dist = fsqrt(spaceobject->cameraDistanceSquared); } else { objtype = OBJ_None; } if (event & SFX_Flag_Mask) { eventflag = event & SFX_Flag_Mask; // new stuff switch (eventflag) { case UI_Flag: if (event <= UI_Trading) { // play the ambient sound soundstop(ambienthandle, SOUND_FADE_STOPTIME); ambienthandle = splayPRV(UIBank, UIEventsLUT->lookup[GetPatch(UIEventsLUT, 0, event)], SOUND_PAN_CENTER, SOUND_PRIORITY_STREAM, (sword)(SFX_AMBIENT_VOLUME * volSFX)); } else { handle = splayFPRVL(UIBank, UIEventsLUT->lookup[GetPatch(UIEventsLUT, 0, event)], NULL, (real32)SOUND_DEFAULT, SOUND_PAN_CENTER, SOUND_PRIORITY_MAX, (sword)(SOUND_VOL_MAX * volSFX), FALSE, FALSE, FALSE); } break; case Gun_Flag: if (smSensorsActive || !mrRenderMainScreen) { // don't want to play this sound from the manager screens break; } ship = (Ship *)object; dbgAssert(gun != NULL); dbgAssert(gun->gunstatic != NULL); if (gun->gunstatic->gunsoundtype >= GunEventsLUT->numobjects) { break; } if (event == Gun_WeaponFireLooped) { if ((!SEinrange(gun->gunstatic->gunsoundtype + GUNSHOT_OFFSET, dist)) || // is it in range (ship->soundevent.burstHandle != SOUND_NOTINITED) || // does the sound engine think its already playing !soundover(ship->soundevent.burstHandle)) // is it actually still playing { break; } ship->soundevent.burstfiring = TRUE; priority = SOUND_PRIORITY_MAX; vol = (sdword)(SEequalize(gun->gunstatic->gunsoundtype + GUNSHOT_OFFSET, dist, tempEQ) * (1.0f - (ship->soundevent.coverage * 0.5))); pan = getPanAngle(ship->posinfo.position, ship->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); handle = splayEPRV(GunBank, GunEventsLUT->lookup[GetPatch(GunEventsLUT, gun->gunstatic->gunsoundtype, event)], tempEQ, pan, priority, vol); ship->soundevent.burstHandle = handle; } else if (event == Gun_WeaponShot) { if (!SEinrange(gun->gunstatic->gunsoundtype + GUNSHOT_OFFSET, dist) || !soundover(ship->soundevent.gunHandle)) { break; } priority = SOUND_PRIORITY_HIGH; vol = (sdword)(SEequalize(gun->gunstatic->gunsoundtype + GUNSHOT_OFFSET, dist, tempEQ) * (1.0f - ship->soundevent.coverage)); pan = getPanAngle(ship->posinfo.position, ship->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); handle = splayEPRV(GunBank, GunEventsLUT->lookup[GetPatch(GunEventsLUT, gun->gunstatic->gunsoundtype, event)], tempEQ, pan, priority, vol); ship->soundevent.gunHandle = handle; } else // event = Gun_WeaponMove { if (!SEinrange(gun->gunstatic->gunsoundtype + GUNMOVE_OFFSET, dist) || !soundover(ship->soundevent.gunHandle)) { break; } priority = SOUND_PRIORITY_MIN; vol = (sdword)(SEequalize(gun->gunstatic->gunsoundtype + GUNMOVE_OFFSET, dist, tempEQ) * (1.0f - ship->soundevent.coverage)); pan = getPanAngle(ship->posinfo.position, ship->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); handle = splayEPRV(GunBank, GunEventsLUT->lookup[GetPatch(GunEventsLUT, gun->gunstatic->gunsoundtype, event)], tempEQ, pan, priority, vol); } break; case ShipCmn_Flag: if (smSensorsActive || !mrRenderMainScreen) { // don't want to play this sound from the manager screens break; } if (objtype != OBJ_ShipType) { break; } ship = (Ship *)object; shipclass = ship->staticinfo->shipclass; if (SEinrange(shipclass, dist)) { if (event == ShipCmn_Engine) { if (ship->soundevent.engineHandle != SOUND_NOTINITED) { break; } ship->soundevent.engineState = SOUND_STARTING; if (shipclass == CLASS_Corvette) { priority = SOUND_PRIORITY_MAX - 1; } else if (shipclass == CLASS_Fighter) { priority = SOUND_PRIORITY_MAX - 2; } else { priority = SOUND_PRIORITY_MAX; } vol = SEequalize(shipclass, dist, tempEQ); if ((shipclass == CLASS_Fighter) || (shipclass == CLASS_Corvette)) { vol = (sword)(vol * (1.0f - ship->soundevent.coverage)); } } else { vol = SEequalize(shipclass + AMBIENT_OFFSET, dist, tempEQ); vol = (sword)(vol * (1.0f - ship->soundevent.coverage)); } pan = getPanAngle(ship->posinfo.position, ship->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); if (ship->shiptype < ShipCmnEventsLUT->numobjects) { handle = splayEPRV(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, event)], tempEQ, pan, priority, vol); } if (event == ShipCmn_Engine) { ship->soundevent.engineHandle = handle; if (handle == SOUND_ERR) { ship->soundevent.engineState = SOUND_NOTINITED; } } } break; case Ship_Flag: if (smSensorsActive || !mrRenderMainScreen) { // don't want to play this sound from the manager screens break; } if (objtype != OBJ_ShipType) { // can't do ship events if its not a ship break; } ship = (Ship *)object; if (!SEinrange(ship->staticinfo->shipclass, dist) && (event != Ship_SelectProbe) && (event != Ship_SinglePlayerHyperspace)) { // the Ship_SelectProbe event doesn't have a range limit on it, // neither does the Ship_SinglePlayerHyperspace // so only break if its out of range and its not that event. break; } if ((event != Ship_SelectProbe) && (event != Ship_SinglePlayerHyperspace)) { // calculate the volume and EQ vol = SEequalize(ship->staticinfo->shipclass, dist, tempEQ); } else { // this is played at a constant volume with no EQ vol = (sword)(SFX_AMBIENT_VOLUME * volSFX); for (i = 0; i < SOUND_EQ_SIZE; i++) { tempEQ[i] = 1.0f; } } pan = getPanAngle(ship->posinfo.position, ship->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); priority = SOUND_PRIORITY_NORMAL; if ((event == Ship_Hyperdrive) || (event == Ship_HyperdriveOff)) { handle = splayPRV(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, event)], SOUND_PAN_CENTER, SOUND_PRIORITY_MAX, vol); ship->soundevent.hyperspaceHandle = handle; } else if (event == Ship_SinglePlayerHyperspace) { handle = splayPRV(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, event)], SOUND_PAN_CENTER, SOUND_PRIORITY_MAX, (sword)(SFX_HYPERSPACE_VOLUME * volSFX)); } else { handle = splayEPRV(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, event)], tempEQ, pan, SOUND_PRIORITY_NORMAL, vol); } break; case Derelict_Flag: dbgMessagef("SoundEventPlay: Derelict event %d\n", event); break; case Exp_Flag: if (smSensorsActive || !mrRenderMainScreen) { // don't want to play this sound from the manager screens break; } dbgMessagef("SoundEventPlay: Explosion event %d\n", event); effect = (Effect *)object; dist = (real32)fsqrt(effect->cameraDistanceSquared); if (SEinrange((event - Exp_Flag) + EXPLOSION_OFFSET, dist)) { vol = SEequalize((event - Exp_Flag) + EXPLOSION_OFFSET, dist, tempEQ); pan = getPanAngle(effect->posinfo.position, EFFECT_SIZE, dist); handle = splayEPRV(SpecialEffectBank, SpecExpEventsLUT->lookup[GetPatch(SpecExpEventsLUT, 0, event)], tempEQ, pan, SOUND_PRIORITY_MAX + 1, vol); } break; case Hit_Flag: if (smSensorsActive || !mrRenderMainScreen) { // don't want to play this sound from the manager screens break; } effect = (Effect *)object; if (SEinrangeSqr((event - Hit_Flag) + HIT_OFFSET, effect->cameraDistanceSquared)) // && // soundover(effectHandle)) { for (i = 0; i < effectHandle[event & SFX_Event_Mask].max; i++) { if (soundover(effectHandle[event & SFX_Event_Mask].handle[i])) { dist = (real32)fsqrt(effect->cameraDistanceSquared); vol = SEequalize((event - Hit_Flag) + HIT_OFFSET, dist, tempEQ); pan = getPanAngle(effect->posinfo.position, EFFECT_SIZE, dist); handle = splayEPRV(SpecialEffectBank, SpecHitEventsLUT->lookup[GetPatch(SpecHitEventsLUT, 0, event)], tempEQ, pan, SOUND_PRIORITY_HIGH, vol); effectHandle[event & SFX_Event_Mask].handle[i] = handle; break; } } } break; default: dbgMessagef("\nsoundEventPlaySound: %d event", event); break; } } #endif return (handle); } /*----------------------------------------------------------------------------- Name : soundEffect Description : This is just a wrapper for soundEventPlay since the ETG doesn't like it when I use a #define for soundEffect. Inputs : effect - pointer to an Effect event - the sound event to play Outputs : Return : handle to the sound, this can be used to turn off the sound later ----------------------------------------------------------------------------*/ sdword soundEffect(void *effect, sdword event) { return (soundEventPlay(effect, event, NULL)); } /*----------------------------------------------------------------------------- Name : soundEffectType Description : Inputs : effect - pointer to an Effect event - the sound event to play objecttype - the type of object playing the event (gun sound type) Outputs : Return : handle to the sound, this can be used to turn off the sound later ----------------------------------------------------------------------------*/ sdword soundEffectType(Effect *effect, sdword event, sdword objecttype) { sdword handle = SOUND_NOTINITED; sword vol; sword pan; real32 dist; sdword priority = SOUND_PRIORITY_MIN; real32 tempEQ[SOUND_EQ_SIZE]; sdword eventflag; if (!enableSFX) { return (SOUND_OK); } if (event & SFX_Flag_Mask) { eventflag = event & SFX_Flag_Mask; switch (eventflag) { case Hit_Flag: if (smSensorsActive || !mrRenderMainScreen) { // don't want to play this sound from the manager screens break; } if (SEinrangeSqr((event - Hit_Flag) + HIT_OFFSET, effect->cameraDistanceSquared)) { dist = (real32)fsqrt(effect->cameraDistanceSquared); vol = SEequalize((event - Hit_Flag) + HIT_OFFSET, dist, tempEQ); pan = getPanAngle(effect->posinfo.position, EFFECT_SIZE, dist); handle = splayEPRV(SpecialEffectBank, SpecHitEventsLUT->lookup[GetPatch(SpecHitEventsLUT, objecttype, event)], tempEQ, pan, SOUND_PRIORITY_NORMAL, vol); } break; default: dbgMessagef("\nShould use soundEffect for %d event instead.", event); break; } } return (handle); }