ft2_module_loader.c (18766B)
1 // for finding memory leaks in debug mode with Visual Studio 2 #if defined _DEBUG && defined _MSC_VER 3 #include <crtdbg.h> 4 #endif 5 6 #include <stdio.h> 7 #include <stdint.h> 8 #include <stdbool.h> 9 #ifndef _WIN32 10 #include <unistd.h> 11 #endif 12 #include "ft2_header.h" 13 #include "scopes/ft2_scopes.h" 14 #include "ft2_trim.h" 15 #include "ft2_inst_ed.h" 16 #include "ft2_sample_ed.h" 17 #include "ft2_wav_renderer.h" 18 #include "ft2_pattern_ed.h" 19 #include "ft2_gui.h" 20 #include "ft2_diskop.h" 21 #include "ft2_sample_loader.h" 22 #include "ft2_smpfx.h" 23 #include "ft2_mouse.h" 24 #include "ft2_midi.h" 25 #include "ft2_events.h" 26 #include "ft2_video.h" 27 #include "ft2_structs.h" 28 #include "ft2_sysreqs.h" 29 30 bool detectBEM(FILE *f); 31 bool loadBEM(FILE *f, uint32_t filesize); 32 33 bool loadIT(FILE *f, uint32_t filesize); 34 bool loadDIGI(FILE *f, uint32_t filesize); 35 bool loadMOD(FILE *f, uint32_t filesize); 36 bool loadS3M(FILE *f, uint32_t filesize); 37 bool loadSTK(FILE *f, uint32_t filesize); 38 bool loadSTM(FILE *f, uint32_t filesize); 39 bool loadXM(FILE *f, uint32_t filesize); 40 41 enum 42 { 43 FORMAT_UNKNOWN = 0, 44 FORMAT_POSSIBLY_STK = 1, 45 FORMAT_XM = 2, 46 FORMAT_MOD = 3, 47 FORMAT_S3M = 4, 48 FORMAT_STM = 5, 49 FORMAT_DIGI = 6, 50 FORMAT_BEM = 7, 51 FORMAT_IT = 8 52 }; 53 54 // file extensions accepted by Disk Op. in module mode 55 char *supportedModExtensions[] = 56 { 57 "xm", "ft", "nst", "stk", "mod", "s3m", "stm", "fst", 58 "digi", "bem", "it", 59 60 // IMPORTANT: Remember comma after last entry above 61 "END_OF_LIST" // do NOT move, remove or edit this line! 62 }; 63 64 // globals for module loaders 65 volatile bool tmpLinearPeriodsFlag; 66 int16_t patternNumRowsTmp[MAX_PATTERNS]; 67 note_t *patternTmp[MAX_PATTERNS]; 68 instr_t *instrTmp[1+256]; 69 song_t songTmp; 70 // -------------------------- 71 72 static volatile bool musicIsLoading, moduleLoaded, moduleFailedToLoad; 73 static SDL_Thread *thread; 74 static uint8_t oldPlayMode; 75 static void setupLoadedModule(void); 76 static void freeTmpModule(void); 77 78 // Crude module detection routine. These aren't always accurate detections! 79 static int8_t detectModule(FILE *f) 80 { 81 uint8_t D[256], I[4]; 82 83 fseek(f, 0, SEEK_END); 84 uint32_t fileLength = (uint32_t)ftell(f); 85 rewind(f); 86 87 memset(D, 0, sizeof (D)); 88 fread(D, 1, sizeof (D), f); 89 fseek(f, 1080, SEEK_SET); // MOD ID 90 I[0] = I[1] = I[2] = I[3] = 0; 91 fread(I, 1, 4, f); 92 rewind(f); 93 94 // BEM ("UN05", from XM only, MikMod) 95 if (detectBEM(f)) 96 return FORMAT_BEM; 97 98 // DIGI Booster (non-Pro) 99 if (!memcmp("DIGI Booster module", &D[0x00], 19+1) && D[0x19] >= 1 && D[0x19] <= 8) 100 return FORMAT_DIGI; 101 102 // Scream Tracker 3 S3M (and compatible trackers) 103 if (!memcmp("SCRM", &D[0x2C], 4) && D[0x1D] == 16) // XXX: byte=16 in all cases? 104 return FORMAT_S3M; 105 106 // Scream Tracker 2 STM 107 if ((!memcmp("!Scream!", &D[0x14], 8) || !memcmp("BMOD2STM", &D[0x14], 8) || 108 !memcmp("WUZAMOD!", &D[0x14], 8) || !memcmp("SWavePro", &D[0x14], 8)) && D[0x1D] == 2) // XXX: byte=2 for "WUZAMOD!"/"SWavePro" ? 109 { 110 return FORMAT_STM; 111 } 112 113 // Generic multi-channel MOD (1..9 channels) 114 if (isdigit(I[0]) && I[0] != '0' && I[1] == 'C' && I[2] == 'H' && I[3] == 'N') // xCHN 115 return FORMAT_MOD; 116 117 // Digital Tracker (Atari Falcon) 118 if (I[0] == 'F' && I[1] == 'A' && I[2] == '0' && I[3] >= '4' && I[3] <= '8') // FA0x (x=4..8) 119 return FORMAT_MOD; 120 121 // Generic multi-channel MOD (10..99 channels) 122 if (isdigit(I[0]) && isdigit(I[1]) && I[0] != '0' && I[2] == 'C' && I[3] == 'H') // xxCH 123 return FORMAT_MOD; 124 125 // Generic multi-channel MOD (10..99 channels) 126 if (isdigit(I[0]) && isdigit(I[1]) && I[0] != '0' && I[2] == 'C' && I[3] == 'N') // xxCN (same as xxCH) 127 return FORMAT_MOD; 128 129 // ProTracker and generic MOD formats 130 if (!memcmp("M.K.", I, 4) || !memcmp("M!K!", I, 4) || !memcmp("NSMS", I, 4) || 131 !memcmp("LARD", I, 4) || !memcmp("PATT", I, 4) || !memcmp("FLT4", I, 4) || 132 !memcmp("FLT8", I, 4) || !memcmp("EXO4", I, 4) || !memcmp("EXO8", I, 4) || 133 !memcmp("N.T.", I, 4) || !memcmp("M&K!", I, 4) || !memcmp("FEST", I, 4) || 134 !memcmp("CD61", I, 4) || !memcmp("CD81", I, 4) || !memcmp("OKTA", I, 4) || 135 !memcmp("OCTA", I, 4)) 136 { 137 return FORMAT_MOD; 138 } 139 140 // Impulse Tracker and compatible trackers 141 if (!memcmp("IMPM", D, 4) && D[0x1D] == 0) 142 return FORMAT_IT; 143 144 /* Fasttracker II XM and compatible trackers. 145 ** Note: This test can falsely be true for STK modules (and non-supported files) where the 146 ** first 17 bytes start with "Extended Module: ". This is unlikely to happen. 147 */ 148 if (!memcmp("Extended Module: ", &D[0x00], 17)) 149 return FORMAT_XM; 150 151 /* Lastly, we assume that the file is either a 15-sample STK or an unsupported file. 152 ** Let's assume it's an STK and do some sanity checks. If they fail, we have an 153 ** unsupported file. 154 */ 155 156 // minimum and maximum (?) possible size for a supported STK 157 if (fileLength < 1624 || fileLength > 984634) 158 return FORMAT_UNKNOWN; 159 160 // test STK numOrders+BPM for illegal values 161 fseek(f, 470, SEEK_SET); 162 D[0] = D[1] = 0; 163 fread(D, 1, 2, f); 164 rewind(f); 165 166 if (D[0] <= 128 && D[1] <= 220) 167 return FORMAT_POSSIBLY_STK; 168 169 return FORMAT_UNKNOWN; 170 } 171 172 static bool doLoadMusic(bool externalThreadFlag) 173 { 174 // setup message box functions 175 loaderMsgBox = externalThreadFlag ? myLoaderMsgBoxThreadSafe : myLoaderMsgBox; 176 loaderSysReq = externalThreadFlag ? okBoxThreadSafe : okBox; 177 178 if (editor.tmpFilenameU == NULL) 179 { 180 loaderMsgBox("Generic memory fault during loading!"); 181 goto loadError; 182 } 183 184 FILE *f = UNICHAR_FOPEN(editor.tmpFilenameU, "rb"); 185 if (f == NULL) 186 { 187 loaderMsgBox("General I/O error during loading! Is the file in use? Does it exist?"); 188 goto loadError; 189 } 190 191 int8_t format = detectModule(f); 192 fseek(f, 0, SEEK_END); 193 uint32_t filesize = ftell(f); 194 195 rewind(f); 196 switch (format) 197 { 198 case FORMAT_XM: moduleLoaded = loadXM(f, filesize); break; 199 case FORMAT_S3M: moduleLoaded = loadS3M(f, filesize); break; 200 case FORMAT_STM: moduleLoaded = loadSTM(f, filesize); break; 201 case FORMAT_MOD: moduleLoaded = loadMOD(f, filesize); break; 202 case FORMAT_POSSIBLY_STK: moduleLoaded = loadSTK(f, filesize); break; 203 case FORMAT_DIGI: moduleLoaded = loadDIGI(f, filesize); break; 204 case FORMAT_BEM: moduleLoaded = loadBEM(f, filesize); break; 205 case FORMAT_IT: moduleLoaded = loadIT(f, filesize); break; 206 207 default: 208 loaderMsgBox("This file is not a supported module!"); 209 break; 210 } 211 fclose(f); 212 213 if (!moduleLoaded) 214 goto loadError; 215 216 moduleLoaded = true; 217 return true; 218 219 loadError: 220 freeTmpModule(); 221 moduleFailedToLoad = true; 222 return false; 223 } 224 225 static void clearTmpModule(void) 226 { 227 memset(patternTmp, 0, sizeof (patternTmp)); 228 memset(instrTmp, 0, sizeof (instrTmp)); 229 memset(&songTmp, 0, sizeof (songTmp)); 230 231 for (uint32_t i = 0; i < MAX_PATTERNS; i++) 232 patternNumRowsTmp[i] = 64; 233 } 234 235 static int32_t SDLCALL loadMusicThread(void *ptr) 236 { 237 return doLoadMusic(true); 238 (void)ptr; 239 } 240 241 void loadMusic(UNICHAR *filenameU) 242 { 243 if (musicIsLoading || filenameU == NULL) 244 return; 245 246 mouseAnimOn(); 247 248 musicIsLoading = true; 249 moduleLoaded = false; 250 moduleFailedToLoad = false; 251 252 clearTmpModule(); // clear stuff from last loading session (very important) 253 UNICHAR_STRCPY(editor.tmpFilenameU, filenameU); 254 255 thread = SDL_CreateThread(loadMusicThread, NULL, NULL); 256 if (thread == NULL) 257 { 258 editor.loadMusicEvent = EVENT_NONE; 259 okBox(0, "System message", "Couldn't create thread!", NULL); 260 musicIsLoading = false; 261 return; 262 } 263 264 SDL_DetachThread(thread); 265 } 266 267 bool loadMusicUnthreaded(UNICHAR *filenameU, bool autoPlay) 268 { 269 if (filenameU == NULL) 270 return false; 271 272 clearTmpModule(); // clear stuff from last loading session (very important) 273 UNICHAR_STRCPY(editor.tmpFilenameU, filenameU); 274 275 editor.loadMusicEvent = EVENT_NONE; 276 doLoadMusic(false); 277 278 if (moduleLoaded) 279 { 280 setupLoadedModule(); 281 if (autoPlay) 282 startPlaying(PLAYMODE_SONG, 0); 283 284 return true; 285 } 286 287 return false; 288 } 289 290 bool allocateTmpPatt(int32_t pattNum, uint16_t numRows) 291 { 292 patternTmp[pattNum] = (note_t *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1); 293 if (patternTmp[pattNum] == NULL) 294 return false; 295 296 patternNumRowsTmp[pattNum] = numRows; 297 return true; 298 } 299 300 bool allocateTmpInstr(int16_t insNum) 301 { 302 if (instrTmp[insNum] != NULL) 303 return false; // already allocated 304 305 instr_t *ins = (instr_t *)calloc(1, sizeof (instr_t)); 306 if (ins == NULL) 307 return false; 308 309 sample_t *s = ins->smp; 310 for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++) 311 { 312 s->panning = 128; 313 s->volume = 64; 314 } 315 316 instrTmp[insNum] = ins; 317 return true; 318 } 319 320 static void freeTmpModule(void) // called on module load error 321 { 322 // free all patterns 323 for (int32_t i = 0; i < MAX_PATTERNS; i++) 324 { 325 if (patternTmp[i] != NULL) 326 { 327 free(patternTmp[i]); 328 patternTmp[i] = NULL; 329 } 330 } 331 332 // free all instruments and samples 333 for (int32_t i = 1; i <= 256; i++) // if >128 instruments, we fake-load up to 128 extra (and discard them later) 334 { 335 if (instrTmp[i] == NULL) 336 continue; 337 338 sample_t *s = instrTmp[i]->smp; 339 for (int32_t j = 0; j < MAX_SMP_PER_INST; j++, s++) 340 freeSmpData(s); 341 342 free(instrTmp[i]); 343 instrTmp[i] = NULL; 344 } 345 } 346 347 bool tmpPatternEmpty(uint16_t pattNum) 348 { 349 if (patternTmp[pattNum] == NULL) 350 return true; 351 352 uint8_t *scanPtr = (uint8_t *)patternTmp[pattNum]; 353 const uint32_t scanLen = patternNumRowsTmp[pattNum] * TRACK_WIDTH; 354 355 for (uint32_t i = 0; i < scanLen; i++) 356 { 357 if (scanPtr[i] != 0) 358 return false; 359 } 360 361 return true; 362 } 363 364 void clearUnusedChannels(note_t *pattPtr, int16_t numRows, int32_t numChannels) 365 { 366 if (pattPtr == NULL || numChannels >= MAX_CHANNELS) 367 return; 368 369 const int32_t width = sizeof (note_t) * (MAX_CHANNELS - numChannels); 370 371 note_t *p = &pattPtr[numChannels]; 372 for (int32_t i = 0; i < numRows; i++, p += MAX_CHANNELS) 373 memset(p, 0, width); 374 } 375 376 // called from input/video thread after the module was done loading 377 static void setupLoadedModule(void) 378 { 379 lockMixerCallback(); 380 381 freeAllInstr(); 382 freeAllPatterns(); 383 384 oldPlayMode = playMode; 385 playMode = PLAYMODE_IDLE; 386 songPlaying = false; 387 388 #ifdef HAS_MIDI 389 midi.currMIDIVibDepth = 0; 390 midi.currMIDIPitch = 0; 391 #endif 392 393 memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab)); 394 395 // copy over new pattern pointers and lengths 396 for (int32_t i = 0; i < MAX_PATTERNS; i++) 397 { 398 pattern[i] = patternTmp[i]; 399 patternNumRows[i] = patternNumRowsTmp[i]; 400 } 401 402 // copy over song struct 403 memcpy(&song, &songTmp, sizeof (song_t)); 404 fixSongName(); 405 406 // copy over new instruments (includes sample pointers) 407 for (int16_t i = 1; i <= MAX_INST; i++) 408 { 409 instr[i] = instrTmp[i]; 410 fixInstrAndSampleNames(i); 411 412 if (instr[i] != NULL) 413 { 414 sanitizeInstrument(instr[i]); 415 for (int32_t j = 0; j < MAX_SMP_PER_INST; j++) 416 { 417 sample_t *s = &instr[i]->smp[j]; 418 419 sanitizeSample(s); 420 if (s->dataPtr != NULL) 421 fixSample(s); // prepare sample for branchless linear interpolation 422 } 423 } 424 } 425 426 // we are the owners of the allocated memory ptrs set by the loader thread now 427 428 // support non-even channel numbers 429 if (song.numChannels & 1) 430 { 431 song.numChannels++; 432 if (song.numChannels > MAX_CHANNELS) 433 song.numChannels = MAX_CHANNELS; 434 } 435 436 song.numChannels = CLAMP(song.numChannels, 2, MAX_CHANNELS); 437 song.songLength = CLAMP(song.songLength, 1, MAX_ORDERS); 438 song.BPM = CLAMP(song.BPM, MIN_BPM, MAX_BPM); 439 song.initialSpeed = song.speed = CLAMP(song.speed, 1, MAX_SPEED); 440 441 if (song.songLoopStart >= song.songLength) 442 song.songLoopStart = 0; 443 444 song.globalVolume = 64; 445 446 // remove overflown stuff in pattern data (FT2 doesn't do this) 447 for (int32_t i = 0; i < MAX_PATTERNS; i++) 448 { 449 if (patternNumRows[i] <= 0) 450 patternNumRows[i] = 64; 451 452 if (patternNumRows[i] > MAX_PATT_LEN) 453 patternNumRows[i] = MAX_PATT_LEN; 454 455 if (pattern[i] == NULL) 456 continue; 457 458 note_t *p = pattern[i]; 459 for (int32_t j = 0; j < MAX_PATT_LEN * MAX_CHANNELS; j++, p++) 460 { 461 if (p->note > 97) 462 p->note = 0; 463 464 if (p->instr > 128) 465 p->instr = 0; 466 467 if (p->efx > 35) 468 { 469 p->efx = 0; 470 p->efxData = 0; 471 } 472 } 473 } 474 475 setScrollBarEnd(SB_POS_ED, (song.songLength - 1) + 5); 476 setScrollBarPos(SB_POS_ED, 0, false); 477 478 resetChannels(); 479 setPos(0, 0, true); 480 setMixerBPM(song.BPM); 481 482 editor.tmpPattern = editor.editPattern; // set kludge variable 483 editor.BPM = song.BPM; 484 editor.speed = song.speed; 485 editor.tick = song.tick; 486 editor.globalVolume = song.globalVolume; 487 488 setLinearPeriods(tmpLinearPeriodsFlag); 489 490 unlockMixerCallback(); 491 492 editor.currVolEnvPoint = 0; 493 editor.currPanEnvPoint = 0; 494 495 refreshScopes(); 496 exitTextEditing(); 497 updateTextBoxPointers(); 498 resetChannelOffset(); 499 updateChanNums(); 500 resetWavRenderer(); 501 clearPattMark(); 502 clearSampleUndo(); 503 resetTrimSizes(); 504 resetPlaybackTime(); 505 506 diskOpSetFilename(DISKOP_ITEM_MODULE, editor.tmpFilenameU); 507 508 // redraw top part of screen 509 if (ui.extendedPatternEditor) 510 { 511 togglePatternEditorExtended(); // exit 512 togglePatternEditorExtended(); // re-enter (force redrawing) 513 } 514 else 515 { 516 // redraw top screen 517 hideTopScreen(); 518 showTopScreen(true); 519 } 520 521 updateSampleEditorSample(); 522 showBottomScreen(); // redraw bottom screen (also redraws pattern editor) 523 524 if (ui.instEditorShown) 525 drawPiano(NULL); // redraw piano now (since if playing = wait for next tick update) 526 527 removeSongModifiedFlag(); 528 529 moduleFailedToLoad = false; 530 moduleLoaded = false; 531 editor.loadMusicEvent = EVENT_NONE; 532 } 533 534 bool handleModuleLoadFromArg(int argc, char **argv) 535 { 536 // we always expect only one parameter, and that it is the module 537 538 if (argc != 2 || argv[1] == NULL || argv[1][0] == '\0') 539 return false; 540 541 #ifdef __APPLE__ 542 if (argc == 2 && !strncmp(argv[1], "-psn_", 5)) 543 return false; // OS X < 10.9 passes a -psn_x_xxxxx parameter on double-click launch 544 #endif 545 546 const uint32_t filenameLen = (const uint32_t)strlen(argv[1]); 547 548 UNICHAR *tmpPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR)); 549 if (tmpPathU == NULL) 550 { 551 okBox(0, "System message", "Not enough memory!", NULL); 552 return false; 553 } 554 555 UNICHAR *filenameU = (UNICHAR *)malloc((filenameLen + 1) * sizeof (UNICHAR)); 556 if (filenameU == NULL) 557 { 558 free(tmpPathU); 559 okBox(0, "System message", "Not enough memory!", NULL); 560 return false; 561 } 562 563 tmpPathU[0] = 0; 564 filenameU[0] = 0; 565 566 #ifdef _WIN32 567 MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, filenameU, filenameLen+1); 568 #else 569 strcpy(filenameU, argv[1]); 570 #endif 571 572 // store old path 573 UNICHAR_GETCWD(tmpPathU, PATH_MAX); 574 575 // set path to where the main executable is 576 UNICHAR_CHDIR(editor.binaryPathU); 577 578 const int32_t filesize = getFileSize(filenameU); 579 if (filesize == -1 || filesize >= 512L*1024*1024) // 1) >=2GB 2) >=512MB 580 { 581 free(filenameU); 582 UNICHAR_CHDIR(tmpPathU); // set old path back 583 free(tmpPathU); 584 585 okBox(0, "System message", "Error: The module is too big to be loaded!", NULL); 586 return false; 587 } 588 589 bool result = loadMusicUnthreaded(filenameU, true); 590 591 free(filenameU); 592 UNICHAR_CHDIR(tmpPathU); // set old path back 593 free(tmpPathU); 594 595 return result; 596 } 597 598 static bool fileIsModule(UNICHAR *pathU) 599 { 600 FILE *f = UNICHAR_FOPEN(pathU, "rb"); 601 if (f == NULL) 602 return false; 603 604 int8_t modFormat = detectModule(f); 605 fclose(f); 606 607 /* If the module was not identified (possibly STK type), 608 ** check the file extension and handle it as a module only 609 ** if it starts with "mod."/"stk." or ends with ".mod"/".stk" (case insensitive). 610 */ 611 if (modFormat == FORMAT_POSSIBLY_STK) 612 { 613 char *path = unicharToCp850(pathU, false); 614 if (path == NULL) 615 return false; 616 617 int32_t pathLen = (int32_t)strlen(path); 618 619 // get filename from path 620 int32_t i = pathLen; 621 while (i--) 622 { 623 if (path[i] == DIR_DELIMITER) 624 break; 625 } 626 627 char *filename = path; 628 if (i > 0) 629 filename += i + 1; 630 631 int32_t filenameLen = (int32_t)strlen(filename); 632 // -------------------------- 633 634 if (filenameLen > 5) 635 { 636 if (!_strnicmp("mod.", filename, 4) || !_strnicmp("stk.", filename, 4)) 637 { 638 free(path); 639 return true; 640 } 641 642 if (!_strnicmp(".mod", &filename[filenameLen-4], 4) || !_strnicmp(".stk", &filename[filenameLen-4], 4)) 643 { 644 free(path); 645 return true; 646 } 647 } 648 649 free(path); 650 return false; 651 } 652 653 return (modFormat != FORMAT_UNKNOWN); 654 } 655 656 void loadDroppedFile(char *fullPathUTF8, bool songModifiedCheck) 657 { 658 if (ui.sysReqShown || fullPathUTF8 == NULL) 659 return; 660 661 const int32_t fullPathLen = (const int32_t)strlen(fullPathUTF8); 662 if (fullPathLen == 0) 663 return; 664 665 UNICHAR *fullPathU = (UNICHAR *)malloc((fullPathLen + 1) * sizeof (UNICHAR)); 666 if (fullPathU == NULL) 667 { 668 okBox(0, "System message", "Not enough memory!", NULL); 669 return; 670 } 671 672 fullPathU[0] = 0; 673 674 #ifdef _WIN32 675 MultiByteToWideChar(CP_UTF8, 0, fullPathUTF8, -1, fullPathU, fullPathLen+1); 676 #else 677 strcpy(fullPathU, fullPathUTF8); 678 #endif 679 680 const int32_t filesize = getFileSize(fullPathU); 681 682 if (filesize == -1) // >2GB 683 { 684 okBox(0, "System message", "The file is too big and can't be loaded (over 2GB).", NULL); 685 free(fullPathU); 686 return; 687 } 688 689 if (filesize >= 128L*1024*1024) // 128MB 690 { 691 if (okBox(2, "System request", "Are you sure you want to load such a big file?", NULL) != 1) 692 { 693 free(fullPathU); 694 return; 695 } 696 } 697 698 exitTextEditing(); 699 700 // pass UTF8 to these tests so that we can test file ending in ASCII/ANSI 701 702 if (fileIsInstr(fullPathU)) 703 { 704 loadInstr(fullPathU); 705 } 706 else if (fileIsModule(fullPathU)) 707 { 708 if (songModifiedCheck && song.isModified) 709 { 710 if (!askUnsavedChanges(ASK_TYPE_LOAD_SONG)) 711 { 712 free(fullPathU); 713 return; 714 } 715 } 716 717 editor.loadMusicEvent = EVENT_LOADMUSIC_DRAGNDROP; 718 loadMusic(fullPathU); 719 } 720 else 721 { 722 loadSample(fullPathU, editor.curSmp, false); 723 } 724 725 free(fullPathU); 726 } 727 728 static void handleOldPlayMode(void) 729 { 730 playMode = oldPlayMode; 731 if (oldPlayMode != PLAYMODE_IDLE && oldPlayMode != PLAYMODE_EDIT) 732 startPlaying(oldPlayMode, 0); 733 734 songPlaying = (playMode >= PLAYMODE_SONG); 735 } 736 737 // called from input/video thread after module load thread was finished 738 void handleLoadMusicEvents(void) 739 { 740 if (!moduleLoaded && !moduleFailedToLoad) 741 return; // no event to handle 742 743 if (moduleFailedToLoad) 744 { 745 // module failed to load from loading thread 746 musicIsLoading = false; 747 moduleFailedToLoad = false; 748 moduleLoaded = false; 749 editor.loadMusicEvent = EVENT_NONE; 750 setMouseBusy(false); 751 return; 752 } 753 754 if (moduleLoaded) 755 { 756 // module was successfully loaded from loading thread 757 758 switch (editor.loadMusicEvent) 759 { 760 // module dragged and dropped *OR* user double clicked a file associated with FT2 clone 761 case EVENT_LOADMUSIC_DRAGNDROP: 762 { 763 setupLoadedModule(); 764 if (editor.autoPlayOnDrop) 765 startPlaying(PLAYMODE_SONG, 0); 766 else 767 handleOldPlayMode(); 768 } 769 break; 770 771 // filename passed as an exe argument *OR* user double clicked a file associated with FT2 clone 772 case EVENT_LOADMUSIC_ARGV: 773 { 774 setupLoadedModule(); 775 startPlaying(PLAYMODE_SONG, 0); 776 } 777 break; 778 779 // module filename pressed in Disk Op. 780 case EVENT_LOADMUSIC_DISKOP: 781 { 782 setupLoadedModule(); 783 handleOldPlayMode(); 784 } 785 break; 786 787 default: break; 788 } 789 790 moduleLoaded = false; 791 editor.loadMusicEvent = EVENT_NONE; 792 musicIsLoading = false; 793 mouseAnimOff(); 794 } 795 }