-
-
Notifications
You must be signed in to change notification settings - Fork 187
/
vgm.hexpat
248 lines (221 loc) · 5.16 KB
/
vgm.hexpat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#pragma author applecuckoo
#pragma description VGM (Video Game Music) sound log
#pragma endian little
import type.magic;
import std.string;
import std.io;
u32 versionValue;
u32 gd3TagPos;
u32 chpClkBase;
u32 chpVolBase;
// note: the versionValue variable exists to help check which fields exist and which don't, otherwise the actual log data would show up as part of the header.
bitfield VGMVersion {
bugfix : 4;
minor : 4;
major : 24;
versionValue = major * 100 + minor * 10 + bugfix;
} [[format("format_VGMVersion")]];
fn format_VGMVersion(auto version) {
return std::format("{}.{}{}", version.major, version.minor, version.bugfix);
};
bitfield SN76489Flags {
frequency : 1;
negateOutput : 1;
GameGearStereo : 1;
clockDiv : 1;
XNORNoiseMode : 1;
padding : 3;
};
bitfield AY8910Flags {
legacyOutput : 1;
singleOutput : 1;
discreteOutput : 1;
RAWOutput : 1;
YMclockDivLow : 1;
padding : 3;
};
bitfield OKIM6258Flags {
clockDiv : 2;
ADPCMsel : 1;
outputBitDepth : 1;
padding : 4;
};
bitfield K054539Flags {
reverseStereo : 1;
disableReverb : 1;
KeyOnUpdate : 1;
padding : 5;
};
enum AY8190Type : u8 {
AY8910,
AY8912,
AY8913,
AY8914,
YM2149 = 0x10,
YM3439,
YMZ284,
YMZ294,
};
enum C140Type : u8 {
C140_NamcoSystem2,
C140_NamcoSystem21,
ASIC219_NamcoNA,
};
struct Gd3 {
type::Magic<"Gd3 "> ident;
VGMVersion version;
u32 Gd3Length;
std::string::NullString16 trackNameEng;
std::string::NullString16 trackNameOriginal;
std::string::NullString16 gameNameEng;
std::string::NullString16 gameNameOriginal;
std::string::NullString16 sysNameEng;
std::string::NullString16 sysNameOriginal;
std::string::NullString16 trackAuthorEnglish;
std::string::NullString16 trackAuthorOriginal;
std::string::NullString16 gameReleaseDate;
std::string::NullString16 VGMConverter;
std::string::NullString16 Notes;
};
struct baseHeader {
type::Magic<"Vgm "> ident;
u32 eofOffset;
VGMVersion version;
u32 SN76489_clk;
u32 YM2413_clk;
gd3TagPos = $;
u32 Gd3Offset;
u32 sampleCount;
u32 loopOffset;
u32 loopSamples;
};
struct Header : baseHeader {
if (versionValue >= 101) {
u32 rate;
} if (versionValue >= 110) {
u16 SN76489_feedback;
u8 SN76489_shift_width;
} if (versionValue >= 151) {
SN76489Flags snflags;
} else {
padding[1];
} if (versionValue >= 110) {
u32 YM2612_clk;
u32 YM2151_clk;
} if (versionValue >= 150) {
u32 VGMOffset;
} if (versionValue >= 151) {
u32 SegaPCM_clk;
u32 SegaPCM_reg;
u32 RF5C68_clk;
u32 YM2203_clk;
u32 YM2608_clk;
u32 YM2610_clk;
u32 YM3812_clk;
u32 YM3526_clk;
u32 Y8950_clk;
u32 YMF262_clk;
u32 YMF278B_clk;
u32 YMF271_clk;
u32 YMZ280B_clk;
u32 RF5C164_clk;
u32 PWM_clk;
u32 AY8910_clk;
AY8190Type AY8910_type;
AY8910Flags AY8910_flags;
u8 YM2203_flags;
u8 YM2608_flags;
} if (versionValue >= 160) {
u8 volumeMod;
padding[1];
u8 loopBase;
} else {
padding[3];
} if (versionValue >= 151) {
u8 loopMod;
} if (versionValue >= 161) {
u32 DMG_clk;
u32 APU_clk;
u32 MultiPCM_clk;
u32 uPD7759_clk;
u32 OKIM6258_clk;
OKIM6258Flags OKIM6258_flags;
K054539Flags K054539_flags;
C140Type C140_type;
padding[1];
u32 OKIM6295_clk;
u32 K051649_clk;
u32 K054539_clk;
u32 HuC6280_clk;
u32 C140_clk;
u32 K053260_clk;
u32 Pokey_clk;
u32 QSound_clk;
} if (versionValue >= 171) {
u32 SCSP_clk;
} else {
padding[4];
} if (versionValue >= 170) {
u32 extraHeaderOffset;
} if (versionValue >= 171) {
u32 WonderSwan_clk;
u32 VSU_clk;
u32 SAA1099_clk;
u32 ES5503_clk;
u32 ES5005_clk;
u8 ES5503_ch;
u8 ES5505_ch;
u8 C352_clockDiv;
padding[1];
u32 X1_010_clk;
u32 C352_clk;
u32 GA20_clk;
} if (versionValue > 172) {
u32 Mikey_clk;
}
};
struct chpClkEntry {
u8 chpID;
u32 chpClk;
};
struct chpClkHeader {
u8 entryCount;
chpClkEntry entries[entryCount];
};
bitfield chpVolume {
volume : 15;
absoluteRelative : 1;
};
struct chpVolEntry {
u8 chpID;
u8 flags;
chpVolume chpVol;
};
struct chpVolHeader {
u8 entryCount;
chpVolEntry entries[entryCount];
};
struct ExtraHeader {
u32 headerSize;
chpClkBase = $;
u32 chpClkOffset;
chpVolBase = $;
u32 chpVolOffset;
if (chpClkOffset > 0) {
$ = chpClkBase + chpClkOffset;
chpClkHeader chpClk;
} if (chpVolOffset > 0) {
$ = chpVolBase + chpVolOffset;
chpVolHeader chpVol;
}
};
struct VGM {
Header header;
if (versionValue >= 170) {
if (header.extraHeaderOffset > 0) {
ExtraHeader extraHeader;
}
}
Gd3 tag @ (gd3TagPos + header.Gd3Offset);
};
VGM vgm @ 0x00;