From d97013cb176bdda64e85db47d8e61a50e7e8bfb7 Mon Sep 17 00:00:00 2001 From: tobigun Date: Sun, 27 Jan 2008 10:05:34 +0000 Subject: - Added missing "override" for TSongs.destroy(). - Bugfix: Fixed a severe Race-Condition that crashed USDX on startup from time to time. The race-condition was due to unsuspended thread-creation in the constructor TSongs.create(). If a class is inherited from TThread and calls "inherited create(false)" in its constructor the thread will immediately start its Execute() method, although the overridden constructor is not finished yet and the members may not be initialized (in this case a TList has not been created). NOTE: If you inherit from TThread always create the thread in suspended mode ("inherited create(true)") and call "Resume()" at the end of the constructor. Don't do this if the class is subject to be overriden, otherwise you may get a race-condition in the child-classes then. In this case it would be better if Resume() was called by the creator of the object. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@805 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/USongs.pas | 1785 +++++++++++++++++++++--------------------- 1 file changed, 888 insertions(+), 897 deletions(-) (limited to 'Game/Code') diff --git a/Game/Code/Classes/USongs.pas b/Game/Code/Classes/USongs.pas index 2bf98151..53d5556f 100644 --- a/Game/Code/Classes/USongs.pas +++ b/Game/Code/Classes/USongs.pas @@ -1,897 +1,888 @@ -unit USongs; - -interface - -{$IFDEF FPC} - {$MODE Delphi} -{$ENDIF} - -{$I switches.inc} - -{$IFDEF DARWIN} - {$IFDEF DEBUG} - {$DEFINE USE_PSEUDO_THREAD} - {$ENDIF} -{$ENDIF} - -uses - {$IFDEF MSWINDOWS} - Windows, - {$ifdef Delphi} - DirWatch, - {$endif} - {$ELSE} - {$IFNDEF DARWIN} -// oldlinux, - syscall, - {$ENDIF} - baseunix, - UnixType, - {$ENDIF} - SysUtils, - Classes, - UPlatform, - ULog, - UTexture, - UCommon, - {$IFDEF DARWIN} - cthreads, - {$ENDIF} - {$IFDEF USE_PSEUDO_THREAD} - PseudoThread, - {$ENDIF} - USong, - UCatCovers; - -type - - TBPM = record - BPM: real; - StartBeat: real; - end; - - TScore = record - Name: widestring; - Score: integer; - Length: string; - end; - - - {$IFDEF USE_PSEUDO_THREAD} - TSongs = class( TPseudoThread ) - {$ELSE} - TSongs = class( TThread ) - {$ENDIF} - private - fNotify , - fWatch : longint; - fParseSongDirectory : boolean; - fProcessing : boolean; - {$ifdef Delphi} - fDirWatch : TDirectoryWatch; - {$endif} - procedure int_LoadSongList; - procedure DoDirChanged(Sender: TObject); - protected - procedure Execute; override; - public -// Song : array of TSong; // array of songs - SongList : TList; // array of songs - Selected : integer; // selected song index - constructor create(); - destructor destroy(); - - - procedure LoadSongList; // load all songs - procedure BrowseDir(Dir: widestring); // should return number of songs in the future - procedure Sort(Order: integer); - function FindSongFile(Dir, Mask: widestring): widestring; - property Processing : boolean read fProcessing; - end; - - - TCatSongs = class - Song: array of TSong; // array of categories with songs - Selected: integer; // selected song index - Order: integer; // order type (0=title) - CatNumShow: integer; // Category Number being seen - CatCount: integer; //Number of Categorys - - procedure Refresh; // refreshes arrays by recreating them from Songs array -// procedure Sort(Order: integer); - procedure ShowCategory(Index: integer); // expands all songs in category - procedure HideCategory(Index: integer); // hides all songs in category - procedure ClickCategoryButton(Index: integer); // uses ShowCategory and HideCategory when needed - procedure ShowCategoryList; //Hides all Songs And Show the List of all Categorys - function FindNextVisible(SearchFrom:integer): integer; //Find Next visible Song - function VisibleSongs: integer; // returns number of visible songs (for tabs) - function VisibleIndex(Index: integer): integer; // returns visible song index (skips invisible) - - function SetFilter(FilterStr: String; const fType: Byte): Cardinal; - end; - -var - Songs: TSongs; // all songs - CatSongs: TCatSongs; // categorized songs - -const - IN_ACCESS = $00000001; //* File was accessed */ - IN_MODIFY = $00000002; //* File was modified */ - IN_ATTRIB = $00000004; //* Metadata changed */ - IN_CLOSE_WRITE = $00000008; //* Writtable file was closed */ - IN_CLOSE_NOWRITE = $00000010; //* Unwrittable file closed */ - IN_OPEN = $00000020; //* File was opened */ - IN_MOVED_FROM = $00000040; //* File was moved from X */ - IN_MOVED_TO = $00000080; //* File was moved to Y */ - IN_CREATE = $00000100; //* Subfile was created */ - IN_DELETE = $00000200; //* Subfile was deleted */ - IN_DELETE_SELF = $00000400; //* Self was deleted */ - - -implementation - -uses StrUtils, - UGraphic, - UCovers, - UFiles, - UMain, - UIni; - -{$IFDEF DARWIN} -function AnsiContainsText(const AText, ASubText: string): Boolean; -begin - Result := AnsiPos(AnsiUppercase(ASubText), AnsiUppercase(AText)) > 0; -end; -{$ENDIF} - -constructor TSongs.create(); -begin - inherited create( false ); - self.freeonterminate := true; - - // This check is needed if PseudoThread is used: - if not Assigned(SongList) then - SongList := TList.create(); - - {$ifdef Delphi} - fDirWatch := TDirectoryWatch.create(nil); - fDirWatch.OnChange := DoDirChanged; - fDirWatch.Directory := SongPath; - fDirWatch.WatchSubDirs := true; - fDirWatch.active := true; - {$ENDIF} - - {$IFDEF linux} - (* - Thankyou to : http://www.linuxjournal.com/article/8478 - http://www.tin.org/bin/man.cgi?section=2&topic=inotify_add_watch - *) -(* - fNotify := -1; - fWatch := -1; - - writeln( 'Calling inotify_init' ); - fNotify := Do_SysCall( syscall_nr_inotify_init ); - if ( fNotify < 0 ) then - writeln( 'Filesystem change notification - disabled' ); - writeln( 'Calling inotify_init : '+ inttostr(fNotify) ); - - writeln( 'Calling syscall_nr_inotify_init ('+SongPath+')' ); - fWatch := Do_SysCall( syscall_nr_inotify_init , TSysParam( fNotify ), longint( pchar( SongPath ) ) , IN_MODIFY AND IN_CREATE AND IN_DELETE ); - - if (fWatch < 0) then - writeln ('inotify_add_watch'); - writeln( 'Calling syscall_nr_inotify_init : '+ inttostr(fWatch) ); -*) - {$endif} - -{$IFNDEF USE_PSEUDO_THREAD} -// Setlength(Song, 0); - SongList.clear; -{$ENDIF} -end; - -destructor TSongs.destroy(); -begin - freeandnil( SongList ); -end; - -procedure TSongs.DoDirChanged(Sender: TObject); -begin - LoadSongList(); -end; - -procedure TSongs.Execute(); -var - fChangeNotify : THandle; -begin -{$IFDEF USE_PSEUDO_THREAD} - int_LoadSongList(); -{$ELSE} - fParseSongDirectory := true; - - while not self.terminated do - begin - - if fParseSongDirectory then - begin - writeln( 'int_LoadSongList' ); - int_LoadSongList(); - end; - - self.suspend; - end; -{$ENDIF} -end; - -procedure TSongs.int_LoadSongList; -begin - try - fProcessing := true; - - {$IFDEF USE_PSEUDO_THREAD} - if not Assigned(SongList) then - SongList := TList.create(); - {$ENDIF} - SongList.clear; - Log.LogError('SongList', 'Searching For Songs'); - - // browse directories - BrowseDir(SongPath); - - if UserSongPath <> SongPath then - BrowseDir(UserSongPath); - - if assigned( CatSongs ) then - CatSongs.Refresh; - - if assigned( CatCovers ) then - CatCovers.Load; - - if assigned( Covers ) then - Covers.Load; - - if assigned(ScreenSong) then - begin - ScreenSong.GenerateThumbnails(); - ScreenSong.OnShow; // refresh ScreenSong - end; - - finally - Log.LogError('SongList', 'Search Complete'); - - fParseSongDirectory := false; - fProcessing := false; - end; -end; - - -procedure TSongs.LoadSongList; -begin - fParseSongDirectory := true; - self.resume; -end; - -procedure TSongs.BrowseDir(Dir: widestring); -var - i : Integer; - Files : TDirectoryEntryArray; - lSong : TSong; -begin - - Files := Platform.DirectoryFindFiles( Dir, '.txt', true); - - for i := 0 to Length(Files)-1 do - begin - if Files[i].IsDirectory then - begin - BrowseDir( Dir + Files[i].Name + PathDelim ); - end - else - begin - lSong := TSong.create( Dir + Files[i].Name ); - - if NOT lSong.Analyse then - begin - Log.LogError('AnalyseFile failed for "' + Files[i].Name + '".'); - freeandnil( lSong ); - end - else - begin - SongList.add( lSong ); - end; - - end; - end; - SetLength( Files, 0); -end; - -procedure TSongs.Sort(Order: integer); -var - S: integer; - S2: integer; - TempSong: TSong; -begin - case Order of - sEdition: // by edition - begin - for S2 := 0 to SongList.Count -1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Edition, TSong( SongList[S-1] ).Edition) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; - sGenre: // by genre - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Genre, TSong( SongList[S-1] ).Genre) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; - sTitle: // by title - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Title, TSong( SongList[S-1] ).Title) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - - end; - sArtist: // by artist - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Artist, TSong( SongList[S-1] ).Artist) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; - sFolder: // by folder - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Folder, TSong( SongList[S-1] ).Folder) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; - sTitle2: // by title2 - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Title, TSong( SongList[S-1] ).Title) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - - end; - sArtist2: // by artist2 - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Artist, TSong( SongList[S-1] ).Artist) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; - sLanguage: // by Language - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Language, TSong( SongList[S-1] ).Language) < 0 then - begin - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; - - end; // case -end; - -function TSongs.FindSongFile(Dir, Mask: widestring): widestring; -var - SR: TSearchRec; // for parsing song directory -begin - Result := ''; - if FindFirst(Dir + Mask, faDirectory, SR) = 0 then begin - Result := SR.Name; - end; // if - FindClose(SR); -end; - -procedure TCatSongs.Refresh; -var - S: integer; // temporary song index - CatLen: integer; // length of CatSongs.Song - Letter: char; // current letter for sorting using letter - SS: string; // current edition for sorting using edition, genre etc. - Order: integer; // number used for ordernum - Letter2: char; // - CatNumber:integer; // Number of Song in Category -begin - CatNumShow := -1; -// Songs.Sort(0); // by title - -case Ini.Sorting of - sEdition: begin - Songs.Sort(sArtist); - Songs.Sort(sEdition); - end; - sGenre: begin - Songs.Sort(sArtist); - Songs.Sort(sGenre); - end; - sLanguage: begin - Songs.Sort(sArtist); - Songs.Sort(sLanguage); - end; - sFolder: begin - Songs.Sort(sArtist); - Songs.Sort(sFolder); - end; - sTitle: Songs.Sort(sTitle); - sArtist: Songs.Sort(sArtist); - sTitle2: Songs.Sort(sTitle2); // by title2 - sArtist2: Songs.Sort(sArtist2); // by artist2 - - end; // case - - - Letter := ' '; - SS := ''; - Order := 0; - CatNumber := 0; - - //Songs leeren - SetLength (Song, 0); - - for S := 0 to Songs.SongList.Count-1 do - begin - if (Ini.Tabs = 1) then - if (Ini.Sorting = sEdition) and (CompareText(SS, TSong( Songs.SongList[S] ).Edition) <> 0) then begin - // add Category Button - Inc(Order); - SS := TSong( Songs.SongList[S] ).Edition; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + SS + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - - - // 0.4.3 - // if SS = 'Singstar' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Part 2' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar German' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Spanish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Italian' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar French' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Party' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Party.jpg'; - // if SS = 'Singstar Popworld' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Popworld.jpg'; - // if SS = 'Singstar 80s' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg'; - // if SS = 'Singstar 80s Polish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg'; - // if SS = 'Singstar Rocks' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Rocks.jpg'; - // if SS = 'Singstar Anthems' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Anthems.jpg'; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';//} - - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sGenre) and (CompareText(SS, TSong( Songs.SongList[S] ).Genre) <> 0) then begin - // add Genre Button - Inc(Order); - SS := TSong( Songs.SongList[S] ).Genre; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := SS; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sLanguage) and (CompareText(SS, TSong( Songs.SongList[S] ).Language) <> 0) then begin - // add Language Button - Inc(Order); - SS := TSong( Songs.SongList[S] ).Language; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := SS; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sTitle) and - (Length(TSong( Songs.SongList[S] ).Title)>=1) and - (Letter <> UpperCase(TSong( Songs.SongList[S] ).Title)[1]) then begin - // add a letter Category Button - Inc(Order); - Letter := Uppercase(TSong( Songs.SongList[S] ).Title)[1]; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - - {// cover-patch - if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sArtist) and (Length(TSong( Songs.SongList[S] ).Artist)>=1) and - (Letter <> UpperCase(TSong( Songs.SongList[S] ).Artist)[1]) then begin - // add a letter Category Button - Inc(Order); - Letter := UpperCase(TSong( Songs.SongList[S] ).Artist)[1]; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sFolder) and (CompareText(SS, TSong( Songs.SongList[S] ).Folder) <> 0) then begin - // 0.5.0: add folder tab - Inc(Order); - SS := TSong( Songs.SongList[S] ).Folder; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := SS; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sTitle2) AND (Length(TSong( Songs.SongList[S] ).Title)>=1) then begin - if (ord(TSong( Songs.SongList[S] ).Title[1]) > 47) and (ord(TSong( Songs.SongList[S] ).Title[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(TSong( Songs.SongList[S] ).Title)[1]; - if (Letter <> Letter2) then begin - // add a letter Category Button - Inc(Order); - Letter := Letter2; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end; - end - - else if (Ini.Sorting = sArtist2) AND (Length(TSong( Songs.SongList[S] ).Artist)>=1) then begin - if (ord(TSong( Songs.SongList[S] ).Artist[1]) > 47) and (ord(TSong( Songs.SongList[S] ).Artist[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(TSong( Songs.SongList[S] ).Artist)[1]; - if (Letter <> Letter2) then begin - // add a letter Category Button - Inc(Order); - Letter := Letter2; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then - begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end; - end; - - - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - - Inc (CatNumber); //Increase Number in Cat - - CatSongs.Song[CatLen] := TSong( Songs.SongList[S] ); - CatSongs.Song[CatLen].OrderNum := Order; // assigns category - CatSongs.Song[CatLen].CatNumber := CatNumber; - - if (Ini.Tabs = 0) then CatSongs.Song[CatLen].Visible := true - else if (Ini.Tabs = 1) then CatSongs.Song[CatLen].Visible := false; -// if (Ini.Tabs = 1) and (Order = 1) then CatSongs.Song[CatLen].Visible := true; // open first tab -//CatSongs.Song[CatLen].Visible := true; - - end; -//CatNumber Patch - Set CatNumber of Last Category -if (ini.Tabs_at_startup = 1) And (high(Song) >=1) then - Song[CatLen - CatNumber].CatNumber := CatNumber;//Set CatNumber of Categroy -//CatCount Patch -CatCount := Order; -end; - -procedure TCatSongs.ShowCategory(Index: integer); -var - S: integer; // song -begin - CatNumShow := Index; - for S := 0 to high(CatSongs.Song) do - begin - if (CatSongs.Song[S].OrderNum = Index) AND (Not CatSongs.Song[S].Main) then - CatSongs.Song[S].Visible := true - else - CatSongs.Song[S].Visible := false; - end; -end; - -procedure TCatSongs.HideCategory(Index: integer); // hides all songs in category -var - S: integer; // song -begin - for S := 0 to high(CatSongs.Song) do begin - if not CatSongs.Song[S].Main then - CatSongs.Song[S].Visible := false // hides all at now - end; -end; - -procedure TCatSongs.ClickCategoryButton(Index: integer); -var - Num, S: integer; -begin - Num := CatSongs.Song[Index].OrderNum; - if Num <> CatNumShow then - begin - ShowCategory(Num); - end - else begin - ShowCategoryList; - end; -end; - -//Hide Categorys when in Category Hack -procedure TCatSongs.ShowCategoryList; -var - Num, S: integer; -begin - //Hide All Songs Show All Cats - for S := 0 to high(CatSongs.Song) do begin - if CatSongs.Song[S].Main then - CatSongs.Song[S].Visible := true - else - CatSongs.Song[S].Visible := false - end; - CatSongs.Selected := CatNumShow; //Show last shown Category - CatNumShow := -1; -end; -//Hide Categorys when in Category Hack End - -//Wrong song selected when tabs on bug -function TCatSongs.FindNextVisible(SearchFrom:integer): integer;//Find next Visible Song -var - I: Integer; - begin - Result := -1; - I := SearchFrom + 1; - while not CatSongs.Song[I].Visible do - begin - Inc (I); - if (I>high(CatSongs.Song)) then - I := low(CatSongs.Song); - if (I = SearchFrom) then //Make One Round and no song found->quit - break; - end; - end; -//Wrong song selected when tabs on bug End - -function TCatSongs.VisibleSongs: integer; -var - S: integer; // song -begin - Result := 0; - for S := 0 to high(CatSongs.Song) do - if CatSongs.Song[S].Visible = true then Inc(Result); -end; - -function TCatSongs.VisibleIndex(Index: integer): integer; -var - S: integer; // song -begin - Result := 0; - for S := 0 to Index-1 do - if CatSongs.Song[S].Visible = true then Inc(Result); -end; - -function TCatSongs.SetFilter(FilterStr: String; const fType: Byte): Cardinal; -var - I, J: Integer; - cString: String; - SearchStr: Array of String; -begin - {fType: 0: All - 1: Title - 2: Artist} - FilterStr := Trim(FilterStr); - if FilterStr<>'' then begin - Result := 0; - //Create Search Array - SetLength(SearchStr, 1); - I := Pos (' ', FilterStr); - While (I <> 0) do - begin - SetLength (SearchStr, Length(SearchStr) + 1); - cString := Copy(FilterStr, 1, I-1); - if (cString <> ' ') AND (cString <> '') then - SearchStr[High(SearchStr)-1] := cString; - Delete (FilterStr, 1, I); - - I := Pos (' ', FilterStr); - end; - //Copy last Word - if (FilterStr <> ' ') AND (FilterStr <> '') then - SearchStr[High(SearchStr)] := FilterStr; - - for I:=0 to High(Song) do begin - if not Song[i].Main then - begin - case fType of - 0: cString := Song[I].Artist + ' ' + Song[i].Title + ' ' + Song[i].Folder; - 1: cString := Song[I].Title; - 2: cString := Song[I].Artist; - end; - Song[i].Visible:=True; - //Look for every Searched Word - For J := 0 to High(SearchStr) do - begin - Song[i].Visible := Song[i].Visible AND AnsiContainsText(cString, SearchStr[J]) - end; - if Song[i].Visible then - Inc(Result); - end - else - Song[i].Visible:=False; - end; - CatNumShow := -2; - end - else begin - for i:=0 to High(Song) do begin - Song[i].Visible:=(Ini.Tabs=1)=Song[i].Main; - CatNumShow := -1; - end; - Result := 0; - end; -end; - - - -// ----------------------------------------------------------------------------- - - - - -end. +unit USongs; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +{$IFDEF DARWIN} + {$IFDEF DEBUG} + {$DEFINE USE_PSEUDO_THREAD} + {$ENDIF} +{$ENDIF} + +uses + {$IFDEF MSWINDOWS} + Windows, + {$IFDEF Delphi} + DirWatch, + {$ENDIF} + {$ELSE} + {$IFNDEF DARWIN} + syscall, + {$ENDIF} + baseunix, + UnixType, + {$ENDIF} + SysUtils, + Classes, + UPlatform, + ULog, + UTexture, + UCommon, + {$IFDEF DARWIN} + cthreads, + {$ENDIF} + {$IFDEF USE_PSEUDO_THREAD} + PseudoThread, + {$ENDIF} + USong, + UCatCovers; + +type + + TBPM = record + BPM: real; + StartBeat: real; + end; + + TScore = record + Name: widestring; + Score: integer; + Length: string; + end; + + + {$IFDEF USE_PSEUDO_THREAD} + TSongs = class( TPseudoThread ) + {$ELSE} + TSongs = class( TThread ) + {$ENDIF} + private + fNotify , + fWatch : longint; + fParseSongDirectory : boolean; + fProcessing : boolean; + {$ifdef Delphi} + fDirWatch : TDirectoryWatch; + {$endif} + procedure int_LoadSongList; + procedure DoDirChanged(Sender: TObject); + protected + procedure Execute; override; + public +// Song : array of TSong; // array of songs + SongList : TList; // array of songs + Selected : integer; // selected song index + constructor create(); + destructor destroy(); override; + + + procedure LoadSongList; // load all songs + procedure BrowseDir(Dir: widestring); // should return number of songs in the future + procedure Sort(Order: integer); + function FindSongFile(Dir, Mask: widestring): widestring; + property Processing : boolean read fProcessing; + end; + + + TCatSongs = class + Song: array of TSong; // array of categories with songs + Selected: integer; // selected song index + Order: integer; // order type (0=title) + CatNumShow: integer; // Category Number being seen + CatCount: integer; //Number of Categorys + + procedure Refresh; // refreshes arrays by recreating them from Songs array +// procedure Sort(Order: integer); + procedure ShowCategory(Index: integer); // expands all songs in category + procedure HideCategory(Index: integer); // hides all songs in category + procedure ClickCategoryButton(Index: integer); // uses ShowCategory and HideCategory when needed + procedure ShowCategoryList; //Hides all Songs And Show the List of all Categorys + function FindNextVisible(SearchFrom:integer): integer; //Find Next visible Song + function VisibleSongs: integer; // returns number of visible songs (for tabs) + function VisibleIndex(Index: integer): integer; // returns visible song index (skips invisible) + + function SetFilter(FilterStr: String; const fType: Byte): Cardinal; + end; + +var + Songs: TSongs; // all songs + CatSongs: TCatSongs; // categorized songs + +const + IN_ACCESS = $00000001; //* File was accessed */ + IN_MODIFY = $00000002; //* File was modified */ + IN_ATTRIB = $00000004; //* Metadata changed */ + IN_CLOSE_WRITE = $00000008; //* Writtable file was closed */ + IN_CLOSE_NOWRITE = $00000010; //* Unwrittable file closed */ + IN_OPEN = $00000020; //* File was opened */ + IN_MOVED_FROM = $00000040; //* File was moved from X */ + IN_MOVED_TO = $00000080; //* File was moved to Y */ + IN_CREATE = $00000100; //* Subfile was created */ + IN_DELETE = $00000200; //* Subfile was deleted */ + IN_DELETE_SELF = $00000400; //* Self was deleted */ + + +implementation + +uses StrUtils, + UGraphic, + UCovers, + UFiles, + UMain, + UIni; + +{$IFDEF DARWIN} +function AnsiContainsText(const AText, ASubText: string): Boolean; +begin + Result := AnsiPos(AnsiUppercase(ASubText), AnsiUppercase(AText)) > 0; +end; +{$ENDIF} + +constructor TSongs.create(); +begin + // do not start thread BEFORE initialization (suspended = true) + inherited create( true ); + self.freeonterminate := true; + + SongList := TList.create(); + + {$ifdef Delphi} + fDirWatch := TDirectoryWatch.create(nil); + fDirWatch.OnChange := DoDirChanged; + fDirWatch.Directory := SongPath; + fDirWatch.WatchSubDirs := true; + fDirWatch.active := true; + {$ENDIF} + + {$IFDEF linux} + (* + Thankyou to : http://www.linuxjournal.com/article/8478 + http://www.tin.org/bin/man.cgi?section=2&topic=inotify_add_watch + *) +(* + fNotify := -1; + fWatch := -1; + + writeln( 'Calling inotify_init' ); + fNotify := Do_SysCall( syscall_nr_inotify_init ); + if ( fNotify < 0 ) then + writeln( 'Filesystem change notification - disabled' ); + writeln( 'Calling inotify_init : '+ inttostr(fNotify) ); + + writeln( 'Calling syscall_nr_inotify_init ('+SongPath+')' ); + fWatch := Do_SysCall( syscall_nr_inotify_init , TSysParam( fNotify ), longint( pchar( SongPath ) ) , IN_MODIFY AND IN_CREATE AND IN_DELETE ); + + if (fWatch < 0) then + writeln ('inotify_add_watch'); + writeln( 'Calling syscall_nr_inotify_init : '+ inttostr(fWatch) ); +*) + {$endif} + + // now we can start the thread + Resume(); +end; + +destructor TSongs.destroy(); +begin + freeandnil( SongList ); +end; + +procedure TSongs.DoDirChanged(Sender: TObject); +begin + LoadSongList(); +end; + +procedure TSongs.Execute(); +var + fChangeNotify : THandle; +begin +{$IFDEF USE_PSEUDO_THREAD} + int_LoadSongList(); +{$ELSE} + fParseSongDirectory := true; + + while not self.terminated do + begin + + if fParseSongDirectory then + begin + writeln( 'int_LoadSongList' ); + int_LoadSongList(); + end; + + self.suspend; + end; +{$ENDIF} +end; + +procedure TSongs.int_LoadSongList; +begin + try + fProcessing := true; + + Log.LogError('SongList', 'Searching For Songs'); + + // browse directories + BrowseDir(SongPath); + + if UserSongPath <> SongPath then + BrowseDir(UserSongPath); + + if assigned( CatSongs ) then + CatSongs.Refresh; + + if assigned( CatCovers ) then + CatCovers.Load; + + if assigned( Covers ) then + Covers.Load; + + if assigned(ScreenSong) then + begin + ScreenSong.GenerateThumbnails(); + ScreenSong.OnShow; // refresh ScreenSong + end; + + finally + Log.LogError('SongList', 'Search Complete'); + + fParseSongDirectory := false; + fProcessing := false; + end; +end; + + +procedure TSongs.LoadSongList; +begin + fParseSongDirectory := true; + self.resume; +end; + +procedure TSongs.BrowseDir(Dir: widestring); +var + i : Integer; + Files : TDirectoryEntryArray; + lSong : TSong; +begin + + Files := Platform.DirectoryFindFiles( Dir, '.txt', true); + + for i := 0 to Length(Files)-1 do + begin + if Files[i].IsDirectory then + begin + BrowseDir( Dir + Files[i].Name + PathDelim ); + end + else + begin + lSong := TSong.create( Dir + Files[i].Name ); + + if NOT lSong.Analyse then + begin + Log.LogError('AnalyseFile failed for "' + Files[i].Name + '".'); + freeandnil( lSong ); + end + else + begin + SongList.add( lSong ); + end; + + end; + end; + SetLength( Files, 0); +end; + +procedure TSongs.Sort(Order: integer); +var + S: integer; + S2: integer; + TempSong: TSong; +begin + case Order of + sEdition: // by edition + begin + for S2 := 0 to SongList.Count -1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Edition, TSong( SongList[S-1] ).Edition) < 0 then + begin + // zamiana miejscami + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + end; + sGenre: // by genre + begin + for S2 := 0 to SongList.Count-1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Genre, TSong( SongList[S-1] ).Genre) < 0 then + begin + // zamiana miejscami + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + end; + sTitle: // by title + begin + for S2 := 0 to SongList.Count-1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Title, TSong( SongList[S-1] ).Title) < 0 then + begin + // zamiana miejscami + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + + end; + sArtist: // by artist + begin + for S2 := 0 to SongList.Count-1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Artist, TSong( SongList[S-1] ).Artist) < 0 then + begin + // zamiana miejscami + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + end; + sFolder: // by folder + begin + for S2 := 0 to SongList.Count-1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Folder, TSong( SongList[S-1] ).Folder) < 0 then + begin + // zamiana miejscami + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + end; + sTitle2: // by title2 + begin + for S2 := 0 to SongList.Count-1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Title, TSong( SongList[S-1] ).Title) < 0 then + begin + // zamiana miejscami + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + + end; + sArtist2: // by artist2 + begin + for S2 := 0 to SongList.Count-1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Artist, TSong( SongList[S-1] ).Artist) < 0 then + begin + // zamiana miejscami + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + end; + sLanguage: // by Language + begin + for S2 := 0 to SongList.Count-1 do + for S := 1 to SongList.Count-1 do + if CompareText(TSong( SongList[S] ).Language, TSong( SongList[S-1] ).Language) < 0 then + begin + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; + end; + end; + + end; // case +end; + +function TSongs.FindSongFile(Dir, Mask: widestring): widestring; +var + SR: TSearchRec; // for parsing song directory +begin + Result := ''; + if FindFirst(Dir + Mask, faDirectory, SR) = 0 then begin + Result := SR.Name; + end; // if + FindClose(SR); +end; + +procedure TCatSongs.Refresh; +var + S: integer; // temporary song index + CatLen: integer; // length of CatSongs.Song + Letter: char; // current letter for sorting using letter + SS: string; // current edition for sorting using edition, genre etc. + Order: integer; // number used for ordernum + Letter2: char; // + CatNumber:integer; // Number of Song in Category +begin + CatNumShow := -1; +// Songs.Sort(0); // by title + +case Ini.Sorting of + sEdition: begin + Songs.Sort(sArtist); + Songs.Sort(sEdition); + end; + sGenre: begin + Songs.Sort(sArtist); + Songs.Sort(sGenre); + end; + sLanguage: begin + Songs.Sort(sArtist); + Songs.Sort(sLanguage); + end; + sFolder: begin + Songs.Sort(sArtist); + Songs.Sort(sFolder); + end; + sTitle: Songs.Sort(sTitle); + sArtist: Songs.Sort(sArtist); + sTitle2: Songs.Sort(sTitle2); // by title2 + sArtist2: Songs.Sort(sArtist2); // by artist2 + + end; // case + + + Letter := ' '; + SS := ''; + Order := 0; + CatNumber := 0; + + //Songs leeren + SetLength (Song, 0); + + for S := 0 to Songs.SongList.Count-1 do + begin + if (Ini.Tabs = 1) then + if (Ini.Sorting = sEdition) and (CompareText(SS, TSong( Songs.SongList[S] ).Edition) <> 0) then begin + // add Category Button + Inc(Order); + SS := TSong( Songs.SongList[S] ).Edition; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := '[' + SS + ']'; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; + CatSongs.Song[CatLen].OrderNum := Order; + + + + // 0.4.3 + // if SS = 'Singstar' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; + // if SS = 'Singstar Part 2' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; + // if SS = 'Singstar German' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; + // if SS = 'Singstar Spanish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; + // if SS = 'Singstar Italian' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; + // if SS = 'Singstar French' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; + // if SS = 'Singstar Party' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Party.jpg'; + // if SS = 'Singstar Popworld' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Popworld.jpg'; + // if SS = 'Singstar 80s' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg'; + // if SS = 'Singstar 80s Polish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg'; + // if SS = 'Singstar Rocks' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Rocks.jpg'; + // if SS = 'Singstar Anthems' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Anthems.jpg'; + + {// cover-patch + if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';//} + + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); + + //CatNumber Patch + if (SS <> '') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end + + else if (Ini.Sorting = sGenre) and (CompareText(SS, TSong( Songs.SongList[S] ).Genre) <> 0) then begin + // add Genre Button + Inc(Order); + SS := TSong( Songs.SongList[S] ).Genre; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := SS; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; + CatSongs.Song[CatLen].OrderNum := Order; + + {// cover-patch + if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); + + //CatNumber Patch + if (SS <> '') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end + + else if (Ini.Sorting = sLanguage) and (CompareText(SS, TSong( Songs.SongList[S] ).Language) <> 0) then begin + // add Language Button + Inc(Order); + SS := TSong( Songs.SongList[S] ).Language; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := SS; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; + CatSongs.Song[CatLen].OrderNum := Order; + + {// cover-patch + if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); + + //CatNumber Patch + if (SS <> '') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end + + else if (Ini.Sorting = sTitle) and + (Length(TSong( Songs.SongList[S] ).Title)>=1) and + (Letter <> UpperCase(TSong( Songs.SongList[S] ).Title)[1]) then begin + // add a letter Category Button + Inc(Order); + Letter := Uppercase(TSong( Songs.SongList[S] ).Title)[1]; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; +// Order := ord(Letter); + CatSongs.Song[CatLen].OrderNum := Order; + + + {// cover-patch + if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); + + //CatNumber Patch + if (Letter <> ' ') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end + + else if (Ini.Sorting = sArtist) and (Length(TSong( Songs.SongList[S] ).Artist)>=1) and + (Letter <> UpperCase(TSong( Songs.SongList[S] ).Artist)[1]) then begin + // add a letter Category Button + Inc(Order); + Letter := UpperCase(TSong( Songs.SongList[S] ).Artist)[1]; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; +// Order := ord(Letter); + CatSongs.Song[CatLen].OrderNum := Order; + + {// cover-patch + if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); + + //CatNumber Patch + if (Letter <> ' ') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end + + else if (Ini.Sorting = sFolder) and (CompareText(SS, TSong( Songs.SongList[S] ).Folder) <> 0) then begin + // 0.5.0: add folder tab + Inc(Order); + SS := TSong( Songs.SongList[S] ).Folder; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := SS; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; + CatSongs.Song[CatLen].OrderNum := Order; + + {// cover-patch + if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); + + //CatNumber Patch + if (SS <> '') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end + + else if (Ini.Sorting = sTitle2) AND (Length(TSong( Songs.SongList[S] ).Title)>=1) then begin + if (ord(TSong( Songs.SongList[S] ).Title[1]) > 47) and (ord(TSong( Songs.SongList[S] ).Title[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(TSong( Songs.SongList[S] ).Title)[1]; + if (Letter <> Letter2) then begin + // add a letter Category Button + Inc(Order); + Letter := Letter2; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; +// Order := ord(Letter); + CatSongs.Song[CatLen].OrderNum := Order; + + {// cover-patch + if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); + + //CatNumber Patch + if (Letter <> ' ') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end; + end + + else if (Ini.Sorting = sArtist2) AND (Length(TSong( Songs.SongList[S] ).Artist)>=1) then begin + if (ord(TSong( Songs.SongList[S] ).Artist[1]) > 47) and (ord(TSong( Songs.SongList[S] ).Artist[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(TSong( Songs.SongList[S] ).Artist)[1]; + if (Letter <> Letter2) then begin + // add a letter Category Button + Inc(Order); + Letter := Letter2; + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; + CatSongs.Song[CatLen].Main := true; + CatSongs.Song[CatLen].OrderTyp := 0; +// Order := ord(Letter); + CatSongs.Song[CatLen].OrderNum := Order; + + {// cover-patch + if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg' + else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} + CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); + + //CatNumber Patch + if (Letter <> ' ') then + begin + Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy + CatNumber := 0; + end; + + CatSongs.Song[CatLen].Visible := true; + end; + end; + + + CatLen := Length(CatSongs.Song); + SetLength(CatSongs.Song, CatLen+1); + + Inc (CatNumber); //Increase Number in Cat + + CatSongs.Song[CatLen] := TSong( Songs.SongList[S] ); + CatSongs.Song[CatLen].OrderNum := Order; // assigns category + CatSongs.Song[CatLen].CatNumber := CatNumber; + + if (Ini.Tabs = 0) then CatSongs.Song[CatLen].Visible := true + else if (Ini.Tabs = 1) then CatSongs.Song[CatLen].Visible := false; +// if (Ini.Tabs = 1) and (Order = 1) then CatSongs.Song[CatLen].Visible := true; // open first tab +//CatSongs.Song[CatLen].Visible := true; + + end; +//CatNumber Patch - Set CatNumber of Last Category +if (ini.Tabs_at_startup = 1) And (high(Song) >=1) then + Song[CatLen - CatNumber].CatNumber := CatNumber;//Set CatNumber of Categroy +//CatCount Patch +CatCount := Order; +end; + +procedure TCatSongs.ShowCategory(Index: integer); +var + S: integer; // song +begin + CatNumShow := Index; + for S := 0 to high(CatSongs.Song) do + begin + if (CatSongs.Song[S].OrderNum = Index) AND (Not CatSongs.Song[S].Main) then + CatSongs.Song[S].Visible := true + else + CatSongs.Song[S].Visible := false; + end; +end; + +procedure TCatSongs.HideCategory(Index: integer); // hides all songs in category +var + S: integer; // song +begin + for S := 0 to high(CatSongs.Song) do begin + if not CatSongs.Song[S].Main then + CatSongs.Song[S].Visible := false // hides all at now + end; +end; + +procedure TCatSongs.ClickCategoryButton(Index: integer); +var + Num, S: integer; +begin + Num := CatSongs.Song[Index].OrderNum; + if Num <> CatNumShow then + begin + ShowCategory(Num); + end + else begin + ShowCategoryList; + end; +end; + +//Hide Categorys when in Category Hack +procedure TCatSongs.ShowCategoryList; +var + Num, S: integer; +begin + //Hide All Songs Show All Cats + for S := 0 to high(CatSongs.Song) do begin + if CatSongs.Song[S].Main then + CatSongs.Song[S].Visible := true + else + CatSongs.Song[S].Visible := false + end; + CatSongs.Selected := CatNumShow; //Show last shown Category + CatNumShow := -1; +end; +//Hide Categorys when in Category Hack End + +//Wrong song selected when tabs on bug +function TCatSongs.FindNextVisible(SearchFrom:integer): integer;//Find next Visible Song +var + I: Integer; + begin + Result := -1; + I := SearchFrom + 1; + while not CatSongs.Song[I].Visible do + begin + Inc (I); + if (I>high(CatSongs.Song)) then + I := low(CatSongs.Song); + if (I = SearchFrom) then //Make One Round and no song found->quit + break; + end; + end; +//Wrong song selected when tabs on bug End + +function TCatSongs.VisibleSongs: integer; +var + S: integer; // song +begin + Result := 0; + for S := 0 to high(CatSongs.Song) do + if CatSongs.Song[S].Visible = true then Inc(Result); +end; + +function TCatSongs.VisibleIndex(Index: integer): integer; +var + S: integer; // song +begin + Result := 0; + for S := 0 to Index-1 do + if CatSongs.Song[S].Visible = true then Inc(Result); +end; + +function TCatSongs.SetFilter(FilterStr: String; const fType: Byte): Cardinal; +var + I, J: Integer; + cString: String; + SearchStr: Array of String; +begin + {fType: 0: All + 1: Title + 2: Artist} + FilterStr := Trim(FilterStr); + if FilterStr<>'' then begin + Result := 0; + //Create Search Array + SetLength(SearchStr, 1); + I := Pos (' ', FilterStr); + While (I <> 0) do + begin + SetLength (SearchStr, Length(SearchStr) + 1); + cString := Copy(FilterStr, 1, I-1); + if (cString <> ' ') AND (cString <> '') then + SearchStr[High(SearchStr)-1] := cString; + Delete (FilterStr, 1, I); + + I := Pos (' ', FilterStr); + end; + //Copy last Word + if (FilterStr <> ' ') AND (FilterStr <> '') then + SearchStr[High(SearchStr)] := FilterStr; + + for I:=0 to High(Song) do begin + if not Song[i].Main then + begin + case fType of + 0: cString := Song[I].Artist + ' ' + Song[i].Title + ' ' + Song[i].Folder; + 1: cString := Song[I].Title; + 2: cString := Song[I].Artist; + end; + Song[i].Visible:=True; + //Look for every Searched Word + For J := 0 to High(SearchStr) do + begin + Song[i].Visible := Song[i].Visible AND AnsiContainsText(cString, SearchStr[J]) + end; + if Song[i].Visible then + Inc(Result); + end + else + Song[i].Visible:=False; + end; + CatNumShow := -2; + end + else begin + for i:=0 to High(Song) do begin + Song[i].Visible:=(Ini.Tabs=1)=Song[i].Main; + CatNumShow := -1; + end; + Result := 0; + end; +end; + + + +// ----------------------------------------------------------------------------- + + + + +end. -- cgit v1.2.3