Commit e18eed6

Nick committed on
WIP implementation of new file format and 3 instrument banks
commit e18eed6cda96301007ecd043054ebacd73f26225 parent 21c58be
7 changed files +130−15
Modifiedcodegen.pas +6−2
@@ -6,7 +6,8 @@ interface
6 6
7 uses 7 uses
8 Classes, SysUtils, math, Instruments, Song, Utils, 8 Classes, SysUtils, math, Instruments, Song, Utils,
9 HugeDatatypes, Constants, dialogs, strutils, FileUtil, LazFileUtils; 9 HugeDatatypes, Constants, dialogs, strutils, FileUtil, LazFileUtils,
10 lclintf;
10 11
11 type 12 type
12 TExportMode = (emNormal, emPreview, emGBS); 13 TExportMode = (emNormal, emPreview, emGBS);
@@ -295,7 +296,7 @@ begin
295 mtError, 296 mtError,
296 [mbOK], 297 [mbOK],
297 0) 298 0)
298 else 299 else begin
299 MessageDlg( 300 MessageDlg(
300 'Error!', 301 'Error!',
301 'There was an error assembling the song for playback.'+LineEnding+LineEnding+ 302 'There was an error assembling the song for playback.'+LineEnding+LineEnding+
@@ -307,6 +308,9 @@ begin
307 [mbOK], 308 [mbOK],
308 0); 309 0);
309 310
311 {$ifdef PRODUCTION}OpenURL('https://github.com/SuperDisk/UGE/issues');{$endif}
312 end;
313
310 Cleanup: 314 Cleanup:
311 Proc.Free; 315 Proc.Free;
312 OutSL.Free; 316 OutSL.Free;
Modifiedconstants.pas +1−1
@@ -18,7 +18,7 @@ type
18 TRoutineIndex = 0..15; 18 TRoutineIndex = 0..15;
19 19
20 const 20 const
21 UGE_FORMAT_VERSION = 2; 21 UGE_FORMAT_VERSION = 3;
22 22
23 INSTRUMENTS_COUNT = 15; 23 INSTRUMENTS_COUNT = 15;
24 ROUTINES_COUNT = 16; 24 ROUTINES_COUNT = 16;
Modifiedhugedatatypes.pas +6−0
@@ -13,6 +13,12 @@ type
13 TRoutine = string; 13 TRoutine = string;
14 14
15 TInstrumentBank = packed array[1..15] of TInstrument; 15 TInstrumentBank = packed array[1..15] of TInstrument;
16 TInstrumentCollection = packed record
17 case Boolean of
18 False: (DutyInstruments, WaveInstruments, NoiseInstruments: TInstrumentBank);
19 True: (All: packed array[1..45] of TInstrument);
20 end;
21
16 TWaveBank = packed array[0..15] of TWave; 22 TWaveBank = packed array[0..15] of TWave;
17 TRoutineBank = packed array[0..15] of TRoutine; 23 TRoutineBank = packed array[0..15] of TRoutine;
18 24
Modifiedmodimport.pas +1−1
@@ -40,7 +40,7 @@ type
40 40
41 { TMODRow } 41 { TMODRow }
42 42
43 TMODRow = bitpacked record 43 TMODRow = record
44 Note: Integer; 44 Note: Integer;
45 Instrument: Integer; 45 Instrument: Integer;
46 Effect: bitpacked record 46 Effect: bitpacked record
Modifiedsong.pas +112−9
@@ -2,6 +2,9 @@ unit Song;
2 2
3 {$mode delphi} 3 {$mode delphi}
4 4
5 // TODO: Lots of duplicated code in here. At some point this should switch over
6 // to a more parsable format, like NBT, JSON, or XML or something.
7
5 interface 8 interface
6 9
7 uses Classes, HugeDatatypes, instruments, Constants; 10 uses Classes, HugeDatatypes, instruments, Constants;
@@ -41,9 +44,28 @@ type
41 Routines: TRoutineBank; 44 Routines: TRoutineBank;
42 end; 45 end;
43 46
47 TSongV3 = packed record
48 Version: Integer;
49
50 Name: ShortString;
51 Artist: ShortString;
52 Comment: ShortString;
53
54 Instruments: TInstrumentCollection;
55
56 Waves: TWaveBank;
57
58 TicksPerRow: Integer;
59
60 Patterns: TPatternMap;
61 OrderMatrix: TOrderMatrix;
62
63 Routines: TRoutineBank;
64 end;
65
44 { TSong } 66 { TSong }
45 67
46 TSong = TSongV2; 68 TSong = TSongV3;
47 69
48 procedure WriteSongToStream(S: TStream; const ASong: TSong); 70 procedure WriteSongToStream(S: TStream; const ASong: TSong);
49 procedure ReadSongFromStream(S: TStream; out ASong: TSong); 71 procedure ReadSongFromStream(S: TStream; out ASong: TSong);
@@ -52,6 +74,7 @@ procedure DestroySong(var S: TSong);
52 74
53 function UpgradeSong(S: TSongV1): TSong; overload; 75 function UpgradeSong(S: TSongV1): TSong; overload;
54 function UpgradeSong(S: TSongV2): TSong; overload; 76 function UpgradeSong(S: TSongV2): TSong; overload;
77 function UpgradeSong(S: TSongV3): TSong; overload;
55 78
56 implementation 79 implementation
57 80
@@ -67,8 +90,6 @@ begin
67 n := SizeOf(TSongV1) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix); 90 n := SizeOf(TSongV1) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix);
68 S.Read(ASong, n); 91 S.Read(ASong, n);
69 92
70 // ASong.Patterns.Clear;
71
72 // Create the patterns 93 // Create the patterns
73 ASong.Patterns := TPatternMap.Create; 94 ASong.Patterns := TPatternMap.Create;
74 // Read the pattern count 95 // Read the pattern count
@@ -107,7 +128,46 @@ begin
107 128
108 S.Read(ASong, n); 129 S.Read(ASong, n);
109 130
110 // ASong.Patterns.Clear; 131 // Create the patterns
132 ASong.Patterns := TPatternMap.Create;
133 // Read the pattern count
134 S.Read(n, SizeOf(Integer));
135 for i:=0 to n - 1 do begin
136 // Allocate memory for each pattern ...
137 New(pat);
138 // and read the pattern content
139 S.Read(pat^, SizeOf(TPattern));
140 // Add the pattern to the list
141 ASong.Patterns.Add(i, pat);
142 end;
143
144 // Read the OrderMatrix
145 for i := 0 to 3 do
146 begin
147 // Read length of each OrderMatrix array
148 S.Read(n, SizeOf(Integer));
149 // Allocate memory for it
150 SetLength(ASong.OrderMatrix[i], n);
151 // Read content of OrderMatrix array
152 S.Read(ASong.OrderMatrix[i, 0], n*SizeOf(Integer));
153 end;
154
155 for I := Low(TRoutineBank) to High(TRoutineBank) do
156 ASong.Routines[I] := S.ReadAnsiString;
157 end;
158
159 procedure ReadSongFromStreamV3(S: TStream; out ASong: TSongV3);
160 var
161 i, n: Integer;
162 pat: PPattern;
163 begin
164 // Read the fixed elements first
165 n := SizeOf(TSongV3)
166 - SizeOf(TPatternMap)
167 - SizeOf(TOrderMatrix)
168 - SizeOf(TRoutineBank);
169
170 S.Read(ASong, n);
111 171
112 // Create the patterns 172 // Create the patterns
113 ASong.Patterns := TPatternMap.Create; 173 ASong.Patterns := TPatternMap.Create;
@@ -143,7 +203,7 @@ var
143 pPat: PPattern; 203 pPat: PPattern;
144 begin 204 begin
145 // Write the fixed record elements first 205 // Write the fixed record elements first
146 n := SizeOf(TSongV2) 206 n := SizeOf(TSongV3)
147 - SizeOf(TPatternMap) 207 - SizeOf(TPatternMap)
148 - SizeOf(TOrderMatrix) 208 - SizeOf(TOrderMatrix)
149 - SizeOf(TRoutineBank); 209 - SizeOf(TRoutineBank);
@@ -173,8 +233,9 @@ end;
173 233
174 procedure ReadSongFromStream(S: TStream; out ASong: TSong); 234 procedure ReadSongFromStream(S: TStream; out ASong: TSong);
175 var 235 var
176 Version: Integer = 1; 236 Version: Integer;
177 SV1: TSongV1; 237 SV1: TSongV1;
238 SV2: TSongV2;
178 begin 239 begin
179 S.Read(Version, SizeOf(Integer)); 240 S.Read(Version, SizeOf(Integer));
180 S.Seek(0, soBeginning); 241 S.Seek(0, soBeginning);
@@ -183,7 +244,11 @@ begin
183 ReadSongFromStreamV1(S, SV1); 244 ReadSongFromStreamV1(S, SV1);
184 ASong := UpgradeSong(SV1); 245 ASong := UpgradeSong(SV1);
185 end; 246 end;
186 2: ReadSongFromStreamV2(S, ASong); 247 2: begin
248 ReadSongFromStreamV2(S, SV2);
249 ASong := UpgradeSong(SV2);
250 end;
251 3: ReadSongFromStreamV3(S, ASong);
187 end; 252 end;
188 end; 253 end;
189 254
@@ -197,8 +262,45 @@ begin
197 Artist := ''; 262 Artist := '';
198 Comment := ''; 263 Comment := '';
199 end; 264 end;
200 for I := Low(S.Instruments) to High(S.Instruments) do 265
201 with S.Instruments[I] do begin 266 for I := Low(S.Instruments.DutyInstruments) to High(S.Instruments.DutyInstruments) do
267 with S.Instruments.DutyInstruments[I] do begin
268 Type_ := itSquare;
269 Length := 0;
270 LengthEnabled := False;
271 InitialVolume := High(TEnvelopeVolume);
272 VolSweepDirection := Down;
273 VolSweepAmount := 0;
274
275 SweepTime := 0;
276 SweepIncDec := Down;
277 SweepShift := 0;
278
279 Duty := 2;
280
281 OutputLevel := 1;
282 end;
283
284 for I := Low(S.Instruments.WaveInstruments) to High(S.Instruments.WaveInstruments) do
285 with S.Instruments.WaveInstruments[I] do begin
286 Type_ := itWave;
287 Length := 0;
288 LengthEnabled := False;
289 InitialVolume := High(TEnvelopeVolume);
290 VolSweepDirection := Down;
291 VolSweepAmount := 0;
292
293 SweepTime := 0;
294 SweepIncDec := Down;
295 SweepShift := 0;
296
297 Duty := 2;
298
299 OutputLevel := 1;
300 end;
301
302 for I := Low(S.Instruments.NoiseInstruments) to High(S.Instruments.NoiseInstruments) do
303 with S.Instruments.NoiseInstruments[I] do begin
202 Type_ := itSquare; 304 Type_ := itSquare;
203 Length := 0; 305 Length := 0;
204 LengthEnabled := False; 306 LengthEnabled := False;
@@ -214,6 +316,7 @@ begin
214 316
215 OutputLevel := 1; 317 OutputLevel := 1;
216 end; 318 end;
319
217 for I := Low(S.Waves) to High(S.Waves) do begin 320 for I := Low(S.Waves) to High(S.Waves) do begin
218 for J := 0 to 32 do 321 for J := 0 to 32 do
219 S.Waves[I][J] := random($F); 322 S.Waves[I][J] := random($F);
Modifiedtracker.lfm +2−2
@@ -907,14 +907,14 @@ object frmTracker: TfrmTracker
907 end 907 end
908 object WavesTabSheet: TTabSheet 908 object WavesTabSheet: TTabSheet
909 Caption = 'Waves' 909 Caption = 'Waves'
910 ClientHeight = 412 910 ClientHeight = 414
911 ClientWidth = 960 911 ClientWidth = 960
912 ParentFont = False 912 ParentFont = False
913 object WaveEditPaintBox: TPaintBox 913 object WaveEditPaintBox: TPaintBox
914 AnchorSideTop.Control = WaveEditGroupBox 914 AnchorSideTop.Control = WaveEditGroupBox
915 AnchorSideTop.Side = asrBottom 915 AnchorSideTop.Side = asrBottom
916 Left = 0 916 Left = 0
917 Height = 252 917 Height = 254
918 Top = 160 918 Top = 160
919 Width = 960 919 Width = 960
920 Align = alBottom 920 Align = alBottom
Modifiedtracker.pas +2−0
@@ -1954,6 +1954,8 @@ procedure TfrmTracker.WaveEditPaintBoxMouseMove(Sender: TObject;
1954 var 1954 var
1955 Idx: Integer; 1955 Idx: Integer;
1956 begin 1956 begin
1957 X := EnsureRange(X, 0, WaveEditPaintBox.Width);
1958 Y := EnsureRange(Y, 0, WaveEditPaintBox.Height);
1957 if DrawingWave then begin 1959 if DrawingWave then begin
1958 Idx := Trunc((X / WaveEditPaintBox.Width)*32); 1960 Idx := Trunc((X / WaveEditPaintBox.Width)*32);
1959 CurrentWave^[Idx] := EnsureRange(Trunc((Y / WaveEditPaintBox.Height)*$F), 0, $F); 1961 CurrentWave^[Idx] := EnsureRange(Trunc((Y / WaveEditPaintBox.Height)*$F), 0, $F);