Files: 7546e2f74d2ea029c47a53149da67f11f39cb16a / src / syntrax / file.c
13104 bytesRaw
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | size_t filesize; |
9 | |
10 | Song* File_loadSong(const char *path) |
11 | { |
12 | Song *synSong; |
13 | FILE *f; |
14 | uint8_t *buffer; |
15 | size_t size; |
16 | |
17 | if (!(f = fopen(path, "rb"))) return NULL; |
18 | |
19 | fseek(f, 0, SEEK_END); |
20 | size = ftell(f); |
21 | fseek(f, 0, SEEK_SET); |
22 | |
23 | if (!(buffer = (uint8_t *) malloc(size))) { |
24 | fclose(f); |
25 | return NULL; |
26 | } |
27 | |
28 | if (fread(buffer, 1, size, f) != size) { |
29 | free(buffer); |
30 | fclose(f); |
31 | return NULL; |
32 | } |
33 | |
34 | fclose(f); |
35 | |
36 | synSong = File_loadSongMem(buffer, size); |
37 | |
38 | free(buffer); |
39 | |
40 | return synSong; |
41 | } |
42 | |
43 | uint16_t get_le16(const void *p) |
44 | { |
45 | return (((const uint8_t*)p)[0]) + |
46 | (((const uint8_t*)p)[1]) * 0x100; |
47 | } |
48 | |
49 | uint32_t get_le32(const void *p) |
50 | { |
51 | return (((const uint8_t*)p)[0]) + |
52 | (((const uint8_t*)p)[1]) * 0x100 + |
53 | (((const uint8_t*)p)[2]) * 0x10000 + |
54 | (((const uint8_t*)p)[3]) * 0x1000000; |
55 | } |
56 | |
57 | static long File_readHeader(SongHeader *h, const uint8_t *buffer, size_t size) |
58 | { |
59 | if (size < 52) return -1; |
60 | |
61 | h->version = get_le16(buffer); |
62 | h->UNK00 = get_le16(buffer + 2); |
63 | h->patNum = get_le32(buffer + 4); |
64 | h->subsongNum = get_le32(buffer + 8); |
65 | h->instrNum = get_le32(buffer + 12); |
66 | h->UNK01 = get_le32(buffer + 16); |
67 | h->UNK02 = get_le16(buffer + 20); |
68 | h->UNK03 = get_le16(buffer + 22); |
69 | h->UNK04 = get_le16(buffer + 24); |
70 | h->UNK05 = get_le16(buffer + 26); |
71 | h->UNK06 = get_le16(buffer + 28); |
72 | h->UNK07 = get_le16(buffer + 30); |
73 | h->UNK08 = get_le16(buffer + 32); |
74 | h->UNK09 = get_le16(buffer + 34); |
75 | h->UNK0A = get_le16(buffer + 36); |
76 | h->UNK0B = get_le16(buffer + 38); |
77 | h->UNK0C = get_le16(buffer + 40); |
78 | h->UNK0D = get_le16(buffer + 42); |
79 | h->UNK0E = get_le16(buffer + 44); |
80 | h->UNK0F = get_le16(buffer + 46); |
81 | h->UNK10 = get_le16(buffer + 48); |
82 | h->UNK11 = get_le16(buffer + 50); |
83 | |
84 | return 52; |
85 | } |
86 | |
87 | static long File_readSubSong(Subsong *subSong, const uint8_t *buffer, size_t size) |
88 | { |
89 | int i, j; |
90 | |
91 | if (size < 16564) return -1; |
92 | |
93 | for (i = 0; i < 16; i++) |
94 | subSong->UNK00[i] = get_le32(buffer + i * 4); |
95 | |
96 | for (i = 0; i < SE_MAXCHANS; i++) |
97 | subSong->mutedChans[i] = buffer[64 + i]; |
98 | |
99 | subSong->tempo = get_le32(buffer + 80); |
100 | subSong->groove = get_le32(buffer + 84); |
101 | subSong->startPosCoarse = get_le32(buffer + 88); |
102 | subSong->startPosFine = get_le32(buffer + 92); |
103 | subSong->endPosCoarse = get_le32(buffer + 96); |
104 | subSong->endPosFine = get_le32(buffer + 100); |
105 | subSong->loopPosCoarse = get_le32(buffer + 104); |
106 | subSong->loopPosFine = get_le32(buffer + 108); |
107 | subSong->isLooping = get_le16(buffer + 112); |
108 | |
109 | memcpy(subSong->m_Name, buffer + 114, 32); |
110 | subSong->m_Name[32] = '\0'; |
111 | |
112 | subSong->channelNumber = get_le16(buffer + 146); |
113 | subSong->delayTime = get_le16(buffer + 148); |
114 | |
115 | for (i = 0; i < SE_MAXCHANS; i++) |
116 | subSong->chanDelayAmt[i] = buffer[150 + i]; |
117 | |
118 | subSong->amplification = get_le16(buffer + 166); |
119 | |
120 | subSong->UNK01 = get_le16(buffer + 168); |
121 | subSong->UNK02 = get_le16(buffer + 170); |
122 | subSong->UNK03 = get_le16(buffer + 172); |
123 | subSong->UNK04 = get_le16(buffer + 174); |
124 | subSong->UNK05 = get_le16(buffer + 176); |
125 | subSong->UNK06 = get_le16(buffer + 178); |
126 | |
127 | for (i = 0; i < SE_MAXCHANS; i++) { |
128 | for (j = 0; j < 0x100; j++) { |
129 | subSong->orders[i][j].patIndex = get_le16(buffer + 180 + i * 1024 + j * 4); |
130 | subSong->orders[i][j].patLen = get_le16(buffer + 180 + i * 1024 + j * 4 + 2); |
131 | } |
132 | } |
133 | |
134 | return 16564; |
135 | } |
136 | |
137 | long File_readRow(Row *r, const uint8_t *buffer, size_t size) |
138 | { |
139 | if (size < 5) return -1; |
140 | |
141 | r->note = buffer[0]; |
142 | r->dest = buffer[1]; |
143 | r->instr = buffer[2]; |
144 | r->spd = buffer[3]; |
145 | r->command = buffer[4]; |
146 | |
147 | return 5; |
148 | } |
149 | |
150 | static long File_readInstrumentEffect(InstrumentEffect *effect, const uint8_t *buffer, size_t size) |
151 | { |
152 | if (size < 40) return -1; |
153 | |
154 | effect->destWave = get_le32(buffer); |
155 | effect->srcWave1 = get_le32(buffer + 4); |
156 | effect->srcWave2 = get_le32(buffer + 8); |
157 | effect->oscWave = get_le32(buffer + 12); |
158 | effect->variable1 = get_le32(buffer + 16); |
159 | effect->variable2 = get_le32(buffer + 20); |
160 | effect->fxSpeed = get_le32(buffer + 24); |
161 | effect->oscSpeed = get_le32(buffer + 28); |
162 | effect->effectType = get_le32(buffer + 32); |
163 | effect->oscSelect = buffer[36]; |
164 | effect->resetEffect = buffer[37]; |
165 | effect->UNK00 = get_le16(buffer + 38); |
166 | |
167 | return 40; |
168 | } |
169 | |
170 | static long File_readInstrument(Instrument *instr, const uint8_t *buffer, size_t size) |
171 | { |
172 | int i, j; |
173 | long sizeRead; |
174 | |
175 | if (size < 8712) return -1; |
176 | |
177 | instr->version = get_le16(buffer); |
178 | |
179 | memcpy(instr->name, buffer + 2, 32); |
180 | instr->name[32] = '\0'; |
181 | |
182 | instr->waveform = get_le16(buffer + 34); |
183 | instr->wavelength = get_le16(buffer + 36); |
184 | instr->masterVolume = get_le16(buffer + 38); |
185 | instr->amWave = get_le16(buffer + 40); |
186 | instr->amSpeed = get_le16(buffer + 42); |
187 | instr->amLoopPoint = get_le16(buffer + 44); |
188 | instr->finetune = get_le16(buffer + 46); |
189 | instr->fmWave = get_le16(buffer + 48); |
190 | instr->fmSpeed = get_le16(buffer + 50); |
191 | instr->fmLoopPoint = get_le16(buffer + 52); |
192 | instr->fmDelay = get_le16(buffer + 54); |
193 | instr->arpIndex = get_le16(buffer + 56); |
194 | |
195 | for (i = 0; i < SE_MAXCHANS; i++) |
196 | instr->m_ResetWave[i] = buffer[58 + i]; |
197 | |
198 | instr->panWave = get_le16(buffer + 74); |
199 | instr->panSpeed = get_le16(buffer + 76); |
200 | instr->panLoopPoint = get_le16(buffer + 78); |
201 | instr->UNK00 = get_le16(buffer + 80); |
202 | instr->UNK01 = get_le16(buffer + 82); |
203 | instr->UNK02 = get_le16(buffer + 84); |
204 | instr->UNK03 = get_le16(buffer + 86); |
205 | instr->UNK04 = get_le16(buffer + 88); |
206 | instr->UNK05 = get_le16(buffer + 90); |
207 | |
208 | buffer += 92; size -= 92; |
209 | |
210 | for (i = 0; i < 4; i++) { |
211 | sizeRead = File_readInstrumentEffect(&instr->effects[i], buffer, size); |
212 | if (sizeRead < 0) return -1; |
213 | buffer += sizeRead; size -= sizeRead; |
214 | } |
215 | |
216 | memcpy(instr->smpFullImportPath, buffer, 192); |
217 | instr->smpFullImportPath[192] = '\0'; |
218 | |
219 | buffer += 192; size -= 192; |
220 | |
221 | instr->UNK06 = get_le32(buffer); |
222 | instr->UNK07 = get_le32(buffer + 4); |
223 | instr->UNK08 = get_le32(buffer + 8); |
224 | instr->UNK09 = get_le32(buffer + 12); |
225 | instr->UNK0A = get_le32(buffer + 16); |
226 | instr->UNK0B = get_le32(buffer + 20); |
227 | instr->UNK0C = get_le32(buffer + 24); |
228 | instr->UNK0D = get_le32(buffer + 28); |
229 | instr->UNK0E = get_le32(buffer + 32); |
230 | instr->UNK0F = get_le32(buffer + 36); |
231 | instr->UNK10 = get_le32(buffer + 40); |
232 | instr->UNK11 = get_le32(buffer + 44); |
233 | instr->UNK12 = get_le16(buffer + 48); |
234 | |
235 | buffer += 50; size -= 50; |
236 | |
237 | instr->shareSmpDataFromInstr = get_le16(buffer); |
238 | instr->hasLoop = get_le16(buffer + 2); |
239 | instr->hasBidiLoop = get_le16(buffer + 4); |
240 | |
241 | buffer += 6; size -= 6; |
242 | |
243 | instr->smpStartPoint = get_le32(buffer); |
244 | instr->smpLoopPoint = get_le32(buffer + 4); |
245 | instr->smpEndPoint = get_le32(buffer + 8); |
246 | instr->hasSample = get_le32(buffer + 12); |
247 | instr->smpLength = get_le32(buffer + 16); |
248 | |
249 | buffer += 20; size -= 20; |
250 | |
251 | for (i = 0; i < SE_MAXCHANS; i++) { |
252 | for (j = 0; j < 0x100; j++) { |
253 | instr->synthBuffers[i][j] = get_le16(buffer + i * 512 + j * 2); |
254 | } |
255 | } |
256 | |
257 | return 8712; |
258 | } |
259 | |
260 | Song* File_loadSongMem(const uint8_t *buffer, size_t size) |
261 | { |
262 | int i, j, k; |
263 | int songVer; |
264 | Subsong *subs; |
265 | Order *orderCol; |
266 | Order *order; |
267 | Row *row; |
268 | Instrument *instr; |
269 | Song *synSong; |
270 | long sizeRead; |
271 | |
272 | synSong = (Song *) calloc(1, sizeof(Song)); |
273 | if (!synSong) return NULL; |
274 | |
275 | /* |
276 | //unused vars |
277 | int8_t _local5[] = [0, 0, 0, 0, 0, 0]; |
278 | bool _local2 = false; |
279 | int _local7 = 0; |
280 | bool _local8 = true; |
281 | */ |
282 | |
283 | sizeRead = File_readHeader(&synSong->h, buffer, size); |
284 | if (sizeRead < 0) goto FAIL; |
285 | buffer += sizeRead; size -= sizeRead; |
286 | |
287 | songVer = synSong->h.version; |
288 | if ((songVer >= 3456) && (songVer <= 3457)){ |
289 | if (synSong->h.subsongNum > 0){ |
290 | synSong->subsongs = (Subsong *) malloc(synSong->h.subsongNum *sizeof(Subsong)); |
291 | if (!synSong->subsongs) goto FAIL; |
292 | |
293 | for (i = 0; i < synSong->h.subsongNum; i++) { |
294 | sizeRead = File_readSubSong(synSong->subsongs + i, buffer, size); |
295 | if (sizeRead < 0) goto FAIL; |
296 | buffer += sizeRead; size -= sizeRead; |
297 | } |
298 | |
299 | synSong->rows = (Row *) malloc(synSong->h.patNum * 64 *sizeof(Row)); |
300 | if (!synSong->rows) goto FAIL; |
301 | |
302 | for (i = 0, j = synSong->h.patNum * 64; i < j; i++) { |
303 | sizeRead = File_readRow(synSong->rows + i, buffer, size); |
304 | if (sizeRead < 0) goto FAIL; |
305 | buffer += sizeRead; size -= sizeRead; |
306 | } |
307 | |
308 | synSong->patNameSizes = (uint32_t *) malloc(synSong->h.patNum * sizeof(uint32_t)); |
309 | if (!synSong->patNameSizes) goto FAIL; |
310 | synSong->patternNames = calloc(sizeof(char *), synSong->h.patNum); |
311 | if (!synSong->patternNames) goto FAIL; |
312 | |
313 | for (i = 0; i < synSong->h.patNum; i++) { |
314 | if (size < 4) goto FAIL; |
315 | j = synSong->patNameSizes[i] = get_le32(buffer); |
316 | buffer += 4; size -= 4; |
317 | |
318 | if (size < j) goto FAIL; |
319 | |
320 | synSong->patternNames[i] = malloc(j + sizeof(char)); |
321 | if (!synSong->patternNames[i]) goto FAIL; |
322 | |
323 | memcpy(synSong->patternNames[i], buffer, j); |
324 | synSong->patternNames[i][j] = '\0'; |
325 | |
326 | buffer += j; size -= j; |
327 | } |
328 | |
329 | synSong->instruments = malloc(synSong->h.instrNum * sizeof(Instrument)); |
330 | if (!synSong->instruments) goto FAIL; |
331 | synSong->samples = calloc(sizeof(int16_t *), synSong->h.instrNum); |
332 | if (!synSong->samples) goto FAIL; |
333 | |
334 | for (i = 0; i < synSong->h.instrNum; i++) { |
335 | instr = &synSong->instruments[i]; |
336 | sizeRead = File_readInstrument(instr, buffer, size); |
337 | if (sizeRead < 0) goto FAIL; |
338 | buffer += sizeRead; size -= sizeRead; |
339 | |
340 | if (songVer == 3456){ |
341 | instr->shareSmpDataFromInstr = 0; |
342 | instr->hasLoop = 0; |
343 | instr->hasBidiLoop = 0; |
344 | instr->smpStartPoint = 0; |
345 | instr->smpLoopPoint = 0; |
346 | instr->smpEndPoint = 0; |
347 | if (instr->hasSample){ |
348 | instr->smpStartPoint = 0; |
349 | instr->smpEndPoint = (instr->smpLength / 2); |
350 | instr->smpLoopPoint = 0; |
351 | } |
352 | } |
353 | if (instr->hasSample){ |
354 | //instr->smpLength is in bytes, I think |
355 | if (size < instr->smpLength) goto FAIL; |
356 | synSong->samples[i] = malloc(instr->smpLength); |
357 | if (!synSong->samples[i]) goto FAIL; |
358 | memcpy(synSong->samples[i], buffer, instr->smpLength); |
359 | buffer += instr->smpLength; size -= instr->smpLength; |
360 | } else { |
361 | synSong->samples[i] = NULL; |
362 | } |
363 | |
364 | } |
365 | memcpy(synSong->arpTable, buffer, 0x100); |
366 | buffer += 0x100; size -= 0x100; |
367 | } else goto FAIL; |
368 | } else goto FAIL; |
369 | |
370 | return synSong; |
371 | |
372 | FAIL: |
373 | File_freeSong(synSong); |
374 | return NULL; |
375 | } |
376 | |
377 | void File_freeSong(Song *synSong) |
378 | { |
379 | int i; |
380 | |
381 | if (synSong) { |
382 | if (synSong->subsongs) free(synSong->subsongs); |
383 | if (synSong->rows) free(synSong->rows); |
384 | if (synSong->patNameSizes) free(synSong->patNameSizes); |
385 | if (synSong->patternNames) { |
386 | for (i = 0; i < synSong->h.patNum; i++) { |
387 | if (synSong->patternNames[i]) free(synSong->patternNames[i]); |
388 | } |
389 | free(synSong->patternNames); |
390 | } |
391 | if (synSong->instruments) free(synSong->instruments); |
392 | if (synSong->samples) { |
393 | for (i = 0; i < synSong->h.instrNum; i++) { |
394 | if (synSong->samples[i]) free(synSong->samples[i]); |
395 | } |
396 | free(synSong->samples); |
397 | } |
398 | free(synSong); |
399 | } |
400 | } |
401 |
Built with git-ssb-web