diff options
author | jaybinks <jaybinks@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2008-01-12 12:31:43 +0000 |
---|---|---|
committer | jaybinks <jaybinks@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2008-01-12 12:31:43 +0000 |
commit | e74bd57c12f470257111c1c0530fb38f0fd34414 (patch) | |
tree | ea55446e8faa73e164d53521c108d748095a9f80 /Game/Code/Classes | |
parent | 79c5b96f49412541efdd51bca62ce5912b864c08 (diff) | |
download | usdx-e74bd57c12f470257111c1c0530fb38f0fd34414.tar.gz usdx-e74bd57c12f470257111c1c0530fb38f0fd34414.tar.xz usdx-e74bd57c12f470257111c1c0530fb38f0fd34414.zip |
bunch of smaller changes...
some changes to song loading...
Record global changed to singleton object
started implementing mic volume display in Settings-Record
hope this dosnt break anything.. :P
git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@789 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to '')
-rw-r--r-- | Game/Code/Classes/UAudioInput_Bass.pas | 23 | ||||
-rw-r--r-- | Game/Code/Classes/UCommandLine.pas | 5 | ||||
-rw-r--r-- | Game/Code/Classes/UDataBase.pas | 1 | ||||
-rw-r--r-- | Game/Code/Classes/UDraw.pas | 28 | ||||
-rw-r--r-- | Game/Code/Classes/UFiles.pas | 360 | ||||
-rw-r--r-- | Game/Code/Classes/UIni.pas | 10 | ||||
-rw-r--r-- | Game/Code/Classes/ULog.pas | 6 | ||||
-rw-r--r-- | Game/Code/Classes/UMain.pas | 86 | ||||
-rw-r--r-- | Game/Code/Classes/UMusic.pas | 1 | ||||
-rw-r--r-- | Game/Code/Classes/UPlatform.pas | 74 | ||||
-rw-r--r-- | Game/Code/Classes/UPlatformLinux.pas | 2 | ||||
-rw-r--r-- | Game/Code/Classes/UPlatformMacOSX.pas | 20 | ||||
-rw-r--r-- | Game/Code/Classes/UPlatformWindows.pas | 59 | ||||
-rw-r--r-- | Game/Code/Classes/URecord.pas | 81 | ||||
-rw-r--r-- | Game/Code/Classes/USongs.pas | 259 |
15 files changed, 375 insertions, 640 deletions
diff --git a/Game/Code/Classes/UAudioInput_Bass.pas b/Game/Code/Classes/UAudioInput_Bass.pas index 9807ffc3..75a5aee5 100644 --- a/Game/Code/Classes/UAudioInput_Bass.pas +++ b/Game/Code/Classes/UAudioInput_Bass.pas @@ -79,7 +79,7 @@ begin //Check for Soundcard with same Description For I := 0 to SC-1 do begin - if (Recording.SoundCard[I].Description = Desc) then + if (AudioInputProcessor.SoundCard[I].Description = Desc) then begin Result := True; Break; @@ -88,7 +88,7 @@ begin end; begin - with Recording do + with AudioInputProcessor do begin // checks for recording devices and puts them into an array SetLength(SoundCard, 0); @@ -170,21 +170,22 @@ var PlayerLeft, PlayerRight: integer; CaptureSoundLeft, CaptureSoundRight: TSound; begin - for S := 0 to High(Recording.Sound) do - Recording.Sound[S].BufferLong[0].Clear; + for S := 0 to High(AudioInputProcessor.Sound) do + AudioInputProcessor.Sound[S].BufferLong[0].Clear; - for SC := 0 to High(Ini.CardList) do begin + for SC := 0 to High(Ini.CardList) do + begin PlayerLeft := Ini.CardList[SC].ChannelL-1; PlayerRight := Ini.CardList[SC].ChannelR-1; if PlayerLeft >= PlayersPlay then PlayerLeft := -1; if PlayerRight >= PlayersPlay then PlayerRight := -1; if (PlayerLeft > -1) or (PlayerRight > -1) then begin if (PlayerLeft > -1) then - CaptureSoundLeft := Recording.Sound[PlayerLeft] + CaptureSoundLeft := AudioInputProcessor.Sound[PlayerLeft] else CaptureSoundLeft := nil; if (PlayerRight > -1) then - CaptureSoundRight := Recording.Sound[PlayerRight] + CaptureSoundRight := AudioInputProcessor.Sound[PlayerRight] else CaptureSoundRight := nil; @@ -224,14 +225,14 @@ end; function MicrophoneCallback(stream: HSTREAM; buffer: Pointer; len: Cardinal; Card: Cardinal): boolean; stdcall; begin - Recording.HandleMicrophoneData(buffer, len, Recording.SoundCard[Card]); + AudioInputProcessor.HandleMicrophoneData(buffer, len, AudioInputProcessor.SoundCard[Card]); Result := true; end; {* * Start input-capturing on Soundcard specified by Card. * Params: - * Card - soundcard index in Recording.SoundCard array + * Card - soundcard index in AudioInputProcessor.SoundCard array * CaptureSoundLeft - sound(-buffer) used for left channel capture data * CaptureSoundRight - sound(-buffer) used for right channel capture data *} @@ -254,7 +255,7 @@ begin end else begin - bassSoundCard := TBassSoundCard(Recording.SoundCard[Card]); + bassSoundCard := TBassSoundCard(AudioInputProcessor.SoundCard[Card]); bassSoundCard.CaptureSoundLeft := CaptureSoundLeft; bassSoundCard.CaptureSoundRight := CaptureSoundRight; @@ -267,7 +268,7 @@ end; {* * Stop input-capturing on Soundcard specified by Card. * Params: - * Card - soundcard index in Recording.SoundCard array + * Card - soundcard index in AudioInputProcessor.SoundCard array *} procedure TAudioInput_Bass.StopCard(Card: byte); begin diff --git a/Game/Code/Classes/UCommandLine.pas b/Game/Code/Classes/UCommandLine.pas index 86f822a4..55dfc6ce 100644 --- a/Game/Code/Classes/UCommandLine.pas +++ b/Game/Code/Classes/UCommandLine.pas @@ -61,7 +61,8 @@ const implementation -uses SysUtils; +uses SysUtils, + uPlatform; // uINI -- Nasty requirement... ( removed with permission of blindy ) @@ -99,7 +100,7 @@ begin writeln( '' ); - halt; + platform.halt; end; //------------- diff --git a/Game/Code/Classes/UDataBase.pas b/Game/Code/Classes/UDataBase.pas index e99cb891..b5636d52 100644 --- a/Game/Code/Classes/UDataBase.pas +++ b/Game/Code/Classes/UDataBase.pas @@ -9,6 +9,7 @@ interface {$I switches.inc} uses USongs, + USong, SQLiteTable3; //-------------------- diff --git a/Game/Code/Classes/UDraw.pas b/Game/Code/Classes/UDraw.pas index c399057b..662050dc 100644 --- a/Game/Code/Classes/UDraw.pas +++ b/Game/Code/Classes/UDraw.pas @@ -161,7 +161,7 @@ end; procedure SingDrawOscilloscope(X, Y, W, H: real; NrSound: integer); var - Pet: integer; + Pet : integer; begin; // Log.LogStatus('Oscilloscope', 'SingDraw'); glColor3f(Skin_OscR, Skin_OscG, Skin_OscB); @@ -169,14 +169,19 @@ begin; glColor3f(1, 1, 1); } glBegin(GL_LINE_STRIP); - glVertex2f(X, -Recording.Sound[NrSound].BufferArray[1] / $10000 * H + Y + H/2); - for Pet := 2 to Recording.Sound[NrSound].n div 1 do begin - glVertex2f(X + (Pet-1) * W / (Recording.Sound[NrSound].n - 1), - -Recording.Sound[NrSound].BufferArray[Pet] / $10000 * H + Y + H/2); + + glVertex2f(X, -AudioInputProcessor.Sound[NrSound].BufferArray[1] / $10000 * H + Y + H/2); + + for Pet := 2 to AudioInputProcessor.Sound[NrSound].n div 1 do + begin + glVertex2f( X + (Pet-1) * W / (AudioInputProcessor.Sound[NrSound].n - 1), + -AudioInputProcessor.Sound[NrSound].BufferArray[Pet] / $10000 * H + Y + H/2 ); end; glEnd; end; + + procedure SingDrawNoteLines(Left, Top, Right: real; Space: integer); var Pet: integer; @@ -366,7 +371,7 @@ var glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if Player[NrGracza].IlNut > 0 then +//// if Player[NrGracza].IlNut > 0 then begin TempR := W / (Czesci[0].Czesc[Czesci[0].Akt].Koniec - Czesci[0].Czesc[Czesci[0].Akt].StartNote); for N := 0 to Player[NrGracza].HighNut do @@ -480,14 +485,7 @@ begin lTmpA := (Right-Left); lTmpB := (Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].Koniec - Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote); - - {$IFDEF LAZARUS} -{* - writeln( 'UDRAW (Right-Left) : ' + floattostr( lTmpA ) ); - writeln( 'UDRAW : ' + floattostr( lTmpB ) ); - writeln( '' ); -*} - {$ENDIF} + if ( lTmpA > 0 ) AND ( lTmpB > 0 ) THEN @@ -555,7 +553,7 @@ begin end; // if not FreeStyle end; // with end; // for - end; // with + end; // with 1 glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); diff --git a/Game/Code/Classes/UFiles.pas b/Game/Code/Classes/UFiles.pas index 69beefe9..d3e4729b 100644 --- a/Game/Code/Classes/UFiles.pas +++ b/Game/Code/Classes/UFiles.pas @@ -10,45 +10,33 @@ interface uses SysUtils, ULog, UMusic, - USongs; + USongs, + USong; //procedure InitializePaths; //Function sets All Absolute Paths eg. for Songs -function ReadTXTHeader(var Song: TSong): boolean; //Reads Standard TXT Header -function AnalyseFile(var Song: TSong): boolean; //Analyse Song File and Read Header -procedure ClearSong(var Song: TSong); //Clears Song Header values +//function ReadTXTHeader(var Song: TSong): boolean; //Reads Standard TXT Header +//function AnalyseFile(var Song: TSong): boolean; //Analyse Song File and Read Header +//procedure ClearSong(var Song: TSong); //Clears Song Header values //Methodes Loading and Saving Songfiles procedure ResetSingTemp; -procedure ParseNote(NrCzesci: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); -procedure NewSentence(NrCzesciP: integer; Param1, Param2: integer); -function LoadSong(Name: string): boolean; +//procedure ParseNote(NrCzesci: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); +//procedure NewSentence(NrCzesciP: integer; Param1, Param2: integer); + +//function LoadSong(Name: string): boolean; function SaveSong(Song: TSong; Czesc: TCzesci; Name: string; Relative: boolean): boolean; var -{* - //Absolute Paths - GamePath: string; - SoundPath: string; - SongPath: string; - LogPath: string; - ThemePath: string; - ScreenshotsPath: string; - CoversPath: string; - LanguagesPath: string; - PluginPath: string; - PlayListPath: string; -*} - SongFile: TextFile; // all procedures in this unit operates on this file FileLineNo: integer; //Line which is readed at Last, for error reporting // variables available for all procedures - Base: array[0..1] of integer; - Rel: array[0..1] of integer; - Mult: integer = 1; - MultBPM: integer = 4; + Base : array[0..1] of integer; + Rel : array[0..1] of integer; + Mult : integer = 1; + MultBPM : integer = 4; implementation @@ -57,7 +45,10 @@ uses TextGL, UPlatform, UMain; +(* //-------------------- +<<<<<<< .mine +======= // Clears Song Header values //-------------------- procedure ClearSong(var Song: TSong); @@ -367,7 +358,7 @@ Result := False; Log.LogError('An Error occured reading Line ' + inttostr(FileLineNo) + ' from SongHeader: ' + Song.FileName); end;} end; - + *) //-------------------- // Resets the temporary Sentence Arrays for each Player and some other Variables //-------------------- @@ -376,7 +367,6 @@ var Pet: integer; begin SetLength(Czesci, Length(Player)); - SetLength(AktSong.BPM, 0); for Pet := 0 to High(Player) do begin SetLength(Czesci[Pet].Czesc, 1); SetLength(Czesci[Pet].Czesc[0].Nuta, 0); @@ -386,316 +376,18 @@ begin Player[pet].IlNut := 0; Player[pet].HighNut := -1; end; - //Reset Path and Filename Values to Prevent Errors in Editor - AktSong.Path := ''; - AktSong.FileName := ''; -end; - -//-------------------- -// Parses Note Infos and save them to Array -//-------------------- -procedure ParseNote(NrCzesci: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string); -var - Space: boolean; -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 Czesci[NrCzesci].Czesc[Czesci[NrCzesci].High] do begin - SetLength(Nuta, Length(Nuta) + 1); - IlNut := IlNut + 1; - HighNut := HighNut + 1; - Muzyka.IlNut := Muzyka.IlNut + 1; - - Nuta[HighNut].Start := StartP; - if IlNut = 1 then begin - StartNote := Nuta[HighNut].Start; - if Czesci[NrCzesci].Ilosc = 1 then - Start := -100; -// Start := Nuta[HighNut].Start; - end; - - Nuta[HighNut].Dlugosc := DurationP; - Muzyka.DlugoscNut := Muzyka.DlugoscNut + Nuta[HighNut].Dlugosc; - - // back to the normal system with normal, golden and now freestyle notes - case TypeP of - 'F': Nuta[HighNut].Wartosc := 0; - ':': Nuta[HighNut].Wartosc := 1; - '*': Nuta[HighNut].Wartosc := 2; - end; - - Czesci[NrCzesci].Wartosc := Czesci[NrCzesci].Wartosc + Nuta[HighNut].Dlugosc * Nuta[HighNut].Wartosc; - Nuta[HighNut].Ton := NoteP; - if Nuta[HighNut].Ton < Base[NrCzesci] then Base[NrCzesci] := Nuta[HighNut].Ton; - Nuta[HighNut].TonGamy := Nuta[HighNut].TonGamy mod 12; - - Nuta[HighNut].Tekst := Copy(LyricS, 2, 100); - Lyric := Lyric + Nuta[HighNut].Tekst; - - if TypeP = 'F' then - Nuta[HighNut].FreeStyle := true; - - Koniec := Nuta[HighNut].Start + Nuta[HighNut].Dlugosc; - end; // with -end; - -//-------------------- -// Called when a new Sentence is found in the TXT File -//-------------------- -procedure NewSentence(NrCzesciP: integer; Param1, Param2: integer); -var -I: Integer; -begin - - // stara czesc //Alter Satz //Update Old Part - Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].BaseNote := Base[NrCzesciP]; - Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].LyricWidth := glTextWidth(PChar(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Lyric)); - - //Total Notes Patch - Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes := 0; - for I := low(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta) to high(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta) do + //Reset Path and Filename Values to Prevent Errors in Editor + if assigned( CurrentSong ) then begin - Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes := Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes + Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta[I].Dlugosc * Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta[I].Wartosc; + SetLength(CurrentSong.BPM, 0); + CurrentSong.Path := ''; + CurrentSong.FileName := ''; end; - //Total Notes Patch End - - - // nowa czesc //Neuer Satz //Update New Part - SetLength(Czesci[NrCzesciP].Czesc, Czesci[NrCzesciP].Ilosc + 1); - Czesci[NrCzesciP].High := Czesci[NrCzesciP].High + 1; - Czesci[NrCzesciP].Ilosc := Czesci[NrCzesciP].Ilosc + 1; - Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].HighNut := -1; - - if not AktSong.Relative then - Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Start := Param1; - - if AktSong.Relative then begin - Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Start := Param1; - Rel[NrCzesciP] := Rel[NrCzesciP] + Param2; - end; - - Base[NrCzesciP] := 100; // high number + +// CurrentSong := nil; end; -//-------------------- -// Load a Song -//-------------------- -function LoadSong(Name: string): boolean; -var - TempC: char; - Tekst: string; - CP: integer; // Current Player (0 or 1) - Pet: integer; - Both: boolean; - Param1: integer; - Param2: integer; - Param3: integer; - ParamS: string; - I: Integer; -begin - Result := false; - - if not FileExists(Name) then begin - Log.LogError('File not found: "' + Name + '"', 'WczytajCzesci'); - exit; - end; - - try - MultBPM := 4; // 4 - mnoznik dla czasu nut - Mult := 1; // 4 - dokladnosc pomiaru nut - Base[0] := 100; // high number -// Base[1] := 100; // high number - Czesci[0].Wartosc := 0; -// Czesci[1].Wartosc := 0; // here was the error in 0.3.2 - AktSong.Relative := false; - - Rel[0] := 0; -// Rel[1] := 0; - CP := 0; - Both := false; - if Length(Player) = 2 then Both := true; - - FileMode := fmOpenRead; - AssignFile(SongFile, Name); - Reset(SongFile); - - //Clear old Song Header - ClearSong(AktSong); - - if (AktSong.Path = '') then - AktSong.Path := ExtractFilePath(Name); - - if (AktSong.FileName = '') then - AktSong.Filename := ExtractFileName(Name); - //Read Header - Result := ReadTxTHeader(AktSong); - if not Result then - begin - CloseFile(SongFile); - Log.LogError('Error Loading SongHeader, abort Song Loading'); - Exit; - end; - - Result := False; - - Reset(SongFile); - FileLineNo := 0; - //Search for Note Begining - repeat - ReadLn(SongFile, Tekst); - Inc(FileLineNo); - - if (EoF(SongFile)) then - begin //Song File Corrupted - No Notes - CloseFile(SongFile); - Log.LogError('Could not load txt File, no Notes found: ' + Name); - Result := False; - Exit; - end; - Read(SongFile, TempC); - until ((TempC = ':') or (TempC = 'F') or (TempC = '*')); - - SetLength(Czesci, 2); - for Pet := 0 to High(Czesci) do begin - SetLength(Czesci[Pet].Czesc, 1); - Czesci[Pet].High := 0; - Czesci[Pet].Ilosc := 1; - Czesci[Pet].Akt := 0; - Czesci[Pet].Resolution := AktSong.Resolution; - Czesci[Pet].NotesGAP := AktSong.NotesGAP; - Czesci[Pet].Czesc[0].IlNut := 0; - Czesci[Pet].Czesc[0].HighNut := -1; - end; - -// TempC := ':'; -// TempC := Tekst[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 - // wczytuje nute - Read(SongFile, Param1); - Read(SongFile, Param2); - Read(SongFile, Param3); - Read(SongFile, ParamS); - - // dodaje nute - 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; // if - if TempC = '-' then begin - // reads sentence - Read(SongFile, Param1); - if AktSong.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(AktSong.BPM, Length(AktSong.BPM) + 1); - Read(SongFile, AktSong.BPM[High(AktSong.BPM)].StartBeat); - AktSong.BPM[High(AktSong.BPM)].StartBeat := AktSong.BPM[High(AktSong.BPM)].StartBeat + Rel[0]; - - Read(SongFile, Tekst); - AktSong.BPM[High(AktSong.BPM)].BPM := StrToFloat(Tekst); - AktSong.BPM[High(AktSong.BPM)].BPM := AktSong.BPM[High(AktSong.BPM)].BPM * Mult * MultBPM; - end; - - - if not Both then begin - Czesci[CP].Czesc[Czesci[CP].High].BaseNote := Base[CP]; - Czesci[CP].Czesc[Czesci[CP].High].LyricWidth := glTextWidth(PChar(Czesci[CP].Czesc[Czesci[CP].High].Lyric)); - //Total Notes Patch - Czesci[CP].Czesc[Czesci[CP].High].TotalNotes := 0; - for I := low(Czesci[CP].Czesc[Czesci[CP].High].Nuta) to high(Czesci[CP].Czesc[Czesci[CP].High].Nuta) do - begin - Czesci[CP].Czesc[Czesci[CP].High].TotalNotes := Czesci[CP].Czesc[Czesci[CP].High].TotalNotes + Czesci[CP].Czesc[Czesci[CP].High].Nuta[I].Dlugosc * Czesci[CP].Czesc[Czesci[CP].High].Nuta[I].Wartosc; - end; - //Total Notes Patch End - end else begin - for Pet := 0 to High(Czesci) do begin - Czesci[Pet].Czesc[Czesci[Pet].High].BaseNote := Base[Pet]; - Czesci[Pet].Czesc[Czesci[Pet].High].LyricWidth := glTextWidth(PChar(Czesci[Pet].Czesc[Czesci[Pet].High].Lyric)); - //Total Notes Patch - Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes := 0; - for I := low(Czesci[Pet].Czesc[Czesci[Pet].High].Nuta) to high(Czesci[Pet].Czesc[Czesci[Pet].High].Nuta) do - begin - Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes := Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes + Czesci[Pet].Czesc[Czesci[Pet].High].Nuta[I].Dlugosc * Czesci[Pet].Czesc[Czesci[Pet].High].Nuta[I].Wartosc; - end; - //Total Notes Patch End - end; - end; - - Read(SongFile, TempC); - Inc(FileLineNo); - end; // while} - - CloseFile(SongFile); - except - try - CloseFile(SongFile); - except - - end; - - Log.LogError('Error Loading File: "' + Name + '" in Line ' + inttostr(FileLineNo)); - exit; - end; - - Result := true; -end; //-------------------- // Saves a Song @@ -738,8 +430,8 @@ begin WriteLn(SongFile, '#GAP:' + FloatToStr(Song.GAP)); RelativeSubTime := 0; - for B := 1 to High(AktSong.BPM) do - WriteLn(SongFile, 'B ' + FloatToStr(AktSong.BPM[B].StartBeat) + ' ' + FloatToStr(AktSong.BPM[B].BPM/4)); + for B := 1 to High(CurrentSong.BPM) do + WriteLn(SongFile, 'B ' + FloatToStr(CurrentSong.BPM[B].StartBeat) + ' ' + FloatToStr(CurrentSong.BPM[B].BPM/4)); for C := 0 to Czesc.High do begin for N := 0 to Czesc.Czesc[C].HighNut do begin diff --git a/Game/Code/Classes/UIni.pas b/Game/Code/Classes/UIni.pas index e4f5e823..599bb8fa 100644 --- a/Game/Code/Classes/UIni.pas +++ b/Game/Code/Classes/UIni.pas @@ -463,9 +463,9 @@ begin //{ B := False; //Look for Soundcard - for I2 := 0 to High(Recording.SoundCard) do + for I2 := 0 to High(AudioInputProcessor.SoundCard) do begin - if (S = Trim(Recording.SoundCard[I2].Description)) then + if (S = Trim(AudioInputProcessor.SoundCard[I2].Description)) then begin B := True; Break; @@ -485,12 +485,12 @@ begin end; // Record - append detected soundcards - for I := 0 to High(Recording.SoundCard) do + for I := 0 to High(AudioInputProcessor.SoundCard) do begin B := False; For I2 := 0 to High(CardList) do begin //Search for Card in List - if (CardList[I2].Name = Trim(Recording.SoundCard[I].Description)) then + if (CardList[I2].Name = Trim(AudioInputProcessor.SoundCard[I].Description)) then begin B := True; Break; @@ -502,7 +502,7 @@ begin begin I3 := Length(CardList); SetLength(CardList, I3+1); - CardList[I3].Name := Trim(Recording.SoundCard[I].Description); + CardList[I3].Name := Trim(AudioInputProcessor.SoundCard[I].Description); CardList[I3].Input := 0; CardList[I3].ChannelL := 0; CardList[I3].ChannelR := 0; diff --git a/Game/Code/Classes/ULog.pas b/Game/Code/Classes/ULog.pas index fc567d54..49b02c00 100644 --- a/Game/Code/Classes/ULog.pas +++ b/Game/Code/Classes/ULog.pas @@ -212,9 +212,9 @@ begin FS := TFileStream.Create(FileName, fmCreate); - for BL := 0 to High(Recording.Sound[SoundNr].BufferLong) do begin - Recording.Sound[SoundNr].BufferLong[BL].Seek(0, soBeginning); - FS.CopyFrom(Recording.Sound[SoundNr].BufferLong[BL], Recording.Sound[SoundNr].BufferLong[BL].Size); + for BL := 0 to High(AudioInputProcessor.Sound[SoundNr].BufferLong) do begin + AudioInputProcessor.Sound[SoundNr].BufferLong[BL].Seek(0, soBeginning); + FS.CopyFrom(AudioInputProcessor.Sound[SoundNr].BufferLong[BL], AudioInputProcessor.Sound[SoundNr].BufferLong[BL].Size); end; FS.Free; diff --git a/Game/Code/Classes/UMain.pas b/Game/Code/Classes/UMain.pas index e2e0eaa0..901d7370 100644 --- a/Game/Code/Classes/UMain.pas +++ b/Game/Code/Classes/UMain.pas @@ -20,6 +20,7 @@ uses ULog, ULyrics, UScreenSing, + USong, OpenGL12, {$IFDEF UseSerialPort} zlportio {you can disable it and all PortWriteB calls}, @@ -107,6 +108,8 @@ var Player: array of TPlayer; PlayersPlay: integer; + CurrentSong : TSong; + procedure InitializePaths; Procedure Main; @@ -130,7 +133,7 @@ uses USongs, math, UCommandLine, ULanguage, SDL_ttf, USkins, UCovers, UCatCovers, UDataBase, UPlaylist, UDLLManager, - UParty, UCore, UGraphicClasses, UPluginDefs, UPlatform; + UParty, UCore, UGraphicClasses, UPluginDefs, UPlatform; const Version = 'UltraStar Deluxe V 1.10 Alpha Build'; @@ -192,12 +195,14 @@ begin Log.BenchmarkEnd(1); Log.LogBenchmark('Loading Skin List', 1); +(* // Sound Card List Log.BenchmarkStart(1); Log.LogStatus('Loading Soundcard list', 'Initialization'); Recording := TRecord.Create; Log.BenchmarkEnd(1); Log.LogBenchmark('Loading Soundcard list', 1); +*) // Sound (+ fills Sound Card List) Log.BenchmarkStart(1); @@ -508,23 +513,23 @@ procedure GetMidBeatSub(BPMNum: integer; var Time: real; var CurBeat: real); var NewTime: real; begin - if High(AktSong.BPM) = BPMNum then begin + if High(CurrentSong.BPM) = BPMNum then begin // last BPM - CurBeat := AktSong.BPM[BPMNum].StartBeat + GetBeats(AktSong.BPM[BPMNum].BPM, Time); + CurBeat := CurrentSong.BPM[BPMNum].StartBeat + GetBeats(CurrentSong.BPM[BPMNum].BPM, Time); Time := 0; end else begin // not last BPM // count how much time is it for start of the new BPM and store it in NewTime - NewTime := GetTimeForBeats(AktSong.BPM[BPMNum].BPM, AktSong.BPM[BPMNum+1].StartBeat - AktSong.BPM[BPMNum].StartBeat); + NewTime := GetTimeForBeats(CurrentSong.BPM[BPMNum].BPM, CurrentSong.BPM[BPMNum+1].StartBeat - CurrentSong.BPM[BPMNum].StartBeat); // compare it to remaining time if (Time - NewTime) > 0 then begin // there is still remaining time - CurBeat := AktSong.BPM[BPMNum].StartBeat; + CurBeat := CurrentSong.BPM[BPMNum].StartBeat; Time := Time - NewTime; end else begin // there is no remaining time - CurBeat := AktSong.BPM[BPMNum].StartBeat + GetBeats(AktSong.BPM[BPMNum].BPM, Time); + CurBeat := CurrentSong.BPM[BPMNum].StartBeat + GetBeats(CurrentSong.BPM[BPMNum].BPM, Time); Time := 0; end; // if end; // if @@ -539,18 +544,18 @@ var // TempTime: real; begin Result := 0; - if Length(AktSong.BPM) = 1 then Result := Time * AktSong.BPM[0].BPM / 60; + if Length(CurrentSong.BPM) = 1 then Result := Time * CurrentSong.BPM[0].BPM / 60; (* 2 BPMs *) -{ if Length(AktSong.BPM) > 1 then begin +{ if Length(CurrentSong.BPM) > 1 then begin (* new system *) CurBeat := 0; - TopBeat := GetBeats(AktSong.BPM[0].BPM, Time); - if TopBeat > AktSong.BPM[1].StartBeat then begin + TopBeat := GetBeats(CurrentSong.BPM[0].BPM, Time); + if TopBeat > CurrentSong.BPM[1].StartBeat then begin // analyze second BPM - Time := Time - GetTimeForBeats(AktSong.BPM[0].BPM, AktSong.BPM[1].StartBeat - CurBeat); - CurBeat := AktSong.BPM[1].StartBeat; - TopBeat := GetBeats(AktSong.BPM[1].BPM, Time); + Time := Time - GetTimeForBeats(CurrentSong.BPM[0].BPM, CurrentSong.BPM[1].StartBeat - CurBeat); + CurBeat := CurrentSong.BPM[1].StartBeat; + TopBeat := GetBeats(CurrentSong.BPM[1].BPM, Time); Result := CurBeat + TopBeat; end else begin @@ -560,7 +565,7 @@ begin end; // if} (* more BPMs *) - if Length(AktSong.BPM) > 1 then begin + if Length(CurrentSong.BPM) > 1 then begin CurBeat := 0; CurBPM := 0; @@ -578,21 +583,21 @@ var CurBPM: integer; begin Result := 0; - if Length(AktSong.BPM) = 1 then Result := AktSong.GAP / 1000 + Beat * 60 / AktSong.BPM[0].BPM; + if Length(CurrentSong.BPM) = 1 then Result := CurrentSong.GAP / 1000 + Beat * 60 / CurrentSong.BPM[0].BPM; (* more BPMs *) - if Length(AktSong.BPM) > 1 then begin - Result := AktSong.GAP / 1000; + if Length(CurrentSong.BPM) > 1 then begin + Result := CurrentSong.GAP / 1000; CurBPM := 0; - while (CurBPM <= High(AktSong.BPM)) and (Beat > AktSong.BPM[CurBPM].StartBeat) do begin - if (CurBPM < High(AktSong.BPM)) and (Beat >= AktSong.BPM[CurBPM+1].StartBeat) then begin + while (CurBPM <= High(CurrentSong.BPM)) and (Beat > CurrentSong.BPM[CurBPM].StartBeat) do begin + if (CurBPM < High(CurrentSong.BPM)) and (Beat >= CurrentSong.BPM[CurBPM+1].StartBeat) then begin // full range - Result := Result + (60 / AktSong.BPM[CurBPM].BPM) * (AktSong.BPM[CurBPM+1].StartBeat - AktSong.BPM[CurBPM].StartBeat); + Result := Result + (60 / CurrentSong.BPM[CurBPM].BPM) * (CurrentSong.BPM[CurBPM+1].StartBeat - CurrentSong.BPM[CurBPM].StartBeat); end; - if (CurBPM = High(AktSong.BPM)) or (Beat < AktSong.BPM[CurBPM+1].StartBeat) then begin + if (CurBPM = High(CurrentSong.BPM)) or (Beat < CurrentSong.BPM[CurBPM+1].StartBeat) then begin // in the middle - Result := Result + (60 / AktSong.BPM[CurBPM].BPM) * (Beat - AktSong.BPM[CurBPM].StartBeat); + Result := Result + (60 / CurrentSong.BPM[CurBPM].BPM) * (Beat - CurrentSong.BPM[CurBPM].StartBeat); end; Inc(CurBPM); end; @@ -615,7 +620,7 @@ begin Czas.Teraz := Czas.Teraz + TimeSkip; Czas.OldBeat := Czas.AktBeat; - Czas.MidBeat := GetMidBeat(Czas.Teraz - (AktSong.Gap{ + 90 I've forgotten for what it is}) / 1000); // new system with variable BPM in function + Czas.MidBeat := GetMidBeat(Czas.Teraz - (CurrentSong.Gap{ + 90 I've forgotten for what it is}) / 1000); // new system with variable BPM in function Czas.AktBeat := Floor(Czas.MidBeat); // Czas.OldHalf := Czas.AktHalf; @@ -623,11 +628,11 @@ begin // Czas.AktHalf := Floor(Czas.MidHalf); Czas.OldBeatC := Czas.AktBeatC; - Czas.MidBeatC := GetMidBeat(Czas.Teraz - (AktSong.Gap) / 1000); + Czas.MidBeatC := GetMidBeat(Czas.Teraz - (CurrentSong.Gap) / 1000); Czas.AktBeatC := Floor(Czas.MidBeatC); Czas.OldBeatD := Czas.AktBeatD; - Czas.MidBeatD := -0.5+GetMidBeat(Czas.Teraz - (AktSong.Gap + 120 + 20) / 1000); // MidBeat with addition GAP + Czas.MidBeatD := -0.5+GetMidBeat(Czas.Teraz - (CurrentSong.Gap + 120 + 20) / 1000); // MidBeat with addition GAP Czas.AktBeatD := Floor(Czas.MidBeatD); Czas.FracBeatD := Frac(Czas.MidBeatD); @@ -822,7 +827,7 @@ begin // beep; // On linux we get an AV @ NEWNOTE, line 600 of Classes/UMain.pas - if not assigned( Recording.Sound ) then // TODO : JB_Linux ... why is this now not assigned... it was fine a few hours ago.. + if not assigned( AudioInputProcessor.Sound ) then // TODO : JB_Linux ... why is this now not assigned... it was fine a few hours ago.. exit; // analizuje dla obu graczy ten sam sygnal (Sound.OneSrcForBoth) @@ -831,7 +836,7 @@ begin begin // analyze buffer - Recording.Sound[CP].AnalizujBufor; + AudioInputProcessor.Sound[CP].AnalyzeBuffer; // adds some noise // Czas.Ton := Czas.Ton + Round(Random(3)) - 1; @@ -866,7 +871,7 @@ begin // Czas.Ton := 27; // gdy moze, to dodaje nute - if (Recording.Sound[CP].SzczytJest) and (Mozna) then begin + if (AudioInputProcessor.Sound[CP].SzczytJest) and (Mozna) then begin // operowanie na ostatniej nucie for Pet := 0 to Czesci[0].Czesc[S].HighNut do if (Czesci[0].Czesc[S].Nuta[Pet].Start <= Czas.OldBeatD+1) @@ -875,10 +880,11 @@ begin // to robi, tylko dla pary nut (oryginalnej i gracza) // przesuwanie tonu w odpowiednia game - while (Recording.Sound[CP].Ton - Czesci[0].Czesc[S].Nuta[Pet].Ton > 6) do - Recording.Sound[CP].Ton := Recording.Sound[CP].Ton - 12; - while (Recording.Sound[CP].Ton - Czesci[0].Czesc[S].Nuta[Pet].Ton < -6) do - Recording.Sound[CP].Ton := Recording.Sound[CP].Ton + 12; + while (AudioInputProcessor.Sound[CP].Ton - Czesci[0].Czesc[S].Nuta[Pet].Ton > 6) do + AudioInputProcessor.Sound[CP].Ton := AudioInputProcessor.Sound[CP].Ton - 12; + + while (AudioInputProcessor.Sound[CP].Ton - Czesci[0].Czesc[S].Nuta[Pet].Ton < -6) do + AudioInputProcessor.Sound[CP].Ton := AudioInputProcessor.Sound[CP].Ton + 12; // Half size Notes Patch NoteHit := false; @@ -887,8 +893,9 @@ begin //if Ini.Difficulty = 1 then Range := 1; //if Ini.Difficulty = 2 then Range := 0; Range := 2 - Ini.Difficulty; - if abs(Czesci[0].Czesc[S].Nuta[Pet].Ton - Recording.Sound[CP].Ton) <= Range then begin - Recording.Sound[CP].Ton := Czesci[0].Czesc[S].Nuta[Pet].Ton; + + if abs(Czesci[0].Czesc[S].Nuta[Pet].Ton - AudioInputProcessor.Sound[CP].Ton) <= Range then begin + AudioInputProcessor.Sound[CP].Ton := Czesci[0].Czesc[S].Nuta[Pet].Ton; // Half size Notes Patch @@ -929,7 +936,7 @@ begin Nowa := true; // jezeli ostatnia ma ten sam ton if (Player[CP].IlNut > 0 ) - and (Player[CP].Nuta[Player[CP].HighNut].Ton = Recording.Sound[CP].Ton) + and (Player[CP].Nuta[Player[CP].HighNut].Ton = AudioInputProcessor.Sound[CP].Ton) and (Player[CP].Nuta[Player[CP].HighNut].Start + Player[CP].Nuta[Player[CP].HighNut].Dlugosc = Czas.AktBeatD) then Nowa := false; // jezeli jest jakas nowa nuta na sprawdzanym beacie @@ -943,10 +950,10 @@ begin Player[CP].IlNut := Player[CP].IlNut + 1; Player[CP].HighNut := Player[CP].HighNut + 1; SetLength(Player[CP].Nuta, Player[CP].IlNut); - Player[CP].Nuta[Player[CP].HighNut].Start := Czas.AktBeatD; + Player[CP].Nuta[Player[CP].HighNut].Start := Czas.AktBeatD; Player[CP].Nuta[Player[CP].HighNut].Dlugosc := 1; - Player[CP].Nuta[Player[CP].HighNut].Ton := Recording.Sound[CP].Ton; // Ton || TonDokl - Player[CP].Nuta[Player[CP].HighNut].Detekt := Czas.MidBeat; + Player[CP].Nuta[Player[CP].HighNut].Ton := AudioInputProcessor.Sound[CP].Ton; // Ton || TonDokl + Player[CP].Nuta[Player[CP].HighNut].Detekt := Czas.MidBeat; // Half Note Patch @@ -977,7 +984,8 @@ begin //On Sentence End -> For LineBonus + SingBar if (sDet >= low(Czesci[0].Czesc)) AND (sDet <= high(Czesci[0].Czesc)) then -if ((Czesci[0].Czesc[SDet].Nuta[Czesci[0].Czesc[SDet].HighNut].Start + Czesci[0].Czesc[SDet].Nuta[Czesci[0].Czesc[SDet].HighNut].Dlugosc - 1) = Czas.AktBeatD) then +if assigned( Sender ) AND + ((Czesci[0].Czesc[SDet].Nuta[Czesci[0].Czesc[SDet].HighNut].Start + Czesci[0].Czesc[SDet].Nuta[Czesci[0].Czesc[SDet].HighNut].Dlugosc - 1) = Czas.AktBeatD) then Sender.onSentenceEnd(sDet); end; diff --git a/Game/Code/Classes/UMusic.pas b/Game/Code/Classes/UMusic.pas index bf366130..a7f1918f 100644 --- a/Game/Code/Classes/UMusic.pas +++ b/Game/Code/Classes/UMusic.pas @@ -413,6 +413,7 @@ end; initialization begin singleton_AudioManager := TInterfaceList.Create(); + end; finalization diff --git a/Game/Code/Classes/UPlatform.pas b/Game/Code/Classes/UPlatform.pas index 19a960e7..bfb03d54 100644 --- a/Game/Code/Classes/UPlatform.pas +++ b/Game/Code/Classes/UPlatform.pas @@ -16,7 +16,6 @@ interface uses Classes; type - TDirectoryEntry = Record Name : WideString; IsDirectory : Boolean; @@ -27,33 +26,16 @@ type IPlatform = Interface ['{63A5EBC3-3F4D-4F23-8DFB-B5165FCA23DF}'] - Function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray; - function TerminateIfAlreadyRunning(var WndTitle : String) : Boolean; - - function GetLogPath : WideString; - function GetGameSharedPath : WideString; - function GetGameUserPath : WideString; - end; - - TPlatform = class( TInterfacedOBject, IPlatform ) - - // DirectoryFindFiles returns all files matching the filter. Do not use '*' in the filter. - // If you set ReturnAllSubDirs = true all directories will be returned, if yout set it to false - // directories are completely ignored. - function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray; virtual; abstract; - - function TerminateIfAlreadyRunning(var WndTitle : String) : Boolean; virtual; - -// function GetGamePath : WideString; virtual; - function GetLogPath : WideString; virtual; - function GetGameSharedPath : WideString; virtual; - function GetGameUserPath : WideString; virtual; - + Function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray; + function TerminateIfAlreadyRunning(var WndTitle : String) : Boolean; + function FindSongFile(Dir, Mask: widestring): widestring; + procedure halt; + function GetLogPath : WideString; + function GetGameSharedPath : WideString; + function GetGameUserPath : WideString; end; - -var - Platform : IPlatform; + function Platform : IPlatform; implementation @@ -69,48 +51,30 @@ uses UPlatformMacOSX; {$ENDIF} -{ TPlatform } -(* -function TPlatform.GetGamePath: WideString; -begin - // Windows and Linux use this: - Result := ExtractFilePath(ParamStr(0)); -end; -*) -function TPlatform.GetLogPath : WideString; -begin - result := ExtractFilePath(ParamStr(0)); -end; - -function TPlatform.GetGameSharedPath : WideString; -begin - result := ExtractFilePath(ParamStr(0)); -end; +// I have modified it to use the Platform_singleton in this location ( in the implementaiton ) +// so that this variable can NOT be overwritten from anywhere else in the application. +// the accessor function platform, emulates all previous calls to work the same way. +var + Platform_singleton : IPlatform; -function TPlatform.GetGameUserPath : WideString; +function Platform : IPlatform; begin - result := ExtractFilePath(ParamStr(0)); + result := Platform_singleton;
end; -function TPlatform.TerminateIfAlreadyRunning(var WndTitle : String) : Boolean; -begin - // Linux and Mac don't check for running apps at the moment - Result := false; -end; initialization - {$IFDEF MSWINDOWS} - Platform := TPlatformWindows.Create; + Platform_singleton := TPlatformWindows.Create; {$ENDIF} {$IFDEF LINUX} - Platform := TPlatformLinux.Create; + Platform_singleton := TPlatformLinux.Create; {$ENDIF} {$IFDEF DARWIN} - Platform := TPlatformMacOSX.Create; + Platform_singleton := TPlatformMacOSX.Create; {$ENDIF} finalization - Platform := nil; + Platform_singleton := nil; end. diff --git a/Game/Code/Classes/UPlatformLinux.pas b/Game/Code/Classes/UPlatformLinux.pas index 0098baee..cde737b6 100644 --- a/Game/Code/Classes/UPlatformLinux.pas +++ b/Game/Code/Classes/UPlatformLinux.pas @@ -12,7 +12,7 @@ uses Classes, UPlatform; type - TPlatformLinux = class(TPlatform) + TPlatformLinux = class(TInterfacedObject, IPlatform) function get_homedir(): string; public Function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray; override; diff --git a/Game/Code/Classes/UPlatformMacOSX.pas b/Game/Code/Classes/UPlatformMacOSX.pas index a418919c..97c32fe3 100644 --- a/Game/Code/Classes/UPlatformMacOSX.pas +++ b/Game/Code/Classes/UPlatformMacOSX.pas @@ -12,13 +12,20 @@ uses Classes, UPlatform; type - TPlatformMacOSX = class(TPlatform) + TPlatformMacOSX = class( TInterfacedObject, IPlatform) private public +<<<<<<< .mine + Function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray; override; + function GetGamePath: WideString; override; + function TerminateIfAlreadyRunning(var WndTitle : String) : Boolean; + procedure halt(); +======= function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray; override; function GetLogPath : WideString; override; function GetGameSharedPath : WideString; override; function GetGameUserPath : WideString; override; +>>>>>>> .r788 end; implementation @@ -100,4 +107,15 @@ begin FPCloseDir(TheDir); end; +function TPlatformMacOSX.TerminateIfAlreadyRunning(var WndTitle : String) : Boolean; +begin + result := false;
+end; + + +procedure TPlatformMacOSX.halt; +begin + halt; +end; + end. diff --git a/Game/Code/Classes/UPlatformWindows.pas b/Game/Code/Classes/UPlatformWindows.pas index 93e72e7a..d4ba757a 100644 --- a/Game/Code/Classes/UPlatformWindows.pas +++ b/Game/Code/Classes/UPlatformWindows.pas @@ -8,19 +8,30 @@ interface {$I switches.inc}
-uses Classes, UPlatform;
+uses Classes,
+ UPlatform;
type
- TPlatformWindows = class(TPlatform)
+ TPlatformWindows = class( TInterfacedObject, IPlatform)
public
- Function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray; override;
- function TerminateIfAlreadyRunning(var WndTitle : String) : Boolean; override;
+ Function DirectoryFindFiles(Dir, Filter : WideString; ReturnAllSubDirs : Boolean) : TDirectoryEntryArray;
+ function TerminateIfAlreadyRunning(var WndTitle : String) : Boolean;
+ function GetGamePath: WideString;
+ function FindSongFile(Dir, Mask: widestring): widestring;
+
+ procedure halt;
+
+ function GetLogPath : WideString;
+ function GetGameSharedPath : WideString; + function GetGameUserPath : WideString; end;
implementation
-uses SysUtils, Windows;
+uses SysUtils,
+ Windows,
+ Forms;
type
@@ -175,4 +186,42 @@ begin FindCloseW(SR);
end;
+function TPlatformWindows.GetGamePath: WideString;
+begin
+ // Windows and Linux use this:
+ Result := ExtractFilePath(ParamStr(0));
+end;
+
+procedure TPlatformWindows.halt;
+begin
+ application.terminate;
+end;
+
+function TPlatformWindows.GetLogPath : WideString;
+begin + result := ExtractFilePath(ParamStr(0)); +end; + +function TPlatformWindows.GetGameSharedPath : WideString; +begin + result := ExtractFilePath(ParamStr(0)); +end; + +function TPlatformWindows.GetGameUserPath : WideString; +begin + result := ExtractFilePath(ParamStr(0)); +end; +
+
function TPlatformWindows.FindSongFile(Dir, Mask: widestring): widestring; +
var +
SR: TSearchRec; // for parsing song directory +begin + Result := ''; + if SysUtils.FindFirst(Dir + Mask, faDirectory, SR) = 0 then begin + Result := SR.Name; + end; // if + SysUtils.FindClose(SR); +end; +
+
end.
diff --git a/Game/Code/Classes/URecord.pas b/Game/Code/Classes/URecord.pas index dee1a687..ab351f6e 100644 --- a/Game/Code/Classes/URecord.pas +++ b/Game/Code/Classes/URecord.pas @@ -14,7 +14,9 @@ uses Classes, UCommon, UMusic, UIni; - + +// http://www.poltran.com + type TSound = class BufferNew: TMemoryStream; // buffer for newest sample @@ -26,7 +28,7 @@ type // pitch detection SzczytJest: boolean; // czy jest szczyt - Szczyt: integer; // pozycja szczytu na osi poziomej + pivot : integer; // Position of summit (top) on horizontal pivot TonDokl: real; // ton aktualnego szczytu Ton: integer; // ton bez ulamka TonGamy: integer; // ton w gamie. wartosci: 0-11 @@ -34,8 +36,8 @@ type // procedures procedure ProcessNewBuffer; - procedure AnalizujBufor; // use to analyze sound from buffers to get new pitch - procedure AnalizujByAutocorrelation; // we call it to analyze sound by checking Autocorrelation + procedure AnalyzeBuffer; // use to analyze sound from buffers to get new pitch + procedure AnalyzeByAutocorrelation; // we call it to analyze sound by checking Autocorrelation function AnalyzeAutocorrelationFreq(Freq: real): real; // use this to check one frequency by Autocorrelation end; @@ -54,31 +56,46 @@ type CaptureSoundRight: TSound; // sound(-buffer) used for right channel capture data end; - TRecord = class + TAudioInputProcessor = class Sound: array of TSound; SoundCard: array of TGenericSoundCard; + constructor Create; - + // handle microphone input procedure HandleMicrophoneData(Buffer: Pointer; Length: Cardinal; - InputDevice: TGenericSoundCard); + InputDevice: TGenericSoundCard); + + function volume( aChannel : byte ): byte; end; smallintarray = array [0..maxInt shr 1-1] of smallInt; psmallintarray = ^smallintarray; -var - Poz: integer; - Recording: TRecord; + function AudioInputProcessor(): TAudioInputProcessor; implementation uses UMain; +var + singleton_AudioInputProcessor : TAudioInputProcessor = nil; + + // FIXME: Race-Conditions between Callback-thread and main-thread // on BufferArray (maybe BufferNew also). // Use SDL-mutexes to solve this problem. + +function AudioInputProcessor(): TAudioInputProcessor; +begin + if singleton_AudioInputProcessor = nil then
+ singleton_AudioInputProcessor := TAudioInputProcessor.create();
+
+ result := singleton_AudioInputProcessor;
+
+end;
+ procedure TSound.ProcessNewBuffer; var S: integer; @@ -108,12 +125,12 @@ begin end; end; -procedure TSound.AnalizujBufor; +procedure TSound.AnalyzeBuffer; begin - AnalizujByAutocorrelation; + AnalyzeByAutocorrelation; end; -procedure TSound.AnalizujByAutocorrelation; +procedure TSound.AnalyzeByAutocorrelation; var T: integer; // tone F: real; // freq @@ -143,7 +160,7 @@ begin // analyze all 12 halftones for T := 0 to 35 do // to 11, then 23, now 35 (for Whitney and my high voice) begin - F := 130.81*Power(1.05946309436, T)/2; // let's analyze below 130.81 + F := 130.81 * Power(1.05946309436, T)/2; // let's analyze below 130.81 Wages[T] := AnalyzeAutocorrelationFreq(F); if Wages[T] > MaxW then @@ -164,8 +181,8 @@ begin if MaxV >= Threshold then begin // found acceptable volume // 0.1 SzczytJest := true; - TonGamy := MaxT mod 12; - Ton := MaxT mod 12; + TonGamy := MaxT mod 12; + Ton := MaxT mod 12; end; end; @@ -206,8 +223,7 @@ end; * Length - number of bytes in Buffer * Input - Soundcard-Input used for capture *} -procedure TRecord.HandleMicrophoneData(Buffer: Pointer; Length: Cardinal; - InputDevice: TGenericSoundCard); +procedure TAudioInputProcessor.HandleMicrophoneData(Buffer: Pointer; Length: Cardinal; InputDevice: TGenericSoundCard); var L: integer; S: integer; @@ -231,8 +247,14 @@ begin for S := 0 to L-1 do begin I := PSI^[S] * Boost; - if I > 32767 then I := 32767; // 0.5.0: limit - if I < -32768 then I := -32768; // 0.5.0: limit + + // TODO : JB - This will clip the audio... cant we reduce the "Boot" if the data clips ?? + if I > 32767 then + I := 32767; // 0.5.0: limit + + if I < -32768 then + I := -32768; // 0.5.0: limit + PSI^[S] := I; end; @@ -266,12 +288,13 @@ begin end; end; -constructor TRecord.Create; +constructor TAudioInputProcessor.Create; var S: integer; begin SetLength(Sound, 6 {max players});//Ini.Players+1); - for S := 0 to High(Sound) do begin //Ini.Players do begin + for S := 0 to High(Sound) do + begin //Ini.Players do begin Sound[S] := TSound.Create; Sound[S].Num := S; Sound[S].BufferNew := TMemoryStream.Create; @@ -281,6 +304,20 @@ begin end; end; +function TAudioInputProcessor.volume( aChannel : byte ): byte; +var + lCount : Integer; + lMaxVol : double; +begin; + lMaxVol := AudioInputProcessor.Sound[aChannel].BufferArray[1]; + for lCount := 2 to AudioInputProcessor.Sound[aChannel].n div 1 do + begin + if AudioInputProcessor.Sound[aChannel].BufferArray[lCount] > lMaxVol then + lMaxVol := AudioInputProcessor.Sound[aChannel].BufferArray[lCount]; + end; + + result := trunc( ( 255 / 32767 ) * trunc( lMaxVol ) ); +end; end. diff --git a/Game/Code/Classes/USongs.pas b/Game/Code/Classes/USongs.pas index a4709b43..c5acec9c 100644 --- a/Game/Code/Classes/USongs.pas +++ b/Game/Code/Classes/USongs.pas @@ -40,6 +40,7 @@ uses {$IFDEF USE_PSEUDO_THREAD} PseudoThread, {$ENDIF} + USong, UCatCovers; type @@ -55,48 +56,6 @@ type Length: string; end; - TSong = record - Path: widestring; - Folder: widestring; // for sorting by folder - FileName: widestring; - - // sorting methods - Category: array of widestring; // I think I won't need this - Genre: widestring; - Edition: widestring; - Language: widestring; // 0.5.0: new - - Title: widestring; - Artist: widestring; - - Text: widestring; - Creator: widestring; - - Cover: widestring; - CoverTex: TTexture; - Mp3: widestring; - Background: widestring; - Video: widestring; - VideoGAP: real; - VideoLoaded: boolean; // 0.5.0: 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 - end; - {$IFDEF USE_PSEUDO_THREAD} TSongs = class( TPseudoThread ) @@ -104,7 +63,6 @@ type TSongs = class( TThread ) {$ENDIF} private - BrowsePos : Integer; //Actual Pos in Song Array. eddie: Must be int, because it could be decremented to -1. fNotify , fWatch : longint; fParseSongDirectory : boolean; @@ -117,9 +75,13 @@ type protected procedure Execute; override; public - Song : array of TSong; // array of songs +// 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); @@ -127,6 +89,7 @@ type property Processing : boolean read fProcessing; end; + TCatSongs = class Song: array of TSong; // array of categories with songs Selected: integer; // selected song index @@ -150,7 +113,6 @@ type var Songs: TSongs; // all songs CatSongs: TCatSongs; // categorized songs - AktSong: TSong; // one song *unknown use) const IN_ACCESS = $00000001; //* File was accessed */ @@ -187,6 +149,8 @@ begin inherited create( false ); self.freeonterminate := true; + SongList := TList.create(); + {$ifdef Delphi} fDirWatch := TDirectoryWatch.create(nil); fDirWatch.OnChange := DoDirChanged; @@ -218,12 +182,18 @@ begin writeln( 'Calling syscall_nr_inotify_init : '+ inttostr(fWatch) ); *) {$endif} - -{$IFNDEF USE_PSEUDO_THREAD} - Setlength(Song, 0); + +{$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(); @@ -237,7 +207,7 @@ begin int_LoadSongList(); {$ELSE} fParseSongDirectory := true; - + while not self.terminated do begin @@ -256,21 +226,15 @@ procedure TSongs.int_LoadSongList; begin try fProcessing := true; - Setlength(Song, 0); + SongList.clear; Log.LogError('SongList', 'Searching For Songs'); - Setlength(Song, 50); - - BrowsePos := 0; // browse directories BrowseDir(SongPath); - + if UserSongPath <> SongPath then BrowseDir(UserSongPath); - - //Set Correct SongArray Length - SetLength(Song, BrowsePos); if assigned( CatSongs ) then CatSongs.Refresh; @@ -287,7 +251,6 @@ begin ScreenSong.OnShow; // refresh ScreenSong end; - finally Log.LogError('SongList', 'Search Complete'); @@ -305,12 +268,13 @@ end; procedure TSongs.BrowseDir(Dir: widestring); var - SLen: integer; - i : Integer; + 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 @@ -319,37 +283,21 @@ begin end else begin - SLen := BrowsePos; + lSong := TSong.create( Dir + Files[i].Name ); - Song[SLen].Path := Dir; -// Song[SLen].Folder := Copy(Dir, Length(SongPath)+1, 10000); - Song[SLen].Folder := Copy(Dir, Length(Dir)+1, 10000); - Song[SLen].Folder := Copy(Song[SLen].Folder, 1, Pos( PathDelim , Song[SLen].Folder)-1); - Song[SLen].FileName := Files[i].Name; - - if (AnalyseFile(Song[SLen]) = false) then + if NOT lSong.Analyse then begin Log.LogError('AnalyseFile failed for "' + Files[i].Name + '".'); - Dec(BrowsePos); + freeandnil( lSong ); end else begin - if Song[SLen].Cover = '' then - Song[SLen].Cover := FindSongFile(Dir, '*[CO].jpg'); + SongList.add( lSong ); end; - //Change Length Only every 50 Entrys - Inc(BrowsePos); - - if (BrowsePos mod 50 = 0) AND (BrowsePos <> 0) then - begin - SetLength(Song, Length(Song) + 50); - end; end; end; SetLength( Files, 0); - -// Log.LogStatus('Parsing directory: ' + Dir + SR.Name, 'LoadSongList'); end; procedure TSongs.Sort(Order: integer); @@ -361,91 +309,99 @@ begin case Order of sEdition: // by edition begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Edition, Song[S-1].Edition) < 0 then 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 := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; end; end; sGenre: // by genre begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Genre, Song[S-1].Genre) < 0 then 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 := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; end; end; sTitle: // by title begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Title, Song[S-1].Title) < 0 then 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 := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; end; end; sArtist: // by artist begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Artist, Song[S-1].Artist) < 0 then 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 := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; end; end; sFolder: // by folder begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Folder, Song[S-1].Folder) < 0 then 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 := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; end; end; sTitle2: // by title2 begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Title, Song[S-1].Title) < 0 then 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 := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; end; end; sArtist2: // by artist2 begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Artist, Song[S-1].Artist) < 0 then 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 := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + TempSong := SongList[S-1]; + SongList[S-1] := SongList[S]; + SongList[S] := TempSong; end; end; sLanguage: // by Language begin - for S2 := 0 to Length(Song)-1 do - for S := 1 to Length(Song)-1 do - if CompareText(Song[S].Language, Song[S-1].Language) < 0 then begin - TempSong := Song[S-1]; - Song[S-1] := Song[S]; - Song[S] := TempSong; + 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; @@ -509,12 +465,13 @@ case Ini.Sorting of //Songs leeren SetLength (Song, 0); - for S := Low(Songs.Song) to High(Songs.Song) do begin + for S := 0 to Songs.SongList.Count-1 do + begin if (Ini.Tabs = 1) then - if (Ini.Sorting = sEdition) and (CompareText(SS, Songs.Song[S].Edition) <> 0) then begin + if (Ini.Sorting = sEdition) and (CompareText(SS, TSong( Songs.SongList[S] ).Edition) <> 0) then begin // add Category Button Inc(Order); - SS := Songs.Song[S].Edition; + SS := TSong( Songs.SongList[S] ).Edition; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := '[' + SS + ']'; @@ -554,10 +511,10 @@ case Ini.Sorting of CatSongs.Song[CatLen].Visible := true; end - else if (Ini.Sorting = sGenre) and (CompareText(SS, Songs.Song[S].Genre) <> 0) then begin + else if (Ini.Sorting = sGenre) and (CompareText(SS, TSong( Songs.SongList[S] ).Genre) <> 0) then begin // add Genre Button Inc(Order); - SS := Songs.Song[S].Genre; + SS := TSong( Songs.SongList[S] ).Genre; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := SS; @@ -580,10 +537,10 @@ case Ini.Sorting of CatSongs.Song[CatLen].Visible := true; end - else if (Ini.Sorting = sLanguage) and (CompareText(SS, Songs.Song[S].Language) <> 0) then begin + else if (Ini.Sorting = sLanguage) and (CompareText(SS, TSong( Songs.SongList[S] ).Language) <> 0) then begin // add Language Button Inc(Order); - SS := Songs.Song[S].Language; + SS := TSong( Songs.SongList[S] ).Language; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := SS; @@ -607,11 +564,11 @@ case Ini.Sorting of end else if (Ini.Sorting = sTitle) and - (Length(Songs.Song[S].Title)>=1) and - (Letter <> UpperCase(Songs.Song[S].Title)[1]) then begin + (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(Songs.Song[S].Title)[1]; + Letter := Uppercase(TSong( Songs.SongList[S] ).Title)[1]; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; @@ -636,10 +593,11 @@ case Ini.Sorting of CatSongs.Song[CatLen].Visible := true; end - else if (Ini.Sorting = sArtist) and (Length(Songs.Song[S].Artist)>=1) and (Letter <> UpperCase(Songs.Song[S].Artist)[1]) then begin + 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(Songs.Song[S].Artist)[1]; + Letter := UpperCase(TSong( Songs.SongList[S] ).Artist)[1]; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; @@ -663,10 +621,10 @@ case Ini.Sorting of CatSongs.Song[CatLen].Visible := true; end - else if (Ini.Sorting = sFolder) and (CompareText(SS, Songs.Song[S].Folder) <> 0) then begin + 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 := Songs.Song[S].Folder; + SS := TSong( Songs.SongList[S] ).Folder; CatLen := Length(CatSongs.Song); SetLength(CatSongs.Song, CatLen+1); CatSongs.Song[CatLen].Artist := SS; @@ -689,8 +647,8 @@ case Ini.Sorting of CatSongs.Song[CatLen].Visible := true; end - else if (Ini.Sorting = sTitle2) AND (Length(Songs.Song[S].Title)>=1) then begin - if (ord(Songs.Song[S].Title[1]) > 47) and (ord(Songs.Song[S].Title[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(Songs.Song[S].Title)[1]; + 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); @@ -719,8 +677,8 @@ case Ini.Sorting of end; end - else if (Ini.Sorting = sArtist2) AND (Length(Songs.Song[S].Artist)>=1) then begin - if (ord(Songs.Song[S].Artist[1]) > 47) and (ord(Songs.Song[S].Artist[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(Songs.Song[S].Artist)[1]; + 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); @@ -755,7 +713,7 @@ case Ini.Sorting of Inc (CatNumber); //Increase Number in Cat - CatSongs.Song[CatLen] := Songs.Song[S]; + CatSongs.Song[CatLen] := TSong( Songs.SongList[S] ); CatSongs.Song[CatLen].OrderNum := Order; // assigns category CatSongs.Song[CatLen].CatNumber := CatNumber; @@ -923,4 +881,11 @@ begin end; end; + + +// ----------------------------------------------------------------------------- + + + + end. |