ft2_module_saver.c (17728B)
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 <stdbool.h> 8 #include "ft2_header.h" 9 #include "ft2_audio.h" 10 #include "ft2_gui.h" 11 #include "ft2_mouse.h" 12 #include "ft2_sample_ed.h" 13 #include "ft2_module_loader.h" 14 #include "ft2_tables.h" 15 #include "ft2_structs.h" 16 17 static int8_t smpChunkBuf[1024]; 18 static uint8_t packedPattData[65536], modPattData[64*32*4]; 19 static SDL_Thread *thread; 20 21 static const char modIDs[32][5] = 22 { 23 "1CHN", "2CHN", "3CHN", "4CHN", "5CHN", "6CHN", "7CHN", "8CHN", 24 "9CHN", "10CH", "11CH", "12CH", "13CH", "14CH", "15CH", "16CH", 25 "17CH", "18CH", "19CH", "20CH", "21CH", "22CH", "23CH", "24CH", 26 "25CH", "26CH", "27CH", "28CH", "29CH", "30CH", "31CH", "32CH" 27 }; 28 29 static uint16_t packPatt(uint8_t *writePtr, uint8_t *pattPtr, uint16_t numRows); 30 31 bool saveXM(UNICHAR *filenameU) 32 { 33 int16_t i, j, k, a; 34 size_t result; 35 xmHdr_t h; 36 xmPatHdr_t ph; 37 instr_t *ins; 38 xmInsHdr_t ih; 39 sample_t *s; 40 xmSmpHdr_t *dst; 41 42 FILE *f = UNICHAR_FOPEN(filenameU, "wb"); 43 if (f == NULL) 44 { 45 okBoxThreadSafe(0, "System message", "Error opening file for saving, is it in use?", NULL); 46 return false; 47 } 48 49 memcpy(h.ID, "Extended Module: ", 17); 50 51 // song name 52 int32_t nameLength = (int32_t)strlen(song.name); 53 if (nameLength > 20) 54 nameLength = 20; 55 56 memset(h.name, ' ', 20); // yes, FT2 pads the name with spaces 57 if (nameLength > 0) 58 memcpy(h.name, song.name, nameLength); 59 60 h.x1A = 0x1A; 61 62 // program/tracker name 63 nameLength = (int32_t)strlen(PROG_NAME_STR); 64 if (nameLength > 20) 65 nameLength = 20; 66 67 memset(h.progName, ' ', 20); // yes, FT2 pads the name with spaces 68 if (nameLength > 0) 69 memcpy(h.progName, PROG_NAME_STR, nameLength); 70 71 h.version = 0x0104; 72 h.headerSize = 20 + 256; 73 h.numOrders = song.songLength; 74 h.songLoopStart = song.songLoopStart; 75 h.numChannels = (uint16_t)song.numChannels; 76 h.speed = song.speed; 77 h.BPM = song.BPM; 78 79 // count number of patterns 80 i = MAX_PATTERNS; 81 do 82 { 83 if (patternEmpty(i-1)) 84 i--; 85 else 86 break; 87 } 88 while (i > 0); 89 h.numPatterns = i; 90 91 // count number of instruments 92 i = 128; 93 while (i > 0 && getUsedSamples(i) == 0 && song.instrName[i][0] == '\0') 94 i--; 95 h.numInstr = i; 96 97 h.flags = audio.linearPeriodsFlag; 98 memcpy(h.orders, song.orders, 256); 99 100 if (fwrite(&h, sizeof (h), 1, f) != 1) 101 { 102 fclose(f); 103 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 104 return false; 105 } 106 107 for (i = 0; i < h.numPatterns; i++) 108 { 109 if (patternEmpty(i)) 110 { 111 if (pattern[i] != NULL) 112 { 113 free(pattern[i]); 114 pattern[i] = NULL; 115 } 116 117 patternNumRows[i] = 64; 118 } 119 120 ph.headerSize = sizeof (xmPatHdr_t); 121 ph.numRows = patternNumRows[i]; 122 ph.type = 0; 123 124 if (pattern[i] == NULL) 125 { 126 ph.dataSize = 0; 127 if (fwrite(&ph, ph.headerSize, 1, f) != 1) 128 { 129 fclose(f); 130 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 131 return false; 132 } 133 } 134 else 135 { 136 ph.dataSize = packPatt(packedPattData, (uint8_t *)pattern[i], patternNumRows[i]); 137 138 result = fwrite(&ph, ph.headerSize, 1, f); 139 result += fwrite(packedPattData, ph.dataSize, 1, f); 140 141 if (result != 2) // write was not OK 142 { 143 fclose(f); 144 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 145 return false; 146 } 147 } 148 } 149 150 memset(&ih, 0, sizeof (ih)); // important, clears reserved stuff 151 152 for (i = 1; i <= h.numInstr; i++) 153 { 154 if (instr[i] == NULL) 155 j = 0; 156 else 157 j = i; 158 159 a = getUsedSamples(i); 160 161 nameLength = (int32_t)strlen(song.instrName[i]); 162 if (nameLength > 22) 163 nameLength = 22; 164 165 memset(ih.name, 0, 22); // pad with zero 166 if (nameLength > 0) 167 memcpy(ih.name, song.instrName[i], nameLength); 168 169 ih.type = 0; 170 ih.numSamples = a; 171 ih.sampleSize = sizeof (xmSmpHdr_t); 172 173 if (a > 0) 174 { 175 ins = instr[j]; 176 177 memcpy(ih.note2SampleLUT, ins->note2SampleLUT, 96); 178 memcpy(ih.volEnvPoints, ins->volEnvPoints, 12*2*sizeof(int16_t)); 179 memcpy(ih.panEnvPoints, ins->panEnvPoints, 12*2*sizeof(int16_t)); 180 ih.volEnvLength = ins->volEnvLength; 181 ih.panEnvLength = ins->panEnvLength; 182 ih.volEnvSustain = ins->volEnvSustain; 183 ih.volEnvLoopStart = ins->volEnvLoopStart; 184 ih.volEnvLoopEnd = ins->volEnvLoopEnd; 185 ih.panEnvSustain = ins->panEnvSustain; 186 ih.panEnvLoopStart = ins->panEnvLoopStart; 187 ih.panEnvLoopEnd = ins->panEnvLoopEnd; 188 ih.volEnvFlags = ins->volEnvFlags; 189 ih.panEnvFlags = ins->panEnvFlags; 190 ih.vibType = ins->autoVibType; 191 ih.vibSweep = ins->autoVibSweep; 192 ih.vibDepth = ins->autoVibDepth; 193 ih.vibRate = ins->autoVibRate; 194 ih.fadeout = ins->fadeout; 195 ih.midiOn = ins->midiOn ? 1 : 0; 196 ih.midiChannel = ins->midiChannel; 197 ih.midiProgram = ins->midiProgram; 198 ih.midiBend = ins->midiBend; 199 ih.mute = ins->mute ? 1 : 0; 200 ih.instrSize = INSTR_HEADER_SIZE; 201 202 for (k = 0; k < a; k++) 203 { 204 s = &instr[j]->smp[k]; 205 dst = &ih.smp[k]; 206 207 bool sample16Bit = !!(s->flags & SAMPLE_16BIT); 208 209 dst->length = s->length; 210 dst->loopStart = s->loopStart; 211 dst->loopLength = s->loopLength; 212 213 if (sample16Bit) 214 { 215 dst->length <<= 1; 216 dst->loopStart <<= 1; 217 dst->loopLength <<= 1; 218 } 219 220 dst->volume = s->volume; 221 dst->finetune = s->finetune; 222 dst->flags = s->flags; 223 dst->panning = s->panning; 224 dst->relativeNote = s->relativeNote; 225 226 nameLength = (int32_t)strlen(s->name); 227 if (nameLength > 22) 228 nameLength = 22; 229 230 dst->nameLength = (uint8_t)nameLength; 231 232 memset(dst->name, ' ', 22); // yes, FT2 pads the name with spaces 233 if (nameLength > 0) 234 memcpy(dst->name, s->name, nameLength); 235 236 if (s->dataPtr == NULL) 237 dst->length = 0; 238 } 239 } 240 else 241 { 242 ih.instrSize = 22 + 11; 243 } 244 245 if (fwrite(&ih, ih.instrSize + (a * sizeof (xmSmpHdr_t)), 1, f) != 1) 246 { 247 fclose(f); 248 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 249 return false; 250 } 251 252 for (k = 1; k <= a; k++) 253 { 254 s = &instr[j]->smp[k-1]; 255 if (s->dataPtr != NULL) 256 { 257 unfixSample(s); 258 samp2Delta(s->dataPtr, s->length, s->flags); 259 260 result = fwrite(s->dataPtr, 1, SAMPLE_LENGTH_BYTES(s), f); 261 262 delta2Samp(s->dataPtr, s->length, s->flags); 263 fixSample(s); 264 265 if (result != (size_t)SAMPLE_LENGTH_BYTES(s)) // write not OK 266 { 267 fclose(f); 268 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 269 return false; 270 } 271 } 272 } 273 } 274 275 removeSongModifiedFlag(); 276 277 fclose(f); 278 279 editor.diskOpReadDir = true; // force diskop re-read 280 281 setMouseBusy(false); 282 return true; 283 } 284 285 static bool saveMOD(UNICHAR *filenameU) 286 { 287 int16_t i; 288 int32_t j, k; 289 instr_t *ins; 290 sample_t *smp; 291 modHdr_t hdr; 292 293 // Commented out. This one was probably confusing to many people... 294 /* 295 if (audio.linearPeriodsFlag) 296 okBoxThreadSafe(0, "System message", "Warning: \"Frequency slides\" is not set to Amiga!"); 297 */ 298 299 int32_t songLength = song.songLength; 300 if (songLength > 128) 301 { 302 songLength = 128; 303 okBoxThreadSafe(0, "System message", "Warning: Song length is above 128!", NULL); 304 } 305 306 // calculate number of patterns referenced (max 128 orders) 307 int32_t numPatterns = 0; 308 for (i = 0; i < songLength; i++) 309 { 310 if (song.orders[i] > numPatterns) 311 numPatterns = song.orders[i]; 312 } 313 numPatterns++; 314 315 if (numPatterns > 100) 316 { 317 numPatterns = 100; 318 okBoxThreadSafe(0, "System message", "Warning: Song has more than 100 patterns!", NULL); 319 } 320 321 // check if song has more than 31 instruments 322 for (i = 32; i <= 128; i++) 323 { 324 if (getRealUsedSamples(i) > 0) 325 { 326 okBoxThreadSafe(0, "System message", "Warning: Song has more than 31 instruments!", NULL); 327 break; 328 } 329 } 330 331 // check if the first 31 samples have a length above 65534 samples 332 bool test = false; 333 bool test2 = false; 334 for (i = 1; i <= 31; i++) 335 { 336 ins = instr[i]; 337 if (ins == NULL) 338 continue; 339 340 smp = &ins->smp[0]; 341 342 if (smp->length > 131070) 343 test = true; 344 else if (smp->length > 65534) 345 test2 = true; 346 } 347 if (test) okBoxThreadSafe(0, "System message", "Warning: Song has sample lengths that are too long for the MOD format!", NULL); 348 else if (test2) okBoxThreadSafe(0, "System message", "Warning: Song has sample lengths above 65534! Not all MOD players support this.", NULL); 349 350 // check if XM instrument features are being used 351 test = false; 352 for (i = 1; i <= 31; i++) 353 { 354 ins = instr[i]; 355 if (ins == NULL) 356 continue; 357 358 smp = &ins->smp[0]; 359 360 j = getRealUsedSamples(i); 361 if (j > 1) 362 { 363 test = true; 364 break; 365 } 366 367 if (j == 1) 368 { 369 if (ins->fadeout != 0 || ins->volEnvFlags != 0 || ins->panEnvFlags != 0 || ins->autoVibRate > 0 || 370 GET_LOOPTYPE(smp->flags) == LOOP_BIDI || smp->relativeNote != 0 || ins->midiOn) 371 { 372 test = true; 373 break; 374 } 375 } 376 } 377 if (test) okBoxThreadSafe(0, "System message", "Warning: Song is using XM instrument features!", NULL); 378 379 bool tooLongPatterns = false; 380 bool tooManyInstr = false; 381 bool incompatEfx = false; 382 bool noteUnderflow = false; 383 384 for (i = 0; i < numPatterns; i++) 385 { 386 if (pattern[i] == NULL) 387 continue; 388 389 if (patternNumRows[i] < 64) 390 { 391 okBoxThreadSafe(0, "System message", "Error: Pattern lengths can't be below 64! Module wasn't saved.", NULL); 392 return false; 393 } 394 395 if (patternNumRows[i] > 64) 396 tooLongPatterns = true; 397 398 for (j = 0; j < 64; j++) 399 { 400 for (k = 0; k < song.numChannels; k++) 401 { 402 note_t *p = &pattern[i][(j * MAX_CHANNELS) + k]; 403 404 if (p->instr > 31) 405 tooManyInstr = true; 406 407 if (p->efx > 0xF || p->vol != 0) 408 incompatEfx = true; 409 410 // added security that wasn't present in FT2 411 if (p->note > 0 && p->note < 10) 412 noteUnderflow = true; 413 } 414 } 415 } 416 417 if (tooLongPatterns) okBoxThreadSafe(0, "System message", "Warning: Song has pattern lengths above 64!", NULL); 418 if (tooManyInstr) okBoxThreadSafe(0, "System message", "Warning: Patterns have instrument numbers above 31!", NULL); 419 if (incompatEfx) okBoxThreadSafe(0, "System message", "Warning: Patterns have incompatible effects!", NULL); 420 if (noteUnderflow) okBoxThreadSafe(0, "System message", "Warning: Patterns have notes below A-0!", NULL); 421 422 // save module now 423 424 memset(&hdr, 0, sizeof (hdr)); 425 426 // song name 427 int32_t nameLength = (int32_t)strlen(song.name); 428 if (nameLength > 20) 429 nameLength = 20; 430 431 memset(hdr.name, 0, 20); // pad with zeroes 432 if (nameLength > 0) 433 memcpy(hdr.name, song.name, nameLength); 434 435 hdr.numOrders = (uint8_t)songLength; // pre-clamped to 0..128 436 437 hdr.songLoopStart = (uint8_t)song.songLoopStart; 438 if (hdr.songLoopStart >= hdr.numOrders) // repeat-point must be lower than the song length 439 hdr.songLoopStart = 0; 440 441 memcpy(hdr.orders, song.orders, hdr.numOrders); 442 443 if (song.numChannels == 4) 444 memcpy(hdr.ID, (numPatterns > 64) ? "M!K!" : "M.K.", 4); 445 else 446 memcpy(hdr.ID, modIDs[song.numChannels-1], 4); 447 448 // fill MOD sample headers 449 for (i = 1; i <= 31; i++) 450 { 451 modSmpHdr_t *modSmp = &hdr.smp[i-1]; 452 453 nameLength = (int32_t)strlen(song.instrName[i]); 454 if (nameLength > 22) 455 nameLength = 22; 456 457 memset(modSmp->name, 0, 22); // pad with zeroes 458 if (nameLength > 0) 459 memcpy(modSmp->name, song.instrName[i], nameLength); 460 461 if (instr[i] != NULL && getRealUsedSamples(i) != 0) 462 { 463 smp = &instr[i]->smp[0]; 464 465 int32_t length = smp->length >> 1; 466 int32_t loopStart = smp->loopStart >> 1; 467 int32_t loopLength = smp->loopLength >> 1; 468 469 // length/loopStart/loopLength are now in units of words 470 471 if (length > UINT16_MAX) 472 length = UINT16_MAX; 473 474 if (GET_LOOPTYPE(smp->flags) == LOOP_OFF) 475 { 476 loopStart = 0; 477 loopLength = 1; 478 } 479 else // looped sample 480 { 481 if (loopLength == 0) // ProTracker hates loopLengths of zero 482 loopLength = 1; 483 484 if (loopStart+loopLength > length) 485 { 486 loopStart = 0; 487 loopLength = 1; 488 } 489 } 490 491 modSmp->length = (uint16_t)SWAP16(length); 492 modSmp->finetune = FINETUNE_XM2MOD(smp->finetune); 493 modSmp->volume = smp->volume; 494 modSmp->loopStart = (uint16_t)SWAP16(loopStart); 495 modSmp->loopLength = (uint16_t)SWAP16(loopLength); 496 } 497 } 498 499 FILE *f = UNICHAR_FOPEN(filenameU, "wb"); 500 if (f == NULL) 501 { 502 okBoxThreadSafe(0, "System message", "Error opening file for saving, is it in use?", NULL); 503 return false; 504 } 505 506 // write header 507 if (fwrite(&hdr, 1, sizeof (hdr), f) != sizeof (hdr)) 508 { 509 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 510 goto modSaveError; 511 } 512 513 // write pattern data 514 const int32_t patternBytes = song.numChannels * 64 * 4; 515 for (i = 0; i < numPatterns; i++) 516 { 517 if (pattern[i] == NULL) // empty pattern 518 { 519 memset(modPattData, 0, patternBytes); 520 } 521 else 522 { 523 int32_t offs = 0; 524 for (j = 0; j < 64; j++) 525 { 526 for (k = 0; k < song.numChannels; k++) 527 { 528 note_t *p = &pattern[i][(j * MAX_CHANNELS) + k]; 529 530 uint8_t inst = p->instr; 531 uint8_t note = p->note; 532 533 // FT2 bugfix: prevent overflow 534 if (inst > 31) 535 inst = 0; 536 537 // FT2 bugfix: convert note-off into no note for MOD saving 538 if (note == NOTE_OFF) 539 note = 0; 540 541 // FT2 bugfix: clamp notes below 10 (A-0) to prevent 12-bit period overflow 542 if (note > 0 && note < 10) 543 note = 10; 544 545 if (note == 0) 546 { 547 modPattData[offs+0] = inst & 0xF0; 548 modPattData[offs+1] = 0; 549 } 550 else 551 { 552 modPattData[offs+0] = (inst & 0xF0) | ((modPeriods[note-1] >> 8) & 0x0F); 553 modPattData[offs+1] = modPeriods[note-1] & 0xFF; 554 } 555 556 // FT2 bugfix: if effect is overflowing (0xF in .MOD), set effect and param to 0 557 if (p->efx > 0x0F) 558 { 559 modPattData[offs+2] = (inst & 0x0F) << 4; 560 modPattData[offs+3] = 0; 561 } 562 else 563 { 564 modPattData[offs+2] = ((inst & 0x0F) << 4) | (p->efx & 0x0F); 565 modPattData[offs+3] = p->efxData; 566 } 567 568 offs += 4; 569 } 570 } 571 } 572 573 if (fwrite(modPattData, 1, patternBytes, f) != (size_t)patternBytes) 574 { 575 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 576 goto modSaveError; 577 } 578 } 579 580 // write sample data 581 for (i = 1; i <= 31; i++) 582 { 583 if (instr[i] == NULL || getRealUsedSamples(i) == 0) 584 continue; 585 586 smp = &instr[i]->smp[0]; 587 if (smp->dataPtr == NULL || smp->length <= 0) 588 continue; 589 590 modSmpHdr_t *modSmp = &hdr.smp[i-1]; 591 592 unfixSample(smp); 593 594 int32_t sampleBytes = SWAP16(modSmp->length) * 2; 595 596 if (smp->flags & SAMPLE_16BIT) // 16-bit sample (convert to 8-bit) 597 { 598 int8_t *dstPtr = (int8_t *)smpChunkBuf; 599 int32_t writeLen = sampleBytes; 600 int32_t samplesWritten = 0; 601 602 while (samplesWritten < writeLen) // write in chunks 603 { 604 int32_t samplesToWrite = sizeof (smpChunkBuf); 605 if (samplesWritten+samplesToWrite > writeLen) 606 samplesToWrite = writeLen - samplesWritten; 607 608 int16_t *srcPtr16 = (int16_t *)smp->dataPtr + samplesWritten; 609 for (j = 0; j < samplesToWrite; j++) 610 dstPtr[j] = srcPtr16[j] >> 8; // convert 16-bit to 8-bit 611 612 if (fwrite(dstPtr, 1, samplesToWrite, f) != (size_t)samplesToWrite) 613 { 614 fixSample(smp); 615 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 616 goto modSaveError; 617 } 618 619 samplesWritten += samplesToWrite; 620 } 621 } 622 else // 8-bit sample 623 { 624 if (fwrite(smp->dataPtr, 1, sampleBytes, f) != (size_t)sampleBytes) 625 { 626 fixSample(smp); 627 okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!", NULL); 628 goto modSaveError; 629 } 630 } 631 632 fixSample(smp); 633 } 634 635 fclose(f); 636 removeSongModifiedFlag(); 637 638 editor.diskOpReadDir = true; // force diskop re-read 639 640 setMouseBusy(false); 641 return true; 642 643 modSaveError: 644 fclose(f); 645 return false; 646 } 647 648 static int32_t SDLCALL saveMusicThread(void *ptr) 649 { 650 assert(editor.tmpFilenameU != NULL); 651 if (editor.tmpFilenameU == NULL) 652 return false; 653 654 pauseAudio(); 655 656 if (editor.moduleSaveMode == 1) 657 saveXM(editor.tmpFilenameU); 658 else 659 saveMOD(editor.tmpFilenameU); 660 661 resumeAudio(); 662 return true; 663 664 (void)ptr; 665 } 666 667 void saveMusic(UNICHAR *filenameU) 668 { 669 UNICHAR_STRCPY(editor.tmpFilenameU, filenameU); 670 671 mouseAnimOn(); 672 thread = SDL_CreateThread(saveMusicThread, NULL, NULL); 673 if (thread == NULL) 674 { 675 okBoxThreadSafe(0, "System message", "Couldn't create thread!", NULL); 676 return; 677 } 678 679 SDL_DetachThread(thread); 680 } 681 682 static uint16_t packPatt(uint8_t *writePtr, uint8_t *pattPtr, uint16_t numRows) 683 { 684 uint8_t bytes[5]; 685 686 if (pattPtr == NULL) 687 return 0; 688 689 uint16_t totalPackLen = 0; 690 691 const int32_t pitch = sizeof (note_t) * (MAX_CHANNELS - song.numChannels); 692 for (int32_t row = 0; row < numRows; row++) 693 { 694 for (int32_t chn = 0; chn < song.numChannels; chn++) 695 { 696 bytes[0] = *pattPtr++; 697 bytes[1] = *pattPtr++; 698 bytes[2] = *pattPtr++; 699 bytes[3] = *pattPtr++; 700 bytes[4] = *pattPtr++; 701 702 uint8_t *firstBytePtr = writePtr++; 703 704 uint8_t packBits = 0; 705 if (bytes[0] > 0) { packBits |= 1; *writePtr++ = bytes[0]; } // note 706 if (bytes[1] > 0) { packBits |= 2; *writePtr++ = bytes[1]; } // instrument 707 if (bytes[2] > 0) { packBits |= 4; *writePtr++ = bytes[2]; } // volume column 708 if (bytes[3] > 0) { packBits |= 8; *writePtr++ = bytes[3]; } // effect 709 710 if (packBits == 15) // first four bits set? 711 { 712 // no packing needed, write pattern data as is 713 714 // point to first byte (and overwrite data) 715 writePtr = firstBytePtr; 716 717 *writePtr++ = bytes[0]; 718 *writePtr++ = bytes[1]; 719 *writePtr++ = bytes[2]; 720 *writePtr++ = bytes[3]; 721 *writePtr++ = bytes[4]; 722 723 totalPackLen += 5; 724 continue; 725 } 726 727 if (bytes[4] > 0) { packBits |= 16; *writePtr++ = bytes[4]; } // effect parameter 728 729 *firstBytePtr = packBits | 128; // write pack bits byte 730 totalPackLen += (uint16_t)(writePtr - firstBytePtr); // bytes writen 731 } 732 733 // skip unused channels (unpacked patterns always have 32 channels) 734 pattPtr += pitch; 735 } 736 737 return totalPackLen; 738 }