diff --git a/SpaceCadetPinball/Sound.cpp b/SpaceCadetPinball/Sound.cpp index 3959df0..4e5f317 100644 --- a/SpaceCadetPinball/Sound.cpp +++ b/SpaceCadetPinball/Sound.cpp @@ -1,3 +1,4 @@ +#include "options.h" #include "pch.h" #include "Sound.h" @@ -41,7 +42,7 @@ void Sound::Close() Mix_Quit(); } -void Sound::PlaySound(Mix_Chunk* wavePtr, int time) +void Sound::PlaySound(Mix_Chunk* wavePtr, int time, TPinballComponent *soundSource, const char* info) { if (wavePtr && enabled_flag) { @@ -52,8 +53,91 @@ void Sound::PlaySound(Mix_Chunk* wavePtr, int time) } auto channel = Mix_PlayChannel(-1, wavePtr, 0); - if (channel != -1) + if (channel != -1) { TimeStamps[channel] = time; + if (options::Options.SoundStereo) { + /* Think 3D sound positioning, where: + * - x goes from 0 to 1, left to right on the screen, + * - y goes from 0 to 1, top to bottom on the screen, + * - z goes from 0 to infinity, from table-level to the sky. + * + * We position the listener at the bottom center of the table, + * at 0.5 height, so roughly a table half-length. Coords of + * the listener are thus {0.5, 1.0, 0.5}. + * + * We use basic trigonometry to calculate the angle and distance + * from a sound source to the listener. + * + * Mix_SetPosition expects an angle in (Sint16)degrees, where + * 0 degrees is in front, 90 degrees is to the right, and so on. + * Mix_SetPosition expects a (Uint8)distance from 0 (near) to 255 (far). + */ + + /* Get the sound source position. */ + vector2 coordinates; + /* Some sounds are unpositioned; for that case the caller sends + * a NULL pointer as a soundSource; in those cases we position + * the sound at the center top of the table. + */ + if (!soundSource) { + coordinates.X = 0.5f; + coordinates.Y = 0.0f; + } + else { + coordinates = soundSource->get_coordinates(); + }; + + /* Player position. */ + auto pX = 0.5f; + auto pY = 1.0f; + auto pZ = 0.5f; + + /* Calculate lengths of three sides of a triangle. + * ptos (Player-to-sound): distance from listener to the sound source, + * ptom (player-to-middle): distance from listener to the sound source + * when the latter is repositioned to the + * X center, + * stom (sound-to-middle): distance from ptos to ptom. + */ + auto ptos = sqrt(((coordinates.X - pX) * (coordinates.X - pX)) + ((coordinates.Y - pY) * (coordinates.Y - pY)) + (pZ * pZ)); + auto ptom = sqrt(((coordinates.Y - pY) * (coordinates.Y - pY)) + (pZ * pZ)); + auto stom = fabs(coordinates.X - 0.5); + + /* Calculate the angle using the law of cosines and acos(). + * That will return an angle in radians, e.g. in the [0,PI] range; + * we remap to [0,180], and cast to an integer. + */ + Sint16 angle = (Sint16)(acos(((stom * stom) - (ptos * ptos) - (ptom * ptom)) / (-2.0f * ptos * ptom)) * 180.0f / IM_PI); + + /* Because we are using distances to calculate the angle, + * we now have no clue if the sound is to the right or the + * left. If the sound is to the right, the current value + * is good, but to the left, we need substract it from 360. + */ + if (coordinates.X < 0.5) { + angle = (360 - angle); + } + + /* Distance from listener to the ball (ptos) is roughly + * in the [0.5,1.55] range; remap to 50-155 by multiplying + * by 100 and cast to an integer. */ + Uint8 distance = (Uint8)(100.0f * ptos); + Mix_SetPosition(channel, angle, distance); + + /* Output position of each sound emitted so we can verify + * the sanity of the implementation. + */ + /* + printf("X: %3.3f Y: %3.3f Angle: %3d Distance: %3d, Object: %s\n", + coordinates.X, + coordinates.Y, + angle, + distance, + info + ); + */ + } + } } } diff --git a/SpaceCadetPinball/Sound.h b/SpaceCadetPinball/Sound.h index 2e2c3ca..000c503 100644 --- a/SpaceCadetPinball/Sound.h +++ b/SpaceCadetPinball/Sound.h @@ -1,4 +1,5 @@ #pragma once +#include "TPinballComponent.h" class Sound @@ -9,7 +10,7 @@ public: static void Activate(); static void Deactivate(); static void Close(); - static void PlaySound(Mix_Chunk* wavePtr, int time); + static void PlaySound(Mix_Chunk* wavePtr, int time, TPinballComponent *soundSource, const char* info); static Mix_Chunk* LoadWaveFile(const std::string& lpName); static void FreeSound(Mix_Chunk* wave); static void SetChannels(int channels); diff --git a/SpaceCadetPinball/TBall.cpp b/SpaceCadetPinball/TBall.cpp index d05130b..d53dc1f 100644 --- a/SpaceCadetPinball/TBall.cpp +++ b/SpaceCadetPinball/TBall.cpp @@ -135,3 +135,12 @@ void TBall::throw_ball(TBall* ball, vector3* direction, float angleMult, float s rnd = RandFloat(); ball->Speed = (1.0f - (rnd + rnd)) * (speedMult1 * speedMult2) + speedMult1; } + +vector2 TBall::get_coordinates() +{ + vector2 coordinates; + vector2i pos2D = proj::xform_to_2d(Position); + coordinates.X = (float)pos2D.X / PinballTable->Width; + coordinates.Y = (float)pos2D.Y / PinballTable->Height; + return coordinates; +} diff --git a/SpaceCadetPinball/TBall.h b/SpaceCadetPinball/TBall.h index b596f01..b451dd2 100644 --- a/SpaceCadetPinball/TBall.h +++ b/SpaceCadetPinball/TBall.h @@ -13,6 +13,7 @@ public : void not_again(TEdgeSegment* edge); bool already_hit(TEdgeSegment* edge); int Message(int code, float value) override; + vector2 get_coordinates(); static void throw_ball(TBall* ball, vector3* direction, float angleMult, float speedMult1, float speedMult2); diff --git a/SpaceCadetPinball/TBlocker.cpp b/SpaceCadetPinball/TBlocker.cpp index 41bc3c2..1bd083d 100644 --- a/SpaceCadetPinball/TBlocker.cpp +++ b/SpaceCadetPinball/TBlocker.cpp @@ -40,11 +40,11 @@ int TBlocker::Message(int code, float value) ActiveFlag = 0; render::sprite_set_bitmap(RenderSprite, nullptr); if (code == 51) - loader::play_sound(SoundIndex3); + loader::play_sound(SoundIndex3, this, "TBlocker1"); return 0; case 52: ActiveFlag = 1; - loader::play_sound(SoundIndex4); + loader::play_sound(SoundIndex4, this, "TBlocker2"); render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0)); break; case 59: diff --git a/SpaceCadetPinball/TBumper.cpp b/SpaceCadetPinball/TBumper.cpp index 9575d82..ecb6fcc 100644 --- a/SpaceCadetPinball/TBumper.cpp +++ b/SpaceCadetPinball/TBumper.cpp @@ -36,9 +36,9 @@ int TBumper::Message(int code, float value) if (nextBmp != BmpIndex) { if (nextBmp >= BmpIndex) - loader::play_sound(SoundIndex4); + loader::play_sound(SoundIndex4, this, "TBumper1"); if (nextBmp < BmpIndex) - loader::play_sound(SoundIndex3); + loader::play_sound(SoundIndex3, this, "TBumper2"); BmpIndex = nextBmp; Fire(); control::handler(11, this); diff --git a/SpaceCadetPinball/TCollisionComponent.cpp b/SpaceCadetPinball/TCollisionComponent.cpp index 96d4fd7..a779c29 100644 --- a/SpaceCadetPinball/TCollisionComponent.cpp +++ b/SpaceCadetPinball/TCollisionComponent.cpp @@ -61,9 +61,9 @@ bool TCollisionComponent::DefaultCollision(TBall* ball, vector2* nextPosition, v auto projSpeed = maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, Threshold, Boost); if (projSpeed > Threshold) - loader::play_sound(HardHitSoundId); + loader::play_sound(HardHitSoundId, ball, "TCollisionComponent1"); else if (projSpeed > 0.2f) - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "TCollisionComponent2"); else return false; return true; @@ -87,9 +87,9 @@ void TCollisionComponent::Collision(TBall* ball, vector2* nextPosition, vector2* Threshold, Boost); if (projSpeed > Threshold) - loader::play_sound(HardHitSoundId); + loader::play_sound(HardHitSoundId, ball, "TCollisionComponent3"); else if (projSpeed > 0.2f) - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "TCollisionComponent4"); } int TCollisionComponent::FieldEffect(TBall* ball, vector2* vecDst) diff --git a/SpaceCadetPinball/TCollisionComponent.h b/SpaceCadetPinball/TCollisionComponent.h index e0d727c..ff58403 100644 --- a/SpaceCadetPinball/TCollisionComponent.h +++ b/SpaceCadetPinball/TCollisionComponent.h @@ -1,9 +1,9 @@ #pragma once #include "TPinballComponent.h" +#include "TBall.h" struct vector2; class TEdgeSegment; -class TBall; class TCollisionComponent : public TPinballComponent { diff --git a/SpaceCadetPinball/TFlagSpinner.cpp b/SpaceCadetPinball/TFlagSpinner.cpp index 235e926..7f80429 100644 --- a/SpaceCadetPinball/TFlagSpinner.cpp +++ b/SpaceCadetPinball/TFlagSpinner.cpp @@ -117,7 +117,7 @@ void TFlagSpinner::NextFrame() { control::handler(63, this); if (SoftHitSoundId) - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, this, "TFlagSpinner"); if (!BmpIndex) control::handler(62, this); } diff --git a/SpaceCadetPinball/TFlipper.cpp b/SpaceCadetPinball/TFlipper.cpp index d2e4bf2..4fece3b 100644 --- a/SpaceCadetPinball/TFlipper.cpp +++ b/SpaceCadetPinball/TFlipper.cpp @@ -73,12 +73,12 @@ int TFlipper::Message(int code, float value) { control::handler(1, this); TimerTime = ExtendAnimationFrameTime; - loader::play_sound(HardHitSoundId); + loader::play_sound(HardHitSoundId, this, "TFlipper1"); } else if (code == 2) { TimerTime = RetractAnimationFrameTime; - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, this, "TFlipper2"); } else { diff --git a/SpaceCadetPinball/TGate.cpp b/SpaceCadetPinball/TGate.cpp index 851571e..5083ffe 100644 --- a/SpaceCadetPinball/TGate.cpp +++ b/SpaceCadetPinball/TGate.cpp @@ -26,14 +26,14 @@ int TGate::Message(int code, float value) { ActiveFlag = 0; render::sprite_set_bitmap(RenderSprite, nullptr); - loader::play_sound(SoundIndex3); + loader::play_sound(SoundIndex3, this, "TGate1"); } else if (code == 54 || code == 1024) { ActiveFlag = 1; render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0)); if (code == 54) - loader::play_sound(SoundIndex4); + loader::play_sound(SoundIndex4, this, "TGate2"); } control::handler(code, this); } diff --git a/SpaceCadetPinball/THole.cpp b/SpaceCadetPinball/THole.cpp index 38cad6f..d76a95a 100644 --- a/SpaceCadetPinball/THole.cpp +++ b/SpaceCadetPinball/THole.cpp @@ -87,7 +87,7 @@ void THole::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl if (!PinballTable->TiltLockFlag) { - loader::play_sound(HardHitSoundId); + loader::play_sound(HardHitSoundId, ball, "THole1"); control::handler(57, this); } } @@ -115,7 +115,7 @@ int THole::FieldEffect(TBall* ball, vector2* vecDst) ball->CollisionComp = nullptr; ball->Direction.X = 0.0; ball->Speed = 0.0; - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "THole2"); control::handler(58, this); } } diff --git a/SpaceCadetPinball/TKickback.cpp b/SpaceCadetPinball/TKickback.cpp index 56cfcdf..28e3e94 100644 --- a/SpaceCadetPinball/TKickback.cpp +++ b/SpaceCadetPinball/TKickback.cpp @@ -62,7 +62,7 @@ void TKickback::TimerExpired(int timerId, void* caller) { kick->Threshold = 0.0; kick->Timer = timer::set(kick->TimerTime2, kick, TimerExpired); - loader::play_sound(kick->HardHitSoundId); + loader::play_sound(kick->HardHitSoundId, kick, "TKickback"); if (kick->ListBitmap) { auto bmp = kick->ListBitmap->at(1); diff --git a/SpaceCadetPinball/TKickout.cpp b/SpaceCadetPinball/TKickout.cpp index 623628c..0f6ff34 100644 --- a/SpaceCadetPinball/TKickout.cpp +++ b/SpaceCadetPinball/TKickout.cpp @@ -122,7 +122,7 @@ void TKickout::Collision(TBall* ball, vector2* nextPosition, vector2* direction, } else { - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "TKickout1"); control::handler(63, this); } } @@ -153,12 +153,12 @@ void TKickout::TimerExpired(int timerId, void* caller) kick->Timer = timer::set(kick->TimerTime2, kick, ResetTimerExpired); if (kick->Ball) { + loader::play_sound(kick->HardHitSoundId, kick->Ball, "TKickout2"); kick->Ball->Position.Z = kick->OriginalBallZ; TBall::throw_ball(kick->Ball, &kick->BallThrowDirection, kick->ThrowAngleMult, kick->ThrowSpeedMult1, kick->ThrowSpeedMult2); kick->ActiveFlag = 0; kick->Ball = nullptr; - loader::play_sound(kick->HardHitSoundId); } } } diff --git a/SpaceCadetPinball/TLightRollover.cpp b/SpaceCadetPinball/TLightRollover.cpp index 7be1064..3ec0f31 100644 --- a/SpaceCadetPinball/TLightRollover.cpp +++ b/SpaceCadetPinball/TLightRollover.cpp @@ -53,7 +53,7 @@ void TLightRollover::Collision(TBall* ball, vector2* nextPosition, vector2* dire } else { - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, this, "TLightRollover"); control::handler(63, this); RolloverFlag = RolloverFlag == 0; if (ListBitmap) diff --git a/SpaceCadetPinball/TOneway.cpp b/SpaceCadetPinball/TOneway.cpp index 7067a53..3c2b70e 100644 --- a/SpaceCadetPinball/TOneway.cpp +++ b/SpaceCadetPinball/TOneway.cpp @@ -51,7 +51,7 @@ void TOneway::Collision(TBall* ball, vector2* nextPosition, vector2* direction, if (!PinballTable->TiltLockFlag) { if (HardHitSoundId) - loader::play_sound(HardHitSoundId); + loader::play_sound(HardHitSoundId, ball, "TOneway1"); control::handler(63, this); } } @@ -69,7 +69,7 @@ void TOneway::Collision(TBall* ball, vector2* nextPosition, vector2* direction, Boost) > 0.2f) { if (SoftHitSoundId) - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "TOneway2"); } } diff --git a/SpaceCadetPinball/TPinballComponent.cpp b/SpaceCadetPinball/TPinballComponent.cpp index e72d6c3..a899ce5 100644 --- a/SpaceCadetPinball/TPinballComponent.cpp +++ b/SpaceCadetPinball/TPinballComponent.cpp @@ -17,6 +17,8 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool ListZMap = nullptr; GroupName = nullptr; Control = nullptr; + Coordinates.X = -1.0f; + Coordinates.Y = -1.0f; if (table) table->ComponentList.push_back(this); if (groupIndex >= 0) @@ -69,6 +71,8 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool rootBmp->XPosition - table->XOffset, rootBmp->YPosition - table->YOffset, &bmp1Rect); + Coordinates.X = (bmp1Rect.XPosition + (bmp1Rect.Width / 2.0f)) / PinballTable->Width; + Coordinates.Y = (bmp1Rect.YPosition + (bmp1Rect.Height / 2.0f)) / PinballTable->Height; } } GroupIndex = groupIndex; @@ -111,3 +115,8 @@ int TPinballComponent::get_scoring(int index) { return 0; } + +vector2 TPinballComponent::get_coordinates() +{ + return this->Coordinates; +} diff --git a/SpaceCadetPinball/TPinballComponent.h b/SpaceCadetPinball/TPinballComponent.h index 8c01f2e..3d32fcf 100644 --- a/SpaceCadetPinball/TPinballComponent.h +++ b/SpaceCadetPinball/TPinballComponent.h @@ -1,4 +1,5 @@ #pragma once +#include "maths.h" struct zmap_header_type; struct gdrv_bitmap8; @@ -23,6 +24,7 @@ public: virtual void port_draw(); virtual void put_scoring(int index, int score); virtual int get_scoring(int index); + virtual vector2 get_coordinates(); char UnusedBaseFlag; char ActiveFlag; @@ -34,4 +36,5 @@ public: TPinballTable* PinballTable; std::vector* ListBitmap; std::vector* ListZMap; + vector2 Coordinates; }; diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index f36e2f5..652cf9b 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -292,7 +292,7 @@ void TPinballTable::tilt(float time) pinball::InfoTextBox->Clear(); pinball::MissTextBox->Clear(); pinball::InfoTextBox->Display(pinball::get_rc_string(35, 0), -1.0); - loader::play_sound(SoundIndex3); + loader::play_sound(SoundIndex3, nullptr, "TPinballTable1"); TiltTimeoutTimer = timer::set(30.0, this, tilt_timeout); for (auto component : ComponentList) @@ -446,7 +446,7 @@ int TPinballTable::Message(int code, float value) pinball::InfoTextBox->Clear(); pinball::MissTextBox->Clear(); LightGroup->Message(28, 0.2f); - auto time = loader::play_sound(SoundIndex1); + auto time = loader::play_sound(SoundIndex1, nullptr, "TPinballTable2"); LightShowTimer = timer::set(time, this, LightShow_timeout); } @@ -543,7 +543,7 @@ int TPinballTable::Message(int code, float value) } break; case 1022: - loader::play_sound(SoundIndex2); + loader::play_sound(SoundIndex2, nullptr, "TPinballTable3"); pinball::MissTextBox->Clear(); pinball::InfoTextBox->Display(pinball::get_rc_string(34, 0), -1.0); EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout); diff --git a/SpaceCadetPinball/TPlunger.cpp b/SpaceCadetPinball/TPlunger.cpp index 2a5454b..619f03a 100644 --- a/SpaceCadetPinball/TPlunger.cpp +++ b/SpaceCadetPinball/TPlunger.cpp @@ -50,7 +50,7 @@ int TPlunger::Message(int code, float value) { Boost = 0.0; Threshold = 1000000000.0; - loader::play_sound(HardHitSoundId); + loader::play_sound(HardHitSoundId, this, "TPlunger1"); PullbackTimer(0, this); } return 0; @@ -70,7 +70,7 @@ int TPlunger::Message(int code, float value) if (BallFeedTimer_) timer::kill(BallFeedTimer_); BallFeedTimer_ = timer::set(0.95999998f, this, BallFeedTimer); - loader::play_sound(SoundIndexP1); + loader::play_sound(SoundIndexP1, this, "TPlunger2"); control::handler(code, this); return 0; case 1017: @@ -95,7 +95,7 @@ int TPlunger::Message(int code, float value) timer::kill(PullbackTimer_); PullbackTimer_ = 0; if (code == 1005) - loader::play_sound(SoundIndexP2); + loader::play_sound(SoundIndexP2, this, "TPlunger3"); auto bmp = ListBitmap->at(0); auto zMap = ListZMap->at(0); render::sprite_set( diff --git a/SpaceCadetPinball/TPopupTarget.cpp b/SpaceCadetPinball/TPopupTarget.cpp index 7a4fe09..98bc56a 100644 --- a/SpaceCadetPinball/TPopupTarget.cpp +++ b/SpaceCadetPinball/TPopupTarget.cpp @@ -79,7 +79,7 @@ void TPopupTarget::Collision(TBall* ball, vector2* nextPosition, vector2* direct this->Boost) > this->Threshold) { if (this->HardHitSoundId) - loader::play_sound(this->HardHitSoundId); + loader::play_sound(this->HardHitSoundId, this, "TPopupTarget1"); this->Message(49, 0.0); control::handler(63, this); } @@ -94,6 +94,6 @@ void TPopupTarget::TimerExpired(int timerId, void* caller) if (timerId) { if (target->SoftHitSoundId) - loader::play_sound(target->SoftHitSoundId); + loader::play_sound(target->SoftHitSoundId, target, "TPopupTarget2"); } } diff --git a/SpaceCadetPinball/TRamp.cpp b/SpaceCadetPinball/TRamp.cpp index 562ef50..7214fcc 100644 --- a/SpaceCadetPinball/TRamp.cpp +++ b/SpaceCadetPinball/TRamp.cpp @@ -164,7 +164,7 @@ void TRamp::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl { if (!PinballTable->TiltLockFlag) { - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "TRamp"); control::handler(63, this); } } diff --git a/SpaceCadetPinball/TRollover.cpp b/SpaceCadetPinball/TRollover.cpp index ac4ecca..45a35eb 100644 --- a/SpaceCadetPinball/TRollover.cpp +++ b/SpaceCadetPinball/TRollover.cpp @@ -54,7 +54,7 @@ void TRollover::Collision(TBall* ball, vector2* nextPosition, vector2* direction } else { - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "TRollover"); control::handler(63, this); } RolloverFlag = RolloverFlag == 0; diff --git a/SpaceCadetPinball/TSink.cpp b/SpaceCadetPinball/TSink.cpp index 2885ad5..70a5904 100644 --- a/SpaceCadetPinball/TSink.cpp +++ b/SpaceCadetPinball/TSink.cpp @@ -86,7 +86,7 @@ void TSink::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl { ball->ActiveFlag = 0; render::sprite_set_bitmap(ball->RenderSprite, nullptr); - loader::play_sound(SoundIndex4); + loader::play_sound(SoundIndex4, ball, "TSink1"); control::handler(63, this); } } @@ -102,6 +102,6 @@ void TSink::TimerExpired(int timerId, void* caller) TBall::throw_ball(ball, &sink->BallThrowDirection, sink->ThrowAngleMult, sink->ThrowSpeedMult1, sink->ThrowSpeedMult2); if (sink->SoundIndex3) - loader::play_sound(sink->SoundIndex3); + loader::play_sound(sink->SoundIndex3, ball, "TSink2"); sink->Timer = 0; } diff --git a/SpaceCadetPinball/TSound.cpp b/SpaceCadetPinball/TSound.cpp index 9e835c8..56a4b30 100644 --- a/SpaceCadetPinball/TSound.cpp +++ b/SpaceCadetPinball/TSound.cpp @@ -10,7 +10,7 @@ TSound::TSound(TPinballTable* table, int groupIndex) : TPinballComponent(table, this->SoundIndex = visual.SoundIndex4; } -float TSound::Play() +float TSound::Play(TPinballComponent *soundSource, const char* info) { - return loader::play_sound(this->SoundIndex); + return loader::play_sound(this->SoundIndex, soundSource, info); } diff --git a/SpaceCadetPinball/TSound.h b/SpaceCadetPinball/TSound.h index aef92eb..5abd837 100644 --- a/SpaceCadetPinball/TSound.h +++ b/SpaceCadetPinball/TSound.h @@ -7,6 +7,7 @@ class TSound : public: TSound(TPinballTable* table, int groupIndex); float Play(); + float Play(TPinballComponent *soundSource, const char* info); int SoundIndex; }; diff --git a/SpaceCadetPinball/TTripwire.cpp b/SpaceCadetPinball/TTripwire.cpp index 4a9c5a4..7808f32 100644 --- a/SpaceCadetPinball/TTripwire.cpp +++ b/SpaceCadetPinball/TTripwire.cpp @@ -19,7 +19,7 @@ void TTripwire::Collision(TBall* ball, vector2* nextPosition, vector2* direction ball->not_again(edge); if (!PinballTable->TiltLockFlag) { - loader::play_sound(SoftHitSoundId); + loader::play_sound(SoftHitSoundId, ball, "TTripwire"); control::handler(63, this); } } diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index 345bc65..b7a8a69 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -932,7 +932,7 @@ void control::pbctrl_bdoor_controller(char key) void control::table_add_extra_ball(float count) { ++TableG->ExtraBalls; - soundwave28->Play(); + soundwave28->Play(nullptr, "table_add_extra_ball"); auto msg = pinball::get_rc_string(9, 0); info_text_box->Display(msg, count); } @@ -981,7 +981,7 @@ void control::table_bump_ball_sink_lock() else { TableG->BallLockedCounter = TableG->BallLockedCounter + 1; - soundwave44->Play(); + soundwave44->Play(nullptr, "table_bump_ball_sink_lock"); info_text_box->Display(pinball::get_rc_string(1, 0), 2.0); TableG->Plunger->Message(1016, 0.0); } @@ -1004,7 +1004,7 @@ void control::cheat_bump_rank() auto rankText = pinball::get_rc_string(RankRcArray[rank], 1); snprintf(Buffer,sizeof Buffer, pinball::get_rc_string(83, 0), rankText); mission_text_box->Display(Buffer, 8.0); - soundwave10->Play(); + soundwave10->Play(nullptr, "cheat_bump_rank"); } } @@ -1055,7 +1055,7 @@ int control::AddRankProgress(int rank) auto rankText = pinball::get_rc_string(RankRcArray[midActiveCount], 1); snprintf(Buffer, sizeof Buffer, pinball::get_rc_string(83, 0), rankText); mission_text_box->Display(Buffer, 8.0); - soundwave10->Play(); + soundwave10->Play(nullptr, "AddRankProgress"); } } else if (activeCount >= 3 * totalCount / 4) @@ -1175,7 +1175,7 @@ void control::DeploymentChuteToEscapeChuteOneWayControl(int code, TPinballCompon int count = skill_shot_lights->Message(37, 0.0); if (count) { - soundwave3->Play(); + soundwave3->Play(nullptr, "DeploymentChuteToEscapeChuteOneWayControl"); int score = TableG->AddScore(caller->get_scoring(count - 1)); snprintf(Buffer, sizeof Buffer, pinball::get_rc_string(21, 0), score); info_text_box->Display(Buffer, 2.0); @@ -1267,7 +1267,7 @@ void control::LaunchRampControl(int code, TPinballComponent* caller) TableG->AddScore(caller->get_scoring(0)); sound = soundwave30; } - sound->Play(); + sound->Play(lite198, "LaunchRampControl"); } } @@ -1404,7 +1404,7 @@ void control::OutLaneRolloverControl(int code, TPinballComponent* caller) } else { - soundwave26->Play(); + soundwave26->Play(caller, "OutLaneRolloverControl"); } if (roll4 == caller) { @@ -1483,12 +1483,12 @@ void control::BonusLaneRolloverControl(int code, TPinballComponent* caller) snprintf(Buffer, sizeof Buffer, pinball::get_rc_string(3, 0), addedScore); info_text_box->Display(Buffer, 2.0); lite16->Message(20, 0.0); - soundwave50_1->Play(); + soundwave50_1->Play(caller, "BonusLaneRolloverControl1"); } else { TableG->AddScore(caller->get_scoring(0)); - soundwave25->Play(); + soundwave25->Play(caller, "BonusLaneRolloverControl2"); info_text_box->Display(pinball::get_rc_string(44, 0), 2.0); } fuel_bargraph->Message(45, 11.0); @@ -1756,7 +1756,7 @@ void control::BoosterTargetControl(int code, TPinballComponent* caller) } } if (sound) - sound->Play(); + sound->Play(caller, "BoosterTargetControl"); target1->MessageField = 0; target1->Message(50, 0.0); @@ -1844,12 +1844,12 @@ void control::FuelSpotTargetControl(int code, TPinballComponent* caller) { top_circle_tgt_lights->Message(16, 2.0); fuel_bargraph->Message(45, 11.0); - soundwave25->Play(); + soundwave25->Play(caller, "FuelSpotTargetControl1"); info_text_box->Display(pinball::get_rc_string(44, 0), 2.0); } else { - soundwave49D->Play(); + soundwave49D->Play(caller, "FuelSpotTargetControl2"); } } } @@ -1883,7 +1883,7 @@ void control::MissionSpotTargetControl(int code, TPinballComponent* caller) } else sound = soundwave49D; - sound->Play(); + sound->Play(caller, "MissionSpotTargetControl"); TableG->AddScore(caller->get_scoring(0)); if (ramp_tgt_lights->Message(37, 0.0) == 3) ramp_tgt_lights->Message(16, 2.0); @@ -1915,13 +1915,13 @@ void control::LeftHazardSpotTargetControl(int code, TPinballComponent* caller) TableG->AddScore(caller->get_scoring(0)); if (lchute_tgt_lights->Message(37, 0.0) == 3) { - soundwave14_1->Play(); + soundwave14_1->Play(caller, "LeftHazardSpotTargetControl1"); gate1->Message(53, 0.0); lchute_tgt_lights->Message(16, 2.0); } else { - soundwave49D->Play(); + soundwave49D->Play(caller, "LeftHazardSpotTargetControl2"); } } } @@ -1951,13 +1951,13 @@ void control::RightHazardSpotTargetControl(int code, TPinballComponent* caller) TableG->AddScore(caller->get_scoring(0)); if (bpr_solotgt_lights->Message(37, 0.0) == 3) { - soundwave14_1->Play(); + soundwave14_1->Play(caller, "RightHazardSpotTargetControl1"); gate2->Message(53, 0.0); bpr_solotgt_lights->Message(16, 2.0); } else { - soundwave49D->Play(); + soundwave49D->Play(caller, "RightHazardSpotTargetControl2"); } } } @@ -2015,7 +2015,7 @@ void control::GravityWellKickoutControl(int code, TPinballComponent* caller) info_text_box->Display(Buffer, 2.0); lite62->Message(20, 0.0); caller->ActiveFlag = 0; - auto duration = soundwave7->Play(); + auto duration = soundwave7->Play(lite62, "GravityWellKickoutControl"); caller->Message(55, duration); break; } @@ -2054,7 +2054,7 @@ void control::SkillShotGate1Control(int code, TPinballComponent* caller) lite54->Message(7, 5.0); lite25->Message(7, 5.0); fuel_bargraph->Message(45, 11.0); - soundwave14_2->Play(); + soundwave14_2->Play(lite67, "SkillShotGate1Control"); } } } @@ -2066,7 +2066,7 @@ void control::SkillShotGate2Control(int code, TPinballComponent* caller) if (light_on(&control_lite67_tag)) { lite68->Message(19, 0.0); - soundwave14_2->Play(); + soundwave14_2->Play(lite68, "SkillShotGate2Control"); } } } @@ -2078,7 +2078,7 @@ void control::SkillShotGate3Control(int code, TPinballComponent* caller) if (light_on(&control_lite67_tag)) { lite69->Message(19, 0.0); - soundwave14_2->Play(); + soundwave14_2->Play(lite69, "SkillShotGate3Control"); } } } @@ -2090,7 +2090,7 @@ void control::SkillShotGate4Control(int code, TPinballComponent* caller) if (light_on(&control_lite67_tag)) { lite131->Message(19, 0.0); - soundwave14_2->Play(); + soundwave14_2->Play(lite131, "SkillShotGate4Control"); } } } @@ -2102,7 +2102,7 @@ void control::SkillShotGate5Control(int code, TPinballComponent* caller) if (light_on(&control_lite67_tag)) { lite132->Message(19, 0.0); - soundwave14_2->Play(); + soundwave14_2->Play(lite132, "SkillShotGate5Control"); } } } @@ -2114,7 +2114,7 @@ void control::SkillShotGate6Control(int code, TPinballComponent* caller) if (light_on(&control_lite67_tag)) { lite133->Message(19, 0.0); - soundwave14_2->Play(); + soundwave14_2->Play(lite133, "SkillShotGate6Control"); } } } @@ -2384,9 +2384,9 @@ void control::HyperspaceKickOutControl(int code, TPinballComponent* caller) { if (someFlag < 1 || someFlag > 3) { - auto duration = soundwave41->Play(); - soundwave36_1->Play(); - soundwave50_2->Play(); + auto duration = soundwave41->Play(lite24, "HyperspaceKickOutControl1"); + soundwave36_1->Play(lite24, "HyperspaceKickOutControl2"); + soundwave50_2->Play(lite24, "HyperspaceKickOutControl3"); lite25->Message(7, 5.0); caller->Message(55, duration); return; @@ -2415,7 +2415,7 @@ void control::HyperspaceKickOutControl(int code, TPinballComponent* caller) break; } } - auto duration = sound->Play(); + auto duration = sound->Play(lite24, "HyperspaceKickOutControl4"); lite25->Message(7, 5.0); caller->Message(55, duration); } @@ -2550,7 +2550,7 @@ void control::BallDrainControl(int code, TPinballComponent* caller) TableG->Message(1022, 0.0); if (pb::chk_highscore()) { - soundwave3->Play(); + soundwave3->Play(nullptr, "BallDrainControl1"); TableG->LightGroup->Message(16, 3.0); char* v11 = pinball::get_rc_string(177, 0); mission_text_box->Display(v11, -1.0); @@ -2578,23 +2578,23 @@ void control::BallDrainControl(int code, TPinballComponent* caller) } if (light_on(&control_lite200_tag)) { - soundwave27->Play(); + soundwave27->Play(nullptr, "BallDrainControl2"); lite200->Message(19, 0.0); info_text_box->Display(pinball::get_rc_string(96, 0), -1.0); - soundwave59->Play(); + soundwave59->Play(nullptr, "BallDrainControl3"); } else if (light_on(&control_lite199_tag)) { - soundwave27->Play(); + soundwave27->Play(nullptr, "BallDrainControl4"); lite199->Message(20, 0.0); lite200->Message(19, 0.0); info_text_box->Display(pinball::get_rc_string(95, 0), 2.0); - soundwave59->Play(); + soundwave59->Play(nullptr, "BallDrainControl5"); --TableG->UnknownP78; } else if (TableG->UnknownP75) { - soundwave27->Play(); + soundwave27->Play(nullptr, "BallDrainControl6"); --TableG->UnknownP75; } else @@ -2610,7 +2610,7 @@ void control::BallDrainControl(int code, TPinballComponent* caller) TableG->ExtraBalls--; char* shootAgainText; - soundwave59->Play(); + soundwave59->Play(nullptr, "BallDrainControl7"); switch (TableG->CurrentPlayer) { case 0: @@ -2641,7 +2641,7 @@ void control::BallDrainControl(int code, TPinballComponent* caller) { lite199->MessageField = 1; } - soundwave27->Play(); + soundwave27->Play(nullptr, "BallDrainControl8"); } bmpr_inc_lights->Message(20, 0.0); ramp_bmpr_inc_lights->Message(20, 0.0); @@ -2812,7 +2812,7 @@ void control::AlienMenacePartTwoController(int code, TPinballComponent* caller) if (!AddRankProgress(7)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "AlienMenacePartTwoController"); } } } @@ -2844,7 +2844,7 @@ void control::BlackHoleThreatController(int code, TPinballComponent* caller) if (!AddRankProgress(8)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "BlackHoleThreatController"); } } } @@ -2969,7 +2969,7 @@ void control::BugHuntController(int code, TPinballComponent* caller) if (!AddRankProgress(7)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "BugHuntController"); } } } @@ -3044,7 +3044,7 @@ void control::CosmicPlaguePartTwoController(int code, TPinballComponent* caller) if (!AddRankProgress(11)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "CosmicPlaguePartTwoController"); } } } @@ -3088,7 +3088,7 @@ void control::DoomsdayMachineController(int code, TPinballComponent* caller) if (!AddRankProgress(9)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "DoomsdayMachineController"); } } } @@ -3229,7 +3229,7 @@ void control::LaunchTrainingController(int code, TPinballComponent* caller) if (!AddRankProgress(6)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "LaunchTrainingController"); } } } @@ -3312,7 +3312,7 @@ void control::MaelstromPartEightController(int code, TPinballComponent* caller) if (!AddRankProgress(18)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "MaelstromPartEightController"); } } } @@ -3573,7 +3573,7 @@ void control::PracticeMissionController(int code, TPinballComponent* caller) if (!AddRankProgress(6)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "PracticeMissionController"); } } } @@ -3636,7 +3636,7 @@ void control::ReconnaissanceController(int code, TPinballComponent* caller) if (!AddRankProgress(9)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "ReconnaissanceController"); } } } @@ -3687,7 +3687,7 @@ void control::ReentryTrainingController(int code, TPinballComponent* caller) if (!AddRankProgress(6)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "ReentryTrainingController"); } } } @@ -3728,7 +3728,7 @@ void control::RescueMissionController(int code, TPinballComponent* caller) if (!AddRankProgress(7)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "RescueMissionController"); } break; } @@ -3801,7 +3801,7 @@ void control::SatelliteController(int code, TPinballComponent* caller) if (!AddRankProgress(9)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "SatelliteController"); } } } @@ -3874,7 +3874,7 @@ void control::ScienceMissionController(int code, TPinballComponent* caller) if (!AddRankProgress(9)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "ScienceMissionController"); } } } @@ -3911,7 +3911,7 @@ void control::SecretMissionGreenController(int code, TPinballComponent* caller) if (!AddRankProgress(10)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "SecretMissionGreenController"); } } } @@ -4219,7 +4219,7 @@ void control::SpaceRadiationController(int code, TPinballComponent* caller) if (!AddRankProgress(8)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "SpaceRadiationController"); } } } @@ -4272,7 +4272,7 @@ void control::StrayCometController(int code, TPinballComponent* caller) if (!AddRankProgress(8)) { mission_text_box->Display(Buffer, 8.0); - soundwave9->Play(); + soundwave9->Play(nullptr, "StrayCometController"); } } } @@ -4381,7 +4381,7 @@ void control::TimeWarpPartTwoController(int code, TPinballComponent* caller) if (!AddRankProgress(12)) { mission_text_box->Display(Buffer, 8.0); - soundwave10->Play(); + soundwave10->Play(nullptr, "TimeWarpPartTwoController"); } } SpecialAddScore(2000000); diff --git a/SpaceCadetPinball/loader.cpp b/SpaceCadetPinball/loader.cpp index 47c51cf..968b6a3 100644 --- a/SpaceCadetPinball/loader.cpp +++ b/SpaceCadetPinball/loader.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "loader.h" #include "GroupData.h" +#include "TPinballComponent.h" #include "pb.h" #include "pinball.h" #include "Sound.h" @@ -326,12 +327,11 @@ int loader::material(int groupIndex, visualStruct* visual) return 0; } - -float loader::play_sound(int soundIndex) +float loader::play_sound(int soundIndex, TPinballComponent *soundSource, const char *info) { if (soundIndex <= 0) return 0.0; - Sound::PlaySound(sound_list[soundIndex].WavePtr, pb::time_ticks); + Sound::PlaySound(sound_list[soundIndex].WavePtr, pb::time_ticks, soundSource, info); return sound_list[soundIndex].Duration; } diff --git a/SpaceCadetPinball/loader.h b/SpaceCadetPinball/loader.h index 597b153..d9085ac 100644 --- a/SpaceCadetPinball/loader.h +++ b/SpaceCadetPinball/loader.h @@ -2,6 +2,7 @@ #include "gdrv.h" #include "maths.h" #include "zdrv.h" +#include "TPinballComponent.h" class DatFile; @@ -99,7 +100,7 @@ public: static float* query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue); static float query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue, float defVal); static int16_t* query_iattribute(int groupIndex, int firstValue, int* arraySize); - static float play_sound(int soundIndex); + static float play_sound(int soundIndex, TPinballComponent *soundSource, const char* info); static DatFile* loader_table; private: static errorMsg loader_errors[]; diff --git a/SpaceCadetPinball/options.cpp b/SpaceCadetPinball/options.cpp index a14a19b..5969312 100644 --- a/SpaceCadetPinball/options.cpp +++ b/SpaceCadetPinball/options.cpp @@ -102,6 +102,7 @@ void options::InitPrimary() Options.HybridSleep = get_int("HybridSleep", false); Options.Prefer3DPBGameData = get_int("Prefer 3DPB Game Data", false); Options.IntegerScaling = get_int("Integer Scaling", false); + Options.SoundStereo = get_int("Stereo Sound Effects", true); Options.SoundVolume = Clamp(get_int("Sound Volume", DefVolume), MinVolume, MaxVolume); Options.MusicVolume = Clamp(get_int("Music Volume", DefVolume), MinVolume, MaxVolume); Options.DebugOverlay = get_int("Debug Overlay", false); @@ -147,6 +148,7 @@ void options::uninit() set_int("HybridSleep", Options.HybridSleep); set_int("Prefer 3DPB Game Data", Options.Prefer3DPBGameData); set_int("Integer Scaling", Options.IntegerScaling); + set_int("Stereo Sound Effects", Options.SoundStereo); set_int("Sound Volume", Options.SoundVolume); set_int("Music Volume", Options.MusicVolume); set_int("Debug Overlay", Options.DebugOverlay); @@ -221,6 +223,9 @@ void options::toggle(Menu1 uIDCheckItem) Options.Sounds ^= true; Sound::Enable(Options.Sounds); return; + case Menu1::SoundStereo: + Options.SoundStereo ^= true; + return; case Menu1::Music: Options.Music ^= true; if (!Options.Music) diff --git a/SpaceCadetPinball/options.h b/SpaceCadetPinball/options.h index 202871b..b1b581d 100644 --- a/SpaceCadetPinball/options.h +++ b/SpaceCadetPinball/options.h @@ -8,6 +8,7 @@ enum class Menu1:int Exit = 105, Sounds = 201, Music = 202, + SoundStereo = 203, Help_Topics = 301, Launch_Ball = 401, Pause_Resume_Game = 402, @@ -80,6 +81,7 @@ struct optionsStruct bool IntegerScaling; int SoundVolume; int MusicVolume; + bool SoundStereo; bool DebugOverlay; bool DebugOverlayGrid; bool DebugOverlayAllEdges; diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 2fe85c3..71d0a5e 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -454,6 +454,10 @@ void winmain::RenderUi() { options::toggle(Menu1::Sounds); } + if (ImGui::MenuItem("Stereo Sound Effects", nullptr, Options.SoundStereo)) + { + options::toggle(Menu1::SoundStereo); + } ImGui::TextUnformatted("Sound Volume"); if (ImGui::SliderInt("##Sound Volume", &Options.SoundVolume, options::MinVolume, options::MaxVolume, "%d", ImGuiSliderFlags_AlwaysClamp))