From 3de159b0d467f57967642431f96b7d675b004b8e Mon Sep 17 00:00:00 2001 From: brunzelchen Date: Mon, 25 Apr 2011 10:53:52 +0000 Subject: added song quality check git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/1.0.1 Challenge MOD@2829 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UDataBase.pas | 30 +++++++++ Game/Code/Classes/UFiles.pas | 124 +++++++++++++++++++++++++++++++++-- Game/Code/Classes/UIni.pas | 2 +- Game/Code/Classes/ULog.pas | 43 +++++++++++- Game/Code/Classes/USongs.pas | 12 ++++ Game/Code/Screens/UScreenEditSub.pas | 3 + Game/Code/Screens/UScreenSong.pas | 37 +++++++++++ 7 files changed, 245 insertions(+), 6 deletions(-) diff --git a/Game/Code/Classes/UDataBase.pas b/Game/Code/Classes/UDataBase.pas index 586e742d..40079b1e 100644 --- a/Game/Code/Classes/UDataBase.pas +++ b/Game/Code/Classes/UDataBase.pas @@ -57,6 +57,8 @@ type function GetHandicap(P1: string; P2: string): THandicapResult; //for Handicap-Mode function GetAspect(Artist, Title: string; def: integer): integer; procedure SetAspect(Artist, Title: string; aspect: integer); + + function GetMaxScore(Artist, Title: string; difficulty: integer): integer; end; var @@ -119,6 +121,34 @@ begin end; end; +function TDataBaseSystem.GetMaxScore(Artist, Title: string; difficulty: integer): integer; +var + ID: Integer; + tArtist, tTitle: string; + +begin + Result := 0; + + if not Assigned(ScoreDB) then + Exit; + + try + tArtist := StringReplace(Artist,'"','""',[rfReplaceAll, rfIgnoreCase]); + tTitle := StringReplace(Title,'"','""',[rfReplaceAll, rfIgnoreCase]); + + ID := ScoreDB.GetTableValue('SELECT `ID` FROM `US_Songs` WHERE `Artist` = "' + + tArtist + '" AND `Title` = "' + tTitle + '"'); + + if ID <> 0 then + begin + Result := ScoreDB.GetTableValue('SELECT MAX(`Score`) FROM `US_Scores` WHERE `SongID` = "' + + IntToStr(ID) + '" AND `Difficulty` = "' + IntToStr(difficulty) + '"'); + end; + except + Result := 0; + end; +end; + function TDataBaseSystem.GetAspect(Artist, Title: string; def: integer): integer; var ID: Integer; diff --git a/Game/Code/Classes/UFiles.pas b/Game/Code/Classes/UFiles.pas index 382f39ff..7a5e7de4 100644 --- a/Game/Code/Classes/UFiles.pas +++ b/Game/Code/Classes/UFiles.pas @@ -6,7 +6,8 @@ uses USongs, SysUtils, StrUtils, ULog, - UMusic; + UMusic, + UDataBase; const DEFAULT_FADE_IN_TIME = 8; //TODO in INI @@ -33,9 +34,10 @@ procedure ClearSong(var Song: TSong); //Clears Song Header values procedure ResetSingTemp; procedure ParseNote(NrCzesci: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); procedure NewSentence(NrCzesciP: integer; Param1, Param2: integer; LoadFullFile: boolean); -function LoadSong(Name: string; LoadFullFile: boolean): boolean; -function CheckSong: boolean; -function SaveSong(Song: TSong; Czesc: array of TCzesci; Name: string; Relative: boolean): boolean; +function LoadSong(Name: string; LoadFullFile: boolean): boolean; +function CheckSong: boolean; +procedure SongQuality(Check: boolean); +function SaveSong(Song: TSong; Czesc: array of TCzesci; Name: string; Relative: boolean): boolean; procedure FindRefrainStart(var Song: TSong); procedure SetMedleyMode; @@ -180,6 +182,14 @@ begin SetLength(Song.DuetNames, 2); Song.DuetNames[0] := 'P1'; Song.DuetNames[1] := 'P2'; + + //Quality + Song.Quality.Syntax := 0; + Song.Quality.BPM := 0; + Song.Quality.NoteGaps := 0; + Song.Quality.NoteJumps := 0; + Song.Quality.Scores := 50; + Song.Quality.Value := 0; end; //-------------------- @@ -879,6 +889,112 @@ begin if (Ini.LoadFaultySongs=0) and (Ini.LoadFaultySongs_temp=0) then Result := false; end; + + SongQuality(Result); +end; + +procedure SongQuality(Check: boolean); +var + p, line, note: integer; + numLines: integer; + numNotes: integer; + firstNote: boolean; + + lastNoteTone: integer; + lastNoteEnd: integer; + + Gaps: array[0..2] of integer; //0=total; 1=gaps with length 0; 2=gaps with length 0 + note jump + GoldenNotes: integer; + gn: real; + +begin + // syntax quality + if Check then + AktSong.Quality.Syntax := 100 + else + AktSong.Quality.Syntax := 0; + + // BPM quality (check only 1st) + if (AktSong.BPM[0].BPM/4 < 100) then + AktSong.Quality.BPM := 5 + else if (AktSong.BPM[0].BPM/4 < 200) then + AktSong.Quality.BPM := (AktSong.BPM[0].BPM/4-100)*0.95 + 5 + else if (AktSong.BPM[0].BPM/4 < 1000) then + AktSong.Quality.BPM := 100 + else + AktSong.Quality.BPM := 50; + + // Score quality + p := Database.GetMaxScore(AktSong.Artist, AktSong.Title, 0); + if (p=0) then + begin + p := round(Database.GetMaxScore(AktSong.Artist, AktSong.Title, 1)*1.2); + if (p=0) then + p := round(Database.GetMaxScore(AktSong.Artist, AktSong.Title, 2)*1.5); + end; + + if (p=0) then + AktSong.Quality.Scores := 50 + else + begin + if (p>10000) then + p := 10000; + + AktSong.Quality.Scores := p/100; + end; + + Gaps[0] := 0; + Gaps[1] := 0; + Gaps[2] := 0; + + GoldenNotes := 0; + gn := 0; + + for p := 0 to Length(Czesci) - 1 do + begin + numLines := Length(Czesci[p].Czesc); + firstNote := true; + + for line := 0 to numLines - 1 do + begin + numNotes := Length(Czesci[p].Czesc[line].Nuta); + + for note := 0 to numNotes - 1 do + begin + if (Czesci[p].Czesc[line].Nuta[note].Wartosc = 2) then + Inc(GoldenNotes); + + if firstNote then + firstNote := false + else + begin + Gaps[0] := Gaps[0] + 1; + if (lastNoteEnd = Czesci[p].Czesc[line].Nuta[note].Start) then + begin + Gaps[1] := Gaps[1] + 1; + if (abs(lastNoteTone - Czesci[p].Czesc[line].Nuta[note].Ton) > 1) then + Gaps[2] := Gaps[2] + 1; + end; + end; + + lastNoteTone := Czesci[p].Czesc[line].Nuta[note].Ton; + lastNoteEnd := Czesci[p].Czesc[line].Nuta[note].Start + Czesci[p].Czesc[line].Nuta[note].Dlugosc; + end; + end; + end; + + if (Gaps[0]>0) then + begin + AktSong.Quality.NoteGaps := 100 * (1-Gaps[1]/Gaps[0]); + AktSong.Quality.NoteJumps := 100 * (1-Gaps[2]/Gaps[0]); + gn := 100 * GoldenNotes/(Gaps[0]+1); + end; + + AktSong.Quality.Value := (AktSong.Quality.Syntax + AktSong.Quality.BPM*3 + AktSong.Quality.NoteGaps*2 + + AktSong.Quality.NoteJumps*2 + AktSong.Quality.Scores*2) / 10; + + Log.LogSongQuality(AktSong.Artist, AktSong.Title, AktSong.Quality.Syntax, AktSong.Quality.BPM, AktSong.Quality.NoteGaps, + AktSong.Quality.NoteJumps, AktSong.Quality.Scores, AktSong.Quality.Value, gn); end; diff --git a/Game/Code/Classes/UIni.pas b/Game/Code/Classes/UIni.pas index 3546e196..3b33785b 100644 --- a/Game/Code/Classes/UIni.pas +++ b/Game/Code/Classes/UIni.pas @@ -358,7 +358,7 @@ begin if Tekst = IResolution[Pet] then Ini.Resolution := Pet; // FullScreen - Tekst := IniFile.ReadString('Graphics', 'FullScreen', 'On'); + Tekst := IniFile.ReadString('Graphics', 'FullScreen', 'Off'); for Pet := 0 to High(IFullScreen) do if Tekst = IFullScreen[Pet] then Ini.FullScreen := Pet; diff --git a/Game/Code/Classes/ULog.pas b/Game/Code/Classes/ULog.pas index a3e7f156..9e6f26fb 100644 --- a/Game/Code/Classes/ULog.pas +++ b/Game/Code/Classes/ULog.pas @@ -17,6 +17,9 @@ type FileSession: TextFile; FileSessionO: boolean; // opened + FileSongQuality: TextFile; + FileSongQualityO: boolean; // opened + NumErrors: integer; NumSungSongs: integer; @@ -43,6 +46,7 @@ type function LogVoice(SoundNr: Integer; Player, Artist, Title, Points: string): string; procedure LogSession(names: array of string; points: array of string; Artist, Title, singmode: string); + procedure LogSongQuality(artist, title: string; syntax, bpm, notegaps, notejumps, score, value, goldennotes: real); // compability procedure LogStatus(Log1, Log2: string); @@ -285,7 +289,7 @@ begin // if FileAnalyzeO then CloseFile(FileAnalyze); if FileErrorO then CloseFile(FileError); if FileSessionO then CloseFile(FileSession); - + if FileSongQualityO then CloseFile(FileSongQuality); end; procedure TLog.BenchmarkStart(Number: integer); @@ -627,6 +631,43 @@ begin end; end; +procedure TLog.LogSongQuality(artist, title: string; + syntax, bpm, notegaps, notejumps, score, value, goldennotes: real); +var + FileName: string; + +begin + if not FileSongQualityO then + begin + NumSungSongs := 0; + FileName := GamePath + 'quality.csv'; + + AssignFile(FileSongQuality, FileName); + {$I-} + Rewrite(FileSongQuality); + if IOResult = 0 then FileSongQualityO := true; + {$I+} + + //If File is opened write column names to File + If (FileSongQualityO) then + begin + WriteLn(FileSongQuality, 'Artist; Title; Syntax; BPM; Note Gaps; Note Jumps; Scores; Value; Anteil Goldene Noten'); + Flush(FileSongQuality); + end; + end; + + if FileSongQualityO then + begin + try + WriteLn(FileSongQuality, artist + ';' + title + ';' + FloatToStr(syntax) + ';' + + FloatToStr(bpm) + ';' + FloatToStr(notegaps) + ';' + FloatToStr(notejumps) + ';' + + FloatToStr(score) + ';' + FloatToStr(value) + ';' + FloatToStr(goldennotes) + ';'); + except + FileSongQualityO := false; + end; + end; +end; + procedure TLog.LogStatus(Log1, Log2: string); begin //Just for Debugging diff --git a/Game/Code/Classes/USongs.pas b/Game/Code/Classes/USongs.pas index f3323244..20d107e1 100644 --- a/Game/Code/Classes/USongs.pas +++ b/Game/Code/Classes/USongs.pas @@ -18,6 +18,16 @@ type FadeOut_time: real; //FadeOut-Time in seconds end; + TSongQuality = record // 0..100% 0% = worst, 100% = should be good + Syntax: real; // are there syntax errors in txt? + BPM: real; // should be between 200 and 450 + NoteGaps: real; // notes should have some space between each other + NoteJumps: real; // don't change the note level too much if there's no space between the notes + Scores: real; // 50% if no highscore available, else: maximum highscore/10 + + Value: real; // summarized quality indicator + end; + { used to hold header tags that are not supported by this version of usdx (e.g. some tags from ultrastar 0.7.0) when songs are loaded in songeditor. They will be written the end of the song header } //from usdx 1.1 @@ -43,6 +53,8 @@ type Folder: string; // for sorting by folder FileName: string; + Quality: TSongQuality; + isDuet: boolean; DuetNames: array of string; Medley: TMedley; diff --git a/Game/Code/Screens/UScreenEditSub.pas b/Game/Code/Screens/UScreenEditSub.pas index b232ff19..31196d45 100644 --- a/Game/Code/Screens/UScreenEditSub.pas +++ b/Game/Code/Screens/UScreenEditSub.pas @@ -387,6 +387,9 @@ begin if SResult then begin Text[TextDebug].Text := Language.Translate('INFO_FILE_SAVED'); + if not CheckSong then + ScreenPopupError.ShowPopup('This song contains some syntax errors!'); + CatSongs.Song[SongIndex] := AktSong; end else begin diff --git a/Game/Code/Screens/UScreenSong.pas b/Game/Code/Screens/UScreenSong.pas index 011e4b26..9b811a62 100644 --- a/Game/Code/Screens/UScreenSong.pas +++ b/Game/Code/Screens/UScreenSong.pas @@ -40,6 +40,7 @@ type ChooseableSongs: integer; isScrolling: boolean; FadeOut: boolean; + ShowSongQuality: boolean; public Sel3: integer; //Selection in party mode (0=current, -1=left, 1=right) @@ -517,6 +518,12 @@ begin Music.EnableVocalRemover; end; + SDLK_I: + begin + if (Mode = smNormal) then + ShowSongQuality := not ShowSongQuality; + end; + SDLK_O: begin if (Mode = smNormal) then @@ -1388,6 +1395,8 @@ begin EqualizerBands[I] := 3; MP3Volume := Ini.PreviewVolume * 10; + + ShowSongQuality := false; end; procedure TScreenSong.ChangeSorting(tabs: boolean; sorting: integer); @@ -2681,6 +2690,34 @@ begin DrawExtensions; + // Song Quality + if ShowSongQuality and not CatSongs.Song[Interaction].Main then + begin + SetFontStyle(0); + SetFontItalic(false); + SetFontSize(6); + + glColor4f(1, 1, 1, 1); + + SetFontPos (525, 80); + glPrint(PChar(FormatFloat('STX: 000%', CatSongs.Song[Interaction].Quality.Syntax))); + + SetFontPos (600, 80); + glPrint(PChar(FormatFloat('BPM: 000%', CatSongs.Song[Interaction].Quality.BPM))); + + SetFontPos (675, 80); + glPrint(PChar(FormatFloat('NGP: 000%', CatSongs.Song[Interaction].Quality.NoteGaps))); + + SetFontPos (525, 95); + glPrint(PChar(FormatFloat('NJP: 000%', CatSongs.Song[Interaction].Quality.NoteJumps))); + + SetFontPos (600, 95); + glPrint(PChar(FormatFloat('SCO: 000%', CatSongs.Song[Interaction].Quality.Scores))); + + SetFontPos (675, 95); + glPrint(PChar(FormatFloat('VAL: 000%', CatSongs.Song[Interaction].Quality.Value))); + end; + StartPreview; end; -- cgit v1.2.3