Files
GTASource/game/replaycoordinator/ReplayPlaybackController.cpp

700 lines
22 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
/////////////////////////////////////////////////////////////////////////////////
//
// FILE : ReplayPlaybackController.cpp
// PURPOSE : Implementation of Playback controller interface, to feed data to replay system.
//
// AUTHOR : james.strain
//
// Copyright (C) 1999-2014 Rockstar Games. All Rights Reserved.
//
/////////////////////////////////////////////////////////////////////////////////
#include "ReplayPlaybackController.h"
#if GTA_REPLAY
// rage
#include "math/amath.h"
// framework
#include "video/IVideoRecordingDataAdapter.h"
// game
#include "audio/frontendaudioentity.h"
#include "audio/music/musicplayer.h"
#include "audio/replayaudioentity.h"
#include "camera/replay/ReplayDirector.h"
#include "camera/CamInterface.h"
#include "control/replay/replay.h"
#include "control/replay/ReplayMarkerContext.h"
#include "replaycoordinator/ReplayCoordinator.h"
#include "replaycoordinator/storage/Montage.h"
REPLAY_COORDINATOR_OPTIMISATIONS();
CReplayPlaybackController::CReplayPlaybackController()
: m_activeMontage( NULL )
, m_activeClip( INDEX_NONE )
, m_pendingJumpClip( INDEX_NONE )
, m_pendingJumpClipNonDilatedTimeMs( INDEX_NONE )
, m_singleClip( true )
, m_recordingDataProvider( NULL )
, m_startClipNextFrame( 0 )
{
}
void CReplayPlaybackController::Initialize( CMontage& montage, s32 const activeClip, bool const singleClipMode,
IVideoRecordingDataProvider const * const exportMode )
{
CReplayMarkerContext::Reset();
m_activeMontage = &montage;
m_singleClip = singleClipMode;
m_recordingDataProvider = exportMode;
SetActiveClip( activeClip );
ClearPendingJumpClipNonDilatedTimeMs();
m_possibleFirstClipOfProject = true;
}
void CReplayPlaybackController::Reset()
{
CReplayMarkerContext::Reset();
SetActiveClip( INDEX_NONE );
m_activeMontage = NULL;
m_singleClip = true;
m_recordingDataProvider = NULL;
ClearPendingJumpClipNonDilatedTimeMs();
m_possibleFirstClipOfProject = false;
}
char const * CReplayPlaybackController::GetProjectName() const
{
return IsValid() ? m_activeMontage->GetName() : "";
}
IReplayMarkerStorage* CReplayPlaybackController::TryGetCurrentMarkerStorage()
{
return IsValid() ? (IReplayMarkerStorage*)GetCurrentClip() : NULL;
}
IReplayMarkerStorage const* CReplayPlaybackController::TryGetCurrentMarkerStorage() const
{
return IsValid() ? (IReplayMarkerStorage*)GetCurrentClip() : NULL;
}
void CReplayPlaybackController::UpdateMarkersForPlayback( float const clipTimeMs )
{
IReplayMarkerStorage* markerStorage = TryGetCurrentMarkerStorage();
if( markerStorage == NULL )
{
return;
}
sReplayMarkerInfo* pCurrentMarker = NULL;
sReplayMarkerInfo* pNextMarker = NULL;
// Reset current marker index.
CReplayMarkerContext::SetCurrentMarkerIndex( -1 );
int const c_markerCount = markerStorage->GetMarkerCount();
if( c_markerCount == 0 )
{
CReplayMgr::SetMarkerSpeed( 1.f );
}
for( int i = 0; i < c_markerCount; ++i )
{
pCurrentMarker = markerStorage->GetMarker( i );
pNextMarker = markerStorage->TryGetMarker( i + 1 );
g_ReplayAudioEntity.SetMarkerSFXValid(i, true);
if(pCurrentMarker)
{
if(pCurrentMarker->GetSfxOSVolume() == 0)
{
g_ReplayAudioEntity.SetMarkerSFXValid(i, false);
}
else if(pNextMarker)
{
static float minTimeBetweenSFXMarkers = 450.0f;
f32 currentMarkerTime = ConvertNonDilatedTimeToTimeMs(GetCurrentClipIndex(), pCurrentMarker->GetNonDilatedTimeMs());
f32 nextMarkerTime = ConvertNonDilatedTimeToTimeMs(GetCurrentClipIndex(), pNextMarker->GetNonDilatedTimeMs());
if(pNextMarker->GetSfxHash() != g_NullSoundHash && ((nextMarkerTime - currentMarkerTime) < minTimeBetweenSFXMarkers) )
{
g_ReplayAudioEntity.SetMarkerSFXValid(i, false);
}
}
}
if( pCurrentMarker && clipTimeMs >= pCurrentMarker->GetNonDilatedTimeMs() &&
( !pNextMarker || ( pNextMarker && clipTimeMs < pNextMarker->GetNonDilatedTimeMs() ) ) )
{
CReplayMarkerContext::SetCurrentMarkerIndex( i );
//Set Speed.
if ( !pCurrentMarker->IsAnchor() && pCurrentMarker != markerStorage->GetLastMarker())
{
eReplayMicType const c_micType = GetMicrophoneType( (eMarkerMicrophoneType)pCurrentMarker->GetMicrophoneType() );
naMicrophones::SetReplayMicType( (u8)c_micType );
if( CReplayMgr::IsPlaying() )
{
CReplayMgr::SetMarkerSpeed( pCurrentMarker->GetSpeedValueFloat() );
}
// Need to update volumes even whilst not playing so that we start playback on the correct volume
g_FrontendAudioEntity.SetClipSpeechOn( pCurrentMarker->IsSpeechOn() );
if(!g_ReplayAudioEntity.ShouldDuckMusic()) // once we're ducking only the play marker of the current SFX can control the music volume
{
g_FrontendAudioEntity.SetClipMusicVolumeIndex( pCurrentMarker->GetMusicVolume() );
}
g_FrontendAudioEntity.SetClipSFXVolumeIndex( pCurrentMarker->GetSfxVolume() );
g_FrontendAudioEntity.SetClipDialogVolumeIndex( pCurrentMarker->GetDialogVolume() );
g_FrontendAudioEntity.SetClipCustomAmbienceVolumeIndex( pCurrentMarker->GetAmbientVolume() );
if(pCurrentMarker->GetSfxHash() != g_NullSoundHash && g_ReplayAudioEntity.IsMarkerSFXValid(i))
{
g_FrontendAudioEntity.SetClipSFXOneshotVolumeIndex( pCurrentMarker->GetSfxOSVolume() );
}
float timeSinceIntensitySwitch = 0;
bool switchMoodsInstantly = false;
bool isDoingFullPlayback = CReplayCoordinator::IsExportingToVideoFile() || CReplayCoordinator::IsPreviewingVideo();
// If this is the very first clip, or we're just editing a single clip, or we're editing a single clip and we've paused,
// then switch moods instantly
if((pCurrentMarker == markerStorage->GetFirstMarker() && GetCurrentClipIndex() == 0) ||
(!isDoingFullPlayback && !CReplayMgr::IsPlaying()))
{
switchMoodsInstantly = true;
}
eReplayMarkerAudioIntensity prevReplayMarkerIntensity = MARKER_AUDIO_INTENSITY_MAX;
if(IsValid() && !isDoingFullPlayback)
{
// Need to find the previous music intensity marke so that we can correctly reproduce any
// intensity crossfade behaviour if playback resumes mid-crossfade
for( int prevMarkerIndex = i - 1; prevMarkerIndex >= 0; prevMarkerIndex-- )
{
sReplayMarkerInfo* pPrevMarker = markerStorage->GetMarker( prevMarkerIndex );
if(pPrevMarker && pPrevMarker->GetScoreIntensity() != pCurrentMarker->GetScoreIntensity())
{
prevReplayMarkerIntensity = eReplayMarkerAudioIntensity( pPrevMarker->GetScoreIntensity() );
CClip* clip = m_activeMontage->GetClip(m_activeClip);
float currentTimeMs = CReplayMgr::GetCurrentTimeRelativeMsFloat();
float prevMarkerTimeMs = clip->ConvertNonDilatedTimeMsToTimeMs( pCurrentMarker->GetNonDilatedTimeMs() );
timeSinceIntensitySwitch = currentTimeMs - prevMarkerTimeMs;
break;
}
}
}
g_InteractiveMusicManager.SetReplayScoreIntensity( eReplayMarkerAudioIntensity( pCurrentMarker->GetScoreIntensity() ), prevReplayMarkerIntensity, switchMoodsInstantly, (u32)timeSinceIntensitySwitch );
}
}
else
{
if (pCurrentMarker == markerStorage->GetFirstMarker() && clipTimeMs < pCurrentMarker->GetNonDilatedTimeMs() )
{
g_FrontendAudioEntity.SetClipSpeechOn(g_FrontendAudioEntity.GetSpeechOn()); // if we are before a marker then use the global setting.
g_FrontendAudioEntity.SetClipMusicVolumeIndex(8);
g_FrontendAudioEntity.SetClipSFXVolumeIndex(8);
g_FrontendAudioEntity.SetClipDialogVolumeIndex(8);
g_FrontendAudioEntity.SetClipCustomAmbienceVolumeIndex(8);
g_FrontendAudioEntity.SetClipSFXOneshotVolumeIndex(8);
CReplayMgr::SetMarkerSpeed( 1.f );
}
}
}
g_ReplayAudioEntity.SetSfxVolumeAffectingMusic(g_SilenceVolume); // base line is no sfx volume so no duck
// replay marker one shot sfx
if(c_markerCount > 1)// && (CReplayMgr::IsPreCachingScene() || CReplayMgr::IsJustPlaying()))
{
g_ReplayAudioEntity.SetShouldDuckMusic(false);
g_ReplayAudioEntity.InvalidateSFX();
bool foundPlayCandidate = false;
for( int i = c_markerCount-1; i >= 0; i-- )
{
pCurrentMarker = markerStorage->GetMarker( i );
if(!pCurrentMarker->IsAnchor())
{
u32 const c_sfxHash = pCurrentMarker->GetSfxHash();
u32 sfxDuration = c_sfxHash != g_NullSoundHash ? CReplayAudioTrackProvider::GetMusicTrackDurationMs(c_sfxHash) : 0;
// Assuming that the SFX doesn't get pitched up/down by replay marker speeds, the duration is measured in real (ie. dilated) time.
// We need to know the end time in non dilated time so that we can compare it to the current playback head.
f32 const sfxEndTimeMs = ConvertTimeToNonDilatedTimeMs(GetCurrentClipIndex(), ConvertNonDilatedTimeToTimeMs(GetCurrentClipIndex(), pCurrentMarker->GetNonDilatedTimeMs()) + sfxDuration);
if(pCurrentMarker && c_sfxHash != g_NullSoundHash && g_ReplayAudioEntity.IsMarkerSFXValid(i))
{
if(!foundPlayCandidate && clipTimeMs >= pCurrentMarker->GetNonDilatedTimeMs() - REPLAY_SFX_PRELAOD_MS && clipTimeMs < sfxEndTimeMs)
{
u32 startOffset = 0;
if(clipTimeMs > pCurrentMarker->GetNonDilatedTimeMs())
{
// As above, assuming that SFX doesn't get pitched up or down, we need to calculate the offset based on the real (ie. dilated) time since the marker was hit
startOffset = (u32)(ConvertNonDilatedTimeToTimeMs(GetCurrentClipIndex(), clipTimeMs) - ConvertNonDilatedTimeToTimeMs(GetCurrentClipIndex(), pCurrentMarker->GetNonDilatedTimeMs()));
}
if(startOffset < sfxDuration)
{
g_ReplayAudioEntity.Preload(i, c_sfxHash, REPLAY_STREAM_SFX, startOffset);
}
}
else
{
g_ReplayAudioEntity.Stop(i, c_sfxHash, true);
}
if(!foundPlayCandidate && clipTimeMs >= pCurrentMarker->GetNonDilatedTimeMs())
{
foundPlayCandidate = true;
}
if(clipTimeMs >= pCurrentMarker->GetNonDilatedTimeMs() - 1000 && clipTimeMs < sfxEndTimeMs && g_ReplayAudioEntity.IsLoadedOrPlaying(i, c_sfxHash))
{
//should duck music
f32 sfxVolume = g_FrontendAudioEntity.VolumeIndexToDb(pCurrentMarker->GetSfxOSVolume());
f32 sfxVolumeAffectingMusic = g_ReplayAudioEntity.GetSFXVolumeAffectingMusic();
if(sfxVolume > sfxVolumeAffectingMusic) // music is affected by the loudest SFX volume within the window
{
g_ReplayAudioEntity.SetSfxVolumeAffectingMusic(sfxVolume);
}
g_ReplayAudioEntity.SetShouldDuckMusic(true);
}
}
if(CReplayMgr::IsJustPlaying() && !CReplayMgr::IsSettingUp() && !CReplayMgr::IsPreCachingScene())
{
if(c_sfxHash != g_NullSoundHash && clipTimeMs >= pCurrentMarker->GetNonDilatedTimeMs() && clipTimeMs < sfxEndTimeMs && g_ReplayAudioEntity.IsReadyToPlay(i, c_sfxHash))
{
Displayf("Play SFX on marker %d", i);
// stop any playing sfx before we start a new one
g_ReplayAudioEntity.StopAllPlayingSFX();
g_ReplayAudioEntity.Play(i, c_sfxHash);
g_FrontendAudioEntity.SetClipMusicVolumeIndex( pCurrentMarker->GetMusicVolume() );
}
}
}
}
g_ReplayAudioEntity.ClearInvalidSFX();
}
s32 currIndex = CReplayMarkerContext::GetCurrentMarkerIndex();
CReplayMarkerContext::SetPreviousActiveMarkerIndex( currIndex );
}
void CReplayPlaybackController::UpdateMontageAudioFadeOut()
{
const f32 currentTimeMs = CReplayMgr::GetCurrentTimeRelativeMsFloat();
f32 sfxVolLinear = 1.0f;
if(IsValid())
{
f32 fraction = 0.0f;
ReplayMarkerTransitionType transition;
u32 clipIndex = GetCurrentClipIndex();
clipIndex = CReplayCoordinator::IsPendingNextClip() && clipIndex > 0 ? clipIndex - 1 : clipIndex;
m_activeMontage->GetActiveTransition(clipIndex, currentTimeMs, transition, fraction);
if(transition != MARKER_TRANSITIONTYPE_MAX &&
transition != MARKER_TRANSITIONTYPE_NONE)
{
sfxVolLinear = 1.0f - fraction;
}
}
g_FrontendAudioEntity.SetClipFadeVolLinear(sfxVolLinear);
}
CClip const* CReplayPlaybackController::GetClip( s32 clipIndex ) const
{
clipIndex = clipIndex < 0 ? m_activeClip : clipIndex;
return IsValid() ? m_activeMontage->GetClip( clipIndex ) : NULL;
}
bool CReplayPlaybackController::IsExportingToVideoFile() const
{
return m_recordingDataProvider && m_recordingDataProvider->IsRecordingVideo();
}
bool CReplayPlaybackController::IsExportingPaused() const
{
return m_recordingDataProvider && m_recordingDataProvider->IsRecordingPaused();
}
bool CReplayPlaybackController::IsExportReadyForReplay() const
{
return m_recordingDataProvider && m_recordingDataProvider->IsRecordingReadyForSamples();
}
bool CReplayPlaybackController::IsExportingAudioFrameCaptureAllowed() const
{
return m_recordingDataProvider && m_recordingDataProvider->IsAudioFrameCaptureAllowed();
}
bool CReplayPlaybackController::HasExportErrored() const
{
return m_recordingDataProvider && m_recordingDataProvider->HasRecordingErrored();
}
float CReplayPlaybackController::GetExportFrameDurationMs() const
{
return m_recordingDataProvider ? m_recordingDataProvider->GetExportFrameDurationMs() : 33.f;
}
u64 CReplayPlaybackController::GetCurrentRawClipOwnerId() const
{
return IsValid() ? m_activeMontage->GetClip( m_activeClip )->GetOwnerId() : 0;
}
char const * CReplayPlaybackController::GetCurrentRawClipFileName() const
{
return IsValid() ? m_activeMontage->GetClip( m_activeClip )->GetName() : NULL;
}
s32 CReplayPlaybackController::GetCurrentClipIndex() const
{
return IsValid() ? m_activeClip : -1;
}
s32 CReplayPlaybackController::GetTotalClipCount() const
{
return IsValid() ? m_activeMontage->GetClipCount() : -1;
}
float CReplayPlaybackController::GetClipStartNonDilatedTimeMs( s32 const clipIndex ) const
{
CClip const * activeClip = GetClip( clipIndex );
return activeClip ? activeClip->GetStartNonDilatedTimeMs() : 0;
}
float CReplayPlaybackController::GetClipNonDilatedEndTimeMs( s32 const clipIndex ) const
{
CClip const * activeClip = GetClip( clipIndex );
return activeClip ? activeClip->GetEndNonDilatedTimeMs() : 0;
}
float CReplayPlaybackController::GetClipNonDilatedDurationMs( s32 const clipIndex ) const
{
CClip const * activeClip = GetClip( clipIndex );
return activeClip ? activeClip->GetRawDurationMs() : 0;
}
float CReplayPlaybackController::GetClipRawEndTimeMs( s32 const clipIndex ) const
{
CClip const * activeClip = GetClip( clipIndex );
return activeClip ? activeClip->GetRawDurationMs() : 0;
}
float CReplayPlaybackController::GetClipTrimmedTimeMs( s32 const clipIndex ) const
{
CClip const * activeClip = GetClip( clipIndex );
return activeClip ? activeClip->GetTrimmedTimeMs() : 0;
}
float CReplayPlaybackController::GetLengthTimeToClipMs( s32 const clipIndex ) const
{
return IsValid() ? m_activeMontage->GetTrimmedTimeToClipMs( clipIndex ) : 0;
}
u64 CReplayPlaybackController::GetLengthTimeToClipNs( s32 const clipIndex ) const
{
return IsValid() ? m_activeMontage->GetTrimmedTimeToClipNs( clipIndex ) : 0;
}
float CReplayPlaybackController::GetLengthNonDilatedTimeToClipMs( s32 const clipIndex ) const
{
return IsValid() ? m_activeMontage->GetTrimmedNonDilatedTimeToClipMs( clipIndex ) : 0;
}
float CReplayPlaybackController::ConvertNonDilatedTimeToTimeMs( s32 const clipIndex, float const currentTimeMs ) const
{
float realTimeMs = (float)GetLengthTimeToClipMs( clipIndex );
CClip const* activeClip = GetClip( clipIndex );
if( activeClip )
{
realTimeMs += activeClip->ConvertNonDilatedTimeMsToTimeMs( currentTimeMs );
}
return realTimeMs;
}
float CReplayPlaybackController::ConvertTimeToNonDilatedTimeMs( s32 const clipIndex, float const currentTimeMS ) const
{
float nonDilatedTimeMS = GetLengthNonDilatedTimeToClipMs( clipIndex );
CClip const* activeClip = GetClip( clipIndex );
if( activeClip )
{
nonDilatedTimeMS += activeClip->ConvertTimeMsToNonDilatedTimeMs( currentTimeMS );
}
return nonDilatedTimeMS;
}
float CReplayPlaybackController::ConvertMusicBeatTimeToNonDilatedTimeMs( s32 const clipIndex, float const beatTimeMs ) const
{
float clipBeatTime = -1.f;
if( IsValid() )
{
s32 beatClipIndex = -1;
// Given a montage-relative music beat time, convert this to an offset within the given clip
m_activeMontage->ConvertMusicBeatTimeToNonDilatedTimeMs( beatTimeMs, beatClipIndex, clipBeatTime );
// Check that the beat is actually within the selected clip
clipBeatTime = (beatClipIndex == clipIndex) ? clipBeatTime : -1.f;
}
return clipBeatTime;
}
s32 CReplayPlaybackController::GetMusicIndexAtCurrentNonDilatedTimeMs( s32 const clipIndex, float const currentTimeMs ) const
{
s32 const index = IsValid() ? m_activeMontage->GetActiveMusicIndex( clipIndex, currentTimeMs ) : -1;
return index;
}
s32 CReplayPlaybackController::GetNextMusicIndexFromCurrentNonDilatedTimeMs( s32 const clipIndex, float const currentTimeMs ) const
{
s32 const index = IsValid() ? m_activeMontage->GetNextActiveMusicIndex( clipIndex, currentTimeMs ) : -1;
return index;
}
s32 CReplayPlaybackController::GetPreviousMusicIndexFromCurrentNonDilatedTimeMs( s32 const clipIndex, float const currentTimeMs ) const
{
s32 const index = IsValid() ? m_activeMontage->GetPreviousActiveMusicIndex( clipIndex, currentTimeMs ) : -1;
return index;
}
s32 CReplayPlaybackController::GetMusicStartTimeMs( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetMusicStartTimeMs( musicIndex ) : -1;
}
s32 CReplayPlaybackController::GetMusicStartOffsetMs( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetMusicStartOffsetMs( musicIndex ) : -1;
}
s32 CReplayPlaybackController::GetMusicDurationMs( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetMusicDurationMs( musicIndex ) : -1;
}
u32 CReplayPlaybackController::GetMusicSoundHash( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetMusicClipSoundHash( musicIndex ) : 0;
}
bool CReplayPlaybackController::PauseMusicOnClipEnd() const
{
return IsValid() && !CReplayCoordinator::IsRenderingVideo();
}
//Ambient track
s32 CReplayPlaybackController::GetAmbientTrackIndexAtCurrentNonDilatedTimeMs( s32 const clipIndex, float const currentTimeMs ) const
{
s32 const index = IsValid() ? m_activeMontage->GetActiveAmbientTrackIndex( clipIndex, currentTimeMs ) : -1;
return index;
}
s32 CReplayPlaybackController::GetAmbientTrackStartTimeMs( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetAmbientStartTimeMs( musicIndex ) : -1;
}
s32 CReplayPlaybackController::GetAmbientTrackStartOffsetMs( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetAmbientStartOffsetMs( musicIndex ) : -1;
}
s32 CReplayPlaybackController::GetAmbientTrackDurationMs( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetAmbientDurationMs( musicIndex ) : -1;
}
u32 CReplayPlaybackController::GetAmbientTrackSoundHash( u32 const musicIndex ) const
{
return IsValid() ? m_activeMontage->GetAmbientClipSoundHash( musicIndex ) : 0;
}
bool CReplayPlaybackController::CanUpdateGameTimer() const
{
return IsValid();
}
float CReplayPlaybackController::GetTotalPlaybackTimeMs() const
{
return IsValid() ? m_activeMontage->GetTotalClipLengthTimeMs() : 0;
}
void CReplayPlaybackController::JumpToClip( s32 const clipIndex, float const clipNonDilatedTimeMs )
{
m_pendingJumpClip = clipIndex;
m_pendingJumpClipNonDilatedTimeMs = clipNonDilatedTimeMs;
}
s32 CReplayPlaybackController::GetPendingJumpClip() const
{
return m_pendingJumpClip;
}
float CReplayPlaybackController::GetPendingJumpClipNonDilatedTimeMs() const
{
return m_pendingJumpClipNonDilatedTimeMs;
}
void CReplayPlaybackController::ClearPendingJumpClipNonDilatedTimeMs()
{
m_pendingJumpClipNonDilatedTimeMs = INDEX_NONE;
}
bool CReplayPlaybackController::IsPendingClipJump() const
{
return GetPendingJumpClip() != INDEX_NONE;
}
bool CReplayPlaybackController::OnClipChanged( s32 const clipIndex )
{
bool success = false;
if( GetClip( clipIndex ) != NULL )
{
if( clipIndex != m_activeClip )
{
OnCurrentClipFinished();
}
SetActiveClip( clipIndex );
success = true;
}
m_pendingJumpClip = INDEX_NONE;
return success;
}
void CReplayPlaybackController::OnCurrentClipFinished()
{
}
void CReplayPlaybackController::OnPlaybackFinished()
{
if( CReplayCoordinator::IsRenderingVideo() )
{
CReplayCoordinator::KillPlaybackOrBake( false );
}
}
void CReplayPlaybackController::OnClipPlaybackStart()
{
//ensure the correct playback states for the various modes are set correctly
if( CReplayCoordinator::IsRenderingVideo() )
{
#if USE_SRLS_IN_REPLAY
if ( CReplayMgr::IsCreatingSRL())
{
CReplayMgr::SetNextPlayBackState(REPLAY_STATE_PLAY | REPLAY_DIRECTION_FWD);
}
else
#endif
{
CReplayMgr::SetNextPlayBackState(REPLAY_STATE_PAUSE);
m_startClipNextFrame = true;
}
}
else if(CReplayCoordinator::IsPreviewingClip())
{
CReplayMgr::SetNextPlayBackState(REPLAY_STATE_PAUSE);
}
else if( CReplayCoordinator::IsPreviewingVideo())
{
if(m_possibleFirstClipOfProject && m_activeClip == 0)
{
CReplayMgr::SetNextPlayBackState(REPLAY_STATE_PAUSE);
m_startClipNextFrame = true;
}
m_possibleFirstClipOfProject = false;
}
}
void CReplayPlaybackController::OnClipPlaybackEnd()
{
if( CReplayCoordinator::IsRenderingVideo() )
{
audNorthAudioEngine::PumpReplayAudio();
CReplayCoordinator::PauseBake();
}
}
void CReplayPlaybackController::OnClipPlaybackUpdate()
{
// should only get called when rendering a video, so don't bother doing another test
if( m_startClipNextFrame )
{
// playback resumed a frame later, to give camera an opportunity to get set up
// perhaps tie into camera returning back it's ready to go, but overkill???
CReplayMgr::ResumeNormalPlayback();
CReplayCoordinator::ResumeBake();
m_startClipNextFrame = false;
}
}
void CReplayPlaybackController::SetActiveClip( s32 const activeClip )
{
m_activeClip = activeClip;
CReplayMarkerContext::SetCurrentMarkerStorage( TryGetCurrentMarkerStorage() );
camInterface::GetReplayDirector().OnReplayClipChanged();
}
CClip* CReplayPlaybackController::GetClip( s32 clipIndex )
{
clipIndex = clipIndex < 0 ? m_activeClip : clipIndex;
return IsValid() ? m_activeMontage->GetClip( clipIndex ) : NULL;
}
eReplayMicType CReplayPlaybackController::GetMicrophoneType( eMarkerMicrophoneType const markerMicrophoneType )
{
eReplayMicType micType = replayMicDefault;
switch( markerMicrophoneType )
{
case MARKER_MICROPHONE_AT_CAMERA:
{
micType = replayMicAtCamera;
break;
}
case MARKER_MICROPHONE_AT_TARGET:
{
micType = replayMicAtTarget;
break;
}
case MARKER_MICROPHONE_CINEMATIC:
{
micType = replayMicCinematic;
break;
}
case MARKER_MICROPHONE_DEFAULT:
default:
{
// NOP
}
}
return micType;
}
#endif // GTA_REPLAY