History

Big code change, read description

1) Don't calculate big LUTs for mixer deltas on init (was just a waste of RAM) 2) The mixer now uses a 64-bit division to calculate max number of safe samples to mix (branchless), instead of using a big hackish LUT for DIV->MUL 3) Module and sample loaders have been refactored so that it's much simpler to write new loaders (or modify the old ones) 4) Added support for importing DIGI Booster (non-Pro) modules 5) Added support for importing 8-channel StarTrekker modules 6) Updated help text 7) Some more minor code change 8) Updated the Visual Studio project and make scripts to include the new loaders * Sorry for not making individual commits for all the changes, but at this point it was simply too difficult for me to do so!

Olav Sørensen committed 5 years ago

Commit 12f28da1 parent 2c1dbb237 files · +6956 −6838Browse files

Showing the changes to src/ft2_module_loader.c (1 of 37 files). Show all

Unified · Split

src/ft2_module_loader.c+248−2315
@@ -10,7 +10,6 @@ · 9 unmodified lines
10#include <unistd.h>10#include <unistd.h>
11#endif11#endif
12#include "ft2_header.h"12#include "ft2_header.h"
13#include "ft2_config.h"
14#include "ft2_scopes.h"13#include "ft2_scopes.h"
15#include "ft2_trim.h"14#include "ft2_trim.h"
16#include "ft2_inst_ed.h"15#include "ft2_inst_ed.h"
@@ -24,1857 +23,206 @@ · 7 unmodified lines
24#include "ft2_midi.h"23#include "ft2_midi.h"
25#include "ft2_events.h"24#include "ft2_events.h"
26#include "ft2_video.h"25#include "ft2_video.h"
27#include "ft2_tables.h"
28#include "ft2_structs.h"26#include "ft2_structs.h"
27#include "ft2_sysreqs.h"
29 28
30/* This is a *HUGE* mess!29bool loadDIGI(FILE *f, uint32_t filesize);
31** I hope you never have to modify it, and you probably shouldn't either.30bool loadMOD(FILE *f, uint32_t filesize);
32** You will experience a lot of headaches if you dig into this file...31bool loadS3M(FILE *f, uint32_t filesize);
33** If something looks to be wrong, it's probably right!32bool loadSTK(FILE *f, uint32_t filesize);
34**33bool loadSTM(FILE *f, uint32_t filesize);
35** The actual module load routines are ported from FT2 and slightly modified.34bool loadXM(FILE *f, uint32_t filesize);
36*/
37 35
38enum36enum
39{37{
40 FORMAT_NONE = 0,38 FORMAT_UNKNOWN = 0,
41 FORMAT_XM = 1,39 FORMAT_POSSIBLY_STK = 1,
42 FORMAT_MOD = 2,40 FORMAT_XM = 2,
43 FORMAT_S3M = 3,41 FORMAT_MOD = 3,
44 FORMAT_STM = 442 FORMAT_S3M = 4,
43 FORMAT_STM = 5,
44 FORMAT_DIGI = 6
45};45};
46 46
47// .MOD types47// file extensions accepted by Disk Op. in module mode
48enum48char *supportedModExtensions[] =
49{
50 FORMAT_MK, // ProTracker or compatible
51 FORMAT_FLT, // StarTrekker (4-channel modules only)
52 FORMAT_FT2, // FT2 (or other trackers, multichannel)
53 FORMAT_STK, // The Ultimate SoundTracker (15 samples)
54 FORMAT_NT, // NoiseTracker
55 FORMAT_HMNT, // His Master's NoiseTracker (special one)
56
57 FORMAT_UNKNOWN // may be The Ultimate Soundtracker (set to FORMAT_STK later)
58};
59
60// DO NOT TOUCH THESE STRUCTS!
61
62#ifdef _MSC_VER
63#pragma pack(push)
64#pragma pack(1)
65#endif
66typedef struct songSTMinstrHeaderTyp_t
67{
68 char name[12];
69 uint8_t nul, insDisk;
70 uint16_t reserved1, len, repS, repE;
71 uint8_t vol, reserved2;
72 uint16_t rate;
73 int32_t reserved3;
74 uint16_t paraLen;
75}
76#ifdef __GNUC__
77__attribute__ ((packed))
78#endif
79songSTMinstrHeaderTyp;
80
81typedef struct songSTMHeaderTyp_t
82{
83 char name[20], sig[8];
84 uint8_t id1a, typ;
85 uint8_t verMajor, verMinor;
86 uint8_t tempo, ap, vol, reserved[13];
87 songSTMinstrHeaderTyp instr[31];
88 uint8_t songTab[128];
89}
90#ifdef __GNUC__
91__attribute__ ((packed))
92#endif
93songSTMHeaderTyp;
94
95typedef struct songS3MinstrHeaderTyp_t
96{
97 uint8_t typ;
98 char dosName[12];
99 uint8_t memSegH;
100 uint16_t memSeg;
101 int32_t len, repS, repE;
102 uint8_t vol, dsk, pack, flags;
103 int32_t c2Spd, res1;
104 uint16_t gusPos;
105 uint8_t res2[6];
106 char name[28], id[4];
107}
108#ifdef __GNUC__
109__attribute__ ((packed))
110#endif
111songS3MinstrHeaderTyp;
112
113typedef struct songS3MHeaderTyp_t
114{
115 char name[28];
116 uint8_t id1a, typ;
117 uint16_t res1;
118 int16_t songTabLen, antInstr, antPatt;
119 uint16_t flags, trackerID, ver;
120 char id[4];
121 uint8_t globalVol, defSpeed, defTempo, masterVol, res2[12], chanType[32];
122}
123#ifdef __GNUC__
124__attribute__ ((packed))
125#endif
126songS3MHeaderTyp;
127#ifdef _MSC_VER
128#pragma pack(pop)
129#endif
130
131static volatile uint8_t loadedFormat;
132static volatile bool linearFreqTable, musicIsLoading, moduleLoaded, moduleFailedToLoad;
133static uint8_t oldPlayMode, pattBuff[12288], packedPattData[65536];
134static const uint8_t stmEff[16] = { 0, 0, 11, 0, 10, 2, 1, 3, 4, 7, 0, 5 ,6, 0, 0, 0 };
135static SDL_Thread *thread;
136
137// these temporarily read to, then copied to real struct if load was OK (should not need to be volatile'd)
138static int16_t pattLensTmp[MAX_PATTERNS];
139static uint32_t extraSampleLengths[32-MAX_SMP_PER_INST]; // ModPlug Tracker & OpenMPT supports up to 32 samples per instrument in .XM
140static tonTyp *pattTmp[MAX_PATTERNS];
141static instrTyp *instrTmp[1+256];
142static songTyp songTmp;
143
144static void setupLoadedModule(void);
145static void freeTmpModule(void);
146static bool loadInstrHeader(FILE *f, uint16_t i, bool externalThreadFlag);
147static bool loadInstrSample(FILE *f, uint16_t i, bool externalThreadFlag);
148void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn);
149static bool tmpPatternEmpty(uint16_t nr);
150static bool loadPatterns(FILE *f, uint16_t antPtn, bool externalThreadFlag);
151
152void checkSampleRepeat(sampleTyp *s);
153
154// ft2_replayer.c
155extern const char modSig[32][5];
156
157static bool allocateTmpInstr(int16_t nr)
158{
159 if (instrTmp[nr] != NULL)
160 return false; // already allocated
161
162 instrTyp *p = (instrTyp *)calloc(1, sizeof (instrTyp));
163 if (p == NULL)
164 return false;
165
166 sampleTyp *s = p->samp;
167 for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++)
168 {
169 s->pan = 128;
170 s->vol = 64;
171 }
172
173 instrTmp[nr] = p;
174 return true;
175}
176
177#define IS_ID(s, b) !strncmp(s, b, 4)
178
179static uint8_t getModType(uint8_t *numChannels, const char *id)
180{
181 uint8_t modFormat = FORMAT_UNKNOWN;
182 *numChannels = 4;
183
184 if (IS_ID("M.K.", id) || IS_ID("M!K!", id) || IS_ID("NSMS", id) || IS_ID("LARD", id) || IS_ID("PATT", id))
185 {
186 modFormat = FORMAT_MK; // ProTracker or compatible
187 }
188 else if (id[1] == 'C' && id[2] == 'H' && id[3] == 'N')
189 {
190 modFormat = FORMAT_FT2; // FT2 or generic multichannel
191 *numChannels = id[0] - '0';
192 }
193 else if (id[2] == 'C' && (id[3] == 'H' || id[3] == 'N'))
194 {
195 modFormat = FORMAT_FT2; // FT2 or generic multichannel
196 *numChannels = ((id[0] - '0') * 10) + (id[1] - '0');
197 }
198 else if (IS_ID("FLT4", id))
199 {
200 modFormat = FORMAT_FLT; // StarTrekker (4-channel modules only)
201 }
202 else if (IS_ID("N.T.", id))
203 {
204 modFormat = FORMAT_NT; // NoiseTracker
205 }
206 else if (IS_ID("M&K!", id) || IS_ID("FEST", id))
207 {
208 modFormat = FORMAT_HMNT; // His Master's NoiseTracker
209 }
210
211 return modFormat;
212}
213
214static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool externalThreadFlag)
215{
216 char ID[16];
217 uint8_t bytes[4], modFormat, numChannels;
218 int16_t i, j, k, ai;
219 uint16_t a, b, period;
220 tonTyp *ton;
221 sampleTyp *s;
222 songMOD31HeaderTyp h_MOD31;
223 songMOD15HeaderTyp h_MOD15;
224 int16_t (*showMsg)(int16_t, const char *, const char *);
225
226 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
227
228 bool veryLateSTKVerFlag = false; // "DFJ SoundTracker III" nad later
229 bool lateSTKVerFlag = false; // "TJC SoundTracker II" and later
230 bool mightBeSTK = false;
231
232 memset(&songTmp, 0, sizeof (songTmp));
233 memset(&h_MOD31, 0, sizeof (songMOD31HeaderTyp));
234 memset(&h_MOD15, 0, sizeof (songMOD15HeaderTyp));
235
236 // start loading MOD
237
238 loadedFormat = FORMAT_MOD;
239
240 rewind(f);
241 fread(ID, 1, 16, f);
242 fseek(f, 0x1D, SEEK_SET);
243 fread(bytes, 1, 1, f);
244 rewind(f);
245
246 // since .mod is the last format tested, check if the file is an .it module (Impulse Tracker)
247 if (!memcmp(ID, "IMPM", 4) && bytes[0] == 0)
248 {
249 showMsg(0, "System message", "Error: Impulse Tracker modules are not supported!");
250 goto modLoadError;
251 }
252
253 // check if the file to load is a WAV, if so reject it
254 if (!memcmp(ID, "RIFF", 4) && !memcmp(&ID[8], "WAVEfmt", 7))
255 {
256 showMsg(0, "System message", "Error: Can't load a .wav file as a module!");
257 goto modLoadError;
258 }
259
260 if (fileLength < 1596 || fileLength > 20842494) // minimum and maximum possible size for a supported .mod
261 {
262 showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");
263 goto modLoadError;
264 }
265
266 if (fread(&h_MOD31, 1, sizeof (h_MOD31), f) != sizeof (h_MOD31))
267 {
268 showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");
269 goto modLoadError;
270 }
271
272 modFormat = getModType(&numChannels, h_MOD31.sig);
273
274 if (modFormat == FORMAT_FLT && numChannels == 8)
275 {
276 showMsg(0, "System message", "8-channel Startrekker modules are not supported!");
277 goto modLoadError;
278 }
279
280 if (modFormat != FORMAT_UNKNOWN)
281 {
282 if (fileLength < sizeof (h_MOD31))
283 {
284 showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");
285 goto modLoadError;
286 }
287
288 songTmp.antChn = numChannels;
289 songTmp.len = h_MOD31.len;
290 songTmp.repS = h_MOD31.repS;
291 memcpy(songTmp.songTab, h_MOD31.songTab, 128);
292 ai = 31;
293 }
294 else
295 {
296 mightBeSTK = true;
297 if (fileLength < sizeof (h_MOD15))
298 {
299 showMsg(0, "System message", "Error: This file is not a module!");
300 goto modLoadError;
301 }
302
303 rewind(f);
304 if (fread(&h_MOD15, 1, sizeof (h_MOD15), f) != sizeof (h_MOD15))
305 {
306 showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");
307 goto modLoadError;
308 }
309
310 songTmp.antChn = numChannels;
311 songTmp.len = h_MOD15.len;
312 songTmp.repS = h_MOD15.repS;
313 memcpy(songTmp.songTab, h_MOD15.songTab, 128);
314 ai = 15;
315 }
316
317 if (modFormat == FORMAT_MK && songTmp.len == 129)
318 songTmp.len = 127; // fixes a specific copy of beatwave.mod (FIXME: Do we want to keep this digsuting hack?)
319
320 if (songTmp.antChn == 0 || songTmp.len < 1 || songTmp.len > 128 || (mightBeSTK && songTmp.repS > 220))
321 {
322 showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");
323 goto modLoadError;
324 }
325
326 for (a = 0; a < ai; a++)
327 {
328 songMODInstrHeaderTyp *smp = &h_MOD31.instr[a];
329
330 if (modFormat != FORMAT_HMNT) // most of "His Master's Noisetracker" songs have junk sample names, so let's not load them
331 {
332 // trim off spaces at end of name
333 for (i = 21; i >= 0; i--)
334 {
335 if (smp->name[i] == ' ' || smp->name[i] == 0x1A)
336 smp->name[i] = '\0';
337 else
338 break;
339 }
340
341 memcpy(songTmp.instrName[1+a], smp->name, 22);
342 songTmp.instrName[1+a][22] = '\0';
343 }
344
345 /* Only late versions of Ultimate SoundTracker could have samples larger than 9999 bytes.
346 ** If found, we know for sure that this is a late STK module.
347 */
348 if (mightBeSTK && 2*SWAP16(smp->len) > 9999)
349 lateSTKVerFlag = true;
350 }
351
352 songTmp.speed = 125;
353 if (mightBeSTK)
354 {
355 /* If we're still here at this point and the mightBeSTK flag is set,
356 ** then it's most likely a proper The Ultimate SoundTracker (STK/UST) module.
357 */
358 modFormat = FORMAT_STK;
359
360 if (songTmp.repS == 0)
361 songTmp.repS = 120;
362
363 // jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored (hackish!)
364 if (!strcmp("jjk55", h_MOD31.name))
365 songTmp.repS = 120;
366
367 // The "restart pos" field in STK is the inital tempo (must be converted to BPM first)
368 if (songTmp.repS != 120) // 120 is a special case and means 50Hz (125BPM)
369 {
370 if (songTmp.repS > 220)
371 songTmp.repS = 220;
372
373 // convert UST tempo to BPM
374 uint16_t ciaPeriod = (240 - songTmp.repS) * 122;
375 double dHz = 709379.0 / ciaPeriod;
376 int32_t BPM = (int32_t)((dHz * 2.5) + 0.5);
377
378 songTmp.speed = (uint16_t)BPM;
379 }
380
381 songTmp.repS = 0;
382 }
383 else if (songTmp.repS >= songTmp.len)
384 {
385 songTmp.repS = 0;
386 }
387
388 // trim off spaces at end of name
389 for (i = 19; i >= 0; i--)
390 {
391 if (h_MOD31.name[i] == ' ' || h_MOD31.name[i] == 0x1A)
392 h_MOD31.name[i] = '\0';
393 else
394 break;
395 }
396
397 memcpy(songTmp.name, h_MOD31.name, 20);
398 songTmp.name[20] = '\0';
399
400 // count number of patterns
401 b = 0;
402 for (a = 0; a < 128; a++)
403 {
404 if (songTmp.songTab[a] > b)
405 b = songTmp.songTab[a];
406 }
407 b++;
408
409 for (a = 0; a < b; a++)
410 {
411 pattTmp[a] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
412 if (pattTmp[a] == NULL)
413 {
414 showMsg(0, "System message", "Not enough memory!");
415 goto modLoadError;
416 }
417
418 pattLensTmp[a] = 64;
419 for (j = 0; j < 64; j++)
420 {
421 for (k = 0; k < songTmp.antChn; k++)
422 {
423 ton = &pattTmp[a][(j * MAX_VOICES) + k];
424
425 if (fread(bytes, 1, 4, f) != 4)
426 {
427 showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");
428 goto modLoadError;
429 }
430
431 // period to note
432 period = ((bytes[0] & 0x0F) << 8) | bytes[1];
433 for (i = 0; i < 8*12; i++)
434 {
435 if (period >= amigaPeriod[i])
436 {
437 ton->ton = (uint8_t)i + 1;
438 break;
439 }
440 }
441
442 ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
443 ton->effTyp = bytes[2] & 0x0F;
444 ton->eff = bytes[3];
445
446 if (modFormat == FORMAT_STK)
447 {
448 if (ton->effTyp == 0xC || ton->effTyp == 0xD || ton->effTyp == 0xE)
449 {
450 // "TJC SoundTracker II" and later
451 lateSTKVerFlag = true;
452 }
453
454 if (ton->effTyp == 0xF)
455 {
456 // "DFJ SoundTracker III" and later
457 lateSTKVerFlag = true;
458 veryLateSTKVerFlag = true;
459 }
460 }
461
462 if (ton->effTyp == 0xC)
463 {
464 if (ton->eff > 64)
465 ton->eff = 64;
466 }
467 else if (ton->effTyp == 0x1)
468 {
469 if (ton->eff == 0)
470 ton->effTyp = 0;
471 }
472 else if (ton->effTyp == 0x2)
473 {
474 if (ton->eff == 0)
475 ton->effTyp = 0;
476 }
477 else if (ton->effTyp == 0x5)
478 {
479 if (ton->eff == 0)
480 ton->effTyp = 0x3;
481 }
482 else if (ton->effTyp == 0x6)
483 {
484 if (ton->eff == 0)
485 ton->effTyp = 0x4;
486 }
487 else if (ton->effTyp == 0xA)
488 {
489 if (ton->eff == 0)
490 ton->effTyp = 0;
491 }
492 else if (ton->effTyp == 0xE)
493 {
494 // check if certain E commands are empty
495 if (ton->eff == 0x10 || ton->eff == 0x20 || ton->eff == 0xA0 || ton->eff == 0xB0)
496 {
497 ton->effTyp = 0;
498 ton->eff = 0;
499 }
500 }
501 }
502 }
503
504 if (tmpPatternEmpty(a))
505 {
506 if (pattTmp[a] != NULL)
507 {
508 free(pattTmp[a]);
509 pattTmp[a] = NULL;
510 }
511 }
512 }
513
514 // pattern command conversion for non-PT formats
515 if (modFormat == FORMAT_STK || modFormat == FORMAT_NT || modFormat == FORMAT_HMNT || modFormat == FORMAT_FLT)
516 {
517 for (a = 0; a < b; a++)
518 {
519 if (pattTmp[a] == NULL)
520 continue;
521
522 for (j = 0; j < 64; j++)
523 {
524 for (k = 0; k < songTmp.antChn; k++)
525 {
526 ton = &pattTmp[a][(j * MAX_VOICES) + k];
527
528 if (modFormat == FORMAT_NT || modFormat == FORMAT_HMNT)
529 {
530 // any Dxx == D00 in NT/HMNT
531 if (ton->effTyp == 0xD)
532 ton->eff = 0;
533
534 // effect F with param 0x00 does nothing in NT/HMNT
535 if (ton->effTyp == 0xF && ton->eff == 0)
536 ton->effTyp = 0;
537 }
538 else if (modFormat == FORMAT_FLT) // Startrekker
539 {
540 if (ton->effTyp == 0xE) // remove unsupported "assembly macros" command
541 {
542 ton->effTyp = 0;
543 ton->eff = 0;
544 }
545
546 // Startrekker is always in vblank mode, and limits speed to 0x1F
547 if (ton->effTyp == 0xF && ton->eff > 0x1F)
548 ton->eff = 0x1F;
549 }
550 else if (modFormat == FORMAT_STK)
551 {
552 // convert STK effects to PT effects
553
554 if (!lateSTKVerFlag)
555 {
556 // old SoundTracker 1.x commands
557
558 if (ton->effTyp == 1)
559 {
560 // arpeggio
561 ton->effTyp = 0;
562 }
563 else if (ton->effTyp == 2)
564 {
565 // pitch slide
566 if (ton->eff & 0xF0)
567 {
568 // pitch slide down
569 ton->effTyp = 2;
570 ton->eff >>= 4;
571 }
572 else if (ton->eff & 0x0F)
573 {
574 // pitch slide up
575 ton->effTyp = 1;
576 }
577 }
578 }
579 else
580 {
581 // "DFJ SoundTracker II" or later
582
583 if (ton->effTyp == 0xD)
584 {
585 if (veryLateSTKVerFlag) // "DFJ SoundTracker III" or later
586 {
587 // pattern break w/ no param (param must be cleared to fix some songs)
588 ton->eff = 0;
589 }
590 else
591 {
592 // volume slide
593 ton->effTyp = 0xA;
594 }
595 }
596 }
597
598 // effect F with param 0x00 does nothing in UST/STK (I think?)
599 if (ton->effTyp == 0xF && ton->eff == 0)
600 ton->effTyp = 0;
601 }
602 }
603 }
604 }
605 }
606
607 for (a = 0; a < ai; a++)
608 {
609 if (h_MOD31.instr[a].len == 0)
610 continue;
611
612 if (!allocateTmpInstr(1+a))
613 {
614 showMsg(0, "System message", "Not enough memory!");
615 goto modLoadError;
616 }
617
618 setNoEnvelope(instrTmp[1+a]);
619
620 s = &instrTmp[1+a]->samp[0];
621
622 s->len = 2 * SWAP16(h_MOD31.instr[a].len);
623
624 if (modFormat != FORMAT_HMNT) // most of "His Master's Noisetracker" songs have junk sample names, so let's not load them
625 memcpy(s->name, songTmp.instrName[1+a], 22);
626
627 if (modFormat == FORMAT_HMNT) // finetune in "His Master's NoiseTracker" is different
628 h_MOD31.instr[a].fine = (uint8_t)((-h_MOD31.instr[a].fine & 0x1F) >> 1); // one more bit of precision, + inverted
629
630 if (modFormat != FORMAT_STK)
631 s->fine = 8 * ((2 * ((h_MOD31.instr[a].fine & 0xF) ^ 8)) - 16);
632
633 s->pan = 128;
634
635 s->vol = h_MOD31.instr[a].vol;
636 if (s->vol > 64)
637 s->vol = 64;
638
639 s->repS = 2 * SWAP16(h_MOD31.instr[a].repS);
640 s->repL = 2 * SWAP16(h_MOD31.instr[a].repL);
641
642 if (s->repL < 2)
643 s->repL = 2;
644
645 // in The Ultimate SoundTracker, sample loop start is in bytes, not words
646 if (modFormat == FORMAT_STK)
647 s->repS >>= 1;
648
649 // fix for poorly converted STK (< v2.5) -> PT/NT modules (FIXME: Worth keeping or not?)
650 if (modFormat != FORMAT_STK && s->repL > 2 && s->repS+s->repL > s->len)
651 {
652 if ((s->repS>>1)+s->repL <= s->len)
653 s->repS >>= 1;
654 }
655
656 // fix overflown loop
657 if (s->repS+s->repL > s->len)
658 {
659 if (s->repS >= s->len)
660 {
661 s->repS = 0;
662 s->repL = 0;
663 }
664 else
665 {
666 s->repL = s->len - s->repS;
667 }
668 }
669
670 if (s->repS+s->repL > 2)
671 s->typ = 1; // enable loop
672
673 /* For Ultimate SoundTracker modules, only the loop area of a looped sample is played.
674 ** Skip loading of eventual data present before loop start.
675 */
676 if (modFormat == FORMAT_STK && s->repS > 0 && s->repL < s->len)
677 {
678 s->len -= s->repS;
679 fseek(f, s->repS, SEEK_CUR);
680 s->repS = 0;
681 }
682
683 s->pek = NULL;
684 s->origPek = (int8_t *)malloc(s->len + LOOP_FIX_LEN);
685 if (s->origPek == NULL)
686 {
687 showMsg(0, "System message", "Not enough memory!");
688 goto modLoadError;
689 }
690
691 s->pek = s->origPek + SMP_DAT_OFFSET;
692
693 int32_t bytesRead = (int32_t)fread(s->pek, 1, s->len, f);
694 if (bytesRead < s->len)
695 {
696 int32_t bytesToClear = s->len - bytesRead;
697 memset(&s->pek[bytesRead], 0, bytesToClear);
698 }
699
700 // clear repL and repS on non-looping samples...
701 if (s->typ == 0)
702 {
703 s->repL = 0;
704 s->repS = 0;
705 }
706
707 fixSample(s);
708 }
709
710 fclose(f);
711
712 songTmp.initialTempo = songTmp.tempo = 6;
713
714 moduleLoaded = true;
715 return true;
716
717modLoadError:
718 fclose(f);
719 freeTmpModule();
720 moduleFailedToLoad = true;
721 return false;
722}
723
724static uint8_t stmTempoToBPM(uint8_t tempo) // ported from original ST2.3 replayer code
725{
726 const uint8_t slowdowns[16] = { 140, 50, 25, 15, 10, 7, 6, 4, 3, 3, 2, 2, 2, 2, 1, 1 };
727 uint16_t hz = 50;
728
729 hz -= ((slowdowns[tempo >> 4] * (tempo & 15)) >> 4); // can and will underflow
730
731 const uint32_t bpm = (hz << 1) + (hz >> 1); // BPM = hz * 2.5
732 return (uint8_t)CLAMP(bpm, 32, 255); // result can be slightly off, but close enough...
733}
734
735static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool externalThreadFlag)
736{
737 uint8_t typ, tempo;
738 int16_t i, j, k, ap, tmp;
739 uint16_t a;
740 tonTyp *ton;
741 sampleTyp *s;
742 songSTMHeaderTyp h_STM;
743 int16_t (*showMsg)(int16_t, const char *, const char *);
744
745 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
746
747 rewind(f);
748
749 // start loading STM
750
751 if (fread(&h_STM, 1, sizeof (h_STM), f) != sizeof (h_STM))
752 return loadMusicMOD(f, fileLength, externalThreadFlag); // file is not a .stm, try to load as .mod
753
754 if (memcmp(h_STM.sig, "!Scream!", 8) && memcmp(h_STM.sig, "BMOD2STM", 8) &&
755 memcmp(h_STM.sig, "WUZAMOD!", 8) && memcmp(h_STM.sig, "SWavePro", 8))
756 {
757 return loadMusicMOD(f, fileLength, externalThreadFlag); // file is not a .stm, try to load as .mod
758 }
759
760 loadedFormat = FORMAT_STM;
761
762 if (h_STM.verMinor == 0 || h_STM.typ != 2)
763 {
764 showMsg(0, "System message", "Error loading .stm: Incompatible module!");
765 goto stmLoadError;
766 }
767
768 songTmp.antChn = 4;
769 memcpy(songTmp.songTab, h_STM.songTab, 128);
770
771 i = 0;
772 while (i < 128 && songTmp.songTab[i] < 99) i++;
773 songTmp.len = i + (i == 0);
774
775 if (songTmp.len < 255)
776 memset(&songTmp.songTab[songTmp.len], 0, 256 - songTmp.len);
777
778 // trim off spaces at end of name
779 for (i = 19; i >= 0; i--)
780 {
781 if (h_STM.name[i] == ' ' || h_STM.name[i] == 0x1A)
782 h_STM.name[i] = '\0';
783 else
784 break;
785 }
786
787 memcpy(songTmp.name, h_STM.name, 20);
788 songTmp.name[20] = '\0';
789
790 tempo = h_STM.tempo;
791 if (h_STM.verMinor < 21)
792 tempo = ((tempo / 10) << 4) + (tempo % 10);
793
794 if (tempo == 0)
795 tempo = 96;
796
797 songTmp.initialTempo = songTmp.tempo = CLAMP(h_STM.tempo >> 4, 1, 31);
798 songTmp.speed = stmTempoToBPM(tempo);
799
800 if (h_STM.verMinor > 10)
801 songTmp.globVol = MIN(h_STM.vol, 64);
802
803 ap = h_STM.ap;
804 for (i = 0; i < ap; i++)
805 {
806 pattTmp[i] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
807 if (pattTmp[i] == NULL)
808 {
809 showMsg(0, "System message", "Not enough memory!");
810 goto stmLoadError;
811 }
812
813 pattLensTmp[i] = 64;
814 if (fread(pattBuff, 64 * 4 * 4, 1, f) != 1)
815 {
816 showMsg(0, "System message", "General I/O error during loading!");
817 goto stmLoadError;
818 }
819
820 a = 0;
821 for (j = 0; j < 64; j++)
822 {
823 for (k = 0; k < 4; k++)
824 {
825 ton = &pattTmp[i][(j * MAX_VOICES) + k];
826
827 if (pattBuff[a] == 254)
828 {
829 ton->ton = 97;
830 }
831 else if (pattBuff[a] < 96)
832 {
833 ton->ton = (12 * (pattBuff[a] >> 4)) + (25 + (pattBuff[a] & 0x0F));
834 if (ton->ton > 96)
835 ton->ton = 0;
836 }
837 else
838 {
839 ton->ton = 0;
840 }
841
842 ton->instr = pattBuff[a + 1] >> 3;
843 typ = (pattBuff[a + 1] & 7) + ((pattBuff[a + 2] & 0xF0) >> 1);
844 if (typ <= 64)
845 ton->vol = typ + 0x10;
846
847 ton->eff = pattBuff[a + 3];
848
849 tmp = pattBuff[a + 2] & 0x0F;
850 if (tmp == 1)
851 {
852 ton->effTyp = 15;
853
854 if (h_STM.verMinor < 21)
855 ton->eff = ((ton->eff / 10) << 4) + (ton->eff % 10);
856
857 ton->eff >>= 4;
858 }
859 else if (tmp == 3)
860 {
861 ton->effTyp = 13;
862 ton->eff = 0;
863 }
864 else if (tmp == 2 || (tmp >= 4 && tmp <= 12))
865 {
866 ton->effTyp = stmEff[tmp];
867 if (ton->effTyp == 0xA)
868 {
869 if (ton->eff & 0x0F)
870 ton->eff &= 0x0F;
871 else
872 ton->eff &= 0xF0;
873 }
874 }
875 else
876 {
877 ton->eff = 0;
878 }
879
880 if (ton->effTyp > 35)
881 {
882 ton->effTyp = 0;
883 ton->eff = 0;
884 }
885
886 a += 4;
887 }
888 }
889
890 if (tmpPatternEmpty(i))
891 {
892 if (pattTmp[i] != NULL)
893 {
894 free(pattTmp[i]);
895 pattTmp[i] = NULL;
896 }
897 }
898 }
899
900 for (i = 0; i < 31; i++)
901 {
902 // trim off spaces at end of name
903 for (j = 11; j >= 0; j--)
904 {
905 if (h_STM.instr[i].name[j] == ' ' || h_STM.instr[i].name[j] == 0x1A)
906 h_STM.instr[i].name[j] = '\0';
907 else
908 break;
909 }
910
911 memset(&songTmp.instrName[1+i], 0, sizeof (songTmp.instrName[1+i]));
912 memcpy(&songTmp.instrName[1+i], h_STM.instr[i].name, 12);
913
914 if (h_STM.instr[i].len != 0 && h_STM.instr[i].reserved1 != 0)
915 {
916 allocateTmpInstr(1 + i);
917 setNoEnvelope(instrTmp[i]);
918
919 s = &instrTmp[1+i]->samp[0];
920
921 s->pek = NULL;
922 s->origPek = (int8_t *)malloc(h_STM.instr[i].len + LOOP_FIX_LEN);
923 if (s->origPek == NULL)
924 {
925 showMsg(0, "System message", "Not enough memory!");
926 goto stmLoadError;
927 }
928
929 s->pek = s->origPek + SMP_DAT_OFFSET;
930
931 s->len = h_STM.instr[i].len;
932 tuneSample(s, h_STM.instr[i].rate, false);
933 s->vol = h_STM.instr[i].vol;
934 s->repS = h_STM.instr[i].repS;
935 s->repL = h_STM.instr[i].repE - h_STM.instr[i].repS;
936 s->pan = 128;
937
938 if (s->repS < s->len && h_STM.instr[i].repE > s->repS && h_STM.instr[i].repE != 0xFFFF)
939 {
940 if (s->repS+s->repL > s->len)
941 s->repL = s->len - s->repS;
942
943 s->typ = 1; // enable loop
944 }
945 else
946 {
947 s->repS = 0;
948 s->repL = 0;
949 s->typ = 0;
950 }
951
952 if (s->vol > 64)
953 s->vol = 64;
954
955 if (fread(s->pek, s->len, 1, f) != 1)
956 {
957 showMsg(0, "System message", "General I/O error during loading! Possibly corrupt module?");
958 goto stmLoadError;
959 }
960
961 fixSample(s);
962 }
963 }
964
965 fclose(f);
966
967 moduleLoaded = true;
968 return true;
969
970stmLoadError:
971 fclose(f);
972 freeTmpModule();
973 moduleFailedToLoad = true;
974 return false;
975}
976
977static int8_t countS3MChannels(uint16_t antPtn)
978{49{
979 int32_t channels = 0;50 "xm", "ft", "nst", "stk", "mod", "s3m", "stm", "fst", "digi",
980 for (int32_t i = 0; i < antPtn; i++)
981 {
982 if (pattTmp[i] == NULL)
983 continue;
984 51
985 tonTyp *ton = pattTmp[i];52 "END_OF_LIST" // do NOT move, remove or edit this line!
986 for (int32_t j = 0; j < 64; j++)53};
987 {
988 for (int32_t k = 0; k < MAX_VOICES; k++, ton++)
989 {
990 if (ton->eff == 0 && ton->effTyp == 0 && ton->instr == 0 && ton->ton == 0 && ton->vol == 0)
991 continue;
992 54
993 if (k > channels)55// globals for module loaders
994 channels = k;56volatile bool tmpLinearPeriodsFlag;
995 }57int16_t pattLensTmp[MAX_PATTERNS];
996 }58tonTyp *pattTmp[MAX_PATTERNS];
997 }59instrTyp *instrTmp[1+256];
998 channels++;60songTyp songTmp;
61// --------------------------
999 62
1000 return (int8_t)channels;63static volatile bool musicIsLoading, moduleLoaded, moduleFailedToLoad;
1001}64static SDL_Thread *thread;
65static uint8_t oldPlayMode;
66static void setupLoadedModule(void);
67static void freeTmpModule(void);
1002 68
1003static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool externalThreadFlag)69// Crude module detection routine. These aren't always accurate detections!
70static int8_t detectModule(FILE *f)
1004{71{
1005 int8_t *tmpSmp;72 uint8_t D[256], I[4];
1006 uint8_t ha[2048];
1007 uint8_t alastnfo[32], alastefx[32], alastvibnfo[32], s3mLastGInstr[32];
1008 uint8_t typ;
1009 int16_t ai, ap, ver, ii, kk, tmp;
1010 uint16_t ptnOfs[256];
1011 int32_t i, j, k, len;
1012 tonTyp ton;
1013 sampleTyp *s;
1014 songS3MHeaderTyp h_S3M;
1015 songS3MinstrHeaderTyp h_S3MInstr;
1016 int16_t (*showMsg)(int16_t, const char *, const char *);
1017
1018 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
1019 73
74 fseek(f, 0, SEEK_END);
75 uint32_t fileLength = (uint32_t)ftell(f);
1020 rewind(f);76 rewind(f);
1021 77
1022 // start loading S3M78 memset(D, 0, sizeof (D));
1023 79 fread(D, 1, sizeof (D), f);
1024 if (fread(&h_S3M, 1, sizeof (h_S3M), f) != sizeof (h_S3M))80 fseek(f, 1080, SEEK_SET); // MOD ID
1025 return loadMusicSTM(f, dataLength, externalThreadFlag); // not a .s3m, try loading as .stm81 I[0] = I[1] = I[2] = I[3] = 0;
1026 82 fread(I, 1, 4, f);
1027 if (memcmp(h_S3M.id, "SCRM", 4))83 rewind(f);
1028 return loadMusicSTM(f, dataLength, externalThreadFlag); // not a .s3m, try loading as .stm
1029 84
1030 loadedFormat = FORMAT_S3M;85 // DIGI Booster (non-Pro)
86 if (!memcmp("DIGI Booster module", &D[0x00], 19+1) && D[0x19] >= 1 && D[0x19] <= 8)
87 return FORMAT_DIGI;
1031 88
1032 if (h_S3M.antInstr > MAX_INST || h_S3M.songTabLen > 256 || h_S3M.antPatt > 256 ||89 // Scream Tracker 3 S3M (and compatible trackers)
1033 h_S3M.typ != 16 || h_S3M.ver < 1 || h_S3M.ver > 2)90 if (!memcmp("SCRM", &D[0x2C], 4) && D[0x1D] == 16) // XXX: byte=16 in all cases?
1034 {91 return FORMAT_S3M;
1035 showMsg(0, "System message", "Error loading .s3m: Incompatible module!");
1036 goto s3mLoadError;
1037 }
1038 92
1039 memset(songTmp.songTab, 255, sizeof (songTmp.songTab));93 // Scream Tracker 2 STM
1040 if (fread(songTmp.songTab, h_S3M.songTabLen, 1, f) != 1)94 if ((!memcmp("!Scream!", &D[0x14], 8) || !memcmp("BMOD2STM", &D[0x14], 8) ||
95 !memcmp("WUZAMOD!", &D[0x14], 8) || !memcmp("SWavePro", &D[0x14], 8)) && D[0x1D] == 2) // XXX: byte=2 for "WUZAMOD!"/"SWavePro" ?
1041 {96 {
1042 showMsg(0, "System message", "General I/O error during loading! Is the file in use?");97 return FORMAT_STM;
1043 goto s3mLoadError;
1044 }98 }
1045 99
1046 songTmp.len = h_S3M.songTabLen;100 // Generic multi-channel MOD (1..9 channels)
1047 101 if (isdigit(I[0]) && I[0] != '0' && I[1] == 'C' && I[2] == 'H' && I[3] == 'N') // xCHN
1048 // remove pattern separators (254)102 return FORMAT_MOD;
1049 k = 0;
1050 j = 0;
1051 for (i = 0; i < songTmp.len; i++)
1052 {
1053 if (songTmp.songTab[i] != 254)
1054 songTmp.songTab[j++] = songTmp.songTab[i];
1055 else
1056 k++;
1057 }
1058 103
1059 if (k <= songTmp.len)104 // Generic multi-channel MOD (10..99 channels)
1060 songTmp.len -= (uint16_t)k;105 if (isdigit(I[0]) && isdigit(I[1]) && I[0] != '0' && I[2] == 'C' && I[3] == 'H') // xxCH
1061 else106 return FORMAT_MOD;
1062 songTmp.len = 1;
1063 107
1064 for (i = 1; i < songTmp.len; i++)108 // Generic multi-channel MOD (10..99 channels)
1065 {109 if (isdigit(I[0]) && isdigit(I[1]) && I[0] != '0' && I[2] == 'C' && I[3] == 'N') // xxCN (same as xxCH)
1066 if (songTmp.songTab[i] == 255)110 return FORMAT_MOD;
1067 {
1068 songTmp.len = (uint16_t)i;
1069 break;
1070 }
1071 }
1072 111
1073 // clear unused song table entries112 // Generic 4-channel MOD (NoiseTracker/ProTracker or compatible)
1074 if (songTmp.len < 255)113 if (!memcmp("M.K.", I, 4) || !memcmp("M!K!", I, 4) || !memcmp("NSMS", I, 4) ||
1075 memset(&songTmp.songTab[songTmp.len], 0, 255-songTmp.len);114 !memcmp("LARD", I, 4) || !memcmp("PATT", I, 4) || !memcmp("PATT", I, 4) ||
1076 115 !memcmp("FLT4", I, 4) || !memcmp("FLT8", I, 4) || !memcmp("N.T.", I, 4) ||
1077 songTmp.speed = h_S3M.defTempo;116 !memcmp("M&K!", I, 4) || !memcmp("FEST", I, 4))
1078 if (songTmp.speed < 32)
1079 songTmp.speed = 32;
1080
1081 songTmp.tempo = h_S3M.defSpeed;
1082 if (songTmp.tempo == 0)
1083 songTmp.tempo = 6;
1084
1085 if (songTmp.tempo > 31)
1086 songTmp.tempo = 31;
1087
1088 songTmp.initialTempo = songTmp.tempo;
1089
1090 // trim off spaces at end of name
1091 for (i = 19; i >= 0; i--)
1092 {
1093 if (h_S3M.name[i] == ' ' || h_S3M.name[i] == 0x1A)
1094 h_S3M.name[i] = '\0';
1095 else
1096 break;
1097 }
1098
1099 memcpy(songTmp.name, h_S3M.name, 20);
1100 songTmp.name[20] = '\0';
1101
1102 ap = h_S3M.antPatt;
1103 ai = h_S3M.antInstr;
1104 ver = h_S3M.ver;
1105
1106 k = 31;
1107 while (k >= 0 && h_S3M.chanType[k] >= 16) k--;
1108 songTmp.antChn = (k + 2) & 254;
1109
1110 if (fread(ha, ai + ai, 1, f) != 1)
1111 {
1112 showMsg(0, "System message", "General I/O error during loading! Is the file in use?");
1113 goto s3mLoadError;
1114 }
1115
1116 if (fread(ptnOfs, ap + ap, 1, f) != 1)
1117 {
1118 showMsg(0, "System message", "General I/O error during loading! Is the file in use?");
1119 goto s3mLoadError;
1120 }
1121
1122 // *** PATTERNS ***
1123
1124 k = 0;
1125 for (i = 0; i < ap; i++)
1126 {117 {
1127 if (ptnOfs[i] == 0)118 return FORMAT_MOD;
1128 continue; // empty pattern
1129
1130 memset(alastnfo, 0, sizeof (alastnfo));
1131 memset(alastefx, 0, sizeof (alastefx));
1132 memset(alastvibnfo, 0, sizeof (alastvibnfo));
1133 memset(s3mLastGInstr, 0, sizeof (s3mLastGInstr));
1134
1135 fseek(f, ptnOfs[i] << 4, SEEK_SET);
1136 if (feof(f))
1137 continue;
1138
1139 if (fread(&j, 2, 1, f) != 1)
1140 {
1141 showMsg(0, "System message", "General I/O error during loading! Is the file in use?");
1142 goto s3mLoadError;
1143 }
1144
1145 if (j > 0 && j <= 12288)
1146 {
1147 pattTmp[i] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
1148 if (pattTmp[i] == NULL)
1149 {
1150 showMsg(0, "System message", "Not enough memory!");
1151 goto s3mLoadError;
1152 }
1153
1154 pattLensTmp[i] = 64;
1155 fread(pattBuff, j, 1, f);
1156
1157 k = 0;
1158 kk = 0;
1159
1160 while (k < j && kk < 64)
1161 {
1162 typ = pattBuff[k++];
1163
1164 if (typ == 0)
1165 {
1166 kk++;
1167 }
1168 else
1169 {
1170 ii = typ & 31;
1171
1172 memset(&ton, 0, sizeof (ton));
1173
1174 // note and sample
1175 if (typ & 32)
1176 {
1177 ton.ton = pattBuff[k++];
1178 ton.instr = pattBuff[k++];
1179
1180 if (ton.instr > MAX_INST)
1181 ton.instr = 0;
1182
1183 if (ton.ton == 254) ton.ton = 97;
1184 else if (ton.ton == 255) ton.ton = 0;
1185 else
1186 {
1187 ton.ton = 1 + (ton.ton & 0xF) + (ton.ton >> 4) * 12;
1188 if (ton.ton > 96)
1189 ton.ton = 0;
1190 }
1191 }
1192
1193 // volume column
1194 if (typ & 64)
1195 {
1196 ton.vol = pattBuff[k++];
1197
1198 if (ton.vol <= 64)
1199 ton.vol += 0x10;
1200 else
1201 ton.vol = 0;
1202 }
1203
1204 // effect
1205 if (typ & 128)
1206 {
1207 ton.effTyp = pattBuff[k++];
1208 ton.eff = pattBuff[k++];
1209
1210 if (ton.eff > 0)
1211 {
1212 alastnfo[ii] = ton.eff;
1213 if (ton.effTyp == 8 || ton.effTyp == 21)
1214 alastvibnfo[ii] = ton.eff; // H/U
1215 }
1216
1217 // in ST3, a lot of effects directly share the same memory!
1218 if (ton.eff == 0 && ton.effTyp != 7) // G
1219 {
1220 uint8_t efx = ton.effTyp;
1221 if (efx == 8 || efx == 21) // H/U
1222 ton.eff = alastvibnfo[ii];
1223 else if ((efx >= 4 && efx <= 12) || (efx >= 17 && efx <= 19)) // D/E/F/I/J/K/L/Q/R/S
1224 ton.eff = alastnfo[ii];
1225
1226 /* If effect data is zero and effect type was the same as last one, clear out
1227 ** data if it's not J or S (those have no memory in the equivalent XM effects).
1228 ** Also goes for extra fine pitch slides and fine volume slides,
1229 ** since they get converted to other effects.
1230 */
1231 if (efx == alastefx[ii] && ton.effTyp != 10 && ton.effTyp != 19) // J/S
1232 {
1233 uint8_t nfo = ton.eff;
1234 bool extraFinePitchSlides = (efx == 5 || efx == 6) && ((nfo & 0xF0) == 0xE0);
1235 bool fineVolSlides = (efx == 4 || efx == 11) &&
1236 ((nfo > 0xF0) || (((nfo & 0xF) == 0xF) && ((nfo & 0xF0) > 0)));
1237
1238 if (!extraFinePitchSlides && !fineVolSlides)
1239 ton.eff = 0;
1240 }
1241 }
1242
1243 if (ton.effTyp > 0)
1244 alastefx[ii] = ton.effTyp;
1245
1246 switch (ton.effTyp)
1247 {
1248 case 1: // A
1249 {
1250 ton.effTyp = 0xF;
1251 if (ton.eff == 0 || ton.eff > 0x1F)
1252 {
1253 ton.effTyp = 0;
1254 ton.eff = 0;
1255 }
1256 }
1257 break;
1258
1259 case 2: ton.effTyp = 0xB; break; // B
1260 case 3: ton.effTyp = 0xD; break; // C
1261 case 4: // D
1262 {
1263 if (ton.eff > 0xF0) // fine slide up
1264 {
1265 ton.effTyp = 0xE;
1266 ton.eff = 0xB0 | (ton.eff & 0xF);
1267 }
1268 else if ((ton.eff & 0x0F) == 0x0F && (ton.eff & 0xF0) > 0) // fine slide down
1269 {
1270 ton.effTyp = 0xE;
1271 ton.eff = 0xA0 | (ton.eff >> 4);
1272 }
1273 else
1274 {
1275 ton.effTyp = 0xA;
1276 if (ton.eff & 0x0F) // on D/K, last nybble has first priority in ST3
1277 ton.eff &= 0x0F;
1278 }
1279 }
1280 break;
1281
1282 case 5: // E
1283 case 6: // F
1284 {
1285 if ((ton.eff & 0xF0) >= 0xE0)
1286 {
1287 // convert to fine slide
1288 if ((ton.eff & 0xF0) == 0xE0)
1289 tmp = 0x21;
1290 else
1291 tmp = 0xE;
1292
1293 ton.eff &= 0x0F;
1294
1295 if (ton.effTyp == 0x05)
1296 ton.eff |= 0x20;
1297 else
1298 ton.eff |= 0x10;
1299
1300 ton.effTyp = (uint8_t)tmp;
1301
1302 if (ton.effTyp == 0x21 && ton.eff == 0)
1303 {
1304 ton.effTyp = 0;
1305 }
1306 }
1307 else
1308 {
1309 // convert to normal 1xx/2xx slide
1310 ton.effTyp = 7 - ton.effTyp;
1311 }
1312 }
1313 break;
1314
1315 case 7: // G
1316 {
1317 ton.effTyp = 0x03;
1318
1319 // fix illegal slides (to new instruments)
1320 if (ton.instr != 0 && ton.instr != s3mLastGInstr[ii])
1321 ton.instr = s3mLastGInstr[ii];
1322 }
1323 break;
1324
1325 case 11: // K
1326 {
1327 if (ton.eff > 0xF0) // fine slide up
1328 {
1329 ton.effTyp = 0xE;
1330 ton.eff = 0xB0 | (ton.eff & 0xF);
1331
1332 // if volume column is unoccupied, set to vibrato
1333 if (ton.vol == 0)
1334 ton.vol = 0xB0;
1335 }
1336 else if ((ton.eff & 0x0F) == 0x0F && (ton.eff & 0xF0) > 0) // fine slide down
1337 {
1338 ton.effTyp = 0xE;
1339 ton.eff = 0xA0 | (ton.eff >> 4);
1340
1341 // if volume column is unoccupied, set to vibrato
1342 if (ton.vol == 0)
1343 ton.vol = 0xB0;
1344 }
1345 else
1346 {
1347 ton.effTyp = 0x6;
1348 if (ton.eff & 0x0F) // on D/K, last nybble has first priority in ST3
1349 ton.eff &= 0x0F;
1350 }
1351 }
1352 break;
1353
1354 case 8: ton.effTyp = 0x04; break; // H
1355 case 9: ton.effTyp = 0x1D; break; // I
1356 case 10: ton.effTyp = 0x00; break; // J
1357 case 12: ton.effTyp = 0x05; break; // L
1358 case 15: ton.effTyp = 0x09; break; // O
1359 case 17: ton.effTyp = 0x1B; break; // Q
1360 case 18: ton.effTyp = 0x07; break; // R
1361
1362 case 19: // S
1363 {
1364 ton.effTyp = 0xE;
1365 tmp = ton.eff >> 4;
1366 ton.eff &= 0x0F;
1367
1368 if (tmp == 0x1) ton.eff |= 0x30;
1369 else if (tmp == 0x2) ton.eff |= 0x50;
1370 else if (tmp == 0x3) ton.eff |= 0x40;
1371 else if (tmp == 0x4) ton.eff |= 0x70;
1372 // ignore S8x becuase it's not compatible with FT2 panning
1373 else if (tmp == 0xB) ton.eff |= 0x60;
1374 else if (tmp == 0xC) // Note Cut
1375 {
1376 ton.eff |= 0xC0;
1377 if (ton.eff == 0xC0)
1378 {
1379 // EC0 does nothing in ST3 but cuts voice in FT2, remove effect
1380 ton.effTyp = 0;
1381 ton.eff = 0;
1382 }
1383 }
1384 else if (tmp == 0xD) // Note Delay
1385 {
1386 ton.eff |= 0xD0;
1387 if (ton.ton == 0 || ton.ton == 97)
1388 {
1389 // EDx without a note does nothing in ST3 but retrigs in FT2, remove effect
1390 ton.effTyp = 0;
1391 ton.eff = 0;
1392 }
1393 else if (ton.eff == 0xD0)
1394 {
1395 // ED0 prevents note/smp/vol from updating in ST3, remove everything
1396 ton.ton = 0;
1397 ton.instr = 0;
1398 ton.vol = 0;
1399 ton.effTyp = 0;
1400 ton.eff = 0;
1401 }
1402 }
1403 else if (tmp == 0xE) ton.eff |= 0xE0;
1404 else if (tmp == 0xF) ton.eff |= 0xF0;
1405 else
1406 {
1407 ton.effTyp = 0;
1408 ton.eff = 0;
1409 }
1410 }
1411 break;
1412
1413 case 20: // T
1414 {
1415 ton.effTyp = 0x0F;
1416 if (ton.eff < 0x21) // Txx with a value lower than 33 (0x21) does nothing in ST3, remove effect
1417 {
1418 ton.effTyp = 0;
1419 ton.eff = 0;
1420 }
1421 }
1422 break;
1423
1424 case 22: // V
1425 {
1426 ton.effTyp = 0x10;
1427 if (ton.eff > 0x40)
1428 {
1429 // Vxx > 0x40 does nothing in ST3
1430 ton.effTyp = 0;
1431 ton.eff = 0;
1432 }
1433 }
1434 break;
1435
1436 default:
1437 {
1438 ton.effTyp = 0;
1439 ton.eff = 0;
1440 }
1441 break;
1442 }
1443 }
1444
1445 if (ton.instr != 0 && ton.effTyp != 0x3)
1446 s3mLastGInstr[ii] = ton.instr;
1447
1448 if (ton.effTyp > 35)
1449 {
1450 ton.effTyp = 0;
1451 ton.eff = 0;
1452 }
1453
1454 pattTmp[i][(kk * MAX_VOICES) + ii] = ton;
1455 }
1456 }
1457
1458 if (tmpPatternEmpty((uint16_t)i))
1459 {
1460 if (pattTmp[i] != NULL)
1461 {
1462 free(pattTmp[i]);
1463 pattTmp[i] = NULL;
1464 }
1465 }
1466 }
1467 }119 }
1468 120
1469 // *** SAMPLES ***121 /* Check if the file is a .it module (Impulse Tracker, not supported).
1470 122 ** Some people may attempt to load .IT files in the FT2 clone, so
1471 bool adlibInsWarn = false;123 ** reject them here instead of accidentally loading them as .STK
1472 124 */
1473 memcpy(ptnOfs, ha, 512);125 if (!memcmp("IMPM", D, 4) && D[0x16] == 0)
1474 for (i = 0; i < ai; i++)126 return FORMAT_UNKNOWN;
1475 {
1476 fseek(f, ptnOfs[i] << 4, SEEK_SET);
1477
1478 if (fread(&h_S3MInstr, 1, sizeof (h_S3MInstr), f) != sizeof (h_S3MInstr))
1479 {
1480 showMsg(0, "System message", "Not enough memory!");
1481 goto s3mLoadError;
1482 }
1483
1484 // trim off spaces at end of name
1485 for (j = 21; j >= 0; j--)
1486 {
1487 if (h_S3MInstr.name[j] == ' ' || h_S3MInstr.name[j] == 0x1A)
1488 h_S3MInstr.name[j] = '\0';
1489 else
1490 break;
1491 }
1492
1493 memcpy(songTmp.instrName[1+i], h_S3MInstr.name, 22);
1494 songTmp.instrName[1+i][22] = '\0';
1495
1496 if (h_S3MInstr.typ == 2)
1497 {
1498 adlibInsWarn = true;
1499 }
1500 else if (h_S3MInstr.typ == 1)
1501 {
1502 if ((h_S3MInstr.flags & (255-1-2-4)) != 0 || h_S3MInstr.pack != 0)
1503 {
1504 showMsg(0, "System message", "Error loading .s3m: Incompatible module!");
1505 goto s3mLoadError;
1506 }
1507 else if (h_S3MInstr.memSeg > 0 && h_S3MInstr.len > 0)
1508 {
1509 if (!allocateTmpInstr((int16_t)(1 + i)))
1510 {
1511 showMsg(0, "System message", "Not enough memory!");
1512 goto s3mLoadError;
1513 }
1514
1515 setNoEnvelope(instrTmp[1 + i]);
1516 s = &instrTmp[1+i]->samp[0];
1517
1518 len = h_S3MInstr.len;
1519
1520 bool hasLoop = h_S3MInstr.flags & 1;
1521 bool stereoSample = (h_S3MInstr.flags >> 1) & 1;
1522 bool is16Bit = (h_S3MInstr.flags >> 2) & 1;
1523
1524 if (is16Bit) // 16-bit
1525 len <<= 1;
1526
1527 if (stereoSample) // stereo
1528 len <<= 1;
1529
1530 tmpSmp = (int8_t *)malloc(len + LOOP_FIX_LEN);
1531 if (tmpSmp == NULL)
1532 {
1533 showMsg(0, "System message", "Not enough memory!");
1534 goto s3mLoadError;
1535 }
1536
1537 int8_t *newPtr = tmpSmp + SMP_DAT_OFFSET;
1538
1539 memcpy(s->name, h_S3MInstr.name, 21);
1540
1541 if (h_S3MInstr.c2Spd > 65535) // ST3 (and OpenMPT) does this
1542 h_S3MInstr.c2Spd = 65535;
1543
1544 tuneSample(s, h_S3MInstr.c2Spd, false);
1545
1546 s->len = h_S3MInstr.len;
1547 s->vol = h_S3MInstr.vol;
1548 s->repS = h_S3MInstr.repS;
1549 s->repL = h_S3MInstr.repE - h_S3MInstr.repS;
1550
1551 // non-FT2: fixes "miracle man.s3m"
1552 if ((h_S3MInstr.memSeg<<4)+s->len > (int32_t)dataLength)
1553 s->len = dataLength - (h_S3MInstr.memSeg << 4);
1554
1555 if (s->repL <= 2 || s->repS+s->repL > s->len)
1556 {
1557 s->repS = 0;
1558 s->repL = 0;
1559 hasLoop = false;
1560 }
1561
1562 if (s->repL == 0)
1563 hasLoop = false;
1564
1565 s->typ = hasLoop + (is16Bit << 4);
1566
1567 if (s->vol > 64)
1568 s->vol = 64;
1569
1570 s->pan = 128;
1571
1572 fseek(f, h_S3MInstr.memSeg << 4, SEEK_SET);
1573
1574 // non-FT2: fixes "miracle man.s3m"
1575 if ((h_S3MInstr.memSeg<<4)+len > (int32_t)dataLength)
1576 len = dataLength - (h_S3MInstr.memSeg << 4);
1577
1578 if (ver == 1)
1579 {
1580 fseek(f, len, SEEK_CUR); // sample not supported
1581 }
1582 else
1583 {
1584 if (fread(newPtr, len, 1, f) != 1)
1585 {
1586 free(tmpSmp);
1587 showMsg(0, "System message", "General I/O error during loading! Is the file in use?");
1588 goto s3mLoadError;
1589 }
1590
1591 if (is16Bit)
1592 {
1593 conv16BitSample(newPtr, len, stereoSample);
1594
1595 s->origPek = tmpSmp;
1596 s->pek = s->origPek + SMP_DAT_OFFSET;
1597
1598 s->len <<= 1;
1599 s->repS <<= 1;
1600 s->repL <<= 1;
1601 }
1602 else
1603 {
1604 conv8BitSample(newPtr, len, stereoSample);
1605
1606 s->origPek = tmpSmp;
1607 s->pek = s->origPek + SMP_DAT_OFFSET;
1608 }
1609
1610 // if stereo sample: reduce memory footprint after sample was downmixed to mono
1611 if (stereoSample)
1612 {
1613 newPtr = (int8_t *)realloc(s->origPek, s->len + LOOP_FIX_LEN);
1614 if (newPtr != NULL)
1615 {
1616 s->origPek = newPtr;
1617 s->pek = s->origPek + SMP_DAT_OFFSET;
1618 }
1619 }
1620
1621 fixSample(s);
1622 }
1623 }
1624 }
1625 }
1626 127
1627 fclose(f);128 /* Fasttracker II XM and compatible trackers.
129 ** Note: This test can falsely be true for STK modules (and non-supported files) where the
130 ** first 17 bytes start with "Extended Module: ". This is unlikely to happen.
131 */
132 if (!memcmp("Extended Module: ", &D[0x00], 17))
133 return FORMAT_XM;
1628 134
1629 songTmp.antChn = countS3MChannels(ap);135 /* Lastly, we assume that the file is either a 15-sample STK or an unsupported file.
136 ** Let's assume it's an STK and do some sanity checks. If they fail, we have an
137 ** unsupported file.
138 */
1630 139
1631 if (adlibInsWarn)140 // minimum and maximum (?) possible size for a supported STK
1632 showMsg(0, "System message", "Warning: The module contains unsupported AdLib instruments!");141 if (fileLength < 1624 || fileLength > 984634)
142 return FORMAT_UNKNOWN;
1633 143
1634 if (!(config.dontShowAgainFlags & DONT_SHOW_S3M_LOAD_WARNING_FLAG))144 // test STK numOrders+BPM for illegal values
1635 showMsg(6, "System message", "Warning: S3M channel panning is ignored because it's not compatible with FT2.");145 fseek(f, 470, SEEK_SET);
146 D[0] = D[1] = 0;
147 fread(D, 1, 2, f);
148 rewind(f);
1636 149
1637 moduleLoaded = true;150 if (D[0] >= 0 && D[0] <= 128 && D[1] <= 220)
1638 return true;151 return FORMAT_POSSIBLY_STK;
1639 152
1640s3mLoadError:153 return FORMAT_UNKNOWN;
1641 fclose(f);
1642 freeTmpModule();
1643 moduleFailedToLoad = true;
1644 return false;
1645}154}
1646 155
1647bool doLoadMusic(bool externalThreadFlag)156static bool doLoadMusic(bool externalThreadFlag)
1648{157{
1649 char tmpText[128];158 // setup message box functions
1650 int16_t k;159 loaderMsgBox = externalThreadFlag ? myLoaderMsgBoxThreadSafe : myLoaderMsgBox;
1651 uint16_t i;160 loaderSysReq = externalThreadFlag ? okBoxThreadSafe : okBox;
1652 uint32_t filelength;
1653 songHeaderTyp h;
1654 FILE *f;
1655 int16_t (*showMsg)(int16_t, const char *, const char *);
1656
1657 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
1658
1659 linearFreqTable = false;
1660 161
1661 if (editor.tmpFilenameU == NULL)162 if (editor.tmpFilenameU == NULL)
1662 {163 {
1663 showMsg(0, "System message", "Generic memory fault during loading!");164 loaderMsgBox("Generic memory fault during loading!");
1664 moduleFailedToLoad = true;165 goto loadError;
1665 return false;
1666 }166 }
1667 167
1668 f = UNICHAR_FOPEN(editor.tmpFilenameU, "rb");168 FILE *f = UNICHAR_FOPEN(editor.tmpFilenameU, "rb");
1669 if (f == NULL)169 if (f == NULL)
1670 {170 {
1671 showMsg(0, "System message", "General I/O error during loading! Is the file in use? Does it exist?");171 loaderMsgBox("General I/O error during loading! Is the file in use? Does it exist?");
1672 moduleFailedToLoad = true;172 goto loadError;
1673 return false;
1674 }173 }
1675 174
175 int8_t format = detectModule(f);
1676 fseek(f, 0, SEEK_END);176 fseek(f, 0, SEEK_END);
1677 filelength = ftell(f);177 uint32_t filesize = ftell(f);
1678 rewind(f);
1679
1680 // start loading
1681 if (fread(&h, 1, sizeof (h), f) != sizeof (h))
1682 return loadMusicS3M(f, filelength, externalThreadFlag); // not a .xm file, try to load as .s3m
1683
1684 if (memcmp(h.sig, "Extended Module: ", 17))
1685 return loadMusicS3M(f, filelength, externalThreadFlag); // not a .xm file, try to load as .s3m
1686
1687 loadedFormat = FORMAT_XM;
1688
1689 if (h.ver < 0x0102 || h.ver > 0x0104)
1690 {
1691 fclose(f);
1692
1693 const int32_t major = (h.ver >> 8) & 0x0F;
1694 const int32_t minor = h.ver & 0xFF;
1695
1696 sprintf(tmpText, "Error loading XM: Unsupported file version (v%01X.%02X).", major, minor);
1697 showMsg(0, "System message", tmpText);
1698
1699 moduleFailedToLoad = true;
1700 return false;
1701 }
1702
1703 if (h.len > MAX_ORDERS)
1704 {
1705 showMsg(0, "System message", "Error loading XM: The song has more than 256 orders!");
1706 goto xmLoadError;
1707 }
1708
1709 if (h.antPtn > MAX_PATTERNS)
1710 {
1711 showMsg(0, "System message", "Error loading XM: The song has more than 256 patterns!");
1712 goto xmLoadError;
1713 }
1714
1715 if (h.antChn == 0)
1716 {
1717 showMsg(0, "System message", "Error loading XM: This file is corrupt.");
1718 goto xmLoadError;
1719 }
1720
1721 if (h.antInstrs > 256) // if >128 instruments, we fake-load up to 128 extra instruments and discard them
1722 {
1723 showMsg(0, "System message", "Error loading XM: This file is corrupt.");
1724 goto xmLoadError;
1725 }
1726
1727 fseek(f, 60 + h.headerSize, SEEK_SET);
1728 if (filelength != 336 && feof(f)) // 336 in length at this point = empty XM
1729 {
1730 showMsg(0, "System message", "Error loading XM: The module is empty!");
1731 goto xmLoadError;
1732 }
1733
1734 // trim off spaces at end of name
1735 for (k = 19; k >= 0; k--)
1736 {
1737 if (h.name[k] == ' ' || h.name[k] == 0x1A)
1738 h.name[k] = '\0';
1739 else
1740 break;
1741 }
1742
1743 memcpy(songTmp.name, h.name, 20);
1744 songTmp.name[20] = '\0';
1745 178
1746 songTmp.len = h.len;179 rewind(f);
1747 songTmp.repS = h.repS;180 switch (format)
1748 songTmp.antChn = (uint8_t)h.antChn;
1749 songTmp.speed = h.defSpeed;
1750 songTmp.tempo = h.defTempo;
1751 songTmp.ver = h.ver;
1752 linearFreqTable = h.flags & 1;
1753
1754 songTmp.speed = CLAMP(songTmp.speed, 1, 999);
1755 songTmp.tempo = CLAMP(songTmp.tempo, 1, 99);
1756
1757 songTmp.initialTempo = songTmp.tempo;
1758
1759 if (songTmp.globVol > 64)
1760 songTmp.globVol = 64;
1761
1762 if (songTmp.len == 0)
1763 songTmp.len = 1; // songTmp.songTab is already empty
1764 else
1765 memcpy(songTmp.songTab, h.songTab, songTmp.len);
1766
1767 // some strange XMs have the order list padded with 0xFF, remove them!
1768 for (int16_t j = 255; j >= 0; j--)
1769 {
1770 if (songTmp.songTab[j] != 0xFF)
1771 break;
1772
1773 if (songTmp.len > j)
1774 songTmp.len = j;
1775 }
1776
1777 // even though XM supports 256 orders, FT2 supports only 255...
1778 if (songTmp.len > 0xFF)
1779 songTmp.len = 0xFF;
1780
1781 if (songTmp.ver < 0x0104)
1782 {
1783 // XM v1.02 and XM v1.03
1784
1785 for (i = 1; i <= h.antInstrs; i++)
1786 {
1787 if (!loadInstrHeader(f, i, externalThreadFlag))
1788 goto xmLoadError;
1789 }
1790
1791 if (!loadPatterns(f, h.antPtn, externalThreadFlag))
1792 goto xmLoadError;
1793
1794 for (i = 1; i <= h.antInstrs; i++)
1795 {
1796 if (!loadInstrSample(f, i, externalThreadFlag))
1797 goto xmLoadError;
1798 }
1799 }
1800 else
1801 {181 {
1802 // XM v1.04 (latest version)182 case FORMAT_XM: moduleLoaded = loadXM(f, filesize); break;
1803 183 case FORMAT_S3M: moduleLoaded = loadS3M(f, filesize); break;
1804 if (!loadPatterns(f, h.antPtn, externalThreadFlag))184 case FORMAT_STM: moduleLoaded = loadSTM(f, filesize); break;
1805 goto xmLoadError;185 case FORMAT_MOD: moduleLoaded = loadMOD(f, filesize); break;
186 case FORMAT_POSSIBLY_STK: moduleLoaded = loadSTK(f, filesize); break;
187 case FORMAT_DIGI: moduleLoaded = loadDIGI(f, filesize); break;
1806 188
1807 for (i = 1; i <= h.antInstrs; i++)189 default:
1808 {190 loaderMsgBox("This file is not a supported module!");
1809 if (!loadInstrHeader(f, i, externalThreadFlag))191 break;
1810 goto xmLoadError;
1811
1812 if (!loadInstrSample(f, i, externalThreadFlag))
1813 goto xmLoadError;
1814 }
1815 }
1816
1817 // if we temporarily loaded more than 128 instruments, clear the extra allocated memory
1818 if (h.antInstrs > MAX_INST)
1819 {
1820 for (i = MAX_INST+1; i <= h.antInstrs; i++)
1821 {
1822 if (instrTmp[i] != NULL)
1823 {
1824 free(instrTmp[i]);
1825 instrTmp[i] = NULL;
1826 }
1827 }
1828 }192 }
1829
1830 fclose(f);193 fclose(f);
1831 194
1832 /* We support loading XMs with up to 32 samples per instrument (ModPlug/OpenMPT),195 if (!moduleLoaded)
1833 ** but only the first 16 will be loaded. Now make sure we set the number of samples196 goto loadError;
1834 ** back to max 16 in the headers before loading is done.
1835 */
1836 bool instrHasMoreThan16Samples = false;
1837 for (i = 1; i <= MAX_INST; i++)
1838 {
1839 if (instrTmp[i] != NULL && instrTmp[i]->antSamp > MAX_SMP_PER_INST)
1840 {
1841 instrHasMoreThan16Samples = true;
1842 instrTmp[i]->antSamp = MAX_SMP_PER_INST;
1843 }
1844 }
1845
1846 if (songTmp.antChn > MAX_VOICES)
1847 {
1848 songTmp.antChn = MAX_VOICES;
1849 showMsg(0, "System message", "Warning: This XM contains >32 channels. The extra channels will be discarded!");
1850 }
1851
1852 if (h.antInstrs > MAX_INST)
1853 showMsg(0, "System message", "Warning: This XM contains >128 instruments. The extra instruments will be discarded!");
1854
1855 if (instrHasMoreThan16Samples)
1856 showMsg(0, "System message", "Warning: This XM contains instrument(s) with >16 samples. The extra samples will be discarded!");
1857 197
1858 moduleLoaded = true;198 moduleLoaded = true;
1859 return true;199 return true;
1860 200
1861xmLoadError:201loadError:
1862 fclose(f);
1863 freeTmpModule();202 freeTmpModule();
1864 moduleFailedToLoad = true;203 moduleFailedToLoad = true;
1865 return false;204 return false;
1866}205}
1867 206
207static void clearTmpModule(void)
208{
209 memset(pattTmp, 0, sizeof (pattTmp));
210 memset(instrTmp, 0, sizeof (instrTmp));
211 memset(&songTmp, 0, sizeof (songTmp));
212
213 for (uint32_t i = 0; i < MAX_PATTERNS; i++)
214 pattLensTmp[i] = 64;
215}
216
1868static int32_t SDLCALL loadMusicThread(void *ptr)217static int32_t SDLCALL loadMusicThread(void *ptr)
1869{218{
1870 return doLoadMusic(true);219 return doLoadMusic(true);
1871
1872 (void)ptr;220 (void)ptr;
1873}221}
1874 222
1875void loadMusic(UNICHAR *filenameU)223void loadMusic(UNICHAR *filenameU)
1876{224{
1877 if (musicIsLoading)225 if (musicIsLoading || filenameU == NULL)
1878 return;226 return;
1879 227
1880 mouseAnimOn();228 mouseAnimOn();
@@ -1882,19 +230,9 @@ void loadMusic(UNICHAR *filenameU) · 1 unmodified line
1882 musicIsLoading = true;230 musicIsLoading = true;
1883 moduleLoaded = false;231 moduleLoaded = false;
1884 moduleFailedToLoad = false;232 moduleFailedToLoad = false;
1885 loadedFormat = FORMAT_NONE;
1886 233
1887 UNICHAR_STRCPY(editor.tmpFilenameU, filenameU);234 clearTmpModule(); // clear stuff from last loading session (very important)
1888 235 UNICHAR_STRCPY(editor.tmpFilenameU, filenameU);
1889 // clear deprecated pointers from possible last loading session (super important)
1890 memset(pattTmp, 0, sizeof (pattTmp));
1891 memset(instrTmp, 0, sizeof (instrTmp));
1892
1893 // prevent stuck instrument names from previous module
1894 memset(&songTmp, 0, sizeof (songTmp));
1895
1896 for (uint32_t i = 0; i < MAX_PATTERNS; i++)
1897 pattLensTmp[i] = 64;
1898 236
1899 thread = SDL_CreateThread(loadMusicThread, NULL, NULL);237 thread = SDL_CreateThread(loadMusicThread, NULL, NULL);
1900 if (thread == NULL)238 if (thread == NULL)
@@ -1910,19 +248,10 @@ void loadMusic(UNICHAR *filenameU) · 9 unmodified lines
1910 248
1911bool loadMusicUnthreaded(UNICHAR *filenameU, bool autoPlay)249bool loadMusicUnthreaded(UNICHAR *filenameU, bool autoPlay)
1912{250{
1913 if (filenameU == NULL || editor.tmpFilenameU == NULL)251 if (filenameU == NULL)
1914 return false;252 return false;
1915 253
1916 // clear deprecated pointers from possible last loading session (super important)254 clearTmpModule(); // clear stuff from last loading session (very important)
1917 memset(pattTmp, 0, sizeof (pattTmp));
1918 memset(instrTmp, 0, sizeof (instrTmp));
1919
1920 // prevent stuck instrument names from previous module
1921 memset(&songTmp, 0, sizeof (songTmp));
1922
1923 for (uint32_t i = 0; i < MAX_PATTERNS; i++)
1924 pattLensTmp[i] = 64;
1925
1926 UNICHAR_STRCPY(editor.tmpFilenameU, filenameU);255 UNICHAR_STRCPY(editor.tmpFilenameU, filenameU);
1927 256
1928 editor.loadMusicEvent = EVENT_NONE;257 editor.loadMusicEvent = EVENT_NONE;
@@ -1940,6 +269,36 @@ bool loadMusicUnthreaded(UNICHAR *filenameU, bool autoPlay) · 11 unmodified lines
1940 return false;269 return false;
1941}270}
1942 271
272bool allocateTmpPatt(int32_t nr, uint16_t rows)
273{
274 pattTmp[nr] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
275 if (pattTmp[nr] == NULL)
276 return false;
277
278 pattLensTmp[nr] = rows;
279 return true;
280}
281
282bool allocateTmpInstr(int16_t nr)
283{
284 if (instrTmp[nr] != NULL)
285 return false; // already allocated
286
287 instrTyp *p = (instrTyp *)calloc(1, sizeof (instrTyp));
288 if (p == NULL)
289 return false;
290
291 sampleTyp *s = p->samp;
292 for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++)
293 {
294 s->pan = 128;
295 s->vol = 64;
296 }
297
298 instrTmp[nr] = p;
299 return true;
300}
301
1943static void freeTmpModule(void) // called on module load error302static void freeTmpModule(void) // called on module load error
1944{303{
1945 // free all patterns304 // free all patterns
@@ -1970,404 +329,7 @@ static void freeTmpModule(void) // called on module load error · 24 unmodified lines
1970 }329 }
1971}330}
1972 331
1973static bool loadInstrHeader(FILE *f, uint16_t i, bool externalThreadFlag)332bool tmpPatternEmpty(uint16_t nr)
1974{
1975 int8_t k;
1976 uint8_t j;
1977 uint32_t readSize;
1978 instrHeaderTyp ih;
1979 instrTyp *ins;
1980 sampleHeaderTyp *src;
1981 sampleTyp *s;
1982 int16_t (*showMsg)(int16_t, const char *, const char *);
1983
1984 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
1985
1986 memset(extraSampleLengths, 0, sizeof (extraSampleLengths));
1987 memset(&ih, 0, sizeof (ih));
1988 fread(&ih.instrSize, 4, 1, f);
1989
1990 readSize = ih.instrSize;
1991
1992 // yes, some XMs can have a header size of 0, and it usually means 263 bytes (INSTR_HEADER_SIZE)
1993 if (readSize == 0 || readSize > INSTR_HEADER_SIZE)
1994 readSize = INSTR_HEADER_SIZE;
1995
1996 if (readSize < 4)
1997 {
1998 showMsg(0, "System message", "Error loading XM: This file is corrupt (or not supported)!");
1999 return false;
2000 }
2001
2002 // load instrument data into temp buffer
2003 fread(ih.name, readSize-4, 1, f); // -4 = skip ih.instrSize
2004
2005 // FT2 bugfix: skip instrument header data if instrSize is above INSTR_HEADER_SIZE
2006 if (ih.instrSize > INSTR_HEADER_SIZE)
2007 fseek(f, ih.instrSize-INSTR_HEADER_SIZE, SEEK_CUR);
2008
2009 if (ih.antSamp < 0 || ih.antSamp > 32)
2010 {
2011 showMsg(0, "System message", "Error loading XM: This file is corrupt (or not supported)!");
2012 return false;
2013 }
2014
2015 if (i <= MAX_INST) // copy over instrument names
2016 {
2017 // trim off spaces at end of name
2018 for (k = 21; k >= 0; k--)
2019 {
2020 if (ih.name[k] == ' ' || ih.name[k] == 0x1A)
2021 ih.name[k] = '\0';
2022 else
2023 break;
2024 }
2025
2026 memcpy(songTmp.instrName[i], ih.name, 22);
2027 songTmp.instrName[i][22] = '\0';
2028 }
2029
2030 if (ih.antSamp > 0)
2031 {
2032 if (!allocateTmpInstr(i))
2033 {
2034 showMsg(0, "System message", "Not enough memory!");
2035 return false;
2036 }
2037
2038 // copy instrument header elements to our instrument struct
2039
2040 ins = instrTmp[i];
2041 memcpy(ins->ta, ih.ta, 96);
2042 memcpy(ins->envVP, ih.envVP, 12*2*sizeof(int16_t));
2043 memcpy(ins->envPP, ih.envPP, 12*2*sizeof(int16_t));
2044 ins->envVPAnt = ih.envVPAnt;
2045 ins->envPPAnt = ih.envPPAnt;
2046 ins->envVSust = ih.envVSust;
2047 ins->envVRepS = ih.envVRepS;
2048 ins->envVRepE = ih.envVRepE;
2049 ins->envPSust = ih.envPSust;
2050 ins->envPRepS = ih.envPRepS;
2051 ins->envPRepE = ih.envPRepE;
2052 ins->envVTyp = ih.envVTyp;
2053 ins->envPTyp = ih.envPTyp;
2054 ins->vibTyp = ih.vibTyp;
2055 ins->vibSweep = ih.vibSweep;
2056 ins->vibDepth = ih.vibDepth;
2057 ins->vibRate = ih.vibRate;
2058 ins->fadeOut = ih.fadeOut;
2059 ins->midiOn = (ih.midiOn == 1) ? true : false;
2060 ins->midiChannel = ih.midiChannel;
2061 ins->midiProgram = ih.midiProgram;
2062 ins->midiBend = ih.midiBend;
2063 ins->mute = (ih.mute == 1) ? true : false;
2064 ins->antSamp = ih.antSamp; // used in loadInstrSample()
2065
2066 // sanitize stuff for broken/unsupported instruments
2067 ins->midiProgram = CLAMP(ins->midiProgram, 0, 127);
2068 ins->midiBend = CLAMP(ins->midiBend, 0, 36);
2069
2070 if (ins->midiChannel > 15) ins->midiChannel = 15;
2071 if (ins->vibDepth > 0x0F) ins->vibDepth = 0x0F;
2072 if (ins->vibRate > 0x3F) ins->vibRate = 0x3F;
2073 if (ins->vibTyp > 3) ins->vibTyp = 0;
2074
2075 for (j = 0; j < 96; j++)
2076 {
2077 if (ins->ta[j] >= MAX_SMP_PER_INST)
2078 ins->ta[j] = MAX_SMP_PER_INST-1;
2079 }
2080
2081 if (ins->envVPAnt > 12) ins->envVPAnt = 12;
2082 if (ins->envVRepS > 11) ins->envVRepS = 11;
2083 if (ins->envVRepE > 11) ins->envVRepE = 11;
2084 if (ins->envVSust > 11) ins->envVSust = 11;
2085 if (ins->envPPAnt > 12) ins->envPPAnt = 12;
2086 if (ins->envPRepS > 11) ins->envPRepS = 11;
2087 if (ins->envPRepE > 11) ins->envPRepE = 11;
2088 if (ins->envPSust > 11) ins->envPSust = 11;
2089
2090 for (j = 0; j < 12; j++)
2091 {
2092 if ((uint16_t)ins->envVP[j][0] > 32767) ins->envVP[j][0] = 32767;
2093 if ((uint16_t)ins->envPP[j][0] > 32767) ins->envPP[j][0] = 32767;
2094 if ((uint16_t)ins->envVP[j][1] > 64) ins->envVP[j][1] = 64;
2095 if ((uint16_t)ins->envPP[j][1] > 63) ins->envPP[j][1] = 63;
2096 }
2097
2098 int32_t sampleHeadersToRead = ih.antSamp;
2099 if (sampleHeadersToRead > MAX_SMP_PER_INST)
2100 sampleHeadersToRead = MAX_SMP_PER_INST;
2101
2102 if (fread(ih.samp, sampleHeadersToRead * sizeof (sampleHeaderTyp), 1, f) != 1)
2103 {
2104 showMsg(0, "System message", "General I/O error during loading!");
2105 return false;
2106 }
2107
2108 // if instrument contains more than 16 sample headers (unsupported), skip them
2109 if (ih.antSamp > MAX_SMP_PER_INST) // can only be 0..32 at this point
2110 {
2111 const int32_t samplesToSkip = ih.antSamp-MAX_SMP_PER_INST;
2112 for (j = 0; j < samplesToSkip; j++)
2113 {
2114 fread(&extraSampleLengths[j], 4, 1, f); // used for skipping data in loadInstrSample()
2115 fseek(f, sizeof (sampleHeaderTyp)-4, SEEK_CUR);
2116 }
2117 }
2118
2119 for (j = 0; j < sampleHeadersToRead; j++)
2120 {
2121 s = &instrTmp[i]->samp[j];
2122 src = &ih.samp[j];
2123
2124 // copy sample header elements to our sample struct
2125
2126 s->len = src->len;
2127 s->repS = src->repS;
2128 s->repL = src->repL;
2129 s->vol = src->vol;
2130 s->fine = src->fine;
2131 s->typ = src->typ;
2132 s->pan = src->pan;
2133 s->relTon = src->relTon;
2134 memcpy(s->name, src->name, 22);
2135 s->name[22] = '\0';
2136
2137 // dst->pek is set up later
2138
2139 // trim off spaces at end of name
2140 for (k = 21; k >= 0; k--)
2141 {
2142 if (s->name[k] == ' ' || s->name[k] == 0x1A)
2143 s->name[k] = '\0';
2144 else
2145 break;
2146 }
2147
2148 // sanitize stuff broken/unsupported samples
2149 if (s->vol > 64)
2150 s->vol = 64;
2151
2152 s->relTon = CLAMP(s->relTon, -48, 71);
2153 }
2154 }
2155
2156 return true;
2157}
2158
2159void checkSampleRepeat(sampleTyp *s)
2160{
2161 if (s->repS < 0) s->repS = 0;
2162 if (s->repL < 0) s->repL = 0;
2163 if (s->repS > s->len) s->repS = s->len;
2164 if (s->repS+s->repL > s->len) s->repL = s->len - s->repS;
2165 if (s->repL == 0) s->typ &= ~3; // non-FT2 fix: force loop off if looplen is 0
2166}
2167
2168static bool loadInstrSample(FILE *f, uint16_t i, bool externalThreadFlag)
2169{
2170 int16_t (*showMsg)(int16_t, const char *, const char *);
2171
2172 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
2173
2174 if (instrTmp[i] == NULL)
2175 return true; // empty instrument, let's just pretend it got loaded successfully
2176
2177 uint16_t k = instrTmp[i]->antSamp;
2178 if (k > MAX_SMP_PER_INST)
2179 k = MAX_SMP_PER_INST;
2180
2181 sampleTyp *s = instrTmp[i]->samp;
2182
2183 if (i > MAX_INST) // insNum > 128, just skip sample data
2184 {
2185 for (uint16_t j = 0; j < k; j++, s++)
2186 {
2187 if (s->len > 0)
2188 fseek(f, s->len, SEEK_CUR);
2189 }
2190 }
2191 else
2192 {
2193 for (uint16_t j = 0; j < k; j++, s++)
2194 {
2195 // if a sample has both forward loop and pingpong loop set, make it pingpong loop only (FT2 mixer behavior)
2196 if ((s->typ & 3) == 3)
2197 s->typ &= 0xFE;
2198
2199 int32_t l = s->len;
2200 if (l <= 0)
2201 {
2202 s->pek = NULL;
2203 s->len = 0;
2204 s->repL = 0;
2205 s->repS = 0;
2206
2207 if (s->typ & 32)
2208 s->typ &= ~32; // remove stereo flag
2209 }
2210 else
2211 {
2212 int32_t bytesToSkip = 0;
2213 if (l > MAX_SAMPLE_LEN)
2214 {
2215 bytesToSkip = l - MAX_SAMPLE_LEN;
2216 l = MAX_SAMPLE_LEN;
2217 }
2218
2219 s->pek = NULL;
2220 s->origPek = (int8_t *)malloc(l + LOOP_FIX_LEN);
2221 if (s->origPek == NULL)
2222 {
2223 showMsg(0, "System message", "Not enough memory!");
2224 return false;
2225 }
2226
2227 s->pek = s->origPek + SMP_DAT_OFFSET;
2228
2229 const int32_t bytesRead = (int32_t)fread(s->pek, 1, l, f);
2230 if (bytesRead < l)
2231 {
2232 const int32_t bytesToClear = l - bytesRead;
2233 memset(&s->pek[bytesRead], 0, bytesToClear);
2234 }
2235
2236 if (bytesToSkip > 0)
2237 fseek(f, bytesToSkip, SEEK_CUR);
2238
2239 delta2Samp(s->pek, l, s->typ);
2240
2241 if (s->typ & 32) // stereo sample - already downmixed to mono in delta2samp()
2242 {
2243 s->typ &= ~32; // remove stereo flag
2244
2245 s->len >>= 1;
2246 s->repL >>= 1;
2247 s->repS >>= 1;
2248
2249 int8_t *newPtr = (int8_t *)realloc(s->origPek, s->len + LOOP_FIX_LEN);
2250 if (newPtr != NULL)
2251 {
2252 s->origPek = newPtr;
2253 s->pek = s->origPek + SMP_DAT_OFFSET;
2254 }
2255 }
2256 }
2257
2258 // NON-FT2 FIX: Align to 2-byte if 16-bit sample
2259 if (s->typ & 16)
2260 {
2261 s->repL &= 0xFFFFFFFE;
2262 s->repS &= 0xFFFFFFFE;
2263 s->len &= 0xFFFFFFFE;
2264 }
2265
2266 checkSampleRepeat(s);
2267 fixSample(s);
2268 }
2269 }
2270
2271 if (instrTmp[i]->antSamp > MAX_SMP_PER_INST)
2272 {
2273 const int32_t samplesToSkip = instrTmp[i]->antSamp-MAX_SMP_PER_INST;
2274 for (i = 0; i < samplesToSkip; i++)
2275 {
2276 if (extraSampleLengths[i] > 0)
2277 fseek(f, extraSampleLengths[i], SEEK_CUR);
2278 }
2279 }
2280
2281 return true;
2282}
2283
2284void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn)
2285{
2286 int32_t j;
2287
2288 if (dst == NULL)
2289 return;
2290
2291 const int32_t srcEnd = len * (sizeof (tonTyp) * antChn);
2292 int32_t srcIdx = 0;
2293
2294 int32_t numChannels = antChn;
2295 if (numChannels > MAX_VOICES)
2296 numChannels = MAX_VOICES;
2297
2298 const int32_t pitch = sizeof (tonTyp) * (MAX_VOICES - antChn);
2299 for (int32_t i = 0; i < len; i++)
2300 {
2301 for (j = 0; j < numChannels; j++)
2302 {
2303 if (srcIdx >= srcEnd)
2304 return; // error!
2305
2306 const uint8_t note = *src++;
2307 if (note & 0x80)
2308 {
2309 *dst++ = (note & 0x01) ? *src++ : 0;
2310 *dst++ = (note & 0x02) ? *src++ : 0;
2311 *dst++ = (note & 0x04) ? *src++ : 0;
2312 *dst++ = (note & 0x08) ? *src++ : 0;
2313 *dst++ = (note & 0x10) ? *src++ : 0;
2314 }
2315 else
2316 {
2317 *dst++ = note;
2318 *dst++ = *src++;
2319 *dst++ = *src++;
2320 *dst++ = *src++;
2321 *dst++ = *src++;
2322 }
2323
2324 // if note is overflowing (>97), remove it
2325 if (*(dst-5) > 97)
2326 *(dst-5) = 0;
2327
2328 // non-FT2 security fix: if effect is above 35 (Z), clear effect and parameter
2329 if (*(dst-2) > 35)
2330 {
2331 *(dst-2) = 0;
2332 *(dst-1) = 0;
2333 }
2334
2335 srcIdx += sizeof (tonTyp);
2336 }
2337
2338 // if more than 32 channels, skip rest of the channels for this row
2339 for (; j < antChn; j++)
2340 {
2341 if (srcIdx >= srcEnd)
2342 return; // error!
2343
2344 const uint8_t note = *src++;
2345 if (note & 0x80)
2346 {
2347 if (note & 0x01) src++;
2348 if (note & 0x02) src++;
2349 if (note & 0x04) src++;
2350 if (note & 0x08) src++;
2351 if (note & 0x10) src++;
2352 }
2353 else
2354 {
2355 src++;
2356 src++;
2357 src++;
2358 src++;
2359 }
2360
2361 srcIdx += sizeof (tonTyp);
2362 }
2363
2364 // if song has <32 channels, align pointer to next row (skip unused channels)
2365 if (antChn < MAX_VOICES)
2366 dst += pitch;
2367 }
2368}
2369
2370static bool tmpPatternEmpty(uint16_t nr)
2371{333{
2372 if (pattTmp[nr] == NULL)334 if (pattTmp[nr] == NULL)
2373 return true;335 return true;
@@ -2396,97 +358,6 @@ void clearUnusedChannels(tonTyp *p, int16_t pattLen, int32_t antChn) · 22 unmodified lines
2396 memset(ptr, 0, width);358 memset(ptr, 0, width);
2397}359}
2398 360
2399static bool loadPatterns(FILE *f, uint16_t antPtn, bool externalThreadFlag)
2400{
2401 uint8_t tmpLen;
2402 patternHeaderTyp ph;
2403 int16_t (*showMsg)(int16_t, const char *, const char *);
2404
2405 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
2406
2407 bool pattLenWarn = false;
2408 for (uint16_t i = 0; i < antPtn; i++)
2409 {
2410 if (fread(&ph.patternHeaderSize, 4, 1, f) != 1)
2411 goto pattCorrupt;
2412
2413 if (fread(&ph.typ, 1, 1, f) != 1)
2414 goto pattCorrupt;
2415
2416 ph.pattLen = 0;
2417 if (songTmp.ver == 0x0102)
2418 {
2419 if (fread(&tmpLen, 1, 1, f) != 1)
2420 goto pattCorrupt;
2421
2422 if (fread(&ph.dataLen, 2, 1, f) != 1)
2423 goto pattCorrupt;
2424
2425 ph.pattLen = tmpLen + 1; // +1 in v1.02
2426
2427 if (ph.patternHeaderSize > 8)
2428 fseek(f, ph.patternHeaderSize - 8, SEEK_CUR);
2429 }
2430 else
2431 {
2432 if (fread(&ph.pattLen, 2, 1, f) != 1)
2433 goto pattCorrupt;
2434
2435 if (fread(&ph.dataLen, 2, 1, f) != 1)
2436 goto pattCorrupt;
2437
2438 if (ph.patternHeaderSize > 9)
2439 fseek(f, ph.patternHeaderSize - 9, SEEK_CUR);
2440 }
2441
2442 if (feof(f))
2443 goto pattCorrupt;
2444
2445 pattLensTmp[i] = ph.pattLen;
2446 if (pattLensTmp[i] > MAX_PATT_LEN)
2447 {
2448 pattLensTmp[i] = MAX_PATT_LEN;
2449 pattLenWarn = true;
2450 }
2451
2452 if (ph.dataLen > 0)
2453 {
2454 pattTmp[i] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
2455 if (pattTmp[i] == NULL)
2456 {
2457 showMsg(0, "System message", "Not enough memory!");
2458 return false;
2459 }
2460
2461 if (fread(packedPattData, 1, ph.dataLen, f) != ph.dataLen)
2462 goto pattCorrupt;
2463
2464 unpackPatt((uint8_t *)pattTmp[i], packedPattData, pattLensTmp[i], songTmp.antChn);
2465 clearUnusedChannels(pattTmp[i], pattLensTmp[i], songTmp.antChn);
2466 }
2467
2468 if (tmpPatternEmpty(i))
2469 {
2470 if (pattTmp[i] != NULL)
2471 {
2472 free(pattTmp[i]);
2473 pattTmp[i] = NULL;
2474 }
2475
2476 pattLensTmp[i] = 64;
2477 }
2478 }
2479
2480 if (pattLenWarn)
2481 showMsg(0, "System message", "This module contains pattern(s) with a length above 256! They will be truncated.");
2482
2483 return true;
2484
2485pattCorrupt:
2486 showMsg(0, "System message", "Error loading XM: This file is corrupt!");
2487 return false;
2488}
2489
2490// called from input/video thread after the module was done loading361// called from input/video thread after the module was done loading
2491static void setupLoadedModule(void)362static void setupLoadedModule(void)
2492{363{
@@ -2513,16 +384,28 @@ static void setupLoadedModule(void) · 20 unmodified lines
2513 pattLens[i] = pattLensTmp[i];384 pattLens[i] = pattLensTmp[i];
2514 }385 }
2515 386
387 // copy over song struct
388 memcpy(&song, &songTmp, sizeof (songTyp));
389 fixSongName();
390
2516 // copy over new instruments (includes sample pointers)391 // copy over new instruments (includes sample pointers)
2517 for (int16_t i = 1; i <= MAX_INST; i++)392 for (int16_t i = 1; i <= MAX_INST; i++)
2518 {393 {
2519 instr[i] = instrTmp[i];394 instr[i] = instrTmp[i];
2520 fixSampleName(i);395 fixInstrAndSampleNames(i);
2521 }
2522 396
2523 // copy over song struct397 if (instr[i] != NULL)
2524 memcpy(&song, &songTmp, sizeof (songTyp));398 {
2525 fixSongName();399 for (int32_t j = 0; j < MAX_SMP_PER_INST; j++)
400 {
401 sampleTyp *s = &instr[i]->samp[j];
402
403 checkSampleRepeat(s);
404 if (s->pek != NULL)
405 fixSample(s); // prepare sample for branchless linear interpolation
406 }
407 }
408 }
2526 409
2527 // we are the owners of the allocated memory ptrs set by the loader thread now410 // we are the owners of the allocated memory ptrs set by the loader thread now
2528 411
@@ -2555,10 +438,7 @@ static void setupLoadedModule(void) · 26 unmodified lines
2555 editor.timer = song.timer;438 editor.timer = song.timer;
2556 editor.globalVol = song.globVol;439 editor.globalVol = song.globVol;
2557 440
2558 if (loadedFormat == FORMAT_XM)441 setFrqTab(tmpLinearPeriodsFlag);
2559 setFrqTab(linearFreqTable);
2560 else
2561 setFrqTab(false);
2562 442
2563 unlockMixerCallback();443 unlockMixerCallback();
2564 444
@@ -2639,14 +519,9 @@ bool handleModuleLoadFromArg(int argc, char **argv) · 74 unmodified lines
2639 UNICHAR_CHDIR(editor.binaryPathU);519 UNICHAR_CHDIR(editor.binaryPathU);
2640 520
2641 const int32_t filesize = getFileSize(filenameU);521 const int32_t filesize = getFileSize(filenameU);
2642 if (filesize == -1 || filesize >= 512L*1024*1024) // >=2GB or >=512MB522 if (filesize == -1 || filesize >= 512L*1024*1024) // 1) >=2GB 2) >=512MB
2643 {523 {
2644 okBox(0, "System message", "Error: The module is too big to be loaded!");524 okBox(0, "System message", "Error: The module is too big to be loaded!");
2645 /* This is not really true, but let's add this check to prevent accidentally
2646 ** passing really big files to the program. And how often do you really
2647 ** see a >=512MB .XM/.S3M module?
2648 */
2649
2650 free(filenameU);525 free(filenameU);
2651 UNICHAR_CHDIR(tmpPathU); // set old path back526 UNICHAR_CHDIR(tmpPathU); // set old path back
2652 return false;527 return false;
@@ -2659,6 +534,64 @@ bool handleModuleLoadFromArg(int argc, char **argv) · 6 unmodified lines
2659 return result;534 return result;
2660}535}
2661 536
537static bool fileIsModule(UNICHAR *pathU)
538{
539 FILE *f = UNICHAR_FOPEN(pathU, "rb");
540 if (f == NULL)
541 return false;
542
543 int8_t modFormat = detectModule(f);
544 fclose(f);
545
546 /* If the module was not identified (possibly STK type),
547 ** check the file extension and handle it as a module only
548 ** if it starts with "mod."/"stk." or ends with ".mod"/".stk" (case insensitive).
549 */
550 if (modFormat == FORMAT_POSSIBLY_STK)
551 {
552 char *path = unicharToCp437(pathU, false);
553 if (path == NULL)
554 return false;
555
556 int32_t pathLen = (int32_t)strlen(path);
557
558 // get filename from path
559 int32_t i = pathLen;
560 while (i--)
561 {
562 if (path[i] == DIR_DELIMITER)
563 break;
564 }
565
566 char *filename = path;
567 if (i > 0)
568 filename += i + 1;
569
570 int32_t filenameLen = (int32_t)strlen(filename);
571 // --------------------------
572
573 if (filenameLen > 5)
574 {
575 if (!_strnicmp("mod.", filename, 4) || !_strnicmp("stk.", filename, 4))
576 {
577 free(path);
578 return true;
579 }
580
581 if (!_strnicmp(".mod", &filename[filenameLen-4], 4) || !_strnicmp(".stk", &filename[filenameLen-4], 4))
582 {
583 free(path);
584 return true;
585 }
586 }
587
588 free(path);
589 return false;
590 }
591
592 return (modFormat != FORMAT_UNKNOWN);
593}
594
2662void loadDroppedFile(char *fullPathUTF8, bool songModifiedCheck)595void loadDroppedFile(char *fullPathUTF8, bool songModifiedCheck)
2663{596{
2664 if (ui.sysReqShown || fullPathUTF8 == NULL)597 if (ui.sysReqShown || fullPathUTF8 == NULL)
@@ -2701,15 +634,11 @@ void loadDroppedFile(char *fullPathUTF8, bool songModifiedCheck) · 36 unmodified lines
2701 634
2702 // pass UTF8 to these tests so that we can test file ending in ASCII/ANSI635 // pass UTF8 to these tests so that we can test file ending in ASCII/ANSI
2703 636
2704 if (fileIsInstrument(fullPathUTF8))637 if (fileIsInstr(fullPathU))
2705 {638 {
2706 loadInstr(fullPathU);639 loadInstr(fullPathU);
2707 }640 }
2708 else if (fileIsSample(fullPathUTF8))641 else if (fileIsModule(fullPathU))
2709 {
2710 loadSample(fullPathU, editor.curSmp, false);
2711 }
2712 else
2713 {642 {
2714 SDL_RestoreWindow(video.window);643 SDL_RestoreWindow(video.window);
2715 644
@@ -2729,6 +658,10 @@ void loadDroppedFile(char *fullPathUTF8, bool songModifiedCheck) · 13 unmodified lines
2729 editor.loadMusicEvent = EVENT_LOADMUSIC_DRAGNDROP;658 editor.loadMusicEvent = EVENT_LOADMUSIC_DRAGNDROP;
2730 loadMusic(fullPathU);659 loadMusic(fullPathU);
2731 }660 }
661 else
662 {
663 loadSample(fullPathU, editor.curSmp, false);
664 }
2732 665
2733 free(fullPathU);666 free(fullPathU);
2734}667}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t