aboutsummaryrefslogtreecommitdiffstats
path: root/Game
diff options
context:
space:
mode:
Diffstat (limited to 'Game')
-rw-r--r--Game/Code/Classes/UAudioDecoder_FFMpeg.pas84
-rw-r--r--Game/Code/Classes/UAudioPlayback_SoftMixer.pas6
-rw-r--r--Game/Code/Classes/UMain.pas24
-rw-r--r--Game/Code/Classes/UMusic.pas75
-rw-r--r--Game/Code/Menu/UDisplay.pas1
-rw-r--r--Game/Code/Menu/UMenu.pas32
-rw-r--r--Game/Code/Screens/UScreenSing.pas12
7 files changed, 153 insertions, 81 deletions
diff --git a/Game/Code/Classes/UAudioDecoder_FFMpeg.pas b/Game/Code/Classes/UAudioDecoder_FFMpeg.pas
index f1c9b364..2a9b7518 100644
--- a/Game/Code/Classes/UAudioDecoder_FFMpeg.pas
+++ b/Game/Code/Classes/UAudioDecoder_FFMpeg.pas
@@ -102,6 +102,7 @@ type
seekRequest: boolean;
seekFlags : integer;
seekPos : int64;
+ seekCond : PSDL_Cond;
parseThread: PSDL_Thread;
packetQueue: TPacketQueue;
@@ -221,6 +222,7 @@ begin
decoderLock := SDL_CreateMutex();
parserLock := SDL_CreateMutex();
resumeCond := SDL_CreateCond();
+ seekCond := SDL_CreateCond();
parseThread := SDL_CreateThread(@DecodeThreadMain, Self);
end;
@@ -278,7 +280,7 @@ begin
// abort parse-thread
LockParser();
quitRequest := true;
- SDL_CondSignal(resumeCond);
+ SDL_CondBroadcast(resumeCond);
UnlockParser();
// and wait until it terminates
if (parseThread <> nil) then
@@ -355,6 +357,22 @@ begin
UnlockDecoder();
end;
+(*
+procedure TFFMpegDecodeStream.SetError(state: boolean);
+begin
+ LockDecoder();
+ ErrorState := state;
+ UnlockDecoder();
+end;
+
+function TFFMpegDecodeStream.IsSeeking(): boolean;
+begin
+ LockDecoder();
+ Result := seekRequest;
+ UnlockDecoder();
+end;
+*)
+
function TFFMpegDecodeStream.GetPosition(): real;
begin
// FIXME: the audio-clock might not be that accurate
@@ -378,9 +396,14 @@ begin
seekFlags := AVSEEK_FLAG_BACKWARD;
seekFlags := AVSEEK_FLAG_ANY;
+LockDecoder();
seekRequest := true;
+UnlockDecoder();
SDL_CondSignal(resumeCond);
-
+ (*
+ while ((not quitRequest) and seekRequest) do
+ SDL_CondWait(seekCond, GetParserMutex());
+ *)
UnlockParser();
end;
@@ -446,7 +469,10 @@ begin
packetQueue.Flush();
packetQueue.PutStatus(PKT_STATUS_FLAG_FLUSH, nil);
end;
+ LockDecoder();
seekRequest := false;
+ UnlockDecoder();
+ SDL_CondSignal(seekCond);
end;
UnlockParser();
@@ -517,20 +543,15 @@ begin
begin
data_size := bufSize;
- try
- {$IF LIBAVCODEC_VERSION >= 51030000} // 51.30.0
- len1 := avcodec_decode_audio2(pCodecCtx, @buffer,
- data_size, audio_pkt_data, audio_pkt_size);
- {$ELSE}
- // FIXME: with avcodec_decode_audio a package could contain several frames
- // this is not handled yet
- len1 := avcodec_decode_audio(pCodecCtx, @buffer,
- data_size, audio_pkt_data, audio_pkt_size);
- {$IFEND}
- except
- Log.LogError('Exception at avcodec_decode_audio(2)!', 'TFFMpegDecodeStream.DecodeFrame');
- len1 := -1;
- end;
+ {$IF LIBAVCODEC_VERSION >= 51030000} // 51.30.0
+ len1 := avcodec_decode_audio2(pCodecCtx, @buffer,
+ data_size, audio_pkt_data, audio_pkt_size);
+ {$ELSE}
+ // FIXME: with avcodec_decode_audio a package could contain several frames
+ // this is not handled yet
+ len1 := avcodec_decode_audio(pCodecCtx, @buffer,
+ data_size, audio_pkt_data, audio_pkt_size);
+ {$IFEND}
if(len1 < 0) then
begin
@@ -632,6 +653,17 @@ begin
if EOF then
exit;
+ LockDecoder();
+ try
+ if (seekRequest) then
+ begin
+ Result := 0;
+ Exit;
+ end;
+ finally
+ UnlockDecoder();
+ end;
+
// copy data to output buffer
while (nBytesRemain > 0) do begin
// check if we need more data
@@ -725,20 +757,27 @@ begin
if (not FileExists(Filename)) then
begin
- Log.LogStatus('LoadSoundFromFile: Sound not found "' + Filename + '"', 'UAudio_FFMpeg');
+ Log.LogError('Audio-file does not exist: "' + Filename + '"', 'UAudio_FFMpeg');
exit;
end;
// open audio file
if (av_open_input_file(pFormatCtx, PChar(Filename), nil, 0, nil) <> 0) then
+ begin
+ Log.LogError('av_open_input_file failed: "' + Filename + '"', 'UAudio_FFMpeg');
exit;
+ end;
// TODO: do we need to generate PTS values if they do not exist?
//pFormatCtx^.flags := pFormatCtx^.flags or AVFMT_FLAG_GENPTS;
-
+
// retrieve stream information
if (av_find_stream_info(pFormatCtx) < 0) then
+ begin
+ Log.LogError('av_find_stream_info failed: "' + Filename + '"', 'UAudio_FFMpeg');
+ av_close_input_file(pFormatCtx);
exit;
+ end;
// FIXME: hack used by ffplay. Maybe should not use url_feof() to test for the end
pFormatCtx^.pb.eof_reached := 0;
@@ -749,7 +788,11 @@ begin
ffmpegStreamID := FindAudioStreamIndex(pFormatCtx);
if (ffmpegStreamID < 0) then
+ begin
+ Log.LogError('FindAudioStreamIndex: No Audio-stream found "' + Filename + '"', 'UAudio_FFMpeg');
+ av_close_input_file(pFormatCtx);
exit;
+ end;
//Log.LogStatus('AudioStreamIndex is: '+ inttostr(ffmpegStreamID), 'UAudio_FFMpeg');
@@ -759,7 +802,8 @@ begin
pCodec := avcodec_find_decoder(pCodecCtx^.codec_id);
if (pCodec = nil) then
begin
- Log.LogStatus('Unsupported codec!', 'UAudio_FFMpeg');
+ Log.LogError('Unsupported codec!', 'UAudio_FFMpeg');
+ av_close_input_file(pFormatCtx);
exit;
end;
@@ -777,7 +821,7 @@ begin
// Note: avcodec_open() is not thread-safe!
if (avcodec_open(pCodecCtx, pCodec) < 0) then
begin
- Log.LogStatus('avcodec_open failed!', 'UAudio_FFMpeg');
+ Log.LogError('avcodec_open failed!', 'UAudio_FFMpeg');
exit;
end;
diff --git a/Game/Code/Classes/UAudioPlayback_SoftMixer.pas b/Game/Code/Classes/UAudioPlayback_SoftMixer.pas
index 714e19ae..8ffe55ac 100644
--- a/Game/Code/Classes/UAudioPlayback_SoftMixer.pas
+++ b/Game/Code/Classes/UAudioPlayback_SoftMixer.pas
@@ -302,7 +302,7 @@ begin
Stop();
// reset and/or free data
-
+
Loop := false;
// TODO: use DecodeStream.Unref() instead of Free();
@@ -450,8 +450,8 @@ begin
mixer.RemoveStream(Self);
// rewind (note: DecodeStream might be closed already, but this is not a problem)
- if assigned(DecodeStream) then
- DecodeStream.Position := 0;
+// if assigned(DecodeStream) then
+// DecodeStream.Position := 0;
end;
function TGenericPlaybackStream.GetLoop(): boolean;
diff --git a/Game/Code/Classes/UMain.pas b/Game/Code/Classes/UMain.pas
index 9c867a3c..ea3da9ad 100644
--- a/Game/Code/Classes/UMain.pas
+++ b/Game/Code/Classes/UMain.pas
@@ -157,7 +157,13 @@ begin
//------------------------------
//StartUp - Create Classes and Load Files
//------------------------------
+
+ // Initialize SDL
+ // Without SDL_INIT_TIMER SDL_GetTicks() might return strange values
+ SDL_Init(SDL_INIT_VIDEO or SDL_INIT_TIMER);
+
USTime := TTime.Create;
+ VideoBGTimer := TRelativeTimer.Create;
// Commandline Parameter Parser
Params := TCMDParams.Create;
@@ -174,19 +180,12 @@ begin
InitializePaths;
Log.LogStatus('Load Language', 'Initialization');
Language := TLanguage.Create;
-
+
// Add Const Values:
Language.AddConst('US_VERSION', USDXVersionStr);
Log.BenchmarkEnd(1);
Log.LogBenchmark('Loading Language', 1);
- // SDL
- Log.BenchmarkStart(1);
- Log.LogStatus('Initialize SDL', 'Initialization');
- SDL_Init(SDL_INIT_VIDEO or SDL_INIT_TIMER);
- Log.BenchmarkEnd(1);
- Log.LogBenchmark('Initializing SDL', 1);
-
// SDL_ttf
Log.BenchmarkStart(1);
Log.LogStatus('Initialize SDL_ttf', 'Initialization');
@@ -223,6 +222,9 @@ begin
Log.BenchmarkEnd(1);
Log.LogBenchmark('Initializing Sound', 1);
+ // Lyrics-engine with media reference timer
+ LineState := TLineState.Create();
+
// Theme
Log.BenchmarkStart(1);
Log.LogStatus('Load Themes', 'Initialization');
@@ -370,6 +372,8 @@ end;
procedure MainLoop;
var
Delay: integer;
+const
+ MAX_FPS = 100;
begin
Delay := 0;
SDL_EnableKeyRepeat(125, 125);
@@ -394,7 +398,7 @@ begin
// delay
CountMidTime;
- Delay := Floor(1000 / 100 - 1000 * TimeMid);
+ Delay := Floor(1000 / MAX_FPS - 1000 * TimeMid);
if Delay >= 1 then
SDL_Delay(Delay); // dynamic, maximum is 100 fps
@@ -655,8 +659,6 @@ var
Done: real;
N: integer;
begin
- LineState.CurrentTime := LineState.CurrentTime + TimeSkip;
-
LineState.OldBeat := LineState.CurrentBeat;
LineState.MidBeat := GetMidBeat(LineState.CurrentTime - (CurrentSong.Gap{ + 90 I've forgotten for what it is}) / 1000); // new system with variable BPM in function
LineState.CurrentBeat := Floor(LineState.MidBeat);
diff --git a/Game/Code/Classes/UMusic.pas b/Game/Code/Classes/UMusic.pas
index 9c029acd..bad0aa86 100644
--- a/Game/Code/Classes/UMusic.pas
+++ b/Game/Code/Classes/UMusic.pas
@@ -9,6 +9,7 @@ interface
{$I switches.inc}
uses
+ UTime,
Classes;
type
@@ -35,7 +36,6 @@ type
end;
ALine = array of TLine; // (TODO: rename to TLineArray)
- // (TCzesci = TSentences) TCzesci changed to TLines because TSentences exist elseware in incompatible form
TLines = record
Current: integer; // for drawing of current line
High: integer;
@@ -46,31 +46,39 @@ type
Line: ALine;
end;
- // (TODO: rename TCzas to something like T(Line/Sentence)Time/TLinePosition/TLineState)
- // (Czas = time)
- TLineState = record // all that concerns the current frames
- OldBeat: integer; // previous discovered beat
- CurrentBeat: integer;
- MidBeat: real; // like CurrentBeat
+ TLineState = class // all that concerns the current frames
+ private
+ Timer: TRelativeTimer; // keeps track of the current time
+ public
+ OldBeat: integer; // previous discovered beat
+ CurrentBeat: integer;
+ MidBeat: real; // like CurrentBeat
+
+ // now we use this for super synchronization!
+ // only used when analyzing voice
+ OldBeatD: integer; // previous discovered beat
+ CurrentBeatD: integer;
+ MidBeatD: real; // like CurrentBeatD
+ FracBeatD: real; // fractional part of MidBeatD
- // now we use this for super synchronization!
- // only used when analyzing voice
- OldBeatD: integer; // previous discovered beat
- CurrentBeatD: integer;
- MidBeatD: real; // like CurrentBeatD
- FracBeatD: real; // fractional part of MidBeatD
+ // we use this for audible clicks
+ OldBeatC: integer; // previous discovered beat
+ CurrentBeatC: integer;
+ MidBeatC: real; // like CurrentBeatC
+ FracBeatC: real; // fractional part of MidBeatC
- // we use this for audible clicks
- OldBeatC: integer; // previous discovered beat
- CurrentBeatC: integer;
- MidBeatC: real; // like CurrentBeatC
- FracBeatC: real; // fractional part of MidBeatC
+ OldLine: integer; // previous displayed sentence
+ TotalTime: real; // total song time
- OldLine: integer; // previous displayed sentence
+ constructor Create();
+ procedure Pause();
+ procedure Resume();
+ function GetCurrentTime(): real;
+ procedure SetCurrentTime(Time: real);
- CurrentTime: real;
- TotalTime: real;
+ // current song time used as base-timer for lyrics etc.
+ property CurrentTime: real READ GetCurrentTime WRITE SetCurrentTime;
end;
@@ -656,6 +664,31 @@ begin
end;
end;
+constructor TLineState.Create();
+begin
+ Timer := TRelativeTimer.Create();
+end;
+
+procedure TLineState.Pause();
+begin
+ Timer.Pause();
+end;
+
+procedure TLineState.Resume();
+begin
+ Timer.Resume();
+end;
+
+procedure TLineState.SetCurrentTime(Time: real);
+begin
+ Timer.SetTime(Time);
+end;
+
+function TLineState.GetCurrentTime(): real;
+begin
+ Result := Timer.GetTime();
+end;
+
initialization
begin
diff --git a/Game/Code/Menu/UDisplay.pas b/Game/Code/Menu/UDisplay.pas
index 7d31e578..94a63ca9 100644
--- a/Game/Code/Menu/UDisplay.pas
+++ b/Game/Code/Menu/UDisplay.pas
@@ -165,7 +165,6 @@ begin
// if (Screens = 2) and (S = 2) then ScreenX := 1;
ScreenX := 0;
- if S = 2 then TimeSkip := 0 else;
glViewPort((S-1) * ScreenW div Screens, 0, ScreenW div Screens, ScreenH);
//popup hack
diff --git a/Game/Code/Menu/UMenu.pas b/Game/Code/Menu/UMenu.pas
index 7656c639..f33ae244 100644
--- a/Game/Code/Menu/UMenu.pas
+++ b/Game/Code/Menu/UMenu.pas
@@ -171,6 +171,7 @@ uses UCommon,
UGraphic,
UDisplay,
UCovers,
+ UTime,
USkins;
destructor TMenu.Destroy;
@@ -325,7 +326,10 @@ begin
if ( BackImg.TexNum = 0 ) then
begin
if VideoPlayback.Open( fFileName ) then
+ begin
+ VideoBGTimer.SetTime(0);
VideoPlayback.Play;
+ end;
end;
BackImg.W := 800;
@@ -740,7 +744,6 @@ var
PetX: integer;
PetY: integer;
begin
-
BackImg.ColR := 1;
BackImg.ColG := 1;
BackImg.ColB := 1;
@@ -748,34 +751,20 @@ begin
BackImg.TexY1 := 0;
BackImg.TexX2 := 1;
BackImg.TexY2 := 1;
+
if (BackImg.TexNum > 0) then
begin
- // does anyone know what these loops were for?
- {
- // draw texture with overlapping
- for PetY := 1 to BackH do
- for PetX := 1 to BackW do begin
- BackImg.X := (PetX-1)/BackW * 800; //640
- BackImg.Y := (PetY-1)/BackH * 600; //480
- DrawTexture(BackImg);
- end; // for PetX
- }
- {
- BackImg.X:=BackW;
- BackImg.Y:=BackW;
- }
BackImg.X := 0;
BackImg.Y := 0;
BackImg.Z := 0; // todo: eddie: to the opengl experts: please check this! On the mac z is not initialized???
BackImg.W := 800;
BackImg.H := 600;
DrawTexture(BackImg);
- end; // if
-
-
- //if assigned( VideoPlayback ) then
+ end
+ else if (VideoPlayback <> nil) then
begin
- VideoPlayback.GetFrame( now() );
+ VideoPlayback.GetFrame(VideoBGTimer.GetTime());
+ // FIXME: why do we draw on screen 2? Seems to be wrong.
VideoPlayback.DrawGL(2);
end;
@@ -1589,7 +1578,10 @@ begin
if fileexists( fFileName ) then
begin
if VideoPlayback.Open( fFileName ) then
+ begin
+ VideoBGTimer.SetTime(0);
VideoPlayback.Play;
+ end;
end;
end;
end;
diff --git a/Game/Code/Screens/UScreenSing.pas b/Game/Code/Screens/UScreenSing.pas
index 1b089eaf..c97bc691 100644
--- a/Game/Code/Screens/UScreenSing.pas
+++ b/Game/Code/Screens/UScreenSing.pas
@@ -31,7 +31,6 @@ type
TScreenSing = class(TMenu)
protected
paused: boolean; //Pause Mod
- PauseTime: Real;
NumEmptySentences: integer;
public
//TextTime: integer;
@@ -216,9 +215,10 @@ begin
if not paused then //enable Pause
begin
// pause Time
- PauseTime := LineState.CurrentTime;
Paused := true;
+ LineState.Pause();
+
// pause Music
AudioPlayback.Pause;
@@ -229,12 +229,12 @@ begin
end
else //disable Pause
begin
- LineState.CurrentTime := PauseTime; //Position of Notes
+ LineState.Resume();
// Position of Music
// FIXME: remove this and provide LineState.CurrentTime as sync-source instead
// so every stream can synch itself
- AudioPlayback.Position := PauseTime;
+ AudioPlayback.Position := LineState.CurrentTime;
// Play Music
AudioPlayback.Play;
@@ -528,7 +528,9 @@ begin
// CountSkipTimeSet;
LineState.CurrentTime := CurrentSong.Start;
LineState.TotalTime := AudioPlayback.Length;
- if (CurrentSong.Finish > 0) then LineState.TotalTime := CurrentSong.Finish / 1000;
+
+ if (CurrentSong.Finish > 0) then
+ LineState.TotalTime := CurrentSong.Finish / 1000;
LineState.OldBeat := -1;
for P := 0 to High(Player) do
ClearScores(P);