Commit 2bb96a7

Nick committed on
Add asm export
commit 2bb96a7a297f007df8b7d5eabfdfafdb7b9b2943 parent f0b36e6
4 changed files +265−227
Modifiedcodegen.pas +243−214
@@ -13,20 +13,13 @@ type
13 TExportMode = (emNormal, emPreview, emGBS); 13 TExportMode = (emNormal, emPreview, emGBS);
14 14
15 function RenderPreviewRom(Song: TSong): boolean; 15 function RenderPreviewRom(Song: TSong): boolean;
16 function RenderSongToFile(Song: TSong; Filename: string; 16 function RenderSongToFile(Song: TSong; Filename: string; Mode: TExportMode = emNormal): boolean;
17 Mode: TExportMode = emNormal; DescriptorName: String = 'song_descriptor'): boolean;
18 procedure RenderSongToGBDKC(Song: TSong; DescriptorName: String; Filename: string); 17 procedure RenderSongToGBDKC(Song: TSong; DescriptorName: String; Filename: string);
18 procedure RenderSongToRGBDSAsm(Song: TSong; DescriptorName: String; Filename: string);
19 19
20 implementation 20 implementation
21 21
22 procedure RenderSongToGBDKC(Song: TSong; DescriptorName: String; Filename: string); 22 procedure RenderSongToGBDKC(Song: TSong; DescriptorName: String; Filename: string);
23 var
24 OrderMatrix: TOrderMatrix;
25 OutSL: TStringList;
26 OrderCnt: integer;
27 I: integer;
28 F: Text;
29
30 function RenderGBDKCell(Cell: TCell): string; 23 function RenderGBDKCell(Cell: TCell): string;
31 var 24 var
32 SL: TStringList; 25 SL: TStringList;
@@ -142,6 +135,12 @@ var
142 Result += '};'; 135 Result += '};';
143 end; 136 end;
144 137
138 var
139 OrderMatrix: TOrderMatrix;
140 OutSL: TStringList;
141 OrderCnt: integer;
142 I: integer;
143 F: Text;
145 begin 144 begin
146 Song := OptimizeSong(Song); 145 Song := OptimizeSong(Song);
147 146
@@ -192,220 +191,218 @@ begin
192 OutSL.Free; 191 OutSL.Free;
193 end; 192 end;
194 193
195 procedure RenderSongToHTTs(Song: TSong; DescriptorName: String; Filename: string); 194 function RenderOrderTable(OrderMatrix: TOrderMatrix): string;
196 function RenderOrderTable(OrderMatrix: TOrderMatrix): string; 195 function ArrayHelper(Ints: array of integer): string;
197
198 function ArrayHelper(Ints: array of integer): string;
199 var
200 I: integer;
201 SL: TStringList;
202 begin
203 SL := TStringList.Create;
204 SL.StrictDelimiter := True;
205 SL.Delimiter := ',';
206 for I := Low(Ints) to High(Ints)-1 do // HACK: account for the off-by-one error
207 SL.Add('P' + IntToStr(Ints[I]));
208 Result := SL.DelimitedText;
209 SL.Free;
210 end;
211
212 var 196 var
213 Res: TStringList; 197 I: integer;
214 OrderCnt: integer; 198 SL: TStringList;
215 begin 199 begin
216 Res := TStringList.Create; 200 SL := TStringList.Create;
217 OrderCnt := MaxIntValue([High(OrderMatrix[0]), High(OrderMatrix[1]), 201 SL.StrictDelimiter := True;
218 High(OrderMatrix[2]), High(OrderMatrix[3])]); 202 SL.Delimiter := ',';
219 203 for I := Low(Ints) to High(Ints)-1 do // HACK: account for the off-by-one error
220 Res.Add('order_cnt: db ' + IntToStr(OrderCnt * 2)); 204 SL.Add('P' + IntToStr(Ints[I]));
221 Res.Add('order1: dw ' + ArrayHelper(OrderMatrix[0])); 205 Result := SL.DelimitedText;
222 Res.Add('order2: dw ' + ArrayHelper(OrderMatrix[1])); 206 SL.Free;
223 Res.Add('order3: dw ' + ArrayHelper(OrderMatrix[2]));
224 Res.Add('order4: dw ' + ArrayHelper(OrderMatrix[3]));
225
226 Result := Res.Text;
227 Res.Free;
228 end; 207 end;
229 208
230 function RenderInstruments(Instruments: TInstrumentBank): string; 209 var
231 var 210 Res: TStringList;
232 SL, ResultSL: TStringList; 211 OrderCnt: integer;
233 AsmInstrument: TAsmInstrument; 212 begin
234 I, J: integer; 213 Res := TStringList.Create;
235 TypePrefix: string; 214 OrderCnt := MaxIntValue([High(OrderMatrix[0]), High(OrderMatrix[1]),
236 HighMask: byte; 215 High(OrderMatrix[2]), High(OrderMatrix[3])]);
237 begin
238 ResultSL := TStringList.Create;
239 216
240 for I := Low(Instruments) to High(Instruments) do 217 Res.Add('order_cnt: db ' + IntToStr(OrderCnt * 2));
241 begin 218 Res.Add('order1: dw ' + ArrayHelper(OrderMatrix[0]));
242 AsmInstrument := InstrumentToBytes(Instruments[I]); 219 Res.Add('order2: dw ' + ArrayHelper(OrderMatrix[1]));
243 SL := TStringList.Create; 220 Res.Add('order3: dw ' + ArrayHelper(OrderMatrix[2]));
244 SL.StrictDelimiter := True; 221 Res.Add('order4: dw ' + ArrayHelper(OrderMatrix[3]));
245 SL.Delimiter := ',';
246 222
247 if Instruments[I].Type_ = itNoise then 223 Result := Res.Text;
248 begin 224 Res.Free;
249 SL.Add(IntToStr(AsmInstrument[1])); // envelope 225 end;
250
251 HighMask := AsmInstrument[0];
252 if Instruments[I].LengthEnabled then
253 HighMask := HighMask or %01000000;
254 if Instruments[I].CounterStep = swSeven then
255 HighMask := HighMask or %10000000;
256 SL.Add(IntToStr(HighMask));
257
258 for J := Low(TNoiseMacro) to High(TNoiseMacro) do
259 SL.Add(IntToStr(Instruments[I].NoiseMacro[J]));
260 end
261 else
262 for J := Low(AsmInstrument) to High(AsmInstrument) do
263 SL.Add(IntToStr(AsmInstrument[J]));
264
265 WriteStr(TypePrefix, Instruments[I].Type_);
266 ResultSL.Add(Format('%s%s: db %s', [TypePrefix, 'inst' + IntToStr(I),
267 SL.DelimitedText]));
268 SL.Free;
269 end;
270 226
271 Result := ResultSL.Text; 227 function RenderInstruments(Instruments: TInstrumentBank): string;
272 ResultSL.Free; 228 var
273 end; 229 SL, ResultSL: TStringList;
230 AsmInstrument: TAsmInstrument;
231 I, J: integer;
232 TypePrefix: string;
233 HighMask: byte;
234 begin
235 ResultSL := TStringList.Create;
274 236
275 function RenderCell(Cell: TCell): string; 237 for I := Low(Instruments) to High(Instruments) do
276 var
277 SL: TStringList;
278 begin 238 begin
239 AsmInstrument := InstrumentToBytes(Instruments[I]);
279 SL := TStringList.Create; 240 SL := TStringList.Create;
280 SL.Delimiter := ',';
281 SL.StrictDelimiter := True; 241 SL.StrictDelimiter := True;
242 SL.Delimiter := ',';
282 243
283 if Cell.Note = NO_NOTE then 244 if Instruments[I].Type_ = itNoise then
284 SL.Add('___') 245 begin
285 else 246 SL.Add(IntToStr(AsmInstrument[1])); // envelope
286 SL.Add(NoteToDriverMap.KeyData[Cell.Note]);
287 247
288 if InRange(Cell.Instrument, 0, 15) then 248 HighMask := AsmInstrument[0];
289 SL.Add(IntToStr(Cell.Instrument)) 249 if Instruments[I].LengthEnabled then
290 else 250 HighMask := HighMask or %01000000;
291 SL.Add('0'); 251 if Instruments[I].CounterStep = swSeven then
252 HighMask := HighMask or %10000000;
253 SL.Add(IntToStr(HighMask));
292 254
293 SL.Add('$' + EffectCodeToStr(Cell.EffectCode, Cell.EffectParams)); 255 for J := Low(TNoiseMacro) to High(TNoiseMacro) do
256 SL.Add(IntToStr(Instruments[I].NoiseMacro[J]));
257 end
258 else
259 for J := Low(AsmInstrument) to High(AsmInstrument) do
260 SL.Add(IntToStr(AsmInstrument[J]));
294 261
295 // RGBDS thinks you're defining a new macro if you don't have a space first. 262 WriteStr(TypePrefix, Instruments[I].Type_);
296 Result := ' dn ' + SL.DelimitedText; 263 ResultSL.Add(Format('%s%s: db %s', [TypePrefix, 'inst' + IntToStr(I),
264 SL.DelimitedText]));
297 SL.Free; 265 SL.Free;
298 end; 266 end;
299 267
300 function RenderPattern(Name: string; Pattern: TPattern): string; 268 Result := ResultSL.Text;
301 var 269 ResultSL.Free;
302 SL: TStringList; 270 end;
303 I: integer;
304 begin
305 SL := TStringList.Create;
306 SL.Add(Name + ':');
307 271
308 for I := Low(TPattern) to High(TPattern) do 272 function RenderCell(Cell: TCell): string;
309 SL.Add(RenderCell(Pattern[I])); 273 var
274 SL: TStringList;
275 begin
276 SL := TStringList.Create;
277 SL.Delimiter := ',';
278 SL.StrictDelimiter := True;
310 279
311 Result := SL.Text; 280 if Cell.Note = NO_NOTE then
312 SL.Free; 281 SL.Add('___')
313 end; 282 else
283 SL.Add(NoteToDriverMap.KeyData[Cell.Note]);
314 284
315 function RenderWaveforms(Waves: TWaveBank): string; 285 if InRange(Cell.Instrument, 0, 15) then
316 var 286 SL.Add(IntToStr(Cell.Instrument))
317 SL, ResultSL: TStringList; 287 else
318 I, J: integer; 288 SL.Add('0');
319 begin
320 ResultSL := TStringList.Create;
321 289
322 for I := Low(Waves) to High(Waves) do 290 SL.Add('$' + EffectCodeToStr(Cell.EffectCode, Cell.EffectParams));
323 begin
324 SL := TStringList.Create;
325 SL.StrictDelimiter := True;
326 SL.Delimiter := ',';
327 291
328 J := Low(Waves[I]); 292 // RGBDS thinks you're defining a new macro if you don't have a space first.
329 while J < High(Waves[I]) do 293 Result := ' dn ' + SL.DelimitedText;
330 begin 294 SL.Free;
331 SL.Add(IntToStr((Waves[I, J] shl 4) or Waves[I, J + 1])); 295 end;
332 Inc(J, 2);
333 end;
334 ResultSL.Add(Format('wave%d: db %s', [I, SL.DelimitedText]));
335 SL.Free;
336 end;
337 296
338 Result := ResultSL.Text; 297 function RenderPattern(Name: string; Pattern: TPattern): string;
339 ResultSL.Free; 298 var
340 end; 299 SL: TStringList;
300 I: integer;
301 begin
302 SL := TStringList.Create;
303 SL.Add(Name + ':');
341 304
342 function RenderConstants(Song: TSong; Mode: TExportMode): string; 305 for I := Low(TPattern) to High(TPattern) do
343 var 306 SL.Add(RenderCell(Pattern[I]));
344 SL: TStringList; 307
308 Result := SL.Text;
309 SL.Free;
310 end;
311
312 function RenderWaveforms(Waves: TWaveBank): string;
313 var
314 SL, ResultSL: TStringList;
315 I, J: integer;
316 begin
317 ResultSL := TStringList.Create;
318
319 for I := Low(Waves) to High(Waves) do
345 begin 320 begin
346 SL := TStringList.Create; 321 SL := TStringList.Create;
347 SL.Add('STANDALONE_MODE EQU 1'); 322 SL.StrictDelimiter := True;
323 SL.Delimiter := ',';
348 324
349 if Mode = emPreview then 325 J := Low(Waves[I]);
350 SL.Add('PREVIEW_MODE EQU 1') 326 while J < High(Waves[I]) do
351 else if Mode = emGBS then
352 begin 327 begin
353 SL.Add('GBS_MODE EQU 1'); 328 SL.Add(IntToStr((Waves[I, J] shl 4) or Waves[I, J + 1]));
354 SL.Add('GBS_TITLE EQUS "\"' + PadRight(Song.Name, 32) + '\""'); 329 Inc(J, 2);
355 SL.Add('GBS_AUTHOR EQUS "\"' + PadRight(Song.Artist, 32) + '\""');
356 SL.Add('GBS_COPYRIGHT EQUS "\"' + PadRight(IntToStr(CurrentYear), 32) + '\""');
357 end; 330 end;
358 SL.Add('TICKS EQU ' + IntToStr(Song.TicksPerRow)); 331 ResultSL.Add(Format('wave%d: db %s', [I, SL.DelimitedText]));
359
360 Result := SL.Text;
361 SL.Free; 332 SL.Free;
362 end; 333 end;
363 334
364 procedure WriteRoutinesToFile(Routines: TRoutineBank); 335 Result := ResultSL.Text;
365 var 336 ResultSL.Free;
366 I: integer; 337 end;
367 F: Text;
368 begin
369 for I := Low(TRoutineBank) to High(TRoutineBank) do
370 begin
371 AssignFile(F, './hUGEDriver/routine' + IntToStr(I) + '.htt');
372 Rewrite(F);
373 Write(F, Routines[I]);
374 CloseFile(F);
375 end;
376 end;
377 338
378 procedure WriteHTT(F: string; S: string); 339 procedure RenderSongToRGBDSAsm(Song: TSong; DescriptorName: String; Filename: string);
379 begin 340 var
380 AssignFile(OutFile, F); 341 OutSL: TStringList;
381 Rewrite(OutFile); 342 F: Text;
382 Write(OutFile, S); 343 I: Integer;
383 CloseFile(OutFile);
384 end;
385 begin 344 begin
386 FilePath := Filename; 345 OutSL := TStringList.Create;
387 Filename := ExtractFileNameWithoutExt(ExtractFileNameOnly(Filename));
388 346
389 WriteHTT('./hUGEDriver/'+DescriptorName+'_constants.htt', RenderConstants(Song, Mode)); 347 OutSL.Add('include "include/hUGE.inc"');
390 WriteHTT('./hUGEDriver/'+DescriptorName+'_wave.htt', RenderWaveforms(Song.Waves)); 348 OutSL.Add('');
391 WriteHTT('./hUGEDriver/'+DescriptorName+'_order.htt', RenderOrderTable(Song.OrderMatrix)); 349 OutSL.Add('SECTION "Song Data", ROMX');
392 WriteHTT('./hUGEDriver/'+DescriptorName+'_duty_instrument.htt', RenderInstruments(Song.Instruments.Duty)); 350 OutSL.Add('');
393 WriteHTT('./hUGEDriver/'+DescriptorName+'_wave_instrument.htt', RenderInstruments(Song.Instruments.Wave));
394 WriteHTT('./hUGEDriver/'+DescriptorName+'_noise_instrument.htt',
395 RenderInstruments(Song.Instruments.Noise));
396 WriteRoutinesToFile(Song.Routines);
397 351
398 AssignFile(OutFile, './hUGEDriver/pattern.htt'); 352 // Render song descriptor
399 Rewrite(OutFile); 353 OutSL.Add(DescriptorName+'::');
354 OutSL.Add('db '+IntToStr(Song.TicksPerRow));
355 OutSL.Add('dw order_cnt');
356 OutSL.Add('dw order1, order2, order3, order4');
357 OutSL.Add('dw duty_instruments, wave_instruments, noise_instruments');
358 OutSL.Add('dw routines');
359 OutSL.Add('dw waves');
360 OutSL.Add('');
361
362 // Render order matrix
363 OutSL.Add(RenderOrderTable(Song.OrderMatrix));
364
365 // Render patterns
400 366
401 // TODO: Are keys and data defined to be aligned? Seems like they are but 367 // TODO: Are keys and data defined to be aligned? Seems like they are but
402 // should probably find out if that's just an implementation detail... 368 // should probably find out if that's just an implementation detail...
403 for I := 0 to Song.Patterns.Count - 1 do 369 for I := 0 to Song.Patterns.Count - 1 do
404 if PatternIsUsed(Song.Patterns.Keys[I], Song) then 370 if PatternIsUsed(Song.Patterns.Keys[I], Song) then
405 Write(OutFile, RenderPattern('P' + IntToStr(Song.Patterns.Keys[I]), 371 OutSL.Add(RenderPattern('P' + IntToStr(Song.Patterns.Keys[I]), Song.Patterns.Data[I]^));
406 Song.Patterns.Data[I]^));
407 372
408 CloseFile(OutFile); 373 // Render instruments
374 OutSL.Add('duty_instruments:');
375 OutSL.Add(RenderInstruments(Song.Instruments.Duty));
376 OutSL.Add('');
377
378 OutSL.Add('wave_instruments:');
379 OutSL.Add(RenderInstruments(Song.Instruments.Wave));
380 OutSL.Add('');
381
382 OutSL.Add('noise_instruments:');
383 OutSL.Add(RenderInstruments(Song.Instruments.Noise));
384 OutSL.Add('');
385
386 // Render routines
387 OutSL.Add('routines:');
388 for I := Low(TRoutineBank) to High(TRoutineBank) do begin
389 OutSL.Add('__hUGE_Routine_'+IntToStr(I)+':');
390 OutSL.Add(Song.Routines[I]);
391 OutSL.Add('__end_hUGE_Routine_'+IntToStr(I)+':');
392 OutSL.Add('ret');
393 OutSL.Add('');
394 end;
395
396 // Render waves
397 OutSL.Add('waves:');
398 OutSL.Add(RenderWaveforms(Song.Waves));
399
400 AssignFile(F, Filename);
401 Rewrite(F);
402 Write(F, OutSL.Text);
403 CloseFile(F);
404
405 OutSL.Free;
409 end; 406 end;
410 407
411 procedure RectifyGBSFile(GBSFile: string); 408 procedure RectifyGBSFile(GBSFile: string);
@@ -433,8 +430,7 @@ begin
433 Result := RenderSongToFile(Song, 'preview.gb', emPreview); 430 Result := RenderSongToFile(Song, 'preview.gb', emPreview);
434 end; 431 end;
435 432
436 function RenderSongToFile(Song: TSong; Filename: String; 433 function RenderSongToFile(Song: TSong; Filename: String; Mode: TExportMode = emNormal): boolean;
437 Mode: TExportMode = emNormal; DescriptorName: String = 'song_descriptor'): boolean;
438 { TODO: Refactor this whole monstrosity. } 434 { TODO: Refactor this whole monstrosity. }
439 var 435 var
440 OutFile: Text; 436 OutFile: Text;
@@ -444,6 +440,14 @@ var
444 FilePath: string; 440 FilePath: string;
445 RenameSucceeded: Boolean; 441 RenameSucceeded: Boolean;
446 442
443 procedure WriteHTT(F: string; S: string);
444 begin
445 AssignFile(OutFile, F);
446 Rewrite(OutFile);
447 Write(OutFile, S);
448 CloseFile(OutFile);
449 end;
450
447 function Assemble(OutFile: string; InFile: string; Defines: array of string): integer; 451 function Assemble(OutFile: string; InFile: string; Defines: array of string): integer;
448 var 452 var
449 Define: string; 453 Define: string;
@@ -495,66 +499,91 @@ label
495 begin 499 begin
496 Song := OptimizeSong(Song); 500 Song := OptimizeSong(Song);
497 501
498 RenderSongToHTTs(Song, DescriptorName, Filename); 502 FilePath := Filename;
503 Filename := ExtractFileNameWithoutExt(ExtractFileNameOnly(Filename));
504
505 WriteHTT('./hUGEDriver/wave.htt', RenderWaveforms(Song.Waves));
506 WriteHTT('./hUGEDriver/order.htt', RenderOrderTable(Song.OrderMatrix));
507 WriteHTT('./hUGEDriver/duty_instrument.htt', RenderInstruments(Song.Instruments.Duty));
508 WriteHTT('./hUGEDriver/wave_instrument.htt', RenderInstruments(Song.Instruments.Wave));
509 WriteHTT('./hUGEDriver/noise_instrument.htt', RenderInstruments(Song.Instruments.Noise));
510 for I := Low(TRoutineBank) to High(TRoutineBank) do
511 WriteHTT('./hUGEDriver/routine'+IntToStr(I)+'.htt', Song.Routines[I]);
512
513 AssignFile(OutFile, './hUGEDriver/pattern.htt');
514 Rewrite(OutFile);
515
516 // TODO: Are keys and data defined to be aligned? Seems like they are but
517 // should probably find out if that's just an implementation detail...
518 for I := 0 to Song.Patterns.Count - 1 do
519 if PatternIsUsed(Song.Patterns.Keys[I], Song) then
520 Write(OutFile, RenderPattern('P' + IntToStr(Song.Patterns.Keys[I]),
521 Song.Patterns.Data[I]^));
522
523 CloseFile(OutFile);
499 524
500 // Build the file 525 // Build the file
501 Chdir('hUGEDriver'); 526 Chdir('hUGEDriver');
502 527
503 OutSL := TStringList.Create; 528 OutSL := TStringList.Create;
504 Proc := TProcess.Create(nil); 529 Proc := TProcess.Create(nil);
505 Proc.Options := Proc.Options + [poWaitOnExit, poUsePipes, poStdErrToOutput, 530 Proc.Options := Proc.Options + [poWaitOnExit, poUsePipes, poStdErrToOutput, poNoConsole];
506 poNoConsole];
507 531
508 // Assemble 532 // Assemble
509 if Mode = emPreview then 533 if Mode = emPreview then
510 begin 534 begin
511 if Assemble(Filename + '_driver.obj', 'hUGEDriver.z80', ['PREVIEW_MODE']) <> 0 then 535 if Assemble(Filename + '_driver.obj', 'hUGEDriver.asm', ['PREVIEW_MODE']) <> 0 then
512 goto AssemblyError; 536 goto AssemblyError;
513 end 537 end
514 else 538 else
515 begin 539 begin
516 if Assemble(Filename + '_driver.obj', 'hUGEDriver.z80', []) <> 0 then 540 if Assemble(Filename + '_driver.obj', 'hUGEDriver.asm', []) <> 0 then
517 goto AssemblyError; 541 goto AssemblyError;
518 end; 542 end;
519 543
520 if Assemble(Filename + '_song.obj', 'song.z80', ['SONG_DESCRIPTOR=_'+DescriptorName]) <> 0 then 544 if Assemble(Filename + '_song.obj',
545 'song.asm',
546 ['SONG_DESCRIPTOR=song', 'TICKS='+IntToStr(Song.TicksPerRow)]) <> 0 then
521 goto AssemblyError; 547 goto AssemblyError;
522 548
523 if Mode = emGBS then 549 if Mode = emGBS then
524 begin 550 begin
525 if Assemble(Filename + '_gbs.obj', 'gbs.z80', ['SONG_DESCRIPTOR=_'+DescriptorName]) <> 0 then 551 if Assemble(
526 goto AssemblyError; 552 Filename + '_gbs.obj', 'gbs.asm',
553 ['SONG_DESCRIPTOR=song',
554 'GBS_TITLE='+PadRight(Song.Name, 32),
555 'GBS_AUTHOR='+PadRight(Song.Artist, 32),
556 'GBS_COPYRIGHT='+PadRight(IntToStr(CurrentYear), 32)]
557 ) <> 0 then goto AssemblyError;
527 end 558 end
528 else 559 else
529 begin 560 begin
530 if Assemble(Filename + '_player.obj', 'player.z80', ['SONG_DESCRIPTOR=_'+DescriptorName]) <> 0 then 561 if Assemble(Filename + '_player.obj', 'player.asm', ['SONG_DESCRIPTOR=song']) <> 0 then
531 goto AssemblyError; 562 goto AssemblyError;
532 end; 563 end;
533 564
534 if Mode in [emNormal, emPreview, emGBS] then begin 565 // Link
535 // Link 566 if Mode = emGBS then
536 if Mode = emGBS then 567 begin
537 begin 568 if Link(Filename + '.gbs', [Filename + '_driver.obj', Filename +
538 if Link(Filename + '.gbs', [Filename + '_driver.obj', Filename + 569 '_song.obj', Filename + '_gbs.obj']) <> 0 then
539 '_song.obj', Filename + '_gbs.obj']) <> 0 then 570 goto AssemblyError;
540 goto AssemblyError; 571 end
541 end 572 else
542 else 573 begin
543 begin 574 if Link(Filename + '.gb', [Filename + '_driver.obj', Filename +
544 if Link(Filename + '.gb', [Filename + '_driver.obj', Filename + 575 '_song.obj', Filename + '_player.obj'], Filename + '.map', Filename +
545 '_song.obj', Filename + '_player.obj'], Filename + '.map', Filename + 576 '.sym') <> 0 then
546 '.sym') <> 0 then 577 goto AssemblyError;
547 goto AssemblyError; 578 end;
548 end;
549 579
550 // Fix 580 // Fix
551 if Mode = emGBS then 581 if Mode = emGBS then
552 RectifyGBSFile(Filename + '.gbs') 582 RectifyGBSFile(Filename + '.gbs')
553 else 583 else
554 begin 584 begin
555 if (Fix(Filename + '.gb') <> 0) then 585 if (Fix(Filename + '.gb') <> 0) then
556 goto AssemblyError; 586 goto AssemblyError;
557 end;
558 end; 587 end;
559 588
560 // Move to destination 589 // Move to destination
ModifiedhUGEDriver +1−1
@@ -1 +1 @@
1 Subproject commit d5c0af75d58777ae0133b3fd86ba5c19264bc5db 1 Subproject commit 4d61fc88b21904fb146d0c3a251e0200030b9d1a
Modifiedtracker.lfm +5−9
@@ -1926,8 +1926,9 @@ object frmTracker: TfrmTracker
1926 object MenuItem40: TMenuItem 1926 object MenuItem40: TMenuItem
1927 Caption = '-' 1927 Caption = '-'
1928 end 1928 end
1929 object MenuItem41: TMenuItem 1929 object ExportAsmMenuItem: TMenuItem
1930 Caption = 'Export RGBDS .htt ...' 1930 Caption = 'Export RGBDS .asm ...'
1931 OnClick = ExportAsmMenuItemClick
1931 end 1932 end
1932 object ExportCMenuItem: TMenuItem 1933 object ExportCMenuItem: TMenuItem
1933 Caption = 'Export GBDK .c ...' 1934 Caption = 'Export GBDK .c ...'
@@ -5379,14 +5380,9 @@ object frmTracker: TfrmTracker
5379 Left = 248 5380 Left = 248
5380 Top = 24 5381 Top = 24
5381 end 5382 end
5382 object RGBDSObjSaveDialog: TSaveDialog 5383 object RGBDSAsmSaveDialog: TSaveDialog
5383 Filter = 'RGBDS Object|*.obj' 5384 Filter = 'RGBDS Assembly|*.asm'
5384 Left = 248 5385 Left = 248
5385 Top = 64 5386 Top = 64
5386 end 5387 end
5387 object GBDKObjSaveDialog: TSaveDialog
5388 Filter = 'GBDK Object|*.o'
5389 Left = 288
5390 Top = 64
5391 end
5392 end 5388 end
Modifiedtracker.pas +16−3
@@ -31,15 +31,14 @@ type
31 MenuItem39: TMenuItem; 31 MenuItem39: TMenuItem;
32 ExportCMenuItem: TMenuItem; 32 ExportCMenuItem: TMenuItem;
33 MenuItem40: TMenuItem; 33 MenuItem40: TMenuItem;
34 MenuItem41: TMenuItem; 34 ExportAsmMenuItem: TMenuItem;
35 MenuItem43: TMenuItem; 35 MenuItem43: TMenuItem;
36 MenuItem44: TMenuItem; 36 MenuItem44: TMenuItem;
37 MenuItem54: TMenuItem; 37 MenuItem54: TMenuItem;
38 NoiseMacroPaintbox: TPaintBox; 38 NoiseMacroPaintbox: TPaintBox;
39 Panel6: TPanel; 39 Panel6: TPanel;
40 GBDKCSaveDialog: TSaveDialog; 40 GBDKCSaveDialog: TSaveDialog;
41 RGBDSObjSaveDialog: TSaveDialog; 41 RGBDSAsmSaveDialog: TSaveDialog;
42 GBDKObjSaveDialog: TSaveDialog;
43 StopAction: TAction; 42 StopAction: TAction;
44 PlayOrderAction: TAction; 43 PlayOrderAction: TAction;
45 PlayCursorAction: TAction; 44 PlayCursorAction: TAction;
@@ -274,6 +273,7 @@ type
274 procedure InsertRowForAllActionUpdate(Sender: TObject); 273 procedure InsertRowForAllActionUpdate(Sender: TObject);
275 procedure MenuItem37Click(Sender: TObject); 274 procedure MenuItem37Click(Sender: TObject);
276 procedure MenuItem38Click(Sender: TObject); 275 procedure MenuItem38Click(Sender: TObject);
276 procedure ExportAsmMenuItemClick(Sender: TObject);
277 procedure NoiseMacroPaintboxMouseDown(Sender: TObject; 277 procedure NoiseMacroPaintboxMouseDown(Sender: TObject;
278 Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 278 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
279 procedure NoiseMacroPaintboxMouseMove(Sender: TObject; Shift: TShiftState; 279 procedure NoiseMacroPaintboxMouseMove(Sender: TObject; Shift: TShiftState;
@@ -1655,6 +1655,19 @@ begin
1655 HexWaveEditEditingDone(nil); 1655 HexWaveEditEditingDone(nil);
1656 end; 1656 end;
1657 1657
1658 procedure TfrmTracker.ExportAsmMenuItemClick(Sender: TObject);
1659 var
1660 S: String;
1661 begin
1662 S := InputBox('Song descriptor', 'Enter the song descriptor (must be a valid RGBDS symbol):', 'song_descriptor');
1663 if RGBDSAsmSaveDialog.Execute then
1664 RenderSongToRGBDSAsm(
1665 Song,
1666 S,
1667 RGBDSAsmSaveDialog.FileName
1668 );
1669 end;
1670
1658 procedure TfrmTracker.NoiseMacroPaintboxMouseDown(Sender: TObject; 1671 procedure TfrmTracker.NoiseMacroPaintboxMouseDown(Sender: TObject;
1659 Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 1672 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
1660 begin 1673 begin