3931 lines
134 KiB
C++
3931 lines
134 KiB
C++
//
|
|
// audio/radioaudioentity.cpp
|
|
//
|
|
// Copyright (C) 1999-2006 Rockstar Games. All Rights Reserved.
|
|
//
|
|
|
|
#include "audiodefines.h"
|
|
|
|
#if NA_RADIO_ENABLED
|
|
|
|
#include "audio/emitteraudioentity.h"
|
|
#include "audiohardware/driver.h"
|
|
#include "audioengine/engine.h"
|
|
#include "camera/CamInterface.h"
|
|
#include "camera/scripted/ScriptedFlyCamera.h"
|
|
#include "cutsceneaudioentity.h"
|
|
#include "frontendAudioEntity.h"
|
|
#include "music/musicplayer.h"
|
|
#include "northaudioengine.h"
|
|
#include "radioaudioentity.h"
|
|
#include "radioslot.h"
|
|
#include "radiostation.h"
|
|
#include "scriptaudioentity.h"
|
|
|
|
#include "debugaudio.h"
|
|
#include "frontend/MobilePhone.h"
|
|
#include "frontend/PauseMenu.h"
|
|
#include "game/ModelIndices.h"
|
|
#include "grcore/debugdraw.h"
|
|
#include "network/NetworkInterface.h"
|
|
#include "peds/ped.h"
|
|
#include "peds/PedIntelligence.h"
|
|
#include "scene/playerswitch/PlayerSwitchInterface.h"
|
|
#include "system/ControlMgr.h"
|
|
#include "vehicles/vehicle.h"
|
|
#include "vehicles/Metadata/VehicleSeatInfo.h"
|
|
|
|
#if GTA_REPLAY
|
|
#include "frontend/VideoEditor/Core/VideoProjectAudioTrackProvider.h"
|
|
#include "replaycoordinator/ReplayCoordinator.h"
|
|
#include "replaycoordinator/ReplayAudioTrackProvider.h"
|
|
#include "replayaudioentity.h"
|
|
#endif
|
|
|
|
AUDIO_MUSIC_OPTIMISATIONS()
|
|
|
|
audRadioAudioEntity g_RadioAudioEntity;
|
|
|
|
f32 g_RadioVolumeControlSmoothRate = 1.0f;
|
|
f32 g_RadioVolumeControlChange = 3.0f;
|
|
u32 g_RadioVolumeHoldTime = 60000;
|
|
u32 g_RadioVolumeRampTime = 30000;
|
|
f32 g_MobilePhoneRadioVolumeOffset = 4.0f;
|
|
|
|
extern bool g_PositionedPlayerVehicleRadioEnabled;
|
|
|
|
const f32 g_AmountToDuckMusicForReplaySFX = -9.0f;
|
|
|
|
const u32 g_MinRadioRetuneDelayMs = 1000;
|
|
//const u32 g_MaxPlayerOutOfVehicleTimeForAutoTune = 15000;
|
|
const f32 g_VehicleRadioProbability = 0.85f;
|
|
#if !__FINAL
|
|
u32 g_RadioDebugSkipForwardTimeMs = 60000; //1 minute.
|
|
u32 g_RadioDebugSkipToTransitionTimeMs = 10000;
|
|
#endif // !__FINAL
|
|
|
|
u32 audRadioAudioEntity::sm_LastRetuneTime = 0;
|
|
u8 audRadioAudioEntity::sm_PendingPlayerRadioStationRetunes = 0;
|
|
bool audRadioAudioEntity::sm_ForceVehicleExplicitRetune = false;
|
|
bool audRadioAudioEntity::sm_IsMobilePhoneRadioActive = false;
|
|
bool audRadioAudioEntity::sm_IsMobilePhoneRadioAvailable = false;
|
|
#if __BANK
|
|
bool audRadioAudioEntity::sm_ShouldPerformRadioRetuneTest = false;
|
|
u8 audRadioAudioEntity::sm_RequestedRadioStationIndex = 0;
|
|
u32 audRadioAudioEntity::sm_RetunePeriodMs = 3000;
|
|
const char *audRadioAudioEntity::sm_RadioStationNames[g_MaxRadioStations];
|
|
bool g_DrawRadioDebug = AUD_DEBUG_STREAMING;
|
|
bool g_DrawRadioSlotDebug = false;
|
|
bkCombo* g_RadioStationCombo = NULL;
|
|
char g_StationDebugNameFilter[128] = {'\0'};
|
|
bool g_DrawRadioStationDebug = false;
|
|
bool g_DrawTakeoverStation1 = false;
|
|
extern bool g_DebugDrawUSBStation;
|
|
bool g_DrawAudibleTrack = false;
|
|
f32 g_StationDebugDrawYScroll = 0.f;
|
|
bool g_DebugSimulateStreamSlotStarvation = false;
|
|
bool g_ForceUnlockSolomun = false;
|
|
bool g_ForceUnlockTaleOfUs = false;
|
|
bool g_ForceUnlockDixon = false;
|
|
bool g_ForceUnlockBlackMadonna = false;
|
|
bool g_PrioritizeSolomun = false;
|
|
bool g_PrioritizeTaleOfUs = false;
|
|
bool g_PrioritizeDixon = false;
|
|
bool g_PrioritizeBlackMadonna = false;
|
|
|
|
#if __WIN32PC
|
|
bool audRadioAudioEntity::sm_DebugUserMusic = false;
|
|
#endif // __WIN32PC
|
|
|
|
#if GTA_REPLAY
|
|
char g_PreviewTrackName[128]={"RADIO_01_CLASS_ROCK_IF_YOU_LEAVE_ME_NOW"};
|
|
#endif
|
|
|
|
#endif // __BANK
|
|
|
|
#if !__FINAL
|
|
bool audRadioAudioEntity::sm_ShouldSkipForward = false;
|
|
bool audRadioAudioEntity::sm_ShouldQuickSkipForward = false;
|
|
bool audRadioAudioEntity::sm_ShouldMuteRadio = false;
|
|
#endif // !__FINAL
|
|
|
|
PARAM(muteradio, "[Audio] Mute radio content.");
|
|
|
|
audRadioAudioEntity::audRadioAudioEntity()
|
|
{
|
|
}
|
|
|
|
|
|
void audRadioAudioEntity::InitClass(void)
|
|
{
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
audWaveSlot::GetEncryptionKeyOverrideCallback = &GetEncryptionKeyForBank;
|
|
#endif
|
|
|
|
sm_LastRetuneTime = 0;
|
|
sm_PendingPlayerRadioStationRetunes = 0;
|
|
|
|
#if __BANK
|
|
sm_ShouldPerformRadioRetuneTest = false;
|
|
sm_RequestedRadioStationIndex = 0;
|
|
sm_RetunePeriodMs = 3000;
|
|
#endif // __BANK
|
|
|
|
#if !__FINAL
|
|
sm_ShouldSkipForward = false;
|
|
sm_ShouldQuickSkipForward = false;
|
|
sm_ShouldMuteRadio = PARAM_muteradio.Get();
|
|
#endif // !__FINAL
|
|
|
|
//Load the radio definitions and instantiate the stations.
|
|
audRadioStation::InitClass();
|
|
// Set up radio slots
|
|
audRadioSlot::InitClass();
|
|
|
|
#if __BANK
|
|
PopulateRetuneWidgetStationNames();
|
|
#endif // __BANK
|
|
}
|
|
|
|
void audRadioAudioEntity::DLCInitClass()
|
|
{
|
|
audRadioStation::MaintainHeist4SPStationState();
|
|
|
|
u32 numStations = audRadioStation::GetNumTotalStations();
|
|
for (u32 radioStationIndex = 0; radioStationIndex < numStations; radioStationIndex++)
|
|
{
|
|
audRadioStation *station = audRadioStation::GetStation(radioStationIndex);
|
|
|
|
if (station)
|
|
{
|
|
station->DLCInit();
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
Displayf("[Telemetry] Radio Station IMMUTABLE_INDEX_TUNEABLE List:");
|
|
|
|
for(u32 i = 0; i < audRadioStation::GetNumTotalStations(); i++)
|
|
{
|
|
if(audRadioStation* radioStation = audRadioStation::FindStationWithImmutableIndex(i, IMMUTABLE_INDEX_TUNEABLE))
|
|
{
|
|
Displayf("[Telemetry] %u: %s", i, radioStation->GetName());
|
|
}
|
|
}
|
|
|
|
Displayf("[Telemetry] Radio Station IMMUTABLE_INDEX_GLOBAL List:");
|
|
|
|
for(u32 i = 0; i < audRadioStation::GetNumTotalStations(); i++)
|
|
{
|
|
if(audRadioStation* radioStation = audRadioStation::FindStationWithImmutableIndex(i, IMMUTABLE_INDEX_GLOBAL))
|
|
{
|
|
Displayf("[Telemetry] %u: %s", i, radioStation->GetName());
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if __BANK
|
|
void audRadioAudioEntity::PopulateRetuneWidgetStationNames()
|
|
{
|
|
//Populate a list of radio station names for the retune widget.
|
|
u32 numStations = audRadioStation::GetNumTotalStations();
|
|
for (u32 radioStationIndex = 0; radioStationIndex < numStations; radioStationIndex++)
|
|
{
|
|
const audRadioStation *station = audRadioStation::GetStation(radioStationIndex);
|
|
if (station)
|
|
{
|
|
sm_RadioStationNames[radioStationIndex] = station->GetName();
|
|
|
|
if (g_RadioStationCombo)
|
|
{
|
|
g_RadioStationCombo->SetString(radioStationIndex, sm_RadioStationNames[radioStationIndex]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sm_RadioStationNames[radioStationIndex] = NULL;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void audRadioAudioEntity::ShutdownClass(void)
|
|
{
|
|
audRadioSlot::ShutdownClass();
|
|
audRadioStation::ShutdownClass();
|
|
}
|
|
|
|
f32 g_RadioPositionedToStereoTime = 0.5f;
|
|
|
|
void audRadioAudioEntity::Init(void)
|
|
{
|
|
m_PlayerVehicleRadioState = PLAYER_RADIO_OFF;
|
|
m_MobilePhoneRadioState = PLAYER_RADIO_OFF;
|
|
m_IsPlayerInVehicleForRadio = false;
|
|
m_IsPlayerInAVehicleWithARadio = false;
|
|
m_WasPlayerInVehicleForRadioLastFrame = false;
|
|
sm_IsMobilePhoneRadioActive = false;
|
|
m_WasMobilePhoneRadioActiveLastFrame = false;
|
|
|
|
m_IgnorePlayerVehicleRadioShutdown = false;
|
|
m_IsPlayerRadioSwitchedOff = false;
|
|
m_PlayerVehicle = NULL;
|
|
m_LastPlayerVehicle = NULL;
|
|
m_LastActiveRadioTimeMs = 0;
|
|
m_PlayerRadioStation = NULL;
|
|
m_CurrentStationIndex = 0;
|
|
m_PlayerRadioStationPendingRetune = NULL;
|
|
m_LastPlayerRadioStation = NULL;
|
|
m_RequestedRadioStation = NULL;
|
|
m_ForcePlayerStation = NULL;
|
|
|
|
#if GTA_REPLAY
|
|
m_ReplayMusicSound = NULL;
|
|
m_PreviouslyRequestedReplayTrack = g_NullSoundHash;
|
|
m_PreviouslyRequestedReplayTrackID = -1;
|
|
m_ShouldPrepareReplayMusic = false;
|
|
m_ShouldStopReplayMusic = false;
|
|
m_StopReplayMusicPreview = false;
|
|
m_StopReplayMusicNoRelease = false;
|
|
m_ShouldPlayReplayMusic = false;
|
|
m_ShouldPlayReplayPreview = false;
|
|
m_ShouldFadeReplayPreview = false;
|
|
m_ShouldUpdateReplayPreview = false;
|
|
m_ShouldUpdateReplayMusic = false;
|
|
m_ReplayMusicStartTime = 0;
|
|
m_PreviewReplayTrack = g_NullSoundHash;
|
|
m_HasParsedMarkers = false;
|
|
m_RockoutStartOffset = 0;
|
|
m_RockoutEndOffset = 0;
|
|
m_PreviewReplayTrackTime = 30000;
|
|
m_ReplayMusicFadeOutScalar = 1.f;
|
|
|
|
m_WasDuckingMusicForSFX = false;
|
|
m_SFXMusicDuckEndTime = 0;
|
|
m_SFXFullMusicDuckVolume = 0.0f;
|
|
#endif
|
|
|
|
m_PlayerVehicleInsideFactor = 0.0f;
|
|
m_RetuneLastReleaseTime = 0;
|
|
m_VolumeLastReleaseTime = 0;
|
|
m_LastPlayerModelId = 0;
|
|
|
|
m_CachedAudibleBeatValid = false;
|
|
m_CachedTimeTillNextAudibleBeat = 0.f;
|
|
m_CachedAudibleBeatBPM = 0.f;
|
|
m_CachedAudibleBeatNum = 0;
|
|
|
|
m_AutoUnfreezeForPlayer = true;
|
|
m_AutoUnfreezeForPlayerTimer = 0.f;
|
|
|
|
m_AreRetunesMuted = false;
|
|
|
|
m_StopEmittersForPlayerVehicle = false;
|
|
m_ForcePlayerCharacterStations = false;
|
|
|
|
m_VolumeOffset = 0.f;
|
|
|
|
m_SkipOnOffSound = false;
|
|
|
|
m_FrontendFadeTime = g_RadioPositionedToStereoTime;
|
|
m_FrontendFadeTimeResetTimer = -1.f;
|
|
|
|
#if __BANK
|
|
m_LastTestRetuneTimeMs = 0;
|
|
#endif // __BANK
|
|
|
|
naAudioEntity::Init();
|
|
audEntity::SetName("audRadioAudioEntity");
|
|
|
|
const f32 increaseDecreaseRate = 0.001f / m_FrontendFadeTime;
|
|
m_PositionedToStereoVolumeSmoother.Init(increaseDecreaseRate, increaseDecreaseRate, 0.0f, 1.0f);
|
|
|
|
m_InFrontendMode = false;
|
|
m_WasMobileRadioActiveOnEnteringFrontend = false;
|
|
|
|
m_LastTimeVehicleRadioWasRetuned = 0;
|
|
m_VehicleRadioJustRetuned = false;
|
|
m_VehicleRadioRetuneAlreadyFlagged = true;
|
|
|
|
m_FadeVolumeLinear = 1.f;
|
|
m_FadeState = kNotFading;
|
|
|
|
m_RadioSounds.Init(ATSTRINGHASH("RADIO_SOUNDSET", 0x951CE826));
|
|
|
|
audRadioStation::ResetHistoryForNewGame();
|
|
|
|
m_bMPDriverHasTriggeredRadioChange = false;
|
|
}
|
|
|
|
void audRadioAudioEntity::Pause()
|
|
{
|
|
g_AudioEngine.GetSoundManager().Pause(2);
|
|
}
|
|
|
|
void audRadioAudioEntity::Unpause()
|
|
{
|
|
g_AudioEngine.GetSoundManager().UnPause(2);
|
|
}
|
|
|
|
#if GTA_REPLAY
|
|
f32 audRadioAudioEntity::GetNextReplayBeat(u32 soundHash, f32 startOffsetMS)
|
|
{
|
|
if(!audRadioTrack::IsScoreTrack(soundHash))
|
|
{
|
|
return GetReplayBeat(soundHash, 1, startOffsetMS);
|
|
}
|
|
else
|
|
{
|
|
return g_InteractiveMusicManager.GetNextReplayBeat(soundHash, startOffsetMS);
|
|
}
|
|
}
|
|
|
|
f32 audRadioAudioEntity::GetPrevReplayBeat(u32 soundHash, f32 startOffsetMS)
|
|
{
|
|
if(!audRadioTrack::IsScoreTrack(soundHash))
|
|
{
|
|
return GetReplayBeat(soundHash, -1, startOffsetMS);
|
|
}
|
|
else
|
|
{
|
|
return g_InteractiveMusicManager.GetPrevReplayBeat(soundHash, startOffsetMS);
|
|
}
|
|
}
|
|
|
|
|
|
bool audRadioAudioEntity::HasBeatMarkers(u32 soundHash)
|
|
{
|
|
if(audRadioTrack::IsScoreTrack(soundHash))
|
|
{
|
|
// Assume that all score tracks have beat markers. Actually checking for beat markers in score tracks
|
|
// requires loading all the appropriate wave data so it isn't trivial to query it when a track isn't actually playing.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
char textIdObjName[16];
|
|
formatf(textIdObjName, "RTB_%08X", audRadioTrack::GetBeatSoundName(soundHash));
|
|
const RadioTrackTextIds *beatMarkers = audNorthAudioEngine::GetObject<RadioTrackTextIds>(textIdObjName);
|
|
|
|
if(beatMarkers && beatMarkers->numTextIds > 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool audRadioAudioEntity::HasBeatMarkersInRange(u32 soundHash, u32 startMS, u32 endMS)
|
|
{
|
|
if(HasBeatMarkers(soundHash))
|
|
{
|
|
if(audRadioTrack::IsScoreTrack(soundHash))
|
|
{
|
|
return g_InteractiveMusicManager.GetNextReplayBeat(soundHash, ((f32)startMS) - 1.f) < endMS;
|
|
}
|
|
else
|
|
{
|
|
char textIdObjName[16];
|
|
formatf(textIdObjName, "RTB_%08X", audRadioTrack::GetBeatSoundName(soundHash));
|
|
const RadioTrackTextIds *beatMarkers = audNorthAudioEngine::GetObject<RadioTrackTextIds>(textIdObjName);
|
|
|
|
if(beatMarkers)
|
|
{
|
|
// search for the two bar markers around the current play head
|
|
for(u32 i=0; i< beatMarkers->numTextIds; i++)
|
|
{
|
|
u32 beatMarkerPlayTimeMS = beatMarkers->TextId[i].OffsetMs;
|
|
|
|
if(beatMarkerPlayTimeMS >= startMS && beatMarkerPlayTimeMS < endMS)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
f32 audRadioAudioEntity::GetReplayBeat(u32 soundHash, s32 direction, f32 startOffsetMS)
|
|
{
|
|
f32 beatTimeMS = startOffsetMS;
|
|
char textIdObjName[16];
|
|
formatf(textIdObjName, "RTB_%08X", audRadioTrack::GetBeatSoundName(soundHash));
|
|
|
|
const RadioTrackTextIds *beatMarkers = audNorthAudioEngine::GetObject<RadioTrackTextIds>(textIdObjName);
|
|
|
|
if(beatMarkers)
|
|
{
|
|
// Can't search backwards past the initial beat marker
|
|
if(direction > 0 || (u32)startOffsetMS > beatMarkers->TextId[0].OffsetMs)
|
|
{
|
|
const f32 currentPlaytimeInSeconds = startOffsetMS * 0.001f;
|
|
|
|
u32 nearestEarlierMarkerTimeMs = 0;
|
|
u32 nearestLaterMarkerTimeMs = ~0U;
|
|
u32 numBeats = 0;
|
|
f32 firstBeatMS = 0;
|
|
u32 nearestBeatMarkerIndex = 0;
|
|
|
|
// search for the two bar markers around the current play head
|
|
for(u32 i=0; i< beatMarkers->numTextIds; i++)
|
|
{
|
|
u32 beatMarkerPlayTimeMS = beatMarkers->TextId[i].OffsetMs;
|
|
|
|
if(beatMarkerPlayTimeMS >= nearestEarlierMarkerTimeMs && beatMarkerPlayTimeMS <= startOffsetMS)
|
|
{
|
|
nearestEarlierMarkerTimeMs = beatMarkerPlayTimeMS;
|
|
numBeats = beatMarkers->TextId[i].TextId;
|
|
nearestBeatMarkerIndex = i;
|
|
}
|
|
else if(beatMarkerPlayTimeMS > startOffsetMS && beatMarkerPlayTimeMS < nearestLaterMarkerTimeMs)
|
|
{
|
|
nearestLaterMarkerTimeMs = beatMarkerPlayTimeMS;
|
|
}
|
|
}
|
|
|
|
if(nearestEarlierMarkerTimeMs != nearestLaterMarkerTimeMs)
|
|
{
|
|
const f32 nearestBarTimeInSeconds = nearestEarlierMarkerTimeMs*0.001f;
|
|
const f32 timeSinceBar = currentPlaytimeInSeconds - nearestBarTimeInSeconds;
|
|
|
|
if(numBeats == 0)
|
|
{
|
|
// If we're somewhere between the start of the track and the first beat, clamp to the first beat
|
|
if(nearestEarlierMarkerTimeMs == 0)
|
|
{
|
|
firstBeatMS = (f32)nearestLaterMarkerTimeMs;
|
|
}
|
|
|
|
numBeats = 8;
|
|
}
|
|
|
|
const f32 beatDuration = (nearestLaterMarkerTimeMs - nearestEarlierMarkerTimeMs) / (numBeats * 1000.f);
|
|
f32 beatsPastLastBar = timeSinceBar / beatDuration;
|
|
u32 beatsPastLastBarRounded = (u32)(beatsPastLastBar + 0.5f);
|
|
bool isOnBeatBoundary = false;
|
|
|
|
// The supplied time is in milliseconds so our timeline position calculation loses some accuracy.
|
|
// We need to round up/down to the nearest beat as appropriate if we're within the error range.
|
|
if(Abs((s32)Floorf((timeSinceBar * 1000.f) + 0.5f) - (s32)Floorf((beatsPastLastBarRounded * beatDuration * 1000.f) + 0.5f)) <= 1)
|
|
{
|
|
beatsPastLastBar = (f32)beatsPastLastBarRounded;
|
|
isOnBeatBoundary = true;
|
|
}
|
|
|
|
s32 currentBeat = (s32)Floorf(beatsPastLastBar);
|
|
|
|
if(direction > 0)
|
|
{
|
|
currentBeat++;
|
|
}
|
|
else if(direction < 0)
|
|
{
|
|
// If searching backwards and we're not on a beat boundary, just floor to the nearest beat,
|
|
// otherwise subtract a beat.
|
|
if(isOnBeatBoundary)
|
|
{
|
|
currentBeat = beatsPastLastBarRounded - 1;
|
|
}
|
|
}
|
|
|
|
f32 beatTimeS = nearestBarTimeInSeconds + (beatDuration * currentBeat);
|
|
beatTimeS = Max(firstBeatMS * 0.001f, beatTimeS);
|
|
beatTimeMS = (beatTimeS * 1000.f);
|
|
}
|
|
}
|
|
}
|
|
|
|
return beatTimeMS;
|
|
}
|
|
|
|
bool audRadioAudioEntity::IsReplayMusicTrackPrepared()
|
|
{
|
|
if(m_PreviouslyRequestedReplayTrack != g_NullSoundHash)
|
|
{
|
|
if(audRadioTrack::IsScoreTrack(m_PreviouslyRequestedReplayTrack))
|
|
{
|
|
return g_InteractiveMusicManager.IsMusicPrepared();
|
|
}
|
|
else
|
|
{
|
|
if(m_ShouldPrepareReplayMusic)
|
|
{
|
|
return false;
|
|
}
|
|
else if(m_ReplayMusicSound && m_ReplayMusicSound->GetPlayState() != AUD_SOUND_PLAYING)
|
|
{
|
|
return m_ReplayMusicSound->Prepare(g_InteractiveMusicManager.GetMusicWaveSlot(), true) == AUD_PREPARED;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void audRadioAudioEntity::RequestReplayMusicTrack(u32 soundHash, s32 musicTrackID, u32 startOffsetMS, u32 durationMs, float fadeOutScalar)
|
|
{
|
|
if(m_PreviouslyRequestedReplayTrack != soundHash || m_PreviouslyRequestedReplayTrackID != musicTrackID)
|
|
{
|
|
StopReplayMusic();
|
|
}
|
|
|
|
if(soundHash != g_NullSoundHash)
|
|
{
|
|
const bool isScoreTrack = audRadioTrack::IsScoreTrack(soundHash);
|
|
if(isScoreTrack)
|
|
{
|
|
g_InteractiveMusicManager.RequestReplayMusic(soundHash, startOffsetMS, durationMs, fadeOutScalar);
|
|
}
|
|
else
|
|
{
|
|
|
|
if(!m_ReplayMusicSound)
|
|
{
|
|
u32 duration = CVideoProjectAudioTrackProvider::GetMusicTrackDurationMs(soundHash);
|
|
if(startOffsetMS < duration - 1000) // we won't allow less than 1 second of music
|
|
{
|
|
// Replay music is requested from the game-thread, so need to defer the creation of the sound until the audio update
|
|
m_ShouldPrepareReplayMusic = true;
|
|
m_ShouldPlayReplayMusic = true;
|
|
m_ReplayMusicStartOffset = startOffsetMS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_ReplayMusicFadeOutScalar = fadeOutScalar;
|
|
m_PreviouslyRequestedReplayTrack = soundHash;
|
|
m_PreviouslyRequestedReplayTrackID = musicTrackID;
|
|
}
|
|
|
|
void audRadioAudioEntity::StopReplayMusic(bool isPreview, bool noRelease)
|
|
{
|
|
const bool isScoreTrack = m_PreviouslyRequestedReplayTrack != g_NullSoundHash && audRadioTrack::IsScoreTrack(m_PreviouslyRequestedReplayTrack);
|
|
if(isScoreTrack)
|
|
{
|
|
g_InteractiveMusicManager.StopAndReset(isPreview && m_ShouldFadeReplayPreview ? REPLAY_PREVIEW_FADE_LENGTH : -1);
|
|
}
|
|
|
|
m_ShouldStopReplayMusic = true;
|
|
m_StopReplayMusicPreview = isPreview;
|
|
m_StopReplayMusicNoRelease = noRelease;
|
|
m_ShouldPrepareReplayMusic = false;
|
|
m_ShouldPlayReplayMusic = false;
|
|
m_ShouldPlayReplayPreview = false;
|
|
m_PreviouslyRequestedReplayTrack = g_NullSoundHash;
|
|
m_PreviouslyRequestedReplayTrackID = -1;
|
|
m_HasParsedMarkers = false;
|
|
m_ShouldUpdateReplayPreview = false;
|
|
m_ShouldUpdateReplayMusic = false;
|
|
m_ShouldFadeReplayPreview = false;
|
|
m_ReplayMusicFadeOutScalar = 1.f;
|
|
}
|
|
|
|
void audRadioAudioEntity::UpdateReplayMusic()
|
|
{
|
|
if(m_ReplayMusicSound)
|
|
{
|
|
if(m_ReplayMusicSound->GetPlayState() == AUD_SOUND_PLAYING && m_ReplayMusicSound->GetSoundTypeID() == StreamingSound::TYPE_ID)
|
|
{
|
|
const audStreamingSound *sound = reinterpret_cast<const audStreamingSound *>(m_ReplayMusicSound);
|
|
for(s32 i = 0; i < sound->GetWavePlayerIdCount(); i++)
|
|
{
|
|
const s32 wavePlayer = sound->GetWavePlayerId(i);
|
|
if(wavePlayer != -1)
|
|
{
|
|
audPcmSourceInterface::SetParam(wavePlayer, audPcmSource::Params::PauseGroup, 0U);
|
|
}
|
|
}
|
|
}
|
|
|
|
UpdateReplayMusicVolume();
|
|
}
|
|
else
|
|
{
|
|
g_InteractiveMusicManager.UpdateReplayMusic();
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::UpdateReplayMusicVolume(bool instant)
|
|
{
|
|
const f32 interpRate = 10.0f;
|
|
static const f32 amountToDuckMusicForReplaySFX = audDriverUtil::ComputeLinearVolumeFromDb(g_AmountToDuckMusicForReplaySFX);
|
|
|
|
f32 desiredVolumeLinear = audDriverUtil::ComputeLinearVolumeFromDb(g_FrontendAudioEntity.GetMontageMusicVolume() + g_FrontendAudioEntity.GetClipMusicVolume()) * m_ReplayMusicFadeOutScalar;
|
|
f32 currentVolumeLinear = audDriverUtil::ComputeLinearVolumeFromDb(m_ReplayMusicSound->GetRequestedPostSubmixVolumeAttenuation());
|
|
|
|
// adjust for user placed SFX
|
|
if(g_ReplayAudioEntity.ShouldDuckMusic())
|
|
{
|
|
if(instant)
|
|
{
|
|
m_SFXMusicDuckEndTime = 0;
|
|
m_SFXFullMusicDuckVolume = g_AmountToDuckMusicForReplaySFX;
|
|
m_WasDuckingMusicForSFX = true;
|
|
}
|
|
if(!m_WasDuckingMusicForSFX)
|
|
{
|
|
m_WasDuckingMusicForSFX = true;
|
|
m_SFXMusicDuckEndTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0) + 1000;
|
|
}
|
|
|
|
f32 fade = 1.0f;
|
|
u32 currentTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
|
|
if(m_SFXMusicDuckEndTime > currentTime)
|
|
{
|
|
fade = Clamp(1.0f - ((f32)(m_SFXMusicDuckEndTime - currentTime)) / 1000.0f, 0.0f, 1.0f);
|
|
//naDisplayf("Fade %f, %u", fade, g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0));
|
|
}
|
|
f32 volumeDb = audDriverUtil::ComputeDbVolumeFromLinear(desiredVolumeLinear);
|
|
f32 sfxVolume = g_ReplayAudioEntity.GetSFXVolumeAffectingMusic();
|
|
|
|
if(volumeDb > g_AmountToDuckMusicForReplaySFX + sfxVolume)
|
|
{
|
|
f32 workingVolume = 1.0f - (fade *(1.0f - amountToDuckMusicForReplaySFX));
|
|
workingVolume = audDriverUtil::ComputeDbVolumeFromLinear(workingVolume);
|
|
m_SFXFullMusicDuckVolume = workingVolume + sfxVolume;
|
|
}
|
|
else
|
|
{
|
|
f32 workingVolume = 1.0f - (fade *(1.0f - amountToDuckMusicForReplaySFX));
|
|
workingVolume = audDriverUtil::ComputeDbVolumeFromLinear(workingVolume);
|
|
m_SFXFullMusicDuckVolume = workingVolume;
|
|
}
|
|
|
|
if(volumeDb > m_SFXFullMusicDuckVolume)
|
|
{
|
|
desiredVolumeLinear = audDriverUtil::ComputeLinearVolumeFromDb(m_SFXFullMusicDuckVolume);
|
|
}
|
|
|
|
//naDisplayf("Desired Music Volume FadeOut %f %f", desiredVolumeLinear, audDriverUtil::ComputeDbVolumeFromLinear(desiredVolumeLinear));
|
|
}
|
|
else
|
|
{
|
|
if(instant)
|
|
{
|
|
m_SFXMusicDuckEndTime = 0;
|
|
m_SFXFullMusicDuckVolume = g_AmountToDuckMusicForReplaySFX;
|
|
m_WasDuckingMusicForSFX = false;
|
|
}
|
|
if(m_WasDuckingMusicForSFX && !instant)
|
|
{
|
|
m_WasDuckingMusicForSFX = false;
|
|
m_SFXMusicDuckEndTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0) + 1000;
|
|
}
|
|
|
|
f32 fade = 0.0f;
|
|
u32 currentTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
|
|
if(m_SFXMusicDuckEndTime > currentTime)
|
|
{
|
|
fade = Clamp((f32)(m_SFXMusicDuckEndTime - currentTime) / 1000.0f, 0.0f, 1.0f);
|
|
//naDisplayf("Fade %f, %u", fade, g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0));
|
|
}
|
|
f32 volumeDb = audDriverUtil::ComputeDbVolumeFromLinear(desiredVolumeLinear);
|
|
|
|
f32 workingVolume = audDriverUtil::ComputeLinearVolumeFromDb(m_SFXFullMusicDuckVolume - volumeDb); // this is the difference between the full duck and where we want to be, we need to fade that range
|
|
workingVolume = 1.0f - (fade *(1.0f - workingVolume));
|
|
workingVolume = audDriverUtil::ComputeDbVolumeFromLinear(workingVolume);
|
|
|
|
desiredVolumeLinear = audDriverUtil::ComputeLinearVolumeFromDb(workingVolume + volumeDb); // add the fade component to the desired component
|
|
|
|
//naDisplayf("Desired Music Volume FadeIn %f %f", desiredVolumeLinear, audDriverUtil::ComputeDbVolumeFromLinear(desiredVolumeLinear));
|
|
}
|
|
|
|
if(instant)
|
|
{
|
|
currentVolumeLinear = desiredVolumeLinear;
|
|
}
|
|
else
|
|
{
|
|
if(currentVolumeLinear < desiredVolumeLinear)
|
|
{
|
|
currentVolumeLinear = Clamp(currentVolumeLinear + (fwTimer::GetTimeStep() * interpRate), currentVolumeLinear, desiredVolumeLinear);
|
|
}
|
|
if(currentVolumeLinear > desiredVolumeLinear)
|
|
{
|
|
currentVolumeLinear = Clamp(currentVolumeLinear - (fwTimer::GetTimeStep() * interpRate), desiredVolumeLinear, currentVolumeLinear);
|
|
}
|
|
}
|
|
m_ReplayMusicSound->SetRequestedPostSubmixVolumeAttenuation(audDriverUtil::ComputeDbVolumeFromLinear(currentVolumeLinear));
|
|
}
|
|
|
|
void audRadioAudioEntity::StartReplayTrackPreview(u32 soundHash, u32 startOffSetMS, u32 trackDuration, bool jumpToRockout, bool fadeIn)
|
|
{
|
|
if(m_ReplayMusicStartTime > 0)
|
|
{
|
|
StopReplayMusic(true);
|
|
g_ReplayAudioEntity.StopAllAmbient(true);
|
|
}
|
|
m_HasParsedMarkers = !jumpToRockout;
|
|
m_ReplayMusicStartTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(1);
|
|
m_ReplayMusicStartOffset = startOffSetMS;
|
|
m_RockoutStartOffset = 0;
|
|
m_RockoutEndOffset = 0;
|
|
m_PreviewReplayTrackTime = trackDuration;
|
|
m_PreviouslyRequestedReplayTrack = soundHash;
|
|
m_ShouldPlayReplayPreview = true;
|
|
m_ShouldFadeReplayPreview = fadeIn;
|
|
m_ReplayMusicFadeOutScalar = 1.f;
|
|
}
|
|
|
|
u32 audRadioAudioEntity::GetReplayMusicPlaybackTimeMs()
|
|
{
|
|
// Query how far through the total track the playback is
|
|
if(m_ReplayMusicStartTime != 0 && m_PreviouslyRequestedReplayTrack != g_NullSoundHash)
|
|
{
|
|
u32 currentTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(1);
|
|
return (m_ReplayMusicStartTime + m_ReplayMusicStartOffset) - currentTime;
|
|
}
|
|
|
|
return 0u;
|
|
}
|
|
|
|
void audRadioAudioEntity::UpdateReplayTrackPreview()
|
|
{
|
|
// we will only process the preview track if this is non 0, this is because we are using some of the same
|
|
// member vars that the main replay audio track uses and this update happens every frame
|
|
if(m_ReplayMusicStartTime != 0 && m_PreviouslyRequestedReplayTrack != g_NullSoundHash)
|
|
{
|
|
u32 currentTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(1);
|
|
u32 soundHash = m_PreviouslyRequestedReplayTrack;
|
|
const bool isScoreTrack = audRadioTrack::IsScoreTrack(soundHash);
|
|
const bool isAmbientTrack = audRadioTrack::IsAmbient(soundHash);
|
|
if(isAmbientTrack)
|
|
{
|
|
g_ReplayAudioEntity.Preload(0, soundHash, REPLAY_STREAM_AMBIENT, 0);
|
|
if(g_ReplayAudioEntity.IsAmbientReadyToPlay(0, soundHash))
|
|
{
|
|
#if __BANK
|
|
Displayf("Preview ambinet track %d index %d", soundHash, 0);
|
|
#endif
|
|
g_ReplayAudioEntity.PlayAmbient(0, soundHash, true);
|
|
}
|
|
if(g_ReplayAudioEntity.IsAmbientPlaying(0, soundHash))
|
|
{
|
|
if(currentTime > m_ReplayMusicStartTime + m_PreviewReplayTrackTime)
|
|
{
|
|
g_ReplayAudioEntity.StopAllAmbient(false);
|
|
m_ReplayMusicStartTime = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ReplayMusicStartTime = currentTime;
|
|
}
|
|
}
|
|
else if(isScoreTrack)
|
|
{
|
|
g_InteractiveMusicManager.SetReplayScoreIntensity(DEFAULT_MARKER_AUDIO_INTENSITY, DEFAULT_MARKER_AUDIO_INTENSITY, true, 0);
|
|
g_InteractiveMusicManager.RequestReplayMusic(soundHash, m_ReplayMusicStartOffset);
|
|
if(!g_InteractiveMusicManager.IsMusicPlaying())
|
|
{
|
|
m_ReplayMusicStartTime = currentTime;
|
|
}
|
|
if(currentTime > m_ReplayMusicStartTime + m_PreviewReplayTrackTime)
|
|
{
|
|
StopReplayMusic(true);
|
|
m_ReplayMusicStartTime = 0;
|
|
}
|
|
g_InteractiveMusicManager.UpdateReplayMusicPreview(m_ShouldFadeReplayPreview);
|
|
}
|
|
else
|
|
{
|
|
// first we preload the wave and parse the markers
|
|
if(!m_HasParsedMarkers && m_ShouldPlayReplayPreview)
|
|
{
|
|
if(m_ReplayMusicSound)
|
|
{
|
|
if(m_ReplayMusicSound->GetPlayState() != AUD_SOUND_PLAYING)
|
|
{
|
|
m_ReplayMusicStartTime = currentTime;
|
|
if(m_ReplayMusicSound->Prepare(g_InteractiveMusicManager.GetMusicWaveSlot(), true) == AUD_PREPARED)
|
|
{
|
|
ParseMarkers();
|
|
m_ReplayMusicStartOffset = m_RockoutStartOffset;
|
|
if(((m_RockoutEndOffset - m_RockoutStartOffset) > REPLAY_PREVIEW_MIN_LENGTH) && ((m_RockoutEndOffset - m_RockoutStartOffset) < REPLAY_PREVIEW_MAX_LENGTH))
|
|
{
|
|
//m_PreviewReplayTrackTime = m_RockoutEndOffset - m_RockoutStartOffset;
|
|
m_PreviewReplayTrackTime = REPLAY_PREVIEW_DEFAULT_LENGTH; // force to 30s preview
|
|
Displayf("Found ROCKOUT section time : %dms", m_PreviewReplayTrackTime);
|
|
u32 duration = CVideoProjectAudioTrackProvider::GetMusicTrackDurationMs(m_PreviouslyRequestedReplayTrack);
|
|
if(m_ReplayMusicStartOffset + m_PreviewReplayTrackTime > duration - 1000)
|
|
{
|
|
m_PreviewReplayTrackTime = (duration - REPLAY_PREVIEW_FADE_LENGTH) - m_ReplayMusicStartOffset;
|
|
if(m_PreviewReplayTrackTime < REPLAY_PREVIEW_MIN_LENGTH)
|
|
{
|
|
m_ReplayMusicStartOffset = 0;
|
|
m_PreviewReplayTrackTime = REPLAY_PREVIEW_DEFAULT_LENGTH;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_PreviewReplayTrackTime = REPLAY_PREVIEW_DEFAULT_LENGTH;
|
|
}
|
|
// kill the sound and preload to the new start offset based on ROCKOUT marker
|
|
m_ReplayMusicSound->StopAndForget();
|
|
m_ShouldPrepareReplayMusic = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ShouldPrepareReplayMusic = true;
|
|
}
|
|
}
|
|
else if(m_ReplayMusicSound)
|
|
{
|
|
if(m_ReplayMusicSound->GetPlayState() != AUD_SOUND_PLAYING && m_ShouldPlayReplayPreview)
|
|
{
|
|
m_ReplayMusicStartTime = currentTime;
|
|
if(m_ReplayMusicSound->Prepare(g_InteractiveMusicManager.GetMusicWaveSlot(), true) == AUD_PREPARED)
|
|
{
|
|
m_ReplayMusicSound->SetRequestedPostSubmixVolumeAttenuation(-100.0f);
|
|
m_ReplayMusicSound->GetRequestedSettings()->SetShouldPersistOverClears(true);
|
|
m_ReplayMusicSound->Play();
|
|
m_ShouldPlayReplayPreview = false;
|
|
|
|
if(audRadioTrack::IsCommercial(m_PreviouslyRequestedReplayTrack))
|
|
{
|
|
m_PreviewReplayTrackTime = m_ReplayMusicSound->ComputeDurationMsIncludingStartOffsetAndPredelay(NULL);
|
|
m_ShouldFadeReplayPreview = false;
|
|
}
|
|
}
|
|
}
|
|
if(m_ReplayMusicSound->GetPlayState() == AUD_SOUND_PLAYING && m_ReplayMusicSound->GetSoundTypeID() == StreamingSound::TYPE_ID)
|
|
{
|
|
f32 currentFade = m_ShouldFadeReplayPreview? (float)(currentTime - m_ReplayMusicStartTime) / (f32)REPLAY_PREVIEW_FADE_LENGTH : 1.0f;
|
|
f32 currentVolumeLinear = Clamp(currentFade, 0.0f, 1.0f);
|
|
m_ReplayMusicSound->SetRequestedPostSubmixVolumeAttenuation(audDriverUtil::ComputeDbVolumeFromLinear(currentVolumeLinear*REPLAY_PREVIEW_MUSIC_VOLUME));
|
|
|
|
const audStreamingSound *sound = reinterpret_cast<const audStreamingSound *>(m_ReplayMusicSound);
|
|
for(s32 i = 0; i < sound->GetWavePlayerIdCount(); i++)
|
|
{
|
|
const s32 wavePlayer = sound->GetWavePlayerId(i);
|
|
if(wavePlayer != -1)
|
|
{
|
|
audPcmSourceInterface::SetParam(wavePlayer, audPcmSource::Params::PauseGroup, 0U);
|
|
}
|
|
}
|
|
}
|
|
if(currentTime > m_ReplayMusicStartTime + m_PreviewReplayTrackTime)
|
|
{
|
|
StopReplayMusic(true);
|
|
m_ReplayMusicStartTime = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ShouldPrepareReplayMusic = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::ParseMarkers()
|
|
{
|
|
if(audVerifyf(g_InteractiveMusicManager.GetMusicWaveSlot(), "Radio track preview playing physically with no wave slot"))
|
|
{
|
|
// find the wavename hash
|
|
const u32 metadataSoundHash = m_PreviouslyRequestedReplayTrack;
|
|
u32 wavehash[2] = {~0U,~0U};
|
|
|
|
const StreamingSound *streamingSound = SOUNDFACTORY.DecompressMetadata<StreamingSound>(metadataSoundHash);
|
|
if(streamingSound)
|
|
{
|
|
for(u32 waveIndex = 0; waveIndex < Min<u32>(2, streamingSound->numSoundRefs); waveIndex++)
|
|
{
|
|
const SimpleSound *simpleSound = SOUNDFACTORY.DecompressMetadata<SimpleSound>(streamingSound->SoundRef[waveIndex].SoundId);
|
|
if(simpleSound)
|
|
{
|
|
wavehash[waveIndex] = simpleSound->WaveRef.WaveName;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(wavehash[0] != ~0U || wavehash[1] != ~0U)
|
|
{
|
|
audWaveRef waveRef;
|
|
audWaveMarkerList markers;
|
|
|
|
u32 sampleRate = 0;
|
|
if(waveRef.Init(g_InteractiveMusicManager.GetMusicWaveSlot(), wavehash[0]))
|
|
{
|
|
waveRef.FindMarkerData(markers);
|
|
const audWaveFormat *format = waveRef.FindFormat();
|
|
if(format)
|
|
{
|
|
sampleRate = format->SampleRate;
|
|
}
|
|
}
|
|
if(markers.GetCount() == 0)
|
|
{
|
|
if(waveRef.Init(g_InteractiveMusicManager.GetMusicWaveSlot(), wavehash[1]))
|
|
{
|
|
waveRef.FindMarkerData(markers);
|
|
const audWaveFormat *format = waveRef.FindFormat();
|
|
if(format)
|
|
{
|
|
sampleRate = format->SampleRate;
|
|
}
|
|
}
|
|
}
|
|
|
|
audRadioTrack::audDjSpeechRegion currentRegion;
|
|
currentRegion.type = audRadioTrack::audDjSpeechRegion::OUTRO;
|
|
|
|
audRadioTrack::audDjSpeechRegion currentRockOutRegion;
|
|
currentRockOutRegion.type = audRadioTrack::audDjSpeechRegion::ROCKOUT;
|
|
|
|
m_RockoutStartOffset = 0;
|
|
m_RockoutEndOffset = 0;
|
|
u32 startRockOut = 0;
|
|
u32 endRockOut = 0;
|
|
for(u32 i=0; i<markers.GetCount(); i++)
|
|
{
|
|
if(markers[i].categoryNameHash == ATSTRINGHASH("ROCKOUT", 0xF31B4F6A))
|
|
{
|
|
if(markers[i].nameHash == ATSTRINGHASH("START", 0x84DC271F))
|
|
{
|
|
startRockOut = audDriverUtil::ConvertSamplesToMs(markers[i].positionSamples, sampleRate);
|
|
|
|
// always grab first ROCKOUT section and use it unless we get a better one in our magic length
|
|
if(m_RockoutStartOffset == 0)
|
|
{
|
|
m_RockoutStartOffset = startRockOut;
|
|
}
|
|
}
|
|
else if(markers[i].nameHash == ATSTRINGHASH("END", 0xB0C485D7))
|
|
{
|
|
endRockOut = audDriverUtil::ConvertSamplesToMs(markers[i].positionSamples, sampleRate);
|
|
u32 rockLength = endRockOut - startRockOut;
|
|
if(rockLength > REPLAY_PREVIEW_MIN_LENGTH && rockLength < REPLAY_PREVIEW_MAX_LENGTH )
|
|
{
|
|
if(endRockOut > startRockOut)
|
|
{
|
|
m_RockoutStartOffset = startRockOut;
|
|
m_RockoutEndOffset = endRockOut;
|
|
m_HasParsedMarkers = true;
|
|
return;
|
|
}
|
|
}
|
|
// always grab first ROCKOUT section and use it unless we get a better one in our magic length
|
|
if(m_RockoutEndOffset == 0 && endRockOut > m_RockoutStartOffset)
|
|
{
|
|
m_RockoutEndOffset = endRockOut;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_HasParsedMarkers = true;
|
|
}
|
|
|
|
void audRadioAudioEntity::StopReplayTrackPreview()
|
|
{
|
|
StopReplayMusic(true);
|
|
g_ReplayAudioEntity.StopAllAmbient(true);
|
|
m_ReplayMusicStartTime = 0;
|
|
}
|
|
|
|
|
|
#endif // GTA_REPLAY
|
|
|
|
void audRadioAudioEntity::FrontendUpdate(const bool previewRadio)
|
|
{
|
|
// only go into frontend mode when the game is paused
|
|
if(CPauseMenu::IsActive() && ((previewRadio && CNetwork::IsGameInProgress() && !g_InteractiveMusicManager.IsMusicPlaying()) || fwTimer::IsGamePaused()))
|
|
{
|
|
if(!m_InFrontendMode)
|
|
{
|
|
m_WasMobileRadioActiveOnEnteringFrontend = sm_IsMobilePhoneRadioActive;
|
|
m_InFrontendMode = true;
|
|
}
|
|
sm_IsMobilePhoneRadioActive = true;
|
|
}
|
|
else
|
|
{
|
|
if(m_InFrontendMode)
|
|
{
|
|
sm_IsMobilePhoneRadioActive = m_WasMobileRadioActiveOnEnteringFrontend;
|
|
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
// If the user tunes away from the special radio in the pause menu, set it back when we exit
|
|
if (m_PlayerVehicleRadioState != PLAYER_RADIO_OFF && m_PlayerVehicle && m_PlayerRadioStation && m_PlayerVehicle->GetModelNameHash() == HEIST3_HIDDEN_RADIO_VEHICLE && m_PlayerRadioStation->GetNameHash() != HEIST3_HIDDEN_RADIO_STATION_NAME)
|
|
{
|
|
if (GetEncryptionKeyForBank(audRadioStation::sm_Heist3HiddenRadioBankId))
|
|
{
|
|
RetuneToStation(HEIST3_HIDDEN_RADIO_STATION_NAME);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
m_InFrontendMode = false;
|
|
}
|
|
|
|
// Allow frontend to override pausing
|
|
// Don't pause when in the replay editor, to ensure radio slots are cleaned up
|
|
const bool frontendPreview = previewRadio && m_InFrontendMode;
|
|
if(!frontendPreview && fwTimer::IsGamePaused() REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive() && !CReplayMgr::IsPlaying()))
|
|
{
|
|
Pause();
|
|
}
|
|
else
|
|
{
|
|
Unpause();
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::Shutdown(void)
|
|
{
|
|
audRadioStation::Reset();
|
|
audEntity::Shutdown();
|
|
}
|
|
|
|
void audRadioAudioEntity::SetFrontendFadeTime(const float fadeTimeSeconds)
|
|
{
|
|
m_FrontendFadeTime = fadeTimeSeconds;
|
|
m_FrontendFadeTimeResetTimer = 5.f;
|
|
}
|
|
|
|
void audRadioAudioEntity::GameUpdate()
|
|
{
|
|
audRadioStation::GameUpdate();
|
|
|
|
if(m_FrontendFadeTimeResetTimer > 0.f)
|
|
{
|
|
m_FrontendFadeTimeResetTimer -= fwTimer::GetSystemTimeStep();
|
|
if(m_FrontendFadeTimeResetTimer <= 0.f)
|
|
{
|
|
m_FrontendFadeTimeResetTimer = -1.f;
|
|
m_FrontendFadeTime = g_RadioPositionedToStereoTime;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BANK_ONLY(m_FrontendFadeTime = g_RadioPositionedToStereoTime);
|
|
}
|
|
const float smootherRate = 0.001f / m_FrontendFadeTime;
|
|
m_PositionedToStereoVolumeSmoother.SetRates(smootherRate, smootherRate);
|
|
|
|
//Update our details about the player vehicle.
|
|
CPed *player = CGameWorld::FindLocalPlayer();
|
|
CVehicle * playerVehicle = CGameWorld::FindLocalPlayerVehicle();
|
|
if (NetworkInterface::IsGameInProgress() && NetworkInterface::IsLocalPlayerOnSCTVTeam())
|
|
{
|
|
CPed *followPlayer = CGameWorld::FindFollowPlayer();
|
|
|
|
if (followPlayer && followPlayer->GetPedConfigFlag( CPED_CONFIG_FLAG_InVehicle ))
|
|
{
|
|
playerVehicle = followPlayer->GetMyVehicle();
|
|
player = followPlayer;
|
|
}
|
|
}
|
|
|
|
if(m_PlayerVehicle != playerVehicle)
|
|
{
|
|
m_PlayerVehicle = playerVehicle;
|
|
}
|
|
if(player->GetModelIndex() != m_LastPlayerModelId)
|
|
{
|
|
m_LastPlayerModelId = player->GetModelIndex();
|
|
|
|
// Player has switched - reset autotuning timer
|
|
m_LastActiveRadioTimeMs = 0;
|
|
}
|
|
|
|
|
|
// Player is getting out if TaskExitVehicle has reached a certain state
|
|
const bool hasPlayerExitedVeh = (player->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_EXIT_VEHICLE)
|
|
&& player->GetAttachState() == ATTACH_STATE_PED_EXIT_CAR);
|
|
|
|
//NOTE: Make sure the car has been started and allocated a radio station (off in the case of the player vehicle.)
|
|
//Also ensure that the player is *really* in the vehicle and not getting in or out.
|
|
bool isPlayerInVehicle = (player && m_PlayerVehicle &&
|
|
!player->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_ENTER_VEHICLE) &&
|
|
!hasPlayerExitedVeh);
|
|
|
|
if(player && m_PlayerVehicle)
|
|
{
|
|
if(m_PlayerVehicle->GetVehicleModelInfo() && m_PlayerVehicle->GetVehicleModelInfo()->m_data != NULL)
|
|
{
|
|
// Don't activate frontend radio if we're just hanging off the side of a vehicle (firetrucks etc.) or are sat in a trailer outside the cabin
|
|
if(m_PlayerVehicle->GetVehicleAudioEntity() && m_PlayerVehicle->GetVehicleAudioEntity()->IsPedSatInExternalSeat(player))
|
|
{
|
|
isPlayerInVehicle = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// IsRadioEnabled will return false until the engine is on
|
|
bool isPlayerInAVehicleWithARadio = isPlayerInVehicle && m_PlayerVehicle->GetVehicleAudioEntity()->GetHasNormalRadio();
|
|
bool isPlayerInVehicleForRadio = (isPlayerInVehicle && m_PlayerVehicle->GetVehicleAudioEntity()->IsRadioEnabled() && (m_PlayerVehicle->GetVehicleAudioEntity()->GetRadioStation() != NULL || (m_IsPlayerInAVehicleWithARadio && (m_PlayerVehicleRadioState != PLAYER_RADIO_OFF || m_ForcePlayerStation != NULL))));
|
|
|
|
if(NetworkInterface::IsGameInProgress() && camInterface::IsFadedOut())
|
|
{
|
|
// Do nothing - script often fiddle with the vehicles etc. during respawn so hold off updating until we are fading back into the game
|
|
}
|
|
else
|
|
{
|
|
// IsRadioEnabled will return false until the engine is on
|
|
m_IsPlayerInAVehicleWithARadio = isPlayerInAVehicleWithARadio;
|
|
m_IsPlayerInVehicleForRadio = isPlayerInVehicleForRadio;
|
|
}
|
|
|
|
#if GTA_REPLAY
|
|
// No radio in replays
|
|
if(CReplayMgr::IsEditModeActive())
|
|
{
|
|
m_IsPlayerInAVehicleWithARadio = false;
|
|
}
|
|
#endif
|
|
|
|
#if !__NO_OUTPUT
|
|
if(m_IsPlayerInAVehicleWithARadio && m_PlayerVehicle && m_PlayerVehicle->GetVehicleAudioEntity()->IsRadioDisabledByScript())
|
|
{
|
|
static f32 s_NextWarnTime = 0.f;
|
|
if(s_NextWarnTime <= 0.f)
|
|
{
|
|
s_NextWarnTime = 1.f;
|
|
audWarningf("Player is in a vehicle with radio disabled by script");
|
|
}
|
|
else
|
|
{
|
|
s_NextWarnTime -= fwTimer::GetTimeStep();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(m_IsPlayerInVehicleForRadio)
|
|
{
|
|
// Deal with warping between vehicles (including character switch); force the station in the new vehicle to
|
|
// match the old one.
|
|
if(m_LastPlayerVehicle != NULL && m_PlayerVehicle && m_LastPlayerVehicle != m_PlayerVehicle && m_PlayerRadioStation)
|
|
{
|
|
// Ensure we go via a STARTING state if we're not retuning
|
|
if(m_PlayerVehicle->GetVehicleAudioEntity()->GetRadioStation() == m_PlayerRadioStation
|
|
|| g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::ForceSeamlessRadioSwitch))
|
|
{
|
|
audDisplayf("Player has switched vehicle, updating radio station");
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioStation(m_PlayerRadioStation);
|
|
if(m_PlayerVehicleRadioState == PLAYER_RADIO_PLAYING)
|
|
{
|
|
// Need to enter the 'starting' state to register this vehicle as a new emitter
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
}
|
|
}
|
|
m_LastPlayerVehicle = m_PlayerVehicle;
|
|
}
|
|
|
|
FrontendUpdate(CPauseMenu::ShouldPlayMusic() || CPauseMenu::ShouldPlayRadioStation());
|
|
}
|
|
|
|
|
|
#if RSG_BANK
|
|
void audRadioAudioEntity::DebugDrawStations()
|
|
{
|
|
const f32 yStepRate = 0.015f;
|
|
f32 xCoord = 0.05f;
|
|
f32 yCoord = 0.05f - g_StationDebugDrawYScroll;
|
|
|
|
if (g_DrawAudibleTrack)
|
|
{
|
|
const audRadioStation* radioStation = FindAudibleStation(25.f);
|
|
|
|
if (radioStation)
|
|
{
|
|
if (radioStation->IsMixStation())
|
|
{
|
|
radioStation->DebugDrawMixBeatMarkers();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_DrawTakeoverStation1)
|
|
{
|
|
if (audRadioStation* station = audRadioStation::FindStation("RADIO_23_DLC_XM19_RADIO"))
|
|
{
|
|
station->DrawTakeoverStation();
|
|
}
|
|
}
|
|
|
|
if (g_DebugDrawUSBStation)
|
|
{
|
|
audRadioStation* station = audRadioStation::GetUSBMixStation();
|
|
|
|
if (station)
|
|
{
|
|
station->DrawUSBStation();
|
|
}
|
|
}
|
|
|
|
if(g_DrawRadioStationDebug)
|
|
{
|
|
u32 numStations = audRadioStation::GetNumTotalStations();
|
|
for(u32 radioStationIndex=0; radioStationIndex<numStations; radioStationIndex++)
|
|
{
|
|
const audRadioStation *station = audRadioStation::GetStation(radioStationIndex);
|
|
if(station)
|
|
{
|
|
if(g_StationDebugNameFilter[0] != 0 && !audEngineUtil::MatchName(station->GetName(), g_StationDebugNameFilter))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
char tempString[256];
|
|
formatf(tempString, "Station %s", station->GetName());
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += yStepRate;
|
|
|
|
formatf(tempString, "Random Seed: %u", station->GetRandomSeed());
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += yStepRate;
|
|
|
|
xCoord += 0.02f;
|
|
const audRadioTrack& currentTrack = station->GetCurrentTrack();
|
|
|
|
if(currentTrack.IsInitialised())
|
|
{
|
|
formatf(tempString, "Current Track: %s (%s track %u)", SOUNDFACTORY.GetMetadataManager().GetObjectName(currentTrack.GetSoundRef()), TrackCats_ToString((TrackCats)currentTrack.GetCategory()), currentTrack.GetTrackIndex());
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += yStepRate;
|
|
|
|
formatf(tempString, "Progress: %u/%u (%.02f%%)", currentTrack.GetPlayTime(), currentTrack.GetDuration(), (currentTrack.GetPlayTime()/(f32)currentTrack.GetDuration()) * 100.f);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += yStepRate;
|
|
}
|
|
else
|
|
{
|
|
formatf(tempString, "Current Track: Not Initialised");
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += yStepRate;
|
|
}
|
|
|
|
const audRadioTrack& nextTrack = station->GetNextTrack();
|
|
|
|
if(nextTrack.IsInitialised())
|
|
{
|
|
formatf(tempString, "Next Track: %s (%s track %u)", SOUNDFACTORY.GetMetadataManager().GetObjectName(nextTrack.GetSoundRef()), TrackCats_ToString((TrackCats)nextTrack.GetCategory()), nextTrack.GetTrackIndex());
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += yStepRate;
|
|
}
|
|
else
|
|
{
|
|
formatf(tempString, "Next Track: Not Initialised");
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += yStepRate;
|
|
}
|
|
|
|
xCoord += 0.02f;
|
|
for(u32 category = 0; category < TrackCats::NUM_RADIO_TRACK_CATS; category++)
|
|
{
|
|
if(audRadioStationTrackListCollection *trackListCollection = const_cast<audRadioStationTrackListCollection *>(station->FindTrackListsForCategory(category)))
|
|
{
|
|
u32 unlockedTrackListIndex = 0;
|
|
|
|
for(u32 listIndex = 0; listIndex < trackListCollection->GetListCount(); listIndex++)
|
|
{
|
|
if(const RadioStationTrackList* trackList = trackListCollection->GetList(listIndex))
|
|
{
|
|
const char* trackListName = audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(trackList->NameTableOffset);
|
|
bool isLocked = trackListCollection->IsListLocked(listIndex);
|
|
|
|
if(!isLocked && station->m_UseRandomizedStrideSelection && audRadioStation::IsRandomizedStrideCategory(category))
|
|
{
|
|
// Special case - for stations with old/new data, we store the new data stride in the takeover slot
|
|
if(!station->m_HasTakeoverContent && trackListCollection->GetUnlockedListCount() == 2)
|
|
{
|
|
if(unlockedTrackListIndex == 1)
|
|
{
|
|
u32 adjustedCategory = category;
|
|
if(category == RADIO_TRACK_CAT_MUSIC) { adjustedCategory = RADIO_TRACK_CAT_TAKEOVER_MUSIC; }
|
|
if(category == RADIO_TRACK_CAT_IDENTS) { adjustedCategory = RADIO_TRACK_CAT_TAKEOVER_IDENTS; }
|
|
if(category == RADIO_TRACK_CAT_DJSOLO) { adjustedCategory = RADIO_TRACK_CAT_TAKEOVER_DJSOLO; }
|
|
audRadioStationHistory* history = const_cast<audRadioStationHistory*>(station->FindHistoryForCategory(adjustedCategory));
|
|
formatf(tempString, " %s: %s, Stride %d, Prev: %d/%d", trackListName, isLocked ? "Locked" : "Unlocked", station->m_CategoryStride[adjustedCategory], (*history)[0], trackList->numTracks);
|
|
}
|
|
else
|
|
{
|
|
audRadioStationHistory* history = const_cast<audRadioStationHistory*>(station->FindHistoryForCategory(category));
|
|
formatf(tempString, " %s: %s, Stride %d, Prev %d/%d", trackListName, isLocked ? "Locked" : "Unlocked", station->m_CategoryStride[category], (*history)[0], trackList->numTracks);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
audRadioStationHistory* history = const_cast<audRadioStationHistory*>(station->FindHistoryForCategory(category));
|
|
formatf(tempString, " %s: %s, Stride %d, Prev %d/%d", trackListName, isLocked ? "Locked" : "Unlocked", station->m_CategoryStride[category], (*history)[0], trackList->numTracks);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
formatf(tempString, " %s: %s", trackListName, isLocked ? "Locked" : "Unlocked");
|
|
}
|
|
|
|
if(!isLocked)
|
|
{
|
|
unlockedTrackListIndex++;
|
|
}
|
|
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), isLocked ? Color_LightGray : Color_white, tempString);
|
|
yCoord += yStepRate;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
xCoord -= 0.02f;
|
|
|
|
xCoord -= 0.02f;
|
|
yCoord += yStepRate;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::DrawDebug()
|
|
{
|
|
if(g_DrawRadioDebug)
|
|
{
|
|
PUSH_DEFAULT_SCREEN();
|
|
|
|
audDriver::SetDebugDrawRenderStates();
|
|
|
|
audSoundDebugDrawManager drawMgr(100.f, 50.f, 20.f, 720.f);
|
|
drawMgr.SetTextScale(1.5f);
|
|
grcColor(Color32(255,255,255,255));
|
|
|
|
drawMgr.DrawLinef("Max positioned levels: L: %f, M: %f, S: %f, V: %f"
|
|
, audDriverUtil::ComputeDbVolumeFromLinear(audRadioTrack::GetLargeReverbMax())
|
|
, audDriverUtil::ComputeDbVolumeFromLinear(audRadioTrack::GetMediumReverbMax())
|
|
, audDriverUtil::ComputeDbVolumeFromLinear(audRadioTrack::GetSmallReverbMax())
|
|
, audRadioTrack::GetVolumeMax()
|
|
);
|
|
|
|
const char *states[] = {"Off","Starting","Playing", "Frozen", "Stopping","Retuning"};
|
|
drawMgr.DrawLinef("PlayerVehicleRadioState: %s, PlayerMobilePhoneRadioState: %s", states[m_PlayerVehicleRadioState],states[m_MobilePhoneRadioState]);
|
|
|
|
const audRadioTrack *audibleTrack = FindAudibleTrack(25.f);
|
|
if(audibleTrack)
|
|
{
|
|
drawMgr.DrawLinef("Currently audible track: %s (ZiT: %u) ", audibleTrack->GetBankName(), audibleTrack->GetTextId());
|
|
drawMgr.DrawLinef("(Play time: %d/%u, %.02f%%, %d remaining)", audibleTrack->GetPlayTime(), audibleTrack->GetDuration(), (audibleTrack->GetPlayTime()/(f32)audibleTrack->GetDuration()) * 100.f, audibleTrack->GetDuration() - audibleTrack->GetPlayTime());
|
|
float bpm = 0.f;
|
|
s32 beatNumber = 1;
|
|
float beatTimeS = 0.;
|
|
if(audibleTrack->GetNextBeat(beatTimeS, bpm, beatNumber))
|
|
{
|
|
drawMgr.DrawLinef("Audible beat: %.2f (%u/4 %.1f BPM)", beatTimeS, beatNumber, bpm);
|
|
}
|
|
|
|
if (audRadioStation* radioStation = audRadioStation::FindStation(audibleTrack->StationNameHash()))
|
|
{
|
|
radioStation->DrawDebug(drawMgr);
|
|
}
|
|
}
|
|
|
|
audRadioSlot::DrawDebug(drawMgr);
|
|
audStreamSlot::DrawDebug(drawMgr);
|
|
|
|
POP_DEFAULT_SCREEN();
|
|
|
|
}
|
|
else if(g_DrawRadioSlotDebug)
|
|
{
|
|
PUSH_DEFAULT_SCREEN();
|
|
|
|
audDriver::SetDebugDrawRenderStates();
|
|
|
|
audSoundDebugDrawManager drawMgr(100.f, 50.f, 20.f, 720.f);
|
|
drawMgr.SetTextScale(1.5f);
|
|
grcColor(Color32(255,255,255,255));
|
|
audRadioSlot::DrawDebug(drawMgr);
|
|
audStreamSlot::DrawDebug(drawMgr);
|
|
POP_DEFAULT_SCREEN();
|
|
}
|
|
|
|
if(IsPlayerRadioActive() && m_PlayerRadioStation)
|
|
{
|
|
static u32 s_LastPlayerTrack = 0;
|
|
const u32 soundRef = m_PlayerRadioStation->GetCurrentTrack().GetSoundRef();
|
|
if(s_LastPlayerTrack != soundRef && m_PlayerRadioStation->GetCurrentTrack().IsInitialised())
|
|
{
|
|
s_LastPlayerTrack = soundRef;
|
|
|
|
audDebugf1("PlayerRadioTrack: %u,%s,%s,%u,%u,%s", GetCurrentTimeMs(), m_PlayerRadioStation->GetName(), g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectName(soundRef),
|
|
m_PlayerRadioStation->GetCurrentTrack().GetPlayTime(),
|
|
m_PlayerRadioStation->GetCurrentTrack().GetDuration(),
|
|
m_PlayerRadioStation->IsCurrentTrackNew() ? "NEW" : "OLD");
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void audRadioAudioEntity::UpdateFade()
|
|
{
|
|
switch(m_FadeState)
|
|
{
|
|
case kFadingIn:
|
|
m_FadeVolumeLinear += m_InvFadeTime * fwTimer::GetTimeStep();
|
|
m_FadeVolumeLinear = Min(m_FadeVolumeLinear, 1.f);
|
|
if(m_FadeVolumeLinear >= 1.f)
|
|
{
|
|
m_FadeState = kNotFading;
|
|
}
|
|
break;
|
|
case kFadingOut:
|
|
m_FadeVolumeLinear -= m_InvFadeTime * fwTimer::GetTimeStep();
|
|
m_FadeVolumeLinear = Max(m_FadeVolumeLinear, 0.f);
|
|
if(m_FadeVolumeLinear <= 0.f)
|
|
{
|
|
m_FadeState = kNotFading;
|
|
}
|
|
break;
|
|
case kWaitingToFadeIn:
|
|
m_FadeWaitTime -= fwTimer::GetTimeStep();
|
|
if(m_FadeWaitTime <= 0.f)
|
|
{
|
|
m_FadeState = kFadingIn;
|
|
}
|
|
break;
|
|
case kWaitingToFadeOut:
|
|
m_FadeWaitTime -= fwTimer::GetTimeStep();
|
|
if(m_FadeWaitTime <= 0.f)
|
|
{
|
|
m_FadeState = kFadingOut;
|
|
}
|
|
break;
|
|
case kNotFading:
|
|
// Don't reset the fade value here, as we want to hold the fade level
|
|
break;
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::CancelFade()
|
|
{
|
|
if(m_FadeVolumeLinear < 1.f)
|
|
{
|
|
m_FadeState = kFadingIn;
|
|
m_InvFadeTime = 2.f;
|
|
}
|
|
else
|
|
{
|
|
m_FadeState = kNotFading;
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::StartFadeIn(const float delayTime, const float fadeTime)
|
|
{
|
|
if(m_FadeState != kNotFading)
|
|
{
|
|
audWarningf("Radio was previously fading %s - overriding with new fade in time of %f", m_FadeState == kFadingIn ? "in" : "out", fadeTime);
|
|
}
|
|
if(fadeTime == 0.f)
|
|
{
|
|
m_FadeState = kNotFading;
|
|
m_FadeVolumeLinear = 1.f;
|
|
}
|
|
else
|
|
{
|
|
m_InvFadeTime = fadeTime > 0.f ? 1.f / fadeTime : 1.f;
|
|
m_FadeWaitTime = delayTime;
|
|
if(delayTime == 0.0f)
|
|
{
|
|
m_FadeState = kFadingIn;
|
|
}
|
|
else
|
|
{
|
|
m_FadeState = kWaitingToFadeIn;
|
|
}
|
|
|
|
// Note; it is assumed that the radio will not be audible when the fade is started
|
|
m_FadeVolumeLinear = 0.f;
|
|
}
|
|
|
|
}
|
|
|
|
void audRadioAudioEntity::StartFadeOut(const float delayTime, const float fadeTime)
|
|
{
|
|
if(m_FadeState != kNotFading)
|
|
{
|
|
audWarningf("Radio was previously fading - overriding with new fade in time of %f (delay time %f)", fadeTime, delayTime);
|
|
}
|
|
m_InvFadeTime = fadeTime > 0.f ? 1.f / fadeTime : 1.f;
|
|
m_FadeWaitTime = delayTime;
|
|
if(delayTime == 0.f)
|
|
{
|
|
m_FadeState = kFadingOut;
|
|
}
|
|
else
|
|
{
|
|
m_FadeState = kWaitingToFadeOut;
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::PreUpdateService(u32)
|
|
{
|
|
UpdateFade();
|
|
|
|
if(m_AutoUnfreezeForPlayerTimer > 0.f)
|
|
{
|
|
m_AutoUnfreezeForPlayerTimer -= fwTimer::GetTimeStep();
|
|
if(m_AutoUnfreezeForPlayerTimer <= 0.f)
|
|
{
|
|
m_AutoUnfreezeForPlayer = true;
|
|
}
|
|
}
|
|
|
|
const u32 timeInMs = GetCurrentTimeMs();
|
|
|
|
// always allow frontend radio while in frontend mode
|
|
if(IsInFrontendMode())
|
|
{
|
|
// Force the positioned smoother to 0
|
|
m_PositionedToStereoVolumeSmoother.Reset();
|
|
if(g_AudioEngine.GetSoundManager().IsPaused(2))
|
|
{
|
|
// If paused, force positioned for the transition out
|
|
m_PositionedToStereoVolumeSmoother.CalculateValue(0.0f, GetCurrentTimeMs());
|
|
m_PlayerVehicleInsideFactor = 0.f;
|
|
}
|
|
else
|
|
{
|
|
// If not paused, force frontend for the transition out
|
|
m_PositionedToStereoVolumeSmoother.CalculateValue(1.0f, GetCurrentTimeMs());
|
|
m_PlayerVehicleInsideFactor = 1.f;
|
|
}
|
|
|
|
}
|
|
|
|
// use the special radio timer
|
|
if(!g_AudioEngine.GetSoundManager().IsPaused(2))
|
|
{
|
|
if(!g_AudioEngine.IsAudioEnabled() || (audRadioStation::GetNumTotalStations() == 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If we're transitioning back from the pause menu and we're on a vehicle with no ambient radio, we need to bypass the normal delay
|
|
// since the radio will be silent for the transition, rather than muffled like it is on a vehicle with radio.
|
|
const bool quickTransitionBackOnBike = (audNorthAudioEngine::IsTransitioningOutOfPauseMenu() && m_PlayerVehicle && m_PlayerVehicle->GetAudioEntity() && m_PlayerVehicle->GetVehicleAudioEntity()->IsAmbientRadioDisabled());
|
|
const bool isSubmarine = m_PlayerVehicle && (m_PlayerVehicle->InheritsFromSubmarineCar() || m_PlayerVehicle->InheritsFromSubmarine());
|
|
const bool isSpectatingPedOnFoot = m_PlayerVehicle == NULL && NetworkInterface::IsGameInProgress() && NetworkInterface::IsLocalPlayerOnSCTVTeam();
|
|
|
|
const camBaseCamera* theActiveRenderedCamera = camInterface::GetDominantRenderedCamera();
|
|
const bool isCreatorModeFlyCamActive = theActiveRenderedCamera && (camScriptedFlyCamera::GetStaticClassId() == theActiveRenderedCamera->GetClassId());
|
|
|
|
// NOTE: use the radio timer for smoothing so that it doesn't slow down during slow mo sequences
|
|
const bool shouldPlayFrontendRadioInGame = (
|
|
!g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::FrontendRadioDisabled) &&
|
|
(sm_IsMobilePhoneRadioActive || (m_IsPlayerInVehicleForRadio && !FindPlayerPed()->IsDead()) || audRadioStation::IsPlayingEndCredits()) &&
|
|
(quickTransitionBackOnBike || audNorthAudioEngine::GetActiveSlowMoMode() == AUD_SLOWMO_RADIOWHEEL || g_AudioEngine.GetEnvironment().GetSpecialEffectMode() == kSpecialEffectModeNormal || ((isSubmarine || isSpectatingPedOnFoot || isCreatorModeFlyCamActive) && g_AudioEngine.GetEnvironment().GetSpecialEffectMode() == kSpecialEffectModeUnderwater)) &&
|
|
(g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::AllowRadioDuringSwitch) || !g_PlayerSwitch.ShouldDisableRadio())
|
|
);
|
|
|
|
#if !__NO_OUTPUT
|
|
if((!shouldPlayFrontendRadioInGame || m_VolumeOffset <= -36.f) && m_IsPlayerInAVehicleWithARadio)
|
|
{
|
|
static u32 s_LastWarnTime = 0;
|
|
const u32 warnTimeNow = GetCurrentTimeMs();
|
|
if(warnTimeNow > s_LastWarnTime + 1000)
|
|
{
|
|
if(g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::FrontendRadioDisabled))
|
|
{
|
|
audWarningf("Player vehicle frontend radio is disabled due to script flag FrontendRadioDisabled");
|
|
}
|
|
if(g_PlayerSwitch.ShouldDisableRadio())
|
|
{
|
|
audWarningf("Player vehicle frontend radio is disabled due to PlayerSwitch");
|
|
}
|
|
if(audNorthAudioEngine::GetActiveSlowMoMode() != AUD_SLOWMO_RADIOWHEEL && !quickTransitionBackOnBike && g_AudioEngine.GetEnvironment().GetSpecialEffectMode() != kSpecialEffectModeNormal)
|
|
{
|
|
audWarningf("Player vehicle frontend radio is disabled due to special effect flags. SlowMoMode: %s (%d) special effect mode: %d",
|
|
SlowMoType_ToString(audNorthAudioEngine::GetActiveSlowMoMode()), audNorthAudioEngine::GetActiveSlowMoMode(),
|
|
g_AudioEngine.GetEnvironment().GetSpecialEffectMode());
|
|
}
|
|
if(m_VolumeOffset <= -36.f)
|
|
{
|
|
audWarningf("Player vehicle frontend radio has been faded out via music event");
|
|
}
|
|
s_LastWarnTime = warnTimeNow;
|
|
}
|
|
}
|
|
#endif
|
|
// Save streaming bandwidth by turning off ambient / vehicle emitters when player is moving at speed
|
|
// or when score is playing
|
|
if(m_PlayerVehicle && (g_InteractiveMusicManager.IsMusicPlaying() ||
|
|
(!m_PlayerVehicle->InheritsFromBicycle() && m_PlayerVehicle->GetVehicleAudioEntity() && m_PlayerVehicle->GetVehicleAudioEntity()->GetCachedVelocity().Mag2() > (10.f*10.f))))
|
|
{
|
|
m_StopEmittersForPlayerVehicle = true;
|
|
}
|
|
else
|
|
{
|
|
m_StopEmittersForPlayerVehicle = false;
|
|
}
|
|
|
|
// We can't use the smoother in frontend mode
|
|
|
|
if(!IsInFrontendMode())
|
|
{
|
|
m_PlayerVehicleInsideFactor = m_PositionedToStereoVolumeSmoother.CalculateValue(shouldPlayFrontendRadioInGame ? 1.0f : 0.0f,
|
|
GetCurrentTimeMs());
|
|
}
|
|
|
|
//Don't update the user controls when we're starting up player radio, as we don't want to mess with that.
|
|
if((m_PlayerVehicleRadioState != PLAYER_RADIO_STARTING) && (m_MobilePhoneRadioState != PLAYER_RADIO_STARTING))
|
|
{
|
|
UpdateUserControl(timeInMs);
|
|
}
|
|
|
|
UpdatePlayerVehicleRadio(timeInMs);
|
|
UpdateMobilePhoneRadio(timeInMs);
|
|
|
|
const audRadioStation* stationBeingListenedTo = nullptr;
|
|
|
|
if (m_MobilePhoneRadioState == PLAYER_RADIO_PLAYING || m_PlayerVehicleRadioState == PLAYER_RADIO_PLAYING)
|
|
{
|
|
stationBeingListenedTo = m_PlayerRadioStation;
|
|
}
|
|
|
|
// We also count the closest audible interior station as being listened to (to pick up apartment radios etc.)
|
|
if (!stationBeingListenedTo && audNorthAudioEngine::GetGtaEnvironment()->AreWeInAnInterior())
|
|
{
|
|
s32 roomIdx = CPortalVisTracker::GetPrimaryRoomIdx();
|
|
CInteriorInst* pIntInst = CPortalVisTracker::GetPrimaryInteriorInst();
|
|
stationBeingListenedTo = FindAudibleStation(pIntInst, roomIdx);
|
|
}
|
|
|
|
if (stationBeingListenedTo)
|
|
{
|
|
// Accumulate system timestep to count time spent listening in the pause menu
|
|
const_cast<audRadioStation*>(stationBeingListenedTo)->SetListenTimer(stationBeingListenedTo->GetListenTimer() + fwTimer::GetSystemTimeStep());
|
|
}
|
|
|
|
ComputeVolumeOffset();
|
|
|
|
m_WasPlayerInVehicleForRadioLastFrame = m_IsPlayerInVehicleForRadio;
|
|
m_WasMobilePhoneRadioActiveLastFrame = sm_IsMobilePhoneRadioActive;
|
|
}
|
|
// need to keep updating slots while paused so that FE music etc gets a look in
|
|
audRadioSlot::UpdateSlots(timeInMs);
|
|
audRadioStation::UpdateStations(timeInMs);
|
|
|
|
// Store when we last retuned, and make sure we're on music
|
|
u32 gameTimeInMs = fwTimer::GetTimeInMilliseconds();
|
|
if (IsVehicleRadioOn() && IsRetuningVehicleRadio())
|
|
{
|
|
m_LastTimeVehicleRadioWasRetuned = gameTimeInMs;
|
|
m_VehicleRadioRetuneAlreadyFlagged = false;
|
|
}
|
|
if ((m_LastTimeVehicleRadioWasRetuned + 3000)< gameTimeInMs && !m_VehicleRadioRetuneAlreadyFlagged)
|
|
{
|
|
m_VehicleRadioRetuneAlreadyFlagged = true;
|
|
// only flag the retune if it's not talk radio, and it's on music
|
|
const audRadioStation* station = g_RadioAudioEntity.GetPlayerRadioStation();
|
|
if (station && !station->IsTalkStation())
|
|
{
|
|
const audRadioTrack &track = station->GetCurrentTrack();
|
|
if (track.IsInitialised())
|
|
{
|
|
u32 trackCategory = track.GetCategory();
|
|
if (trackCategory == RADIO_TRACK_CAT_MUSIC || trackCategory == RADIO_TRACK_CAT_TAKEOVER_MUSIC)
|
|
{
|
|
m_VehicleRadioJustRetuned = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_VehicleRadioJustRetuned = false;
|
|
}
|
|
|
|
m_CachedAudibleBeatValid = GetNextAudibleBeat(m_CachedTimeTillNextAudibleBeat, m_CachedAudibleBeatBPM, m_CachedAudibleBeatNum);
|
|
|
|
#if GTA_REPLAY
|
|
if(!audDriver::GetMixer()->IsCapturing())
|
|
{
|
|
PreUpdateReplayMusic();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if GTA_REPLAY
|
|
void audRadioAudioEntity::PreUpdateReplayMusic(bool play)
|
|
{
|
|
// Replay music is requested from the game-thread, so need to defer the creation of the sound until the audio update
|
|
static s32 delayCount = 0;
|
|
|
|
if(m_ShouldStopReplayMusic)
|
|
{
|
|
if(m_ReplayMusicSound)
|
|
{
|
|
if(!m_StopReplayMusicNoRelease && m_StopReplayMusicPreview && m_ShouldFadeReplayPreview)
|
|
{
|
|
m_ReplayMusicSound->SetReleaseTime(REPLAY_PREVIEW_FADE_LENGTH);
|
|
}
|
|
else if(!m_StopReplayMusicNoRelease)
|
|
{
|
|
m_ReplayMusicSound->SetReleaseTime(250);
|
|
}
|
|
m_ReplayMusicSound->StopAndForget();
|
|
}
|
|
|
|
m_ShouldStopReplayMusic = false;
|
|
m_StopReplayMusicNoRelease = false;
|
|
m_StopReplayMusicPreview = false;
|
|
}
|
|
|
|
if(m_ShouldPrepareReplayMusic)
|
|
{
|
|
audSoundInitParams initParams;
|
|
|
|
if(m_ReplayMusicStartOffset > 100)
|
|
{
|
|
initParams.StartOffset = m_ReplayMusicStartOffset;
|
|
}
|
|
initParams.EffectRoute = EFFECT_ROUTE_MUSIC;
|
|
initParams.TimerId = 1;
|
|
initParams.Category = g_AudioEngine.GetCategoryManager().GetCategoryPtr(ATSTRINGHASH("MUSIC_SLIDER", 0xA4D158B0));
|
|
Assign(initParams.BucketId, audNorthAudioEngine::GetBucketIdForStreamingSounds());
|
|
CreateSound_PersistentReference(m_PreviouslyRequestedReplayTrack, &m_ReplayMusicSound, &initParams);
|
|
|
|
if(m_ReplayMusicSound)
|
|
{
|
|
m_ReplayMusicSound->Prepare(g_InteractiveMusicManager.GetMusicWaveSlot(), true);
|
|
UpdateReplayMusicVolume(true);
|
|
delayCount = 1;
|
|
}
|
|
|
|
m_ShouldPrepareReplayMusic = false;
|
|
}
|
|
|
|
if(m_ShouldPlayReplayMusic)
|
|
{
|
|
if(m_ReplayMusicSound)
|
|
{
|
|
if(audDriver::GetMixer()->IsCapturing())
|
|
{
|
|
audPrepareState prepare = AUD_PREPARING;
|
|
|
|
if(delayCount > 0)
|
|
{
|
|
sysIpcSleep(1000);
|
|
prepare = m_ReplayMusicSound->Prepare(g_InteractiveMusicManager.GetMusicWaveSlot(), true);
|
|
}
|
|
delayCount++;
|
|
}
|
|
|
|
if(m_ReplayMusicSound->Prepare(g_InteractiveMusicManager.GetMusicWaveSlot(), true) == AUD_PREPARED)
|
|
{
|
|
//Displayf("prepared music : %d", delayCount);
|
|
delayCount = 0;
|
|
|
|
bool waitForPlayButton = false;
|
|
if(!play) // play overrides any waiting, play now!
|
|
{
|
|
bool loadingScreenActive = CVideoEditorPlayback::IsLoading();
|
|
waitForPlayButton = CReplayMgr::IsPlaybackPaused() || loadingScreenActive;
|
|
}
|
|
if(m_ReplayMusicSound->GetPlayState() != AUD_SOUND_PLAYING && !audDriver::GetMixer()->IsPaused(0) && (play || !waitForPlayButton ))
|
|
{
|
|
if(m_ReplayMusicStartOffset > 100)
|
|
{
|
|
m_ReplayMusicSound->SetRequestedPostSubmixVolumeAttenuation(g_SilenceVolume);
|
|
}
|
|
else
|
|
{
|
|
m_ReplayMusicSound->SetRequestedPostSubmixVolumeAttenuation(g_FrontendAudioEntity.GetMontageMusicVolume() + g_FrontendAudioEntity.GetClipMusicVolume() + audDriverUtil::ComputeDbVolumeFromLinear(m_ReplayMusicFadeOutScalar));
|
|
}
|
|
m_ReplayMusicSound->GetRequestedSettings()->SetShouldPersistOverClears(true);
|
|
m_ReplayMusicSound->Play();
|
|
UpdateReplayMusicVolume(true);
|
|
m_ShouldPlayReplayMusic = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_ShouldUpdateReplayPreview)
|
|
{
|
|
UpdateReplayTrackPreview();
|
|
m_ShouldUpdateReplayPreview = false;
|
|
}
|
|
|
|
if(m_ShouldUpdateReplayMusic)
|
|
{
|
|
UpdateReplayMusic();
|
|
m_ShouldUpdateReplayMusic = false;
|
|
}
|
|
}
|
|
#endif // GTA_REPLAY
|
|
|
|
void audRadioAudioEntity::UpdatePlayerVehicleRadio(u32 timeInMs)
|
|
{
|
|
audRadioEmitter *radioEmitter = NULL;
|
|
|
|
if(m_LastPlayerVehicle)
|
|
{
|
|
radioEmitter = m_LastPlayerVehicle->GetVehicleAudioEntity()->GetRadioEmitter();
|
|
}
|
|
else
|
|
{
|
|
// Do nothing - script often fiddle with the vehicles etc. during respawn so hold off updating until we are fading back into the game
|
|
if (!NetworkInterface::IsGameInProgress() || !camInterface::IsFadedOut() || m_PlayerVehicleRadioState != PLAYER_RADIO_PLAYING)
|
|
{
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_OFF);
|
|
}
|
|
}
|
|
|
|
switch(m_PlayerVehicleRadioState)
|
|
{
|
|
case PLAYER_RADIO_STARTING:
|
|
{
|
|
if(!m_PlayerRadioStation)
|
|
{
|
|
m_PlayerRadioStation = m_RequestedRadioStation? m_RequestedRadioStation : audRadioStation::GetStation(ChooseRandomRadioStationForGenre(RADIO_GENRE_UNSPECIFIED));
|
|
}
|
|
if(!audRadioSlot::RequestRadioStationForEmitter(m_PlayerRadioStation, radioEmitter,
|
|
audStreamSlot::STREAM_PRIORITY_PLAYER_RADIO))
|
|
{
|
|
audWarningf("Failed to request radio station %s for the player", m_PlayerRadioStation->GetName());
|
|
// We need to wait until we grab a slot so stay in the STARTING state
|
|
break;
|
|
}
|
|
|
|
m_LastPlayerVehicle->GetVehicleAudioEntity()->SetRadioStation(m_PlayerRadioStation);
|
|
if(m_PlayerRadioStation)
|
|
{
|
|
m_CurrentStationIndex = m_PlayerRadioStation->GetStationIndex();
|
|
}
|
|
if(m_PlayerRadioStation && m_PlayerRadioStation->IsFrozen())
|
|
{
|
|
if(m_AutoUnfreezeForPlayer)
|
|
{
|
|
Displayf("Automatically unfreezing player station (%s) (PLAYER_RADIO_STARTING)", m_PlayerRadioStation->GetName());
|
|
const_cast<audRadioStation*>(m_PlayerRadioStation)->Unfreeze();
|
|
}
|
|
else
|
|
{
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_FROZEN);
|
|
}
|
|
}
|
|
if(m_PlayerRadioStation && !m_PlayerRadioStation->IsFrozen() && m_PlayerRadioStation->IsStreamingPhysically())
|
|
{
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_PLAYING);
|
|
}
|
|
else
|
|
{
|
|
UpdateRetuneSounds();
|
|
}
|
|
m_PlayerRadioStationPendingRetune = m_PlayerRadioStation;
|
|
|
|
// Ensure we bail out of the STARTING state if we get stuck for some reason, since we disable retunes during that
|
|
if(GetCurrentTimeMs() > m_TimeEnteringStartingState + 30000)
|
|
{
|
|
audErrorf("Radio stuck in STARTING state for more than 30 seconds, on station %s. Switching off to recover",
|
|
m_PlayerRadioStation ? m_PlayerRadioStation->GetName() : "NULL");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STOPPING);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PLAYER_RADIO_FROZEN:
|
|
{
|
|
audRadioStation::StopRetuneSounds();
|
|
if(m_PlayerRadioStation && m_PlayerRadioStation->IsFrozen() && m_AutoUnfreezeForPlayer)
|
|
{
|
|
Displayf("Automatically unfreezing player station (%s) (PLAYER_RADIO_FROZEN)", m_PlayerRadioStation->GetName());
|
|
const_cast<audRadioStation*>(m_PlayerRadioStation)->Unfreeze();
|
|
}
|
|
if(m_PlayerRadioStation && !m_PlayerRadioStation->IsFrozen() && m_PlayerRadioStation->IsStreamingPhysically())
|
|
{
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_PLAYING);
|
|
}
|
|
/*else if(m_RequestedRadioStation != NULL)
|
|
{
|
|
audWarningf("Retuning radio from a frozen state");
|
|
|
|
u32 numStations = audRadioStation::GetNumUnlockedStations();
|
|
Assign(sm_PendingPlayerRadioStationRetunes,(m_RequestedRadioStation->GetStationIndex() + numStations - m_CurrentStationIndex) % numStations);
|
|
m_PlayerRadioStationPendingRetune = m_RequestedRadioStation;
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_RETUNING);
|
|
m_AutoUnfreezeForPlayer = true; // ensure user can't get stuck on a frozen station; if they choose one we'll unfreeze automatically.
|
|
m_RequestedRadioStation = NULL;
|
|
}*/
|
|
}
|
|
break;
|
|
|
|
case PLAYER_RADIO_PLAYING:
|
|
{
|
|
audRadioStation::StopRetuneSounds();
|
|
|
|
if (m_LastPlayerVehicle)
|
|
{
|
|
m_PlayerRadioStation = m_LastPlayerVehicle->GetVehicleAudioEntity()->GetRadioStation();
|
|
|
|
bool isStationLockedOrHidden = false;
|
|
|
|
if (m_PlayerRadioStation)
|
|
{
|
|
bool isHidden = m_PlayerRadioStation->IsHidden();
|
|
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
if (isHidden && m_LastPlayerVehicle->GetModelNameHash() == HEIST3_HIDDEN_RADIO_VEHICLE && m_PlayerRadioStation->GetNameHash() == HEIST3_HIDDEN_RADIO_STATION_NAME)
|
|
{
|
|
isHidden = false;
|
|
}
|
|
#endif
|
|
|
|
// We want to turn off the radio if we end up listening to a non-favourited station, but only for the player vehicle (as its valid for ambient vehicles
|
|
// to still listen to a non-favourited station). We also ignore this when the radio control is disabled as we assume that script are doing something
|
|
// custom (eg. forcing the user to listen to a particular station)
|
|
if(!g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::UserRadioControlDisabled))
|
|
{
|
|
if(!m_PlayerRadioStation->IsFavourited())
|
|
{
|
|
audDisplayf("Player is listening to a non favourite station, force stopping");
|
|
m_LastPlayerVehicle->GetVehicleAudioEntity()->SetRadioOffState(true);
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STOPPING);
|
|
break;
|
|
}
|
|
}
|
|
|
|
isStationLockedOrHidden = m_PlayerRadioStation->IsLocked() || (isHidden && !m_LastPlayerVehicle->GetVehicleAudioEntity()->IsInCarModShop());
|
|
}
|
|
|
|
// B*2518841 - Allow retuning to hidden radio whilst a vehicle is in the mod shop
|
|
if (!m_PlayerRadioStation || isStationLockedOrHidden)
|
|
{
|
|
if (m_LastPlayerVehicle->GetVehicleAudioEntity()->IsRadioSwitchedOff())
|
|
{
|
|
// Can happen if script switch instantly from one player controlled vehicle to another
|
|
audDisplayf("Player vehicle radio is playing but vehicle has it switched off, force stopping");
|
|
m_SkipOnOffSound = true;
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STOPPING);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// If we've simply 'lost' the station while in a network game with the screen faded out, its highly likely that script
|
|
// are messing with vehicles etc. behind the scenes, so just retune back to the previous station rather than advancing
|
|
// round the radio wheel (the station isn't locked or hiddens so there shouldn't be any reason why we can't simply retune
|
|
// back to it)
|
|
if (!isStationLockedOrHidden && NetworkInterface::IsGameInProgress() && camInterface::IsFadedOut())
|
|
{
|
|
// Force a retune to the same station
|
|
audDisplayf("Player vehicle radio station has been lost, force retuning to previous station");
|
|
sm_PendingPlayerRadioStationRetunes = 1;
|
|
sm_ForceVehicleExplicitRetune = true;
|
|
}
|
|
else
|
|
{
|
|
// Force a retune to a valid station
|
|
audDisplayf("Player station is now locked/hidden, force retuning");
|
|
sm_PendingPlayerRadioStationRetunes = 1;
|
|
sm_ForceVehicleExplicitRetune = false;
|
|
}
|
|
|
|
TriggerRetuneBurst();
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_RETUNING);
|
|
break;
|
|
}
|
|
}
|
|
m_PlayerRadioStationPendingRetune = m_PlayerRadioStation;
|
|
m_LastPlayerRadioStation = m_PlayerRadioStation;
|
|
|
|
if (m_PlayerRadioStation)
|
|
{
|
|
m_CurrentStationIndex = m_PlayerRadioStation->GetStationIndex();
|
|
}
|
|
|
|
if (m_PlayerRadioStation && m_PlayerRadioStation->IsFrozen() && m_AutoUnfreezeForPlayer)
|
|
{
|
|
Displayf("Automatically unfreezing player station (%s) (PLAYER_RADIO_PLAYING)", m_PlayerRadioStation->GetName());
|
|
const_cast<audRadioStation*>(m_PlayerRadioStation)->Unfreeze();
|
|
}
|
|
|
|
// Switch off the radio if the vehicle radio has been switched off
|
|
if (!m_PlayerVehicle || m_PlayerVehicle->GetVehicleAudioEntity()->IsRadioSwitchedOff())
|
|
{
|
|
audDisplayf("Player vehicle radio has been switched off - stopping");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STOPPING);
|
|
}
|
|
|
|
if (m_IsPlayerInVehicleForRadio)
|
|
{
|
|
m_LastActiveRadioTimeMs = timeInMs;
|
|
|
|
if (sm_PendingPlayerRadioStationRetunes > 0)
|
|
{
|
|
audDisplayf("Pending retunes = %d - retuning", sm_PendingPlayerRadioStationRetunes);
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_RETUNING);
|
|
}
|
|
|
|
#if !__FINAL
|
|
//Handle debug skip through radio tracks.
|
|
else if (sm_ShouldSkipForward)
|
|
{
|
|
audRadioSlot::FindAndSkipForwardEmitter(radioEmitter, g_RadioDebugSkipForwardTimeMs);
|
|
sm_ShouldSkipForward = false;
|
|
}
|
|
else if (sm_ShouldQuickSkipForward)
|
|
{
|
|
audRadioSlot::FindAndSkipForwardEmitter(radioEmitter, 10000);
|
|
sm_ShouldQuickSkipForward = false;
|
|
}
|
|
#endif // !__FINAL
|
|
else if (m_RequestedRadioStation != NULL)
|
|
{
|
|
audDisplayf("Requested radio station %s (current %s) - retuning", m_RequestedRadioStation->GetName(), m_PlayerRadioStation ? m_PlayerRadioStation->GetName() : "NULL");
|
|
u32 numStations = audRadioStation::GetNumUnlockedStations();
|
|
|
|
bool isHidden = m_RequestedRadioStation->IsHidden();
|
|
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
if (isHidden && m_PlayerVehicle && m_PlayerVehicle->GetModelNameHash() == HEIST3_HIDDEN_RADIO_VEHICLE && m_RequestedRadioStation->GetNameHash() == HEIST3_HIDDEN_RADIO_STATION_NAME)
|
|
{
|
|
isHidden = false;
|
|
}
|
|
#endif
|
|
|
|
// Special case logic if we're in the mod-shop and retuning to a hidden radio - just do a single retune and we jump stright to the desired station
|
|
if (isHidden && m_PlayerVehicle && m_PlayerVehicle->GetVehicleAudioEntity()->IsInCarModShop())
|
|
{
|
|
sm_PendingPlayerRadioStationRetunes = 1;
|
|
}
|
|
else
|
|
{
|
|
Assign(sm_PendingPlayerRadioStationRetunes, (m_RequestedRadioStation->GetStationIndex() + numStations - m_CurrentStationIndex) % numStations);
|
|
}
|
|
|
|
if (sm_PendingPlayerRadioStationRetunes > 0)
|
|
{
|
|
m_PlayerRadioStationPendingRetune = m_RequestedRadioStation;
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_RETUNING);
|
|
}
|
|
|
|
m_RequestedRadioStation = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//We are in a static playing state when the player is no longer in a vehicle, so force the state to off.
|
|
audDisplayf("Player not in vehicle for radio - switching off");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_OFF);
|
|
}
|
|
|
|
// If we've not changed state, ensure the station is still playing physically
|
|
if (m_PlayerRadioStation->IsStreamingVirtually() && m_PlayerVehicleRadioState == PLAYER_RADIO_PLAYING)
|
|
{
|
|
audErrorf("Player vehicle playing station virtually; restarting on %s", m_PlayerRadioStation->GetName());
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PLAYER_RADIO_STOPPING:
|
|
if(m_IsPlayerInVehicleForRadio)
|
|
{
|
|
if(m_PlayerRadioStation)
|
|
{
|
|
PlayRadioOnOffSound(false);
|
|
}
|
|
|
|
audRadioSlot::FindAndStopEmitter(radioEmitter);
|
|
m_PlayerRadioStationPendingRetune = m_PlayerRadioStation = NULL;
|
|
naCErrorf(m_LastPlayerVehicle, "During update of player vehicle radio, in PLAYER_RADIO_STOPPING state but there is no last player vehicle set");
|
|
//m_LastPlayerRadioStation = m_PlayerRadioStation;
|
|
}
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_OFF);
|
|
break;
|
|
|
|
case PLAYER_RADIO_RETUNING:
|
|
UpdateRetuneSounds();
|
|
if(sm_PendingPlayerRadioStationRetunes > 0)
|
|
{
|
|
bool isHidden = m_PlayerRadioStationPendingRetune && m_PlayerRadioStationPendingRetune->IsHidden();
|
|
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
if (isHidden && m_PlayerVehicle && m_PlayerVehicle->GetModelNameHash() == HEIST3_HIDDEN_RADIO_VEHICLE && m_PlayerRadioStationPendingRetune->GetNameHash() == HEIST3_HIDDEN_RADIO_STATION_NAME)
|
|
{
|
|
// Do nothing, keep the retune station to the hidden station
|
|
}
|
|
else
|
|
#endif
|
|
|
|
// B*2518841 - If we're in the car mod shop and want to retune to a hidden station, just retune to the explicit requested station.
|
|
// sm_PendingPlayerRadioStationRetunes assumes that the radio is one of the unlocked stations (ie. not hidden) and therefore isn't valid
|
|
if(!(m_PlayerRadioStationPendingRetune && m_PlayerVehicle && isHidden && m_PlayerVehicle->GetVehicleAudioEntity()->IsInCarModShop()))
|
|
{
|
|
if(sm_ForceVehicleExplicitRetune)
|
|
{
|
|
m_PlayerRadioStationPendingRetune = audRadioStation::GetStation(m_CurrentStationIndex % audRadioStation::GetNumUnlockedStations());
|
|
audDisplayf("Player radio retuning - target station is %s", m_PlayerRadioStationPendingRetune? m_PlayerRadioStationPendingRetune->GetName() : "null");
|
|
}
|
|
else
|
|
{
|
|
m_PlayerRadioStationPendingRetune = audRadioStation::GetStation((m_CurrentStationIndex + sm_PendingPlayerRadioStationRetunes) % audRadioStation::GetNumUnlockedStations());
|
|
audDisplayf("Player radio pending %d retunes - target station is %s", sm_PendingPlayerRadioStationRetunes, m_PlayerRadioStationPendingRetune? m_PlayerRadioStationPendingRetune->GetName() : "null");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
audDisplayf("Player retuning to a hidden modshop radio station %s", m_PlayerRadioStationPendingRetune? m_PlayerRadioStationPendingRetune->GetName() : "null");
|
|
}
|
|
|
|
const audRadioStation *station = m_PlayerRadioStationPendingRetune;
|
|
if(station && station->IsFrozen())
|
|
{
|
|
Displayf("Automatically unfreezing player station (%s) (RETUNING)", station->GetName());
|
|
const_cast<audRadioStation*>(station)->Unfreeze();
|
|
}
|
|
audRadioSlot::FindAndRetuneEmitter(radioEmitter);
|
|
}
|
|
else if(!audRadioSlot::IsEmitterRetuning(radioEmitter))
|
|
{
|
|
//We are done tuning.
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_PLAYING);
|
|
}
|
|
break;
|
|
|
|
case PLAYER_RADIO_OFF:
|
|
default: //Intentional fall-through.
|
|
if(!sm_IsMobilePhoneRadioActive)
|
|
{
|
|
audRadioStation::StopRetuneSounds();
|
|
}
|
|
if(m_PlayerVehicle && ((m_IsPlayerInAVehicleWithARadio && m_ForcePlayerStation) || m_IsPlayerInVehicleForRadio) && !m_WasPlayerInVehicleForRadioLastFrame)
|
|
{
|
|
const bool allowScoreAndRadio = g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::AllowScoreAndRadio);
|
|
const bool isScorePlaying = g_InteractiveMusicManager.IsMusicPlaying() && !allowScoreAndRadio && !g_InteractiveMusicManager.IsScoreMutedForRadio();
|
|
const bool isForcingStation = (m_ForcePlayerStation != NULL);
|
|
|
|
m_PlayerRadioStation = m_PlayerVehicle->GetVehicleAudioEntity()->GetRadioStation();
|
|
|
|
//Only automatically turn on the radio if the player has not previous turned this radio off, or if mobile phone
|
|
//radio is active, as this should transfer to the vehicle radio.
|
|
if(isForcingStation && !m_PlayerVehicle->GetVehicleAudioEntity()->IsRadioSwitchedOn())
|
|
{
|
|
audDisplayf("Forcing radio station, but radio is currently off - switching ON");
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioOffState(false);
|
|
}
|
|
if(m_PlayerVehicle->GetVehicleAudioEntity()->IsRadioSwitchedOn() || sm_IsMobilePhoneRadioActive)
|
|
{
|
|
if(isForcingStation || m_PlayerRadioStation == NULL)
|
|
{
|
|
if(isForcingStation)
|
|
{
|
|
m_PlayerRadioStation = m_ForcePlayerStation;
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioStation(m_ForcePlayerStation, true, true);
|
|
audAssertf(m_PlayerVehicle->GetVehicleAudioEntity()->GetRadioStation() == m_ForcePlayerStation, "Failed to set radio station on the player vehicle!");
|
|
|
|
naDisplayf("Forced retune to station %s", m_ForcePlayerStation->GetName());
|
|
m_ForcePlayerStation = NULL;
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
else if(m_PlayerVehicle->GetVehicleAudioEntity()->GetLastRadioStation() != NULL)
|
|
{
|
|
m_PlayerRadioStation = m_PlayerVehicle->GetVehicleAudioEntity()->GetLastRadioStation();
|
|
audDisplayf("Re-starting player radio with previous radio station (%s)", m_PlayerRadioStation->GetName());
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
/*else if(!isScorePlaying &&
|
|
(m_LastPlayerRadioStation) &&
|
|
(timeInMs < (m_LastActiveRadioTimeMs + g_MaxPlayerOutOfVehicleTimeForAutoTune)))
|
|
{
|
|
//Auto-tune to the last player station.
|
|
m_PlayerRadioStation = m_LastPlayerRadioStation;
|
|
TriggerRetuneBurst();
|
|
naDisplayf("Autotuning radio");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}*/
|
|
else
|
|
{
|
|
//Choose a random station to start with.
|
|
m_PlayerRadioStation = audRadioStation::GetStation(ChooseRandomRadioStationForGenre(m_PlayerVehicle->GetVehicleAudioEntity()->GetRadioGenre()));
|
|
// NOTE: this will leave the radio off if the car was set up as OFF; required for the hearse
|
|
if(m_PlayerRadioStation == NULL)
|
|
{
|
|
audDisplayf("Vehicle has OFF as the default genre - leaving radio OFF");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_OFF);
|
|
break;
|
|
}
|
|
|
|
audDisplayf("Picked %s as a random radio station based on genre", m_PlayerRadioStation->GetName());
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
|
|
if(isScorePlaying && !(m_PlayerRadioStation && m_PlayerRadioStation->IsFrozen()))
|
|
{
|
|
// switch the vehicle radio off if score is active and the player station isn't frozen
|
|
audDisplayf("1 - Switching OFF player radio. isScorePlaying: %s, playerRadioFrozen: %s", isScorePlaying? "true" : "false", m_PlayerRadioStation ? (m_PlayerRadioStation->IsFrozen()? "true" : "false") : "NULL");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_OFF);
|
|
m_PlayerRadioStation = NULL;
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioOffState(true);
|
|
}
|
|
else
|
|
{
|
|
audDisplayf("2 - STARTING player radio station %s. isScorePlaying: %s, playerRadioFrozen: %s", m_PlayerRadioStation->GetName(), isScorePlaying? "true" : "false", m_PlayerRadioStation ? (m_PlayerRadioStation->IsFrozen()? "true" : "false") : "NULL");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(isScorePlaying && !(m_PlayerRadioStation && m_PlayerRadioStation->IsFrozen()))
|
|
{
|
|
if(m_PlayerRadioStation && NetworkInterface::IsGameInProgress() && m_PlayerVehicle->GetDriver() && m_PlayerVehicle->GetDriver()->IsNetworkPlayer())
|
|
{
|
|
//We want to play the active vehicle station.
|
|
audDisplayf("8 - Score playing, but entering network player vehicle which has the radio on. STARTING player radio station %s to keep in sync. isScorePlaying: %s, playerRadioFrozen: %s", m_PlayerRadioStation->GetName(), isScorePlaying? "true" : "false", m_PlayerRadioStation ? (m_PlayerRadioStation->IsFrozen()? "true" : "false") : "NULL");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING); // was playing
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
else
|
|
{
|
|
// If music is playing and we enter a vehicle with a radio, switch it off
|
|
audDisplayf("3 - STOPPING player radio. isScorePlaying: %s, playerRadioFrozen: %s", isScorePlaying? "true" : "false", m_PlayerRadioStation ? (m_PlayerRadioStation->IsFrozen()? "true" : "false") : "NULL");
|
|
m_SkipOnOffSound = true;
|
|
|
|
if (m_PlayerVehicleRadioState != PLAYER_RADIO_OFF)
|
|
{
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STOPPING);
|
|
}
|
|
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioOffState(true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//We want to play the active vehicle station.
|
|
audDisplayf("4 - STARTING player radio station %s. isScorePlaying: %s, playerRadioFrozen: %s", m_PlayerRadioStation->GetName(), isScorePlaying? "true" : "false", m_PlayerRadioStation ? (m_PlayerRadioStation->IsFrozen()? "true" : "false") : "NULL");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING); // was playing
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
}
|
|
}
|
|
}
|
|
else if(m_PlayerRadioStation != NULL)
|
|
{
|
|
if(isScorePlaying && !(m_PlayerRadioStation && m_PlayerRadioStation->IsFrozen()))
|
|
{
|
|
// If music is playing and we enter a vehicle with a radio, switch it off
|
|
audDisplayf("5- STOPPING player radio. isScorePlaying: %s, playerRadioFrozen: %s", isScorePlaying? "true" : "false", m_PlayerRadioStation ? (m_PlayerRadioStation->IsFrozen()? "true" : "false") : "NULL");
|
|
m_SkipOnOffSound = true;
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STOPPING);
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioOffState(true);
|
|
}
|
|
else
|
|
{
|
|
//We want to play the active vehicle station.
|
|
audDisplayf("6 - PLAYING player radio. isScorePlaying: %s, playerRadioFrozen: %s", isScorePlaying? "true" : "false", m_PlayerRadioStation ? (m_PlayerRadioStation->IsFrozen()? "true" : "false") : "NULL");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_PLAYING);
|
|
}
|
|
}
|
|
else if(isScorePlaying)
|
|
{
|
|
// Leave the radio off
|
|
audDisplayf("7 - Score is playing, swtiching radio off.");
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_OFF);
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Clear network flag whenever radio is off/retuned
|
|
m_bMPDriverHasTriggeredRadioChange &= IsRetuningVehicleRadio();
|
|
}
|
|
|
|
void audRadioAudioEntity::SetPlayerVehicleRadioState(u8 newState)
|
|
{
|
|
if (newState != m_PlayerVehicleRadioState)
|
|
{
|
|
m_PlayerVehicleRadioState = newState;
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::SetMobileRadioState(u8 newState)
|
|
{
|
|
if (newState != m_MobilePhoneRadioState)
|
|
{
|
|
m_MobilePhoneRadioState = newState;
|
|
}
|
|
}
|
|
|
|
bool audRadioAudioEntity::IsMobileRadioNormallyPermitted() const
|
|
{
|
|
return !CNetwork::IsGameInProgress() && !CTheScripts::GetPlayerIsOnAMission() && !audNorthAudioEngine::GetGtaEnvironment()->AreWeInAnInterior() && sm_IsMobilePhoneRadioAvailable;
|
|
}
|
|
|
|
void audRadioAudioEntity::UpdateMobilePhoneRadio(u32 timeInMs)
|
|
{
|
|
audRadioEmitter *radioEmitter = &m_MobilePhoneRadioEmitter;
|
|
|
|
// ensure mobile radio is never active in game play unless explicitly requested by script
|
|
if(!IsInFrontendMode() && !IsMobileRadioNormallyPermitted() && !g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::MobileRadioInGame) && sm_IsMobilePhoneRadioActive && !fwTimer::IsGamePaused() && !audNorthAudioEngine::IsInNetworkLobby() && !audRadioStation::IsPlayingEndCredits() && DYNAMICMIXER.GetMobileRadioCount() == 0)
|
|
{
|
|
SetMobilePhoneRadioState(false);
|
|
}
|
|
|
|
#if GTA_REPLAY
|
|
if(CReplayMgr::IsEditModeActive())
|
|
{
|
|
SetMobilePhoneRadioState(false);
|
|
}
|
|
#endif
|
|
|
|
if((!sm_IsMobilePhoneRadioActive && m_WasMobilePhoneRadioActiveLastFrame) || (m_PlayerVehicleRadioState == PLAYER_RADIO_PLAYING))
|
|
{
|
|
//The player just turned off mobile phone radio, or has active vehicle radio, so force the state to off.
|
|
SetMobileRadioState(PLAYER_RADIO_OFF);
|
|
}
|
|
|
|
switch(m_MobilePhoneRadioState)
|
|
{
|
|
case PLAYER_RADIO_STARTING:
|
|
StartMobileRadio();
|
|
break;
|
|
|
|
case PLAYER_RADIO_PLAYING:
|
|
|
|
// Wait until the track is playing before we stop the retune sound
|
|
if(m_PlayerRadioStation && m_PlayerRadioStation->GetCurrentTrack().IsPlayingPhysicallyOrVirtually())
|
|
{
|
|
audRadioStation::StopRetuneSounds();
|
|
}
|
|
if(!m_PlayerRadioStation || m_PlayerRadioStation->IsLocked() || m_PlayerRadioStation->IsHidden())
|
|
{
|
|
audDisplayf("Player mobile radio station is now locked, force retuning");
|
|
// Force a retune to a valid station
|
|
sm_PendingPlayerRadioStationRetunes = 1;
|
|
SetMobileRadioState(PLAYER_RADIO_RETUNING);
|
|
break;
|
|
}
|
|
|
|
if(m_PlayerRadioStation)
|
|
{
|
|
m_CurrentStationIndex = m_PlayerRadioStation->GetStationIndex();
|
|
}
|
|
m_PlayerRadioStationPendingRetune = m_PlayerRadioStation;
|
|
m_LastPlayerRadioStation = m_PlayerRadioStation;
|
|
m_LastActiveRadioTimeMs = timeInMs;
|
|
|
|
if(sm_PendingPlayerRadioStationRetunes > 0)
|
|
{
|
|
m_PlayerRadioStationPendingRetune = audRadioStation::GetStation((m_CurrentStationIndex + sm_PendingPlayerRadioStationRetunes) %
|
|
audRadioStation::GetNumUnlockedStations());
|
|
SetMobileRadioState(PLAYER_RADIO_RETUNING);
|
|
}
|
|
#if !__FINAL
|
|
//Handle debug skip through radio tracks.
|
|
else if(sm_ShouldSkipForward)
|
|
{
|
|
audRadioSlot::FindAndSkipForwardEmitter(radioEmitter, g_RadioDebugSkipForwardTimeMs);
|
|
sm_ShouldSkipForward = false;
|
|
}
|
|
else if(sm_ShouldQuickSkipForward)
|
|
{
|
|
audRadioSlot::FindAndSkipForwardEmitter(radioEmitter, 10000);
|
|
sm_ShouldQuickSkipForward = false;
|
|
}
|
|
#endif // !__FINAL
|
|
else if(m_RequestedRadioStation)
|
|
{
|
|
u32 numStations = audRadioStation::GetNumUnlockedStations();
|
|
Assign(sm_PendingPlayerRadioStationRetunes, (m_RequestedRadioStation->GetStationIndex() + numStations - m_CurrentStationIndex) % numStations);
|
|
|
|
if (sm_PendingPlayerRadioStationRetunes > 0)
|
|
{
|
|
m_PlayerRadioStationPendingRetune = m_RequestedRadioStation;
|
|
SetMobileRadioState(PLAYER_RADIO_RETUNING);
|
|
}
|
|
|
|
m_RequestedRadioStation = NULL;
|
|
}
|
|
break;
|
|
|
|
case PLAYER_RADIO_STOPPING:
|
|
{
|
|
PlayRadioOnOffSound(false);
|
|
audRadioSlot::FindAndStopEmitter(radioEmitter);
|
|
m_PlayerRadioStationPendingRetune = m_PlayerRadioStation = NULL;
|
|
SetMobileRadioState(PLAYER_RADIO_OFF);
|
|
}
|
|
break;
|
|
|
|
case PLAYER_RADIO_RETUNING:
|
|
UpdateRetuneSounds();
|
|
|
|
if(sm_PendingPlayerRadioStationRetunes > 0)
|
|
{
|
|
m_PlayerRadioStationPendingRetune = audRadioStation::GetStation((m_CurrentStationIndex + sm_PendingPlayerRadioStationRetunes) %
|
|
audRadioStation::GetNumUnlockedStations());
|
|
audRadioSlot::FindAndRetuneEmitter(radioEmitter);
|
|
}
|
|
else if(!audRadioSlot::IsEmitterRetuning(radioEmitter))
|
|
{
|
|
//We are done tuning.
|
|
SetMobileRadioState(PLAYER_RADIO_PLAYING);
|
|
}
|
|
break;
|
|
|
|
case PLAYER_RADIO_OFF:
|
|
default: //Intentional fall-through.
|
|
//audRadioStation::StopRetuneSounds();
|
|
if(sm_IsMobilePhoneRadioActive && (m_PlayerVehicleRadioState == PLAYER_RADIO_OFF))
|
|
{
|
|
//Auto-tune to the last player station.
|
|
if (!CPauseMenu::IsActive() || !m_PlayerRadioStation) // Possibly should always do this? Intentionally limiting scope to pause menu only as a targetted fix for url:bugstar:7441459 Fixer: 3A - When cycling through the radio stations in the Front End Menu, the station selected does not match the audio being played.
|
|
{
|
|
m_PlayerRadioStation = m_LastPlayerRadioStation;
|
|
}
|
|
|
|
if(m_ForcePlayerStation != NULL || m_PlayerRadioStation == NULL)
|
|
{
|
|
//Choose a random station to start with.
|
|
//TriggerRetuneBurst();
|
|
|
|
if(m_ForcePlayerStation != NULL)
|
|
{
|
|
m_PlayerRadioStation = m_ForcePlayerStation;
|
|
/*if(!g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::StickyForcedRadioStation))
|
|
{
|
|
m_ForcePlayerStation = NULL;
|
|
}*/
|
|
}
|
|
else
|
|
{
|
|
// Keep in sync with the pause menu
|
|
u32 stationIndex = (u32)CPauseMenu::GetMenuPreference(PREF_RADIO_STATION);
|
|
if(audVerifyf(stationIndex < audRadioStation::GetNumUnlockedStations(), "Invalid station ID in PREF_RADIO_STATION: %u (only have %u stations)", stationIndex, audRadioStation::GetNumUnlockedStations() ))
|
|
{
|
|
m_PlayerRadioStation = audRadioStation::GetStation(stationIndex);
|
|
}
|
|
else
|
|
{
|
|
m_PlayerRadioStation = audRadioStation::GetStation(0);
|
|
}
|
|
}
|
|
}
|
|
else if(!audRadioSlot::IsStationActive(m_PlayerRadioStation) && !IsInFrontendMode() && !audRadioStation::IsPlayingEndCredits())
|
|
{
|
|
//TriggerRetuneBurst();
|
|
}
|
|
|
|
SetMobileRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
StartMobileRadio();
|
|
}
|
|
else
|
|
{
|
|
//Ensure we remove the emitter for the player's mobile phone if it isn't active.
|
|
audRadioSlot::FindAndStopEmitter(radioEmitter);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::StartMobileRadio()
|
|
{
|
|
if (m_RequestedRadioStation && m_PlayerRadioStation != m_RequestedRadioStation)
|
|
{
|
|
m_PlayerRadioStation = m_RequestedRadioStation;
|
|
}
|
|
|
|
if (!audRadioSlot::RequestRadioStationForEmitter(m_PlayerRadioStation, &m_MobilePhoneRadioEmitter,
|
|
audStreamSlot::STREAM_PRIORITY_PLAYER_RADIO))
|
|
{
|
|
audWarningf("Failed to request radio station %s for player mobile radio", m_PlayerRadioStation ? m_PlayerRadioStation->GetName() : "NULL");
|
|
}
|
|
else
|
|
{
|
|
if (m_PlayerRadioStation && m_PlayerRadioStation->IsStreamingPhysically())
|
|
{
|
|
SetMobileRadioState(PLAYER_RADIO_PLAYING);
|
|
}
|
|
|
|
m_PlayerRadioStationPendingRetune = m_PlayerRadioStation;
|
|
}
|
|
}
|
|
|
|
bool audRadioAudioEntity::StopEmittersForPlayerVehicle() const
|
|
{
|
|
return m_StopEmittersForPlayerVehicle;
|
|
}
|
|
|
|
const audRadioStation *audRadioAudioEntity::RequestVehicleRadio(CVehicle *vehicle)
|
|
{
|
|
const audRadioStation *radioStation = NULL;
|
|
const bool vehicleContainsPlayer = vehicle->ContainsLocalPlayer();
|
|
|
|
if(m_MobilePhoneRadioState == PLAYER_RADIO_PLAYING && vehicleContainsPlayer && m_PlayerRadioStation)
|
|
{
|
|
audRadioEmitter *radioEmitter = vehicle->GetVehicleAudioEntity()->GetRadioEmitter();
|
|
if(audRadioSlot::RequestRadioStationForEmitter(m_PlayerRadioStation, radioEmitter, radioEmitter->GetPriority()))
|
|
{
|
|
return m_PlayerRadioStation;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if((vehicle != NULL) && (audRadioStation::GetNumUnlockedStations() > 0))
|
|
{
|
|
CVehicle *playerVehicle = CGameWorld::FindLocalPlayerVehicle();
|
|
|
|
bool followPlayerInCar = false;
|
|
if (NetworkInterface::IsGameInProgress() && NetworkInterface::IsLocalPlayerOnSCTVTeam())
|
|
{
|
|
CPed* pFollowPlayer = CGameWorld::FindFollowPlayer();
|
|
if (pFollowPlayer && pFollowPlayer->GetPedConfigFlag( CPED_CONFIG_FLAG_InVehicle ))
|
|
{
|
|
CVehicle* pFollowPlayerVehicle = pFollowPlayer->GetMyVehicle();
|
|
if (pFollowPlayerVehicle)
|
|
followPlayerInCar = (pFollowPlayerVehicle==vehicle);
|
|
}
|
|
}
|
|
|
|
//Don't request any ambient radio when the player moving quickly in a vehicle, to save streaming bandwidth.
|
|
if(vehicleContainsPlayer || followPlayerInCar || playerVehicle == NULL || playerVehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE || !StopEmittersForPlayerVehicle())
|
|
{
|
|
//Don't play radio from all vehicles, and allow the vehicle to specify no radio.
|
|
// If script have specified LOUD_RADIO then skip the random probability
|
|
if(vehicleContainsPlayer || vehicle->GetVehicleAudioEntity()->IsPersonalVehicle() || followPlayerInCar || vehicle->GetVehicleAudioEntity()->HasLoudRadio() || audEngineUtil::ResolveProbability(g_VehicleRadioProbability))
|
|
{
|
|
// use the last radio station for this car if there was one
|
|
const audRadioStation *lastRadioStation = vehicle->GetVehicleAudioEntity()->GetLastRadioStation();
|
|
if(lastRadioStation)
|
|
{
|
|
radioStation = lastRadioStation;
|
|
// Don't allow ambient, non-player vehicles to select a frozen station
|
|
if(!vehicleContainsPlayer && !followPlayerInCar && !vehicle->PopTypeIsMission() && (radioStation->IsFrozen() || radioStation->IsLocked()))
|
|
{
|
|
radioStation = NULL;
|
|
}
|
|
else
|
|
{
|
|
//See if we can play it.
|
|
audRadioEmitter *radioEmitter = vehicle->GetVehicleAudioEntity()->GetRadioEmitter();
|
|
if(!audRadioSlot::RequestRadioStationForEmitter(radioStation, radioEmitter, radioEmitter->GetPriority()))
|
|
{
|
|
radioStation = NULL;
|
|
}
|
|
|
|
// Automatically unfreeze a station if the player is going to listen to it.
|
|
if(radioStation && m_AutoUnfreezeForPlayer && (vehicleContainsPlayer || followPlayerInCar) && radioStation->IsFrozen())
|
|
{
|
|
Displayf("Auto-Unfreezing radio station %s for player vehicle", radioStation->GetName());
|
|
const_cast<audRadioStation*>(radioStation)->Unfreeze();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
if (vehicle->GetModelNameHash() == HEIST3_HIDDEN_RADIO_VEHICLE)
|
|
{
|
|
if (GetEncryptionKeyForBank(audRadioStation::sm_Heist3HiddenRadioBankId))
|
|
{
|
|
radioStation = audRadioStation::FindStation(HEIST3_HIDDEN_RADIO_STATION_NAME);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Only switch a radio on automatically if the vehicle is not tagged with the 'off' genre
|
|
if(!radioStation && vehicle->GetVehicleAudioEntity()->GetRadioGenre() != RADIO_GENRE_OFF)
|
|
{
|
|
// Player character overrides
|
|
if(m_ForcePlayerCharacterStations && radioStation == NULL && vehicle->GetDriver())
|
|
{
|
|
switch(vehicle->GetDriver()->GetPedType())
|
|
{
|
|
case PEDTYPE_PLAYER_0: //MICHAEL
|
|
{
|
|
radioStation = audRadioStation::FindStation(ATSTRINGHASH("RADIO_01_CLASS_ROCK", 0x9E34587));
|
|
}
|
|
break;
|
|
case PEDTYPE_PLAYER_1: //FRANKLIN
|
|
{
|
|
radioStation = audRadioStation::FindStation(ATSTRINGHASH("RADIO_03_HIPHOP_NEW", 0xFA17DE37));
|
|
}
|
|
break;
|
|
case PEDTYPE_PLAYER_2: //TREVOR
|
|
{
|
|
radioStation = audRadioStation::FindStation(ATSTRINGHASH("RADIO_04_PUNK", 0x719B0AFB));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If the vehicle hasn't already picked a station, choose based on ped/vehicle genre
|
|
if(radioStation == NULL)
|
|
{
|
|
const bool isPlayerDriver = vehicle->GetDriver() && vehicle->GetDriver()->IsPlayer();
|
|
|
|
//Choose a station at random based on genre prefs
|
|
RadioGenre genre1 = RADIO_GENRE_UNSPECIFIED, genre2 = RADIO_GENRE_UNSPECIFIED;
|
|
if(vehicle->GetDriver() && !vehicle->GetDriver()->IsPlayer())
|
|
{
|
|
s32 g1, g2;
|
|
vehicle->GetDriver()->GetPedRadioCategory(g1, g2);
|
|
if(g1 != -1)
|
|
{
|
|
genre1 = (RadioGenre)g1;
|
|
}
|
|
if(g2 != -1)
|
|
{
|
|
genre2 = (RadioGenre)g2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
genre1 = vehicle->GetVehicleAudioEntity()->GetRadioGenre();
|
|
}
|
|
|
|
radioStation = audRadioStation::GetStation(ChooseRandomRadioStationForGenre(genre1));
|
|
|
|
bool pickFavouriteAsFallback = false;
|
|
|
|
if(radioStation && isPlayerDriver && !radioStation->IsFavourited())
|
|
{
|
|
pickFavouriteAsFallback = true;
|
|
radioStation = nullptr;
|
|
}
|
|
|
|
if(radioStation)
|
|
{
|
|
//See if we can play it.
|
|
audRadioEmitter *radioEmitter = vehicle->GetVehicleAudioEntity()->GetRadioEmitter();
|
|
if(!audRadioSlot::RequestRadioStationForEmitter(radioStation, radioEmitter, radioEmitter->GetPriority()))
|
|
{
|
|
radioStation = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
if(radioStation == NULL && genre2 != RADIO_GENRE_OFF)
|
|
{
|
|
// fall back to the second choice
|
|
radioStation = audRadioStation::GetStation(ChooseRandomRadioStationForGenre(genre2));
|
|
|
|
if(radioStation && isPlayerDriver && !radioStation->IsFavourited())
|
|
{
|
|
pickFavouriteAsFallback = true;
|
|
radioStation = nullptr;
|
|
}
|
|
|
|
if(radioStation)
|
|
{
|
|
//See if we can play it.
|
|
audRadioEmitter *radioEmitter = vehicle->GetVehicleAudioEntity()->GetRadioEmitter();
|
|
if(!audRadioSlot::RequestRadioStationForEmitter(radioStation, radioEmitter, radioEmitter->GetPriority()))
|
|
{
|
|
radioStation = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!radioStation && pickFavouriteAsFallback)
|
|
{
|
|
if(audRadioStation::GetNumUnlockedFavouritedStations() > 0)
|
|
{
|
|
u32 stationIndex = audEngineUtil::GetRandomNumberInRange(0, audRadioStation::GetNumUnlockedFavouritedStations()-1);
|
|
radioStation = audRadioStation::GetStation(stationIndex);
|
|
|
|
if(radioStation)
|
|
{
|
|
//See if we can play it.
|
|
audRadioEmitter *radioEmitter = vehicle->GetVehicleAudioEntity()->GetRadioEmitter();
|
|
if(!audRadioSlot::RequestRadioStationForEmitter(radioStation, radioEmitter, radioEmitter->GetPriority()))
|
|
{
|
|
radioStation = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}// genre != off
|
|
}
|
|
}
|
|
}
|
|
|
|
return radioStation;
|
|
}
|
|
|
|
u32 audRadioAudioEntity::ChooseRandomRadioStationForGenre(const RadioGenre genre) const
|
|
{
|
|
if(g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::LimitAmbientRadioStations))
|
|
{
|
|
// MAGDEMO 2012 - limit radio station selection
|
|
atFixedArray<u32,4> options;
|
|
for(u32 i = 0; i < audRadioStation::GetNumUnlockedStations(); i++)
|
|
{
|
|
audRadioStation *station = audRadioStation::GetStation(i);
|
|
if(station->IsTalkStation() || station->IsInGenre(RADIO_GENRE_POP) || station->IsInGenre(RADIO_GENRE_CLASSIC_HIPHOP))
|
|
{
|
|
options.Append() = i;
|
|
}
|
|
}
|
|
if(options.GetCount() == 0)
|
|
{
|
|
return g_OffRadioStation;
|
|
}
|
|
return options[audEngineUtil::GetRandomNumberInRange(0, options.GetCount()-1)];
|
|
}
|
|
else
|
|
{
|
|
if(genre == RADIO_GENRE_UNSPECIFIED)
|
|
{
|
|
// pick at random
|
|
return audEngineUtil::GetRandomNumberInRange(0, audRadioStation::GetNumUnlockedStations()-1);
|
|
}
|
|
else if(genre == RADIO_GENRE_OFF)
|
|
{
|
|
return g_OffRadioStation;
|
|
}
|
|
else
|
|
{
|
|
const u32 maxOptions = 3;
|
|
u32 options[maxOptions];
|
|
u32 numOptions = 0;
|
|
for(u32 i = 0; i < audRadioStation::GetNumUnlockedStations(); i++)
|
|
{
|
|
const audRadioStation *station = audRadioStation::GetStation(i);
|
|
|
|
if(station->IsInGenre(genre))
|
|
{
|
|
// if we find a match that's streaming physically then use that so we maximise disk bandwidth
|
|
if(station->IsStreamingPhysically())
|
|
{
|
|
return i;
|
|
}
|
|
else
|
|
{
|
|
if(numOptions < maxOptions)
|
|
{
|
|
options[numOptions++] = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(numOptions == 0)
|
|
{
|
|
//Assert(0);
|
|
return g_OffRadioStation;
|
|
}
|
|
else
|
|
{
|
|
return options[audEngineUtil::GetRandomNumberInRange(0, numOptions-1)];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::StopVehicleRadio(CVehicle *vehicle, bool clearStation)
|
|
{
|
|
if(naVerifyf(vehicle, "Null CVehicle * passed into StopVehicleRadio"))
|
|
{
|
|
if(vehicle == FindPlayerVehicle() && m_IgnorePlayerVehicleRadioShutdown)
|
|
{
|
|
return;
|
|
}
|
|
|
|
audRadioEmitter *radioEmitter = vehicle->GetVehicleAudioEntity()->GetRadioEmitter();
|
|
audRadioSlot::FindAndStopEmitter(radioEmitter, clearStation);
|
|
}
|
|
|
|
if(vehicle == m_LastPlayerVehicle)
|
|
{
|
|
if(!sm_IsMobilePhoneRadioActive)
|
|
{
|
|
//Ensure we stop the retune sounds for the player's last vehicle to catch the case of the vehicle
|
|
//being destroyed while its radio is retuning.
|
|
audRadioStation::StopRetuneSounds();
|
|
sm_PendingPlayerRadioStationRetunes = 0;
|
|
}
|
|
m_LastPlayerVehicle = NULL;
|
|
}
|
|
}
|
|
|
|
bool audRadioAudioEntity::RequestStaticRadio(audStaticRadioEmitter *emitter, u32 stationNameHash, s32 requestedPCMChannel)
|
|
{
|
|
naCErrorf(emitter, "Null audStaticRadioEmitter passed into RequestStaticRadio");
|
|
|
|
if(emitter && (audRadioStation::GetNumUnlockedStations() > 0) REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive()))
|
|
{
|
|
if(!StopEmittersForPlayerVehicle())
|
|
{
|
|
const audRadioStation *station = NULL;
|
|
if(stationNameHash == ATSTRINGHASH("random", 0xEBE23568))
|
|
{
|
|
station = audRadioStation::GetStation(audEngineUtil::GetRandomNumberInRange(0, audRadioStation::GetNumUnlockedStations() - 1));
|
|
}
|
|
else
|
|
{
|
|
station = audRadioStation::FindStation(stationNameHash);
|
|
}
|
|
|
|
if(station)
|
|
{
|
|
//See if we can play it.
|
|
if(audRadioSlot::RequestRadioStationForEmitter(station, emitter, emitter->GetPriority(), requestedPCMChannel))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void audRadioAudioEntity::StopStaticRadio(audStaticRadioEmitter *emitter)
|
|
{
|
|
naAssertf(emitter, "Null audStaticRadioEmitter passed into StopStaticRadio");
|
|
audRadioSlot::FindAndStopEmitter(emitter);
|
|
}
|
|
|
|
bool audRadioAudioEntity::IsStaticRadioEmitterActive(audStaticRadioEmitter *emitter)
|
|
{
|
|
return audRadioSlot::IsEmitterActive(emitter);
|
|
}
|
|
|
|
void audRadioAudioEntity::SkipStationsForward(void)
|
|
{
|
|
#if !__FINAL
|
|
audRadioStation::SkipForwardStations(g_RadioDebugSkipForwardTimeMs); //Skip all virtually streaming stations.
|
|
audRadioSlot::SkipForwardSlots(g_RadioDebugSkipForwardTimeMs); //Skip all physically streaming stations.
|
|
#endif
|
|
}
|
|
|
|
const char *audRadioAudioEntity::GetPlayerRadioStationNamePendingRetune() const
|
|
{
|
|
if(m_PlayerRadioStationPendingRetune)
|
|
{
|
|
return m_PlayerRadioStationPendingRetune->GetName();
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
const audRadioStation *audRadioAudioEntity::GetPlayerRadioStationPendingRetune() const
|
|
{
|
|
return m_PlayerRadioStationPendingRetune;
|
|
}
|
|
|
|
void audRadioAudioEntity::UpdateUserControl(u32 BANK_ONLY(timeInMs))
|
|
{
|
|
#if __BANK
|
|
if(sm_ShouldPerformRadioRetuneTest && (timeInMs > m_LastTestRetuneTimeMs + sm_RetunePeriodMs))
|
|
{
|
|
if(audEngineUtil::ResolveProbability(0.5f))
|
|
{
|
|
RetuneRadioUp();
|
|
}
|
|
else
|
|
{
|
|
RetuneRadioDown();
|
|
}
|
|
|
|
m_LastTestRetuneTimeMs = timeInMs;
|
|
|
|
return; //Don't take any other user input if we are testing retunes.
|
|
}
|
|
#endif // __BANK
|
|
|
|
#if !__FINAL
|
|
if(ioMapper::DebugKeyPressed(KEY_PERIOD))
|
|
{
|
|
if(ioMapper::DebugKeyDown(KEY_CONTROL))
|
|
{
|
|
sm_ShouldQuickSkipForward = true;
|
|
}
|
|
else
|
|
{
|
|
sm_ShouldSkipForward = true;
|
|
}
|
|
}
|
|
if(CControlMgr::GetKeyboard().GetKeyJustDown(KEY_COMMA, KEYBOARD_MODE_DEBUG, "Toggle mobile phone radio on/off"))
|
|
{
|
|
ToggleMobilePhoneRadioState();
|
|
}
|
|
if(CControlMgr::GetKeyboard().GetKeyJustDown(KEY_8, KEYBOARD_MODE_DEBUG, "Toggle radio on/off"))
|
|
{
|
|
sm_ShouldMuteRadio = !sm_ShouldMuteRadio;
|
|
}
|
|
#endif // !__FINAL
|
|
}
|
|
|
|
void audRadioAudioEntity::ComputeVolumeOffset(void)
|
|
{
|
|
m_VolumeOffset = audDriverUtil::ComputeDbVolumeFromLinear(m_FadeVolumeLinear);
|
|
}
|
|
|
|
bool audRadioAudioEntity::IsTimeToRetune(u32 timeInMs)
|
|
{
|
|
return (timeInMs >= (sm_LastRetuneTime + g_MinRadioRetuneDelayMs));
|
|
}
|
|
|
|
void audRadioAudioEntity::RetuneRadioUp(void)
|
|
{
|
|
CVehicle *playerVehicle = CGameWorld::FindLocalPlayerVehicle();
|
|
if((sm_IsMobilePhoneRadioActive || (playerVehicle && playerVehicle->GetVehicleAudioEntity()->GetHasNormalRadio())) &&
|
|
(g_RadioAudioEntity.GetPlayerRadioStation()))
|
|
{
|
|
sm_PendingPlayerRadioStationRetunes = (sm_PendingPlayerRadioStationRetunes + 1) %
|
|
audRadioStation::GetNumUnlockedStations();
|
|
sm_LastRetuneTime = GetCurrentTimeMs();
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::RetuneRadioDown(void)
|
|
{
|
|
CVehicle *playerVehicle = CGameWorld::FindLocalPlayerVehicle();
|
|
if((sm_IsMobilePhoneRadioActive || (playerVehicle && playerVehicle->GetVehicleAudioEntity()->GetHasNormalRadio())) &&
|
|
(g_RadioAudioEntity.GetPlayerRadioStation()))
|
|
{
|
|
Assign(sm_PendingPlayerRadioStationRetunes, (sm_PendingPlayerRadioStationRetunes +
|
|
audRadioStation::GetNumUnlockedStations() - 1) % audRadioStation::GetNumUnlockedStations());
|
|
sm_LastRetuneTime = GetCurrentTimeMs();
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
void audRadioAudioEntity::DebugHideStation(void)
|
|
{
|
|
audRadioStation* station = audRadioStation::FindStation(g_RadioStationCombo->GetString(sm_RequestedRadioStationIndex));
|
|
|
|
if (station)
|
|
{
|
|
station->SetHidden(true);
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::DebugUnHideStation(void)
|
|
{
|
|
audRadioStation* station = audRadioStation::FindStation(g_RadioStationCombo->GetString(sm_RequestedRadioStationIndex));
|
|
|
|
if (station)
|
|
{
|
|
station->SetHidden(false);
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::DebugLockStation(void)
|
|
{
|
|
audRadioStation* station = audRadioStation::FindStation(g_RadioStationCombo->GetString(sm_RequestedRadioStationIndex));
|
|
|
|
if (station)
|
|
{
|
|
station->SetLocked(true);
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::DebugUnlockStation(void)
|
|
{
|
|
audRadioStation* station = audRadioStation::FindStation(g_RadioStationCombo->GetString(sm_RequestedRadioStationIndex));
|
|
|
|
if (station)
|
|
{
|
|
station->SetLocked(false);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void audRadioAudioEntity::RetuneToStation(const char *stationName)
|
|
{
|
|
if(!strcmp(stationName, "OFF"))
|
|
{
|
|
if(m_PlayerRadioStation || sm_IsMobilePhoneRadioActive)
|
|
{
|
|
//Switch off the player radio (vehicle and mobile.)
|
|
if(m_PlayerVehicle)
|
|
{
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STOPPING);
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioOffState(true);
|
|
}
|
|
|
|
m_PlayerRadioStation = NULL;
|
|
m_PlayerRadioStationPendingRetune = NULL;
|
|
m_RequestedRadioStation = NULL;
|
|
sm_IsMobilePhoneRadioActive = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetuneToStation(atStringHash(stationName));
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::RetuneToStation(const u32 stationNameHash)
|
|
{
|
|
const audRadioStation *station = audRadioStation::FindStation(stationNameHash);
|
|
if(station)
|
|
{
|
|
RetuneToStation(station);
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::SwitchOffRadio()
|
|
{
|
|
RetuneToStation("OFF");
|
|
}
|
|
|
|
#if __BANK
|
|
void audRadioAudioEntity::PrintRadioDebug()
|
|
{
|
|
audDisplayf("Player radio state: %u", m_PlayerVehicleRadioState);
|
|
audDisplayf("Mobile phone radio state: %u", m_MobilePhoneRadioState);
|
|
audDisplayf("Player radio station: %s", m_PlayerRadioStation? m_PlayerRadioStation->GetName() : "NULL");
|
|
audDisplayf("Player vehicle: %s", m_PlayerVehicle? m_PlayerVehicle->GetBaseModelInfo()->GetModelName() : "NULL");
|
|
}
|
|
#endif
|
|
|
|
bool audRadioAudioEntity::ShouldBlockPauseMenuRetunes() const
|
|
{
|
|
// url:bugstar:7806555 - Summer 2022 - Radio News Broadcast - Players can bypass the Radio News Broadcast by changing the Radio Station in the Pause Menu Settings tab.
|
|
if(IsInFrontendMode() && CPauseMenu::IsMP() && m_PlayerRadioStation && m_PlayerRadioStation->IsLocalPlayerNewsStation() && !m_PlayerRadioStation->IsLocked())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void audRadioAudioEntity::RetuneToStation(const audRadioStation *station)
|
|
{
|
|
audDisplayf("Tuning player radio station to %s", station? station->GetName() : "NULL");
|
|
BANK_ONLY(PrintRadioDebug();)
|
|
|
|
if(!m_PlayerRadioStation || (m_PlayerVehicleRadioState == PLAYER_RADIO_OFF && m_MobilePhoneRadioState == PLAYER_RADIO_OFF))
|
|
{
|
|
if(station && !station->IsFrozen())
|
|
{
|
|
PlayStationSelectSound();
|
|
}
|
|
if(m_PlayerVehicle && m_PlayerVehicle->GetVehicleAudioEntity()->GetHasNormalRadio() && m_PlayerVehicle->GetVehicleAudioEntity()->IsRadioEnabled())
|
|
{
|
|
SetPlayerVehicleRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioOffState(false);
|
|
m_LastPlayerVehicle = m_PlayerVehicle;
|
|
}
|
|
else if(IsMobileRadioNormallyPermitted() || g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::MobileRadioInGame))
|
|
{
|
|
SetMobileRadioState(PLAYER_RADIO_STARTING);
|
|
m_TimeEnteringStartingState = GetCurrentTimeMs();
|
|
sm_IsMobilePhoneRadioActive = true;
|
|
}
|
|
|
|
if(m_PlayerRadioStation)
|
|
{
|
|
m_RequestedRadioStation = station;
|
|
m_PlayerRadioStation = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_PlayerRadioStation = station;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_PlayerVehicleRadioState == PLAYER_RADIO_OFF)
|
|
{
|
|
// Apply mobile phone radio station to the player vehicle, so that you can switch the vehicle radio on/retune in the pause menu
|
|
if(m_PlayerVehicle && m_PlayerVehicle->GetVehicleAudioEntity()->GetHasNormalRadio() && m_PlayerVehicle->GetVehicleAudioEntity()->IsRadioEnabled())
|
|
{
|
|
m_PlayerVehicle->GetVehicleAudioEntity()->SetRadioStation(station, false);
|
|
}
|
|
}
|
|
m_RequestedRadioStation = station;
|
|
}
|
|
|
|
CancelFade();
|
|
}
|
|
|
|
void audRadioAudioEntity::ToggleMobilePhoneRadioState(void)
|
|
{
|
|
g_RadioAudioEntity.SetMobilePhoneRadioState(!sm_IsMobilePhoneRadioActive);
|
|
}
|
|
|
|
void audRadioAudioEntity::SetMobilePhoneRadioState(bool isActive)
|
|
{
|
|
if(sm_IsMobilePhoneRadioActive != isActive)
|
|
{
|
|
if(sm_PendingPlayerRadioStationRetunes == 0)
|
|
{
|
|
//Only allow the state of the mobile phone radio to be altered outside of retuning.
|
|
sm_IsMobilePhoneRadioActive = isActive;
|
|
naDisplayf("Switching %s mobile radio", isActive? "on" : "off");
|
|
}
|
|
else
|
|
{
|
|
naDisplayf("Attempting to switch %s mobile radio but we have %d retunes pending", isActive? "on" : "off", sm_PendingPlayerRadioStationRetunes);
|
|
}
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::PlayRadioOnOffSound(bool bModulateVolume)
|
|
{
|
|
if(!m_SkipOnOffSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TimerId = 2;
|
|
if( bModulateVolume )
|
|
{
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(m_PlayerVehicleInsideFactor);
|
|
}
|
|
initParams.Volume += GetVolumeOffset();
|
|
CreateAndPlaySound(m_RadioSounds.Find(ATSTRINGHASH("OnOff", 0x73C5AA9)), &initParams);
|
|
}
|
|
m_SkipOnOffSound = false;
|
|
}
|
|
|
|
void audRadioAudioEntity::PlayWheelShowSound()
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TimerId = 2;
|
|
CreateAndPlaySound(m_RadioSounds.Find(ATSTRINGHASH("Show_Wheel", 0xBE07C731)), &initParams);
|
|
}
|
|
|
|
void audRadioAudioEntity::PlayWheelHideSound()
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TimerId = 2;
|
|
CreateAndPlaySound(m_RadioSounds.Find(ATSTRINGHASH("Hide_Wheel", 0x1EDF5668)), &initParams);
|
|
}
|
|
|
|
void audRadioAudioEntity::PlayStationSelectSound(bool bModulateVolume)
|
|
{
|
|
if (!g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::SuppressRadioSwitchBeep) && !camInterface::IsFadedOut())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TimerId = 2;
|
|
if (bModulateVolume)
|
|
{
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(m_PlayerVehicleInsideFactor);
|
|
}
|
|
|
|
audDisplayf("Triggering change radio station sound");
|
|
CreateAndPlaySound(m_RadioSounds.Find(ATSTRINGHASH("Change_Station", 0x37AD47AB)), &initParams);
|
|
}
|
|
}
|
|
|
|
extern u32 g_IceVanTuneTextId;
|
|
u32 audRadioAudioEntity::GetAudibleTrackTextId() const
|
|
{
|
|
// Please implement through modelinfo or vehicle flags ... MI currently not in metadata
|
|
//if(FindPlayerVehicle() && FindPlayerVehicle()->GetModelIndex() == MI_CAR_ICEVAN)
|
|
//{
|
|
// if(FindPlayerVehicle()->GetVehicleAudioEntity()->IsSirenOn())
|
|
// {
|
|
// naDisplayf("Zit! icecream tune: %u", g_IceVanTuneTextId);
|
|
// return g_IceVanTuneTextId;
|
|
// }
|
|
//}
|
|
|
|
const audRadioTrack *track = FindAudibleTrack(10.f);
|
|
if(track && (track->GetCategory() == RADIO_TRACK_CAT_MUSIC || track->GetCategory() == RADIO_TRACK_CAT_TAKEOVER_MUSIC))
|
|
{
|
|
return track->GetTextId();
|
|
}
|
|
enum {kUnknownTrackTextId = 1};
|
|
return kUnknownTrackTextId;
|
|
}
|
|
|
|
const audRadioStation* audRadioAudioEntity::FindAudibleStation(const float searchRadius) const
|
|
{
|
|
const audRadioStation* audibleStation = NULL;
|
|
|
|
if(m_PlayerVehicleRadioState == PLAYER_RADIO_PLAYING || m_MobilePhoneRadioState == PLAYER_RADIO_PLAYING)
|
|
{
|
|
audibleStation = m_PlayerRadioStation;
|
|
}
|
|
else
|
|
{
|
|
// search for nearby emitters
|
|
u32 nearestStation = ~0U;
|
|
f32 nearestDist2 = LARGE_FLOAT;
|
|
|
|
// Fix for B*4731228 - GET_NEXT_AUDIBLE_BEAT not working on hidden nightclub stations. This should probably be the same regardless of MP/SP but
|
|
// just being overly cautious and restricting the change to MP only
|
|
const u32 numStationsToCheck = CNetwork::IsGameInProgress() ? audRadioStation::GetNumTotalStations() : audRadioStation::GetNumUnlockedStations();
|
|
|
|
for(u32 i = 0; i < numStationsToCheck; i++)
|
|
{
|
|
audRadioSlot *slot = audRadioSlot::FindSlotByStation(audRadioStation::GetStation(i));
|
|
if(slot)
|
|
{
|
|
f32 thisDist2 = slot->ComputeDistanceSqToNearestEmitter();
|
|
if(thisDist2 < nearestDist2)
|
|
{
|
|
nearestDist2 = thisDist2;
|
|
nearestStation = i;
|
|
}
|
|
}
|
|
}
|
|
if(nearestDist2 < (searchRadius*searchRadius))
|
|
{
|
|
audibleStation = audRadioStation::GetStation(nearestStation);
|
|
}
|
|
}
|
|
|
|
return audibleStation;
|
|
}
|
|
|
|
const audRadioStation* audRadioAudioEntity::FindAudibleStation(CInteriorInst* pIntInst, s32 roomIdx) const
|
|
{
|
|
// search for nearby emitters
|
|
u32 nearestStation = ~0U;
|
|
f32 nearestDist2 = LARGE_FLOAT;
|
|
|
|
// Fix for B*4731228 - GET_NEXT_AUDIBLE_BEAT not working on hidden nightclub stations. This should probably be the same regardless of MP/SP but
|
|
// just being overly cautious and restricting the change to MP only
|
|
const u32 numStationsToCheck = CNetwork::IsGameInProgress() ? audRadioStation::GetNumTotalStations() : audRadioStation::GetNumUnlockedStations();
|
|
|
|
for (u32 i = 0; i < numStationsToCheck; i++)
|
|
{
|
|
audRadioSlot *slot = audRadioSlot::FindSlotByStation(audRadioStation::GetStation(i));
|
|
if (slot)
|
|
{
|
|
f32 thisDist2 = slot->ComputeDistanceSqToNearestEmitter(pIntInst, roomIdx);
|
|
if (thisDist2 < nearestDist2)
|
|
{
|
|
nearestDist2 = thisDist2;
|
|
nearestStation = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return audRadioStation::GetStation(nearestStation);
|
|
}
|
|
|
|
const audRadioTrack *audRadioAudioEntity::FindAudibleTrack(const float searchRadius) const
|
|
{
|
|
const audRadioStation* audibleStation = FindAudibleStation(searchRadius);
|
|
|
|
if (audibleStation)
|
|
{
|
|
const audRadioTrack* audibleTrack = &(audibleStation->GetCurrentTrack());
|
|
|
|
if (audibleTrack->GetPlayTime() == -1 && audibleStation->GetNextTrack().GetPlayTime() >= 0)
|
|
{
|
|
audibleTrack = &(audibleStation->GetNextTrack());
|
|
}
|
|
|
|
return audibleTrack;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool audRadioAudioEntity::GetNextAudibleBeat(float &timeS, float &bpm, s32 &beatNum) const
|
|
{
|
|
const audRadioTrack *track = FindAudibleTrack(25.f);
|
|
if(track)
|
|
{
|
|
return track->GetNextBeat(timeS, bpm, beatNum);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
u32 audRadioAudioEntity::GetPlayingTrackTextIdByStationIndex(const u32 index, bool &WIN32PC_ONLY(isUserTrack)) const
|
|
{
|
|
const audRadioStation *playerStation = audRadioStation::GetStation(index);
|
|
if(playerStation)
|
|
{
|
|
const audRadioTrack &track = playerStation->GetCurrentTrack();
|
|
if(track.GetCategory() == RADIO_TRACK_CAT_MUSIC || track.GetCategory() == RADIO_TRACK_CAT_TAKEOVER_MUSIC)
|
|
{
|
|
WIN32PC_ONLY(isUserTrack = track.IsUserTrack());
|
|
return track.GetTextId();
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
u32 audRadioAudioEntity::GetPlayingTrackPlayTimeByStationIndex(const u32 index, bool &WIN32PC_ONLY(isUserTrack)) const
|
|
{
|
|
const audRadioStation *playerStation = audRadioStation::GetStation(index);
|
|
if(playerStation)
|
|
{
|
|
const audRadioTrack &track = playerStation->GetCurrentTrack();
|
|
if(track.GetCategory() == RADIO_TRACK_CAT_MUSIC || track.GetCategory() == RADIO_TRACK_CAT_TAKEOVER_MUSIC)
|
|
{
|
|
WIN32PC_ONLY(isUserTrack = track.IsUserTrack());
|
|
return track.GetPlayTime();
|
|
}
|
|
}
|
|
return ~0u;
|
|
}
|
|
|
|
u32 audRadioAudioEntity::GetCurrentlyPlayingTrackTextId() const
|
|
{
|
|
const audRadioStation *playerStation = GetPlayerRadioStationPendingRetune();
|
|
if(playerStation)
|
|
{
|
|
const audRadioTrack &track = playerStation->GetCurrentTrack();
|
|
if(track.GetCategory() == RADIO_TRACK_CAT_MUSIC || track.GetCategory() == RADIO_TRACK_CAT_MUSIC)
|
|
{
|
|
return track.GetTextId();
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#if !__FINAL
|
|
void audRadioAudioEntity::SkipForward(void)
|
|
{
|
|
sm_ShouldSkipForward = true;
|
|
}
|
|
|
|
void audRadioAudioEntity::SkipForwardToTransition(void)
|
|
{
|
|
if (const audRadioStation* radioStation = g_RadioAudioEntity.FindAudibleStation(25.f))
|
|
{
|
|
audRadioSlot* slot = audRadioSlot::FindSlotByStation(radioStation);
|
|
|
|
if (slot)
|
|
{
|
|
slot->SkipForwardToTransition(g_RadioDebugSkipToTransitionTimeMs);
|
|
}
|
|
}
|
|
}
|
|
#endif // !__FINAL
|
|
|
|
bool audRadioAudioEntity::IsInControlOfRadio(void) const
|
|
{
|
|
return true; // local player is always in control of radio for time being - radio syncing will be added later
|
|
}
|
|
|
|
bool audRadioAudioEntity::GetCachedNextAudibleBeat(float &timeS, float &bpm, s32 &beatNum) const
|
|
{
|
|
timeS = m_CachedTimeTillNextAudibleBeat;
|
|
bpm = m_CachedAudibleBeatBPM;
|
|
beatNum = m_CachedAudibleBeatNum;
|
|
return m_CachedAudibleBeatValid;
|
|
}
|
|
|
|
void audRadioAudioEntity::StartEndCredits()
|
|
{
|
|
audRadioStation::StartEndCredits();
|
|
m_AreRetunesMuted = true;
|
|
}
|
|
|
|
void audRadioAudioEntity::StopEndCredits()
|
|
{
|
|
audRadioStation::StopEndCredits();
|
|
m_AreRetunesMuted = false;
|
|
}
|
|
|
|
void audRadioAudioEntity::TriggerRetuneBurst()
|
|
{
|
|
if(!IsInFrontendMode() && !m_AreRetunesMuted)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TimerId = 2;
|
|
|
|
g_RadioAudioEntity.CreateAndPlaySound(m_RadioSounds.Find(ATSTRINGHASH("RADIO_RETUNE_MONO_ONE_SHOT", 0xC2F6E164)), &initParams);
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::UpdateRetuneSounds()
|
|
{
|
|
if(!m_AreRetunesMuted)
|
|
{
|
|
audRadioStation::UpdateRetuneSounds();
|
|
}
|
|
else
|
|
{
|
|
audRadioStation::StopRetuneSounds();
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::FindFavouriteStations(u32 &mostFavourite, u32 &leastFavourite) const
|
|
{
|
|
mostFavourite = leastFavourite = 0;
|
|
float longestTime = 60.f; // User must have listened to the station for at least a minute before it can be their favourite
|
|
float shortestTime = 0.f;
|
|
|
|
for(u32 i = 0; i < audRadioStation::GetNumUnlockedStations(); i++)
|
|
{
|
|
const audRadioStation *station = audRadioStation::GetStation(i);
|
|
if(station->GetListenTimer() >= longestTime)
|
|
{
|
|
longestTime = station->GetListenTimer();
|
|
mostFavourite = station->GetNameHash();
|
|
}
|
|
else if(station->GetListenTimer() <= shortestTime)
|
|
{
|
|
shortestTime = station->GetListenTimer();
|
|
leastFavourite = station->GetNameHash();
|
|
}
|
|
}
|
|
|
|
// Don't return a valid least favourite station if the user hasn't listened to one station for the minimum time
|
|
if(mostFavourite == 0)
|
|
{
|
|
leastFavourite = 0;
|
|
}
|
|
}
|
|
|
|
u32 audRadioAudioEntity::GetCurrentTimeMs()
|
|
{
|
|
return g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(2);
|
|
}
|
|
|
|
#if __BANK
|
|
void audRadioAudioEntity::RAGUpdateDLCBattleUnlockableTracks()
|
|
{
|
|
UpdateDLCBattleUnlockableTracks(true);
|
|
}
|
|
#endif
|
|
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
u32* audRadioAudioEntity::GetEncryptionKeyForBank(u32 bankId)
|
|
{
|
|
if (bankId == audRadioStation::sm_Heist3HiddenRadioBankId)
|
|
{
|
|
bool tuneableAvailable = true;
|
|
static u32 tuneableEncryptionKey[4];
|
|
|
|
#if HEIST3_HIDDEN_RADIO_OVERRIDE_TUNEABLE
|
|
tuneableEncryptionKey[0] = HEIST3_HIDDEN_RADIO_KEY_A;
|
|
tuneableEncryptionKey[1] = HEIST3_HIDDEN_RADIO_KEY_B;
|
|
tuneableEncryptionKey[2] = HEIST3_HIDDEN_RADIO_KEY_C;
|
|
tuneableEncryptionKey[3] = HEIST3_HIDDEN_RADIO_KEY_D;
|
|
#else
|
|
tuneableAvailable &= Tunables::GetInstance().Access(BASE_GLOBALS_HASH, HEIST3_HIDDEN_RADIO_KEY_TUNEABLE_HASH_A, tuneableEncryptionKey[0]);
|
|
tuneableAvailable &= Tunables::GetInstance().Access(BASE_GLOBALS_HASH, HEIST3_HIDDEN_RADIO_KEY_TUNEABLE_HASH_B, tuneableEncryptionKey[1]);
|
|
tuneableAvailable &= Tunables::GetInstance().Access(BASE_GLOBALS_HASH, HEIST3_HIDDEN_RADIO_KEY_TUNEABLE_HASH_C, tuneableEncryptionKey[2]);
|
|
tuneableAvailable &= Tunables::GetInstance().Access(BASE_GLOBALS_HASH, HEIST3_HIDDEN_RADIO_KEY_TUNEABLE_HASH_D, tuneableEncryptionKey[3]);
|
|
#endif
|
|
|
|
if (tuneableAvailable)
|
|
{
|
|
audWaveSlot::TeaStirEncryptionKey(&(tuneableEncryptionKey[0]));
|
|
return &(tuneableEncryptionKey[0]);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
void audRadioAudioEntity::UpdateDLCBattleUnlockableTracks(bool allowReprioritization)
|
|
{
|
|
audRadioStation* dlcBattleStation = audRadioStation::FindStation(ATSTRINGHASH("RADIO_22_DLC_BATTLE_MIX1_RADIO", 0xF8BEAA16));
|
|
|
|
if (dlcBattleStation)
|
|
{
|
|
audDisplayf("--- DLC_Battle Unlockable Music ---");
|
|
|
|
if (allowReprioritization && audRadioStation::HasSyncedUnlockableDJStation())
|
|
{
|
|
audDisplayf("Ignoring reprioritization request as we have already synced the station state from a remote machine");
|
|
allowReprioritization = false;
|
|
}
|
|
|
|
bool solomunEnabled = false;
|
|
bool taleOfUsEnabled = false;
|
|
bool dixonEnabled = false;
|
|
bool blackMadonnaEnabled = false;
|
|
bool priorizeMix1 = false;
|
|
bool priorizeMix2 = false;
|
|
bool priorizeMix3 = false;
|
|
bool priorizeMix4 = false;
|
|
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("ENABLE_LSUR_SOL", 0x6268383A), solomunEnabled))
|
|
audDisplayf("Found ENABLE_LSUR_SOL tuneable - state %s", solomunEnabled ? "enabled" : "disabled");
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("ENABLE_LSUR_TOS", 0x1F91894), taleOfUsEnabled))
|
|
audDisplayf("Found ENABLE_LSUR_TOS tuneable - state %s", taleOfUsEnabled ? "enabled" : "disabled");
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("ENABLE_LSUR_DIX", 0x138F159C), dixonEnabled))
|
|
audDisplayf("Found ENABLE_LSUR_DIX tuneable - state %s", dixonEnabled ? "enabled" : "disabled");
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("ENABLE_LSUR_BM", 0x2E637DC9), blackMadonnaEnabled))
|
|
audDisplayf("Found ENABLE_LSUR_BM tuneable - state %s", blackMadonnaEnabled ? "enabled" : "disabled");
|
|
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("PRIORITISE_MIX_1", 0x17BF3CB6), priorizeMix1))
|
|
audDisplayf("Found PRIORITISE_MIX_1 tuneable - state %s", priorizeMix1 ? "enabled" : "disabled");
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("PRIORITISE_MIX_2", 0x5809839), priorizeMix2))
|
|
audDisplayf("Found PRIORITISE_MIX_2 tuneable - state %s", priorizeMix2 ? "enabled" : "disabled");
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("PRIORITISE_MIX_3", 0x18743E24), priorizeMix3))
|
|
audDisplayf("Found PRIORITISE_MIX_3 tuneable - state %s", priorizeMix3 ? "enabled" : "disabled");
|
|
if (Tunables::GetInstance().Access(BASE_GLOBALS_HASH, ATSTRINGHASH("PRIORITISE_MIX_4", 0x7199B6F), priorizeMix4))
|
|
audDisplayf("Found PRIORITISE_MIX_4 tuneable - state %s", priorizeMix4 ? "enabled" : "disabled");
|
|
|
|
#if __BANK
|
|
solomunEnabled |= g_ForceUnlockSolomun;
|
|
taleOfUsEnabled |= g_ForceUnlockTaleOfUs;
|
|
dixonEnabled |= g_ForceUnlockDixon;
|
|
blackMadonnaEnabled |= g_ForceUnlockBlackMadonna;
|
|
|
|
priorizeMix1 |= g_PrioritizeSolomun;
|
|
priorizeMix2 |= g_PrioritizeTaleOfUs;
|
|
priorizeMix3 |= g_PrioritizeDixon;
|
|
priorizeMix4 |= g_PrioritizeBlackMadonna;
|
|
#endif
|
|
|
|
s32 trackToPrioritize = -1;
|
|
|
|
// Assuming that if multiple priorities are set, we probably want to use the latest
|
|
if (blackMadonnaEnabled && priorizeMix4)
|
|
trackToPrioritize = 4;
|
|
else if (dixonEnabled && priorizeMix3)
|
|
trackToPrioritize = 3;
|
|
else if (taleOfUsEnabled && priorizeMix2)
|
|
trackToPrioritize = 2;
|
|
else if (solomunEnabled && priorizeMix1)
|
|
trackToPrioritize = 1;
|
|
|
|
audDisplayf("Solomun (ENABLE_LSUR_SOL) %s", solomunEnabled ? "enabled" : "disabled");
|
|
audDisplayf("Tale of Us (ENABLE_LSUR_TOS) %s", taleOfUsEnabled ? "enabled" : "disabled");
|
|
audDisplayf("Dixon (ENABLE_LSUR_DIX) %s", dixonEnabled ? "enabled" : "disabled");
|
|
audDisplayf("The Black Madonna (ENABLE_LSUR_BM) %s", blackMadonnaEnabled ? "enabled" : "disabled");
|
|
|
|
audDisplayf("PRIORITISE_MIX_1 %s", priorizeMix1 ? "enabled" : "disabled");
|
|
audDisplayf("PRIORITISE_MIX_2 %s", priorizeMix2 ? "enabled" : "disabled");
|
|
audDisplayf("PRIORITISE_MIX_3 %s", priorizeMix3 ? "enabled" : "disabled");
|
|
audDisplayf("PRIORITISE_MIX_4 %s", priorizeMix4 ? "enabled" : "disabled");
|
|
|
|
// Always unlocking at least one track list to prevent asserts (station will still be hidden in this situation)
|
|
/*if (solomunEnabled)*/ { dlcBattleStation->UnlockTrackList("BATTLE_MIX1_RADIO"); }
|
|
//else { dlcBattleStation->LockTrackList("BATTLE_MIX1_RADIO"); }
|
|
|
|
if (taleOfUsEnabled) { dlcBattleStation->UnlockTrackList("BATTLE_MIX2_RADIO"); }
|
|
else { dlcBattleStation->LockTrackList("BATTLE_MIX2_RADIO"); }
|
|
|
|
if (dixonEnabled) { dlcBattleStation->UnlockTrackList("BATTLE_MIX3_RADIO"); }
|
|
else { dlcBattleStation->LockTrackList("BATTLE_MIX3_RADIO"); }
|
|
|
|
if (blackMadonnaEnabled) { dlcBattleStation->UnlockTrackList("BATTLE_MIX4_RADIO"); }
|
|
else { dlcBattleStation->LockTrackList("BATTLE_MIX4_RADIO"); }
|
|
|
|
if (solomunEnabled || taleOfUsEnabled || dixonEnabled || blackMadonnaEnabled)
|
|
{
|
|
dlcBattleStation->SetLocked(false);
|
|
audDisplayf("Tracks available - unlocking station");
|
|
|
|
if (allowReprioritization)
|
|
{
|
|
audDisplayf("Prioritizing track %d", trackToPrioritize);
|
|
RadioStationTrackList* forcedTrackList = NULL;
|
|
|
|
if (trackToPrioritize == 4)
|
|
forcedTrackList = audNorthAudioEngine::GetObject<RadioStationTrackList>(ATSTRINGHASH("BATTLE_MIX4_RADIO", 0x25FD177D));
|
|
else if (trackToPrioritize == 3)
|
|
forcedTrackList = audNorthAudioEngine::GetObject<RadioStationTrackList>(ATSTRINGHASH("BATTLE_MIX3_RADIO", 0xEC028F91));
|
|
else if (trackToPrioritize == 2)
|
|
forcedTrackList = audNorthAudioEngine::GetObject<RadioStationTrackList>(ATSTRINGHASH("BATTLE_MIX2_RADIO", 0x2E8F5458));
|
|
else if (trackToPrioritize == 1)
|
|
forcedTrackList = audNorthAudioEngine::GetObject<RadioStationTrackList>(ATSTRINGHASH("BATTLE_MIX1_RADIO", 0xDA1AA248));
|
|
|
|
const s32 numTracks = dlcBattleStation->ComputeNumTracksAvailable(RADIO_TRACK_CAT_MUSIC);
|
|
const audRadioStationTrackListCollection *trackLists = dlcBattleStation->FindTrackListsForCategory(RADIO_TRACK_CAT_MUSIC);
|
|
dlcBattleStation->Freeze();
|
|
|
|
if (forcedTrackList)
|
|
{
|
|
dlcBattleStation->ForceTrack(forcedTrackList->Track[0].SoundRef, 0);
|
|
|
|
for (u32 trackIndex = 0; trackIndex < numTracks; trackIndex++)
|
|
{
|
|
if (trackLists->GetTrack(trackIndex)->SoundRef == forcedTrackList->Track[0].SoundRef)
|
|
{
|
|
audRadioStationHistory *history = const_cast<audRadioStationHistory*>(dlcBattleStation->FindHistoryForCategory(RADIO_TRACK_CAT_MUSIC));
|
|
(*history)[0] = (trackIndex + 1) % numTracks;
|
|
}
|
|
}
|
|
}
|
|
else // No forced track list, just do a pure randomization
|
|
{
|
|
u32 randomTrackIndex = audEngineUtil::GetRandomNumberInRange(0, numTracks - 1);
|
|
const u32 soundRef = trackLists->GetTrack(randomTrackIndex)->SoundRef;
|
|
dlcBattleStation->ForceTrack(soundRef, audEngineUtil::GetRandomNumberInRange(0, 1000000));
|
|
audRadioStationHistory *history = const_cast<audRadioStationHistory*>(dlcBattleStation->FindHistoryForCategory(RADIO_TRACK_CAT_MUSIC));
|
|
(*history)[0] = (randomTrackIndex + 1) % numTracks;
|
|
}
|
|
|
|
dlcBattleStation->Unfreeze();
|
|
}
|
|
else
|
|
{
|
|
audDisplayf("Track prioritization disabled");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dlcBattleStation->SetLocked(true);
|
|
audDisplayf("No tracks unlocked - locking station");
|
|
}
|
|
|
|
audDisplayf("--- DLC_Battle Unlockable Music ---");
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
|
|
char g_ScriptStream[128]={0};
|
|
char g_ForcePlayerStationName[128]={0};
|
|
u32 g_ScriptStreamStartOffset = 0;
|
|
|
|
atArray<audStreamSlot*> g_DebugStreamSlots;
|
|
|
|
void audRadioAudioEntity::DebugAllocateAllStreamSlots()
|
|
{
|
|
audStreamClientSettings settings;
|
|
u32 priority = audStreamSlot::STREAM_PRIORITY_CUTSCENE;
|
|
Assign(settings.priority, priority);
|
|
|
|
for(u32 loop = 0; loop < g_NumStreamSlots; loop++)
|
|
{
|
|
audStreamSlot* streamSlot = audStreamSlot::AllocateSlot(&settings);
|
|
|
|
if(streamSlot)
|
|
{
|
|
g_DebugStreamSlots.PushAndGrow(streamSlot);
|
|
}
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::DebugFreeStreamSlots()
|
|
{
|
|
for(u32 loop = 0; loop < g_DebugStreamSlots.GetCount(); loop++)
|
|
{
|
|
g_DebugStreamSlots[loop]->StopAndFree();
|
|
}
|
|
|
|
g_DebugStreamSlots.clear();
|
|
}
|
|
|
|
void audRadioAudioEntity::RetuneToRequestedStation(void)
|
|
{
|
|
g_RadioAudioEntity.RetuneToStation(audRadioStation::FindStation(sm_RadioStationNames[sm_RequestedRadioStationIndex]));
|
|
}
|
|
|
|
void audRadioAudioEntity::DebugPrintTrackListInfo()
|
|
{
|
|
if (audRadioStation* station = audRadioStation::FindStation(g_RadioStationCombo->GetString(sm_RequestedRadioStationIndex)))
|
|
{
|
|
for(u32 category = 0; category < TrackCats::NUM_RADIO_TRACK_CATS; category++)
|
|
{
|
|
if(audRadioStationTrackListCollection *trackListCollection = const_cast<audRadioStationTrackListCollection *>(station->FindTrackListsForCategory(category)))
|
|
{
|
|
for(u32 listIndex = 0; listIndex < trackListCollection->GetListCount(); listIndex++)
|
|
{
|
|
if(const RadioStationTrackList* trackList = trackListCollection->GetList(listIndex))
|
|
{
|
|
const char* trackListName = audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(trackList->NameTableOffset);
|
|
bool isLocked = trackListCollection->IsListLocked(listIndex);
|
|
audDisplayf("%s: %s", trackListName, isLocked ? "Locked" : "Unlocked");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::DebugShutdownTracks()
|
|
{
|
|
if (audRadioStation* station = audRadioStation::FindStation(g_RadioStationCombo->GetString(sm_RequestedRadioStationIndex)))
|
|
{
|
|
station->GetCurrentTrack().Shutdown();
|
|
station->GetNextTrack().Shutdown();
|
|
}
|
|
}
|
|
|
|
void audRadioAudioEntity::RetuneClubEmittersToRequestedStation(void)
|
|
{
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_Bogs", true);
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_Entry_Stairs", true);
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_garage", true);
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_main_area_2", true);
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_main_area", true);
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_office", true);
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_rear_L_corridor", true);
|
|
g_EmitterAudioEntity.SetEmitterEnabled("SE_ba_dlc_int_01_Bogs", true);
|
|
|
|
const char* stationName = sm_RadioStationNames[sm_RequestedRadioStationIndex];
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_Bogs", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_Entry_Stairs", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_garage", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_main_area_2", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_main_area", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_office", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_rear_L_corridor", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_ba_dlc_int_01_Bogs", stationName);
|
|
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_h4_dlc_int_02_h4_Bogs", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_h4_dlc_int_02_h4_Entrance_Doorway", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_h4_dlc_int_02_h4_lobby", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_h4_dlc_int_02_h4_main_bar", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_h4_dlc_int_02_h4_main_front_01", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_h4_dlc_int_02_h4_main_front_02", stationName);
|
|
g_EmitterAudioEntity.SetEmitterRadioStation("SE_h4_dlc_int_02_h4_main_room_cutscenes", stationName);
|
|
}
|
|
|
|
void PreloadStreamCB()
|
|
{
|
|
g_ScriptAudioEntity.PreloadStreamInternal(g_ScriptStream, g_ScriptStreamStartOffset, NULL);
|
|
}
|
|
|
|
void PlayStreamCB()
|
|
{
|
|
g_ScriptAudioEntity.PlayStreamFrontendInternal();
|
|
}
|
|
|
|
void PlayStreamFromPlayerCB()
|
|
{
|
|
g_ScriptAudioEntity.PlayStreamFromEntityInternal(CGameWorld::FindLocalPlayer());
|
|
}
|
|
|
|
void StopStreamCB()
|
|
{
|
|
g_ScriptAudioEntity.StopStream();
|
|
}
|
|
void KapowCB()
|
|
{
|
|
if(g_RadioAudioEntity.GetAudibleTrackTextId()==1)
|
|
{
|
|
naDisplayf("Kapow: Unknown");
|
|
}
|
|
}
|
|
void UnpauseCB()
|
|
{
|
|
g_RadioAudioEntity.Unpause();
|
|
}
|
|
|
|
void StartEndCreditsCB()
|
|
{
|
|
g_RadioAudioEntity.StartEndCredits();
|
|
}
|
|
|
|
void StopEndCreditsCB()
|
|
{
|
|
g_RadioAudioEntity.StopEndCredits();
|
|
}
|
|
|
|
void FreezeStationCB()
|
|
{
|
|
audRadioStation::FindStation(g_ForcePlayerStationName)->Freeze();
|
|
// Match the script API: reset to auto-unfreeze on Freeze()
|
|
g_RadioAudioEntity.SetAutoUnfreezeForPlayer(true);
|
|
}
|
|
|
|
void UnfreezeStationCB()
|
|
{
|
|
audRadioStation::FindStation(g_ForcePlayerStationName)->Unfreeze();
|
|
}
|
|
|
|
void ForceNextPlayerStation()
|
|
{
|
|
audRadioStation *station = audRadioStation::FindStation(g_ForcePlayerStationName);
|
|
if(station)
|
|
{
|
|
g_RadioAudioEntity.ForcePlayerRadioStation(station->GetStationIndex());
|
|
}
|
|
else
|
|
{
|
|
audErrorf("Failed to find station \'%s\'", g_ForcePlayerStationName);
|
|
}
|
|
}
|
|
|
|
#if __WIN32PC // user music
|
|
void NextTrackCB()
|
|
{
|
|
audRadioStation::FindStation("RADIO_19_USER")->NextTrack();
|
|
}
|
|
|
|
void PrevTrackCB()
|
|
{
|
|
audRadioStation::FindStation("RADIO_19_USER")->PrevTrack();
|
|
}
|
|
#endif
|
|
|
|
#if GTA_REPLAY
|
|
void PreviewTrackCB()
|
|
{
|
|
g_RadioAudioEntity.StartReplayTrackPreview(atStringHash(g_PreviewTrackName));
|
|
}
|
|
|
|
void StopPreviewTrackCB()
|
|
{
|
|
g_RadioAudioEntity.StopReplayTrackPreview();
|
|
}
|
|
|
|
#endif
|
|
|
|
extern s32 g_TrackReleaseTime;
|
|
extern bank_float g_CutsceneRadioLeakage;
|
|
void audRadioAudioEntity::AddWidgets(bkBank &bank)
|
|
{
|
|
bank.PushGroup("Radio", false);
|
|
bank.PushGroup("DLC Battle Unlockable Tracks", false);
|
|
bank.AddButton("Update Unlockable Track Status", datCallback(CFA(RAGUpdateDLCBattleUnlockableTracks)));
|
|
bank.AddToggle("Force Unlock - Solomun", &g_ForceUnlockSolomun);
|
|
bank.AddToggle("Force Unlock - Tale Of Us", &g_ForceUnlockTaleOfUs);
|
|
bank.AddToggle("Force Unlock - Dixon", &g_ForceUnlockDixon);
|
|
bank.AddToggle("Force Unlock - The Black Madonna", &g_ForceUnlockBlackMadonna);
|
|
bank.AddToggle("Prioritize - Solomun", &g_PrioritizeSolomun);
|
|
bank.AddToggle("Prioritize - Tale Of Us", &g_PrioritizeTaleOfUs);
|
|
bank.AddToggle("Prioritize - Dixon", &g_PrioritizeDixon);
|
|
bank.AddToggle("Prioritize - The Black Madonna", &g_PrioritizeBlackMadonna);
|
|
bank.PopGroup();
|
|
|
|
bank.AddToggle("MobilePhoneRadioAvailable?", &sm_IsMobilePhoneRadioAvailable);
|
|
bank.AddText("ForcePlayerStationName", &g_ForcePlayerStationName[0], sizeof(g_ForcePlayerStationName));
|
|
bank.AddButton("ForceNextPlayerStation", datCallback(CFA(ForceNextPlayerStation)));
|
|
bank.AddToggle("Auto-Unfreeze", &g_RadioAudioEntity.m_AutoUnfreezeForPlayer);
|
|
bank.AddButton("Freeze", CFA(FreezeStationCB));
|
|
bank.AddButton("Unfreeze", CFA(UnfreezeStationCB));
|
|
bank.AddSlider("RadioPositionedToStereoTime", &g_RadioPositionedToStereoTime, 0.f, 10000.f, 0.01f);
|
|
bank.AddToggle("Enable Positioned Player Radio", &g_PositionedPlayerVehicleRadioEnabled);
|
|
|
|
#if __WIN32PC // user music
|
|
bank.PushGroup("User Music", false);
|
|
bank.AddToggle("Show User Music Data", &g_RadioAudioEntity.sm_DebugUserMusic);
|
|
bank.AddButton("NextTrack", CFA(NextTrackCB));
|
|
bank.AddButton("PrevTrack", CFA(PrevTrackCB));
|
|
bank.PopGroup();
|
|
#endif
|
|
#if GTA_REPLAY
|
|
bank.PushGroup("Replay", false);
|
|
bank.AddText("Preview Track", &g_PreviewTrackName[0], sizeof(g_PreviewTrackName));
|
|
bank.AddButton("Preview Track", CFA(PreviewTrackCB));
|
|
bank.AddButton("Stop Track", CFA(StopPreviewTrackCB));
|
|
bank.PopGroup();
|
|
#endif
|
|
bank.AddToggle("Perform retune test", &sm_ShouldPerformRadioRetuneTest);
|
|
bank.AddSlider("Retune period", &sm_RetunePeriodMs, 0, 300000, 1000);
|
|
bank.AddSlider("SkipForwardTime", &g_RadioDebugSkipForwardTimeMs, 0, 999999, 1);
|
|
bank.AddButton("Skip player station forward", datCallback(CFA(SkipForward)));
|
|
bank.AddButton("Skip all stations forward", datCallback(CFA(SkipStationsForward)));
|
|
bank.AddSlider("TransitionTime", &g_RadioDebugSkipToTransitionTimeMs, 0, 999999, 1);
|
|
bank.AddButton("Skip audible station to transition", datCallback(CFA(SkipForwardToTransition)));
|
|
bank.AddButton("Tune Up", datCallback(CFA(RetuneRadioUp)));
|
|
bank.AddButton("Tune Down", datCallback(CFA(RetuneRadioDown)));
|
|
g_RadioStationCombo = bank.AddCombo("Station", &sm_RequestedRadioStationIndex, g_MaxRadioStations, sm_RadioStationNames);
|
|
bank.AddButton("Lock Station", datCallback(CFA(DebugLockStation)));
|
|
bank.AddButton("Unlock Station", datCallback(CFA(DebugUnlockStation)));
|
|
bank.AddButton("Hide Station", datCallback(CFA(DebugHideStation)));
|
|
bank.AddButton("UnHide Station", datCallback(CFA(DebugUnHideStation)));
|
|
bank.AddButton("Retune to station", datCallback(CFA1(RetuneToRequestedStation)));
|
|
bank.AddButton("Print Station Track List Info", datCallback(CFA1(DebugPrintTrackListInfo)));
|
|
bank.AddButton("Shutdown Tracks", datCallback(CFA1(DebugShutdownTracks)));
|
|
bank.AddButton("Retune Club Emitters to station", datCallback(CFA1(RetuneClubEmittersToRequestedStation)));
|
|
bank.AddSlider("VolumeControlSmoothRate", &g_RadioVolumeControlSmoothRate, 0.f,100.f,0.1f);
|
|
bank.AddSlider("VolumeControlChange", &g_RadioVolumeControlChange, 0.0f, 12.0f, 0.5f);
|
|
bank.AddSlider("VolumeHoldTime", &g_RadioVolumeHoldTime, 0, 300000, 1000);
|
|
bank.AddSlider("VolumeHoldTime", &g_RadioVolumeRampTime, 0, 300000, 1000);
|
|
bank.AddButton("Toggle mobile phone radio on/off", datCallback(CFA(ToggleMobilePhoneRadioState)));
|
|
bank.AddSlider("Mobile phone radio volume offset (dB)", &g_MobilePhoneRadioVolumeOffset, 0.0f, 12.0f, 0.5f);
|
|
|
|
bank.AddToggle("DrawDebug", &g_DrawRadioDebug);
|
|
bank.AddToggle("DrawSlotDebug", &g_DrawRadioSlotDebug);
|
|
bank.AddToggle("Draw Station Debug", &g_DrawRadioStationDebug);
|
|
bank.AddText("Draw Station Name Filter", &g_StationDebugNameFilter[0], sizeof(g_StationDebugNameFilter));
|
|
bank.AddToggle("Draw Takeover Station 1", &g_DrawTakeoverStation1);
|
|
bank.AddToggle("Debug Audible Beat", &g_DrawAudibleTrack);
|
|
bank.AddSlider("Debug Draw Scroll", &g_StationDebugDrawYScroll, 0.0f, 15.0f, 0.1f);
|
|
bank.AddToggle("Simulate Stream Slot Starvation", &g_DebugSimulateStreamSlotStarvation);
|
|
bank.AddButton("Allocate All Stream Slots", datCallback(CFA(DebugAllocateAllStreamSlots)));
|
|
bank.AddButton("Release Allocated Stream Slots", datCallback(CFA(DebugFreeStreamSlots)));
|
|
audRadioStation::AddWidgets(bank);
|
|
|
|
bank.AddText("ScriptStream", &g_ScriptStream[0], sizeof(g_ScriptStream));
|
|
bank.AddSlider("StartOffset", &g_ScriptStreamStartOffset, 0, 1000000, 1);
|
|
bank.AddButton("PreloadStream", CFA(PreloadStreamCB));
|
|
bank.AddButton("PlayStream", CFA(PlayStreamCB));
|
|
bank.AddButton("PlayStreamFromPlayer", CFA(PlayStreamFromPlayerCB));
|
|
bank.AddButton("StopStream", CFA(StopStreamCB));
|
|
bank.AddSlider("TrackReleaseTime", &g_TrackReleaseTime, -1, 5000, 1);
|
|
|
|
bank.AddButton("Kapow!", CFA(KapowCB));
|
|
bank.AddButton("Unpause", CFA(UnpauseCB));
|
|
bank.AddButton("RollEndCreditsMusic", CFA(StartEndCreditsCB));
|
|
bank.AddButton("StopEndCreditsMusic", CFA(StopEndCreditsCB));
|
|
bank.AddSlider("CutsceneRadioLeakage", &g_CutsceneRadioLeakage, 0.f, 1.f, 0.01f);
|
|
|
|
bank.PopGroup();
|
|
}
|
|
#endif
|
|
#endif // NA_RADIO_ENABLED
|