From 7a01b05b3861a667eb32ce2e0fc88ff3bacb99ae Mon Sep 17 00:00:00 2001 From: mogguh Date: Tue, 2 Sep 2008 17:25:26 +0000 Subject: Moved: The folder classes has been renamed to base Updated: ultrastardx.dpr has been changed accordingly git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1339 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 1027 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1027 insertions(+) create mode 100644 src/base/USong.pas (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas new file mode 100644 index 00000000..3517bce6 --- /dev/null +++ b/src/base/USong.pas @@ -0,0 +1,1027 @@ +unit USong; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + {$IFDEF MSWINDOWS} + Windows, + {$ELSE} + {$IFNDEF DARWIN} + syscall, + {$ENDIF} + baseunix, + UnixType, + {$ENDIF} + SysUtils, + Classes, + UPlatform, + ULog, + UTexture, + UCommon, + {$IFDEF DARWIN} + cthreads, + {$ENDIF} + {$IFDEF USE_PSEUDO_THREAD} + PseudoThread, + {$ENDIF} + UCatCovers, + UXMLSong; + +type + + TSingMode = ( smNormal, smPartyMode, smPlaylistRandom ); + + TBPM = record + BPM: real; + StartBeat: real; + end; + + TScore = record + Name: WideString; + Score: integer; + Length: string; + end; + + TSong = class + FileLineNo : integer; //Line which is readed at Last, for error reporting + + procedure ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); + procedure NewSentence(LineNumberP: integer; Param1, Param2: integer); + + function ReadTXTHeader( const aFileName : WideString ): boolean; + function ReadXMLHeader( const aFileName : WideString ): boolean; + public + Path: WideString; + Folder: WideString; // for sorting by folder + fFileName, + FileName: WideString; + + // sorting methods + Category: array of WideString; // TODO: do we need this? + Genre: WideString; + Edition: WideString; + Language: WideString; + + Title: WideString; + Artist: WideString; + + Text: WideString; + Creator: WideString; + + Cover: WideString; + CoverTex: TTexture; + Mp3: WideString; + Background: WideString; + Video: WideString; + VideoGAP: real; + VideoLoaded: boolean; // true if the video has been loaded + NotesGAP: integer; + Start: real; // in seconds + Finish: integer; // in miliseconds + Relative: boolean; + Resolution: integer; + BPM: array of TBPM; + GAP: real; // in miliseconds + + Score: array[0..2] of array of TScore; + + // these are used when sorting is enabled + Visible: boolean; // false if hidden, true if visible + Main: boolean; // false for songs, true for category buttons + OrderNum: integer; // has a number of category for category buttons and songs + OrderTyp: integer; // type of sorting for this button (0=name) + CatNumber: integer; // Count of Songs in Category for Cats and Number of Song in Category for Songs + + SongFile: TextFile; // all procedures in this unit operate on this file + + Base : array[0..1] of integer; + Rel : array[0..1] of integer; + Mult : integer; + MultBPM : integer; + + constructor Create (); overload; + constructor Create ( const aFileName : WideString ); overload; + function LoadSong: boolean; + function LoadXMLSong: boolean; + function Analyse(): boolean; + function AnalyseXML(): boolean; + procedure Clear(); + end; + +implementation + +uses + TextGL, + UIni, + UMusic, //needed for Lines + UMain; //needed for Player + +constructor TSong.Create(); +begin + inherited; +end; + +constructor TSong.Create( const aFileName : WideString ); +begin + inherited Create(); + + Mult := 1; + MultBPM := 4; + fFileName := aFileName; + + if fileexists( aFileName ) then + begin + self.Path := ExtractFilePath( aFileName ); + self.Folder := ExtractFilePath( aFileName ); + self.FileName := ExtractFileName( aFileName ); + (* + if ReadTXTHeader( aFileName ) then + begin + LoadSong(); + end + else + begin + Log.LogError('Error Loading SongHeader, abort Song Loading'); + Exit; + end; + *) + end; +end; + +//Load TXT Song +function TSong.LoadSong(): boolean; + +var + TempC: char; + Text: string; + CP: integer; // Current Player (0 or 1) + Count: integer; + Both: boolean; + Param1: integer; + Param2: integer; + Param3: integer; + ParamS: string; + I: integer; +begin + Result := false; + + if not FileExists(Path + PathDelim + FileName) then + begin + Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()'); + exit; + end; + + MultBPM := 4; // multiply beat-count of note by 4 + Mult := 1; // accuracy of measurement of note + Base[0] := 100; // high number + Lines[0].ScoreValue := 0; + self.Relative := false; + Rel[0] := 0; + CP := 0; + Both := false; + + if Length(Player) = 2 then + Both := true; + + try + // Open song file for reading..... + FileMode := fmOpenRead; + AssignFile(SongFile, fFileName); + Reset(SongFile); + + //Clear old Song Header + if (self.Path = '') then + self.Path := ExtractFilePath(FileName); + + if (self.FileName = '') then + self.Filename := ExtractFileName(FileName); + + Result := False; + + Reset(SongFile); + FileLineNo := 0; + //Search for Note Begining + repeat + ReadLn(SongFile, Text); + Inc(FileLineNo); + + if (EoF(SongFile)) then + begin //Song File Corrupted - No Notes + CloseFile(SongFile); + Log.LogError('Could not load txt File, no Notes found: ' + FileName); + Result := False; + Exit; + end; + Read(SongFile, TempC); + until ((TempC = ':') or (TempC = 'F') or (TempC = '*')); + + SetLength(Lines, 2); + for Count := 0 to High(Lines) do + begin + SetLength(Lines[Count].Line, 1); + Lines[Count].High := 0; + Lines[Count].Number := 1; + Lines[Count].Current := 0; + Lines[Count].Resolution := self.Resolution; + Lines[Count].NotesGAP := self.NotesGAP; + Lines[Count].Line[0].HighNote := -1; + Lines[Count].Line[0].LastLine := False; + end; + + // TempC := ':'; + // TempC := Text[1]; // read from backup variable, don't use default ':' value + + while (TempC <> 'E') AND (not EOF(SongFile)) do + begin + + if (TempC = ':') or (TempC = '*') or (TempC = 'F') then + begin + // read notes + Read(SongFile, Param1); + Read(SongFile, Param2); + Read(SongFile, Param3); + Read(SongFile, ParamS); + + + //Check for ZeroNote + if Param2 = 0 then Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') else + begin + // add notes + if not Both then + // P1 + ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) + else begin + // P1 + P2 + ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); + ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); + end; + end; //Zeronote check + end; // if + + if TempC = '-' then + begin + // reads sentence + Read(SongFile, Param1); + if self.Relative then Read(SongFile, Param2); // read one more data for relative system + + // new sentence + if not Both then + // P1 + NewSentence(0, (Param1 + Rel[0]) * Mult, Param2) + else begin + // P1 + P2 + NewSentence(0, (Param1 + Rel[0]) * Mult, Param2); + NewSentence(1, (Param1 + Rel[1]) * Mult, Param2); + end; + end; // if + + if TempC = 'B' then + begin + SetLength(self.BPM, Length(self.BPM) + 1); + Read(SongFile, self.BPM[High(self.BPM)].StartBeat); + self.BPM[High(self.BPM)].StartBeat := self.BPM[High(self.BPM)].StartBeat + Rel[0]; + + Read(SongFile, Text); + self.BPM[High(self.BPM)].BPM := StrToFloat(Text); + self.BPM[High(self.BPM)].BPM := self.BPM[High(self.BPM)].BPM * Mult * MultBPM; + end; + + + if not Both then + begin + Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; + Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(PChar(Lines[CP].Line[Lines[CP].High].Lyric)); + //Total Notes Patch + Lines[CP].Line[Lines[CP].High].TotalNotes := 0; + for I := low(Lines[CP].Line[Lines[CP].High].Note) to high(Lines[CP].Line[Lines[CP].High].Note) do + begin + if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType = ntGolden) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; + + if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType <> ntFreestyle) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; + end; + //Total Notes Patch End + end else begin + for Count := 0 to High(Lines) do + begin + Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; + Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); + //Total Notes Patch + Lines[Count].Line[Lines[Count].High].TotalNotes := 0; + for I := low(Lines[Count].Line[Lines[Count].High].Note) to high(Lines[Count].Line[Lines[Count].High].Note) do + begin + if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType = ntGolden) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[I].Length; + if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType <> ntFreestyle) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[I].Length; + end; + //Total Notes Patch End + end; + end; + Read(SongFile, TempC); + Inc(FileLineNo); + end; // while} + + for Count := 0 to High(Lines) do + begin + Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; + end; + + CloseFile(SongFile); + except + try + CloseFile(SongFile); + except + + end; + + Log.LogError('Error Loading File: "' + fFileName + '" in Line ' + inttostr(FileLineNo)); + exit; + end; + + Result := true; +end; + +//Load XML Song +function TSong.LoadXMLSong(): boolean; +var + //TempC: char; + Text: string; + CP: integer; // Current Player (0 or 1) + Count: integer; + Both: boolean; + Param1: integer; + Param2: integer; + Param3: integer; + ParamS: string; + I,J,X: integer; + + NoteType: Char; + SentenceEnd, Rest, Time: Integer; + Parser: TParser; +begin + Result := false; + + if not FileExists(Path + PathDelim + FileName) then + begin + Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()'); + exit; + end; + + MultBPM := 4; // multiply beat-count of note by 4 + Mult := 1; // accuracy of measurement of note + Base[0] := 100; // high number + Lines[0].ScoreValue := 0; + self.Relative := false; + Rel[0] := 0; + CP := 0; + Both := false; + + if Length(Player) = 2 then + Both := true; + + Parser := TParser.Create; + Parser.Settings.DashReplacement := '~'; + + for Count := 0 to High(Lines) do + begin + SetLength(Lines[Count].Line, 1); + Lines[Count].High := 0; + Lines[Count].Number := 1; + Lines[Count].Current := 0; + Lines[Count].Resolution := self.Resolution; + Lines[Count].NotesGAP := self.NotesGAP; + Lines[Count].Line[0].HighNote := -1; + Lines[Count].Line[0].LastLine := False; + end; + +//Try to Parse the Song + + if Parser.ParseSong(Path + PathDelim + FileName) then + begin +// Writeln('XML Inputfile Parsed succesful'); + //Start write parsed information to Song + //Notes Part + for I := 0 to High(Parser.SongInfo.Sentences) do + begin + //Add Notes + for J := 0 to High(Parser.SongInfo.Sentences[I].Notes) do + begin + case Parser.SongInfo.Sentences[I].Notes[J].NoteTyp of + NT_Normal: NoteType := ':'; + NT_Golden: NoteType := '*'; + NT_Freestyle: NoteType := 'F'; + end; + + Param1:=Parser.SongInfo.Sentences[I].Notes[J].Start; //Note Start + Param2:=Parser.SongInfo.Sentences[I].Notes[J].Duration; //Note Duration + Param3:=Parser.SongInfo.Sentences[I].Notes[J].Tone; //Note Tone + ParamS:=' ' + Parser.SongInfo.Sentences[I].Notes[J].Lyric; //Note Lyric + + if not Both then + // P1 + ParseNote(0, NoteType, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) + else + begin + // P1 + P2 + ParseNote(0, NoteType, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); + ParseNote(1, NoteType, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); + end; + + if not Both then + begin + Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; + Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(PChar(Lines[CP].Line[Lines[CP].High].Lyric)); + //Total Notes Patch + Lines[CP].Line[Lines[CP].High].TotalNotes := 0; + for X := low(Lines[CP].Line[Lines[CP].High].Note) to high(Lines[CP].Line[Lines[CP].High].Note) do + begin + if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType = ntGolden) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; + + if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType <> ntFreestyle) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; + end; + //Total Notes Patch End + end + else + begin + for Count := 0 to High(Lines) do + begin + Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; + Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); + //Total Notes Patch + Lines[Count].Line[Lines[Count].High].TotalNotes := 0; + for X := low(Lines[Count].Line[Lines[Count].High].Note) to high(Lines[Count].Line[Lines[Count].High].Note) do + begin + if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType = ntGolden) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; + if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType <> ntFreestyle) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; + + end; + //Total Notes Patch End + end; + end; { end of for loop } + + end; //J Forloop + + //Add Sentence break + if (I < High(Parser.SongInfo.Sentences)) then + begin + + SentenceEnd := Parser.SongInfo.Sentences[I].Notes[High(Parser.SongInfo.Sentences[I].Notes)].Start + Parser.SongInfo.Sentences[I].Notes[High(Parser.SongInfo.Sentences[I].Notes)].Duration; + Rest := Parser.SongInfo.Sentences[I+1].Notes[0].Start - SentenceEnd; + + //Calculate Time + case Rest of + 0, 1: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; + 2: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 1; + 3: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 2; + else + if (Rest >= 4) then + Time := SentenceEnd + 2 + else //Sentence overlapping :/ + Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; + end; + // new sentence + if not Both then + // P1 + NewSentence(0, (Time + Rel[0]) * Mult, Param2) + else + begin + // P1 + P2 + NewSentence(0, (Time + Rel[0]) * Mult, Param2); + NewSentence(1, (Time + Rel[1]) * Mult, Param2); + end; + + end; + end; + //End write parsed information to Song + Parser.Free; + end + else + begin + Log.LogError('Could not parse Inputfile: ' + Path + PathDelim + FileName); + exit; + end; + + for Count := 0 to High(Lines) do + begin + Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; + end; + + Result := true; +end; + +function TSong.ReadXMLHeader(const aFileName : WideString): boolean; +var + Line, Identifier, Value: string; + Temp : word; + Done : byte; + Parser : TParser; +begin + Result := true; + Done := 0; + +//Parse XML + Parser := TParser.Create; + Parser.Settings.DashReplacement := '~'; + + + if Parser.ParseSong(self.Path + self.FileName) then + begin + //----------- + //Required Attributes + //----------- + + //Title + self.Title := Parser.SongInfo.Header.Title; + + //Add Title Flag to Done + Done := Done or 1; + + //Artist + self.Artist := Parser.SongInfo.Header.Artist; + + //Add Artist Flag to Done + Done := Done or 2; + + //MP3 File //Test if Exists + self.Mp3 := platform.FindSongFile(Path, '*.mp3'); + if (FileExists(self.Path + self.Mp3)) then + //Add Mp3 Flag to Done + Done := Done or 4; + + //Beats per Minute + SetLength(self.BPM, 1); + self.BPM[0].StartBeat := 0; + + self.BPM[0].BPM := (Parser.SongInfo.Header.BPM * Parser.SongInfo.Header.Resolution/4 ) * Mult * MultBPM; + + if self.BPM[0].BPM <> 0 then + //Add BPM Flag to Done + Done := Done or 8; + + //--------- + //Additional Header Information + //--------- + + // Gap + self.GAP := Parser.SongInfo.Header.Gap; + + //Cover Picture + self.Cover := platform.FindSongFile(Path, '*[CO].jpg'); + + //Background Picture + self.Background := platform.FindSongFile(Path, '*[BG].jpg'); + + // Video File + // self.Video := Value + + // Video Gap + // self.VideoGAP := song_StrtoFloat( Value ) + + //Genre Sorting + self.Genre := Parser.SongInfo.Header.Genre; + + //Edition Sorting + self.Edition := Parser.SongInfo.Header.Edition; + + //Year Sorting + //Parser.SongInfo.Header.Year + + //Language Sorting + self.Language := Parser.SongInfo.Header.Language; + end else + Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName); + + Parser.Free; + + //Check if all Required Values are given + if (Done <> 15) then + begin + Result := False; + if (Done and 8) = 0 then //No BPM Flag + Log.LogError('BPM Tag Missing: ' + self.FileName) + else if (Done and 4) = 0 then //No MP3 Flag + Log.LogError('MP3 Tag/File Missing: ' + self.FileName) + else if (Done and 2) = 0 then //No Artist Flag + Log.LogError('Artist Tag Missing: ' + self.FileName) + else if (Done and 1) = 0 then //No Title Flag + Log.LogError('Title Tag Missing: ' + self.FileName) + else //unknown Error + Log.LogError('File Incomplete or not SingStar XML (B - '+ inttostr(Done) +'): ' + aFileName); + end; + +end; + + +function TSong.ReadTXTHeader(const aFileName : WideString): boolean; + + function song_StrtoFloat( aValue : string ) : Extended; + var + lValue : string; +// lOldDecimalSeparator : Char; // Auto Removed, Unused Variable + begin + lValue := aValue; + + if (Pos(',', lValue) <> 0) then + lValue[Pos(',', lValue)] := '.'; + + Result := StrToFloatDef(lValue, 0); + end; + +var + Line, Identifier, Value: string; + Temp : word; + Done : byte; +begin + Result := true; + Done := 0; + + //Read first Line + ReadLn (SongFile, Line); + + if (Length(Line)<=0) then + begin + Log.LogError('File Starts with Empty Line: ' + aFileName); + Result := False; + Exit; + end; + + //Read Lines while Line starts with # or its empty + while ( Length(Line) = 0 ) or + ( Line[1] = '#' ) do + begin + //Increase Line Number + Inc (FileLineNo); + Temp := Pos(':', Line); + + //Line has a Seperator-> Headerline + if (Temp <> 0) then + begin + //Read Identifier and Value + Identifier := Uppercase(Trim(Copy(Line, 2, Temp - 2))); //Uppercase is for Case Insensitive Checks + Value := Trim(Copy(Line, Temp + 1,Length(Line) - Temp)); + + //Check the Identifier (If Value is given) + if (Length(Value) <> 0) then + begin + + //----------- + //Required Attributes + //----------- + + {$IFDEF UTF8_FILENAMES} + if ((Identifier = 'MP3') or (Identifier = 'BACKGROUND') or (Identifier = 'COVER') or (Identifier = 'VIDEO')) then + Value := Utf8Encode(Value); + {$ENDIF} + + //Title + if (Identifier = 'TITLE') then + begin + self.Title := Value; + + //Add Title Flag to Done + Done := Done or 1; + end + + //Artist + else if (Identifier = 'ARTIST') then + begin + self.Artist := Value; + + //Add Artist Flag to Done + Done := Done or 2; + end + + //MP3 File //Test if Exists + else if (Identifier = 'MP3') AND + (FileExists(self.Path + Value)) then + begin + self.Mp3 := Value; + + //Add Mp3 Flag to Done + Done := Done or 4; + end + + //Beats per Minute + else if (Identifier = 'BPM') then + begin + SetLength(self.BPM, 1); + self.BPM[0].StartBeat := 0; + + self.BPM[0].BPM := song_StrtoFloat( Value ) * Mult * MultBPM; + + if self.BPM[0].BPM <> 0 then + begin + //Add BPM Flag to Done + Done := Done or 8; + end; + end + + //--------- + //Additional Header Information + //--------- + + // Gap + else if (Identifier = 'GAP') then + self.GAP := song_StrtoFloat( Value ) + + //Cover Picture + else if (Identifier = 'COVER') then + self.Cover := Value + + //Background Picture + else if (Identifier = 'BACKGROUND') then + self.Background := Value + + // Video File + else if (Identifier = 'VIDEO') then + begin + if (FileExists(self.Path + Value)) then + self.Video := Value + else + Log.LogError('Can''t find Video File in Song: ' + aFileName); + end + + // Video Gap + else if (Identifier = 'VIDEOGAP') then + self.VideoGAP := song_StrtoFloat( Value ) + + //Genre Sorting + else if (Identifier = 'GENRE') then + self.Genre := Value + + //Edition Sorting + else if (Identifier = 'EDITION') then + self.Edition := Value + + //Creator Tag + else if (Identifier = 'CREATOR') then + self.Creator := Value + + //Language Sorting + else if (Identifier = 'LANGUAGE') then + self.Language := Value + + // Song Start + else if (Identifier = 'START') then + self.Start := song_StrtoFloat( Value ) + + // Song Ending + else if (Identifier = 'END') then + TryStrtoInt(Value, self.Finish) + + // Resolution + else if (Identifier = 'RESOLUTION') then + TryStrtoInt(Value, self.Resolution) + + // Notes Gap + else if (Identifier = 'NOTESGAP') then + TryStrtoInt(Value, self.NotesGAP) + // Relative Notes + else if (Identifier = 'RELATIVE') AND (uppercase(Value) = 'YES') then + self.Relative := True; + + end; + end; + + if not EOf(SongFile) then + ReadLn (SongFile, Line) + else + begin + Result := False; + Log.LogError('File Incomplete or not Ultrastar TxT (A): ' + aFileName); + break; + end; + + end; + + if self.Cover = '' then + self.Cover := platform.FindSongFile(Path, '*[CO].jpg'); + + //Check if all Required Values are given + if (Done <> 15) then + begin + Result := False; + if (Done and 8) = 0 then //No BPM Flag + Log.LogError('BPM Tag Missing: ' + self.FileName) + else if (Done and 4) = 0 then //No MP3 Flag + Log.LogError('MP3 Tag/File Missing: ' + self.FileName) + else if (Done and 2) = 0 then //No Artist Flag + Log.LogError('Artist Tag Missing: ' + self.FileName) + else if (Done and 1) = 0 then //No Title Flag + Log.LogError('Title Tag Missing: ' + self.FileName) + else //unknown Error + Log.LogError('File Incomplete or not Ultrastar TxT (B - '+ inttostr(Done) +'): ' + aFileName); + end; + +end; + +procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); +//var +// Space: boolean; // Auto Removed, Unused Variable +begin + case Ini.Solmization of + 1: // european + begin + case (NoteP mod 12) of + 0..1: LyricS := ' do '; + 2..3: LyricS := ' re '; + 4: LyricS := ' mi '; + 5..6: LyricS := ' fa '; + 7..8: LyricS := ' sol '; + 9..10: LyricS := ' la '; + 11: LyricS := ' si '; + end; + end; + 2: // japanese + begin + case (NoteP mod 12) of + 0..1: LyricS := ' do '; + 2..3: LyricS := ' re '; + 4: LyricS := ' mi '; + 5..6: LyricS := ' fa '; + 7..8: LyricS := ' so '; + 9..10: LyricS := ' la '; + 11: LyricS := ' shi '; + end; + end; + 3: // american + begin + case (NoteP mod 12) of + 0..1: LyricS := ' do '; + 2..3: LyricS := ' re '; + 4: LyricS := ' mi '; + 5..6: LyricS := ' fa '; + 7..8: LyricS := ' sol '; + 9..10: LyricS := ' la '; + 11: LyricS := ' ti '; + end; + end; + end; // case + + with Lines[LineNumber].Line[Lines[LineNumber].High] do + begin + SetLength(Note, Length(Note) + 1); + HighNote := High(Note); + + Note[HighNote].Start := StartP; + if HighNote = 0 then + begin + if Lines[LineNumber].Number = 1 then + Start := -100; +// Start := Note[HighNote].Start; + end; + + Note[HighNote].Length := DurationP; + + // back to the normal system with normal, golden and now freestyle notes + case TypeP of + 'F': Note[HighNote].NoteType := ntFreestyle; + ':': Note[HighNote].NoteType := ntNormal; + '*': Note[HighNote].NoteType := ntGolden; + end; + + if (Note[HighNote].NoteType = ntGolden) then + Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; + + if (Note[HighNote].NoteType <> ntFreestyle) then + Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; + + Note[HighNote].Tone := NoteP; + if Note[HighNote].Tone < Base[LineNumber] then Base[LineNumber] := Note[HighNote].Tone; + + Note[HighNote].Text := Copy(LyricS, 2, 100); + Lyric := Lyric + Note[HighNote].Text; + + End_ := Note[HighNote].Start + Note[HighNote].Length; + end; // with +end; + +procedure TSong.NewSentence(LineNumberP: integer; Param1, Param2: integer); +var + I: integer; +begin + + // stara czesc //Alter Satz //Update Old Part + Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; + Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(PChar(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric)); + + //Total Notes Patch + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; + for I := low(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) to high(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) do + begin + if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType = ntGolden) then + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; + + if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType <> ntFreestyle) then + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; + end; + //Total Notes Patch End + + + // nowa czesc //Neuer Satz //Update New Part + SetLength(Lines[LineNumberP].Line, Lines[LineNumberP].Number + 1); + Lines[LineNumberP].High := Lines[LineNumberP].High + 1; + Lines[LineNumberP].Number := Lines[LineNumberP].Number + 1; + Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote := -1; + + if self.Relative then + begin + Lines[LineNumberP].Line[Lines[LineNumberP].High].Start := Param1; + Rel[LineNumberP] := Rel[LineNumberP] + Param2; + end + else + Lines[LineNumberP].Line[Lines[LineNumberP].High].Start := Param1; + + Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := False; + + Base[LineNumberP] := 100; // high number +end; + +procedure TSong.clear(); +begin + //Main Information + Title := ''; + Artist := ''; + + //Sortings: + Genre := 'Unknown'; + Edition := 'Unknown'; + Language := 'Unknown'; //Language Patch + + //Required Information + Mp3 := ''; + {$IFDEF FPC} + setlength( BPM, 0 ); + {$ELSE} + BPM := nil; + {$ENDIF} + + GAP := 0; + Start := 0; + Finish := 0; + + //Additional Information + Background := ''; + Cover := ''; + Video := ''; + VideoGAP := 0; + NotesGAP := 0; + Resolution := 4; + Creator := ''; + +end; + +function TSong.Analyse(): boolean; +begin + Result := False; + + //Reset LineNo + FileLineNo := 0; + + //Open File and set File Pointer to the beginning + AssignFile(SongFile, self.Path + self.FileName); + + try + Reset(SongFile); + + //Clear old Song Header + self.clear; + + //Read Header + Result := self.ReadTxTHeader( FileName ) + + //And Close File + finally + CloseFile(SongFile); + end; +end; + + +function TSong.AnalyseXML(): boolean; +begin + Result := False; + + //Reset LineNo + FileLineNo := 0; + + //Clear old Song Header + self.clear; + + //Read Header + Result := self.ReadXMLHeader( FileName ); + +end; + +end. -- cgit v1.2.3 From 76cf2462d732357522cc6aadcf66027bd55cad0f Mon Sep 17 00:00:00 2001 From: tobigun Date: Sat, 13 Sep 2008 11:26:03 +0000 Subject: SourceForge patch [2086204] applied. Thanks hawkear. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1378 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 316 ++++++++++++++++++++++++++--------------------------- 1 file changed, 154 insertions(+), 162 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 3517bce6..a99ca4a4 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -234,8 +234,8 @@ begin Lines[Count].Line[0].LastLine := False; end; - // TempC := ':'; - // TempC := Text[1]; // read from backup variable, don't use default ':' value + //TempC := ':'; + //TempC := Text[1]; // read from backup variable, don't use default ':' value while (TempC <> 'E') AND (not EOF(SongFile)) do begin @@ -248,20 +248,19 @@ begin Read(SongFile, Param3); Read(SongFile, ParamS); - - //Check for ZeroNote - if Param2 = 0 then Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') else - begin - // add notes - if not Both then - // P1 - ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) - else begin - // P1 + P2 - ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); - ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); - end; - end; //Zeronote check + //Check for ZeroNote + if Param2 = 0 then Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') else + begin + // add notes + if not Both then + // P1 + ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) + else begin + // P1 + P2 + ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); + ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); + end; + end; //Zeronote check end; // if if TempC = '-' then @@ -402,11 +401,12 @@ begin Lines[Count].Line[0].LastLine := False; end; -//Try to Parse the Song + //Try to Parse the Song if Parser.ParseSong(Path + PathDelim + FileName) then begin -// Writeln('XML Inputfile Parsed succesful'); + //Writeln('XML Inputfile Parsed succesful'); + //Start write parsed information to Song //Notes Part for I := 0 to High(Parser.SongInfo.Sentences) do @@ -414,93 +414,90 @@ begin //Add Notes for J := 0 to High(Parser.SongInfo.Sentences[I].Notes) do begin - case Parser.SongInfo.Sentences[I].Notes[J].NoteTyp of - NT_Normal: NoteType := ':'; - NT_Golden: NoteType := '*'; - NT_Freestyle: NoteType := 'F'; - end; - - Param1:=Parser.SongInfo.Sentences[I].Notes[J].Start; //Note Start - Param2:=Parser.SongInfo.Sentences[I].Notes[J].Duration; //Note Duration - Param3:=Parser.SongInfo.Sentences[I].Notes[J].Tone; //Note Tone - ParamS:=' ' + Parser.SongInfo.Sentences[I].Notes[J].Lyric; //Note Lyric - - if not Both then - // P1 - ParseNote(0, NoteType, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) - else - begin - // P1 + P2 - ParseNote(0, NoteType, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); - ParseNote(1, NoteType, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); - end; + case Parser.SongInfo.Sentences[I].Notes[J].NoteTyp of + NT_Normal: NoteType := ':'; + NT_Golden: NoteType := '*'; + NT_Freestyle: NoteType := 'F'; + end; - if not Both then - begin - Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; - Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(PChar(Lines[CP].Line[Lines[CP].High].Lyric)); - //Total Notes Patch - Lines[CP].Line[Lines[CP].High].TotalNotes := 0; - for X := low(Lines[CP].Line[Lines[CP].High].Note) to high(Lines[CP].Line[Lines[CP].High].Note) do - begin - if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType = ntGolden) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; - - if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType <> ntFreestyle) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; - end; - //Total Notes Patch End - end - else - begin - for Count := 0 to High(Lines) do - begin - Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; - Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); - //Total Notes Patch - Lines[Count].Line[Lines[Count].High].TotalNotes := 0; - for X := low(Lines[Count].Line[Lines[Count].High].Note) to high(Lines[Count].Line[Lines[Count].High].Note) do - begin - if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType = ntGolden) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; - if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType <> ntFreestyle) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; - - end; - //Total Notes Patch End - end; - end; { end of for loop } + Param1:=Parser.SongInfo.Sentences[I].Notes[J].Start; //Note Start + Param2:=Parser.SongInfo.Sentences[I].Notes[J].Duration; //Note Duration + Param3:=Parser.SongInfo.Sentences[I].Notes[J].Tone; //Note Tone + ParamS:=' ' + Parser.SongInfo.Sentences[I].Notes[J].Lyric; //Note Lyric + + if not Both then + // P1 + ParseNote(0, NoteType, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) + else + begin + // P1 + P2 + ParseNote(0, NoteType, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); + ParseNote(1, NoteType, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); + end; + + if not Both then + begin + Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; + Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(PChar(Lines[CP].Line[Lines[CP].High].Lyric)); + //Total Notes Patch + Lines[CP].Line[Lines[CP].High].TotalNotes := 0; + for X := 0 to high(Lines[CP].Line[Lines[CP].High].Note) do + begin + if (Lines[CP].Line[Lines[CP].High].Note[X].NoteType = ntGolden) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; + + if (Lines[CP].Line[Lines[CP].High].Note[X].NoteType <> ntFreestyle) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; + end; + //Total Notes Patch End + end + else + begin + for Count := 0 to High(Lines) do + begin + Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; + Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); + //Total Notes Patch + Lines[Count].Line[Lines[Count].High].TotalNotes := 0; + for X := 0 to high(Lines[Count].Line[Lines[Count].High].Note) do + begin + if (Lines[Count].Line[Lines[Count].High].Note[X].NoteType = ntGolden) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; + if (Lines[Count].Line[Lines[Count].High].Note[X].NoteType <> ntFreestyle) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; + + end; + //Total Notes Patch End + end; + end; { end of for loop } end; //J Forloop - //Add Sentence break + //Add Sentence break if (I < High(Parser.SongInfo.Sentences)) then begin - - SentenceEnd := Parser.SongInfo.Sentences[I].Notes[High(Parser.SongInfo.Sentences[I].Notes)].Start + Parser.SongInfo.Sentences[I].Notes[High(Parser.SongInfo.Sentences[I].Notes)].Duration; - Rest := Parser.SongInfo.Sentences[I+1].Notes[0].Start - SentenceEnd; - - //Calculate Time - case Rest of - 0, 1: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; - 2: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 1; - 3: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 2; - else - if (Rest >= 4) then - Time := SentenceEnd + 2 - else //Sentence overlapping :/ - Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; - end; - // new sentence - if not Both then - // P1 - NewSentence(0, (Time + Rel[0]) * Mult, Param2) - else - begin - // P1 + P2 - NewSentence(0, (Time + Rel[0]) * Mult, Param2); - NewSentence(1, (Time + Rel[1]) * Mult, Param2); - end; + SentenceEnd := Parser.SongInfo.Sentences[I].Notes[High(Parser.SongInfo.Sentences[I].Notes)].Start + Parser.SongInfo.Sentences[I].Notes[High(Parser.SongInfo.Sentences[I].Notes)].Duration; + Rest := Parser.SongInfo.Sentences[I+1].Notes[0].Start - SentenceEnd; + + //Calculate Time + case Rest of + 0, 1: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; + 2: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 1; + 3: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 2; + else + if (Rest >= 4) then + Time := SentenceEnd + 2 + else //Sentence overlapping :/ + Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; + end; + // new sentence + if not Both then // P1 + NewSentence(0, (Time + Rel[0]) * Mult, Param2) + else + begin // P1 + P2 + NewSentence(0, (Time + Rel[0]) * Mult, Param2); + NewSentence(1, (Time + Rel[1]) * Mult, Param2); + end; end; end; @@ -531,79 +528,78 @@ begin Result := true; Done := 0; -//Parse XML - Parser := TParser.Create; - Parser.Settings.DashReplacement := '~'; + //Parse XML + Parser := TParser.Create; + Parser.Settings.DashReplacement := '~'; + if Parser.ParseSong(self.Path + self.FileName) then + begin + //----------- + //Required Attributes + //----------- - if Parser.ParseSong(self.Path + self.FileName) then - begin - //----------- - //Required Attributes - //----------- - - //Title - self.Title := Parser.SongInfo.Header.Title; + //Title + self.Title := Parser.SongInfo.Header.Title; - //Add Title Flag to Done - Done := Done or 1; + //Add Title Flag to Done + Done := Done or 1; - //Artist - self.Artist := Parser.SongInfo.Header.Artist; + //Artist + self.Artist := Parser.SongInfo.Header.Artist; - //Add Artist Flag to Done - Done := Done or 2; + //Add Artist Flag to Done + Done := Done or 2; - //MP3 File //Test if Exists - self.Mp3 := platform.FindSongFile(Path, '*.mp3'); - if (FileExists(self.Path + self.Mp3)) then - //Add Mp3 Flag to Done - Done := Done or 4; + //MP3 File //Test if Exists + self.Mp3 := platform.FindSongFile(Path, '*.mp3'); + //Add Mp3 Flag to Done + if (FileExists(self.Path + self.Mp3)) then + Done := Done or 4; - //Beats per Minute - SetLength(self.BPM, 1); - self.BPM[0].StartBeat := 0; + //Beats per Minute + SetLength(self.BPM, 1); + self.BPM[0].StartBeat := 0; - self.BPM[0].BPM := (Parser.SongInfo.Header.BPM * Parser.SongInfo.Header.Resolution/4 ) * Mult * MultBPM; + self.BPM[0].BPM := (Parser.SongInfo.Header.BPM * Parser.SongInfo.Header.Resolution/4 ) * Mult * MultBPM; - if self.BPM[0].BPM <> 0 then - //Add BPM Flag to Done - Done := Done or 8; + //Add BPM Flag to Done + if self.BPM[0].BPM <> 0 then + Done := Done or 8; - //--------- - //Additional Header Information - //--------- + //--------- + //Additional Header Information + //--------- - // Gap - self.GAP := Parser.SongInfo.Header.Gap; + // Gap + self.GAP := Parser.SongInfo.Header.Gap; - //Cover Picture - self.Cover := platform.FindSongFile(Path, '*[CO].jpg'); + //Cover Picture + self.Cover := platform.FindSongFile(Path, '*[CO].jpg'); - //Background Picture - self.Background := platform.FindSongFile(Path, '*[BG].jpg'); + //Background Picture + self.Background := platform.FindSongFile(Path, '*[BG].jpg'); - // Video File - // self.Video := Value + // Video File + // self.Video := Value - // Video Gap - // self.VideoGAP := song_StrtoFloat( Value ) + // Video Gap + // self.VideoGAP := song_StrtoFloat( Value ) - //Genre Sorting - self.Genre := Parser.SongInfo.Header.Genre; + //Genre Sorting + self.Genre := Parser.SongInfo.Header.Genre; - //Edition Sorting - self.Edition := Parser.SongInfo.Header.Edition; + //Edition Sorting + self.Edition := Parser.SongInfo.Header.Edition; - //Year Sorting - //Parser.SongInfo.Header.Year + //Year Sorting + //Parser.SongInfo.Header.Year - //Language Sorting - self.Language := Parser.SongInfo.Header.Language; - end else - Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName); + //Language Sorting + self.Language := Parser.SongInfo.Header.Language; + end else + Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName); - Parser.Free; + Parser.Free; //Check if all Required Values are given if (Done <> 15) then @@ -629,7 +625,6 @@ function TSong.ReadTXTHeader(const aFileName : WideString): boolean; function song_StrtoFloat( aValue : string ) : Extended; var lValue : string; -// lOldDecimalSeparator : Char; // Auto Removed, Unused Variable begin lValue := aValue; @@ -650,7 +645,7 @@ begin //Read first Line ReadLn (SongFile, Line); - if (Length(Line)<=0) then + if (Length(Line) <= 0) then begin Log.LogError('File Starts with Empty Line: ' + aFileName); Result := False; @@ -658,8 +653,8 @@ begin end; //Read Lines while Line starts with # or its empty - while ( Length(Line) = 0 ) or - ( Line[1] = '#' ) do + while (Length(Line) = 0) or + (Line[1] = '#') do begin //Increase Line Number Inc (FileLineNo); @@ -675,14 +670,13 @@ begin //Check the Identifier (If Value is given) if (Length(Value) <> 0) then begin - //----------- //Required Attributes //----------- {$IFDEF UTF8_FILENAMES} - if ((Identifier = 'MP3') or (Identifier = 'BACKGROUND') or (Identifier = 'COVER') or (Identifier = 'VIDEO')) then - Value := Utf8Encode(Value); + if ((Identifier = 'MP3') or (Identifier = 'BACKGROUND') or (Identifier = 'COVER') or (Identifier = 'VIDEO')) then + Value := Utf8Encode(Value); {$ENDIF} //Title @@ -828,8 +822,6 @@ begin end; procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); -//var -// Space: boolean; // Auto Removed, Unused Variable begin case Ini.Solmization of 1: // european @@ -880,7 +872,7 @@ begin begin if Lines[LineNumber].Number = 1 then Start := -100; -// Start := Note[HighNote].Start; + //Start := Note[HighNote].Start; end; Note[HighNote].Length := DurationP; -- cgit v1.2.3 From b8888af755c5ce6102d66bb057fc7e8d4b128b74 Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Sat, 13 Sep 2008 12:04:40 +0000 Subject: rename X: integer to NoteIndex: integer git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1379 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index a99ca4a4..b3410550 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -360,7 +360,8 @@ var Param2: integer; Param3: integer; ParamS: string; - I,J,X: integer; + I, J: integer; + NoteIndex: integer; NoteType: Char; SentenceEnd, Rest, Time: Integer; @@ -441,13 +442,13 @@ begin Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(PChar(Lines[CP].Line[Lines[CP].High].Lyric)); //Total Notes Patch Lines[CP].Line[Lines[CP].High].TotalNotes := 0; - for X := 0 to high(Lines[CP].Line[Lines[CP].High].Note) do + for NoteIndex := 0 to high(Lines[CP].Line[Lines[CP].High].Note) do begin - if (Lines[CP].Line[Lines[CP].High].Note[X].NoteType = ntGolden) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; + if (Lines[CP].Line[Lines[CP].High].Note[NoteIndex].NoteType = ntGolden) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[NoteIndex].Length; - if (Lines[CP].Line[Lines[CP].High].Note[X].NoteType <> ntFreestyle) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[X].Length; + if (Lines[CP].Line[Lines[CP].High].Note[NoteIndex].NoteType <> ntFreestyle) then + Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[NoteIndex].Length; end; //Total Notes Patch End end @@ -459,12 +460,12 @@ begin Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); //Total Notes Patch Lines[Count].Line[Lines[Count].High].TotalNotes := 0; - for X := 0 to high(Lines[Count].Line[Lines[Count].High].Note) do + for NoteIndex := 0 to high(Lines[Count].Line[Lines[Count].High].Note) do begin - if (Lines[Count].Line[Lines[Count].High].Note[X].NoteType = ntGolden) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; - if (Lines[Count].Line[Lines[Count].High].Note[X].NoteType <> ntFreestyle) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[X].Length; + if (Lines[Count].Line[Lines[Count].High].Note[NoteIndex].NoteType = ntGolden) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[NoteIndex].Length; + if (Lines[Count].Line[Lines[Count].High].Note[NoteIndex].NoteType <> ntFreestyle) then + Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[NoteIndex].Length; end; //Total Notes Patch End -- cgit v1.2.3 From b0dcfe05f53197bd9f159e46d6cbc2cd3ebff5ca Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Sat, 13 Sep 2008 12:18:08 +0000 Subject: minor layout changes. no code change git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1380 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 55 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 19 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index b3410550..e5a7cf57 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -168,6 +168,7 @@ var Param3: integer; ParamS: string; I: integer; + begin Result := false; @@ -307,7 +308,9 @@ begin Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; end; //Total Notes Patch End - end else begin + end + else + begin for Count := 0 to High(Lines) do begin Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; @@ -350,22 +353,24 @@ end; //Load XML Song function TSong.LoadXMLSong(): boolean; + var - //TempC: char; - Text: string; - CP: integer; // Current Player (0 or 1) - Count: integer; - Both: boolean; - Param1: integer; - Param2: integer; - Param3: integer; - ParamS: string; - I, J: integer; + //TempC: char; + Text: string; + CP: integer; // Current Player (0 or 1) + Count: integer; + Both: boolean; + Param1: integer; + Param2: integer; + Param3: integer; + ParamS: string; + I, J: integer; NoteIndex: integer; - NoteType: Char; - SentenceEnd, Rest, Time: Integer; + NoteType: char; + SentenceEnd, Rest, Time: integer; Parser: TParser; + begin Result := false; @@ -520,11 +525,13 @@ begin end; function TSong.ReadXMLHeader(const aFileName : WideString): boolean; + var Line, Identifier, Value: string; Temp : word; Done : byte; Parser : TParser; + begin Result := true; Done := 0; @@ -624,8 +631,10 @@ end; function TSong.ReadTXTHeader(const aFileName : WideString): boolean; function song_StrtoFloat( aValue : string ) : Extended; + var lValue : string; + begin lValue := aValue; @@ -639,6 +648,7 @@ var Line, Identifier, Value: string; Temp : word; Done : byte; + begin Result := true; Done := 0; @@ -823,6 +833,7 @@ begin end; procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); + begin case Ini.Solmization of 1: // european @@ -902,8 +913,10 @@ begin end; procedure TSong.NewSentence(LineNumberP: integer; Param1, Param2: integer); + var I: integer; + begin // stara czesc //Alter Satz //Update Old Part @@ -943,6 +956,7 @@ begin end; procedure TSong.clear(); + begin //Main Information Title := ''; @@ -976,7 +990,9 @@ begin end; + function TSong.Analyse(): boolean; + begin Result := False; @@ -987,15 +1003,15 @@ begin AssignFile(SongFile, self.Path + self.FileName); try - Reset(SongFile); + Reset(SongFile); - //Clear old Song Header - self.clear; + //Clear old Song Header + self.clear; - //Read Header - Result := self.ReadTxTHeader( FileName ) + //Read Header + Result := self.ReadTxTHeader( FileName ) - //And Close File + //And Close File finally CloseFile(SongFile); end; @@ -1003,6 +1019,7 @@ end; function TSong.AnalyseXML(): boolean; + begin Result := False; -- cgit v1.2.3 From a40eb015f8dc43ee087bb8374e67c6a75eb9fbc6 Mon Sep 17 00:00:00 2001 From: tobigun Date: Sat, 13 Sep 2008 13:02:27 +0000 Subject: - stop both Video and Visualizer (because of the video-toggle with 'v'-key both could have been active) (See SF-tracker Patch 2078902) - VideoLoaded does not belong to the song state anymore git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1381 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 1 - 1 file changed, 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index e5a7cf57..8229b9d9 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -80,7 +80,6 @@ type Background: WideString; Video: WideString; VideoGAP: real; - VideoLoaded: boolean; // true if the video has been loaded NotesGAP: integer; Start: real; // in seconds Finish: integer; // in miliseconds -- cgit v1.2.3 From dbf39d5bfc56c24a67d481187c619dc84828221f Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Tue, 23 Sep 2008 21:17:22 +0000 Subject: gpl header added and property svn:header set to "HeadURL Id" git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1403 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 8229b9d9..66288503 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -1,3 +1,28 @@ +{* UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + *} + unit USong; interface -- cgit v1.2.3 From 015b6c092b0779ee9b53ed1ee78044737f8dc592 Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Tue, 23 Sep 2008 21:43:52 +0000 Subject: indentation unified, no code change. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1406 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 66288503..0f36662b 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -34,29 +34,29 @@ interface {$I switches.inc} uses - {$IFDEF MSWINDOWS} + {$IFDEF MSWINDOWS} Windows, - {$ELSE} - {$IFNDEF DARWIN} - syscall, - {$ENDIF} - baseunix, - UnixType, + {$ELSE} + {$IFNDEF DARWIN} + syscall, {$ENDIF} - SysUtils, - Classes, - UPlatform, - ULog, - UTexture, - UCommon, - {$IFDEF DARWIN} + baseunix, + UnixType, + {$ENDIF} + SysUtils, + Classes, + UPlatform, + ULog, + UTexture, + UCommon, + {$IFDEF DARWIN} cthreads, - {$ENDIF} - {$IFDEF USE_PSEUDO_THREAD} + {$ENDIF} + {$IFDEF USE_PSEUDO_THREAD} PseudoThread, - {$ENDIF} - UCatCovers, - UXMLSong; + {$ENDIF} + UCatCovers, + UXMLSong; type -- cgit v1.2.3 From e5222f99929e0a893fca4ea0ffe08c3bb90fd5c3 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sun, 28 Sep 2008 16:30:08 +0000 Subject: Songclass now reports an error if there is no linebreak in a txt file. Error is written to log. Added detailed error description to ERROR_CORRUPT_SONG Popup. Some translation may be added to this one git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1423 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 0f36662b..3679863b 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -129,6 +129,8 @@ type Mult : integer; MultBPM : integer; + LastError: String; + constructor Create (); overload; constructor Create ( const aFileName : WideString ); overload; function LoadSong: boolean; @@ -159,6 +161,8 @@ begin MultBPM := 4; fFileName := aFileName; + LastError := ''; + if fileexists( aFileName ) then begin self.Path := ExtractFilePath( aFileName ); @@ -195,9 +199,11 @@ var begin Result := false; + LastError := ''; if not FileExists(Path + PathDelim + FileName) then begin + LastError := 'File not found'; Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()'); exit; end; @@ -240,7 +246,7 @@ begin begin //Song File Corrupted - No Notes CloseFile(SongFile); Log.LogError('Could not load txt File, no Notes found: ' + FileName); - Result := False; + LastError := 'Can''t find any notes'; Exit; end; Read(SongFile, TempC); @@ -361,6 +367,16 @@ begin end; CloseFile(SongFile); + + For I := 0 to High(Lines) do + begin + If ((Both) or (I = 0)) AND (Length(Lines[I].Line) < 2) then + begin + LastError := 'Can''t find any linebreaks'; + Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"'); + exit; + end; + end; except try CloseFile(SongFile); @@ -368,6 +384,7 @@ begin end; + LastError := 'Error reading line ' + inttostr(FileLineNo); Log.LogError('Error Loading File: "' + fFileName + '" in Line ' + inttostr(FileLineNo)); exit; end; -- cgit v1.2.3 From 276411ffc65aa73fce9fdc1bec7555d6df76357c Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sun, 28 Sep 2008 18:51:06 +0000 Subject: Fixed some minor bugs in txt file reader Added workaround for empty sentences. Ignores the emtpy sentences and use values from 2nd linebreak. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1425 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 92 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 36 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 3679863b..47ac0a30 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -233,9 +233,6 @@ begin if (self.FileName = '') then self.Filename := ExtractFileName(FileName); - Result := False; - - Reset(SongFile); FileLineNo := 0; //Search for Note Begining repeat @@ -292,9 +289,9 @@ begin ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); end; end; //Zeronote check - end; // if + end // if - if TempC = '-' then + Else if TempC = '-' then begin // reads sentence Read(SongFile, Param1); @@ -309,9 +306,9 @@ begin NewSentence(0, (Param1 + Rel[0]) * Mult, Param2); NewSentence(1, (Param1 + Rel[1]) * Mult, Param2); end; - end; // if + end // if - if TempC = 'B' then + Else if TempC = 'B' then begin SetLength(self.BPM, Length(self.BPM) + 1); Read(SongFile, self.BPM[High(self.BPM)].StartBeat); @@ -342,7 +339,7 @@ begin else begin for Count := 0 to High(Lines) do - begin + begin Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); //Total Notes Patch @@ -357,26 +354,40 @@ begin //Total Notes Patch End end; end; + ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32) + Read(SongFile, TempC); Inc(FileLineNo); end; // while} - for Count := 0 to High(Lines) do - begin - Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; - end; - CloseFile(SongFile); For I := 0 to High(Lines) do begin - If ((Both) or (I = 0)) AND (Length(Lines[I].Line) < 2) then + If ((Both) or (I = 0)) then begin - LastError := 'Can''t find any linebreaks'; - Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"'); - exit; + If (Length(Lines[I].Line) < 2) then + begin + LastError := 'Can''t find any linebreaks'; + Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"'); + exit; + end; + + If (Lines[I].Line[Lines[I].High].HighNote < 0) then + begin + SetLength(Lines[I].Line, Lines[I].Number - 1); + Lines[I].High := Lines[I].High - 1; + Lines[I].Number := Lines[I].Number - 1; + Log.LogError('Error loading Song, sentence w/o note found in last line before E: ' + Filename); + end; end; end; + + for Count := 0 to High(Lines) do + begin + If (High(Lines[Count].Line) >= 0) then + Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; + end; except try CloseFile(SongFile); @@ -414,6 +425,7 @@ var begin Result := false; + LastError := ''; if not FileExists(Path + PathDelim + FileName) then begin @@ -936,7 +948,7 @@ begin ':': Note[HighNote].NoteType := ntNormal; '*': Note[HighNote].NoteType := ntGolden; end; - + if (Note[HighNote].NoteType = ntGolden) then Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; @@ -960,27 +972,35 @@ var begin - // stara czesc //Alter Satz //Update Old Part - Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; - Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(PChar(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric)); + If (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then + begin //Update old Sentence if it has notes and create a new sentence + // stara czesc //Alter Satz //Update Old Part + Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; + Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(PChar(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric)); + + //Total Notes Patch + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; + for I := low(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) to high(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) do + begin + if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType = ntGolden) then + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; + + if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType <> ntFreestyle) then + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; + end; + //Total Notes Patch End - //Total Notes Patch - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; - for I := low(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) to high(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) do - begin - if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType = ntGolden) then - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; - - if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType <> ntFreestyle) then - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; - end; - //Total Notes Patch End + // nowa czesc //Neuer Satz //Update New Part + SetLength(Lines[LineNumberP].Line, Lines[LineNumberP].Number + 1); + Lines[LineNumberP].High := Lines[LineNumberP].High + 1; + Lines[LineNumberP].Number := Lines[LineNumberP].Number + 1; + end + else + begin //Use old Sentence if it has no notes + Log.LogError('Error loading Song, sentence w/o note found in line ' + InttoStr(FileLineNo) + ': ' + Filename); + end; - // nowa czesc //Neuer Satz //Update New Part - SetLength(Lines[LineNumberP].Line, Lines[LineNumberP].Number + 1); - Lines[LineNumberP].High := Lines[LineNumberP].High + 1; - Lines[LineNumberP].Number := Lines[LineNumberP].Number + 1; Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote := -1; if self.Relative then -- cgit v1.2.3 From 528d8cd40ec3763bb3018da4829803404d1cd04b Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Thu, 9 Oct 2008 17:57:10 +0000 Subject: Errormessages during songload now translatable German and English translations updated Added four new language strings: ERROR_CORRUPT_SONG_FILE_NOT_FOUND ERROR_CORRUPT_SONG_NO_NOTES ERROR_CORRUPT_SONG_NO_BREAKS ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1443 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 47ac0a30..6c81cecc 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -130,6 +130,9 @@ type MultBPM : integer; LastError: String; + Function GetErrorLineNo: Integer; + Property ErrorLineNo: Integer read GetErrorLineNo; + constructor Create (); overload; constructor Create ( const aFileName : WideString ); overload; @@ -203,7 +206,7 @@ begin if not FileExists(Path + PathDelim + FileName) then begin - LastError := 'File not found'; + LastError := 'ERROR_CORRUPT_SONG_FILE_NOT_FOUND'; Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()'); exit; end; @@ -243,7 +246,7 @@ begin begin //Song File Corrupted - No Notes CloseFile(SongFile); Log.LogError('Could not load txt File, no Notes found: ' + FileName); - LastError := 'Can''t find any notes'; + LastError := 'ERROR_CORRUPT_SONG_NO_NOTES'; Exit; end; Read(SongFile, TempC); @@ -368,7 +371,7 @@ begin begin If (Length(Lines[I].Line) < 2) then begin - LastError := 'Can''t find any linebreaks'; + LastError := 'ERROR_CORRUPT_SONG_NO_BREAKS'; Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"'); exit; end; @@ -395,7 +398,7 @@ begin end; - LastError := 'Error reading line ' + inttostr(FileLineNo); + LastError := 'ERROR_CORRUPT_SONG_ERROR_IN_LINE'; Log.LogError('Error Loading File: "' + fFileName + '" in Line ' + inttostr(FileLineNo)); exit; end; @@ -885,6 +888,14 @@ begin end; +Function TSong.GetErrorLineNo: Integer; +begin + If (LastError='ERROR_CORRUPT_SONG_ERROR_IN_LINE') then + Result := FileLineNo + Else + Result := -1; +end; + procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); begin -- cgit v1.2.3 From e8a388e32a4563ac9ea0895ca6c7cdf83cf9d3ec Mon Sep 17 00:00:00 2001 From: tobigun Date: Tue, 28 Oct 2008 18:57:02 +0000 Subject: - glPrint(Pchar) -> glPrint(string) - glPrintLetter removed - font engine handles FT_PIXEL_MODE_MONO as FT_Glyph_To_Bitmap(FT_RENDER_MODE_NORMAL) might return a 1bit/pixel black/white image instead of 8bit/pixel gray shaded one (happened with 16px japanese glyphs of simsun.ttf, latin ones were correct). git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1482 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 6c81cecc..4793b7e9 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -326,7 +326,7 @@ begin if not Both then begin Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; - Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(PChar(Lines[CP].Line[Lines[CP].High].Lyric)); + Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(Lines[CP].Line[Lines[CP].High].Lyric); //Total Notes Patch Lines[CP].Line[Lines[CP].High].TotalNotes := 0; for I := low(Lines[CP].Line[Lines[CP].High].Note) to high(Lines[CP].Line[Lines[CP].High].Note) do @@ -344,7 +344,7 @@ begin for Count := 0 to High(Lines) do begin Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; - Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); + Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); //Total Notes Patch Lines[Count].Line[Lines[Count].High].TotalNotes := 0; for I := low(Lines[Count].Line[Lines[Count].High].Note) to high(Lines[Count].Line[Lines[Count].High].Note) do @@ -500,7 +500,7 @@ begin if not Both then begin Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; - Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(PChar(Lines[CP].Line[Lines[CP].High].Lyric)); + Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(Lines[CP].Line[Lines[CP].High].Lyric); //Total Notes Patch Lines[CP].Line[Lines[CP].High].TotalNotes := 0; for NoteIndex := 0 to high(Lines[CP].Line[Lines[CP].High].Note) do @@ -518,7 +518,7 @@ begin for Count := 0 to High(Lines) do begin Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; - Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(PChar(Lines[Count].Line[Lines[Count].High].Lyric)); + Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); //Total Notes Patch Lines[Count].Line[Lines[Count].High].TotalNotes := 0; for NoteIndex := 0 to high(Lines[Count].Line[Lines[Count].High].Note) do @@ -987,7 +987,7 @@ begin begin //Update old Sentence if it has notes and create a new sentence // stara czesc //Alter Satz //Update Old Part Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; - Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(PChar(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric)); + Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric); //Total Notes Patch Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; -- cgit v1.2.3 From 6585afce2ccd8e7c5ccb3bb3599d4723b00a0433 Mon Sep 17 00:00:00 2001 From: tobigun Date: Tue, 28 Oct 2008 20:16:05 +0000 Subject: some compiler warnings/hints removed git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1485 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 4793b7e9..cff56c1d 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -583,8 +583,8 @@ end; function TSong.ReadXMLHeader(const aFileName : WideString): boolean; var - Line, Identifier, Value: string; - Temp : word; + //Line, Identifier, Value: string; + //Temp : word; Done : byte; Parser : TParser; -- cgit v1.2.3 From d33f56a40d9e8325a2782f90bb253dece5127c5f Mon Sep 17 00:00:00 2001 From: tobigun Date: Mon, 3 Nov 2008 14:53:17 +0000 Subject: All comments are English now (Polish ones have been translated) git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1498 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index cff56c1d..525f7bcc 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -985,7 +985,7 @@ begin If (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then begin //Update old Sentence if it has notes and create a new sentence - // stara czesc //Alter Satz //Update Old Part + // Update old part Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric); @@ -1002,7 +1002,7 @@ begin //Total Notes Patch End - // nowa czesc //Neuer Satz //Update New Part + // Update new part SetLength(Lines[LineNumberP].Line, Lines[LineNumberP].Number + 1); Lines[LineNumberP].High := Lines[LineNumberP].High + 1; Lines[LineNumberP].Number := Lines[LineNumberP].Number + 1; -- cgit v1.2.3 From d4075ab694515dbf0ead0181b0a9f1b21f113ae2 Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Thu, 13 Nov 2008 20:13:55 +0000 Subject: Format adjustments. no code change. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1520 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 94 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 45 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 525f7bcc..c31f6df1 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -130,8 +130,8 @@ type MultBPM : integer; LastError: String; - Function GetErrorLineNo: Integer; - Property ErrorLineNo: Integer read GetErrorLineNo; + function GetErrorLineNo: integer; + property ErrorLineNo: integer read GetErrorLineNo; constructor Create (); overload; @@ -262,13 +262,13 @@ begin Lines[Count].Resolution := self.Resolution; Lines[Count].NotesGAP := self.NotesGAP; Lines[Count].Line[0].HighNote := -1; - Lines[Count].Line[0].LastLine := False; + Lines[Count].Line[0].LastLine := false; end; //TempC := ':'; //TempC := Text[1]; // read from backup variable, don't use default ':' value - while (TempC <> 'E') AND (not EOF(SongFile)) do + while (TempC <> 'E') and (not EOF(SongFile)) do begin if (TempC = ':') or (TempC = '*') or (TempC = 'F') then @@ -280,13 +280,16 @@ begin Read(SongFile, ParamS); //Check for ZeroNote - if Param2 = 0 then Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') else + if Param2 = 0 then + Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') + else begin // add notes if not Both then // P1 ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) - else begin + else + begin // P1 + P2 ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); @@ -294,24 +297,26 @@ begin end; //Zeronote check end // if - Else if TempC = '-' then + else if TempC = '-' then begin // reads sentence Read(SongFile, Param1); - if self.Relative then Read(SongFile, Param2); // read one more data for relative system + if self.Relative then + Read(SongFile, Param2); // read one more data for relative system // new sentence if not Both then // P1 NewSentence(0, (Param1 + Rel[0]) * Mult, Param2) - else begin + else + begin // P1 + P2 NewSentence(0, (Param1 + Rel[0]) * Mult, Param2); NewSentence(1, (Param1 + Rel[1]) * Mult, Param2); end; end // if - Else if TempC = 'B' then + else if TempC = 'B' then begin SetLength(self.BPM, Length(self.BPM) + 1); Read(SongFile, self.BPM[High(self.BPM)].StartBeat); @@ -342,7 +347,7 @@ begin else begin for Count := 0 to High(Lines) do - begin + begin Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); //Total Notes Patch @@ -365,18 +370,18 @@ begin CloseFile(SongFile); - For I := 0 to High(Lines) do + for I := 0 to High(Lines) do begin - If ((Both) or (I = 0)) then + if ((Both) or (I = 0)) then begin - If (Length(Lines[I].Line) < 2) then + if (Length(Lines[I].Line) < 2) then begin LastError := 'ERROR_CORRUPT_SONG_NO_BREAKS'; Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"'); exit; end; - If (Lines[I].Line[Lines[I].High].HighNote < 0) then + if (Lines[I].Line[Lines[I].High].HighNote < 0) then begin SetLength(Lines[I].Line, Lines[I].Number - 1); Lines[I].High := Lines[I].High - 1; @@ -388,8 +393,8 @@ begin for Count := 0 to High(Lines) do begin - If (High(Lines[Count].Line) >= 0) then - Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; + if (High(Lines[Count].Line) >= 0) then + Lines[Count].Line[High(Lines[Count].Line)].LastLine := true; end; except try @@ -460,7 +465,7 @@ begin Lines[Count].Resolution := self.Resolution; Lines[Count].NotesGAP := self.NotesGAP; Lines[Count].Line[0].HighNote := -1; - Lines[Count].Line[0].LastLine := False; + Lines[Count].Line[0].LastLine := false; end; //Try to Parse the Song @@ -477,8 +482,8 @@ begin for J := 0 to High(Parser.SongInfo.Sentences[I].Notes) do begin case Parser.SongInfo.Sentences[I].Notes[J].NoteTyp of - NT_Normal: NoteType := ':'; - NT_Golden: NoteType := '*'; + NT_Normal: NoteType := ':'; + NT_Golden: NoteType := '*'; NT_Freestyle: NoteType := 'F'; end; @@ -544,8 +549,8 @@ begin //Calculate Time case Rest of 0, 1: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; - 2: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 1; - 3: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 2; + 2: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 1; + 3: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 2; else if (Rest >= 4) then Time := SentenceEnd + 2 @@ -574,7 +579,7 @@ begin for Count := 0 to High(Lines) do begin - Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; + Lines[Count].Line[High(Lines[Count].Line)].LastLine := true; end; Result := true; @@ -660,7 +665,8 @@ begin //Language Sorting self.Language := Parser.SongInfo.Header.Language; - end else + end + else Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName); Parser.Free; @@ -668,7 +674,7 @@ begin //Check if all Required Values are given if (Done <> 15) then begin - Result := False; + Result := false; if (Done and 8) = 0 then //No BPM Flag Log.LogError('BPM Tag Missing: ' + self.FileName) else if (Done and 4) = 0 then //No MP3 Flag @@ -686,7 +692,7 @@ end; function TSong.ReadTXTHeader(const aFileName : WideString): boolean; - function song_StrtoFloat( aValue : string ) : Extended; + function song_StrtoFloat( aValue : string ) : extended; var lValue : string; @@ -715,13 +721,12 @@ begin if (Length(Line) <= 0) then begin Log.LogError('File Starts with Empty Line: ' + aFileName); - Result := False; + Result := false; Exit; end; //Read Lines while Line starts with # or its empty - while (Length(Line) = 0) or - (Line[1] = '#') do + while (Length(Line) = 0) or (Line[1] = '#') do begin //Increase Line Number Inc (FileLineNo); @@ -765,8 +770,7 @@ begin end //MP3 File //Test if Exists - else if (Identifier = 'MP3') AND - (FileExists(self.Path + Value)) then + else if (Identifier = 'MP3') and (FileExists(self.Path + Value)) then begin self.Mp3 := Value; @@ -850,17 +854,17 @@ begin else if (Identifier = 'NOTESGAP') then TryStrtoInt(Value, self.NotesGAP) // Relative Notes - else if (Identifier = 'RELATIVE') AND (uppercase(Value) = 'YES') then - self.Relative := True; + else if (Identifier = 'RELATIVE') and (uppercase(Value) = 'YES') then + self.Relative := true; end; end; - if not EOf(SongFile) then + if not EOF(SongFile) then ReadLn (SongFile, Line) else begin - Result := False; + Result := false; Log.LogError('File Incomplete or not Ultrastar TxT (A): ' + aFileName); break; end; @@ -873,7 +877,7 @@ begin //Check if all Required Values are given if (Done <> 15) then begin - Result := False; + Result := false; if (Done and 8) = 0 then //No BPM Flag Log.LogError('BPM Tag Missing: ' + self.FileName) else if (Done and 4) = 0 then //No MP3 Flag @@ -888,11 +892,11 @@ begin end; -Function TSong.GetErrorLineNo: Integer; +function TSong.GetErrorLineNo: integer; begin - If (LastError='ERROR_CORRUPT_SONG_ERROR_IN_LINE') then + if (LastError='ERROR_CORRUPT_SONG_ERROR_IN_LINE') then Result := FileLineNo - Else + else Result := -1; end; @@ -967,7 +971,8 @@ begin Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; Note[HighNote].Tone := NoteP; - if Note[HighNote].Tone < Base[LineNumber] then Base[LineNumber] := Note[HighNote].Tone; + if Note[HighNote].Tone < Base[LineNumber] then + Base[LineNumber] := Note[HighNote].Tone; Note[HighNote].Text := Copy(LyricS, 2, 100); Lyric := Lyric + Note[HighNote].Text; @@ -983,7 +988,7 @@ var begin - If (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then + if (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then begin //Update old Sentence if it has notes and create a new sentence // Update old part Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; @@ -1022,7 +1027,7 @@ begin else Lines[LineNumberP].Line[Lines[LineNumberP].High].Start := Param1; - Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := False; + Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := false; Base[LineNumberP] := 100; // high number end; @@ -1062,11 +1067,10 @@ begin end; - function TSong.Analyse(): boolean; begin - Result := False; + Result := false; //Reset LineNo FileLineNo := 0; @@ -1093,7 +1097,7 @@ end; function TSong.AnalyseXML(): boolean; begin - Result := False; + Result := false; //Reset LineNo FileLineNo := 0; -- cgit v1.2.3 From cb11733f11fd82d80b0bdae558444c5c78ac586f Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Wed, 26 Nov 2008 22:47:05 +0000 Subject: some small format edits git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1529 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index c31f6df1..b1458e69 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -74,7 +74,7 @@ type end; TSong = class - FileLineNo : integer; //Line which is readed at Last, for error reporting + FileLineNo : integer; // line, which is read last, for error reporting procedure ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); procedure NewSentence(LineNumberP: integer; Param1, Param2: integer); @@ -281,15 +281,15 @@ begin //Check for ZeroNote if Param2 = 0 then - Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') - else + Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') + else begin // add notes if not Both then // P1 ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) else - begin + begin // P1 + P2 ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); @@ -302,14 +302,14 @@ begin // reads sentence Read(SongFile, Param1); if self.Relative then - Read(SongFile, Param2); // read one more data for relative system + Read(SongFile, Param2); // read one more data for relative system // new sentence if not Both then // P1 NewSentence(0, (Param1 + Rel[0]) * Mult, Param2) else - begin + begin // P1 + P2 NewSentence(0, (Param1 + Rel[0]) * Mult, Param2); NewSentence(1, (Param1 + Rel[1]) * Mult, Param2); @@ -338,7 +338,7 @@ begin begin if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType = ntGolden) then Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; - + if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType <> ntFreestyle) then Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; end; @@ -347,7 +347,7 @@ begin else begin for Count := 0 to High(Lines) do - begin + begin Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); //Total Notes Patch @@ -362,7 +362,7 @@ begin //Total Notes Patch End end; end; - ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32) + ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32) Read(SongFile, TempC); Inc(FileLineNo); @@ -430,7 +430,7 @@ var NoteType: char; SentenceEnd, Rest, Time: integer; Parser: TParser; - + begin Result := false; LastError := ''; @@ -473,7 +473,7 @@ begin if Parser.ParseSong(Path + PathDelim + FileName) then begin //Writeln('XML Inputfile Parsed succesful'); - + //Start write parsed information to Song //Notes Part for I := 0 to High(Parser.SongInfo.Sentences) do @@ -946,7 +946,7 @@ begin begin SetLength(Note, Length(Note) + 1); HighNote := High(Note); - + Note[HighNote].Start := StartP; if HighNote = 0 then begin @@ -966,7 +966,7 @@ begin if (Note[HighNote].NoteType = ntGolden) then Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; - + if (Note[HighNote].NoteType <> ntFreestyle) then Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; -- cgit v1.2.3 From 8f2fc12d58f248a7b548c4919c640500c7a4524d Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sat, 28 Feb 2009 20:56:12 +0000 Subject: Some cleanup done moved ScoreFactor to UMusic removed unused field TLines.LyricWidth removed unused field TSong.Category removed some weird and useless code from songloading procedures songloading simplified, commented parts that are difficult to understand some changes to score calculation that assure not more nor less than 10000 Points are gainable. after many tests I could not find any bug in score calculation, at least after these changes. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1610 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 178 ++++++++++++++++++----------------------------------- 1 file changed, 61 insertions(+), 117 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index b1458e69..ef0768c5 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -88,7 +88,7 @@ type FileName: WideString; // sorting methods - Category: array of WideString; // TODO: do we need this? + //Category: array of WideString; // TODO: do we need this? Genre: WideString; Edition: WideString; Language: WideString; @@ -185,6 +185,11 @@ begin end; end; +{function TSong.LoadSong(): boolean; +begin + +end; } + //Load TXT Song function TSong.LoadSong(): boolean; @@ -213,8 +218,6 @@ begin MultBPM := 4; // multiply beat-count of note by 4 Mult := 1; // accuracy of measurement of note - Base[0] := 100; // high number - Lines[0].ScoreValue := 0; self.Relative := false; Rel[0] := 0; CP := 0; @@ -255,19 +258,23 @@ begin SetLength(Lines, 2); for Count := 0 to High(Lines) do begin - SetLength(Lines[Count].Line, 1); Lines[Count].High := 0; Lines[Count].Number := 1; Lines[Count].Current := 0; Lines[Count].Resolution := self.Resolution; Lines[Count].NotesGAP := self.NotesGAP; + Lines[Count].ScoreValue := 0; + + //Add first line and set some standard values to fields + //see procedure NewSentence for further explantation + //concerning most of these values + SetLength(Lines[Count].Line, 1); Lines[Count].Line[0].HighNote := -1; Lines[Count].Line[0].LastLine := false; + Lines[Count].Line[0].BaseNote := High(Integer); + Lines[Count].Line[0].TotalNotes := 0; end; - //TempC := ':'; - //TempC := Text[1]; // read from backup variable, don't use default ':' value - while (TempC <> 'E') and (not EOF(SongFile)) do begin @@ -327,41 +334,6 @@ begin self.BPM[High(self.BPM)].BPM := self.BPM[High(self.BPM)].BPM * Mult * MultBPM; end; - - if not Both then - begin - Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; - Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(Lines[CP].Line[Lines[CP].High].Lyric); - //Total Notes Patch - Lines[CP].Line[Lines[CP].High].TotalNotes := 0; - for I := low(Lines[CP].Line[Lines[CP].High].Note) to high(Lines[CP].Line[Lines[CP].High].Note) do - begin - if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType = ntGolden) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; - - if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType <> ntFreestyle) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; - end; - //Total Notes Patch End - end - else - begin - for Count := 0 to High(Lines) do - begin - Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; - Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); - //Total Notes Patch - Lines[Count].Line[Lines[Count].High].TotalNotes := 0; - for I := low(Lines[Count].Line[Lines[Count].High].Note) to high(Lines[Count].Line[Lines[Count].High].Note) do - begin - if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType = ntGolden) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[I].Length; - if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType <> ntFreestyle) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[I].Length; - end; - //Total Notes Patch End - end; - end; ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32) Read(SongFile, TempC); @@ -443,7 +415,6 @@ begin MultBPM := 4; // multiply beat-count of note by 4 Mult := 1; // accuracy of measurement of note - Base[0] := 100; // high number Lines[0].ScoreValue := 0; self.Relative := false; Rel[0] := 0; @@ -458,14 +429,21 @@ begin for Count := 0 to High(Lines) do begin - SetLength(Lines[Count].Line, 1); Lines[Count].High := 0; - Lines[Count].Number := 1; - Lines[Count].Current := 0; - Lines[Count].Resolution := self.Resolution; - Lines[Count].NotesGAP := self.NotesGAP; - Lines[Count].Line[0].HighNote := -1; - Lines[Count].Line[0].LastLine := false; + Lines[Count].Number := 1; + Lines[Count].Current := 0; + Lines[Count].Resolution := self.Resolution; + Lines[Count].NotesGAP := self.NotesGAP; + Lines[Count].ScoreValue := 0; + + //Add first line and set some standard values to fields + //see procedure NewSentence for further explantation + //concerning most of these values + SetLength(Lines[Count].Line, 1); + Lines[Count].Line[0].HighNote := -1; + Lines[Count].Line[0].LastLine := false; + Lines[Count].Line[0].BaseNote := High(Integer); + Lines[Count].Line[0].TotalNotes := 0; end; //Try to Parse the Song @@ -502,42 +480,6 @@ begin ParseNote(1, NoteType, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); end; - if not Both then - begin - Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; - Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(Lines[CP].Line[Lines[CP].High].Lyric); - //Total Notes Patch - Lines[CP].Line[Lines[CP].High].TotalNotes := 0; - for NoteIndex := 0 to high(Lines[CP].Line[Lines[CP].High].Note) do - begin - if (Lines[CP].Line[Lines[CP].High].Note[NoteIndex].NoteType = ntGolden) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[NoteIndex].Length; - - if (Lines[CP].Line[Lines[CP].High].Note[NoteIndex].NoteType <> ntFreestyle) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[NoteIndex].Length; - end; - //Total Notes Patch End - end - else - begin - for Count := 0 to High(Lines) do - begin - Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; - Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); - //Total Notes Patch - Lines[Count].Line[Lines[Count].High].TotalNotes := 0; - for NoteIndex := 0 to high(Lines[Count].Line[Lines[Count].High].Note) do - begin - if (Lines[Count].Line[Lines[Count].High].Note[NoteIndex].NoteType = ntGolden) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[NoteIndex].Length; - if (Lines[Count].Line[Lines[Count].High].Note[NoteIndex].NoteType <> ntFreestyle) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[NoteIndex].Length; - - end; - //Total Notes Patch End - end; - end; { end of for loop } - end; //J Forloop //Add Sentence break @@ -964,17 +906,28 @@ begin '*': Note[HighNote].NoteType := ntGolden; end; - if (Note[HighNote].NoteType = ntGolden) then - Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; + //add this notes value ("notes length" * "notes scorefactor") to the current songs entire value + Inc(Lines[LineNumber].ScoreValue, Note[HighNote].Length * ScoreFactor[Note[HighNote].NoteType]); + + //and to the current lines entire value + Inc(TotalNotes, Note[HighNote].Length * ScoreFactor[Note[HighNote].NoteType]); - if (Note[HighNote].NoteType <> ntFreestyle) then - Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; Note[HighNote].Tone := NoteP; - if Note[HighNote].Tone < Base[LineNumber] then - Base[LineNumber] := Note[HighNote].Tone; - Note[HighNote].Text := Copy(LyricS, 2, 100); + //if a note w/ a deeper pitch then the current basenote is found + //we replace the basenote w/ the current notes pitch + if Note[HighNote].Tone < BaseNote then + BaseNote := Note[HighNote].Tone; + + //delete the space that seperates the notes pitch from its lyrics + //it is left in the LyricS string because Read("some ordinal type") will + //set the files pointer to the first whitespace character after the + //ordinal string. Trim is no solution because it would cut the spaces + //that seperate the words of the lyrics, too. + Delete(LyricS, 1, 1); + + Note[HighNote].Text := LyricS; Lyric := Lyric + Note[HighNote].Text; End_ := Note[HighNote].Start + Note[HighNote].Length; @@ -989,36 +942,29 @@ var begin if (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then - begin //Update old Sentence if it has notes and create a new sentence - // Update old part - Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; - Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric); - - //Total Notes Patch - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; - for I := low(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) to high(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) do - begin - if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType = ntGolden) then - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; - - if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType <> ntFreestyle) then - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; - end; - //Total Notes Patch End - - - // Update new part + begin //create a new line SetLength(Lines[LineNumberP].Line, Lines[LineNumberP].Number + 1); - Lines[LineNumberP].High := Lines[LineNumberP].High + 1; - Lines[LineNumberP].Number := Lines[LineNumberP].Number + 1; + Inc(Lines[LineNumberP].High); + Inc(Lines[LineNumberP].Number); end else - begin //Use old Sentence if it has no notes + begin //use old line if it there were no notes added since last call of NewSentence Log.LogError('Error loading Song, sentence w/o note found in line ' + InttoStr(FileLineNo) + ': ' + Filename); end; Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote := -1; + //set the current lines value to zero + //it will be incremented w/ the value of every added note + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; + + //basenote is the pitch of the deepest note, it is used for note drawing. + //if a note with a less value than the current sentences basenote is found, + //basenote will be set to this notes pitch. Therefore the initial value of + //this field has to be very high. + Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := High(Integer); + + if self.Relative then begin Lines[LineNumberP].Line[Lines[LineNumberP].High].Start := Param1; @@ -1028,8 +974,6 @@ begin Lines[LineNumberP].Line[Lines[LineNumberP].High].Start := Param1; Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := false; - - Base[LineNumberP] := 100; // high number end; procedure TSong.clear(); -- cgit v1.2.3 From cb2a7d2226338a26b4b77a1b08041d2bf7770fa4 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sat, 28 Feb 2009 21:41:23 +0000 Subject: loading of songs with relative: yes fixed git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1611 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index ef0768c5..4dd6be0f 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -218,7 +218,6 @@ begin MultBPM := 4; // multiply beat-count of note by 4 Mult := 1; // accuracy of measurement of note - self.Relative := false; Rel[0] := 0; CP := 0; Both := false; @@ -1009,6 +1008,7 @@ begin Resolution := 4; Creator := ''; + Relative := false; end; function TSong.Analyse(): boolean; -- cgit v1.2.3 From f469075a0335399c753ae5d2d362047dedf116b1 Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Sat, 7 Mar 2009 21:14:14 +0000 Subject: final cleanup of Umain. Creation of UNote git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1627 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 4dd6be0f..1197f3be 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -149,7 +149,7 @@ uses TextGL, UIni, UMusic, //needed for Lines - UMain; //needed for Player + UNote; //needed for Player constructor TSong.Create(); begin -- cgit v1.2.3 From 786adb9a238a6e8a4e49b16f691a926c265da232 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Tue, 10 Mar 2009 20:50:23 +0000 Subject: folder sorting w/ cats on fixed (ticket #84) it works good for the moment, but it should be changed when we support nested categories. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1631 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 1197f3be..57f78a27 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -146,8 +146,10 @@ type implementation uses + StrUtils, TextGL, UIni, + UPath, UMusic, //needed for Lines UNote; //needed for Player @@ -156,7 +158,42 @@ begin inherited; end; -constructor TSong.Create( const aFileName : WideString ); +constructor TSong.Create( const aFileName: WideString ); + // This may be changed, when we rewrite song select code. + // it is some kind of dirty, but imho the best possible + // solution as we do atm not support nested categorys. + // it works like the folder sorting in 1.0.1a + // folder is set to the first folder under the songdir + // so songs ~/.ultrastardx/songs/punk is in the same + // category as songs in shared/ultrastardx/songs are. + // note: folder is just the name of a category it has + // nothing to do with the path used for file loading + function GetFolderCategory: WideString; + var + I: Integer; + P: Integer; //position of next path delimiter + begin + Result := 'Unknown'; //default folder category, if we can't locate the song dir + + for I := 0 to SongPaths.Count-1 do + if (AnsiStartsText(SongPaths.Strings[I], aFilename)) then + begin + P := PosEx(PathDelim, aFilename, Length(SongPaths.Strings[I]) + 1); + + If (P > 0) then + begin + // we have found the category name => get it + Result := copy(self.Path, Length(SongPaths.Strings[I]) + 1, P - Length(SongPaths.Strings[I]) - 1); + end + else + begin + // songs are in the "root" of the songdir => use songdir for the categorys name + Result := SongPaths.Strings[I]; + end; + + Exit; + end; + end; begin inherited Create(); @@ -169,7 +206,7 @@ begin if fileexists( aFileName ) then begin self.Path := ExtractFilePath( aFileName ); - self.Folder := ExtractFilePath( aFileName ); + self.Folder := GetFolderCategory; self.FileName := ExtractFileName( aFileName ); (* if ReadTXTHeader( aFileName ) then -- cgit v1.2.3 From 917901e8e33438c425aef50a0a7417f32d77b760 Mon Sep 17 00:00:00 2001 From: s_alexander Date: Mon, 9 Nov 2009 00:27:55 +0000 Subject: merged unicode branch (r1931) into trunk git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1939 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 1050 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 615 insertions(+), 435 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 57f78a27..d2043a93 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -56,7 +56,11 @@ uses PseudoThread, {$ENDIF} UCatCovers, - UXMLSong; + UXMLSong, + UUnicodeUtils, + UTextEncoding, + UFilesystem, + UPath; type @@ -68,42 +72,54 @@ type end; TScore = record - Name: WideString; + Name: UTF8String; Score: integer; - Length: string; end; TSong = class + private FileLineNo : integer; // line, which is read last, for error reporting - procedure ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); + function DecodeFilename(Filename: RawByteString): IPath; + function Solmizate(Note: integer; Type_: integer): string; + procedure ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: UTF8String); procedure NewSentence(LineNumberP: integer; Param1, Param2: integer); - function ReadTXTHeader( const aFileName : WideString ): boolean; - function ReadXMLHeader( const aFileName : WideString ): boolean; - public - Path: WideString; - Folder: WideString; // for sorting by folder - fFileName, - FileName: WideString; + function ParseLyricStringParam(const Line: RawByteString; var LinePos: integer): RawByteString; + function ParseLyricIntParam(const Line: RawByteString; var LinePos: integer): integer; + function ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): real; + function ParseLyricCharParam(const Line: RawByteString; var LinePos: integer): AnsiChar; + function ParseLyricText(const Line: RawByteString; var LinePos: integer): RawByteString; + + function ReadTXTHeader(SongFile: TTextFileStream): boolean; + function ReadXMLHeader(const aFileName: IPath): boolean; + function GetFolderCategory(const aFileName: IPath): UTF8String; + function FindSongFile(Dir: IPath; Mask: UTF8String): IPath; + + public + Path: IPath; // kust path component of file (only set if file was found) + Folder: UTF8String; // for sorting by folder (only set if file was found) + FileName: IPath; // just name component of file (only set if file was found) + + // filenames + Cover: IPath; + Mp3: IPath; + Background: IPath; + Video: IPath; + // sorting methods - //Category: array of WideString; // TODO: do we need this? - Genre: WideString; - Edition: WideString; - Language: WideString; + Genre: UTF8String; + Edition: UTF8String; + Language: UTF8String; - Title: WideString; - Artist: WideString; + Title: UTF8String; + Artist: UTF8String; - Text: WideString; - Creator: WideString; + Creator: UTF8String; - Cover: WideString; CoverTex: TTexture; - Mp3: WideString; - Background: WideString; - Video: WideString; + VideoGAP: real; NotesGAP: integer; Start: real; // in seconds @@ -113,6 +129,8 @@ type BPM: array of TBPM; GAP: real; // in miliseconds + Encoding: TEncoding; + Score: array[0..2] of array of TScore; // these are used when sorting is enabled @@ -122,20 +140,18 @@ type OrderTyp: integer; // type of sorting for this button (0=name) CatNumber: integer; // Count of Songs in Category for Cats and Number of Song in Category for Songs - SongFile: TextFile; // all procedures in this unit operate on this file - Base : array[0..1] of integer; Rel : array[0..1] of integer; Mult : integer; MultBPM : integer; - LastError: String; + LastError: AnsiString; function GetErrorLineNo: integer; property ErrorLineNo: integer read GetErrorLineNo; - constructor Create (); overload; - constructor Create ( const aFileName : WideString ); overload; + constructor Create(); overload; + constructor Create(const aFileName : IPath); overload; function LoadSong: boolean; function LoadXMLSong: boolean; function Analyse(): boolean; @@ -149,67 +165,74 @@ uses StrUtils, TextGL, UIni, - UPath, + UPathUtils, UMusic, //needed for Lines UNote; //needed for Player +const + // use USDX < 1.1 encoding for backward compatibility + DEFAULT_ENCODING = encCP1252; + constructor TSong.Create(); begin inherited; end; -constructor TSong.Create( const aFileName: WideString ); - // This may be changed, when we rewrite song select code. - // it is some kind of dirty, but imho the best possible - // solution as we do atm not support nested categorys. - // it works like the folder sorting in 1.0.1a - // folder is set to the first folder under the songdir - // so songs ~/.ultrastardx/songs/punk is in the same - // category as songs in shared/ultrastardx/songs are. - // note: folder is just the name of a category it has - // nothing to do with the path used for file loading - function GetFolderCategory: WideString; - var - I: Integer; - P: Integer; //position of next path delimiter - begin - Result := 'Unknown'; //default folder category, if we can't locate the song dir +// This may be changed, when we rewrite song select code. +// it is some kind of dirty, but imho the best possible +// solution as we do atm not support nested categorys. +// it works like the folder sorting in 1.0.1a +// folder is set to the first folder under the songdir +// so songs ~/.ultrastardx/songs/punk is in the same +// category as songs in shared/ultrastardx/songs are. +// note: folder is just the name of a category it has +// nothing to do with the path used for file loading +function TSong.GetFolderCategory(const aFileName: IPath): UTF8String; +var + I: Integer; + CurSongPath: IPath; + CurSongPathRel: IPath; +begin + Result := 'Unknown'; //default folder category, if we can't locate the song dir - for I := 0 to SongPaths.Count-1 do - if (AnsiStartsText(SongPaths.Strings[I], aFilename)) then + for I := 0 to SongPaths.Count-1 do + begin + CurSongPath := SongPaths[I] as IPath; + if (aFileName.IsChildOf(CurSongPath, false)) then + begin + if (aFileName.IsChildOf(CurSongPath, true)) then begin - P := PosEx(PathDelim, aFilename, Length(SongPaths.Strings[I]) + 1); - - If (P > 0) then - begin - // we have found the category name => get it - Result := copy(self.Path, Length(SongPaths.Strings[I]) + 1, P - Length(SongPaths.Strings[I]) - 1); - end - else - begin - // songs are in the "root" of the songdir => use songdir for the categorys name - Result := SongPaths.Strings[I]; - end; - - Exit; + // songs are in the "root" of the songdir => use songdir for the categorys name + Result := CurSongPath.ToUTF8; // TODO: remove trailing path-delim? + end + else + begin + // use the first subdirectory below CurSongPath as the category name + CurSongPathRel := aFileName.GetRelativePath(CurSongPath.AppendPathDelim); + Result := CurSongPathRel.SplitDirs[0].RemovePathDelim.ToUTF8; end; + Exit; + end; end; +end; + +constructor TSong.Create(const aFileName: IPath); begin inherited Create(); Mult := 1; MultBPM := 4; - fFileName := aFileName; LastError := ''; - if fileexists( aFileName ) then + Self.Path := aFileName.GetPath; + Self.FileName := aFileName.GetName; + Self.Folder := GetFolderCategory(aFileName); + + (* + if (aFileName.IsFile) then begin - self.Path := ExtractFilePath( aFileName ); - self.Folder := GetFolderCategory; - self.FileName := ExtractFileName( aFileName ); - (* - if ReadTXTHeader( aFileName ) then + if ReadTXTHeader(aFileName) then begin LoadSong(); end @@ -218,45 +241,178 @@ begin Log.LogError('Error Loading SongHeader, abort Song Loading'); Exit; end; - *) + end; + *) +end; + +function TSong.FindSongFile(Dir: IPath; Mask: UTF8String): IPath; +var + Iter: IFileIterator; + FileInfo: TFileInfo; + FileName: IPath; +begin + Iter := FileSystem.FileFind(Dir.Append(Mask), faDirectory); + if (Iter.HasNext) then + Result := Iter.Next.Name + else + Result := PATH_NONE; +end; + +function TSong.DecodeFilename(Filename: RawByteString): IPath; +begin + Result := UPath.Path(DecodeStringUTF8(Filename, Encoding)); +end; + +type + EUSDXParseException = class(Exception); + +{** + * Parses the Line string starting from LinePos for a parameter. + * Leading whitespace is trimmed, same applies to the first trailing whitespace. + * After the call LinePos will point to the position after the first trailing + * whitespace. + * + * Raises an EUSDXParseException if no string was found. + * + * Example: + * ParseLyricParam(Line:'Param0 Param1 Param2', LinePos:8, ...) + * -> Param:'Param1', LinePos:16 (= start of 'Param2') + *} +function TSong.ParseLyricStringParam(const Line: RawByteString; var LinePos: integer): RawByteString; +var + Start: integer; + OldLinePos: integer; +const + Whitespace = [#9, ' ']; +begin + OldLinePos := LinePos; + + Start := 0; + while (LinePos <= Length(Line)) do + begin + if (Line[LinePos] in Whitespace) then + begin + // check for end of param + if (Start > 0) then + Break; + end + // check for beginning of param + else if (Start = 0) then + begin + Start := LinePos; + end; + Inc(LinePos); + end; + + // check if param was found + if (Start = 0) then + begin + LinePos := OldLinePos; + raise EUSDXParseException.Create('String expected'); + end + else + begin + // copy param without trailing whitespace + Result := Copy(Line, Start, LinePos-Start); + // skip first trailing whitespace (if not at EOL) + if (LinePos <= Length(Line)) then + Inc(LinePos); + end; +end; + +function TSong.ParseLyricIntParam(const Line: RawByteString; var LinePos: integer): integer; +var + Str: RawByteString; + OldLinePos: integer; +begin + OldLinePos := LinePos; + Str := ParseLyricStringParam(Line, LinePos); + try + Result := StrToInt(Str); + except // on EConvertError + LinePos := OldLinePos; + raise EUSDXParseException.Create('Integer expected'); end; end; -{function TSong.LoadSong(): boolean; +function TSong.ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): real; +var + Str: RawByteString; + OldLinePos: integer; +begin + OldLinePos := LinePos; + Str := ParseLyricStringParam(Line, LinePos); + try + Result := StrToFloat(Str); + except // on EConvertError + LinePos := OldLinePos; + raise EUSDXParseException.Create('Float expected'); + end; +end; + +function TSong.ParseLyricCharParam(const Line: RawByteString; var LinePos: integer): AnsiChar; +var + Str: RawByteString; + OldLinePos: integer; begin + OldLinePos := LinePos; + Str := ParseLyricStringParam(Line, LinePos); + if (Length(Str) <> 1) then + begin + LinePos := OldLinePos; + raise EUSDXParseException.Create('Character expected'); + end; + Result := Str[1]; +end; -end; } +{** + * Returns the rest of the line from LinePos as lyric text. + * Leading and trailing whitespace is not trimmed. + *} +function TSong.ParseLyricText(const Line: RawByteString; var LinePos: integer): RawByteString; +begin + if (LinePos > Length(Line)) then + Result := '' + else + begin + Result := Copy(Line, LinePos, Length(Line)-LinePos+1); + LinePos := Length(Line)+1; + end; +end; //Load TXT Song function TSong.LoadSong(): boolean; - var - TempC: char; - Text: string; - CP: integer; // Current Player (0 or 1) + CurLine: RawByteString; + LinePos: integer; Count: integer; Both: boolean; - Param1: integer; - Param2: integer; - Param3: integer; - ParamS: string; - I: integer; + Param0: AnsiChar; + Param1: integer; + Param2: integer; + Param3: integer; + ParamLyric: UTF8String; + + I: integer; + NotesFound: boolean; + SongFile: TTextFileStream; + FileNamePath: IPath; begin Result := false; LastError := ''; - if not FileExists(Path + PathDelim + FileName) then + FileNamePath := Path.Append(FileName); + if not FileNamePath.IsFile() then begin LastError := 'ERROR_CORRUPT_SONG_FILE_NOT_FOUND'; - Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()'); - exit; + Log.LogError('File not found: "' + FileNamePath.ToNative + '"', 'TSong.LoadSong()'); + Exit; end; MultBPM := 4; // multiply beat-count of note by 4 Mult := 1; // accuracy of measurement of note Rel[0] := 0; - CP := 0; Both := false; if Length(Player) = 2 then @@ -264,156 +420,155 @@ begin try // Open song file for reading..... - FileMode := fmOpenRead; - AssignFile(SongFile, fFileName); - Reset(SongFile); - - //Clear old Song Header - if (self.Path = '') then - self.Path := ExtractFilePath(FileName); - - if (self.FileName = '') then - self.Filename := ExtractFileName(FileName); - - FileLineNo := 0; - //Search for Note Begining - repeat - ReadLn(SongFile, Text); - Inc(FileLineNo); + SongFile := TMemTextFileStream.Create(FileNamePath, fmOpenRead); + try + //Search for Note Beginning + FileLineNo := 0; + NotesFound := false; + while (SongFile.ReadLine(CurLine)) do + begin + Inc(FileLineNo); + if (Length(CurLine) > 0) and (CurLine[1] in [':', 'F', '*']) then + begin + NotesFound := true; + Break; + end; + end; - if (EoF(SongFile)) then + if (not NotesFound) then begin //Song File Corrupted - No Notes - CloseFile(SongFile); - Log.LogError('Could not load txt File, no Notes found: ' + FileName); + Log.LogError('Could not load txt File, no notes found: ' + FileNamePath.ToNative); LastError := 'ERROR_CORRUPT_SONG_NO_NOTES'; Exit; end; - Read(SongFile, TempC); - until ((TempC = ':') or (TempC = 'F') or (TempC = '*')); - - SetLength(Lines, 2); - for Count := 0 to High(Lines) do - begin - Lines[Count].High := 0; - Lines[Count].Number := 1; - Lines[Count].Current := 0; - Lines[Count].Resolution := self.Resolution; - Lines[Count].NotesGAP := self.NotesGAP; - Lines[Count].ScoreValue := 0; - //Add first line and set some standard values to fields - //see procedure NewSentence for further explantation - //concerning most of these values - SetLength(Lines[Count].Line, 1); - Lines[Count].Line[0].HighNote := -1; - Lines[Count].Line[0].LastLine := false; - Lines[Count].Line[0].BaseNote := High(Integer); - Lines[Count].Line[0].TotalNotes := 0; - end; - - while (TempC <> 'E') and (not EOF(SongFile)) do - begin - - if (TempC = ':') or (TempC = '*') or (TempC = 'F') then + SetLength(Lines, 2); + for Count := 0 to High(Lines) do begin - // read notes - Read(SongFile, Param1); - Read(SongFile, Param2); - Read(SongFile, Param3); - Read(SongFile, ParamS); - - //Check for ZeroNote - if Param2 = 0 then - Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') - else - begin - // add notes - if not Both then - // P1 - ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) - else - begin - // P1 + P2 - ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); - ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); - end; - end; //Zeronote check - end // if - - else if TempC = '-' then - begin - // reads sentence - Read(SongFile, Param1); - if self.Relative then - Read(SongFile, Param2); // read one more data for relative system - - // new sentence - if not Both then - // P1 - NewSentence(0, (Param1 + Rel[0]) * Mult, Param2) - else - begin - // P1 + P2 - NewSentence(0, (Param1 + Rel[0]) * Mult, Param2); - NewSentence(1, (Param1 + Rel[1]) * Mult, Param2); - end; - end // if + Lines[Count].High := 0; + Lines[Count].Number := 1; + Lines[Count].Current := 0; + Lines[Count].Resolution := self.Resolution; + Lines[Count].NotesGAP := self.NotesGAP; + Lines[Count].ScoreValue := 0; + + //Add first line and set some standard values to fields + //see procedure NewSentence for further explantation + //concerning most of these values + SetLength(Lines[Count].Line, 1); + Lines[Count].Line[0].HighNote := -1; + Lines[Count].Line[0].LastLine := false; + Lines[Count].Line[0].BaseNote := High(Integer); + Lines[Count].Line[0].TotalNotes := 0; + end; - else if TempC = 'B' then + while true do begin - SetLength(self.BPM, Length(self.BPM) + 1); - Read(SongFile, self.BPM[High(self.BPM)].StartBeat); - self.BPM[High(self.BPM)].StartBeat := self.BPM[High(self.BPM)].StartBeat + Rel[0]; + LinePos := 0; - Read(SongFile, Text); - self.BPM[High(self.BPM)].BPM := StrToFloat(Text); - self.BPM[High(self.BPM)].BPM := self.BPM[High(self.BPM)].BPM * Mult * MultBPM; - end; + Param0 := ParseLyricCharParam(CurLine, LinePos); + if (Param0 = 'E') then + begin + Break + end + else if (Param0 in [':', '*', 'F']) then + begin + // read notes + Param1 := ParseLyricIntParam(CurLine, LinePos); + Param2 := ParseLyricIntParam(CurLine, LinePos); + Param3 := ParseLyricIntParam(CurLine, LinePos); + ParamLyric := ParseLyricText(CurLine, LinePos); + + //Check for ZeroNote + if Param2 = 0 then + Log.LogError('Found zero-length note at "'+Param0+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamLyric+'" -> Note ignored!') + else + begin + // add notes + if not Both then + // P1 + ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric) + else + begin + // P1 + P2 + ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric); + ParseNote(1, Param0, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamLyric); + end; + end; //Zeronote check + end // if + + else if Param0 = '-' then + begin + // reads sentence + Param1 := ParseLyricIntParam(CurLine, LinePos); + if self.Relative then + Param2 := ParseLyricIntParam(CurLine, LinePos); // read one more data for relative system + + // new sentence + if not Both then + // P1 + NewSentence(0, (Param1 + Rel[0]) * Mult, Param2) + else + begin + // P1 + P2 + NewSentence(0, (Param1 + Rel[0]) * Mult, Param2); + NewSentence(1, (Param1 + Rel[1]) * Mult, Param2); + end; + end // if - ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32) + else if Param0 = 'B' then + begin + SetLength(self.BPM, Length(self.BPM) + 1); + self.BPM[High(self.BPM)].StartBeat := ParseLyricFloatParam(CurLine, LinePos); + self.BPM[High(self.BPM)].StartBeat := self.BPM[High(self.BPM)].StartBeat + Rel[0]; - Read(SongFile, TempC); - Inc(FileLineNo); - end; // while} + self.BPM[High(self.BPM)].BPM := ParseLyricFloatParam(CurLine, LinePos); + self.BPM[High(self.BPM)].BPM := self.BPM[High(self.BPM)].BPM * Mult * MultBPM; + end; - CloseFile(SongFile); + // Read next line in File + if (not SongFile.ReadLine(CurLine)) then + Break; - for I := 0 to High(Lines) do + Inc(FileLineNo); + end; // while + finally + SongFile.Free; + end; + except + on E: Exception do begin - if ((Both) or (I = 0)) then - begin - if (Length(Lines[I].Line) < 2) then - begin - LastError := 'ERROR_CORRUPT_SONG_NO_BREAKS'; - Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"'); - exit; - end; - - if (Lines[I].Line[Lines[I].High].HighNote < 0) then - begin - SetLength(Lines[I].Line, Lines[I].Number - 1); - Lines[I].High := Lines[I].High - 1; - Lines[I].Number := Lines[I].Number - 1; - Log.LogError('Error loading Song, sentence w/o note found in last line before E: ' + Filename); - end; - end; + Log.LogError(Format('Error loading file: "%s" in line %d,%d: %s', + [FileNamePath.ToNative, FileLineNo, LinePos, E.Message])); + Exit; end; + end; - for Count := 0 to High(Lines) do + for I := 0 to High(Lines) do + begin + if ((Both) or (I = 0)) then begin - if (High(Lines[Count].Line) >= 0) then - Lines[Count].Line[High(Lines[Count].Line)].LastLine := true; - end; - except - try - CloseFile(SongFile); - except + if (Length(Lines[I].Line) < 2) then + begin + LastError := 'ERROR_CORRUPT_SONG_NO_BREAKS'; + Log.LogError('Error loading file: Can''t find any linebreaks in "' + FileNamePath.ToNative + '"'); + exit; + end; + if (Lines[I].Line[Lines[I].High].HighNote < 0) then + begin + SetLength(Lines[I].Line, Lines[I].Number - 1); + Lines[I].High := Lines[I].High - 1; + Lines[I].Number := Lines[I].Number - 1; + Log.LogError('Error loading Song, sentence w/o note found in last line before E: ' + FileNamePath.ToNative); + end; end; + end; - LastError := 'ERROR_CORRUPT_SONG_ERROR_IN_LINE'; - Log.LogError('Error Loading File: "' + fFileName + '" in Line ' + inttostr(FileLineNo)); - exit; + for Count := 0 to High(Lines) do + begin + if (High(Lines[Count].Line) >= 0) then + Lines[Count].Line[High(Lines[Count].Line)].LastLine := true; end; Result := true; @@ -421,11 +576,7 @@ end; //Load XML Song function TSong.LoadXMLSong(): boolean; - var - //TempC: char; - Text: string; - CP: integer; // Current Player (0 or 1) Count: integer; Both: boolean; Param1: integer; @@ -438,14 +589,15 @@ var NoteType: char; SentenceEnd, Rest, Time: integer; Parser: TParser; - + FileNamePath: IPath; begin Result := false; LastError := ''; - if not FileExists(Path + PathDelim + FileName) then + FileNamePath := Path.Append(FileName); + if not FileNamePath.IsFile() then begin - Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()'); + Log.LogError('File not found: "' + FileNamePath.ToNative + '"', 'TSong.LoadSong()'); exit; end; @@ -454,7 +606,6 @@ begin Lines[0].ScoreValue := 0; self.Relative := false; Rel[0] := 0; - CP := 0; Both := false; if Length(Player) = 2 then @@ -484,7 +635,7 @@ begin //Try to Parse the Song - if Parser.ParseSong(Path + PathDelim + FileName) then + if Parser.ParseSong(FileNamePath) then begin //Writeln('XML Inputfile Parsed succesful'); @@ -551,7 +702,7 @@ begin end else begin - Log.LogError('Could not parse Inputfile: ' + Path + PathDelim + FileName); + Log.LogError('Could not parse inputfile: ' + FileNamePath.ToNative); exit; end; @@ -563,14 +714,11 @@ begin Result := true; end; -function TSong.ReadXMLHeader(const aFileName : WideString): boolean; - +function TSong.ReadXMLHeader(const aFileName : IPath): boolean; var - //Line, Identifier, Value: string; - //Temp : word; Done : byte; Parser : TParser; - + FileNamePath: IPath; begin Result := true; Done := 0; @@ -579,7 +727,8 @@ begin Parser := TParser.Create; Parser.Settings.DashReplacement := '~'; - if Parser.ParseSong(self.Path + self.FileName) then + FileNamePath := Self.Path.Append(Self.FileName); + if Parser.ParseSong(FileNamePath) then begin //----------- //Required Attributes @@ -598,9 +747,9 @@ begin Done := Done or 2; //MP3 File //Test if Exists - self.Mp3 := platform.FindSongFile(Path, '*.mp3'); + Self.Mp3 := FindSongFile(Self.Path, '*.mp3'); //Add Mp3 Flag to Done - if (FileExists(self.Path + self.Mp3)) then + if (Self.Path.Append(Self.Mp3).IsFile()) then Done := Done or 4; //Beats per Minute @@ -621,16 +770,16 @@ begin self.GAP := Parser.SongInfo.Header.Gap; //Cover Picture - self.Cover := platform.FindSongFile(Path, '*[CO].jpg'); + self.Cover := FindSongFile(Path, '*[CO].jpg'); //Background Picture - self.Background := platform.FindSongFile(Path, '*[BG].jpg'); + self.Background := FindSongFile(Path, '*[BG].jpg'); // Video File // self.Video := Value // Video Gap - // self.VideoGAP := song_StrtoFloat( Value ) + // self.VideoGAP := StrtoFloatI18n( Value ) //Genre Sorting self.Genre := Parser.SongInfo.Header.Genre; @@ -645,7 +794,7 @@ begin self.Language := Parser.SongInfo.Header.Language; end else - Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName); + Log.LogError('File incomplete or not SingStar XML (A): ' + aFileName.ToNative); Parser.Free; @@ -654,220 +803,260 @@ begin begin Result := false; if (Done and 8) = 0 then //No BPM Flag - Log.LogError('BPM Tag Missing: ' + self.FileName) + Log.LogError('BPM tag missing: ' + self.FileName.ToNative) else if (Done and 4) = 0 then //No MP3 Flag - Log.LogError('MP3 Tag/File Missing: ' + self.FileName) + Log.LogError('MP3 tag/file missing: ' + self.FileName.ToNative) else if (Done and 2) = 0 then //No Artist Flag - Log.LogError('Artist Tag Missing: ' + self.FileName) + Log.LogError('Artist tag missing: ' + self.FileName.ToNative) else if (Done and 1) = 0 then //No Title Flag - Log.LogError('Title Tag Missing: ' + self.FileName) + Log.LogError('Title tag missing: ' + self.FileName.ToNative) else //unknown Error - Log.LogError('File Incomplete or not SingStar XML (B - '+ inttostr(Done) +'): ' + aFileName); + Log.LogError('File incomplete or not SingStar XML (B - '+ inttostr(Done) +'): ' + aFileName.ToNative); end; end; -function TSong.ReadTXTHeader(const aFileName : WideString): boolean; - - function song_StrtoFloat( aValue : string ) : extended; - - var - lValue : string; - - begin - lValue := aValue; - - if (Pos(',', lValue) <> 0) then - lValue[Pos(',', lValue)] := '.'; - - Result := StrToFloatDef(lValue, 0); - end; - +{** + * "International" StrToFloat variant. Uses either ',' or '.' as decimal + * separator. + *} +function StrToFloatI18n(const Value: string): extended; var - Line, Identifier, Value: string; - Temp : word; - Done : byte; + TempValue : string; +begin + TempValue := Value; + if (Pos(',', TempValue) <> 0) then + TempValue[Pos(',', TempValue)] := '.'; + Result := StrToFloatDef(TempValue, 0); +end; +function TSong.ReadTXTHeader(SongFile: TTextFileStream): boolean; +var + Line, Identifier: string; + Value: string; + SepPos: integer; // separator position + Done: byte; // bit-vector of mandatory fields + EncFile: IPath; // encoded filename + FullFileName: string; begin Result := true; Done := 0; - //Read first Line - ReadLn (SongFile, Line); + FullFileName := Path.Append(Filename).ToNative; + //Read first Line + SongFile.ReadLine(Line); if (Length(Line) <= 0) then begin - Log.LogError('File Starts with Empty Line: ' + aFileName); + Log.LogError('File starts with empty line: ' + FullFileName, + 'TSong.ReadTXTHeader'); 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 (FileLineNo); - Temp := Pos(':', Line); + SepPos := Pos(':', Line); - //Line has a Seperator-> Headerline - if (Temp <> 0) then - begin - //Read Identifier and Value - Identifier := Uppercase(Trim(Copy(Line, 2, Temp - 2))); //Uppercase is for Case Insensitive Checks - Value := Trim(Copy(Line, Temp + 1,Length(Line) - Temp)); + //Line has no Seperator, ignore non header field + if (SepPos = 0) then + Continue; - //Check the Identifier (If Value is given) - if (Length(Value) <> 0) then - begin - //----------- - //Required Attributes - //----------- - - {$IFDEF UTF8_FILENAMES} - if ((Identifier = 'MP3') or (Identifier = 'BACKGROUND') or (Identifier = 'COVER') or (Identifier = 'VIDEO')) then - Value := Utf8Encode(Value); - {$ENDIF} + //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)); - //Title - if (Identifier = 'TITLE') then - begin - self.Title := Value; - - //Add Title Flag to Done - Done := Done or 1; - end + //Check the Identifier (If Value is given) + if (Length(Value) = 0) then + begin + Log.LogWarn('Empty field "'+Identifier+'" in file ' + FullFileName, + 'TSong.ReadTXTHeader'); + end + else + begin + + //----------- + //Required Attributes + //----------- - //Artist - else if (Identifier = 'ARTIST') then - begin - self.Artist := Value; + if (Identifier = 'TITLE') then + begin + DecodeStringUTF8(Value, Title, Encoding); + //Add Title Flag to Done + Done := Done or 1; + end - //Add Artist Flag to Done - Done := Done or 2; - end + else if (Identifier = 'ARTIST') then + begin + DecodeStringUTF8(Value, Artist, Encoding); + //Add Artist Flag to Done + Done := Done or 2; + end - //MP3 File //Test if Exists - else if (Identifier = 'MP3') and (FileExists(self.Path + Value)) then + //MP3 File + else if (Identifier = 'MP3') then + begin + EncFile := DecodeFilename(Value); + if (Self.Path.Append(EncFile).IsFile) then begin - self.Mp3 := Value; + self.Mp3 := EncFile; //Add Mp3 Flag to Done Done := Done or 4; - end + end; + end - //Beats per Minute - else if (Identifier = 'BPM') then - begin - SetLength(self.BPM, 1); - self.BPM[0].StartBeat := 0; + //Beats per Minute + else if (Identifier = 'BPM') then + begin + SetLength(self.BPM, 1); + self.BPM[0].StartBeat := 0; - self.BPM[0].BPM := song_StrtoFloat( Value ) * Mult * MultBPM; + self.BPM[0].BPM := StrToFloatI18n( Value ) * Mult * MultBPM; - if self.BPM[0].BPM <> 0 then - begin - //Add BPM Flag to Done - Done := Done or 8; - end; - end + if self.BPM[0].BPM <> 0 then + begin + //Add BPM Flag to Done + Done := Done or 8; + end; + end - //--------- - //Additional Header Information - //--------- + //--------- + //Additional Header Information + //--------- - // Gap - else if (Identifier = 'GAP') then - self.GAP := song_StrtoFloat( Value ) + // Gap + else if (Identifier = 'GAP') then + begin + self.GAP := StrToFloatI18n(Value); + end - //Cover Picture - else if (Identifier = 'COVER') then - self.Cover := Value + //Cover Picture + else if (Identifier = 'COVER') then + begin + self.Cover := DecodeFilename(Value); + end - //Background Picture - else if (Identifier = 'BACKGROUND') then - self.Background := Value + //Background Picture + else if (Identifier = 'BACKGROUND') then + begin + self.Background := DecodeFilename(Value); + end - // Video File - else if (Identifier = 'VIDEO') then - begin - if (FileExists(self.Path + Value)) then - self.Video := Value - else - Log.LogError('Can''t find Video File in Song: ' + aFileName); - end + // Video File + else if (Identifier = 'VIDEO') then + begin + EncFile := DecodeFilename(Value); + if (self.Path.Append(EncFile).IsFile) then + self.Video := EncFile + else + Log.LogError('Can''t find video file in song: ' + FullFileName); + end - // Video Gap - else if (Identifier = 'VIDEOGAP') then - self.VideoGAP := song_StrtoFloat( Value ) + // Video Gap + else if (Identifier = 'VIDEOGAP') then + begin + self.VideoGAP := StrToFloatI18n( Value ) + end - //Genre Sorting - else if (Identifier = 'GENRE') then - self.Genre := Value + //Genre Sorting + else if (Identifier = 'GENRE') then + begin + DecodeStringUTF8(Value, Genre, Encoding) + end - //Edition Sorting - else if (Identifier = 'EDITION') then - self.Edition := Value + //Edition Sorting + else if (Identifier = 'EDITION') then + begin + DecodeStringUTF8(Value, Edition, Encoding) + end - //Creator Tag - else if (Identifier = 'CREATOR') then - self.Creator := Value + //Creator Tag + else if (Identifier = 'CREATOR') then + begin + DecodeStringUTF8(Value, Creator, Encoding) + end + + //Language Sorting + else if (Identifier = 'LANGUAGE') then + begin + DecodeStringUTF8(Value, Language, Encoding) + end - //Language Sorting - else if (Identifier = 'LANGUAGE') then - self.Language := Value + // Song Start + else if (Identifier = 'START') then + begin + self.Start := StrToFloatI18n( Value ) + end - // Song Start - else if (Identifier = 'START') then - self.Start := song_StrtoFloat( Value ) + // Song Ending + else if (Identifier = 'END') then + begin + TryStrtoInt(Value, self.Finish) + end - // Song Ending - else if (Identifier = 'END') then - TryStrtoInt(Value, self.Finish) + // Resolution + else if (Identifier = 'RESOLUTION') then + begin + TryStrtoInt(Value, self.Resolution) + end - // Resolution - else if (Identifier = 'RESOLUTION') then - TryStrtoInt(Value, self.Resolution) + // Notes Gap + else if (Identifier = 'NOTESGAP') then + begin + TryStrtoInt(Value, self.NotesGAP) + end - // Notes Gap - else if (Identifier = 'NOTESGAP') then - TryStrtoInt(Value, self.NotesGAP) - // Relative Notes - else if (Identifier = 'RELATIVE') and (uppercase(Value) = 'YES') then + // Relative Notes + else if (Identifier = 'RELATIVE') then + begin + if (UpperCase(Value) = 'YES') then self.Relative := true; + end + // File encoding + else if (Identifier = 'ENCODING') then + begin + self.Encoding := ParseEncoding(Value, DEFAULT_ENCODING); end; - end; + + end; // End check for non-empty Value - if not EOF(SongFile) then - ReadLn (SongFile, Line) - else + // read next line + if (not SongFile.ReadLine(Line)) then begin Result := false; - Log.LogError('File Incomplete or not Ultrastar TxT (A): ' + aFileName); - break; + Log.LogError('File incomplete or not Ultrastar txt (A): ' + FullFileName); + Break; end; + end; // while - end; - - if self.Cover = '' then - self.Cover := platform.FindSongFile(Path, '*[CO].jpg'); + if self.Cover.IsUnset then + self.Cover := FindSongFile(Path, '*[CO].jpg'); //Check if all Required Values are given if (Done <> 15) then begin Result := false; if (Done and 8) = 0 then //No BPM Flag - Log.LogError('BPM Tag Missing: ' + self.FileName) + Log.LogError('BPM tag missing: ' + FullFileName) else if (Done and 4) = 0 then //No MP3 Flag - Log.LogError('MP3 Tag/File Missing: ' + self.FileName) + Log.LogError('MP3 tag/file missing: ' + FullFileName) else if (Done and 2) = 0 then //No Artist Flag - Log.LogError('Artist Tag Missing: ' + self.FileName) + Log.LogError('Artist tag missing: ' + FullFileName) else if (Done and 1) = 0 then //No Title Flag - Log.LogError('Title Tag Missing: ' + self.FileName) + Log.LogError('Title tag missing: ' + FullFileName) else //unknown Error - Log.LogError('File Incomplete or not Ultrastar TxT (B - '+ inttostr(Done) +'): ' + aFileName); + Log.LogError('File incomplete or not Ultrastar txt (B - '+ inttostr(Done) +'): ' + FullFileName); end; - end; function TSong.GetErrorLineNo: integer; @@ -878,47 +1067,52 @@ begin Result := -1; end; -procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); - +function TSong.Solmizate(Note: integer; Type_: integer): string; begin - case Ini.Solmization of + case (Type_) of 1: // european begin - case (NoteP mod 12) of - 0..1: LyricS := ' do '; - 2..3: LyricS := ' re '; - 4: LyricS := ' mi '; - 5..6: LyricS := ' fa '; - 7..8: LyricS := ' sol '; - 9..10: LyricS := ' la '; - 11: LyricS := ' si '; + case (Note mod 12) of + 0..1: Result := ' do '; + 2..3: Result := ' re '; + 4: Result := ' mi '; + 5..6: Result := ' fa '; + 7..8: Result := ' sol '; + 9..10: Result := ' la '; + 11: Result := ' si '; end; end; 2: // japanese begin - case (NoteP mod 12) of - 0..1: LyricS := ' do '; - 2..3: LyricS := ' re '; - 4: LyricS := ' mi '; - 5..6: LyricS := ' fa '; - 7..8: LyricS := ' so '; - 9..10: LyricS := ' la '; - 11: LyricS := ' shi '; + case (Note mod 12) of + 0..1: Result := ' do '; + 2..3: Result := ' re '; + 4: Result := ' mi '; + 5..6: Result := ' fa '; + 7..8: Result := ' so '; + 9..10: Result := ' la '; + 11: Result := ' shi '; end; end; 3: // american begin - case (NoteP mod 12) of - 0..1: LyricS := ' do '; - 2..3: LyricS := ' re '; - 4: LyricS := ' mi '; - 5..6: LyricS := ' fa '; - 7..8: LyricS := ' sol '; - 9..10: LyricS := ' la '; - 11: LyricS := ' ti '; + case (Note mod 12) of + 0..1: Result := ' do '; + 2..3: Result := ' re '; + 4: Result := ' mi '; + 5..6: Result := ' fa '; + 7..8: Result := ' sol '; + 9..10: Result := ' la '; + 11: Result := ' ti '; end; end; end; // case +end; + +procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: UTF8String); +begin + if (Ini.Solmization <> 0) then + LyricS := Solmizate(NoteP, Ini.Solmization); with Lines[LineNumber].Line[Lines[LineNumber].High] do begin @@ -956,14 +1150,7 @@ begin if Note[HighNote].Tone < BaseNote then BaseNote := Note[HighNote].Tone; - //delete the space that seperates the notes pitch from its lyrics - //it is left in the LyricS string because Read("some ordinal type") will - //set the files pointer to the first whitespace character after the - //ordinal string. Trim is no solution because it would cut the spaces - //that seperate the words of the lyrics, too. - Delete(LyricS, 1, 1); - - Note[HighNote].Text := LyricS; + DecodeStringUTF8(LyricS, Note[HighNote].Text, Encoding); Lyric := Lyric + Note[HighNote].Text; End_ := Note[HighNote].Start + Note[HighNote].Length; @@ -971,10 +1158,8 @@ begin end; procedure TSong.NewSentence(LineNumberP: integer; Param1, Param2: integer); - var I: integer; - begin if (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then @@ -985,7 +1170,8 @@ begin end else begin //use old line if it there were no notes added since last call of NewSentence - Log.LogError('Error loading Song, sentence w/o note found in line ' + InttoStr(FileLineNo) + ': ' + Filename); + Log.LogError('Error loading Song, sentence w/o note found in line ' + + InttoStr(FileLineNo) + ': ' + Filename.ToNative); end; Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote := -1; @@ -1012,8 +1198,7 @@ begin Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := false; end; -procedure TSong.clear(); - +procedure TSong.Clear(); begin //Main Information Title := ''; @@ -1024,22 +1209,21 @@ begin Edition := 'Unknown'; Language := 'Unknown'; //Language Patch + // set to default encoding + Encoding := DEFAULT_ENCODING; + //Required Information - Mp3 := ''; - {$IFDEF FPC} - setlength( BPM, 0 ); - {$ELSE} - BPM := nil; - {$ENDIF} + Mp3 := PATH_NONE; + SetLength(BPM, 0); GAP := 0; Start := 0; Finish := 0; //Additional Information - Background := ''; - Cover := ''; - Video := ''; + Background := PATH_NONE; + Cover := PATH_NONE; + Video := PATH_NONE; VideoGAP := 0; NotesGAP := 0; Resolution := 4; @@ -1049,7 +1233,8 @@ begin end; function TSong.Analyse(): boolean; - +var + SongFile: TTextFileStream; begin Result := false; @@ -1057,20 +1242,15 @@ begin FileLineNo := 0; //Open File and set File Pointer to the beginning - AssignFile(SongFile, self.Path + self.FileName); - + SongFile := TMemTextFileStream.Create(Self.Path.Append(Self.FileName), fmOpenRead); try - Reset(SongFile); - //Clear old Song Header - self.clear; + Self.clear; //Read Header - Result := self.ReadTxTHeader( FileName ) - - //And Close File + Result := Self.ReadTxTHeader(SongFile) finally - CloseFile(SongFile); + SongFile.Free; end; end; -- cgit v1.2.3 From 85c7cf68848e3640238cfaa631305ae87e59cf66 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Mon, 9 Nov 2009 21:00:17 +0000 Subject: fixed folders=on bug for the moment git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1941 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index d2043a93..a6d46c4c 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -176,6 +176,14 @@ const constructor TSong.Create(); begin inherited; + + //dirty fix to fix folders=on + Self.Path := PATH_NONE(); + Self.FileName := PATH_NONE(); + Self.Cover := PATH_NONE(); + Self.Mp3 := PATH_NONE(); + Self.Background:= PATH_NONE(); + Self.Video := PATH_NONE(); end; // This may be changed, when we rewrite song select code. -- cgit v1.2.3 From ec75bc2b03e707c479f3605ffc1a8d9fe38c165b Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Tue, 17 Nov 2009 15:25:54 +0000 Subject: header tags that are not supported are written to the end of the songheader when saving in editor fixed header reader ending in infinite loop when there is a header line w/o Colon git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1943 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 8 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index a6d46c4c..d76718d2 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -76,6 +76,14 @@ type Score: integer; 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 } + TCustomHeaderTag = record + Tag: UTF8String; + Content: UTF8String; + end; + TSong = class private FileLineNo : integer; // line, which is read last, for error reporting @@ -91,12 +99,11 @@ type function ParseLyricCharParam(const Line: RawByteString; var LinePos: integer): AnsiChar; function ParseLyricText(const Line: RawByteString; var LinePos: integer): RawByteString; - function ReadTXTHeader(SongFile: TTextFileStream): boolean; + function ReadTXTHeader(SongFile: TTextFileStream; ReadCustomTags: Boolean): boolean; function ReadXMLHeader(const aFileName: IPath): boolean; function GetFolderCategory(const aFileName: IPath): UTF8String; function FindSongFile(Dir: IPath; Mask: UTF8String): IPath; - public Path: IPath; // kust path component of file (only set if file was found) Folder: UTF8String; // for sorting by folder (only set if file was found) @@ -131,6 +138,8 @@ type Encoding: TEncoding; + CustomTags: array of TCustomHeaderTag; + Score: array[0..2] of array of TScore; // these are used when sorting is enabled @@ -154,7 +163,7 @@ type constructor Create(const aFileName : IPath); overload; function LoadSong: boolean; function LoadXMLSong: boolean; - function Analyse(): boolean; + function Analyse(const ReadCustomTags: Boolean = false): boolean; function AnalyseXML(): boolean; procedure Clear(); end; @@ -177,6 +186,7 @@ constructor TSong.Create(); begin inherited; + // to-do : special create for category "songs" //dirty fix to fix folders=on Self.Path := PATH_NONE(); Self.FileName := PATH_NONE(); @@ -211,7 +221,7 @@ begin if (aFileName.IsChildOf(CurSongPath, true)) then begin // songs are in the "root" of the songdir => use songdir for the categorys name - Result := CurSongPath.ToUTF8; // TODO: remove trailing path-delim? + Result := CurSongPath.RemovePathDelim.ToUTF8; end else begin @@ -824,7 +834,6 @@ begin end; - {** * "International" StrToFloat variant. Uses either ',' or '.' as decimal * separator. @@ -839,7 +848,7 @@ begin Result := StrToFloatDef(TempValue, 0); end; -function TSong.ReadTXTHeader(SongFile: TTextFileStream): boolean; +function TSong.ReadTXTHeader(SongFile: TTextFileStream; ReadCustomTags: Boolean): boolean; var Line, Identifier: string; Value: string; @@ -847,6 +856,21 @@ var Done: byte; // bit-vector of mandatory fields EncFile: IPath; // encoded filename FullFileName: string; + + { adds a custom header tag to the song + if there is no ':' in the read line, Tag should be empty + and the whole line should be in Content } + procedure AddCustomTag(const Tag, Content: String); + var Len: Integer; + begin + if ReadCustomTags then + begin + Len := Length(CustomTags); + SetLength(CustomTags, Len + 1); + CustomTags[Len].Tag := DecodeStringUTF8(Tag, Encoding); + CustomTags[Len].Content := DecodeStringUTF8(Content, Encoding); + end; + end; begin Result := true; Done := 0; @@ -876,7 +900,17 @@ begin //Line has no Seperator, ignore non header field if (SepPos = 0) then + begin + AddCustomTag('', Copy(Line, 2, Length(Line) - 1)); + // read next line + if (not SongFile.ReadLine(Line)) then + begin + Result := false; + Log.LogError('File incomplete or not Ultrastar txt (A): ' + FullFileName); + Break; + end; Continue; + end; //Read Identifier and Value Identifier := UpperCase(Trim(Copy(Line, 2, SepPos - 2))); //Uppercase is for Case Insensitive Checks @@ -887,6 +921,7 @@ begin begin Log.LogWarn('Empty field "'+Identifier+'" in file ' + FullFileName, 'TSong.ReadTXTHeader'); + AddCustomTag(Identifier, ''); end else begin @@ -1034,6 +1069,12 @@ begin else if (Identifier = 'ENCODING') then begin self.Encoding := ParseEncoding(Value, DEFAULT_ENCODING); + end + + // unsupported tag + else + begin + AddCustomTag(Identifier, Value); end; end; // End check for non-empty Value @@ -1220,6 +1261,9 @@ begin // set to default encoding Encoding := DEFAULT_ENCODING; + // clear custom header tags + SetLength(CustomTags, 0); + //Required Information Mp3 := PATH_NONE; SetLength(BPM, 0); @@ -1240,7 +1284,7 @@ begin Relative := false; end; -function TSong.Analyse(): boolean; +function TSong.Analyse(const ReadCustomTags: Boolean): boolean; var SongFile: TTextFileStream; begin @@ -1256,7 +1300,7 @@ begin Self.clear; //Read Header - Result := Self.ReadTxTHeader(SongFile) + Result := Self.ReadTxTHeader(SongFile, ReadCustomTags) finally SongFile.Free; end; -- cgit v1.2.3 From 61eaa45ee2bf7fc1d91faae3d10f3e093e3bc42c Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Tue, 17 Nov 2009 15:37:08 +0000 Subject: load and save year tag sorting by year still missing git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1944 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index d76718d2..33e8d8df 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -119,6 +119,7 @@ type Genre: UTF8String; Edition: UTF8String; Language: UTF8String; + Year: Integer; Title: UTF8String; Artist: UTF8String; @@ -1034,6 +1035,12 @@ begin DecodeStringUTF8(Value, Language, Encoding) end + //Language Sorting + else if (Identifier = 'YEAR') then + begin + TryStrtoInt(Value, self.Year) + end + // Song Start else if (Identifier = 'START') then begin @@ -1256,7 +1263,8 @@ begin //Sortings: Genre := 'Unknown'; Edition := 'Unknown'; - Language := 'Unknown'; //Language Patch + Language := 'Unknown'; + Year := 0; // set to default encoding Encoding := DEFAULT_ENCODING; -- cgit v1.2.3 From 735a5b67345e2888de89d89b4f31b4d48c06f9ec Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Tue, 24 Nov 2009 20:04:01 +0000 Subject: use second players color to indicate selected note in editor git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1960 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 33e8d8df..f8d465c7 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -1206,6 +1206,8 @@ begin if Note[HighNote].Tone < BaseNote then BaseNote := Note[HighNote].Tone; + Note[HighNote].Color := 1; // default color to 1 for editor + DecodeStringUTF8(LyricS, Note[HighNote].Text, Encoding); Lyric := Lyric + Note[HighNote].Text; -- cgit v1.2.3 From d589e6221ffcafc077eeefaa60cdc3e33a800558 Mon Sep 17 00:00:00 2001 From: s_alexander Date: Sat, 5 Dec 2009 12:26:00 +0000 Subject: added autodetection of utf8 used w3c regex to match all song lines whether they are utf8 lines and decode it on match as utf8 and as latin1 otherwise git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1964 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index f8d465c7..f8698d43 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -114,7 +114,7 @@ type Mp3: IPath; Background: IPath; Video: IPath; - + // sorting methods Genre: UTF8String; Edition: UTF8String; @@ -127,7 +127,7 @@ type Creator: UTF8String; CoverTex: TTexture; - + VideoGAP: real; NotesGAP: integer; Start: real; // in seconds @@ -180,8 +180,7 @@ uses UNote; //needed for Player const - // use USDX < 1.1 encoding for backward compatibility - DEFAULT_ENCODING = encCP1252; + DEFAULT_ENCODING = encAuto; constructor TSong.Create(); begin @@ -381,7 +380,7 @@ begin LinePos := OldLinePos; raise EUSDXParseException.Create('Character expected'); end; - Result := Str[1]; + Result := Str[1]; end; {** @@ -926,7 +925,7 @@ begin end else begin - + //----------- //Required Attributes //----------- @@ -1083,7 +1082,7 @@ begin begin AddCustomTag(Identifier, Value); end; - + end; // End check for non-empty Value // read next line @@ -1265,7 +1264,7 @@ begin //Sortings: Genre := 'Unknown'; Edition := 'Unknown'; - Language := 'Unknown'; + Language := 'Unknown'; Year := 0; // set to default encoding -- cgit v1.2.3 From 13220c16acafe9e9c1cab5a59a6be4ce38b43754 Mon Sep 17 00:00:00 2001 From: s_alexander Date: Sun, 6 Dec 2009 12:13:34 +0000 Subject: Add Date to Score, Filter Players, Switch Difficulty - ID: 2901824 applied patch form sf.net bug tracker (id: 2901824) thanks to brunzelchen - Add a date-column to the score entries (UNIX-Timestamp); the date will be shown on Top5- und Stats Screen! - The Players on Top-5-Screen are now filtered: Every player with his best score! - You can switch through the difficulties on Top-5-Screen git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1972 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 1 + 1 file changed, 1 insertion(+) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index f8698d43..c465f198 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -74,6 +74,7 @@ type TScore = record Name: UTF8String; Score: integer; + Date: UTF8String; end; { used to hold header tags that are not supported by this version of -- cgit v1.2.3 From d803b2322d8322a8e3fab7cffb043c0c62d94c9d Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sun, 13 Dec 2009 11:04:30 +0000 Subject: fixed bug in song parser that may lead to an Access Violation git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2023 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index c465f198..47200e63 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -483,7 +483,7 @@ begin while true do begin - LinePos := 0; + LinePos := 1; Param0 := ParseLyricCharParam(CurLine, LinePos); if (Param0 = 'E') then -- cgit v1.2.3 From 9902c756e8a15bb4582cdc43bb94378f29de0999 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sun, 13 Dec 2009 11:16:12 +0000 Subject: use TryStrToInt and TryStrToFloat instead of try .. except block may increase performance at least for medley branch git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2024 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 47200e63..151ad73d 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -96,7 +96,7 @@ type function ParseLyricStringParam(const Line: RawByteString; var LinePos: integer): RawByteString; function ParseLyricIntParam(const Line: RawByteString; var LinePos: integer): integer; - function ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): real; + function ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): extended; function ParseLyricCharParam(const Line: RawByteString; var LinePos: integer): AnsiChar; function ParseLyricText(const Line: RawByteString; var LinePos: integer): RawByteString; @@ -346,24 +346,26 @@ var begin OldLinePos := LinePos; Str := ParseLyricStringParam(Line, LinePos); - try - Result := StrToInt(Str); - except // on EConvertError + + if not TryStrToInt(Str, Result) then + begin // on convert error + Result := 0; LinePos := OldLinePos; raise EUSDXParseException.Create('Integer expected'); end; end; -function TSong.ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): real; +function TSong.ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): extended; var Str: RawByteString; OldLinePos: integer; begin OldLinePos := LinePos; Str := ParseLyricStringParam(Line, LinePos); - try - Result := StrToFloat(Str); - except // on EConvertError + + if not TryStrToFloat(Str, Result) then + begin // on convert error + Result := 0; LinePos := OldLinePos; raise EUSDXParseException.Create('Float expected'); end; -- cgit v1.2.3 From bc2e9999248beb57e85d3ae9d0f154eb1c3c1c52 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sun, 13 Dec 2009 11:27:28 +0000 Subject: added a note concerning song parser needs to be fixed before release git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2025 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 151ad73d..fccf2757 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -380,6 +380,14 @@ begin Str := ParseLyricStringParam(Line, LinePos); if (Length(Str) <> 1) then begin + { to-do : decide what to do here + usdx < 1.1 does not nead a whitespace after a char param + so we may just write a warning to error.log and use the + first non whitespace character instead of raising an + exception that causes the song not to load. So the more + error resistant code is: + LinePos := OldLinePos + 1; + // raise EUSDXParseException.Create('Character expected'); } LinePos := OldLinePos; raise EUSDXParseException.Create('Character expected'); end; -- cgit v1.2.3 From 5d1e512e23f6506f270868f1509397674c2e4d5b Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Fri, 18 Dec 2009 16:12:33 +0000 Subject: change zero note error to warning with better description git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2050 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index fccf2757..705206c4 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -510,7 +510,9 @@ begin //Check for ZeroNote if Param2 = 0 then - Log.LogError('Found zero-length note at "'+Param0+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamLyric+'" -> Note ignored!') + Log.LogWarn(Format('"%s" in line %d: %s', + [FileNamePath.ToNative, FileLineNo, 'found note with length zero -> note ignored']), 'TSong.LoadSong') + //Log.LogError('Found zero-length note at "'+Param0+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamLyric+'" -> Note ignored!') else begin // add notes -- cgit v1.2.3 From 52cc4b6e5416c1bcd4e94abcec2e9532e4f66403 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Wed, 14 Apr 2010 11:45:52 +0000 Subject: completly remove solmization new default values: - bgmusic = on - lyriceffect = shift git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2237 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 705206c4..07b1a6b5 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -90,7 +90,6 @@ type FileLineNo : integer; // line, which is read last, for error reporting function DecodeFilename(Filename: RawByteString): IPath; - function Solmizate(Note: integer; Type_: integer): string; procedure ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: UTF8String); procedure NewSentence(LineNumberP: integer; Param1, Param2: integer); @@ -1135,53 +1134,8 @@ begin Result := -1; end; -function TSong.Solmizate(Note: integer; Type_: integer): string; -begin - case (Type_) of - 1: // european - begin - case (Note mod 12) of - 0..1: Result := ' do '; - 2..3: Result := ' re '; - 4: Result := ' mi '; - 5..6: Result := ' fa '; - 7..8: Result := ' sol '; - 9..10: Result := ' la '; - 11: Result := ' si '; - end; - end; - 2: // japanese - begin - case (Note mod 12) of - 0..1: Result := ' do '; - 2..3: Result := ' re '; - 4: Result := ' mi '; - 5..6: Result := ' fa '; - 7..8: Result := ' so '; - 9..10: Result := ' la '; - 11: Result := ' shi '; - end; - end; - 3: // american - begin - case (Note mod 12) of - 0..1: Result := ' do '; - 2..3: Result := ' re '; - 4: Result := ' mi '; - 5..6: Result := ' fa '; - 7..8: Result := ' sol '; - 9..10: Result := ' la '; - 11: Result := ' ti '; - end; - end; - end; // case -end; - procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: UTF8String); begin - if (Ini.Solmization <> 0) then - LyricS := Solmizate(NoteP, Ini.Solmization); - with Lines[LineNumber].Line[Lines[LineNumber].High] do begin SetLength(Note, Length(Note) + 1); -- cgit v1.2.3 From 698dff10499ff6bd08a7a23da3c50903216a5384 Mon Sep 17 00:00:00 2001 From: tobigun Date: Mon, 19 Apr 2010 16:12:18 +0000 Subject: reduced verbose output on missing theme and song tags (info instead of warn) git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2250 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 07b1a6b5..597bcb46 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -931,7 +931,7 @@ begin //Check the Identifier (If Value is given) if (Length(Value) = 0) then begin - Log.LogWarn('Empty field "'+Identifier+'" in file ' + FullFileName, + Log.LogInfo('Empty field "'+Identifier+'" in file ' + FullFileName, 'TSong.ReadTXTHeader'); AddCustomTag(Identifier, ''); end -- cgit v1.2.3 From 39cff2441c45040c9260a6f5eba5b8debd66604e Mon Sep 17 00:00:00 2001 From: tobigun Date: Tue, 20 Apr 2010 18:58:10 +0000 Subject: do not handle txt file format errors that strict git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2253 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 597bcb46..a441fe40 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -377,19 +377,20 @@ var begin OldLinePos := LinePos; Str := ParseLyricStringParam(Line, LinePos); - if (Length(Str) <> 1) then + + if (Length(Str) < 1) then begin - { to-do : decide what to do here - usdx < 1.1 does not nead a whitespace after a char param - so we may just write a warning to error.log and use the - first non whitespace character instead of raising an - exception that causes the song not to load. So the more - error resistant code is: - LinePos := OldLinePos + 1; - // raise EUSDXParseException.Create('Character expected'); } LinePos := OldLinePos; raise EUSDXParseException.Create('Character expected'); + end + else if (Length(Str) > 1) then + begin + Log.LogWarn(Format('"%s" in line %d: %s', + [FileName.ToNative, FileLineNo, 'character expected but found "' + Str + '"']), + 'TSong.ParseLyricCharParam'); end; + + LinePos := OldLinePos + 1; Result := Str[1]; end; -- cgit v1.2.3 From 7d7011bd7b2eeac58d660f267abfc62df0dad8f6 Mon Sep 17 00:00:00 2001 From: brunzelchen Date: Sun, 23 May 2010 13:17:45 +0000 Subject: zero-length notes will no longer be ignored. they will be converted into freestyle notes. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2407 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index a441fe40..43251f8f 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -510,22 +510,25 @@ begin //Check for ZeroNote if Param2 = 0 then + begin Log.LogWarn(Format('"%s" in line %d: %s', - [FileNamePath.ToNative, FileLineNo, 'found note with length zero -> note ignored']), 'TSong.LoadSong') + [FileNamePath.ToNative, FileLineNo, + 'found note with length zero -> converted to FreeStyle']), + 'TSong.LoadSong'); //Log.LogError('Found zero-length note at "'+Param0+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamLyric+'" -> Note ignored!') + Param0 := 'F'; + end; + + // add notes + if not Both then + // P1 + ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric) else begin - // add notes - if not Both then - // P1 - ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric) - else - begin - // P1 + P2 - ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric); - ParseNote(1, Param0, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamLyric); - end; - end; //Zeronote check + // P1 + P2 + ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric); + ParseNote(1, Param0, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamLyric); + end; end // if else if Param0 = '-' then -- cgit v1.2.3 From 9033f7e98be7a2bc9221af9903ac5b8b1d098782 Mon Sep 17 00:00:00 2001 From: tobigun Date: Sat, 12 Jun 2010 19:07:39 +0000 Subject: Previously removed option Lyrics:Encoding now back in config.ini: - Possible values: Auto/CP1250/CP1252/UTF8/Locale - Default: Auto - Recommended: Auto or UTF8 - IMPORTANT: CP1250(old US default), CP1252 (old USDX default) and Locale (country specific) are only for backwards compatibility and should not be used as they break portability git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2507 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/base/USong.pas | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/base/USong.pas') diff --git a/src/base/USong.pas b/src/base/USong.pas index 43251f8f..e92c5b45 100644 --- a/src/base/USong.pas +++ b/src/base/USong.pas @@ -179,9 +179,6 @@ uses UMusic, //needed for Lines UNote; //needed for Player -const - DEFAULT_ENCODING = encAuto; - constructor TSong.Create(); begin inherited; @@ -1090,7 +1087,7 @@ begin // File encoding else if (Identifier = 'ENCODING') then begin - self.Encoding := ParseEncoding(Value, DEFAULT_ENCODING); + self.Encoding := ParseEncoding(Value, Ini.DefaultEncoding); end // unsupported tag @@ -1239,7 +1236,7 @@ begin Year := 0; // set to default encoding - Encoding := DEFAULT_ENCODING; + Encoding := Ini.DefaultEncoding; // clear custom header tags SetLength(CustomTags, 0); -- cgit v1.2.3