aboutsummaryrefslogtreecommitdiffstats
path: root/unicode/src/base
diff options
context:
space:
mode:
Diffstat (limited to 'unicode/src/base')
-rw-r--r--unicode/src/base/UDataBase.pas44
-rw-r--r--unicode/src/base/UIni.pas17
-rw-r--r--unicode/src/base/USong.pas422
-rw-r--r--unicode/src/base/USongs.pas212
4 files changed, 390 insertions, 305 deletions
diff --git a/unicode/src/base/UDataBase.pas b/unicode/src/base/UDataBase.pas
index 0f9d88a7..87e9519c 100644
--- a/unicode/src/base/UDataBase.pas
+++ b/unicode/src/base/UDataBase.pas
@@ -58,29 +58,29 @@ type
TStatResultBestScores = class(TStatResult)
public
- Singer: WideString;
+ Singer: UTF8String;
Score: Word;
Difficulty: Byte;
- SongArtist: WideString;
- SongTitle: WideString;
+ SongArtist: UTF8String;
+ SongTitle: UTF8String;
end;
TStatResultBestSingers = class(TStatResult)
public
- Player: WideString;
+ Player: UTF8String;
AverageScore: Word;
end;
TStatResultMostSungSong = class(TStatResult)
public
- Artist: WideString;
- Title: WideString;
+ Artist: UTF8String;
+ Title: UTF8String;
TimesSung: Word;
end;
TStatResultMostPopBand = class(TStatResult)
public
- ArtistName: WideString;
+ ArtistName: UTF8String;
TimesSungTot: Word;
end;
@@ -99,7 +99,7 @@ type
procedure Init(const Filename: string);
procedure ReadScore(Song: TSong);
- procedure AddScore(Song: TSong; Level: integer; const Name: WideString; Score: integer);
+ procedure AddScore(Song: TSong; Level: integer; const Name: UTF8String; Score: integer);
procedure WriteScore(Song: TSong);
function GetStats(Typ: TStatType; Count: Byte; Page: Cardinal; Reversed: Boolean): TList;
@@ -237,7 +237,7 @@ begin
'WHERE [Artist] = ? AND [Title] = ? ' +
'LIMIT 1) ' +
'ORDER BY [Score] DESC LIMIT 15',
- [UTF8Encode(Song.Artist), UTF8Encode(Song.Title)]);
+ [Song.Artist, Song.Title]);
// Empty Old Scores
SetLength(Song.Score[0], 0);
@@ -255,7 +255,7 @@ begin
SetLength(Song.Score[Difficulty], Length(Song.Score[Difficulty]) + 1);
Song.Score[Difficulty, High(Song.Score[Difficulty])].Name :=
- UTF8Decode(TableData.FieldByName['Player']);
+ TableData.FieldByName['Player'];
Song.Score[Difficulty, High(Song.Score[Difficulty])].Score :=
TableData.FieldAsInteger(TableData.FieldIndex['Score']);
end;
@@ -277,7 +277,7 @@ end;
(**
* Adds one new score to DB
*)
-procedure TDataBaseSystem.AddScore(Song: TSong; Level: integer; const Name: WideString; Score: integer);
+procedure TDataBaseSystem.AddScore(Song: TSong; Level: integer; const Name: UTF8String; Score: integer);
var
ID: Integer;
TableData: TSQLiteTable;
@@ -296,7 +296,7 @@ begin
ID := ScoreDB.GetTableValue(
'SELECT [ID] FROM ['+cUS_Songs+'] ' +
'WHERE [Artist] = ? AND [Title] = ?',
- [UTF8Encode(Song.Artist), UTF8Encode(Song.Title)]);
+ [Song.Artist, Song.Title]);
if (ID = 0) then
begin
// Create song if it does not exist
@@ -304,7 +304,7 @@ begin
'INSERT INTO ['+cUS_Songs+'] ' +
'([ID], [Artist], [Title], [TimesPlayed]) VALUES ' +
'(NULL, ?, ?, 0);',
- [UTF8Encode(Song.Artist), UTF8Encode(Song.Title)]);
+ [Song.Artist, Song.Title]);
// Get song-ID
ID := ScoreDB.GetLastInsertRowID();
end;
@@ -313,7 +313,7 @@ begin
'INSERT INTO ['+cUS_Scores+'] ' +
'([SongID] ,[Difficulty], [Player], [Score]) VALUES ' +
'(?, ?, ?, ?);',
- [ID, Level, UTF8Encode(Name), Score]);
+ [ID, Level, Name, Score]);
// Delete last position when there are more than 5 entrys.
// Fixes crash when there are > 5 ScoreEntrys
@@ -364,7 +364,7 @@ begin
'UPDATE ['+cUS_Songs+'] ' +
'SET [TimesPlayed] = [TimesPlayed] + 1 ' +
'WHERE [Title] = ? AND [Artist] = ?;',
- [UTF8Encode(Song.Title), UTF8Encode(Song.Artist)]);
+ [Song.Title, Song.Artist]);
except on E: Exception do
Log.LogError(E.Message, 'TDataBaseSystem.WriteScore');
end;
@@ -437,18 +437,18 @@ begin
Stat := TStatResultBestScores.Create;
with TStatResultBestScores(Stat) do
begin
- Singer := UTF8Decode(TableData.Fields[0]);
+ Singer := TableData.Fields[0];
Difficulty := TableData.FieldAsInteger(1);
Score := TableData.FieldAsInteger(2);
- SongArtist := UTF8Decode(TableData.Fields[3]);
- SongTitle := UTF8Decode(TableData.Fields[4]);
+ SongArtist := TableData.Fields[3];
+ SongTitle := TableData.Fields[4];
end;
end;
stBestSingers: begin
Stat := TStatResultBestSingers.Create;
with TStatResultBestSingers(Stat) do
begin
- Player := UTF8Decode(TableData.Fields[0]);
+ Player := TableData.Fields[0];
AverageScore := TableData.FieldAsInteger(1);
end;
end;
@@ -456,8 +456,8 @@ begin
Stat := TStatResultMostSungSong.Create;
with TStatResultMostSungSong(Stat) do
begin
- Artist := UTF8Decode(TableData.Fields[0]);
- Title := UTF8Decode(TableData.Fields[1]);
+ Artist := TableData.Fields[0];
+ Title := TableData.Fields[1];
TimesSung := TableData.FieldAsInteger(2);
end;
end;
@@ -465,7 +465,7 @@ begin
Stat := TStatResultMostPopBand.Create;
with TStatResultMostPopBand(Stat) do
begin
- ArtistName := UTF8Decode(TableData.Fields[0]);
+ ArtistName := TableData.Fields[0];
TimesSungTot := TableData.FieldAsInteger(1);
end;
end
diff --git a/unicode/src/base/UIni.pas b/unicode/src/base/UIni.pas
index f50f95ce..2bf49d9d 100644
--- a/unicode/src/base/UIni.pas
+++ b/unicode/src/base/UIni.pas
@@ -37,6 +37,7 @@ uses
Classes,
IniFiles,
ULog,
+ UTextEncoding,
SysUtils;
type
@@ -84,11 +85,11 @@ type
procedure LoadScreenModes(IniFile: TCustomIniFile);
public
- Name: array[0..11] of string;
+ Name: array[0..11] of UTF8String;
// Templates for Names Mod
- NameTeam: array[0..2] of string;
- NameTemplate: array[0..11] of string;
+ NameTeam: array[0..2] of UTF8String;
+ NameTemplate: array[0..11] of UTF8String;
//Filename of the opened iniFile
Filename: string;
@@ -155,6 +156,9 @@ type
// Controller
Joypad: integer;
+ // default encoding for texts (lyrics, song-name, ...)
+ EncodingDefault: TEncoding;
+
procedure Load();
procedure Save();
procedure SaveNames;
@@ -724,6 +728,10 @@ begin
// NoteLines
NoteLines := GetArrayIndex(INoteLines, IniFile.ReadString('Lyrics', 'NoteLines', INoteLines[1]));
+ //Encoding default
+ // CP1252 is the USDX <1.1 default encoding
+ EncodingDefault := ParseEncoding(IniFile.ReadString('Lyrics', 'Encoding', ''), encCP1252);
+
LoadThemes(IniFile);
// Color
@@ -872,6 +880,9 @@ begin
// NoteLines
IniFile.WriteString('Lyrics', 'NoteLines', INoteLines[NoteLines]);
+ //Encoding default
+ IniFile.WriteString('Lyrics', 'Encoding', EncodingNames[EncodingDefault]);
+
// Theme
IniFile.WriteString('Themes', 'Theme', ITheme[Theme]);
diff --git a/unicode/src/base/USong.pas b/unicode/src/base/USong.pas
index cff56c1d..ac134350 100644
--- a/unicode/src/base/USong.pas
+++ b/unicode/src/base/USong.pas
@@ -56,7 +56,8 @@ uses
PseudoThread,
{$ENDIF}
UCatCovers,
- UXMLSong;
+ UXMLSong,
+ UTextEncoding;
type
@@ -68,15 +69,16 @@ type
end;
TScore = record
- Name: WideString;
+ Name: UTF8String;
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);
+ function EncodeFilename(Filename: string): string;
+ 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;
@@ -87,23 +89,24 @@ type
fFileName,
FileName: WideString;
+ // filenames
+ Cover: WideString;
+ Mp3: WideString;
+ Background: WideString;
+ Video: WideString;
+
// 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 +116,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
@@ -129,13 +134,13 @@ type
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 : WideString ); overload;
function LoadSong: boolean;
function LoadXMLSong: boolean;
function Analyse(): boolean;
@@ -185,21 +190,32 @@ begin
end;
end;
+function TSong.EncodeFilename(Filename: string): string;
+begin
+ {$IFDEF UTF8_FILENAMES}
+ Result := RecodeStringUTF8(Filename, Encoding);
+ {$ELSE}
+ // FIXME: just for compatibility, should be UTF-8 in general
+ if (Encoding = encUTF8) then
+ Result := UTF8ToAnsi(Filename)
+ else
+ Result := Filename;
+ {$ENDIF}
+end;
+
//Load TXT Song
function TSong.LoadSong(): boolean;
-
var
TempC: char;
- Text: string;
+ Text: UTF8String;
CP: integer; // Current Player (0 or 1)
Count: integer;
Both: boolean;
Param1: integer;
Param2: integer;
Param3: integer;
- ParamS: string;
+ ParamS: UTF8String;
I: integer;
-
begin
Result := false;
LastError := '';
@@ -242,7 +258,7 @@ begin
ReadLn(SongFile, Text);
Inc(FileLineNo);
- if (EoF(SongFile)) then
+ if (Eof(SongFile)) then
begin //Song File Corrupted - No Notes
CloseFile(SongFile);
Log.LogError('Could not load txt File, no Notes found: ' + FileName);
@@ -342,7 +358,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
@@ -361,7 +377,7 @@ begin
Read(SongFile, TempC);
Inc(FileLineNo);
- end; // while}
+ end; // while
CloseFile(SongFile);
@@ -408,7 +424,6 @@ end;
//Load XML Song
function TSong.LoadXMLSong(): boolean;
-
var
//TempC: char;
Text: string;
@@ -425,7 +440,6 @@ var
NoteType: char;
SentenceEnd, Rest, Time: integer;
Parser: TParser;
-
begin
Result := false;
LastError := '';
@@ -581,13 +595,9 @@ 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;
@@ -647,7 +657,7 @@ begin
// self.Video := Value
// Video Gap
- // self.VideoGAP := song_StrtoFloat( Value )
+ // self.VideoGAP := StrtoFloatI18n( Value )
//Genre Sorting
self.Genre := Parser.SongInfo.Header.Genre;
@@ -686,25 +696,26 @@ end;
function TSong.ReadTXTHeader(const aFileName : WideString): boolean;
- function song_StrtoFloat( aValue : string ) : Extended;
-
+ {**
+ * "International" StrToFloat variant. Uses either ',' or '.' as decimal
+ * separator.
+ *}
+ function StrToFloatI18n(const Value: string): Extended;
var
- lValue : string;
-
+ TempValue : string;
begin
- lValue := aValue;
-
- if (Pos(',', lValue) <> 0) then
- lValue[Pos(',', lValue)] := '.';
-
- Result := StrToFloatDef(lValue, 0);
+ TempValue := Value;
+ if (Pos(',', TempValue) <> 0) then
+ TempValue[Pos(',', TempValue)] := '.';
+ Result := StrToFloatDef(TempValue, 0);
end;
var
- Line, Identifier, Value: string;
- Temp : word;
- Done : byte;
-
+ Line, Identifier: string;
+ Value: string;
+ SepPos: integer; // separator position
+ Done: byte; // bit-vector of mandatory fields
+ EncFile: string; // encoded filename
begin
Result := true;
Done := 0;
@@ -719,153 +730,188 @@ begin
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
- //-----------
+ //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));
- {$IFDEF UTF8_FILENAMES}
- if ((Identifier = 'MP3') or (Identifier = 'BACKGROUND') or (Identifier = 'COVER') or (Identifier = 'VIDEO')) then
- Value := Utf8Encode(Value);
- {$ENDIF}
+ //Check the Identifier (If Value is given)
+ if (Length(Value) = 0) then
+ Continue;
- //Title
- if (Identifier = 'TITLE') then
- begin
- self.Title := Value;
+ //-----------
+ //Required Attributes
+ //-----------
- //Add Title Flag to Done
- Done := Done or 1;
- end
+ if (Identifier = 'TITLE') then
+ begin
+ self.Title := RecodeStringUTF8(Value, Encoding);
- //Artist
- else if (Identifier = 'ARTIST') then
- begin
- self.Artist := Value;
+ //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
+ self.Artist := RecodeStringUTF8(Value, Encoding);
- //MP3 File //Test if Exists
- else if (Identifier = 'MP3') AND
- (FileExists(self.Path + Value)) then
- begin
- self.Mp3 := Value;
+ //Add Artist Flag to Done
+ Done := Done or 2;
+ end
- //Add Mp3 Flag to Done
- Done := Done or 4;
- end
+ //MP3 File
+ else if (Identifier = 'MP3') then
+ begin
+ EncFile := EncodeFilename(Value);
+ if (FileExists(self.Path + EncFile)) then
+ begin
+ self.Mp3 := EncFile;
- //Beats per Minute
- else if (Identifier = 'BPM') then
- begin
- SetLength(self.BPM, 1);
- self.BPM[0].StartBeat := 0;
+ //Add Mp3 Flag to Done
+ Done := Done or 4;
+ end;
+ end
- self.BPM[0].BPM := song_StrtoFloat( Value ) * Mult * MultBPM;
+ //Beats per Minute
+ else if (Identifier = 'BPM') then
+ begin
+ SetLength(self.BPM, 1);
+ self.BPM[0].StartBeat := 0;
- if self.BPM[0].BPM <> 0 then
- begin
- //Add BPM Flag to Done
- Done := Done or 8;
- end;
- end
+ 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
- //---------
- //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 := EncodeFilename(Value);
+ end
- //Background Picture
- else if (Identifier = 'BACKGROUND') then
- self.Background := Value
+ //Background Picture
+ else if (Identifier = 'BACKGROUND') then
+ begin
+ self.Background := EncodeFilename(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 := EncodeFilename(Value);
+ if (FileExists(self.Path + EncFile)) then
+ self.Video := EncFile
+ else
+ Log.LogError('Can''t find Video File in Song: ' + aFileName);
+ 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
+ self.Genre := RecodeStringUTF8(Value, Encoding)
+ end
- //Edition Sorting
- else if (Identifier = 'EDITION') then
- self.Edition := Value
+ //Edition Sorting
+ else if (Identifier = 'EDITION') then
+ begin
+ self.Edition := RecodeStringUTF8(Value, Encoding)
+ end
+
+ //Creator Tag
+ else if (Identifier = 'CREATOR') then
+ begin
+ self.Creator := RecodeStringUTF8(Value, Encoding)
+ end
- //Creator Tag
- else if (Identifier = 'CREATOR') then
- self.Creator := Value
+ //Language Sorting
+ else if (Identifier = 'LANGUAGE') then
+ begin
+ self.Language := RecodeStringUTF8(Value, 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
- self.Relative := True;
+ // Relative Notes
+ else if (Identifier = 'RELATIVE') then
+ begin
+ if (UpperCase(Value) = 'YES') then
+ self.Relative := True;
+ end
- end;
+ // File encoding
+ else if (Identifier = 'ENCODING') then
+ begin
+ self.Encoding := ParseEncoding(Value, Ini.EncodingDefault);
end;
- if not EOf(SongFile) then
- ReadLn (SongFile, Line)
- else
+ // check for end of file
+ if Eof(SongFile) then
begin
Result := False;
Log.LogError('File Incomplete or not Ultrastar TxT (A): ' + aFileName);
- break;
+ Break;
end;
- end;
+ // read next line
+ ReadLn(SongFile, Line)
+ end; // while
if self.Cover = '' then
self.Cover := platform.FindSongFile(Path, '*[CO].jpg');
@@ -896,47 +942,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
@@ -969,7 +1020,9 @@ begin
Note[HighNote].Tone := NoteP;
if Note[HighNote].Tone < Base[LineNumber] then Base[LineNumber] := Note[HighNote].Tone;
- Note[HighNote].Text := Copy(LyricS, 2, 100);
+ Note[HighNote].Text := RecodeStringUTF8(
+ Copy(LyricS, 2, Length(LyricS)-1),
+ Encoding);
Lyric := Lyric + Note[HighNote].Text;
End_ := Note[HighNote].Start + Note[HighNote].Length;
@@ -977,10 +1030,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
@@ -1039,6 +1090,9 @@ begin
Edition := 'Unknown';
Language := 'Unknown'; //Language Patch
+ // set to default encoding
+ Encoding := Ini.EncodingDefault;
+
//Required Information
Mp3 := '';
{$IFDEF FPC}
diff --git a/unicode/src/base/USongs.pas b/unicode/src/base/USongs.pas
index 6f66bf3f..be880433 100644
--- a/unicode/src/base/USongs.pas
+++ b/unicode/src/base/USongs.pas
@@ -156,7 +156,8 @@ uses StrUtils,
UCovers,
UFiles,
UMain,
- UIni;
+ UIni,
+ UUnicodeUtils;
constructor TSongs.Create();
begin
@@ -459,14 +460,14 @@ procedure TCatSongs.Refresh;
var
SongIndex: integer;
CurSong: TSong;
- CatIndex: integer; // index of current song in Song
- Letter: char; // current letter for sorting using letter
- CurCategory: string; // current edition for sorting using edition, genre etc.
- Order: integer; // number used for ordernum
- LetterTmp: char;
- CatNumber: integer; // Number of Song in Category
-
- procedure AddCategoryButton(const CategoryName: string);
+ CatIndex: integer; // index of current song in Song
+ Letter: UCS4Char; // current letter for sorting using letter
+ CurCategory: UTF8String; // current edition for sorting using edition, genre etc.
+ Order: integer; // number used for ordernum
+ LetterTmp: UCS4Char;
+ CatNumber: integer; // Number of Song in Category
+
+ procedure AddCategoryButton(const CategoryName: UTF8String);
var
PrevCatBtnIndex: integer;
begin
@@ -501,7 +502,7 @@ begin
// Note: do NOT set Letter to ' ', otherwise no category-button will be
// created for songs beginning with ' ' if songs of this category exist.
// TODO: trim song-properties so ' ' will not occur as first chararcter.
- Letter := #0;
+ Letter := 0;
// clear song-list
for SongIndex := 0 to Songs.SongList.Count-1 do
@@ -520,101 +521,120 @@ begin
// if tabs are on, add section buttons for each new section
if (Ini.Tabs = 1) then
begin
- if (Ini.Sorting = sEdition) and
- (CompareText(CurCategory, CurSong.Edition) <> 0) then
- begin
- CurCategory := CurSong.Edition;
-
- // TODO: remove this block if it is not needed anymore
- {
- if CurSection = 'Singstar Part 2' then CoverName := 'Singstar';
- if CurSection = 'Singstar German' then CoverName := 'Singstar';
- if CurSection = 'Singstar Spanish' then CoverName := 'Singstar';
- if CurSection = 'Singstar Italian' then CoverName := 'Singstar';
- if CurSection = 'Singstar French' then CoverName := 'Singstar';
- if CurSection = 'Singstar 80s Polish' then CoverName := 'Singstar 80s';
- }
-
- // add Category Button
- AddCategoryButton(CurCategory);
- end
-
- else if (Ini.Sorting = sGenre) and
- (CompareText(CurCategory, CurSong.Genre) <> 0) then
- begin
- CurCategory := CurSong.Genre;
- // add Genre Button
- AddCategoryButton(CurCategory);
- end
-
- else if (Ini.Sorting = sLanguage) and
- (CompareText(CurCategory, CurSong.Language) <> 0) then
- begin
- CurCategory := CurSong.Language;
- // add Language Button
- AddCategoryButton(CurCategory);
- end
+ case (Ini.Sorting) of
+ sEdition: begin
+ if (CompareText(CurCategory, CurSong.Edition) <> 0) then
+ begin
+ CurCategory := CurSong.Edition;
+
+ // TODO: remove this block if it is not needed anymore
+ {
+ if CurSection = 'Singstar Part 2' then CoverName := 'Singstar';
+ if CurSection = 'Singstar German' then CoverName := 'Singstar';
+ if CurSection = 'Singstar Spanish' then CoverName := 'Singstar';
+ if CurSection = 'Singstar Italian' then CoverName := 'Singstar';
+ if CurSection = 'Singstar French' then CoverName := 'Singstar';
+ if CurSection = 'Singstar 80s Polish' then CoverName := 'Singstar 80s';
+ }
+
+ // add Category Button
+ AddCategoryButton(CurCategory);
+ end;
+ end;
- else if (Ini.Sorting = sTitle) and
- (Length(CurSong.Title) >= 1) and
- (Letter <> UpperCase(CurSong.Title)[1]) then
- begin
- Letter := Uppercase(CurSong.Title)[1];
- // add a letter Category Button
- AddCategoryButton(Letter);
- end
+ sGenre: begin
+ if (CompareText(CurCategory, CurSong.Genre) <> 0) then
+ begin
+ CurCategory := CurSong.Genre;
+ // add Genre Button
+ AddCategoryButton(CurCategory);
+ end;
+ end;
- else if (Ini.Sorting = sArtist) and
- (Length(CurSong.Artist) >= 1) and
- (Letter <> UpperCase(CurSong.Artist)[1]) then
- begin
- Letter := UpperCase(CurSong.Artist)[1];
- // add a letter Category Button
- AddCategoryButton(Letter);
- end
+ sLanguage: begin
+ if (CompareText(CurCategory, CurSong.Language) <> 0) then
+ begin
+ CurCategory := CurSong.Language;
+ // add Language Button
+ AddCategoryButton(CurCategory);
+ end
+ end;
- else if (Ini.Sorting = sFolder) and
- (CompareText(CurCategory, CurSong.Folder) <> 0) then
- begin
- CurCategory := CurSong.Folder;
- // add folder tab
- AddCategoryButton(CurCategory);
- end
+ sTitle: begin
+ if (Length(CurSong.Title) >= 1) then
+ begin
+ LetterTmp := UCS4UpperCase(UTF8ToUCS4String(CurSong.Title)[0]);
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
+ end;
- else if (Ini.Sorting = sTitle2) and
- (Length(CurSong.Title) >= 1) then
- begin
- // pack all numbers into a category named '#'
- if (CurSong.Title[1] >= '0') and (CurSong.Title[1] <= '9') then
- LetterTmp := '#'
- else
- LetterTmp := UpperCase(CurSong.Title)[1];
+ sArtist: begin
+ if (Length(CurSong.Artist) >= 1) then
+ begin
+ LetterTmp := UCS4UpperCase(UTF8ToUCS4String(CurSong.Artist)[0]);
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
+ end;
- if (Letter <> LetterTmp) then
- begin
- Letter := LetterTmp;
- // add a letter Category Button
- AddCategoryButton(Letter);
+ sFolder: begin
+ if (CompareText(CurCategory, CurSong.Folder) <> 0) then
+ begin
+ CurCategory := CurSong.Folder;
+ // add folder tab
+ AddCategoryButton(CurCategory);
+ end;
end;
- end
- else if (Ini.Sorting = sArtist2) and
- (Length(CurSong.Artist)>=1) then
- begin
- // pack all numbers into a category named '#'
- if (CurSong.Artist[1] >= '0') and (CurSong.Artist[1] <= '9') then
- LetterTmp := '#'
- else
- LetterTmp := UpperCase(CurSong.Artist)[1];
+ sTitle2: begin
+ if (Length(CurSong.Title) >= 1) then
+ begin
+ LetterTmp := UTF8ToUCS4String(CurSong.Title)[0];
+ // pack all numbers into a category named '#'
+ if (LetterTmp in [UCS4Char('0') .. UCS4Char('9')]) then
+ LetterTmp := UCS4Char('#')
+ else
+ LetterTmp := UCS4UpperCase(LetterTmp);
+
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
+ end;
- if (Letter <> LetterTmp) then
- begin
- Letter := LetterTmp;
- // add a letter Category Button
- AddCategoryButton(Letter);
+ sArtist2: begin
+ if (Length(CurSong.Artist) >= 1) then
+ begin
+ LetterTmp := UTF8ToUCS4String(CurSong.Artist)[0];
+ // pack all numbers into a category named '#'
+ if (LetterTmp in [UCS4Char('0') .. UCS4Char('9')]) then
+ LetterTmp := UCS4Char('#')
+ else
+ LetterTmp := UCS4UpperCase(LetterTmp);
+
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
end;
- end;
- end;
+
+ end; // case (Ini.Sorting)
+ end; // if (Ini.Tabs = 1)
CatIndex := Length(Song);
SetLength(Song, CatIndex+1);