From 7403bb1fc38a74c25a636666681a42d663d27512 Mon Sep 17 00:00:00 2001 From: tobigun Date: Tue, 13 May 2008 18:45:37 +0000 Subject: - fixed video-background - fixed buggy SkipTime (using TRelativeTimer now) - TLineState is a class now. TLineState.CurrentTime is now automatically updated using TRelativeTimer git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1088 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudioDecoder_FFMpeg.pas | 84 ++++++++++++++++++++------ Game/Code/Classes/UAudioPlayback_SoftMixer.pas | 6 +- Game/Code/Classes/UMain.pas | 24 ++++---- Game/Code/Classes/UMusic.pas | 75 ++++++++++++++++------- 4 files changed, 134 insertions(+), 55 deletions(-) (limited to 'Game/Code/Classes') 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 -- cgit v1.2.3