Merging three-instrument-banks
9 changed files
Diffed against the first of 2 parents.
+356−131
19e9eac@@ -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); |
@@ -56,6 +57,7 @@ var | |||
| 56 | SL, ResultSL: TStringList; |
57 | SL, ResultSL: TStringList; |
| 57 | AsmInstrument: TAsmInstrument; |
58 | AsmInstrument: TAsmInstrument; |
| 58 | I, J: Integer; |
59 | I, J: Integer; |
|
60 | TypePrefix: String; |
|
| 59 | begin |
61 | begin |
| 60 | ResultSL := TStringList.Create; |
62 | ResultSL := TStringList.Create; |
| 61 | |
63 | |
@@ -68,7 +70,8 @@ begin | |||
| 68 | for J := Low(AsmInstrument) to High(AsmInstrument) do |
70 | for J := Low(AsmInstrument) to High(AsmInstrument) do |
| 69 | SL.Add(IntToStr(AsmInstrument[J])); |
71 | SL.Add(IntToStr(AsmInstrument[J])); |
| 70 | |
72 | |
| 71 | ResultSL.Add(Format('%s: db %s', ['inst'+IntToStr(I), SL.DelimitedText])); |
73 | WriteStr(TypePrefix, Instruments[I].Type_); |
|
74 | ResultSL.Add(Format('%s%s: db %s', [TypePrefix, 'inst'+IntToStr(I), SL.DelimitedText])); |
|
| 72 | SL.Free; |
75 | SL.Free; |
| 73 | end; |
76 | end; |
| 74 | |
77 | |
@@ -206,9 +209,19 @@ begin | |||
| 206 | Write(OutFile, RenderOrderTable(Song.OrderMatrix)); |
209 | Write(OutFile, RenderOrderTable(Song.OrderMatrix)); |
| 207 | CloseFile(OutFile); |
210 | CloseFile(OutFile); |
| 208 | |
211 | |
| 209 | AssignFile(OutFile, './hUGEDriver/instrument.htt'); |
212 | AssignFile(OutFile, './hUGEDriver/duty_instrument.htt'); |
| 210 | Rewrite(OutFile); |
213 | Rewrite(OutFile); |
| 211 | Write(OutFile, RenderInstruments(Song.Instruments)); |
214 | Write(OutFile, RenderInstruments(Song.Instruments.Duty)); |
|
215 | CloseFile(OutFile); |
|
|
216 | |
|
|
217 | AssignFile(OutFile, './hUGEDriver/wave_instrument.htt'); |
|
|
218 | Rewrite(OutFile); |
|
|
219 | Write(OutFile, RenderInstruments(Song.Instruments.Wave)); |
|
|
220 | CloseFile(OutFile); |
|
|
221 | |
|
|
222 | AssignFile(OutFile, './hUGEDriver/noise_instrument.htt'); |
|
|
223 | Rewrite(OutFile); |
|
|
224 | Write(OutFile, RenderInstruments(Song.Instruments.Noise)); |
|
| 212 | CloseFile(OutFile); |
225 | CloseFile(OutFile); |
| 213 | |
226 | |
| 214 | WriteRoutinesToFile(Song.Routines); |
227 | WriteRoutinesToFile(Song.Routines); |
@@ -295,7 +308,7 @@ begin | |||
| 295 | mtError, |
308 | mtError, |
| 296 | [mbOK], |
309 | [mbOK], |
| 297 | 0) |
310 | 0) |
| 298 | else |
311 | else begin |
| 299 | MessageDlg( |
312 | MessageDlg( |
| 300 | 'Error!', |
313 | 'Error!', |
| 301 | 'There was an error assembling the song for playback.'+LineEnding+LineEnding+ |
314 | 'There was an error assembling the song for playback.'+LineEnding+LineEnding+ |
@@ -307,6 +320,9 @@ begin | |||
| 307 | [mbOK], |
320 | [mbOK], |
| 308 | 0); |
321 | 0); |
| 309 | |
322 | |
|
323 | {$ifdef PRODUCTION}OpenURL('https://github.com/SuperDisk/UGE/issues');{$endif} |
|
|
324 | end; |
|
|
325 | |
|
| 310 | Cleanup: |
326 | Cleanup: |
| 311 | Proc.Free; |
327 | Proc.Free; |
| 312 | OutSL.Free; |
328 | OutSL.Free; |
@@ -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; |
@@ -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: (Duty, Wave, Noise: 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 | |
@@ -33,7 +39,17 @@ type | |||
| 33 | TPattern = packed array[0..63] of TCell; |
39 | TPattern = packed array[0..63] of TCell; |
| 34 | PPattern = ^TPattern; |
40 | PPattern = ^TPattern; |
| 35 | |
41 | |
| 36 | TPatternMap = specialize TFPGMap<Integer, PPattern>; |
42 | //TPatternMap = specialize TFPGMap<Integer, PPattern>; |
|
43 | TPatternMap = class(specialize TFPGMap<Integer, PPattern>) |
|
|
44 | function GetOrCreateNew(Key: Integer): PPattern; |
|
|
45 | function CreateNewPattern(Key: Integer): PPattern; |
|
|
46 | function MaxKey: Integer; |
|
|
47 | |
|
|
48 | procedure DeletePattern(Key: Integer); |
|
|
49 | |
|
|
50 | destructor Destroy; override; |
|
|
51 | end; |
|
|
52 | |
|
| 37 | TOrderMatrix = packed array[0..3] of array of Integer; |
53 | TOrderMatrix = packed array[0..3] of array of Integer; |
| 38 | |
54 | |
| 39 | TCellPart = ( |
55 | TCellPart = ( |
@@ -68,6 +84,8 @@ procedure DecSelectionPos(var SP: TSelectionPos); | |||
| 68 | |
84 | |
| 69 | implementation |
85 | implementation |
| 70 | |
86 | |
|
87 | uses Utils; |
|
|
88 | |
|
| 71 | operator>(L, R: TSelectionPos): Boolean; |
89 | operator>(L, R: TSelectionPos): Boolean; |
| 72 | begin |
90 | begin |
| 73 | if L.X > R.X then |
91 | if L.X > R.X then |
@@ -121,5 +139,53 @@ begin | |||
| 121 | else Dec(SP.SelectedPart); |
139 | else Dec(SP.SelectedPart); |
| 122 | end; |
140 | end; |
| 123 | |
141 | |
|
142 | { TPatternMap } |
|
|
143 | |
|
|
144 | function TPatternMap.GetOrCreateNew(Key: Integer): PPattern; |
|
|
145 | begin |
|
|
146 | if Self.IndexOf(Key) <> -1 then |
|
|
147 | Result := Self.KeyData[Key] |
|
|
148 | else begin |
|
|
149 | New(Result); |
|
|
150 | BlankPattern(Result); |
|
|
151 | Self.Add(Key, Result); |
|
|
152 | end; |
|
|
153 | end; |
|
|
154 | |
|
|
155 | function TPatternMap.CreateNewPattern(Key: Integer): PPattern; |
|
|
156 | begin |
|
|
157 | if IndexOf(Key) <> -1 then Exit(KeyData[Key]); |
|
|
158 | |
|
|
159 | New(Result); |
|
|
160 | BlankPattern(Result); |
|
|
161 | Self.Add(Key, Result); |
|
|
162 | end; |
|
|
163 | |
|
|
164 | function TPatternMap.MaxKey: Integer; |
|
|
165 | var |
|
|
166 | X: Integer; |
|
|
167 | begin |
|
|
168 | Result := 0; |
|
|
169 | for X := 0 to Self.Count-1 do |
|
|
170 | if Self.Keys[X] > Result then Result := Self.Keys[X]; |
|
|
171 | Inc(Result); |
|
|
172 | end; |
|
|
173 | |
|
|
174 | procedure TPatternMap.DeletePattern(Key: Integer); |
|
|
175 | begin |
|
|
176 | Dispose(KeyData[Key]); |
|
|
177 | Self.Remove(Key); |
|
|
178 | end; |
|
|
179 | |
|
|
180 | destructor TPatternMap.Destroy; |
|
|
181 | var |
|
|
182 | I: Integer; |
|
|
183 | begin |
|
|
184 | for I := 0 to Self.Count-1 do |
|
|
185 | Dispose(Self.Data[I]); |
|
|
186 | |
|
|
187 | inherited; |
|
|
188 | end; |
|
|
189 | |
|
| 124 | end. |
190 | end. |
| 125 | |
191 | |
@@ -8,10 +8,10 @@ uses | |||
| 8 | Classes, SysUtils; |
8 | Classes, SysUtils; |
| 9 | |
9 | |
| 10 | type |
10 | type |
| 11 | TInstrumentType = (itSquare, itWave, itNoise); |
11 | TInstrumentType = (itSquare = 0, itWave = 1, itNoise = 2); |
| 12 | TDutyType = 0..3; |
12 | TDutyType = 0..3; |
| 13 | TSweepType = (Up, Down); |
13 | TSweepType = (Up, Down); |
| 14 | TStepWidth = (Fifteen, Seven); |
14 | TStepWidth = (swFifteen, swSeven); |
| 15 | TEnvelopeVolume = 0..15; |
15 | TEnvelopeVolume = 0..15; |
| 16 | TEnvelopeSweepAmount = 0..7; |
16 | TEnvelopeSweepAmount = 0..7; |
| 17 | |
17 | |
@@ -282,7 +282,7 @@ begin | |||
| 282 | NR43.ShiftClockFrequency := $F - (Frequency shr 7); // Quantize CH4 note |
282 | NR43.ShiftClockFrequency := $F - (Frequency shr 7); // Quantize CH4 note |
| 283 | |
283 | |
| 284 | NR43.DividingRatio:= Instr.DividingRatio; |
284 | NR43.DividingRatio:= Instr.DividingRatio; |
| 285 | NR43.SevenBitCounter:=Instr.CounterStep = Seven; |
285 | NR43.SevenBitCounter:=Instr.CounterStep = swSeven; |
| 286 | |
286 | |
| 287 | NR44.Initial:= Initial; |
287 | NR44.Initial:= Initial; |
| 288 | NR44.UseLength:=Instr.LengthEnabled; |
288 | NR44.UseLength:=Instr.LengthEnabled; |
@@ -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 |
@@ -196,13 +196,13 @@ begin | |||
| 196 | // Create the instruments. |
196 | // Create the instruments. |
| 197 | |
197 | |
| 198 | // First four are just the default instrument with a different duty cycle. |
198 | // First four are just the default instrument with a different duty cycle. |
| 199 | Result.Instruments[1].Duty := 1; |
199 | Result.Instruments.Duty[1].Duty := 1; |
| 200 | Result.Instruments[2].Duty := 2; |
200 | Result.Instruments.Duty[2].Duty := 2; |
| 201 | Result.Instruments[3].Duty := 3; |
201 | Result.Instruments.Duty[3].Duty := 3; |
| 202 | Result.Instruments[4].Duty := 0; |
202 | Result.Instruments.Duty[4].Duty := 0; |
| 203 | |
203 | |
| 204 | for I := 8 to 15 do |
204 | for I := 8 to 15 do |
| 205 | with Result.Instruments[I] do begin |
205 | with Result.Instruments.Wave[I] do begin |
| 206 | Waveform := I - 8; |
206 | Waveform := I - 8; |
| 207 | Type_ := itWave; |
207 | Type_ := itWave; |
| 208 | end; |
208 | end; |
@@ -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,9 +74,12 @@ 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 | |
|
81 | uses Utils; |
|
|
82 | |
|
| 58 | // Thanks to WP on the FreePascal forums for this code! |
83 | // Thanks to WP on the FreePascal forums for this code! |
| 59 | // https://forum.lazarus.freepascal.org/index.php/topic,47892.msg344152.html#msg344152 |
84 | // https://forum.lazarus.freepascal.org/index.php/topic,47892.msg344152.html#msg344152 |
| 60 | |
85 | |
@@ -67,8 +92,6 @@ begin | |||
| 67 | n := SizeOf(TSongV1) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix); |
92 | n := SizeOf(TSongV1) - SizeOf(TPatternMap) - SizeOf(TOrderMatrix); |
| 68 | S.Read(ASong, n); |
93 | S.Read(ASong, n); |
| 69 | |
94 | |
| 70 | // ASong.Patterns.Clear; |
|
|
| 71 | |
|
|
| 72 | // Create the patterns |
95 | // Create the patterns |
| 73 | ASong.Patterns := TPatternMap.Create; |
96 | ASong.Patterns := TPatternMap.Create; |
| 74 | // Read the pattern count |
97 | // Read the pattern count |
@@ -107,7 +130,46 @@ begin | |||
| 107 | |
130 | |
| 108 | S.Read(ASong, n); |
131 | S.Read(ASong, n); |
| 109 | |
132 | |
| 110 | // ASong.Patterns.Clear; |
133 | // Create the patterns |
|
134 | ASong.Patterns := TPatternMap.Create; |
|
|
135 | // Read the pattern count |
|
|
136 | S.Read(n, SizeOf(Integer)); |
|
|
137 | for i:=0 to n - 1 do begin |
|
|
138 | // Allocate memory for each pattern ... |
|
|
139 | New(pat); |
|
|
140 | // and read the pattern content |
|
|
141 | S.Read(pat^, SizeOf(TPattern)); |
|
|
142 | // Add the pattern to the list |
|
|
143 | ASong.Patterns.Add(i, pat); |
|
|
144 | end; |
|
|
145 | |
|
|
146 | // Read the OrderMatrix |
|
|
147 | for i := 0 to 3 do |
|
|
148 | begin |
|
|
149 | // Read length of each OrderMatrix array |
|
|
150 | S.Read(n, SizeOf(Integer)); |
|
|
151 | // Allocate memory for it |
|
|
152 | SetLength(ASong.OrderMatrix[i], n); |
|
|
153 | // Read content of OrderMatrix array |
|
|
154 | S.Read(ASong.OrderMatrix[i, 0], n*SizeOf(Integer)); |
|
|
155 | end; |
|
|
156 | |
|
|
157 | for I := Low(TRoutineBank) to High(TRoutineBank) do |
|
|
158 | ASong.Routines[I] := S.ReadAnsiString; |
|
|
159 | end; |
|
|
160 | |
|
|
161 | procedure ReadSongFromStreamV3(S: TStream; out ASong: TSongV3); |
|
|
162 | var |
|
|
163 | i, n: Integer; |
|
|
164 | pat: PPattern; |
|
|
165 | begin |
|
|
166 | // Read the fixed elements first |
|
|
167 | n := SizeOf(TSongV3) |
|
|
168 | - SizeOf(TPatternMap) |
|
|
169 | - SizeOf(TOrderMatrix) |
|
|
170 | - SizeOf(TRoutineBank); |
|
|
171 | |
|
|
172 | S.Read(ASong, n); |
|
| 111 | |
173 | |
| 112 | // Create the patterns |
174 | // Create the patterns |
| 113 | ASong.Patterns := TPatternMap.Create; |
175 | ASong.Patterns := TPatternMap.Create; |
@@ -143,7 +205,7 @@ var | |||
| 143 | pPat: PPattern; |
205 | pPat: PPattern; |
| 144 | begin |
206 | begin |
| 145 | // Write the fixed record elements first |
207 | // Write the fixed record elements first |
| 146 | n := SizeOf(TSongV2) |
208 | n := SizeOf(TSongV3) |
| 147 | - SizeOf(TPatternMap) |
209 | - SizeOf(TPatternMap) |
| 148 | - SizeOf(TOrderMatrix) |
210 | - SizeOf(TOrderMatrix) |
| 149 | - SizeOf(TRoutineBank); |
211 | - SizeOf(TRoutineBank); |
@@ -173,8 +235,9 @@ end; | |||
| 173 | |
235 | |
| 174 | procedure ReadSongFromStream(S: TStream; out ASong: TSong); |
236 | procedure ReadSongFromStream(S: TStream; out ASong: TSong); |
| 175 | var |
237 | var |
| 176 | Version: Integer = 1; |
238 | Version: Integer; |
| 177 | SV1: TSongV1; |
239 | SV1: TSongV1; |
|
240 | SV2: TSongV2; |
|
| 178 | begin |
241 | begin |
| 179 | S.Read(Version, SizeOf(Integer)); |
242 | S.Read(Version, SizeOf(Integer)); |
| 180 | S.Seek(0, soBeginning); |
243 | S.Seek(0, soBeginning); |
@@ -183,7 +246,11 @@ begin | |||
| 183 | ReadSongFromStreamV1(S, SV1); |
246 | ReadSongFromStreamV1(S, SV1); |
| 184 | ASong := UpgradeSong(SV1); |
247 | ASong := UpgradeSong(SV1); |
| 185 | end; |
248 | end; |
| 186 | 2: ReadSongFromStreamV2(S, ASong); |
249 | 2: begin |
|
250 | ReadSongFromStreamV2(S, SV2); |
|
|
251 | ASong := UpgradeSong(SV2); |
|
|
252 | end; |
|
|
253 | 3: ReadSongFromStreamV3(S, ASong); |
|
| 187 | end; |
254 | end; |
| 188 | end; |
255 | end; |
| 189 | |
256 | |
@@ -197,8 +264,9 @@ begin | |||
| 197 | Artist := ''; |
264 | Artist := ''; |
| 198 | Comment := ''; |
265 | Comment := ''; |
| 199 | end; |
266 | end; |
| 200 | for I := Low(S.Instruments) to High(S.Instruments) do |
267 | |
| 201 | with S.Instruments[I] do begin |
268 | for I := Low(S.Instruments.Duty) to High(S.Instruments.Duty) do |
|
269 | with S.Instruments.Duty[I] do begin |
|
| 202 | Type_ := itSquare; |
270 | Type_ := itSquare; |
| 203 | Length := 0; |
271 | Length := 0; |
| 204 | LengthEnabled := False; |
272 | LengthEnabled := False; |
@@ -214,6 +282,30 @@ begin | |||
| 214 | |
282 | |
| 215 | OutputLevel := 1; |
283 | OutputLevel := 1; |
| 216 | end; |
284 | end; |
|
285 | |
|
|
286 | for I := Low(S.Instruments.Wave) to High(S.Instruments.Wave) do |
|
|
287 | with S.Instruments.Wave[I] do begin |
|
|
288 | Type_ := itWave; |
|
|
289 | Length := 0; |
|
|
290 | LengthEnabled := False; |
|
|
291 | OutputLevel := 1; |
|
|
292 | Waveform := 0; |
|
|
293 | end; |
|
|
294 | |
|
|
295 | for I := Low(S.Instruments.Noise) to High(S.Instruments.Noise) do |
|
|
296 | with S.Instruments.Noise[I] do begin |
|
|
297 | Type_ := itNoise; |
|
|
298 | Length := 0; |
|
|
299 | LengthEnabled := False; |
|
|
300 | InitialVolume := High(TEnvelopeVolume); |
|
|
301 | VolSweepDirection := Down; |
|
|
302 | VolSweepAmount := 0; |
|
|
303 | |
|
|
304 | ShiftClockFreq := 0; |
|
|
305 | DividingRatio := 0; |
|
|
306 | CounterStep := swFifteen; |
|
|
307 | end; |
|
|
308 | |
|
| 217 | for I := Low(S.Waves) to High(S.Waves) do begin |
309 | for I := Low(S.Waves) to High(S.Waves) do begin |
| 218 | for J := 0 to 32 do |
310 | for J := 0 to 32 do |
| 219 | S.Waves[I][J] := random($F); |
311 | S.Waves[I][J] := random($F); |
@@ -253,6 +345,36 @@ begin | |||
| 253 | end; |
345 | end; |
| 254 | |
346 | |
| 255 | function UpgradeSong(S: TSongV2): TSong; |
347 | function UpgradeSong(S: TSongV2): TSong; |
|
348 | var |
|
|
349 | SV3: TSongV3; |
|
|
350 | I: Integer; |
|
|
351 | begin |
|
|
352 | InitializeSong(SV3); |
|
|
353 | SV3.Patterns.Free; // We already have one in S, so free the one InitializeSong creates. |
|
|
354 | |
|
|
355 | SV3.Version:=3; |
|
|
356 | SV3.Name:=S.Name; |
|
|
357 | SV3.Artist:=S.Artist; |
|
|
358 | SV3.Comment:=S.Comment; |
|
|
359 | |
|
|
360 | for I := Low(S.Instruments) to High(S.Instruments) do begin |
|
|
361 | case S.Instruments[I].Type_ of |
|
|
362 | itSquare: SV3.Instruments.Duty[I] := S.Instruments[I]; |
|
|
363 | itWave: SV3.Instruments.Wave[I] := S.Instruments[I]; |
|
|
364 | itNoise: SV3.Instruments.Noise[I] := S.Instruments[I]; |
|
|
365 | end; |
|
|
366 | end; |
|
|
367 | |
|
|
368 | SV3.Waves:=S.Waves; |
|
|
369 | SV3.TicksPerRow:=S.TicksPerRow; |
|
|
370 | SV3.Patterns:=S.Patterns; |
|
|
371 | SV3.OrderMatrix:=S.OrderMatrix; |
|
|
372 | SV3.Routines:=S.Routines; |
|
|
373 | |
|
|
374 | Result := UpgradeSong(SV3); |
|
|
375 | end; |
|
|
376 | |
|
|
377 | function UpgradeSong(S: TSongV3): TSong; |
|
| 256 | begin |
378 | begin |
| 257 | Result := S; |
379 | Result := S; |
| 258 | end; |
380 | end; |
@@ -1,7 +1,7 @@ | |||
| 1 | object frmTracker: TfrmTracker |
1 | object frmTracker: TfrmTracker |
| 2 | Left = 1860 |
2 | Left = 1888 |
| 3 | Height = 726 |
3 | Height = 726 |
| 4 | Top = 69 |
4 | Top = 59 |
| 5 | Width = 1180 |
5 | Width = 1180 |
| 6 | Caption = 'hUGETracker' |
6 | Caption = 'hUGETracker' |
| 7 | ClientHeight = 706 |
7 | ClientHeight = 706 |
@@ -60,7 +60,7 @@ object frmTracker: TfrmTracker | |||
| 60 | Height = 480 |
60 | Height = 480 |
| 61 | Top = 0 |
61 | Top = 0 |
| 62 | Width = 982 |
62 | Width = 982 |
| 63 | ActivePage = WavesTabSheet |
63 | ActivePage = InstrumentTabSheet |
| 64 | Align = alClient |
64 | Align = alClient |
| 65 | ParentFont = False |
65 | ParentFont = False |
| 66 | TabIndex = 3 |
66 | TabIndex = 3 |
@@ -911,8 +911,8 @@ object frmTracker: TfrmTracker | |||
| 911 | end |
911 | end |
| 912 | object WavesTabSheet: TTabSheet |
912 | object WavesTabSheet: TTabSheet |
| 913 | Caption = 'Waves' |
913 | Caption = 'Waves' |
| 914 | ClientHeight = 452 |
914 | ClientHeight = 414 |
| 915 | ClientWidth = 974 |
915 | ClientWidth = 960 |
| 916 | ParentFont = False |
916 | ParentFont = False |
| 917 | object WaveEditPaintBox: TPaintBox |
917 | object WaveEditPaintBox: TPaintBox |
| 918 | AnchorSideTop.Control = WaveEditGroupBox |
918 | AnchorSideTop.Control = WaveEditGroupBox |
@@ -361,6 +361,7 @@ type | |||
| 361 | Song: TSong; |
361 | Song: TSong; |
| 362 | CurrentInstrument: ^TInstrument; |
362 | CurrentInstrument: ^TInstrument; |
| 363 | CurrentWave: ^TWave; |
363 | CurrentWave: ^TWave; |
|
364 | CurrentInstrumentBank: TInstrumentType; |
|
| 364 | |
365 | |
| 365 | EmulationThread: TThread; |
366 | EmulationThread: TThread; |
| 366 | |
367 | |
@@ -370,7 +371,12 @@ type | |||
| 370 | LoadingFile: Boolean; |
371 | LoadingFile: Boolean; |
| 371 | SaveSucceeded: Boolean; |
372 | SaveSucceeded: Boolean; |
| 372 | |
373 | |
| 373 | {PatternsNode, }InstrumentsNode, WavesNode, RoutinesNode: TTreeNode; |
374 | {PatternsNode, } |
|
375 | WaveInstrumentsNode, |
|
|
376 | NoiseInstrumentsNode, |
|
|
377 | DutyInstrumentsNode, |
|
|
378 | WavesNode, |
|
|
379 | RoutinesNode: TTreeNode; |
|
| 374 | |
380 | |
| 375 | OptionsFile: TIniFile; |
381 | OptionsFile: TIniFile; |
| 376 | |
382 | |
@@ -379,7 +385,7 @@ type | |||
| 379 | procedure ChangeToSquare; |
385 | procedure ChangeToSquare; |
| 380 | procedure ChangeToWave; |
386 | procedure ChangeToWave; |
| 381 | procedure ChangeToNoise; |
387 | procedure ChangeToNoise; |
| 382 | procedure LoadInstrument(Instr: Integer); |
388 | procedure LoadInstrument(Bank: TInstrumentType; Instr: Integer); |
| 383 | procedure LoadWave(Wave: Integer); |
389 | procedure LoadWave(Wave: Integer); |
| 384 | procedure LoadSong(Filename: String); |
390 | procedure LoadSong(Filename: String); |
| 385 | procedure ReloadPatterns; |
391 | procedure ReloadPatterns; |
@@ -425,7 +431,7 @@ begin | |||
| 425 | ResetEmulationThread; |
431 | ResetEmulationThread; |
| 426 | |
432 | |
| 427 | LoadingFile := True; // HACK!!!!! |
433 | LoadingFile := True; // HACK!!!!! |
| 428 | LoadInstrument(1); |
434 | LoadInstrument(itSquare, 1); |
| 429 | LoadWave(0); |
435 | LoadWave(0); |
| 430 | |
436 | |
| 431 | RoutineSynedit.Text := Song.Routines[0]; |
437 | RoutineSynedit.Text := Song.Routines[0]; |
@@ -440,11 +446,22 @@ begin | |||
| 440 | RecreateTrackerGrid; |
446 | RecreateTrackerGrid; |
| 441 | CopyOrderMatrixToOrderGrid; |
447 | CopyOrderMatrixToOrderGrid; |
| 442 | |
448 | |
| 443 | for I := Low(Song.Instruments) to High(song.Instruments) do |
449 | // PLACEHOLDER |
| 444 | InstrumentComboBox.Items[I] := IntToStr(I)+': '+Song.Instruments[I].Name; |
450 | while InstrumentComboBox.Items.Count > 1 do |
| 445 | |
451 | InstrumentComboBox.Items.Delete(1); |
| 446 | for I := Low(Song.Instruments) to High(song.Instruments) do |
452 | |
| 447 | InstrumentsNode.Items[I-1].Text := IntToStr(I)+': '+Song.Instruments[I].Name; |
453 | for I := Low(Song.Instruments.Duty) to High(song.Instruments.Duty) do |
|
454 | InstrumentComboBox.Items.Add('Square '+IntToStr(I)+': '+Song.Instruments.Duty[ModInst(I)].Name); |
|
|
455 | for I := Low(Song.Instruments.Wave) to High(song.Instruments.Wave) do |
|
|
456 | InstrumentComboBox.Items.Add('Wave '+IntToStr(I)+': '+Song.Instruments.Wave[ModInst(I)].Name); |
|
|
457 | for I := Low(Song.Instruments.Noise) to High(song.Instruments.Noise) do |
|
|
458 | InstrumentComboBox.Items.Add('Noise '+IntToStr(I)+': '+Song.Instruments.Noise[ModInst(I)].Name); |
|
|
459 | |
|
|
460 | for I := Low(TInstrumentBank) to High(TInstrumentBank) do begin |
|
|
461 | DutyInstrumentsNode.Items[I-1].Text := IntToStr(I)+': '+Song.Instruments.Duty[I].Name; |
|
|
462 | WaveInstrumentsNode.Items[I-1].Text := IntToStr(I)+': '+Song.Instruments.Wave[I].Name; |
|
|
463 | NoiseInstrumentsNode.Items[I-1].Text := IntToStr(I)+': '+Song.Instruments.Noise[I].Name; |
|
|
464 | end; |
|
| 448 | |
465 | |
| 449 | LoadingFile := False; // HACK!!!! |
466 | LoadingFile := False; // HACK!!!! |
| 450 | |
467 | |
@@ -566,11 +583,11 @@ begin | |||
| 566 | // TODO: Find some way to synchronize with the playback thread, so it doesn't |
583 | // TODO: Find some way to synchronize with the playback thread, so it doesn't |
| 567 | // fail sometimes. |
584 | // fail sometimes. |
| 568 | |
585 | |
| 569 | with Song.Instruments[Instr] do |
586 | with Song.Instruments.All[Instr] do //PLACEHOLDER |
| 570 | begin |
587 | begin |
| 571 | case Type_ of |
588 | case Type_ of |
| 572 | itSquare: begin |
589 | itSquare: begin |
| 573 | Regs := SquareInstrumentToRegisters(Freq, True, Song.Instruments[Instr]); |
590 | Regs := SquareInstrumentToRegisters(Freq, True, Song.Instruments.All[Instr]); |
| 574 | Spokeb(NR10, Regs.NR10); |
591 | Spokeb(NR10, Regs.NR10); |
| 575 | Spokeb(NR11, Regs.NR11); |
592 | Spokeb(NR11, Regs.NR11); |
| 576 | Spokeb(NR12, Regs.NR12); |
593 | Spokeb(NR12, Regs.NR12); |
@@ -583,7 +600,7 @@ begin | |||
| 583 | for I := Low(NewWaveform) to High(NewWaveform) do |
600 | for I := Low(NewWaveform) to High(NewWaveform) do |
| 584 | Spokeb(AUD3_WAVE_RAM+I, NewWaveform[I]); |
601 | Spokeb(AUD3_WAVE_RAM+I, NewWaveform[I]); |
| 585 | |
602 | |
| 586 | Regs := WaveInstrumentToRegisters(Freq, True, Song.Instruments[Instr]); |
603 | Regs := WaveInstrumentToRegisters(Freq, True, Song.Instruments.All[Instr]); |
| 587 | |
604 | |
| 588 | Spokeb(NR30, Regs.NR30); |
605 | Spokeb(NR30, Regs.NR30); |
| 589 | Spokeb(NR31, Regs.NR31); |
606 | Spokeb(NR31, Regs.NR31); |
@@ -592,7 +609,7 @@ begin | |||
| 592 | Spokeb(NR34, Regs.NR34) |
609 | Spokeb(NR34, Regs.NR34) |
| 593 | end; |
610 | end; |
| 594 | itNoise: begin |
611 | itNoise: begin |
| 595 | Regs := NoiseInstrumentToRegisters(Freq, True, Song.Instruments[Instr]); |
612 | Regs := NoiseInstrumentToRegisters(Freq, True, Song.Instruments.All[Instr]); |
| 596 | Spokeb(NR41, Regs.NR41); |
613 | Spokeb(NR41, Regs.NR41); |
| 597 | Spokeb(NR42, Regs.NR42); |
614 | Spokeb(NR42, Regs.NR42); |
| 598 | Spokeb(NR43, Regs.NR43); |
615 | Spokeb(NR43, Regs.NR43); |
@@ -605,7 +622,7 @@ end; | |||
| 605 | procedure TfrmTracker.PreviewC5; |
622 | procedure TfrmTracker.PreviewC5; |
| 606 | begin |
623 | begin |
| 607 | if not LoadingFile then begin |
624 | if not LoadingFile then begin |
| 608 | PreviewInstrument(NotesToFreqs.Data[C_5], InstrumentNumberSpinner.Value); |
625 | PreviewInstrument(NotesToFreqs.Data[C_5], UnmodInst(CurrentInstrumentBank, InstrumentNumberSpinner.Value)); |
| 609 | NoteHaltTimer.Enabled := False; |
626 | NoteHaltTimer.Enabled := False; |
| 610 | NoteHaltTimer.Enabled := True |
627 | NoteHaltTimer.Enabled := True |
| 611 | end; |
628 | end; |
@@ -808,13 +825,19 @@ begin | |||
| 808 | TrackerGrid.PopupMenu := TrackerGridPopup; |
825 | TrackerGrid.PopupMenu := TrackerGridPopup; |
| 809 | end; |
826 | end; |
| 810 | |
827 | |
| 811 | procedure TfrmTracker.LoadInstrument(Instr: Integer); |
828 | procedure TfrmTracker.LoadInstrument(Bank: TInstrumentType; Instr: Integer); |
| 812 | var |
829 | var |
| 813 | CI: ^TInstrument; |
830 | CI: ^TInstrument; |
| 814 | begin |
831 | begin |
| 815 | CurrentInstrument := @Song.Instruments[Instr]; |
832 | CurrentInstrumentBank := Bank; |
|
833 | case Bank of |
|
|
834 | itSquare: CurrentInstrument := @Song.Instruments.Duty[Instr]; |
|
|
835 | itWave: CurrentInstrument := @Song.Instruments.Wave[Instr]; |
|
|
836 | itNoise: CurrentInstrument := @Song.Instruments.Noise[Instr]; |
|
|
837 | end; |
|
| 816 | CI := CurrentInstrument; |
838 | CI := CurrentInstrument; |
| 817 | |
839 | |
|
840 | InstrumentTypeComboBox.ItemIndex := Integer(CurrentInstrumentBank); |
|
| 818 | InstrumentNumberSpinner.Value := Instr; |
841 | InstrumentNumberSpinner.Value := Instr; |
| 819 | InstrumentNameEdit.Text := CI^.Name; |
842 | InstrumentNameEdit.Text := CI^.Name; |
| 820 | LengthEnabledCheckbox.Checked := CI^.LengthEnabled; |
843 | LengthEnabledCheckbox.Checked := CI^.LengthEnabled; |
@@ -861,7 +884,7 @@ begin | |||
| 861 | itNoise: begin |
884 | itNoise: begin |
| 862 | ShiftClockTrackbar.Position := CI^.ShiftClockFreq; |
885 | ShiftClockTrackbar.Position := CI^.ShiftClockFreq; |
| 863 | DivRatioTrackbar.Position := CI^.DividingRatio; |
886 | DivRatioTrackbar.Position := CI^.DividingRatio; |
| 864 | SevenBitCounterCheckbox.Checked := CI^.CounterStep = Seven; |
887 | SevenBitCounterCheckbox.Checked := CI^.CounterStep = swSeven; |
| 865 | end; |
888 | end; |
| 866 | end; |
889 | end; |
| 867 | |
890 | |
@@ -932,9 +955,9 @@ end; | |||
| 932 | procedure TfrmTracker.SevenBitCounterCheckboxChange(Sender: TObject); |
955 | procedure TfrmTracker.SevenBitCounterCheckboxChange(Sender: TObject); |
| 933 | begin |
956 | begin |
| 934 | if SevenBitCounterCheckbox.Checked then |
957 | if SevenBitCounterCheckbox.Checked then |
| 935 | CurrentInstrument^.CounterStep := Seven |
958 | CurrentInstrument^.CounterStep := swSeven |
| 936 | else |
959 | else |
| 937 | CurrentInstrument^.CounterStep := Fifteen; |
960 | CurrentInstrument^.CounterStep := swFifteen; |
| 938 | end; |
961 | end; |
| 939 | |
962 | |
| 940 | procedure TfrmTracker.SongEditChange(Sender: TObject); |
963 | procedure TfrmTracker.SongEditChange(Sender: TObject); |
@@ -973,20 +996,12 @@ end; | |||
| 973 | |
996 | |
| 974 | procedure TfrmTracker.InstrumentTypeComboboxChange(Sender: TObject); |
997 | procedure TfrmTracker.InstrumentTypeComboboxChange(Sender: TObject); |
| 975 | begin |
998 | begin |
| 976 | case InstrumentTypeComboBox.Text of |
999 | case InstrumentTypeCombobox.ItemIndex of |
| 977 | 'Square': begin |
1000 | 0: CurrentInstrumentBank := itSquare; |
| 978 | CurrentInstrument^.Type_ := itSquare; |
1001 | 1: CurrentInstrumentBank := itWave; |
| 979 | ChangeToSquare |
1002 | 2: CurrentInstrumentBank := itNoise; |
| 980 | end; |
|
|
| 981 | 'Wave': begin |
|
|
| 982 | CurrentInstrument^.Type_ := itWave; |
|
|
| 983 | ChangeToWave |
|
|
| 984 | end; |
|
|
| 985 | 'Noise': begin |
|
|
| 986 | CurrentInstrument^.Type_ := itNoise; |
|
|
| 987 | ChangeToNoise |
|
|
| 988 | end; |
|
|
| 989 | end; |
1003 | end; |
|
1004 | LoadInstrument(CurrentInstrumentBank, InstrumentNumberSpinner.Value); |
|
| 990 | end; |
1005 | end; |
| 991 | |
1006 | |
| 992 | procedure TfrmTracker.RandomizeNoiseButtonClick(Sender: TObject); |
1007 | procedure TfrmTracker.RandomizeNoiseButtonClick(Sender: TObject); |
@@ -998,7 +1013,7 @@ begin | |||
| 998 | LengthTrackbar.Position := Random(Round(LengthTrackbar.Max)); |
1013 | LengthTrackbar.Position := Random(Round(LengthTrackbar.Max)); |
| 999 | |
1014 | |
| 1000 | PreviewInstrument(NotesToFreqs.KeyData[RandomRange(LOWEST_NOTE, HIGHEST_NOTE)], |
1015 | PreviewInstrument(NotesToFreqs.KeyData[RandomRange(LOWEST_NOTE, HIGHEST_NOTE)], |
| 1001 | InstrumentNumberSpinner.Value); |
1016 | UnmodInst(CurrentInstrumentBank, InstrumentNumberSpinner.Value)); |
| 1002 | end; |
1017 | end; |
| 1003 | |
1018 | |
| 1004 | procedure TfrmTracker.FormCreate(Sender: TObject); |
1019 | procedure TfrmTracker.FormCreate(Sender: TObject); |
@@ -1040,31 +1055,33 @@ begin | |||
| 1040 | // Initialize ticks per row |
1055 | // Initialize ticks per row |
| 1041 | Song.TicksPerRow := TicksPerRowSpinEdit.Value; |
1056 | Song.TicksPerRow := TicksPerRowSpinEdit.Value; |
| 1042 | |
1057 | |
| 1043 | LoadInstrument(1); |
1058 | LoadInstrument(itSquare, 1); |
| 1044 | LoadWave(0); |
1059 | LoadWave(0); |
| 1045 | |
1060 | |
| 1046 | // Fetch the tree items |
1061 | // Fetch the tree items |
| 1047 | with TreeView1 do begin |
1062 | with TreeView1 do begin |
| 1048 | //PatternsNode := Items[0]; |
1063 | //PatternsNode := Items[0]; |
| 1049 | InstrumentsNode := Items[0]; |
1064 | DutyInstrumentsNode := Items[0].Items[0]; |
| 1050 | WavesNode := Items[1]; |
1065 | WaveInstrumentsNode := Items[0].Items[1]; |
| 1051 | RoutinesNode := Items[2]; |
1066 | NoiseInstrumentsNode := Items[0].Items[2]; |
|
1067 | |
|
|
1068 | // TODO: Find out how to actually do this... WTF? |
|
|
1069 | WavesNode := Items[4]; |
|
|
1070 | RoutinesNode := Items[5]; |
|
| 1052 | end; |
1071 | end; |
| 1053 | |
1072 | |
| 1054 | for PUI := 1 to 15 do |
1073 | for PUI := 1 to 15 do begin |
| 1055 | TreeView1.Items.AddChild(InstrumentsNode, IntToStr(PUI)+':').Data := {%H-}Pointer(PUI); |
1074 | TreeView1.Items.AddChild(DutyInstrumentsNode, IntToStr(PUI)+':').Data := {%H-}Pointer(PUI); |
|
1075 | TreeView1.Items.AddChild(WaveInstrumentsNode, IntToStr(PUI)+':').Data := {%H-}Pointer(PUI); |
|
|
1076 | TreeView1.Items.AddChild(NoiseInstrumentsNode, IntToStr(PUI)+':').Data := {%H-}Pointer(PUI); |
|
|
1077 | end; |
|
| 1056 | |
1078 | |
| 1057 | for PUI := 0 to 15 do begin |
1079 | for PUI := 0 to 15 do begin |
| 1058 | TreeView1.Items.AddChild(WavesNode, 'Wave '+IntToStr(PUI)).Data := {%H-}Pointer(PUI); |
1080 | TreeView1.Items.AddChild(WavesNode, 'Wave '+IntToStr(PUI)).Data := {%H-}Pointer(PUI); |
| 1059 | TreeView1.Items.AddChild(RoutinesNode, 'Routine '+IntToStr(PUI)).Data := {%H-}Pointer(PUI); |
1081 | TreeView1.Items.AddChild(RoutinesNode, 'Routine '+IntToStr(PUI)).Data := {%H-}Pointer(PUI); |
| 1060 | end; |
1082 | end; |
| 1061 | |
1083 | |
| 1062 | // Initialize order table |
1084 | // Initialize order table (InitializeSong creates the default order table) |
| 1063 | {for I := 0 to 3 do begin |
|
|
| 1064 | OrderEditStringGrid.Cells[I+1, 1] := IntToStr(I); |
|
|
| 1065 | TrackerGrid.LoadPattern(I, I); |
|
|
| 1066 | end;} |
|
|
| 1067 | //CopyOrderGridToOrderMatrix; |
|
|
| 1068 | CopyOrderMatrixToOrderGrid; |
1085 | CopyOrderMatrixToOrderGrid; |
| 1069 | |
1086 | |
| 1070 | // Manually resize the fixed column in the order editor |
1087 | // Manually resize the fixed column in the order editor |
@@ -1306,7 +1323,7 @@ end; | |||
| 1306 | |
1323 | |
| 1307 | procedure TfrmTracker.InstrumentComboBoxChange(Sender: TObject); |
1324 | procedure TfrmTracker.InstrumentComboBoxChange(Sender: TObject); |
| 1308 | begin |
1325 | begin |
| 1309 | TrackerGrid.SelectedInstrument := InstrumentComboBox.ItemIndex; |
1326 | TrackerGrid.SelectedInstrument := ModInst(InstrumentComboBox.ItemIndex); |
| 1310 | end; |
1327 | end; |
| 1311 | |
1328 | |
| 1312 | procedure TfrmTracker.EditDelete1Execute(Sender: TObject); |
1329 | procedure TfrmTracker.EditDelete1Execute(Sender: TObject); |
@@ -1456,17 +1473,30 @@ begin | |||
| 1456 | end; |
1473 | end; |
| 1457 | |
1474 | |
| 1458 | procedure TfrmTracker.InstrumentNameEditChange(Sender: TObject); |
1475 | procedure TfrmTracker.InstrumentNameEditChange(Sender: TObject); |
|
1476 | var |
|
|
1477 | S: String; |
|
| 1459 | begin |
1478 | begin |
|
1479 | S := IntToStr(InstrumentNumberSpinner.Value) + ': ' + InstrumentNameEdit.Text; |
|
| 1460 | CurrentInstrument^.Name := InstrumentNameEdit.Text; |
1480 | CurrentInstrument^.Name := InstrumentNameEdit.Text; |
| 1461 | InstrumentComboBox.Items[InstrumentNumberSpinner.Value] := |
1481 | case CurrentInstrumentBank of |
| 1462 | IntToStr(InstrumentNumberSpinner.Value) + ': ' + InstrumentNameEdit.Text; |
1482 | itSquare: begin |
| 1463 | InstrumentsNode.Items[InstrumentNumberSpinner.Value-1].Text := |
1483 | InstrumentComboBox.Items[(0*15) + InstrumentNumberSpinner.Value] := 'Square '+S; |
| 1464 | InstrumentComboBox.Items[InstrumentNumberSpinner.Value]; |
1484 | DutyInstrumentsNode.Items[InstrumentNumberSpinner.Value-1].Text := S; |
|
1485 | end; |
|
|
1486 | itWave: begin |
|
|
1487 | InstrumentComboBox.Items[(1*15) + InstrumentNumberSpinner.Value] := 'Wave '+S; |
|
|
1488 | WaveInstrumentsNode.Items[InstrumentNumberSpinner.Value-1].Text := S; |
|
|
1489 | end; |
|
|
1490 | itNoise: begin |
|
|
1491 | InstrumentComboBox.Items[(2*15) + InstrumentNumberSpinner.Value] := 'Noise '+S; |
|
|
1492 | NoiseInstrumentsNode.Items[InstrumentNumberSpinner.Value-1].Text := S; |
|
|
1493 | end; |
|
|
1494 | end; |
|
| 1465 | end; |
1495 | end; |
| 1466 | |
1496 | |
| 1467 | procedure TfrmTracker.InstrumentNumberSpinnerChange(Sender: TObject); |
1497 | procedure TfrmTracker.InstrumentNumberSpinnerChange(Sender: TObject); |
| 1468 | begin |
1498 | begin |
| 1469 | LoadInstrument(InstrumentNumberSpinner.Value); |
1499 | LoadInstrument(CurrentInstrumentBank, InstrumentNumberSpinner.Value); |
| 1470 | end; |
1500 | end; |
| 1471 | |
1501 | |
| 1472 | procedure TfrmTracker.LengthSpinnerChange(Sender: TObject); |
1502 | procedure TfrmTracker.LengthSpinnerChange(Sender: TObject); |
@@ -1971,8 +2001,18 @@ end; | |||
| 1971 | |
2001 | |
| 1972 | procedure TfrmTracker.TreeView1DblClick(Sender: TObject); |
2002 | procedure TfrmTracker.TreeView1DblClick(Sender: TObject); |
| 1973 | begin |
2003 | begin |
| 1974 | if TreeView1.Selected.Parent = InstrumentsNode then begin |
2004 | if TreeView1.Selected.Parent = DutyInstrumentsNode then begin |
| 1975 | InstrumentNumberSpinner.Value := {%H-}PtrUInt(TreeView1.Selected.Data); |
2005 | LoadInstrument(itSquare, {%H-}PtrUInt(TreeView1.Selected.Data)); |
|
2006 | PageControl1.ActivePage := InstrumentTabSheet; |
|
|
2007 | end; |
|
|
2008 | |
|
|
2009 | if TreeView1.Selected.Parent = WaveInstrumentsNode then begin |
|
|
2010 | LoadInstrument(itWave, {%H-}PtrUInt(TreeView1.Selected.Data)); |
|
|
2011 | PageControl1.ActivePage := InstrumentTabSheet; |
|
|
2012 | end; |
|
|
2013 | |
|
|
2014 | if TreeView1.Selected.Parent = NoiseInstrumentsNode then begin |
|
|
2015 | LoadInstrument(itNoise, {%H-}PtrUInt(TreeView1.Selected.Data)); |
|
| 1976 | PageControl1.ActivePage := InstrumentTabSheet; |
2016 | PageControl1.ActivePage := InstrumentTabSheet; |
| 1977 | end; |
2017 | end; |
| 1978 | |
2018 | |
@@ -2003,6 +2043,8 @@ procedure TfrmTracker.WaveEditPaintBoxMouseMove(Sender: TObject; | |||
| 2003 | var |
2043 | var |
| 2004 | Idx: Integer; |
2044 | Idx: Integer; |
| 2005 | begin |
2045 | begin |
|
2046 | X := EnsureRange(X, 0, WaveEditPaintBox.Width); |
|
|
2047 | Y := EnsureRange(Y, 0, WaveEditPaintBox.Height); |
|
| 2006 | if DrawingWave then begin |
2048 | if DrawingWave then begin |
| 2007 | Idx := EnsureRange(Trunc((X / WaveEditPaintBox.Width)*High(TWave)), Low(TWave), High(TWave)); |
2049 | Idx := EnsureRange(Trunc((X / WaveEditPaintBox.Width)*High(TWave)), Low(TWave), High(TWave)); |
| 2008 | CurrentWave^[Idx] := EnsureRange(Trunc((Y / WaveEditPaintBox.Height)*$F), 0, $F); |
2050 | CurrentWave^[Idx] := EnsureRange(Trunc((Y / WaveEditPaintBox.Height)*$F), 0, $F); |
@@ -5,7 +5,7 @@ unit Utils; | |||
| 5 | interface |
5 | interface |
| 6 | |
6 | |
| 7 | uses |
7 | uses |
| 8 | Classes, SysUtils, Song, Waves, HugeDatatypes, Constants, gHashSet; |
8 | Classes, SysUtils, Song, Waves, HugeDatatypes, Constants, gHashSet, fgl, instruments; |
| 9 | |
9 | |
| 10 | type |
10 | type |
| 11 | |
11 | |
@@ -17,16 +17,6 @@ type | |||
| 17 | |
17 | |
| 18 | TUsedMap = specialize THashSet<Integer, TIntegerHash>; |
18 | TUsedMap = specialize THashSet<Integer, TIntegerHash>; |
| 19 | |
19 | |
| 20 | { TOrderMapHelper } |
|
|
| 21 | |
|
|
| 22 | TOrderMapHelper = class helper for TPatternMap |
|
|
| 23 | function GetOrCreateNew(Key: Integer): PPattern; |
|
|
| 24 | function CreateNewPattern(Key: Integer): PPattern; |
|
|
| 25 | function MaxKey: Integer; |
|
|
| 26 | |
|
|
| 27 | procedure DeletePattern(Key: Integer); |
|
|
| 28 | end; |
|
|
| 29 | |
|
|
| 30 | { TSongUsageReport } |
20 | { TSongUsageReport } |
| 31 | |
21 | |
| 32 | TSongUsageReport = record |
22 | TSongUsageReport = record |
@@ -46,6 +36,10 @@ procedure BlankCell(var Cell: TCell); | |||
| 46 | function EffectCodeToStr(Code: Integer; Params: TEffectParams): String; |
36 | function EffectCodeToStr(Code: Integer; Params: TEffectParams): String; |
| 47 | function EffectToExplanation(Code: Integer; Params: TEffectParams): String; |
37 | function EffectToExplanation(Code: Integer; Params: TEffectParams): String; |
| 48 | |
38 | |
|
39 | function ModInst(Inst: Integer): Integer; |
|
|
40 | function UnmodInst(Bank: TInstrumentType; Inst: Integer): Integer; |
|
|
41 | function InstBankName(Bank: TInstrumentType): String; |
|
|
42 | |
|
| 49 | function GetUsageReport(Song: TSong): TSongUsageReport; |
43 | function GetUsageReport(Song: TSong): TSongUsageReport; |
| 50 | procedure FreeUsageReport(Report: TSongUsageReport); |
44 | procedure FreeUsageReport(Report: TSongUsageReport); |
| 51 | |
45 | |
@@ -58,44 +52,6 @@ begin | |||
| 58 | Result := I mod N; |
52 | Result := I mod N; |
| 59 | end; |
53 | end; |
| 60 | |
54 | |
| 61 | { TOrderMapHelper } |
|
|
| 62 | |
|
|
| 63 | function TOrderMapHelper.GetOrCreateNew(Key: Integer): PPattern; |
|
|
| 64 | begin |
|
|
| 65 | if Self.IndexOf(Key) <> -1 then |
|
|
| 66 | Result := Self.KeyData[Key] |
|
|
| 67 | else begin |
|
|
| 68 | New(Result); |
|
|
| 69 | BlankPattern(Result); |
|
|
| 70 | Self.Add(Key, Result); |
|
|
| 71 | end; |
|
|
| 72 | end; |
|
|
| 73 | |
|
|
| 74 | function TOrderMapHelper.CreateNewPattern(Key: Integer): PPattern; |
|
|
| 75 | begin |
|
|
| 76 | if IndexOf(Key) <> -1 then Exit(KeyData[Key]); |
|
|
| 77 | |
|
|
| 78 | New(Result); |
|
|
| 79 | BlankPattern(Result); |
|
|
| 80 | Self.Add(Key, Result); |
|
|
| 81 | end; |
|
|
| 82 | |
|
|
| 83 | function TOrderMapHelper.MaxKey: Integer; |
|
|
| 84 | var |
|
|
| 85 | X: Integer; |
|
|
| 86 | begin |
|
|
| 87 | Result := 0; |
|
|
| 88 | for X := 0 to Self.Count-1 do |
|
|
| 89 | if Self.Keys[X] > Result then Result := Self.Keys[X]; |
|
|
| 90 | Inc(Result); |
|
|
| 91 | end; |
|
|
| 92 | |
|
|
| 93 | procedure TOrderMapHelper.DeletePattern(Key: Integer); |
|
|
| 94 | begin |
|
|
| 95 | Dispose(KeyData[Key]); |
|
|
| 96 | Self.Remove(Key); |
|
|
| 97 | end; |
|
|
| 98 | |
|
|
| 99 | function Lerp(v0, v1, t: Double): Double; |
55 | function Lerp(v0, v1, t: Double): Double; |
| 100 | begin |
56 | begin |
| 101 | Result := ((1 - t) * v0) + (t * v1); |
57 | Result := ((1 - t) * v0) + (t * v1); |
@@ -156,6 +112,29 @@ begin | |||
| 156 | end; |
112 | end; |
| 157 | end; |
113 | end; |
| 158 | |
114 | |
|
115 | function ModInst(Inst: Integer): Integer; |
|
|
116 | begin |
|
|
117 | Result := ((Inst-1) mod 15)+1; |
|
|
118 | end; |
|
|
119 | |
|
|
120 | function UnmodInst(Bank: TInstrumentType; Inst: Integer): Integer; |
|
|
121 | begin |
|
|
122 | case Bank of |
|
|
123 | itSquare: Result := Inst+(15*0); |
|
|
124 | itWave: Result := Inst+(15*1); |
|
|
125 | itNoise: Result := Inst+(15*2); |
|
|
126 | end; |
|
|
127 | end; |
|
|
128 | |
|
|
129 | function InstBankName(Bank: TInstrumentType): String; |
|
|
130 | begin |
|
|
131 | case Bank of |
|
|
132 | itSquare: Result := 'Square'; |
|
|
133 | itWave: Result := 'Wave'; |
|
|
134 | itNoise: Result := 'Noise'; |
|
|
135 | end; |
|
|
136 | end; |
|
|
137 | |
|
| 159 | function GetUsageReport(Song: TSong): TSongUsageReport; |
138 | function GetUsageReport(Song: TSong): TSongUsageReport; |
| 160 | var |
139 | var |
| 161 | I, J, X, Y: Integer; |
140 | I, J, X, Y: Integer; |