diff options
-rw-r--r-- | Medley/game/themes/Deluxe.ini | 18 | ||||
-rw-r--r-- | Medley/src/base/UDraw.pas | 9 | ||||
-rw-r--r-- | Medley/src/base/UNote.pas | 36 | ||||
-rw-r--r-- | Medley/src/base/USong.pas | 329 | ||||
-rw-r--r-- | Medley/src/base/USongs.pas | 19 | ||||
-rw-r--r-- | Medley/src/base/UThemes.pas | 16 | ||||
-rw-r--r-- | Medley/src/screens/UScreenScore.pas | 241 | ||||
-rw-r--r-- | Medley/src/screens/UScreenSing.pas | 399 | ||||
-rw-r--r-- | Medley/src/screens/UScreenSong.pas | 150 |
9 files changed, 1058 insertions, 159 deletions
diff --git a/Medley/game/themes/Deluxe.ini b/Medley/game/themes/Deluxe.ini index cf3ad368..d7ac8adb 100644 --- a/Medley/game/themes/Deluxe.ini +++ b/Medley/game/themes/Deluxe.ini @@ -991,6 +991,24 @@ Size = 18 Color = White Align = 1 +[SingSongNameStatic] +X = 5 +Y = 3 +W = 790 +H = 34 +Tex = Button +Color = White +Type = Transparen + +[SingSongNameText] +Text = should not see me +X = 400 +Y = 5 +Font = 1 +Size = 30 +Color = Black +Align = 1 + # O N E P L A Y E R M O D E # # # # # # # # # # # # # # # # # # # # #PlayerOne [SingP1Static] diff --git a/Medley/src/base/UDraw.pas b/Medley/src/base/UDraw.pas index 1783986f..8bb2c210 100644 --- a/Medley/src/base/UDraw.pas +++ b/Medley/src/base/UDraw.pas @@ -97,6 +97,7 @@ uses URecord, UScreenSing, UScreenSingModi, + USong, UTexture; procedure SingDrawBackground; @@ -1387,7 +1388,13 @@ begin if (CurLyricsTime > 0) and (LyricsState.TotalTime > 0) then begin - LyricsProgress := CurLyricsTime / LyricsState.TotalTime; + if ScreenSong.Mode <> smMedley then + LyricsProgress := CurLyricsTime / LyricsState.TotalTime + else + LyricsProgress := (CurLyricsTime - GetTimeFromBeat(CurrentSong.Medley.StartBeat) + + CurrentSong.Medley.FadeIn_time) / (GetTimeFromBeat(CurrentSong.Medley.EndBeat) + + CurrentSong.Medley.FadeOut_time - GetTimeFromBeat(CurrentSong.Medley.StartBeat) + + CurrentSong.Medley.FadeIn_time); glTexCoord2f((width * LyricsProgress) / 8, 0); glVertex2f(x + width * LyricsProgress, y); diff --git a/Medley/src/base/UNote.pas b/Medley/src/base/UNote.pas index 8e5b709a..bc91c892 100644 --- a/Medley/src/base/UNote.pas +++ b/Medley/src/base/UNote.pas @@ -88,13 +88,30 @@ type Note: array of TPlayerNote; end; + TStats = record + Player: array of TPlayer; + SongArtist: UTF8String; + SongTitle: UTF8String; + end; + + TMedleyPlaylist = record + Song: array of integer; + NumMedleySongs: integer; + CurrentMedleySong: integer; + ApplausePlayed: boolean; + Stats: array of TStats; + NumPlayer: integer; + end; + var // player and music info Player: array of TPlayer; PlayersPlay: integer; - + PlaylistMedley: TMedleyPlaylist; CurrentSong: TSong; + max_song_score_medley: integer; + max_song_line_bonus_medley: integer; const MAX_SONG_SCORE = 10000; // max. achievable points per song @@ -463,10 +480,19 @@ begin // half size notes patch NoteHit := true; - if (Ini.LineBonus > 0) then - MaxSongPoints := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS - else - MaxSongPoints := MAX_SONG_SCORE; + if ScreenSong.Mode <> smMedley then + begin + if (Ini.LineBonus > 0) then + MaxSongPoints := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS + else + MaxSongPoints := MAX_SONG_SCORE; + end else + begin + if (Ini.LineBonus > 0) then + MaxSongPoints := max_song_score_medley - max_song_line_bonus_medley + else + MaxSongPoints := max_song_score_medley; + end; // Note: ScoreValue is the sum of all note values of the song // (MaxSongPoints / ScoreValue) is the points that a player diff --git a/Medley/src/base/USong.pas b/Medley/src/base/USong.pas index c465f198..d4eb714d 100644 --- a/Medley/src/base/USong.pas +++ b/Medley/src/base/USong.pas @@ -64,7 +64,8 @@ uses type - TSingMode = ( smNormal, smPartyMode, smPlaylistRandom ); + TSingMode = ( smNormal, smPartyMode, smPlaylistRandom, smMedley ); + TMedleySource = ( msNone, msCalculated, msTag ); TBPM = record BPM: real; @@ -85,6 +86,16 @@ type Content: UTF8String; end; + TMedley = record + Source: TMedleySource; //source of the information + StartBeat: integer; //start beat of medley + EndBeat: integer; //end beat of medley + FadeIn: integer; //start beat of fadein + FadeOut: integer; //end beat of fadeout + FadeIn_time: real; //FadeIn-Time in seconds + FadeOut_time: real; //FadeIn-Time in seconds + end; + TSong = class private FileLineNo : integer; // line, which is read last, for error reporting @@ -157,6 +168,9 @@ type MultBPM : integer; LastError: AnsiString; + + Medley: TMedley; //infos for medley-mode and preview start + function GetErrorLineNo: integer; property ErrorLineNo: integer read GetErrorLineNo; @@ -168,6 +182,9 @@ type function Analyse(const ReadCustomTags: Boolean = false): boolean; function AnalyseXML(): boolean; procedure Clear(); + procedure FindRefrainStart; + procedure SetMedleyMode; + function ReadMedleyFile(MedleyFilePath: IPath): boolean; end; implementation @@ -178,7 +195,7 @@ uses UIni, UPathUtils, UMusic, //needed for Lines - UNote; //needed for Player + UNote; const DEFAULT_ENCODING = encAuto; @@ -461,6 +478,7 @@ begin Exit; end; + SetLength(Lines, 0); //just a fix.. for medley-mod SetLength(Lines, 2); for Count := 0 to High(Lines) do begin @@ -589,7 +607,6 @@ begin if (High(Lines[Count].Line) >= 0) then Lines[Count].Line[High(Lines[Count].Line)].LastLine := true; end; - Result := true; end; @@ -1292,6 +1309,7 @@ begin Creator := ''; Relative := false; + Medley.Source := msNone; end; function TSong.Analyse(const ReadCustomTags: Boolean): boolean; @@ -1310,7 +1328,10 @@ begin Self.clear; //Read Header - Result := Self.ReadTxTHeader(SongFile, ReadCustomTags) + Result := Self.ReadTxTHeader(SongFile, ReadCustomTags); + + //Load Song (for testing) + Result := Result and Self.LoadSong; finally SongFile.Free; end; @@ -1318,7 +1339,6 @@ end; function TSong.AnalyseXML(): boolean; - begin Result := false; @@ -1331,6 +1351,305 @@ begin //Read Header Result := self.ReadXMLHeader( FileName ); + //Load Song (for testing) + Result := Result and self.LoadXMLSong; + +end; + + +{* new procedure for preview + tries find out the beginning of a refrain *} +procedure TSong.FindRefrainStart(); +Type + TSeries = record + start: integer; //Start sentence of series + end_: integer; //End sentence of series + len: integer; //Length of sentence series + end; + +var + I, J, K, num_lines: integer; + sentences: array of UTF8String; + series: array of TSeries; + temp_series: TSeries; + max: integer; + +begin + if Medley.Source = msTag then + Exit; + + num_lines := Length(Lines[0].Line); + SetLength(sentences, num_lines); + + //build sentences array + for I := 0 to num_lines - 1 do + begin + sentences[I] := ''; + for J := 0 to Length(Lines[0].Line[I].Note) - 1 do + begin + sentences[I] := sentences[I] + Lines[0].Line[I].Note[J].Text; + end; + end; + + //find equal sentences series + SetLength(series, 0); + + for I := 0 to num_lines - 2 do + begin + for J := I+1 to num_lines - 1 do + begin + if sentences[I]=sentences[J] then + begin + temp_series.start := I; + temp_series.end_ := I; + + if (J+J-I-1>num_lines-1) then + max:=num_lines-1-J + else + max:=J-I-1; + + for K := 1 to max do + begin + if sentences[I+K]=sentences[J+K] then + temp_series.end_ := I+K + else + break; + end; + temp_series.len := temp_series.end_ - temp_series.start + 1; + SetLength(series, Length(series)+1); + series[Length(series)-1] := temp_series; + end; + end; + end; + + //search for longest sequence + if Length(series)>0 then + begin + max := 0; + for I := 0 to Length(series) - 1 do + begin + if series[I].len > series[max].len then + max := I; + end; + end; + + if (Length(series)>0) and (series[max].len > 3) then + begin + Medley.Source := msCalculated; + Medley.StartBeat := Lines[0].Line[series[max].start].Note[0].Start; + end else + Medley.Source := msNone; +end; + +//sets a song to medley-mod: +//converts all unneeded notes into freestyle +//updates score values +procedure TSong.SetMedleyMode; +var + pl, line, note: integer; + LF: TLineFragment; + start: integer; + end_: integer; +begin + start := self.Medley.StartBeat; + end_ := self.Medley.EndBeat; + + for pl := 0 to Length(Lines) - 1 do + begin + Lines[pl].ScoreValue := 0; + for line := 0 to Length(Lines[pl].Line) - 1 do + begin + Lines[pl].Line[line].TotalNotes := 0; + for note := 0 to Length(Lines[pl].Line[line].Note) - 1 do + begin + LF := Lines[pl].Line[line].Note[note]; + if LF.Start < start then //check start + Lines[pl].Line[line].Note[note].NoteType := ntFreestyle + else if LF.Start>= end_ then //check end + Lines[pl].Line[line].Note[note].NoteType := ntFreestyle + else + begin + //add this notes value ("notes length" * "notes scorefactor") to the current songs entire value + Inc(Lines[pl].ScoreValue, LF.Length * ScoreFactor[LF.NoteType]); + //and to the current lines entire value + Inc(Lines[pl].Line[line].TotalNotes, LF.Length * ScoreFactor[LF.NoteType]); + end; + end; + end; + end; +end; + +//reads the txtm +//TODO move this to ReadTXTHeader and implement the MEDLEY-TAGS in txt-file: +//conversion: START-> MEDLEY_START +// END-> MEDLEY_END +// FADE_IN -> MEDLEY_FADE_IN +// FADE_OUT-> MEDLEY_FADE_OUT +//TODO: write a tool to convert existing txtm +function TSong.ReadMedleyFile(MedleyFilePath: IPath): boolean; +const + DEFAULT_FADE_IN_TIME = 10; + DEFAULT_FADE_OUT_TIME = 4; +var + Line, Identifier: string; + Value: string; + SepPos: integer; // separator position + Done: byte; // bit-vector of mandatory fields + EncFile: IPath; // encoded filename + FullFileName: string; + LineNo: integer; + MedleyFile: TTextFileStream; + found_fadeIn, found_fadeOut: boolean; + +begin + Result := true; + Done := 0; + + MedleyFile := TMemTextFileStream.Create(MedleyFilePath, fmOpenRead); + FullFileName := MedleyFilePath.ToNative; + + //set standard values + found_fadeIn := false; + found_fadeOut := false; + + //Read first Line + MedleyFile.ReadLine(Line); + if (Length(Line) <= 0) then + begin + Log.LogError('File starts with empty line: ' + FullFileName, + 'TSong.ReadMedleyFile'); + Result := false; + Exit; + end; + + // check if file begins with a UTF-8 BOM, if so set encoding to UTF-8 + if (CheckReplaceUTF8BOM(Line)) then + Encoding := encUTF8; + + //Read Lines while Line starts with # or its empty + while (Length(Line) = 0) or (Line[1] = '#') do + begin + //Increase Line Number + Inc (LineNo); + SepPos := Pos(':', Line); + + //Line has no Seperator, ignore non header field + if (SepPos = 0) then + begin + // read next line + if (not MedleyFile.ReadLine(Line)) then + begin + Result := false; + Log.LogError('File incomplete or not Ultrastar txtm (A): ' + FullFileName); + Break; + end; + Continue; + end; + + //Read Identifier and Value + Identifier := UpperCase(Trim(Copy(Line, 2, SepPos - 2))); //Uppercase is for Case Insensitive Checks + Value := Trim(Copy(Line, SepPos + 1, Length(Line) - SepPos)); + + //Check the Identifier (If Value is given) + if (Length(Value) = 0) then + begin + Log.LogWarn('Empty field "'+Identifier+'" in file ' + FullFileName, + 'TSong.ReadMedleyFile'); + end + else + begin + + //----------- + //Required Attributes + //----------- + + if (Identifier = 'START') then + begin + if TryStrtoInt(Value, self.Medley.StartBeat) then + //Add START flag to Done + Done := Done or 1; + end + + else if (Identifier = 'END') then + begin + if TryStrtoInt(Value, self.Medley.EndBeat) then + //Add END Flag to Done + Done := Done or 2; + end + + //--------- + //Additional Header Information + //--------- + + else if (Identifier = 'FADE_IN') then + begin + if TryStrtoInt(Value, self.Medley.FadeIn) then + found_fadeIn := true; + end + + else if (Identifier = 'FADE_OUT') then + begin + if TryStrtoInt(Value, self.Medley.FadeOut) then + found_fadeOut := true; + end + end; // End check for non-empty Value + + // read next line + if (not MedleyFile.ReadLine(Line)) then + begin + Result := false; + Log.LogError('File incomplete or not Ultrastar txtm (A): ' + FullFileName); + Break; + end; + end; // while + + //Check if all Required Values are given + if (Done <> 3) then + begin + Result := false; + if (Done and 2) = 0 then //No End Flag + Log.LogError('END tag missing: ' + FullFileName) + else if (Done and 1) = 0 then //No Start Flag + Log.LogError('START tag missing: ' + FullFileName) + else //unknown Error + Log.LogError('File incomplete or not Ultrastar txtm (B - '+ inttostr(Done) +'): ' + FullFileName); + + Self.Medley.Source := msNone; + end else if self.Medley.StartBeat>=self.Medley.EndBeat then + begin + Log.LogError('Failed to load MEDLEY-TAGS (Start>=End): ' + FullFileName); + self.Medley.Source := msNone; + Result := false; + end else if found_fadeIn and (self.Medley.FadeIn>=self.Medley.StartBeat) then + begin + Log.LogError('Failed to load MEDLEY-TAGS (FadeIn>=Start): ' + FullFileName); + self.Medley.Source := msNone; + Result := false; + end else if found_fadeOut and (self.Medley.EndBeat>=self.Medley.FadeOut) then + begin + Log.LogError('Failed to load MEDLEY-TAGS (End>=FadeOut): ' + FullFileName); + self.Medley.Source := msNone; + Result := false; + end else + begin + self.Medley.Source := msTag; + CurrentSong := self; + if not found_fadeIn then //set FadeIn if not defined + begin // TODO: what if FadeIn < song start? + self.Medley.FadeIn := self.Medley.StartBeat - round(GetMidBeat(DEFAULT_FADE_IN_TIME)); + end; + if not found_fadeOut then //set FadeOut if not defined + begin // TODO: what if FadeOut > song end? + self.Medley.FadeOut := self.Medley.EndBeat + round(GetMidBeat(DEFAULT_FADE_OUT_TIME)); + end; + + //calculate fade time + + self.Medley.FadeIn_time := GetTimeFromBeat(CurrentSong.Medley.StartBeat) - + GetTimeFromBeat(CurrentSong.Medley.FadeIn); + self.Medley.FadeOut_time := GetTimeFromBeat(CurrentSong.Medley.FadeOut) - + GetTimeFromBeat(CurrentSong.Medley.EndBeat); + end; end; end. diff --git a/Medley/src/base/USongs.pas b/Medley/src/base/USongs.pas index baeec13a..af7f7a16 100644 --- a/Medley/src/base/USongs.pas +++ b/Medley/src/base/USongs.pas @@ -312,18 +312,33 @@ var Files: TPathDynArray; Song: TSong; Extension: IPath; + MedleyFiles: TPathDynArray; + MedleyExtension: IPath; begin SetLength(Files, 0); + Extension := Path('.txt'); + MedleyExtension := Path('.txtm'); FindFilesByExtension(Dir, Extension, true, Files); + for I := 0 to High(Files) do begin Song := TSong.Create(Files[I]); if Song.Analyse then - SongList.Add(Song) - else + begin + //medley support... TODO: move it (see USong...) + SetLength(MedleyFiles, 0); + FindFilesByExtension(Files[I].GetPath, MedleyExtension, true, MedleyFiles); + + if Length(MedleyFiles)>0 then + begin + Song.ReadMedleyFile(MedleyFiles[0]); + end; + + SongList.Add(Song); + end else begin Log.LogError('AnalyseFile failed for "' + Files[I].ToNative + '".'); FreeAndNil(Song); diff --git a/Medley/src/base/UThemes.pas b/Medley/src/base/UThemes.pas index 4322815e..6ffeb3b1 100644 --- a/Medley/src/base/UThemes.pas +++ b/Medley/src/base/UThemes.pas @@ -306,6 +306,9 @@ type end; TThemeSing = class(TThemeBasic) + //Show actual SongName + StaticSongName : TThemeStatic; + TextSongName : TThemeText; //TimeBar mod StaticTimeProgress: TThemeStatic; @@ -358,7 +361,7 @@ type LineBonusText: array [0..8] of UTF8String; //Pause Popup - PausePopUp: TThemeStatic; + PausePopUp: TThemeStatic; end; TThemeLyricBar = record @@ -1051,10 +1054,13 @@ begin // Sing ThemeLoadBasic(Sing, 'Sing'); - //TimeBar mod - ThemeLoadStatic(Sing.StaticTimeProgress, 'SingTimeProgress'); - ThemeLoadText(Sing.TextTimeText, 'SingTimeText'); - //eoa TimeBar mod + ThemeLoadStatic(Sing.StaticSongName, 'SingSongNameStatic'); + ThemeLoadText(Sing.TextSongName, 'SingSongNameText'); + + //TimeBar mod + ThemeLoadStatic(Sing.StaticTimeProgress, 'SingTimeProgress'); + ThemeLoadText(Sing.TextTimeText, 'SingTimeText'); + //eoa TimeBar mod //moveable singbar mod ThemeLoadStatic(Sing.StaticP1SingBar, 'SingP1SingBar'); diff --git a/Medley/src/screens/UScreenScore.pas b/Medley/src/screens/UScreenScore.pas index ce1b11e5..5a50a3dc 100644 --- a/Medley/src/screens/UScreenScore.pas +++ b/Medley/src/screens/UScreenScore.pas @@ -39,6 +39,7 @@ uses SysUtils, UDisplay, UMusic, + USong, USongs, UThemes, gl, @@ -74,19 +75,30 @@ type BarGolden_ActualHeight: real; end; + TPlayerScoreData = record + Data: array[1..6] of TPlayerScoreScreenData; + end; + TPlayerScoreRatingPics = record // a fine array of the rating pictures RateEaseStep: integer; RateEaseValue: real; end; + TPLayerScorePics = record + Data: array[1..6] of TPlayerScoreRatingPics; + end; + TScreenScore = class(TMenu) private BarTime: cardinal; ArrayStartModifier: integer; public + //TeamInfo: TTeamInfo; aPlayerScoreScreenTextures: array[1..6] of TPlayerScoreScreenTexture; - aPlayerScoreScreenDatas: array[1..6] of TPlayerScoreScreenData; - aPlayerScoreScreenRatings: array[1..6] of TPlayerScoreRatingPics; + aPlayerScoreScreenDatas: array of TPlayerScoreData; + aPlayerScoreScreenRatings: array of TPlayerScorePics; + + ActualRound: integer; BarScore_EaseOut_Step: real; BarPhrase_EaseOut_Step: real; @@ -133,6 +145,7 @@ type procedure OnShow; override; procedure OnShowFinish; override; function Draw: boolean; override; + procedure RefreshTexts; procedure FillPlayer(Item, P: integer); procedure EaseBarIn(PlayerNumber: integer; BarType: string); @@ -190,6 +203,22 @@ begin begin Display.SaveScreenShot; end; + SDLK_RIGHT: + begin + if ActualRound<Length(PlaylistMedley.Stats)-1 then + begin + inc(ActualRound); + RefreshTexts; + end; + end; + SDLK_LEFT: + begin + if ActualRound>0 then + begin + dec(ActualRound); + RefreshTexts; + end; + end; end; end; end; @@ -203,6 +232,37 @@ begin end; end; +procedure TScreenScore.RefreshTexts; +begin + if (ActualRound < Length(PlaylistMedley.Stats)-1) then + begin + Text[TextArtist].Text := IntToStr(ActualRound+1) + '/' + + IntToStr(Length(PlaylistMedley.Stats)-1) + ': ' + + PlaylistMedley.Stats[ActualRound].SongArtist; + Text[TextTitle].Text := PlaylistMedley.Stats[ActualRound].SongTitle; + Text[TextTitle].Visible := true; + Text[TextArtistTitle].Text := IntToStr(ActualRound+1) + '/' + + IntToStr(Length(PlaylistMedley.Stats)-1) + ': ' + + PlaylistMedley.Stats[ActualRound].SongArtist + + ' - ' + PlaylistMedley.Stats[ActualRound].SongTitle; + end else + begin + if (ScreenSong.Mode = smMedley) then + begin + Text[TextArtist].Text := Language.Translate('SING_TOTAL'); + Text[TextTitle].Visible := false; + Text[TextArtistTitle].Text := Language.Translate('SING_TOTAL'); + end else + begin + Text[TextArtist].Text := PlaylistMedley.Stats[ActualRound].SongArtist; + Text[TextTitle].Text := PlaylistMedley.Stats[ActualRound].SongTitle; + Text[TextTitle].Visible := true; + Text[TextArtistTitle].Text := PlaylistMedley.Stats[ActualRound].SongArtist + ' - ' + + PlaylistMedley.Stats[ActualRound].SongTitle; + end; + end; +end; + constructor TScreenScore.Create; var Player: integer; @@ -293,20 +353,21 @@ begin else ArrayStartModifier := 0; //this should never happen end; + ActualRound:=0; + SetLength(aPlayerScoreScreenDatas, Length(PlaylistMedley.Stats)); + SetLength(aPlayerScoreScreenRatings, Length(PlaylistMedley.Stats)); - for P := 1 to PlayersPlay do + for I := 0 to Length(PlaylistMedley.Stats) - 1 do begin - // data - aPlayerScoreScreenDatas[P].Bar_Y := Theme.Score.StaticBackLevel[P + ArrayStartModifier].Y; - - // ratings - aPlayerScoreScreenRatings[P].RateEaseStep := 1; - aPlayerScoreScreenRatings[P].RateEaseValue := 20; + for P := 1 to PlayersPlay do + begin + aPlayerScoreScreenDatas[I].Data[P].Bar_Y := + Theme.Score.StaticBackLevel[P + ArrayStartModifier].Y; + aPlayerScoreScreenRatings[I].Data[P].RateEaseStep := 1; + aPlayerScoreScreenRatings[I].Data[P].RateEaseValue := 20; + end; end; - - Text[TextArtist].Text := CurrentSong.Artist; - Text[TextTitle].Text := CurrentSong.Title; - Text[TextArtistTitle].Text := CurrentSong.Artist + ' - ' + CurrentSong.Title; + RefreshTexts; // set visibility case PlayersPlay of @@ -405,18 +466,6 @@ var PStart: integer; PHigh: integer; begin -{* - player[0].ScoreInt := 7000; - player[0].ScoreLineInt := 2000; - player[0].ScoreGoldenInt := 1000; - player[0].ScoreTotalInt := 10000; - - player[1].ScoreInt := 2500; - player[1].ScoreLineInt := 1100; - player[1].ScoreGoldenInt := 900; - player[1].ScoreTotalInt := 4500; -*} - //Draw the Background DrawBG; @@ -548,7 +597,8 @@ begin Text[TextNotesScore[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); // total score - Text[TextTotalScore[ThemeIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber] + TextPhrase_ActualValue[PlayerNumber] + TextGolden_ActualValue[PlayerNumber]); + Text[TextTotalScore[ThemeIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber] + + TextPhrase_ActualValue[PlayerNumber] + TextGolden_ActualValue[PlayerNumber]); Text[TextTotalScore[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); Text[TextTotal[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); @@ -562,9 +612,13 @@ begin end; procedure TScreenScore.ShowRating(PlayerNumber: integer); +const + rate_factor: array[0..7] of real = (2.0, 4.0, 5.0, 6.0, 7.5, 8.5, 9.0, 10.0); var Rating: integer; ThemeIndex: integer; + rate_max: array[0..7] of integer; + max, I: integer; begin // We have to do this here because we use the same Theme Object @@ -575,55 +629,57 @@ begin 6: ThemeIndex := ((PlayerNumber-1) mod 3) + 1 + ArrayStartModifier; end; - case (Player[PlayerNumber-1].ScoreTotalInt) of - 0..2009: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_TONE_DEAF'); - Rating := 0; - end; - 2010..4009: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_AMATEUR'); - Rating := 1; - end; - 4010..5009: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_WANNABE'); - Rating := 2; - end; - 5010..6009: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_HOPEFUL'); - Rating := 3; - end; - 6010..7509: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_RISING_STAR'); - Rating := 4; - end; - 7510..8509: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_LEAD_SINGER'); - Rating := 5; - end; - 8510..9009: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_SUPERSTAR'); - Rating := 6; - end; - 9010..10000: - begin - Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_ULTRASTAR'); - Rating := 7; - end; + //build rating scores + if ActualRound = Length(PlaylistMedley.Stats)-1 then + max := MAX_SONG_SCORE else + max := max_song_score_medley; + + for I := 0 to 6 do + rate_max[I] := round(max/10*rate_factor[I])+9; + + //fix 7 + rate_max[7] := 10000; + + if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[0] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_TONE_DEAF'); + Rating := 0; + end else if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[1] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_AMATEUR'); + Rating := 1; + end else if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[2] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_WANNABE'); + Rating := 2; + end else if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[3] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_HOPEFUL'); + Rating := 3; + end else if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[4] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_RISING_STAR'); + Rating := 4; + end else if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[5] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_LEAD_SINGER'); + Rating := 5; + end else if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[6] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_SUPERSTAR'); + Rating := 6; + end else if PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreTotalInt<=rate_max[7] then + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_ULTRASTAR'); + Rating := 7; + end else Rating := 0; // Cheata :P - end; //todo: this could break if the width is not given, for instance when there's a skin with no picture for ratings - if ( Theme.Score.StaticRatings[ThemeIndex].W > 0 ) and ( aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue > 0 ) then + if ( Theme.Score.StaticRatings[ThemeIndex].W > 0 ) and ( aPlayerScoreScreenRatings[ActualRound].Data[PlayerNumber].RateEaseValue > 0 ) then begin - Text[TextScore[ThemeIndex]].Alpha := aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue / Theme.Score.StaticRatings[ThemeIndex].W; + Text[TextScore[ThemeIndex]].Alpha := aPlayerScoreScreenRatings[ActualRound].Data[PlayerNumber].RateEaseValue / Theme.Score.StaticRatings[ThemeIndex].W; end; // end todo @@ -642,7 +698,7 @@ begin PosX := Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].X + (Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].W * 0.5); PosY := Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].Y + (Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].H * 0.5); ; - Width := aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue/2; + Width := aPlayerScoreScreenRatings[ActualRound].Data[PlayerNumber].RateEaseValue/2; glBindTexture(GL_TEXTURE_2D, Tex_Score_Ratings[Rating].TexNum); @@ -669,7 +725,7 @@ var RaiseStep, MaxVal: real; EaseOut_Step: integer; begin - EaseOut_Step := aPlayerScoreScreenRatings[PlayerNumber].RateEaseStep; + EaseOut_Step := aPlayerScoreScreenRatings[ActualRound].Data[PlayerNumber].RateEaseStep; MaxVal := Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].W; RaiseStep := EaseOut_Step; @@ -688,8 +744,8 @@ begin s := p/(2*PI) * arcsin (1); ReturnValue := MaxVal * power(2,-5 * RaiseStep) * sin( (RaiseStep * MaxVal - s) * (2 * PI) / p) + MaxVal; - inc(aPlayerScoreScreenRatings[PlayerNumber].RateEaseStep); - aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue := ReturnValue; + inc(aPlayerScoreScreenRatings[ActualRound].Data[PlayerNumber].RateEaseStep); + aPlayerScoreScreenRatings[ActualRound].Data[PlayerNumber].RateEaseValue := ReturnValue; end; Result := ReturnValue; @@ -716,21 +772,21 @@ begin // EaseOut_Step is the actual step in the raising process, like the 20iest step of EaseOut_MaxSteps if (BarType = 'Note') then begin - Score := Player[PlayerNumber - 1].ScoreInt; + Score := PlaylistMedley.Stats[ActualRound].Player[PlayerNumber - 1].ScoreInt; RaiseStep := BarScore_EaseOut_Step; BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y + MaxHeight; end else if (BarType = 'Line') then begin - Score := Player[PlayerNumber - 1].ScoreLineInt; + Score := PlaylistMedley.Stats[ActualRound].Player[PlayerNumber - 1].ScoreLineInt; RaiseStep := BarPhrase_EaseOut_Step; - BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight + MaxHeight; + BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y - aPlayerScoreScreenDatas[ActualRound].Data[PlayerNumber].BarScore_ActualHeight + MaxHeight; end else if (BarType = 'Golden') then begin - Score := Player[PlayerNumber - 1].ScoreGoldenInt; + Score := PlaylistMedley.Stats[ActualRound].Player[PlayerNumber - 1].ScoreGoldenInt; RaiseStep := BarGolden_EaseOut_Step; - BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight - aPlayerScoreScreenDatas[PlayerNumber].BarLine_ActualHeight + MaxHeight; + BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y - aPlayerScoreScreenDatas[ActualRound].Data[PlayerNumber].BarScore_ActualHeight - aPlayerScoreScreenDatas[ActualRound].Data[PlayerNumber].BarLine_ActualHeight + MaxHeight; end else begin @@ -739,9 +795,12 @@ begin end; // the height dependend of the score - Height2Reach := (Score / MAX_SONG_SCORE) * MaxHeight; + if ActualRound=Length(PlaylistMedley.Stats)-1 then + Height2Reach := (Score / MAX_SONG_SCORE) * MaxHeight + else + Height2Reach := (Score / max_song_score_medley) * MaxHeight; - if (aPlayerScoreScreenDatas[PlayerNumber].Bar_Actual_Height < Height2Reach) then + if (aPlayerScoreScreenDatas[ActualRound].Data[PlayerNumber].Bar_Actual_Height < Height2Reach) then begin // Check http://proto.layer51.com/d.aspx?f=400 for more info on easing functions // Calculate the actual step according to the maxsteps @@ -761,11 +820,11 @@ begin DrawBar(BarType, PlayerNumber, BarStartPosY, NewHeight); if (BarType = 'Note') then - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight := NewHeight + aPlayerScoreScreenDatas[ActualRound].Data[PlayerNumber].BarScore_ActualHeight := NewHeight else if (BarType = 'Line') then - aPlayerScoreScreenDatas[PlayerNumber].BarLine_ActualHeight := NewHeight + aPlayerScoreScreenDatas[ActualRound].Data[PlayerNumber].BarLine_ActualHeight := NewHeight else if (BarType = 'Golden') then - aPlayerScoreScreenDatas[PlayerNumber].BarGolden_ActualHeight := NewHeight; + aPlayerScoreScreenDatas[ActualRound].Data[PlayerNumber].BarGolden_ActualHeight := NewHeight; end; procedure TscreenScore.DrawBar(BarType: string; PlayerNumber: integer; BarStartPosY: single; NewHeight: real); @@ -839,19 +898,19 @@ begin begin EaseOut_Step := BarScore_EaseOut_Step; ActualScoreValue := TextScore_ActualValue[PlayerNumber]; - ScoreReached := Player[PlayerNumber-1].ScoreInt; + ScoreReached := PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreInt; end; if (ScoreType = 'Line') then begin EaseOut_Step := BarPhrase_EaseOut_Step; ActualScoreValue := TextPhrase_ActualValue[PlayerNumber]; - ScoreReached := Player[PlayerNumber-1].ScoreLineInt; + ScoreReached := PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreLineInt; end; if (ScoreType = 'Golden') then begin EaseOut_Step := BarGolden_EaseOut_Step; ActualScoreValue := TextGolden_ActualValue[PlayerNumber]; - ScoreReached := Player[PlayerNumber-1].ScoreGoldenInt; + ScoreReached := PlaylistMedley.Stats[ActualRound].Player[PlayerNumber-1].ScoreGoldenInt; end; // EaseOut_Step is the actual step in the raising process, like the 20iest step of EaseOut_MaxSteps @@ -893,7 +952,7 @@ var begin Text[TextName[Item]].Text := Ini.Name[P]; - S := IntToStr((Round(Player[P].Score) div 10) * 10); + S := IntToStr((Round(PlaylistMedley.Stats[ActualRound].Player[P].Score) div 10) * 10); while (Length(S)<4) do S := '0' + S; Text[TextNotesScore[Item]].Text := S; @@ -903,17 +962,17 @@ begin //fixed: line bonus and golden notes don't show up, // another bug: total score was shown without added golden-, linebonus - S := IntToStr(Player[P].ScoreTotalInt); + S := IntToStr(PlaylistMedley.Stats[ActualRound].Player[P].ScoreTotalInt); while (Length(S)<5) do S := '0' + S; Text[TextTotalScore[Item]].Text := S; - S := IntToStr(Player[P].ScoreLineInt); + S := IntToStr(PlaylistMedley.Stats[ActualRound].Player[P].ScoreLineInt); while (Length(S)<4) do S := '0' + S; Text[TextLineBonusScore[Item]].Text := S; - S := IntToStr(Player[P].ScoreGoldenInt); + S := IntToStr(PlaylistMedley.Stats[ActualRound].Player[P].ScoreGoldenInt); while (Length(S)<4) do S := '0' + S; Text[TextGoldenNotesScore[Item]].Text := S; diff --git a/Medley/src/screens/UScreenSing.pas b/Medley/src/screens/UScreenSing.pas index 342abac1..1bc16754 100644 --- a/Medley/src/screens/UScreenSing.pas +++ b/Medley/src/screens/UScreenSing.pas @@ -46,10 +46,12 @@ uses UMenu, UMusic, USingScores, + USong, USongs, UTexture, UThemes, UPath, + UPathUtils, UTime; type @@ -95,6 +97,11 @@ type FadeOut: boolean; Lyrics: TLyricEngine; + SongNameStatic: integer; + SongNameText: integer; + + ApplauseSounds: array of TAudioPlaybackStream; + // score manager: Scores: TSingScores; @@ -112,6 +119,8 @@ type function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override; function Draw: boolean; override; + procedure LoadNextSong; + procedure UpdateMedleyStats(medley_end: boolean); procedure Finish; virtual; procedure Pause; // toggle pause @@ -130,7 +139,6 @@ uses ULanguage, UNote, URecord, - USong, UDisplay, UUnicodeUtils; @@ -149,7 +157,14 @@ begin begin // when not ask before exit then finish now if (Ini.AskbeforeDel <> 1) then - Finish + begin + if ScreenSong.Mode=smMedley then + PlaylistMedley.CurrentMedleySong:=PlaylistMedley.NumMedleySongs+1; + Finish; + AudioPlayback.PlaySound(SoundLib.Back); + FadeOut := true; + FadeTo(@ScreenScore); + end // else just pause and let the popup make the work else if not Paused then Pause; @@ -185,9 +200,11 @@ begin begin // record sound hack: //Sound[0].BufferLong - + if ScreenSong.Mode=smMedley then + PlaylistMedley.CurrentMedleySong:=PlaylistMedley.NumMedleySongs+1; Finish; AudioPlayback.PlaySound(SoundLib.Back); + FadeOut := true; FadeTo(@ScreenScore); end; @@ -307,11 +324,18 @@ begin // <note> pausepopup is not visibile at the beginning </note> Static[StaticPausePopup].Visible := false; + SongNameStatic := AddStatic(Theme.Sing.StaticSongName); + SongNameText := AddText(Theme.Sing.TextSongName); + Lyrics := TLyricEngine.Create( Theme.LyricBar.UpperX, Theme.LyricBar.UpperY, Theme.LyricBar.UpperW, Theme.LyricBar.UpperH, Theme.LyricBar.LowerX, Theme.LyricBar.LowerY, Theme.LyricBar.LowerW, Theme.LyricBar.LowerH); LyricsSync := TLyricsSyncSource.Create(); + + SetLength(ApplauseSounds, 1); + FreeAndNil(ApplauseSounds[0]); + ApplauseSounds[0] := AudioPlayback.OpenSound(SoundPath.Append('Applause.mp3')); end; procedure TScreenSing.OnShow; @@ -334,6 +358,19 @@ begin //the song was sung to the end SungToEnd := false; + //Reset Player Medley stats + if ScreenSong.Mode = smMedley then + begin + PlaylistMedley.CurrentMedleySong:=1; + PlaylistMedley.ApplausePlayed := false; + + //max_song_score_medley := round(MAX_SONG_SCORE / NumMedleySongs); + //max_song_line_bonus_medley := round(MAX_SONG_LINE_BONUS / NumMedleySongs); + PlaylistMedley.NumPlayer := PlayersPlay; + SetLength(PlaylistMedley.Stats, 0); + max_song_score_medley := round(MAX_SONG_SCORE / PlaylistMedley.NumMedleySongs); + max_song_line_bonus_medley := round(MAX_SONG_LINE_BONUS / PlaylistMedley.NumMedleySongs); + end; // reset video playback engine, to play video clip ... fCurrentVideoPlaybackEngine := VideoPlayback; @@ -425,10 +462,43 @@ begin Static[StaticP3R].Visible := V3R; Text[TextP3R].Visible := V3R; + if ScreenSong.Mode = smMedley then + begin + Static[SongNameStatic].Visible := true; + Text[SongNameText].Visible := true; + end else + begin + Static[SongNameStatic].Visible := false; + Text[SongNameText].Visible := false; + end; + + LoadNextSong; + + Log.LogStatus('End', 'OnShow'); +end; + +procedure TScreenSing.LoadNextSong; +var + Index: integer; + VideoFile, BgFile: IPath; + success: boolean; + +begin // FIXME: sets path and filename to '' + //AudioPlayback.Stop(); ResetSingTemp; - - CurrentSong := CatSongs.Song[CatSongs.Selected]; + + if ScreenSong.Mode <> smMedley then + CurrentSong := CatSongs.Song[CatSongs.Selected] + else + begin + CurrentSong := CatSongs.Song[PlaylistMedley.Song[PlaylistMedley.CurrentMedleySong-1]]; + {AudioPlayback.Open(CurrentSong[CatSongsMedley.Selected].Path.Append(CatSongsMedley.Song[CatSongsMedley.Selected].Mp3)); + CurrentSong := CatSongsMedley.Song[CatSongsMedley.Selected]; + Text[SongNameText].Text := 'Medley ' + IntToStr(CurrentMedleySong)+'/'+ + IntToStr(NumMedleySongs)+': '+ + CurrentSong.Artist+' - '+CurrentSong.Title;} + end; // FIXME: bad style, put the try-except into loadsong() and not here try @@ -445,6 +515,7 @@ begin begin // error loading song -> go back to song screen and show some error message FadeTo(@ScreenSong); + // select new song in party mode if ScreenSong.Mode = smPartyMode then ScreenSong.SelectRandomSong(); @@ -453,10 +524,17 @@ begin else ScreenPopupError.ShowPopup(Language.Translate('ERROR_CORRUPT_SONG')); // FIXME: do we need this? - CurrentSong.Path := CatSongs.Song[CatSongs.Selected].Path; + //CurrentSong.Path := CatSongs.Song[CatSongs.Selected].Path; Exit; end; + if ScreenSong.Mode = smMedley then + begin + CurrentSong.SetMedleyMode; + Text[SongNameText].Text := IntToStr(PlaylistMedley.CurrentMedleySong) + + '/' + IntToStr(PlaylistMedley.NumMedleySongs) + ': ' + + CurrentSong.Artist + ' - ' + CurrentSong.Title; + end; // reset video playback engine, to play video clip ... fCurrentVideoPlaybackEngine.Close; fCurrentVideoPlaybackEngine := VideoPlayback; @@ -484,7 +562,12 @@ begin begin fShowVisualization := false; fCurrentVideoPlaybackEngine := VideoPlayback; - fCurrentVideoPlaybackEngine.Position := CurrentSong.VideoGAP + CurrentSong.Start; + if ScreenSong.Mode <> smMedley then + fCurrentVideoPlaybackEngine.Position := CurrentSong.VideoGAP + CurrentSong.Start + else + fCurrentVideoPlaybackEngine.Position := CurrentSong.VideoGAP + + GetTimeFromBeat(CurrentSong.Medley.StartBeat) - CurrentSong.Medley.FadeIn_time + + CurrentSong.Start; fCurrentVideoPlaybackEngine.Play; VideoLoaded := true; end; @@ -534,17 +617,34 @@ begin // prepare lyrics timer LyricsState.Reset(); - LyricsState.SetCurrentTime(CurrentSong.Start); - LyricsState.StartTime := CurrentSong.Gap; - if (CurrentSong.Finish > 0) then - LyricsState.TotalTime := CurrentSong.Finish / 1000 - else - LyricsState.TotalTime := AudioPlayback.Length; - LyricsState.UpdateBeats(); + if ScreenSong.Mode <> smMedley then + begin + LyricsState.SetCurrentTime(CurrentSong.Start); //in seconds + LyricsState.StartTime := CurrentSong.Gap; //in milliseconds + if (CurrentSong.Finish > 0) then + LyricsState.TotalTime := CurrentSong.Finish / 1000 //in seconds + else + LyricsState.TotalTime := AudioPlayback.Length; + LyricsState.UpdateBeats(); - // prepare music - AudioPlayback.Stop(); - AudioPlayback.Position := CurrentSong.Start; + // prepare music + AudioPlayback.Stop(); + AudioPlayback.Position := CurrentSong.Start; + end else + begin + LyricsState.SetCurrentTime(GetTimeFromBeat(CurrentSong.Medley.StartBeat) - CurrentSong.Medley.FadeIn_time); + LyricsState.StartTime := CurrentSong.Gap; + if (CurrentSong.Finish > 0) then + LyricsState.TotalTime := CurrentSong.Finish / 1000 //in seconds + else + LyricsState.TotalTime := AudioPlayback.Length; + LyricsState.UpdateBeats(); + + // prepare music + AudioPlayback.Stop(); + AudioPlayback.Open(CurrentSong.Path.Append(CurrentSong.Mp3)); + AudioPlayback.Position := GetTimeFromBeat(CurrentSong.Medley.StartBeat) - CurrentSong.Medley.FadeIn_time; + end; // synchronize music to the lyrics AudioPlayback.SetSyncSource(LyricsSync); @@ -572,7 +672,7 @@ begin // main text Lyrics.Clear(CurrentSong.BPM[0].BPM, CurrentSong.Resolution); - + // set custom options case Ini.LyricsFont of 0: // normal fonts @@ -615,42 +715,82 @@ begin end; end; // case - // initialize lyrics by filling its queue - while (not Lyrics.IsQueueFull) and + if ScreenSong.Mode <> smMedley then + begin + // initialize lyrics by filling its queue + while (not Lyrics.IsQueueFull) and (Lyrics.LineCounter <= High(Lines[0].Line)) do + begin + Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]); + end; + + // deactivate pause + Paused := false; + + // kill all stars not killed yet (goldenstarstwinkle mod) + GoldenRec.SentenceChange; + + // set position of line bonus - line bonus end + // set number of empty sentences for line bonus + NumEmptySentences := 0; + for Index := Low(Lines[0].Line) to High(Lines[0].Line) do + if Lines[0].Line[Index].TotalNotes = 0 then + Inc(NumEmptySentences); + end else begin - Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]); + // initialize lyrics by filling its queue + while (not Lyrics.IsQueueFull) and + (Lyrics.LineCounter <= High(Lines[0].Line)) do + begin + Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]); + end; + + // deactivate pause + Paused := false; + + // kill all stars not killed yet (goldenstarstwinkle mod) + GoldenRec.SentenceChange; + + // set position of line bonus - line bonus end + // set number of empty sentences for line bonus + NumEmptySentences := 0; + for Index := Low(Lines[0].Line) to High(Lines[0].Line) do + if Lines[0].Line[Index].TotalNotes = 0 then + Inc(NumEmptySentences); end; - // deactivate pause - Paused := false; + //Test + // start lyrics + LyricsState.Resume(); - // kill all stars not killed yet (goldenstarstwinkle mod) - GoldenRec.SentenceChange; + // start music + if ScreenSong.Mode <> smMedley then + AudioPlayback.Play() + else + begin + AudioPlayback.SetVolume(0.3); + AudioPlayback.FadeIn(CurrentSong.Medley.FadeIn_time, 1.0); + end; - // set position of line bonus - line bonus end - // set number of empty sentences for line bonus - NumEmptySentences := 0; - for Index := Low(Lines[0].Line) to High(Lines[0].Line) do - if Lines[0].Line[Index].TotalNotes = 0 then - Inc(NumEmptySentences); + // start timer + CountSkipTimeSet; - Log.LogStatus('End', 'OnShow'); + PlaylistMedley.ApplausePlayed := false; end; procedure TScreenSing.onShowFinish; begin - // hide cursor on singscreen show + //hide cursor on singscreen show Display.SetCursor; - + // start lyrics - LyricsState.Resume(); + //LyricsState.Resume(); // start music - AudioPlayback.Play(); + //AudioPlayback.Play(); // start timer - CountSkipTimeSet; + //CountSkipTimeSet; end; procedure TScreenSing.OnHide; @@ -672,6 +812,8 @@ var Sec: integer; T: integer; CurLyricsTime: real; + medley_end: boolean; + medley_start_applause: boolean; Line: TLyricLine; LastWord: TLyricWord; begin @@ -742,7 +884,12 @@ begin // retrieve current lyrics time, we have to store the value to avoid // that min- and sec-values do not match - CurLyricsTime := LyricsState.GetCurrentTime(); + if ScreenSong.Mode <> smMedley then + CurLyricsTime := LyricsState.TotalTime - LyricsState.GetCurrentTime() + else + CurLyricsTime := GetTimeFromBeat(CurrentSong.Medley.EndBeat) + + CurrentSong.Medley.FadeOut_time - LyricsState.GetCurrentTime(); + Min := Round(CurLyricsTime) div 60; Sec := Round(CurLyricsTime) mod 60; @@ -785,24 +932,44 @@ begin // draw static menu (FG) DrawFG; + if (ScreenSong.Mode = smMedley) and (LyricsState.GetCurrentTime() > + GetTimeFromBeat(CurrentSong.Medley.EndBeat) + CurrentSong.Medley.FadeOut_time) then + medley_end := true + else + medley_end := false; + + if (ScreenSong.Mode = smMedley) and (LyricsState.GetCurrentTime() > + GetTimeFromBeat(CurrentSong.Medley.EndBeat)) then + medley_start_applause := true + else + medley_start_applause := false; + // check for music finish //Log.LogError('Check for music finish: ' + BoolToStr(Music.Finished) + ' ' + FloatToStr(LyricsState.CurrentTime*1000) + ' ' + IntToStr(CurrentSong.Finish)); if ShowFinish then begin - if (not AudioPlayback.Finished) and ((CurrentSong.Finish = 0) or + if (not AudioPlayback.Finished) and not medley_end and ((CurrentSong.Finish = 0) or (LyricsState.GetCurrentTime() * 1000 <= CurrentSong.Finish)) then begin // analyze song if not paused if (not Paused) then + begin Sing(Self); + //Update Medley Stats + if (ScreenSong.Mode = smMedley) and not FadeOut then + UpdateMedleyStats(medley_start_applause); + end; end else begin if (not FadeOut) then begin Finish; - FadeOut := true; - FadeTo(@ScreenScore); + if ScreenSong.Mode = smNormal then + begin + FadeOut := true; + FadeTo(@ScreenScore); + end; end; end; end; @@ -850,7 +1017,49 @@ begin Result := true; end; +procedure TScreenSing.UpdateMedleyStats(medley_end: boolean); +var + len, num, I : integer; + lastline: boolean; + vol: real; +begin + len := Length(PlaylistMedley.Stats); + num := PlaylistMedley.NumPlayer; + + if (PlaylistMedley.CurrentMedleySong>len) and + (PlaylistMedley.CurrentMedleySong<=PlaylistMedley.NumMedleySongs) then + begin + inc(len); + SetLength(PlaylistMedley.Stats, len); + SetLength(PlaylistMedley.Stats[len-1].Player, num); + PlaylistMedley.Stats[len-1].SongArtist := CurrentSong.Artist; + PlaylistMedley.Stats[len-1].SongTitle := CurrentSong.Title; + end; + + if (PlaylistMedley.CurrentMedleySong<=PlaylistMedley.NumMedleySongs) then + for I := 0 to num - 1 do + PlaylistMedley.Stats[len-1].Player[I] := Player[I]; + + if medley_end and not PlaylistMedley.ApplausePlayed and + (PlaylistMedley.CurrentMedleySong<=PlaylistMedley.NumMedleySongs) then + begin + PlaylistMedley.ApplausePlayed:=true; + AudioPlayback.PlaySound(ApplauseSounds[0]); + end; + + if(LyricsState.GetCurrentTime() > GetTimeFromBeat(CurrentSong.Medley.EndBeat)) then + begin + vol := 1-(LyricsState.GetCurrentTime() - GetTimeFromBeat(CurrentSong.Medley.EndBeat))/ + CurrentSong.Medley.FadeOut_time ; + AudioPlayback.SetVolume(vol); //used as fade out! + end; +end; + procedure TScreenSing.Finish; +var + I, J: integer; + len, num: integer; + Color: TRGB; begin AudioInput.CaptureStop; AudioPlayback.Stop; @@ -879,6 +1088,91 @@ begin end; SetFontItalic(false); + + if ScreenSong.Mode = smMedley then + begin + {***** just a quick and dirty fix.... *******} + // setup score manager + Scores.ClearPlayers; // clear old player values + + Color.R := 0; + Color.G := 0; + Color.B := 0; + // add new players + for I := 0 to PlayersPlay - 1 do + begin + Scores.AddPlayer(Tex_ScoreBG[I], Color); + end; + + Scores.Init; // get positions for players + + // prepare players + SetLength(Player, PlayersPlay); + {***** end of quick and dirty fix ******} + + if not FadeOut then + begin + inc(PlaylistMedley.CurrentMedleySong); + if PlaylistMedley.CurrentMedleySong<=PlaylistMedley.NumMedleySongs then + begin + //AudioPlayback.PlaySound(SoundLib.Applause); + LoadNextSong; + end else + begin + //build sums + len := Length(PlaylistMedley.Stats); + num := PlaylistMedley.NumPlayer; + + SetLength(PlaylistMedley.Stats, len+1); + SetLength(PlaylistMedley.Stats[len].Player, num); + + for J := 0 to len - 1 do + begin + for I := 0 to num - 1 do + begin + PlaylistMedley.Stats[len].Player[I].Score := + PlaylistMedley.Stats[len].Player[I].Score + + PlaylistMedley.Stats[J].Player[I].Score; + + PlaylistMedley.Stats[len].Player[I].ScoreLine := + PlaylistMedley.Stats[len].Player[I].ScoreLine + + PlaylistMedley.Stats[J].Player[I].ScoreLine; + + PlaylistMedley.Stats[len].Player[I].ScoreGolden := + PlaylistMedley.Stats[len].Player[I].ScoreGolden + + PlaylistMedley.Stats[J].Player[I].ScoreGolden; + + PlaylistMedley.Stats[len].Player[I].ScoreInt := + PlaylistMedley.Stats[len].Player[I].ScoreInt + + PlaylistMedley.Stats[J].Player[I].ScoreInt; + + PlaylistMedley.Stats[len].Player[I].ScoreLineInt := + PlaylistMedley.Stats[len].Player[I].ScoreLineInt + + PlaylistMedley.Stats[J].Player[I].ScoreLineInt; + + PlaylistMedley.Stats[len].Player[I].ScoreGoldenInt := + PlaylistMedley.Stats[len].Player[I].ScoreGoldenInt + + PlaylistMedley.Stats[J].Player[I].ScoreGoldenInt; + + PlaylistMedley.Stats[len].Player[I].ScoreTotalInt := + PlaylistMedley.Stats[len].Player[I].ScoreTotalInt + + PlaylistMedley.Stats[J].Player[I].ScoreTotalInt; + end; //of for I + end; //of for J + + FadeOut:=true; + FadeTo(@ScreenScore); + end; + end; + end else + begin + SetLength(PlaylistMedley.Stats, 1); + SetLength(PlaylistMedley.Stats[0].Player, PlayersPlay); + for I := 0 to PlayersPlay - 1 do + PlaylistMedley.Stats[0].Player[I] := Player[I]; + PlaylistMedley.Stats[0].SongArtist := CurrentSong.Artist; + PlaylistMedley.Stats[0].SongTitle := CurrentSong.Title; + end; end; procedure TScreenSing.OnSentenceEnd(SentenceIndex: cardinal); @@ -904,10 +1198,19 @@ begin Exit; // set max song score - if (Ini.LineBonus = 0) then - MaxSongScore := MAX_SONG_SCORE - else - MaxSongScore := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS; + if ScreenSong.Mode <> smMedley then + begin + if (Ini.LineBonus = 0) then + MaxSongScore := MAX_SONG_SCORE + else + MaxSongScore := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS; + end else + begin + if (Ini.LineBonus = 0) then + MaxSongScore := max_song_score_medley + else + MaxSongScore := max_song_score_medley - max_song_line_bonus_medley; + end; // Note: ScoreValue is the sum of all note values of the song MaxLineScore := MaxSongScore * (Line.TotalNotes / Lines[0].ScoreValue); @@ -941,7 +1244,11 @@ begin if (Ini.LineBonus > 0) then begin // line-bonus points (same for each line, no matter how long the line is) - LineBonus := MAX_SONG_LINE_BONUS / (Length(Lines[0].Line) - + if ScreenSong.Mode <> smMedley then + LineBonus := MAX_SONG_LINE_BONUS / (Length(Lines[0].Line) - + NumEmptySentences) + else + LineBonus := max_song_line_bonus_medley / (Length(Lines[0].Line) - NumEmptySentences); // apply line-bonus CurrentPlayer.ScoreLine := diff --git a/Medley/src/screens/UScreenSong.pas b/Medley/src/screens/UScreenSong.pas index bd5eebe5..bab2ef51 100644 --- a/Medley/src/screens/UScreenSong.pas +++ b/Medley/src/screens/UScreenSong.pas @@ -53,6 +53,8 @@ uses UTime; type + TVisArr = array of integer; + TScreenSong = class(TMenu) private Equalizer: Tms_Equalizer; @@ -138,6 +140,9 @@ type procedure HideCatTL;// Show Cat in Tob left procedure Refresh; //Refresh Song Sorting procedure ChangeMusic; + + function getVisibleMedleyArr(): TVisArr; + procedure StartMedley(num: integer); //Party Mode procedure SelectRandomSong; procedure SetJoker; @@ -345,6 +350,21 @@ begin Exit; end; + Ord('S'): + begin + if (Length(getVisibleMedleyArr()) > 0) and (Mode = smNormal) and + (CatSongs.Song[Interaction].Medley.Source = msTag) then + begin + StartMedley(0); + end; + end; + Ord('D'): + begin + if (Length(getVisibleMedleyArr()) > 0) and (Mode = smNormal) then + begin + StartMedley(5); + end; + end; Ord('M'): //Show SongMenu begin if (Songs.SongList.Count > 0) then @@ -1002,6 +1022,11 @@ begin // Set texts Text[TextArtist].Text := CatSongs.Song[Interaction].Artist; Text[TextTitle].Text := CatSongs.Song[Interaction].Title; + + //medley mod + if CatSongs.Song[Interaction].Medley.Source = msTag then + Text[TextTitle].Text := Text[TextTitle].Text + '[M]'; + if (Ini.TabsAtStartup = 1) and (CatSongs.CatNumShow = -1) then begin Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].OrderNum) + '/' + IntToStr(CatSongs.CatCount); @@ -1496,6 +1521,9 @@ begin AudioPlayback.Stop; + if Mode = smMedley then + Mode := smNormal; + if Ini.Players <= 3 then PlayersPlay := Ini.Players + 1; if Ini.Players = 4 then PlayersPlay := 6; @@ -1725,19 +1753,29 @@ end; procedure TScreenSong.StartMusicPreview(); var - Song: TSong; + Song: TSong; + success: boolean; begin AudioPlayback.Close(); + if CatSongs.Song[Interaction].Main then + Exit; + Song := CatSongs.Song[Interaction]; - if not assigned(Song) then + if not assigned(Song) or Song.Main then Exit; if AudioPlayback.Open(Song.Path.Append(Song.Mp3)) then begin PreviewOpened := Interaction; - - AudioPlayback.Position := AudioPlayback.Length / 4; + + if Song.Medley.Source <> msNone then + begin + CurrentSong := Song; + AudioPlayback.Position := GetTimeFromBeat(Song.Medley.StartBeat); + end else + AudioPlayback.Position := AudioPlayback.Length / 4; + // set preview volume if (Ini.PreviewFading = 0) then begin @@ -1747,6 +1785,10 @@ begin end else begin + AudioPlayback.Position := AudioPlayback.Position - Ini.PreviewFading; + if AudioPlayback.Position<0 then + AudioPlayback.Position := 0; + // music fade enabled: start muted and fade-in AudioPlayback.SetVolume(0); AudioPlayback.FadeIn(Ini.PreviewFading, IPreviewVolumeVals[Ini.PreviewVolume]); @@ -1796,6 +1838,106 @@ begin end; end; +function TScreenSong.getVisibleMedleyArr(): TVisArr; +var + I: integer; + res: TVisArr; +begin + SetLength(res, 0); + for I := 0 to Length(CatSongs.Song) - 1 do + begin + if CatSongs.Song[I].Visible and (CatSongs.Song[I].Medley.Source = msTag) then + begin + SetLength(res, Length(res)+1); + res[Length(res)-1] := I; + end; + end; + Result := res; +end; + +//start Medley round +procedure TScreenSong.StartMedley(num: integer); + procedure AddSong(SongNr: integer); + begin + SetLength(PlaylistMedley.Song, Length(PlaylistMedley.Song)+1); + PlaylistMedley.Song[Length(PlaylistMedley.Song)-1] := SongNr; + end; + + function SongAdded(SongNr: integer): boolean; + var + i: integer; + skipped :boolean; + begin + skipped := false; + for i := 0 to Length(PlaylistMedley.Song) - 1 do + begin + if (SongNr=PlaylistMedley.Song[i]) then + begin + skipped:=true; + break; + end; + end; + Result:=skipped; + end; + + function NumSongsAdded(): Integer; + begin + Result := Length(PlaylistMedley.Song); + end; + + function GetNextSongNr: integer; + var + I, num: integer; + unused_arr: array of integer; + visible_arr: TVisArr; + begin + SetLength(unused_arr, 0); + visible_arr := getVisibleMedleyArr(); + for I := 0 to Length(visible_arr) - 1 do + begin + if (not SongAdded(visible_arr[I])) then + begin + SetLength(unused_arr, Length(unused_arr)+1); + unused_arr[Length(unused_arr)-1] := visible_arr[I]; + end; + end; + + num := random(Length(unused_arr)); + Result := unused_arr[num]; +end; + +var + I: integer; + VS: integer; + +begin + StopMusicPreview(); + Mode := smMedley; + + if num>0 then + begin + VS := Length(getVisibleMedleyArr()); + if VS < num then + PlaylistMedley.NumMedleySongs := VS + else + PlaylistMedley.NumMedleySongs := num; + + Randomize; + //set up Playlist Medley + SetLength(PlaylistMedley.Song, 0); + for I := 0 to PlaylistMedley.NumMedleySongs - 1 do + begin + AddSong(GetNextSongNr); + end; + end else + begin + SetLength(PlaylistMedley.Song, 1); + PlaylistMedley.Song[0] := Interaction; + PlaylistMedley.NumMedleySongs := 1; + end; + FadeTo(@ScreenSing); +end; + procedure TScreenSong.SkipTo(Target: cardinal); var i: integer; |