Commit 8f059fa

Nick committed on
More work on tracker
commit 8f059fa04a376b7c20d2d80623f4d849d140924d parent bf10cbc
8 changed files +534−95
ModifiedGBEmu.lpi +11−1
@@ -63,7 +63,7 @@
63 <PackageName Value="LCL"/> 63 <PackageName Value="LCL"/>
64 </Item6> 64 </Item6>
65 </RequiredPackages> 65 </RequiredPackages>
66 <Units Count="17"> 66 <Units Count="19">
67 <Unit0> 67 <Unit0>
68 <Filename Value="GBEmu.lpr"/> 68 <Filename Value="GBEmu.lpr"/>
69 <IsPartOfProject Value="True"/> 69 <IsPartOfProject Value="True"/>
@@ -148,6 +148,16 @@
148 <IsPartOfProject Value="True"/> 148 <IsPartOfProject Value="True"/>
149 <UnitName Value="Utils"/> 149 <UnitName Value="Utils"/>
150 </Unit16> 150 </Unit16>
151 <Unit17>
152 <Filename Value="constants.pas"/>
153 <IsPartOfProject Value="True"/>
154 <UnitName Value="Constants"/>
155 </Unit17>
156 <Unit18>
157 <Filename Value="waves.pas"/>
158 <IsPartOfProject Value="True"/>
159 <UnitName Value="Waves"/>
160 </Unit18>
151 </Units> 161 </Units>
152 </ProjectOptions> 162 </ProjectOptions>
153 <CompilerOptions> 163 <CompilerOptions>
Addedconstants.pas +191−0
@@ -0,0 +1,191 @@
1 unit Constants;
2
3 {$mode objfpc}
4
5 interface
6
7 uses
8 fgl;
9
10 type
11 TNoteMap = specialize TFPGMap<Integer, String>;
12 TKeybindings = specialize TFPGmap<Word, Integer>;
13
14 const
15 // Sound controller registers
16 NR10 = $FF10;
17 NR11 = $FF11;
18 NR12 = $FF12;
19 NR13 = $FF13;
20 NR14 = $FF14;
21 NR21 = $FF16;
22 NR22 = $FF17;
23 NR23 = $FF18;
24 NR24 = $FF19;
25 NR30 = $FF1A;
26 NR31 = $FF1B;
27 NR32 = $FF1C;
28 NR33 = $FF1D;
29 NR34 = $FF1E;
30 NR41 = $FF20;
31 NR42 = $FF21;
32 NR43 = $FF22;
33 NR44 = $FF23;
34
35 // Note constants. These will probably go in a dictionary instead later
36 C_3 = 44;
37 CS3 = 156;
38 D_3 = 262;
39 DS3 = 363;
40 E_3 = 457;
41 F_3 = 547;
42 FS3 = 631;
43 G_3 = 710;
44 GS3 = 786;
45 A_3 = 854;
46 AS3 = 923;
47 B_3 = 986;
48 C_4 = 1046;
49 CS4 = 1102;
50 D_4 = 1155;
51 DS4 = 1205;
52 E_4 = 1253;
53 F_4 = 1297;
54 FS4 = 1339;
55 G_4 = 1379;
56 GS4 = 1417;
57 A_4 = 1452;
58 AS4 = 1486;
59 B_4 = 1517;
60 C_5 = 1546;
61 CS5 = 1575;
62 D_5 = 1602;
63 DS5 = 1627;
64 E_5 = 1650;
65 F_5 = 1673;
66 FS5 = 1694;
67 G_5 = 1714;
68 GS5 = 1732;
69 A_5 = 1750;
70 AS5 = 1767;
71 B_5 = 1783;
72 C_6 = 1798;
73 CS6 = 1812;
74 D_6 = 1825;
75 DS6 = 1837;
76 E_6 = 1849;
77 F_6 = 1860;
78 FS6 = 1871;
79 G_6 = 1881;
80 GS6 = 1890;
81 A_6 = 1899;
82 AS6 = 1907;
83 B_6 = 1915;
84 C_7 = 1923;
85 CS7 = 1930;
86 D_7 = 1936;
87 DS7 = 1943;
88 E_7 = 1949;
89 F_7 = 1954;
90 FS7 = 1959;
91 G_7 = 1964;
92 GS7 = 1969;
93 A_7 = 1974;
94 AS7 = 1978;
95 B_7 = 1982;
96 C_8 = 1985;
97 CS8 = 1988;
98 D_8 = 1992;
99 DS8 = 1995;
100 E_8 = 1998;
101 F_8 = 2001;
102 FS8 = 2004;
103 G_8 = 2006;
104 GS8 = 2009;
105 A_8 = 2011;
106 AS8 = 2013;
107 B_8 = 2015;
108
109 var
110 NoteMap: TNoteMap;
111 Keybindings: TKeybindings;
112
113 implementation
114
115 uses SysUtils;
116
117 begin
118 NoteMap := TNoteMap.Create;
119 Keybindings := TKeybindings.Create;
120
121 Keybindings.Add(Ord('Q'), C_4);
122 Keybindings.Add(Ord('W'), CS4);
123 Keybindings.Add(Ord('E'), D_4);
124 Keybindings.Add(Ord('R'), DS4);
125 Keybindings.Add(Ord('T'), E_4);
126 Keybindings.Add(Ord('Y'), F_4);
127 Keybindings.Add(Ord('U'), FS4);
128 Keybindings.Add(Ord('I'), G_4);
129 Keybindings.Add(Ord('O'), GS4);
130 Keybindings.Add(Ord('P'), A_4);
131 Keybindings.Add(Ord('['), AS4);
132 Keybindings.Add(Ord(']'), B_4);
133 Keybindings.Add(Ord('\'), B_5);
134 Keybindings.Add(Ord('A'), C_5);
135 Keybindings.Add(Ord('S'), CS5);
136 Keybindings.Add(Ord('D'), D_5);
137 Keybindings.Add(Ord('F'), DS5);
138 Keybindings.Add(Ord('G'), E_5);
139 Keybindings.Add(Ord('H'), F_5);
140 Keybindings.Add(Ord('J'), FS5);
141 Keybindings.Add(Ord('K'), G_5);
142 Keybindings.Add(Ord('L'), GS5);
143 Keybindings.Add(Ord(';'), A_5);
144 Keybindings.Add(Ord(''''), AS5);
145 Keybindings.Add(Ord('Z'), C_6);
146 Keybindings.Add(Ord('X'), CS6);
147 Keybindings.Add(Ord('C'), D_6);
148 Keybindings.Add(Ord('V'), DS6);
149 Keybindings.Add(Ord('B'), E_6);
150 Keybindings.Add(Ord('N'), F_6);
151 Keybindings.Add(Ord('M'), FS6);
152 Keybindings.Add(Ord(','), G_6);
153 Keybindings.Add(Ord('.'), GS6);
154 Keybindings.Add(Ord('/'), A_6);
155
156 NoteMap.Add(C_4, 'C_4');
157 NoteMap.Add(CS4, 'C#4');
158 NoteMap.Add(D_4, 'D_4');
159 NoteMap.Add(DS4, 'D#4');
160 NoteMap.Add(E_4, 'E_4');
161 NoteMap.Add(F_4, 'F_4');
162 NoteMap.Add(FS4, 'F#4');
163 NoteMap.Add(G_4, 'G_4');
164 NoteMap.Add(GS4, 'G#4');
165 NoteMap.Add(A_4, 'A_4');
166 NoteMap.Add(AS4, 'A#4');
167 NoteMap.Add(B_4, 'B_4');
168 NoteMap.Add(B_5, 'B_5');
169 NoteMap.Add(C_5, 'C_5');
170 NoteMap.Add(CS5, 'C#5');
171 NoteMap.Add(D_5, 'D_5');
172 NoteMap.Add(DS5, 'D#5');
173 NoteMap.Add(E_5, 'E_5');
174 NoteMap.Add(F_5, 'F_5');
175 NoteMap.Add(FS5, 'F#5');
176 NoteMap.Add(G_5, 'G_5');
177 NoteMap.Add(GS5, 'G#5');
178 NoteMap.Add(A_5, 'A_5');
179 NoteMap.Add(AS5, 'A#5');
180 NoteMap.Add(C_6, 'C_6');
181 NoteMap.Add(CS6, 'C#6');
182 NoteMap.Add(D_6, 'D_6');
183 NoteMap.Add(DS6, 'D#6');
184 NoteMap.Add(E_6, 'E_6');
185 NoteMap.Add(F_6, 'F_6');
186 NoteMap.Add(FS6, 'F#6');
187 NoteMap.Add(G_6, 'G_6');
188 NoteMap.Add(GS6, 'G#6');
189 NoteMap.Add(A_6, 'A_6');
190 end.
191
Modifiedinstruments.pas +23−22
@@ -49,6 +49,8 @@ type
49 TEnvelopeSweepAmount = 0..7; 49 TEnvelopeSweepAmount = 0..7;
50 50
51 TInstrument = record 51 TInstrument = record
52 Type_: TInstrumentType;
53
52 Name: String; 54 Name: String;
53 Length: Integer; 55 Length: Integer;
54 // Highmask 56 // Highmask
@@ -58,28 +60,27 @@ type
58 VolSweepDirection: TSweepType; 60 VolSweepDirection: TSweepType;
59 VolSweepAmount: TEnvelopeSweepAmount; 61 VolSweepAmount: TEnvelopeSweepAmount;
60 62
61 case Type_: TInstrumentType of 63 // Square
62 Square: ( 64 // NR10
63 // NR10 65 SweepTime: Integer;
64 SweepTime: Integer; 66 SweepIncDec: TSweepType;
65 SweepIncDec: TSweepType; 67 SweepShift: Integer;
66 SweepShift: Integer; 68
67 69 // NR11
68 // NR11 70 Duty: TDutyType;
69 Duty: TDutyType; 71
70 ); 72 // Wave
71 Wave: ( 73
72 // NR32 74 // NR32
73 OutputLevel: Integer; 75 OutputLevel: Integer;
74 // Wave 76 // Wave
75 Waveform: Integer; 77 Waveform: Integer;
76 ); 78
77 Noise: ( 79 // Noise
78 // NR42 80 // NR42
79 ShiftClockFreq: Integer; 81 ShiftClockFreq: Integer;
80 CounterStep: TStepWidth; 82 CounterStep: TStepWidth;
81 DividingRatio: Integer; 83 DividingRatio: Integer;
82 );
83 end; 84 end;
84 85
85 implementation 86 implementation
Modifiedsong.pas +2−1
@@ -4,7 +4,7 @@ unit Song;
4 4
5 interface 5 interface
6 6
7 uses instruments; 7 uses instruments, waves;
8 8
9 type 9 type
10 TSong = record 10 TSong = record
@@ -13,6 +13,7 @@ type
13 Comment: String; 13 Comment: String;
14 14
15 Instruments: array[1..15] of TInstrument; 15 Instruments: array[1..15] of TInstrument;
16 Waves: array[0..15] of TWave;
16 end; 17 end;
17 18
18 implementation 19 implementation
Modifiedtracker.lfm +101−30
@@ -1,17 +1,19 @@
1 object frmTracker: TfrmTracker 1 object frmTracker: TfrmTracker
2 Left = 497 2 Left = 497
3 Height = 930 3 Height = 874
4 Top = 131 4 Top = 131
5 Width = 1306 5 Width = 1286
6 Caption = 'hUGETracker' 6 Caption = 'hUGETracker'
7 ClientHeight = 910 7 ClientHeight = 854
8 ClientWidth = 1306 8 ClientWidth = 1286
9 Menu = MainMenu1 9 Menu = MainMenu1
10 OnCreate = FormCreate 10 OnCreate = FormCreate
11 OnKeyDown = FormKeyDown
12 OnKeyUp = FormKeyUp
11 LCLVersion = '2.0.2.0' 13 LCLVersion = '2.0.2.0'
12 object TreeView1: TTreeView 14 object TreeView1: TTreeView
13 Left = 0 15 Left = 0
14 Height = 685 16 Height = 629
15 Top = 202 17 Top = 202
16 Width = 193 18 Width = 193
17 Align = alLeft 19 Align = alLeft
@@ -31,25 +33,25 @@ object frmTracker: TfrmTracker
31 end 33 end
32 object Splitter1: TSplitter 34 object Splitter1: TSplitter
33 Left = 193 35 Left = 193
34 Height = 685 36 Height = 629
35 Top = 202 37 Top = 202
36 Width = 5 38 Width = 5
37 end 39 end
38 object Panel1: TPanel 40 object Panel1: TPanel
39 Left = 198 41 Left = 198
40 Height = 685 42 Height = 629
41 Top = 202 43 Top = 202
42 Width = 1108 44 Width = 1088
43 Align = alClient 45 Align = alClient
44 BevelOuter = bvNone 46 BevelOuter = bvNone
45 ClientHeight = 685 47 ClientHeight = 629
46 ClientWidth = 1108 48 ClientWidth = 1088
47 TabOrder = 2 49 TabOrder = 2
48 object PageControl1: TPageControl 50 object PageControl1: TPageControl
49 Left = 0 51 Left = 0
50 Height = 685 52 Height = 629
51 Top = 0 53 Top = 0
52 Width = 1108 54 Width = 1088
53 ActivePage = InstrumentTabSheet 55 ActivePage = InstrumentTabSheet
54 Align = alClient 56 Align = alClient
55 TabIndex = 2 57 TabIndex = 2
@@ -106,13 +108,13 @@ object frmTracker: TfrmTracker
106 end 108 end
107 object InstrumentTabSheet: TTabSheet 109 object InstrumentTabSheet: TTabSheet
108 Caption = 'Instruments' 110 Caption = 'Instruments'
109 ClientHeight = 657 111 ClientHeight = 601
110 ClientWidth = 1100 112 ClientWidth = 1080
111 object PaintBox1: TPaintBox 113 object PaintBox1: TPaintBox
112 Left = 0 114 Left = 0
113 Height = 321 115 Height = 265
114 Top = 336 116 Top = 336
115 Width = 1100 117 Width = 1080
116 Align = alClient 118 Align = alClient
117 Color = clBlack 119 Color = clBlack
118 ParentColor = False 120 ParentColor = False
@@ -122,10 +124,10 @@ object frmTracker: TfrmTracker
122 Left = 0 124 Left = 0
123 Height = 336 125 Height = 336
124 Top = 0 126 Top = 0
125 Width = 1100 127 Width = 1080
126 Align = alTop 128 Align = alTop
127 ClientHeight = 336 129 ClientHeight = 336
128 ClientWidth = 1100 130 ClientWidth = 1080
129 TabOrder = 0 131 TabOrder = 0
130 object InstrumentGroupBox: TGroupBox 132 object InstrumentGroupBox: TGroupBox
131 Left = 8 133 Left = 8
@@ -139,7 +141,7 @@ object frmTracker: TfrmTracker
139 object InstrumentNumberSpinner: TSpinEdit 141 object InstrumentNumberSpinner: TSpinEdit
140 Left = 80 142 Left = 80
141 Height = 23 143 Height = 23
142 Top = 0 144 Top = 1
143 Width = 176 145 Width = 176
144 MaxValue = 15 146 MaxValue = 15
145 MinValue = 1 147 MinValue = 1
@@ -594,21 +596,22 @@ object frmTracker: TfrmTracker
594 Top = 40 596 Top = 40
595 Width = 176 597 Width = 176
596 ItemHeight = 15 598 ItemHeight = 15
599 OnChange = WaveformComboboxChange
597 Style = csDropDownList 600 Style = csDropDownList
598 TabOrder = 0 601 TabOrder = 0
599 end 602 end
600 object Panel4: TPanel 603 object Panel4: TPanel
601 Left = 8 604 Left = 8
602 Height = 50 605 Height = 59
603 Top = 80 606 Top = 80
604 Width = 272 607 Width = 272
605 BevelOuter = bvLowered 608 BevelOuter = bvLowered
606 ClientHeight = 50 609 ClientHeight = 59
607 ClientWidth = 272 610 ClientWidth = 272
608 TabOrder = 1 611 TabOrder = 1
609 object WavePaintbox: TPaintBox 612 object WavePaintbox: TPaintBox
610 Left = 1 613 Left = 1
611 Height = 48 614 Height = 57
612 Top = 1 615 Top = 1
613 Width = 270 616 Width = 270
614 Align = alClient 617 Align = alClient
@@ -774,15 +777,75 @@ object frmTracker: TfrmTracker
774 end 777 end
775 end 778 end
776 end 779 end
780 object WavesTabSheet: TTabSheet
781 Caption = 'Waves'
782 ClientHeight = 601
783 ClientWidth = 1080
784 object WaveEditPaintBox: TPaintBox
785 Left = 0
786 Height = 385
787 Top = 216
788 Width = 1080
789 Align = alBottom
790 Anchors = [akTop, akLeft, akRight, akBottom]
791 OnPaint = WaveEditPaintBoxPaint
792 end
793 object WaveEditGroupBox: TGroupBox
794 Left = 8
795 Height = 192
796 Top = 8
797 Width = 345
798 Caption = 'Wave Editor'
799 ClientHeight = 172
800 ClientWidth = 341
801 TabOrder = 0
802 object Label20: TLabel
803 Left = 16
804 Height = 15
805 Top = 16
806 Width = 29
807 Caption = 'Wave'
808 ParentColor = False
809 end
810 object WaveEditNumberSpinner: TSpinEdit
811 Left = 64
812 Height = 23
813 Top = 8
814 Width = 80
815 MaxValue = 15
816 MinValue = 1
817 OnChange = WaveEditNumberSpinnerChange
818 TabOrder = 0
819 Value = 1
820 end
821 object ImportWaveButton: TButton
822 Left = 16
823 Height = 25
824 Top = 48
825 Width = 147
826 Caption = 'Import'
827 OnClick = ImportWaveButtonClick
828 TabOrder = 1
829 end
830 object ExportButton: TButton
831 Left = 16
832 Height = 25
833 Top = 80
834 Width = 147
835 Caption = 'Export'
836 TabOrder = 2
837 end
838 end
839 end
777 object CommentsTabSheet: TTabSheet 840 object CommentsTabSheet: TTabSheet
778 Caption = 'Comments' 841 Caption = 'Comments'
779 ClientHeight = 657 842 ClientHeight = 601
780 ClientWidth = 1100 843 ClientWidth = 1080
781 object CommentMemo: TMemo 844 object CommentMemo: TMemo
782 Left = 0 845 Left = 0
783 Height = 593 846 Height = 537
784 Top = 64 847 Top = 64
785 Width = 1100 848 Width = 1080
786 Align = alBottom 849 Align = alBottom
787 Anchors = [akTop, akLeft, akRight, akBottom] 850 Anchors = [akTop, akLeft, akRight, akBottom]
788 OnChange = CommentMemoChange 851 OnChange = CommentMemoChange
@@ -1336,7 +1399,7 @@ object frmTracker: TfrmTracker
1336 Left = 0 1399 Left = 0
1337 Height = 24 1400 Height = 24
1338 Top = 0 1401 Top = 0
1339 Width = 1306 1402 Width = 1286
1340 Bands = < 1403 Bands = <
1341 item 1404 item
1342 end> 1405 end>
@@ -1345,7 +1408,7 @@ object frmTracker: TfrmTracker
1345 Left = 0 1408 Left = 0
1346 Height = 178 1409 Height = 178
1347 Top = 24 1410 Top = 24
1348 Width = 1306 1411 Width = 1286
1349 Align = alTop 1412 Align = alTop
1350 BevelOuter = bvNone 1413 BevelOuter = bvNone
1351 TabOrder = 4 1414 TabOrder = 4
@@ -1353,8 +1416,8 @@ object frmTracker: TfrmTracker
1353 object StatusBar1: TStatusBar 1416 object StatusBar1: TStatusBar
1354 Left = 0 1417 Left = 0
1355 Height = 23 1418 Height = 23
1356 Top = 887 1419 Top = 831
1357 Width = 1306 1420 Width = 1286
1358 Panels = < 1421 Panels = <
1359 item 1422 item
1360 Width = 200 1423 Width = 200
@@ -1390,4 +1453,12 @@ object frmTracker: TfrmTracker
1390 OnClick = MenuItem6Click 1453 OnClick = MenuItem6Click
1391 end 1454 end
1392 end 1455 end
1456 object OpenDialog1: TOpenDialog
1457 left = 768
1458 top = 32
1459 end
1460 object SaveDialog1: TSaveDialog
1461 left = 688
1462 top = 32
1463 end
1393 end 1464 end
Modifiedtracker.pas +145−34
@@ -7,16 +7,24 @@ interface
7 uses 7 uses
8 Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, ComCtrls, 8 Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, ComCtrls,
9 Menus, Spin, StdCtrls, SynEdit, VirtualTrees, ECSlider, ECProgressBar, 9 Menus, Spin, StdCtrls, SynEdit, VirtualTrees, ECSlider, ECProgressBar,
10 Instruments, Song, EmulationThread, Utils, 10 Instruments, Waves, Song, EmulationThread, Utils, Constants,
11 mainloop, sound, vars, machine; 11 mainloop, sound, vars, machine;
12 12
13 type 13 type
14 { TfrmTracker } 14 { TfrmTracker }
15 15
16 TfrmTracker = class(TForm) 16 TfrmTracker = class(TForm)
17 ExportButton: TButton;
18 ImportWaveButton: TButton;
17 CommentMemo: TMemo; 19 CommentMemo: TMemo;
20 Label20: TLabel;
21 OpenDialog1: TOpenDialog;
22 SaveDialog1: TSaveDialog;
23 WaveEditNumberSpinner: TSpinEdit;
24 WaveEditGroupBox: TGroupBox;
18 Label19: TLabel; 25 Label19: TLabel;
19 MenuItem6: TMenuItem; 26 MenuItem6: TMenuItem;
27 WaveEditPaintBox: TPaintBox;
20 RoutineNumberSpinner: TSpinEdit; 28 RoutineNumberSpinner: TSpinEdit;
21 Label17: TLabel; 29 Label17: TLabel;
22 EnvelopePaintbox: TPaintBox; 30 EnvelopePaintbox: TPaintBox;
@@ -31,6 +39,7 @@ type
31 SevenBitCounterCheckbox: TCheckBox; 39 SevenBitCounterCheckbox: TCheckBox;
32 SweepTimeCombobox: TComboBox; 40 SweepTimeCombobox: TComboBox;
33 RoutineSynedit: TSynEdit; 41 RoutineSynedit: TSynEdit;
42 WavesTabSheet: TTabSheet;
34 WaveformCombobox: TComboBox; 43 WaveformCombobox: TComboBox;
35 WaveVolumeCombobox: TComboBox; 44 WaveVolumeCombobox: TComboBox;
36 SweepDirectionCombobox: TComboBox; 45 SweepDirectionCombobox: TComboBox;
@@ -95,11 +104,16 @@ type
95 procedure EnvChangeSpinnerChange(Sender: TObject); 104 procedure EnvChangeSpinnerChange(Sender: TObject);
96 procedure EnvelopePaintboxPaint(Sender: TObject); 105 procedure EnvelopePaintboxPaint(Sender: TObject);
97 procedure FormCreate(Sender: TObject); 106 procedure FormCreate(Sender: TObject);
107 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
108 procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
109 procedure ImportWaveButtonClick(Sender: TObject);
98 procedure InstrumentNameEditChange(Sender: TObject); 110 procedure InstrumentNameEditChange(Sender: TObject);
99 procedure InstrumentNumberSpinnerChange(Sender: TObject); 111 procedure InstrumentNumberSpinnerChange(Sender: TObject);
100 procedure LengthSpinnerChange(Sender: TObject); 112 procedure LengthSpinnerChange(Sender: TObject);
101 procedure MenuItem6Click(Sender: TObject); 113 procedure MenuItem6Click(Sender: TObject);
102 procedure NoiseFreqSpinnerChange(Sender: TObject); 114 procedure NoiseFreqSpinnerChange(Sender: TObject);
115 procedure WaveEditNumberSpinnerChange(Sender: TObject);
116 procedure WaveEditPaintBoxPaint(Sender: TObject);
103 procedure RandomizeNoiseButtonClick(Sender: TObject); 117 procedure RandomizeNoiseButtonClick(Sender: TObject);
104 procedure InstrumentTypeComboboxChange(Sender: TObject); 118 procedure InstrumentTypeComboboxChange(Sender: TObject);
105 procedure LengthEnabledCheckboxChange(Sender: TObject); 119 procedure LengthEnabledCheckboxChange(Sender: TObject);
@@ -110,20 +124,27 @@ type
110 procedure SweepDirectionComboboxChange(Sender: TObject); 124 procedure SweepDirectionComboboxChange(Sender: TObject);
111 procedure SweepSizeSpinnerChange(Sender: TObject); 125 procedure SweepSizeSpinnerChange(Sender: TObject);
112 procedure SweepTimeComboboxChange(Sender: TObject); 126 procedure SweepTimeComboboxChange(Sender: TObject);
127 procedure WaveformComboboxChange(Sender: TObject);
113 procedure WavePaintboxPaint(Sender: TObject); 128 procedure WavePaintboxPaint(Sender: TObject);
114 procedure WaveVolumeComboboxChange(Sender: TObject); 129 procedure WaveVolumeComboboxChange(Sender: TObject);
115 private 130 private
116 Song: TSong; 131 Song: TSong;
117 CurrentInstrument: ^TInstrument; 132 CurrentInstrument: ^TInstrument;
133 CurrentWave: ^TWave;
118 134
119 EmulationThread: TThread; 135 EmulationThread: TThread;
120 136
137 PreviewingInstrument: Boolean;
138
121 procedure ChangeToSquare; 139 procedure ChangeToSquare;
122 procedure ChangeToWave; 140 procedure ChangeToWave;
123 procedure ChangeToNoise; 141 procedure ChangeToNoise;
124 procedure LoadInstrument(Instr: Integer); 142 procedure LoadInstrument(Instr: Integer);
143 procedure LoadWave(Wave: Integer);
144
145 procedure DrawWaveform(PB: TPaintBox; Wave: TWave);
125 146
126 procedure PlayC4WithInstrument(Instr: Integer); 147 procedure PreviewInstrument(Freq: Integer; Instr: Integer);
127 public 148 public
128 149
129 end; 150 end;
@@ -137,33 +158,44 @@ implementation
137 158
138 { TfrmTracker } 159 { TfrmTracker }
139 160
140 const 161 procedure TfrmTracker.DrawWaveform(PB: TPaintBox; Wave: TWave);
141 NR10 = $FF10; 162 var
142 NR11 = $FF11; 163 Interval: Integer;
143 NR12 = $FF12; 164 I: Integer;
144 NR13 = $FF13; 165 W, H : Integer;
145 NR14 = $FF14; 166 begin
146 NR21 = $FF16; 167 W := PB.Width;
147 NR22 = $FF17; 168 H := PB.Height;
148 NR23 = $FF18; 169
149 NR24 = $FF19; 170 Interval := W div 32;
150 NR30 = $FF1A; 171 With PB.Canvas do begin
151 NR31 = $FF1B; 172 Brush.Color := clBlack;
152 NR32 = $FF1C; 173 Clear;
153 NR33 = $FF1D; 174
154 NR34 = $FF1E; 175 Brush.Color := clTeal;
155 NR41 = $FF20; 176 Pen.Color := clTeal;
156 NR42 = $FF21; 177 MoveTo(0, H);
157 NR43 = $FF22; 178 for I := 0 to 32 do
158 NR44 = $FF23; 179 LineTo(I*Interval, Round((Wave[I]/$F)*H));
159 180 LineTo(W, Round((Wave[0]/$F)*H));
160 procedure TfrmTracker.PlayC4WithInstrument(Instr: Integer); 181 end;
182 end;
183
184 procedure TfrmTracker.PreviewInstrument(Freq: Integer; Instr: Integer);
161 var 185 var
162 Regs: TRegisters; 186 Regs: TRegisters;
163 begin 187 begin
164 with Song.Instruments[Instr] do 188 with Song.Instruments[Instr] do
165 begin 189 begin
166 case Type_ of 190 case Type_ of
191 Square: begin
192 Regs := SquareInstrumentToRegisters(Freq, True, Song.Instruments[Instr]);
193 Spokeb(NR10, Regs.NR10);
194 Spokeb(NR11, Regs.NR11);
195 Spokeb(NR12, Regs.NR12);
196 Spokeb(NR13, Regs.NR13);
197 Spokeb(NR14, Regs.NR14);
198 end;
167 Noise: begin 199 Noise: begin
168 Regs := NoiseInstrumentToRegisters(True, Song.Instruments[Instr]); 200 Regs := NoiseInstrumentToRegisters(True, Song.Instruments[Instr]);
169 Spokeb(NR41, Regs.NR41); 201 Spokeb(NR41, Regs.NR41);
@@ -175,6 +207,12 @@ begin
175 end; 207 end;
176 end; 208 end;
177 209
210 procedure TfrmTracker.LoadWave(Wave: Integer);
211 begin
212 CurrentWave := @Song.Waves[Wave];
213 WaveEditPaintBox.Invalidate;
214 end;
215
178 procedure TfrmTracker.LoadInstrument(Instr: Integer); 216 procedure TfrmTracker.LoadInstrument(Instr: Integer);
179 var 217 var
180 CI: ^TInstrument; 218 CI: ^TInstrument;
@@ -187,6 +225,21 @@ begin
187 LengthEnabledCheckbox.Checked := CI^.LengthEnabled; 225 LengthEnabledCheckbox.Checked := CI^.LengthEnabled;
188 LengthSpinner.Position := CI^.Length; 226 LengthSpinner.Position := CI^.Length;
189 227
228 case CI^.Type_ of
229 Square: begin
230 InstrumentTypeComboBox.Text := 'Square';
231 ChangeToSquare;
232 end;
233 Wave: begin
234 InstrumentTypeComboBox.Text := 'Wave';
235 ChangeToWave;
236 end;
237 Noise: begin
238 InstrumentTypeComboBox.Text := 'Noise';
239 ChangeToNoise;
240 end;
241 end;
242
190 StartVolSpinner.Position := CI^.InitialVolume; 243 StartVolSpinner.Position := CI^.InitialVolume;
191 case CI^.VolSweepDirection of 244 case CI^.VolSweepDirection of
192 Up: DirectionComboBox.Text := 'Up'; 245 Up: DirectionComboBox.Text := 'Up';
@@ -250,10 +303,14 @@ end;
250 303
251 procedure TfrmTracker.WavePaintboxPaint(Sender: TObject); 304 procedure TfrmTracker.WavePaintboxPaint(Sender: TObject);
252 begin 305 begin
253 with WavePaintbox.Canvas do begin 306 if not WaveGroupBox.Enabled then begin
254 Brush.Color := clBlack; 307 with WavePaintbox.Canvas do begin
255 Clear; 308 Brush.Color := clBlack;
256 end; 309 Clear;
310 end;
311 end
312 else if WaveformCombobox.ItemIndex > -1 then
313 DrawWaveform(WavePaintbox, Song.Waves[WaveformCombobox.ItemIndex]);
257 end; 314 end;
258 315
259 procedure TfrmTracker.WaveVolumeComboboxChange(Sender: TObject); 316 procedure TfrmTracker.WaveVolumeComboboxChange(Sender: TObject);
@@ -263,10 +320,8 @@ end;
263 320
264 procedure TfrmTracker.PaintBox1Paint(Sender: TObject); 321 procedure TfrmTracker.PaintBox1Paint(Sender: TObject);
265 begin 322 begin
266 with PaintBox1.Canvas do begin 323 if WaveformCombobox.ItemIndex > -1 then
267 Brush.Color := clBlack; 324 DrawWaveform(PaintBox1, Song.Waves[WaveformCombobox.ItemIndex]);
268 Clear;
269 end;
270 end; 325 end;
271 326
272 procedure TfrmTracker.SevenBitCounterCheckboxChange(Sender: TObject); 327 procedure TfrmTracker.SevenBitCounterCheckboxChange(Sender: TObject);
@@ -305,6 +360,11 @@ begin
305 CurrentInstrument^.SweepTime := SweepTimeCombobox.ItemIndex; 360 CurrentInstrument^.SweepTime := SweepTimeCombobox.ItemIndex;
306 end; 361 end;
307 362
363 procedure TfrmTracker.WaveformComboboxChange(Sender: TObject);
364 begin
365 WavePaintbox.Invalidate;
366 end;
367
308 procedure TfrmTracker.InstrumentTypeComboboxChange(Sender: TObject); 368 procedure TfrmTracker.InstrumentTypeComboboxChange(Sender: TObject);
309 begin 369 begin
310 case InstrumentTypeComboBox.Text of 370 case InstrumentTypeComboBox.Text of
@@ -331,12 +391,12 @@ begin
331 LengthEnabledCheckbox.Checked := Random <= 0.5; 391 LengthEnabledCheckbox.Checked := Random <= 0.5;
332 LengthSpinner.Position := Random(Round(LengthSpinner.Max)); 392 LengthSpinner.Position := Random(Round(LengthSpinner.Max));
333 393
334 PlayC4WithInstrument(InstrumentNumberSpinner.Value); 394 PreviewInstrument(C_5, InstrumentNumberSpinner.Value);
335 end; 395 end;
336 396
337 procedure TfrmTracker.FormCreate(Sender: TObject); 397 procedure TfrmTracker.FormCreate(Sender: TObject);
338 var 398 var
339 I: Integer; 399 I, J: Integer;
340 begin 400 begin
341 for I := Low(Song.Instruments) to High(Song.Instruments) do 401 for I := Low(Song.Instruments) to High(Song.Instruments) do
342 with Song.Instruments[I] do begin 402 with Song.Instruments[I] do begin
@@ -354,13 +414,54 @@ begin
354 Duty := 2; 414 Duty := 2;
355 end; 415 end;
356 416
417 for I := Low(Song.Waves) to High(Song.Waves) do begin
418 for J := 0 to 32 do
419 Song.Waves[I][J] := random($F);
420 WaveformCombobox.Items.Add('Wave #' + IntToStr(I));
421 end;
422
357 LoadInstrument(1); 423 LoadInstrument(1);
424 LoadWave(1);
358 425
359 // Get the emulator ready to make sound... 426 // Get the emulator ready to make sound...
360 EmulationThread := TEmulationThread.Create; 427 EmulationThread := TEmulationThread.Create;
361 EmulationThread.Start; 428 EmulationThread.Start;
362 end; 429 end;
363 430
431 procedure TfrmTracker.FormKeyDown(Sender: TObject; var Key: Word;
432 Shift: TShiftState);
433 var
434 Freq: Integer;
435 begin
436 if PreviewingInstrument then exit;
437
438 Keybindings.TryGetData(Key, Freq);
439 if Freq <> 0 then
440 PreviewInstrument(Keybindings[Key], InstrumentNumberSpinner.Value);
441
442 PreviewingInstrument := True;
443 end;
444
445 procedure TfrmTracker.FormKeyUp(Sender: TObject; var Key: Word;
446 Shift: TShiftState);
447 begin
448 PreviewingInstrument := False;
449
450 // Silence channel 1
451 Spokeb(NR12, 0);
452 Spokeb(NR14, %10000000);
453 end;
454
455 procedure TfrmTracker.ImportWaveButtonClick(Sender: TObject);
456 var
457 F: file of byte;
458 begin
459 OpenDialog1.DefaultExt := '*.pcm';
460 if OpenDialog1.Execute then begin
461
462 end;
463 end;
464
364 procedure TfrmTracker.DirectionComboBoxChange(Sender: TObject); 465 procedure TfrmTracker.DirectionComboBoxChange(Sender: TObject);
365 begin 466 begin
366 case DirectionComboBox.Text of 467 case DirectionComboBox.Text of
@@ -419,7 +520,7 @@ end;
419 520
420 procedure TfrmTracker.MenuItem6Click(Sender: TObject); 521 procedure TfrmTracker.MenuItem6Click(Sender: TObject);
421 begin 522 begin
422 PlayC4WithInstrument(InstrumentNumberSpinner.Value); 523 PreviewInstrument(C_5, InstrumentNumberSpinner.Value);
423 {Spokeb($FF10, 0); 524 {Spokeb($FF10, 0);
424 Spokeb($FF11, %11111111); 525 Spokeb($FF11, %11111111);
425 Spokeb($FF12, %11110000); 526 Spokeb($FF12, %11110000);
@@ -432,6 +533,16 @@ begin
432 CurrentInstrument^.ShiftClockFreq := Round(NoiseFreqSpinner.Position); 533 CurrentInstrument^.ShiftClockFreq := Round(NoiseFreqSpinner.Position);
433 end; 534 end;
434 535
536 procedure TfrmTracker.WaveEditNumberSpinnerChange(Sender: TObject);
537 begin
538 LoadWave(WaveEditNumberSpinner.Value);
539 end;
540
541 procedure TfrmTracker.WaveEditPaintBoxPaint(Sender: TObject);
542 begin
543 DrawWaveform(WaveEditPaintBox, CurrentWave^);
544 end;
545
435 procedure TfrmTracker.LengthEnabledCheckboxChange(Sender: TObject); 546 procedure TfrmTracker.LengthEnabledCheckboxChange(Sender: TObject);
436 begin 547 begin
437 LengthSpinner.Enabled := LengthEnabledCheckbox.Checked; 548 LengthSpinner.Enabled := LengthEnabledCheckbox.Checked;
Modifiedutils.pas +45−7
@@ -10,6 +10,8 @@ uses
10 type 10 type
11 TRegisters = record 11 TRegisters = record
12 case Type_: TInstrumentType of 12 case Type_: TInstrumentType of
13 Square: (NR10, NR11, NR12, NR13, NR14: Byte);
14 Wave: (NR30, NR31, NR32, NR33, NR34: Byte);
13 Noise: (NR41, NR42, NR43, NR44: Byte); 15 Noise: (NR41, NR42, NR43, NR44: Byte);
14 end; 16 end;
15 17
@@ -31,19 +33,21 @@ function NoiseInstrumentToRegisters(
31 Initial: Boolean; 33 Initial: Boolean;
32 Instr: TInstrument): TRegisters; 34 Instr: TInstrument): TRegisters;
33 35
36 function SquareInstrumentToRegisters(
37 Frequency: Word;
38 Initial: Boolean;
39 Instr: TInstrument): TRegisters;
40
34 implementation 41 implementation
35 42
36 function BuildEnvelope( 43 function BuildEnvelope(
37 InitialVol: TEnvelopeVolume; 44 InitialVol: TEnvelopeVolume;
38 Direction: TSweepType; 45 Direction: TSweepType;
39 Amount: TEnvelopeSweepAmount): Byte; 46 Amount: TEnvelopeSweepAmount): Byte;
40 var
41 DirectionNumber: Integer;
42 begin 47 begin
43 if Direction = Up then DirectionNumber := 1
44 else DirectionNumber := 0;
45 Result := (InitialVol shl 4); 48 Result := (InitialVol shl 4);
46 Result := Result or (DirectionNumber shl 2); 49 if Direction = Up then
50 Result := Result or %00001000;
47 Result := Result or Amount; 51 Result := Result or Amount;
48 end; 52 end;
49 53
@@ -55,14 +59,14 @@ begin
55 Result := 0; 59 Result := 0;
56 if Initial then Result := %10000000; 60 if Initial then Result := %10000000;
57 if LengthEnabled then Result := Result or %01000000; 61 if LengthEnabled then Result := Result or %01000000;
58 Result := Result or Frequency; 62 Result := Result or ((Frequency and %0000011100000000) shr 8);
59 end; 63 end;
60 64
61 function BuildHighByte( 65 function BuildHighByte(
62 Initial: Boolean; 66 Initial: Boolean;
63 LengthEnabled: Boolean): Byte; 67 LengthEnabled: Boolean): Byte;
64 begin 68 begin
65 BuildHighByte(Initial, LengthEnabled, 0); 69 Result := BuildHighByte(Initial, LengthEnabled, 0);
66 end; 70 end;
67 71
68 function NoiseInstrumentToRegisters( 72 function NoiseInstrumentToRegisters(
@@ -89,5 +93,39 @@ begin
89 end; 93 end;
90 end; 94 end;
91 95
96 function SquareInstrumentToRegisters(
97 Frequency: Word;
98 Initial: Boolean;
99 Instr: TInstrument): TRegisters;
100
101 function BuildSweep(
102 SweepTime: Integer;
103 SweepIncDec: TSweepType;
104 SweepShift: Integer): Byte;
105 begin
106 Result := (SweepTime shl 4);
107 if SweepIncDec = Down then
108 Result := Result or %00001000;
109 Result := Result or SweepShift;
110 end;
111
112 function BuildLengthDuty(
113 Duty: TDutyType;
114 Length: Integer): Byte;
115 begin
116 Result := Duty shl 6;
117 Result := Result or Length;
118 end;
119
120 begin
121 with Instr do begin
122 Result.NR10 := BuildSweep(SweepTime, SweepIncDec, SweepShift);
123 Result.NR11 := BuildLengthDuty(Duty, Length);
124 Result.NR12 := BuildEnvelope(InitialVolume, VolSweepDirection, VolSweepAmount);
125 Result.NR13 := (Frequency and %0000000011111111);
126 Result.NR14 := BuildHighByte(Initial, LengthEnabled, Frequency);
127 end;
128 end;
129
92 end. 130 end.
93 131
Addedwaves.pas +16−0
@@ -0,0 +1,16 @@
1 unit Waves;
2
3 {$mode delphi}
4
5 interface
6
7 uses
8 Classes, SysUtils;
9
10 type
11 TWave = array[0..32] of Byte;
12
13 implementation
14
15 end.
16