diff options
Diffstat (limited to 'Game')
-rw-r--r-- | Game/Code/Classes/UAudioDecoder_FFMpeg.pas | 84 | ||||
-rw-r--r-- | Game/Code/Classes/UAudioPlayback_SoftMixer.pas | 6 | ||||
-rw-r--r-- | Game/Code/Classes/UMain.pas | 24 | ||||
-rw-r--r-- | Game/Code/Classes/UMusic.pas | 75 | ||||
-rw-r--r-- | Game/Code/Menu/UDisplay.pas | 1 | ||||
-rw-r--r-- | Game/Code/Menu/UMenu.pas | 32 | ||||
-rw-r--r-- | Game/Code/Screens/UScreenSing.pas | 12 |
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);
|