Commit f284a8f

Nick committed on
WIP adding routines, fixing new file format
commit f284a8f1bc249f0fb75e3f680bfb3512ef7fd7d4 parent 749f4a2
6 changed files +165−38
Modifiedcodegen.pas +23−0
@@ -161,6 +161,24 @@ begin
161 SL.Free; 161 SL.Free;
162 end; 162 end;
163 163
164 function RenderRoutines(Routines: TRoutineBank): String;
165 var
166 I: Integer;
167 SL: TStringList;
168 begin
169 SL := TStringList.Create;
170
171 for I := Low(TRoutineBank) to High(TRoutineBank) do begin
172 SL.Add(Format('__hUGE_Routine_%d:', [I]));
173 SL.Add(Routines[I]);
174 SL.Add(Format('__end_hUGE_Routine_%d:', [I]));
175 SL.Add(Format('ds 16 - (__end_hUGE_Routine_%d - __hUGE_Routine_%d)', [I, I]));
176 end;
177
178 Result := SL.Text;
179 SL.Free
180 end;
181
164 function RenderPreviewROM(Song: TSong): Boolean; 182 function RenderPreviewROM(Song: TSong): Boolean;
165 begin 183 begin
166 Result := RenderSongToFile(Song, 'preview.gb', emPreview); 184 Result := RenderSongToFile(Song, 'preview.gb', emPreview);
@@ -198,6 +216,11 @@ begin
198 Write(OutFile, RenderInstruments(Song.Instruments)); 216 Write(OutFile, RenderInstruments(Song.Instruments));
199 CloseFile(OutFile); 217 CloseFile(OutFile);
200 218
219 AssignFile(OutFile, './hUGEDriver/routine.htt');
220 Rewrite(OutFile);
221 Write(OutFile, RenderRoutines(Song.Routines));
222 CloseFile(OutFile);
223
201 AssignFile(OutFile, './hUGEDriver/pattern.htt'); 224 AssignFile(OutFile, './hUGEDriver/pattern.htt');
202 Rewrite(OutFile); 225 Rewrite(OutFile);
203 226
Modifiedhugedatatypes.pas +3−0
@@ -10,8 +10,11 @@ uses
10 type 10 type
11 Nibble = $0..$F; 11 Nibble = $0..$F;
12 12
13 TRoutine = string;
14
13 TInstrumentBank = packed array[1..15] of TInstrument; 15 TInstrumentBank = packed array[1..15] of TInstrument;
14 TWaveBank = packed array[0..15] of TWave; 16 TWaveBank = packed array[0..15] of TWave;
17 TRoutineBank = packed array[0..15] of TRoutine;
15 18
16 TEffectParams = bitpacked record 19 TEffectParams = bitpacked record
17 case Boolean of 20 case Boolean of
Modifiedsong.pas +111−33
@@ -6,10 +6,27 @@ interface
6 6
7 uses Classes, HugeDatatypes, instruments; 7 uses Classes, HugeDatatypes, instruments;
8 8
9 const
10 CURRENT_VERSION = 2;
11
9 type 12 type
10 { TSong } 13 TSongV1 = packed record
14 Version: Integer;
15
16 Name: ShortString;
17 Artist: ShortString;
18 Comment: ShortString;
11 19
12 TSong = packed record 20 Instruments: TInstrumentBank;
21 Waves: TWaveBank;
22
23 TicksPerRow: Integer;
24
25 Patterns: TPatternMap;
26 OrderMatrix: TOrderMatrix;
27 end;
28
29 TSongV2 = packed record
13 Version: Integer; 30 Version: Integer;
14 31
15 Name: ShortString; 32 Name: ShortString;
@@ -23,52 +40,34 @@ type
23 40
24 Patterns: TPatternMap; 41 Patterns: TPatternMap;
25 OrderMatrix: TOrderMatrix; 42 OrderMatrix: TOrderMatrix;
43
44 Routines: TRoutineBank;
26 end; 45 end;
27 46
47 { TSong }
48
49 TSong = TSongV2;
50
28 procedure WriteSongToStream(S: TStream; const ASong: TSong); 51 procedure WriteSongToStream(S: TStream; const ASong: TSong);
29 procedure ReadSongFromStream(S: TStream; var ASong: TSong); 52 procedure ReadSongFromStream(S: TStream; out ASong: TSong);
30 procedure InitializeSong(var S: TSong); 53 procedure InitializeSong(var S: TSong);
31 procedure DestroySong(var S: TSong); 54 procedure DestroySong(var S: TSong);
32 55
56 function UpgradeSong(S: TSongV1): TSong; overload;
57 function UpgradeSong(S: TSongV2): TSong; overload;
58
33 implementation 59 implementation
34 60
35 // Thanks to WP on the FreePascal forums for this code! 61 // Thanks to WP on the FreePascal forums for this code!
36 // https://forum.lazarus.freepascal.org/index.php/topic,47892.msg344152.html#msg344152 62 // https://forum.lazarus.freepascal.org/index.php/topic,47892.msg344152.html#msg344152
37 63
38 procedure WriteSongToStream(S: TStream; const ASong: TSong); 64 procedure ReadSongFromStreamV1(S: TStream; out ASong: TSongV1);
39 var
40 i, n: Integer;
41 pPat: PPattern;
42 begin
43 // Write the fixed record elements first
44 n := SizeOf(TSong) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix);
45 S.Write(ASong, n);
46
47 // Write the pattern count
48 S.Write(ASong.Patterns.Count, SizeOf(Integer));
49 // Write the patterns
50 for i := 0 to ASong.Patterns.Count-1 do
51 begin
52 pPat := ASong.Patterns[i];
53 S.Write(pPat^, SizeOf(pPat^));
54 end;
55
56 // Write the OrderMatrix arrays
57 for i := 0 to 3 do
58 begin
59 n := Length(ASong.OrderMatrix[i]);
60 S.Write(n, SizeOf(Integer));
61 S.Write(ASong.OrderMatrix[i][0], n*SizeOf(Integer));
62 end;
63 end;
64
65 procedure ReadSongFromStream(S: TStream; var ASong: TSong);
66 var 65 var
67 i, n: Integer; 66 i, n: Integer;
68 pat: PPattern; 67 pat: PPattern;
69 begin 68 begin
70 // Read the fixed elements first 69 // Read the fixed elements first
71 n := SizeOf(TSong) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix); 70 n := SizeOf(TSongV1) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix);
72 S.Read(ASong, n); 71 S.Read(ASong, n);
73 72
74 // ASong.Patterns.Clear; 73 // ASong.Patterns.Clear;
@@ -98,12 +97,71 @@ begin
98 end; 97 end;
99 end; 98 end;
100 99
100 procedure ReadSongFromStreamV2(S: TStream; out ASong: TSongV2);
101 var
102 i: Integer;
103 SongV1: TSongV1 absolute ASong;
104 begin
105 ReadSongFromStreamV1(S, SongV1);
106
107 // Read routines
108 for I := Low(TRoutineBank) to High(TRoutineBank) do
109 ASong.Routines[I] := S.ReadAnsiString;
110 end;
111
112 procedure WriteSongToStream(S: TStream; const ASong: TSong);
113 var
114 i, n: Integer;
115 pPat: PPattern;
116 begin
117 // Write the fixed record elements first
118 n := SizeOf(TSong) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix);
119 S.Write(ASong, n);
120
121 // Write the pattern count
122 S.Write(ASong.Patterns.Count, SizeOf(Integer));
123 // Write the patterns
124 for i := 0 to ASong.Patterns.Count-1 do
125 begin
126 pPat := ASong.Patterns[i];
127 S.Write(pPat^, SizeOf(pPat^));
128 end;
129
130 // Write the OrderMatrix arrays
131 for i := 0 to 3 do
132 begin
133 n := Length(ASong.OrderMatrix[i]);
134 S.Write(n, SizeOf(Integer));
135 S.Write(ASong.OrderMatrix[i][0], n*SizeOf(Integer));
136 end;
137
138 // Write the routines
139 for i := Low(TRoutineBank) to High(TRoutineBank) do
140 S.WriteAnsiString(ASong.Routines[i]);
141 end;
142
143 procedure ReadSongFromStream(S: TStream; out ASong: TSong);
144 var
145 Version: Integer;
146 SV1: TSongV1;
147 begin
148 S.Read(Version, SizeOf(Integer));
149 S.Seek(0, soBeginning);
150 case Version of
151 0..1: begin
152 ReadSongFromStreamV1(S, SV1);
153 ASong := UpgradeSong(SV1);
154 end;
155 2: ReadSongFromStreamV2(S, ASong);
156 end;
157 end;
158
101 procedure InitializeSong(var S: TSong); 159 procedure InitializeSong(var S: TSong);
102 var 160 var
103 I, J: Integer; 161 I, J: Integer;
104 begin 162 begin
105 with S do begin 163 with S do begin
106 Version := 1; 164 Version := CURRENT_VERSION;
107 Name := ''; 165 Name := '';
108 Artist := ''; 166 Artist := '';
109 Comment := ''; 167 Comment := '';
@@ -148,5 +206,25 @@ begin
148 SetLength(S.OrderMatrix[I], 0); 206 SetLength(S.OrderMatrix[I], 0);
149 end; 207 end;
150 208
209 function UpgradeSong(S: TSongV1): TSong;
210 var
211 SV2: TSongV2;
212 begin
213 SV2 := Default(TSongV2);
214 Move(S, SV2, SizeOf(TSongV1) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix));
215
216 // Gotta preserve reference count so can't include it in the move...
217 SV2.Patterns := S.Patterns;
218 SV2.OrderMatrix := S.OrderMatrix;
219 Inc(SV2.Version); // Bump version
220
221 Result := UpgradeSong(SV2);
222 end;
223
224 function UpgradeSong(S: TSongV2): TSong;
225 begin
226 Result := S;
227 end;
228
151 end. 229 end.
152 230
Modifiedtracker.lfm +4−3
@@ -1,7 +1,7 @@
1 object frmTracker: TfrmTracker 1 object frmTracker: TfrmTracker
2 Left = 807 2 Left = 1123
3 Height = 1200 3 Height = 1200
4 Top = 205 4 Top = 146
5 Width = 2040 5 Width = 2040
6 Caption = 'hUGETracker' 6 Caption = 'hUGETracker'
7 ClientHeight = 1166 7 ClientHeight = 1166
@@ -1486,6 +1486,7 @@ object frmTracker: TfrmTracker
1486 MouseLinkColor.Foreground = clBlue 1486 MouseLinkColor.Foreground = clBlue
1487 LineHighlightColor.Background = clNone 1487 LineHighlightColor.Background = clNone
1488 LineHighlightColor.Foreground = clNone 1488 LineHighlightColor.Foreground = clNone
1489 OnChange = RoutineSyneditChange
1489 inline SynLeftGutterPartList1: TSynGutterPartList 1490 inline SynLeftGutterPartList1: TSynGutterPartList
1490 object SynGutterMarks1: TSynGutterMarks 1491 object SynGutterMarks1: TSynGutterMarks
1491 Width = 42 1492 Width = 42
@@ -1537,9 +1538,9 @@ object frmTracker: TfrmTracker
1537 Height = 38 1538 Height = 38
1538 Top = 14 1539 Top = 14
1539 Width = 308 1540 Width = 308
1540 Enabled = False
1541 MaxValue = 15 1541 MaxValue = 15
1542 MinValue = 1 1542 MinValue = 1
1543 OnChange = RoutineNumberSpinnerChange
1543 ParentFont = False 1544 ParentFont = False
1544 TabOrder = 1 1545 TabOrder = 1
1545 Value = 1 1546 Value = 1
Modifiedtracker.pas +12−0
@@ -280,6 +280,8 @@ type
280 procedure PanicToolButtonClick(Sender: TObject); 280 procedure PanicToolButtonClick(Sender: TObject);
281 procedure PasteActionExecute(Sender: TObject); 281 procedure PasteActionExecute(Sender: TObject);
282 procedure OctaveSpinEditChange(Sender: TObject); 282 procedure OctaveSpinEditChange(Sender: TObject);
283 procedure RoutineNumberSpinnerChange(Sender: TObject);
284 procedure RoutineSyneditChange(Sender: TObject);
283 procedure ShiftClockSpinnerChange(Sender: TObject); 285 procedure ShiftClockSpinnerChange(Sender: TObject);
284 procedure StepSpinEditChange(Sender: TObject); 286 procedure StepSpinEditChange(Sender: TObject);
285 procedure TicksPerRowSpinEditChange(Sender: TObject); 287 procedure TicksPerRowSpinEditChange(Sender: TObject);
@@ -1272,6 +1274,16 @@ begin
1272 TrackerGrid.SelectedOctave := OctaveSpinEdit.Value; 1274 TrackerGrid.SelectedOctave := OctaveSpinEdit.Value;
1273 end; 1275 end;
1274 1276
1277 procedure TfrmTracker.RoutineNumberSpinnerChange(Sender: TObject);
1278 begin
1279 RoutineSynedit.Text := Song.Routines[RoutineNumberSpinner.Value];
1280 end;
1281
1282 procedure TfrmTracker.RoutineSyneditChange(Sender: TObject);
1283 begin
1284 Song.Routines[RoutineNumberSpinner.Value] := RoutineSynedit.Text;
1285 end;
1286
1275 procedure TfrmTracker.ShiftClockSpinnerChange(Sender: TObject); 1287 procedure TfrmTracker.ShiftClockSpinnerChange(Sender: TObject);
1276 begin 1288 begin
1277 CurrentInstrument^.ShiftClockFreq := Round(ShiftClockTrackbar.Position); 1289 CurrentInstrument^.ShiftClockFreq := Round(ShiftClockTrackbar.Position);
Modifiedtrackergrid.pas +12−2
@@ -533,10 +533,20 @@ end;
533 533
534 procedure TTrackerGrid.ClampCursors; 534 procedure TTrackerGrid.ClampCursors;
535 begin 535 begin
536 if Cursor.X < Low(TPatternGrid) then
537 Cursor.SelectedPart := Low(TCellPart);
538 if Cursor.X > High(TPatternGrid) then
539 Cursor.SelectedPart := High(TCellPart);
540
541 if Other.X < Low(TPatternGrid) then
542 Other.SelectedPart := Low(TCellPart);
543 if Other.X > High(TPatternGrid) then
544 Other.SelectedPart := High(TCellPart);
545
536 Cursor.Y := EnsureRange(Cursor.Y, Low(TPattern), High(TPattern)); 546 Cursor.Y := EnsureRange(Cursor.Y, Low(TPattern), High(TPattern));
537 Cursor.X := EnsureRange(Cursor.X, Low(TPattern), High(TPattern)); 547 Cursor.X := EnsureRange(Cursor.X, Low(TPatternGrid), High(TPatternGrid));
538 Other.Y := EnsureRange(Other.Y, Low(TPattern), High(TPattern)); 548 Other.Y := EnsureRange(Other.Y, Low(TPattern), High(TPattern));
539 Other.X := EnsureRange(Other.X, Low(TPattern), High(TPattern)); 549 Other.X := EnsureRange(Other.X, Low(TPatternGrid), High(TPatternGrid));
540 end; 550 end;
541 551
542 procedure TTrackerGrid.NormalizeCursors; 552 procedure TTrackerGrid.NormalizeCursors;