417 lines
12 KiB
Ucode
417 lines
12 KiB
Ucode
//==============================================================================
|
|
// Created on: 10/12/2003
|
|
// Relays player input to the appropriate handlers on behalf of the streaming music system
|
|
// Relays notification of streaming music events to the appropriate handlers
|
|
//
|
|
// Written by Ron Prestenback
|
|
// © 2003, Epic Games, Inc. All Rights Reserved
|
|
//==============================================================================
|
|
class StreamInteraction extends Interaction
|
|
Native
|
|
Config(User);
|
|
|
|
cpptext
|
|
{
|
|
void Destroy();
|
|
static struct FrameTypeList* GetFrameTypes();
|
|
}
|
|
|
|
var() config float FadeInSeconds;
|
|
var() config float FadeOutSeconds;
|
|
|
|
var() config string PlaylistManagerType;
|
|
var() editconst noexport editinline StreamPlaylistManager PlaylistManager;
|
|
var() editconst noexport editinline StreamInterface FileManager;
|
|
|
|
var() editconst noexport protected int CurrentSongHandle;
|
|
var() editconst noexport protected float CurrentSongPosition, LastPlayTime, CurrentSongDuration;
|
|
var() editconst noexport protected string CurrentSong;
|
|
var() editconst noexport Stream CurrentStreamAttachment;
|
|
|
|
var() config bool bAutoStart; // Whether to automatically start the stream player when the game is started
|
|
var() config bool bDisplayTrackChanges; // When new song begins, display the track name on the HUD for a few seconds
|
|
var() transient editconst noexport protected bool bRestartTrack; // Used to restart stream after level change
|
|
var() transient editconst noexport protected bool bTrackWaiting; // Used to switch tracks
|
|
|
|
delegate OnStreamChanged( string NewStreamFileName );
|
|
delegate OnStreamingStopped();
|
|
delegate OnAdjustVolume( float NewVolume );
|
|
|
|
const INVALIDSONGHANDLE = 0;
|
|
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
// Initialization
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
|
|
event Initialized()
|
|
{
|
|
Super.Initialized();
|
|
|
|
ClearSongInfo();
|
|
|
|
FileManager = CreateFileManager();
|
|
PlaylistManager = CreatePlaylistManager();
|
|
if ( PlaylistManager != None )
|
|
PlaylistManager.Initialize( FileManager );
|
|
|
|
if ( bAutoStart )
|
|
QueueNextSong();
|
|
}
|
|
|
|
function StreamInterface CreateFileManager()
|
|
{
|
|
return new class'Engine.StreamInterface';
|
|
}
|
|
|
|
function StreamPlaylistManager CreatePlaylistManager()
|
|
{
|
|
local class<StreamPlaylistManager> PlaylistManagerClass;
|
|
|
|
if ( PlaylistManagerType != "" )
|
|
PlaylistManagerClass = class<StreamPlaylistManager>(DynamicLoadObject(PlaylistManagerType,class'Class'));
|
|
|
|
if ( PlaylistManagerClass == None )
|
|
PlaylistManagerClass = class'Engine.StreamPlaylistManager';
|
|
|
|
return new PlaylistManagerClass;
|
|
}
|
|
|
|
function QueueNextSong()
|
|
{
|
|
bTrackWaiting = True;
|
|
}
|
|
|
|
event Tick( float DeltaTime )
|
|
{
|
|
if ( bTrackWaiting )
|
|
NextSong();
|
|
|
|
else if ( bRestartTrack )
|
|
{
|
|
bRestartTrack = False;
|
|
PlayStream(CurrentSong, CurrentSongPosition);
|
|
}
|
|
|
|
else if ( !IsPaused() && CurrentSongHandle != INVALIDSONGHANDLE )
|
|
CurrentSongPosition += (DeltaTime / ViewportOwner.Actor.Level.TimeDilation);
|
|
}
|
|
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
// Notification / Events
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
|
|
native final function bool IsPaused( optional int SongHandle );
|
|
|
|
function SetStreamAttachment( Stream StreamObj )
|
|
{
|
|
local StreamTag sTag;
|
|
|
|
CurrentStreamAttachment = StreamObj;
|
|
if ( CurrentStreamAttachment != None )
|
|
{
|
|
sTag = CurrentStreamAttachment.GetTag();
|
|
if ( sTag != None )
|
|
CurrentSongDuration = float(sTag.Duration.FieldValue) / 1000.0;
|
|
}
|
|
}
|
|
|
|
// Called when the current song is over
|
|
function StreamFinished( int Handle, EStreamFinishReason Reason )
|
|
{
|
|
Super.StreamFinished( Handle, Reason );
|
|
|
|
PlaylistManager.Save();
|
|
|
|
log("StreamFinished() Handle:"$Handle@"Reason:"$GetEnum(enum'EStreamFinishReason',Reason),'MusicPlayer');
|
|
if ( Handle == CurrentSongHandle && CurrentSongHandle != INVALIDSONGHANDLE )
|
|
{
|
|
log("CurrentSongPosition:"$class'StreamBase'.static.FormatTimeDisplay(CurrentSongPosition)@"Total song time:"$class'StreamBase'.static.FormatTimeDisplay(GetStreamDuration()));
|
|
CurrentSongPosition = 0.0;
|
|
CurrentSongHandle = INVALIDSONGHANDLE;
|
|
SetStreamAttachment(None);
|
|
OnStreamingStopped();
|
|
QueueNextSong();
|
|
}
|
|
else log(Name@"StreamFinished Invalid Song Handle",'MusicPlayer');
|
|
}
|
|
|
|
event NotifyLevelChange()
|
|
{
|
|
// log("Last Position before level change was:"$CurrentSongPosition);
|
|
if ( CurrentSongHandle != INVALIDSONGHANDLE && CurrentSong != "" )
|
|
bRestartTrack = True;
|
|
}
|
|
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
// Commands
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
|
|
exec function string GetCurrentStream()
|
|
{
|
|
HasPlayer();
|
|
log("CurrentSongHandle:"$CurrentSongHandle@"CurrentSong:"$CurrentSong@"IsPaused:"$IsPaused());
|
|
|
|
return CurrentSong;
|
|
}
|
|
|
|
function int CurrentHandle()
|
|
{
|
|
return CurrentSongHandle;
|
|
}
|
|
|
|
exec function NextSong( optional bool bForce )
|
|
{
|
|
if ( !HasPlayer() )
|
|
return; //!! Might cause player to get stuck
|
|
|
|
bTrackWaiting = False;
|
|
PlayStream( PlaylistManager.NextSong(bForce) );
|
|
}
|
|
|
|
exec function PrevSong( optional bool bForce )
|
|
{
|
|
if ( !HasPlayer() )
|
|
return;
|
|
|
|
bTrackWaiting = False;
|
|
|
|
// Unless we're still in the first three seconds of the song,
|
|
// restart the current track
|
|
if ( CurrentSongPosition > 3.0 )
|
|
PlayStream( CurrentSong );
|
|
|
|
else PlayStream( PlaylistManager.PrevSong(bForce) );
|
|
}
|
|
|
|
exec function PauseSong()
|
|
{
|
|
if ( !HasPlayer() )
|
|
return;
|
|
|
|
if ( CurrentSongHandle != INVALIDSONGHANDLE )
|
|
PC().PauseStream(CurrentSongHandle);
|
|
}
|
|
|
|
exec function PlaySong( string SongName, float InitialTime )
|
|
{
|
|
if ( !HasPlayer() )
|
|
return;
|
|
|
|
// log("PlaySong SongName:"$SongName@"InitialTime:"$InitialTime);
|
|
PlayStream(SongName, InitialTime);
|
|
}
|
|
|
|
exec function StopSong()
|
|
{
|
|
if ( !HasPlayer() )
|
|
return;
|
|
|
|
if ( CurrentSongHandle != INVALIDSONGHANDLE )
|
|
PC().StopStream(CurrentSongHandle, FadeOutSeconds);
|
|
|
|
// Re-enable music playback
|
|
PC().AllowMusicPlayback(True);
|
|
ClearSongInfo();
|
|
}
|
|
|
|
exec function SetMusicVolume( float NewVolume )
|
|
{
|
|
if ( HasPlayer() )
|
|
{
|
|
PC().AdjustVolume( CurrentSongHandle, FClamp(NewVolume, 0.0, 1.0) );
|
|
OnAdjustVolume(NewVolume);
|
|
}
|
|
}
|
|
|
|
exec function SeekStream( float Seconds )
|
|
{
|
|
Seek(Seconds);
|
|
}
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
// Stream Manipulation
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
function bool Seek( float SeekSeconds )
|
|
{
|
|
// log("StreamInternaction CurrentHandle:"$CurrentSongHandle@"CurrentPosition:"$CurrentSongPosition@"seeking to "$SeekSeconds);
|
|
// Current decoder doesn't support seeking, so just return false
|
|
return False;
|
|
if ( CurrentSongHandle != INVALIDSONGHANDLE )
|
|
{
|
|
if ( PC().SeekStream(CurrentSongHandle, SeekSeconds) > 0 )
|
|
{
|
|
CurrentSongPosition = SeekSeconds;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function PlayStream( string FileName, optional int SeekSeconds )
|
|
{
|
|
local int LastSongHandle;
|
|
|
|
if ( FileName != "" )
|
|
{
|
|
if ( FileName == CurrentSong && IsPaused() && SeekSeconds == 0.0 )
|
|
{
|
|
PauseSong();
|
|
return;
|
|
}
|
|
|
|
// Current decoder doesn't support seeking - reset this value unless decoder is changed
|
|
SeekSeconds = 0;
|
|
LastSongHandle = CurrentSongHandle;
|
|
|
|
if ( SeekSeconds > 0.0 && CurrentSong == FileName )
|
|
CurrentSongHandle = PC().PlayStream(FileName, True);
|
|
else CurrentSongHandle = PC().PlayStream(FileName, True);
|
|
|
|
if ( CurrentSongHandle == INVALIDSONGHANDLE )
|
|
log("StreamInteraction::PlaySong() Invalid song name:"@FileName,'MusicPlayer');
|
|
else
|
|
{
|
|
KillMusic();
|
|
CurrentSongPosition = SeekSeconds;
|
|
CurrentSongDuration = 0.0;
|
|
|
|
if ( LastSongHandle != INVALIDSONGHANDLE )
|
|
{
|
|
if ( SeekSeconds > 0.0 && CurrentSong == Filename )
|
|
PC().StopStream(LastSongHandle);
|
|
else PC().StopStream(LastSongHandle, FadeOutSeconds);
|
|
}
|
|
|
|
CurrentSong = Filename;
|
|
|
|
// TODO : better render to hud
|
|
if ( bDisplayTrackChanges )
|
|
PC().ClientMessage( "Now playing '"$CurrentSong$"' Handle:"$CurrentSongHandle);
|
|
|
|
OnStreamChanged(CurrentSong);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( CurrentSongHandle == INVALIDSONGHANDLE )
|
|
{
|
|
PC().AllowMusicPlayback(True);
|
|
ClearSongInfo();
|
|
}
|
|
}
|
|
}
|
|
|
|
function float GetStreamPosition()
|
|
{
|
|
return CurrentSongPosition;
|
|
}
|
|
|
|
function float GetStreamVolume()
|
|
{
|
|
if ( HasPlayer() )
|
|
return float(PC().ConsoleCommand("get ini:Engine.Engine.AudioDevice MusicVolume"));
|
|
|
|
return 0.8;
|
|
}
|
|
|
|
function float GetStreamDuration()
|
|
{
|
|
if ( !IsPlaying() )
|
|
return 0.0;
|
|
|
|
if ( CurrentSongDuration == 0.0 )
|
|
CurrentSongDuration = float(PC().ConsoleCommand("GETDURATION"@CurrentSongHandle));
|
|
|
|
return CurrentSongDuration;
|
|
}
|
|
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
// Utility / Internal
|
|
// =====================================================================================================================
|
|
// =====================================================================================================================
|
|
|
|
// Call SongNext() when Tick() is called
|
|
|
|
function bool IsPlaying()
|
|
{
|
|
return CurrentSongHandle != INVALIDSONGHANDLE;
|
|
}
|
|
|
|
function bool HasPlayer()
|
|
{
|
|
if ( ViewportOwner == None )
|
|
{
|
|
log("StreamInteraction::HasPlayer() - No ViewportOwner!",'MusicPlayer');
|
|
return false;
|
|
}
|
|
|
|
if ( ViewportOwner.Actor == None )
|
|
{
|
|
log("StreamInteraction::HasPlayer() - No PlayerController!",'MusicPlayer');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function ClearSongInfo()
|
|
{
|
|
// Clear all transients
|
|
SetStreamAttachment(None);
|
|
CurrentSong = "";
|
|
CurrentSongHandle = INVALIDSONGHANDLE;
|
|
CurrentSongPosition = 0.0;
|
|
CurrentSongDuration = 0.0;
|
|
}
|
|
|
|
// Kill any level/background music currently playing, and disable music
|
|
protected function KillMusic()
|
|
{
|
|
if ( !HasPlayer() )
|
|
return;
|
|
|
|
PC().StopAllMusic();
|
|
PC().AllowMusicPlayback(false);
|
|
}
|
|
|
|
protected function PlayerController PC()
|
|
{
|
|
if ( HasPlayer() )
|
|
return ViewportOwner.Actor;
|
|
|
|
return None;
|
|
}
|
|
|
|
exec function streamdebug( string Command, string Param )
|
|
{
|
|
if ( Command ~= "getstats" )
|
|
{
|
|
log(" CurrentSong '"$CurrentSong$"' Handle:"$CurrentSongHandle@"Pos:"$CurrentSongPosition@"Duration:"$CurrentSongDuration);
|
|
return;
|
|
}
|
|
if ( FileManager.HandleDebugExec(Command,Param) )
|
|
return;
|
|
|
|
if ( PlaylistManager.HandleDebugExec( Command, Param) )
|
|
return;
|
|
|
|
// if ( Editor != None )
|
|
// Editor.HandleDebugExec(Command,Param);
|
|
}
|
|
|
|
DefaultProperties
|
|
{
|
|
FadeInSeconds=0.5
|
|
FadeOutSeconds=0.5
|
|
bRequiresTick=True
|
|
}
|