// for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdio.h>#include <stdint.h>#include <stdbool.h>#ifndef _WIN32#include <unistd.h>#endif#include "ft2_header.h"#include "ft2_config.h"#include "ft2_scopes.h"#include "ft2_trim.h"#include "ft2_inst_ed.h"#include "ft2_sample_ed.h"#include "ft2_wav_renderer.h"#include "ft2_pattern_ed.h"#include "ft2_gui.h"#include "ft2_diskop.h"#include "ft2_sample_loader.h"#include "ft2_mouse.h"#include "ft2_midi.h"#include "ft2_events.h"#include "ft2_video.h"#include "ft2_tables.h"#include "ft2_structs.h" /* This is a *HUGE* mess!** I hope you never have to modify it, and you probably shouldn't either.** You will experience a lot of headaches if you dig into this file...** If something looks to be wrong, it's probably right!**** The actual module load routines are ported from FT2 and slightly modified.*/ enum{ FORMAT_NONE = 0, FORMAT_XM = 1, FORMAT_MOD = 2, FORMAT_S3M = 3, FORMAT_STM = 4}; // .MOD typesenum{ FORMAT_MK, // ProTracker or compatible FORMAT_FLT, // StarTrekker (4-channel modules only) FORMAT_FT2, // FT2 (or other trackers, multichannel) FORMAT_STK, // The Ultimate SoundTracker (15 samples) FORMAT_NT, // NoiseTracker FORMAT_HMNT, // His Master's NoiseTracker (special one) FORMAT_UNKNOWN // may be The Ultimate Soundtracker (set to FORMAT_STK later)}; // DO NOT TOUCH THESE STRUCTS! #ifdef _MSC_VER#pragma pack(push)#pragma pack(1)#endiftypedef struct songSTMinstrHeaderTyp_t{ char name[12]; uint8_t nul, insDisk; uint16_t reserved1, len, repS, repE; uint8_t vol, reserved2; uint16_t rate; int32_t reserved3; uint16_t paraLen;}#ifdef __GNUC____attribute__ ((packed))#endifsongSTMinstrHeaderTyp; typedef struct songSTMHeaderTyp_t{ char name[20], sig[8]; uint8_t id1a, typ; uint8_t verMajor, verMinor; uint8_t tempo, ap, vol, reserved[13]; songSTMinstrHeaderTyp instr[31]; uint8_t songTab[128];}#ifdef __GNUC____attribute__ ((packed))#endifsongSTMHeaderTyp; typedef struct songS3MinstrHeaderTyp_t{ uint8_t typ; char dosName[12]; uint8_t memSegH; uint16_t memSeg; int32_t len, repS, repE; uint8_t vol, dsk, pack, flags; int32_t c2Spd, res1; uint16_t gusPos; uint8_t res2[6]; char name[28], id[4];}#ifdef __GNUC____attribute__ ((packed))#endifsongS3MinstrHeaderTyp; typedef struct songS3MHeaderTyp_t{ char name[28]; uint8_t id1a, typ; uint16_t res1; int16_t songTabLen, antInstr, antPatt; uint16_t flags, trackerID, ver; char id[4]; uint8_t globalVol, defSpeed, defTempo, masterVol, res2[12], chanType[32];}#ifdef __GNUC____attribute__ ((packed))#endifsongS3MHeaderTyp;#ifdef _MSC_VER#pragma pack(pop)#endif static volatile uint8_t loadedFormat;static volatile bool linearFreqTable, musicIsLoading, moduleLoaded, moduleFailedToLoad;static uint8_t oldPlayMode, pattBuff[12288], packedPattData[65536];static const uint8_t stmEff[16] = { 0, 0, 11, 0, 10, 2, 1, 3, 4, 7, 0, 5 ,6, 0, 0, 0 };static SDL_Thread *thread; // these temporarily read to, then copied to real struct if load was OK (should not need to be volatile'd)static int16_t pattLensTmp[MAX_PATTERNS];static tonTyp *pattTmp[MAX_PATTERNS];static instrTyp *instrTmp[1 + MAX_INST];static songTyp songTmp; static void setupLoadedModule(void);static void freeTmpModule(void);static bool loadInstrHeader(FILE *f, uint16_t i);static bool loadInstrSample(FILE *f, uint16_t i);void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn);static bool tmpPatternEmpty(uint16_t nr);static bool loadPatterns(FILE *f, uint16_t antPtn); void checkSampleRepeat(sampleTyp *s); // ft2_replayer.cextern const char modSig[32][5]; static bool allocateTmpInstr(int16_t nr){ instrTyp *p; if (instrTmp[nr] != NULL) return false; // already allocated p = (instrTyp *)malloc(sizeof (instrTyp)); if (p == NULL) return false; memset(p, 0, sizeof (instrTyp)); for (int8_t i = 0; i < 16; i++) // set standard sample pan/vol { p->samp[i].pan = 128; p->samp[i].vol = 64; } instrTmp[nr] = p; return true;} #define IS_ID(s, b) !strncmp(s, b, 4) static uint8_t getModType(uint8_t *numChannels, const char *id){ uint8_t modFormat = FORMAT_UNKNOWN; *numChannels = 4; if (IS_ID("M.K.", id) || IS_ID("M!K!", id) || IS_ID("NSMS", id) || IS_ID("LARD", id) || IS_ID("PATT", id)) { modFormat = FORMAT_MK; // ProTracker or compatible } else if (id[1] == 'C' && id[2] == 'H' && id[3] == 'N') { modFormat = FORMAT_FT2; // FT2 or generic multichannel *numChannels = id[0] - '0'; } else if (id[2] == 'C' && (id[3] == 'H' || id[3] == 'N')) { modFormat = FORMAT_FT2; // FT2 or generic multichannel *numChannels = ((id[0] - '0') * 10) + (id[1] - '0'); } else if (IS_ID("FLT4", id)) { modFormat = FORMAT_FLT; // StarTrekker (4-channel modules only) } else if (IS_ID("N.T.", id)) { modFormat = FORMAT_NT; // NoiseTracker } else if (IS_ID("M&K!", id) || IS_ID("FEST", id)) { modFormat = FORMAT_HMNT; // His Master's NoiseTracker } return modFormat;} static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread){ char ID[16]; bool mightBeSTK, lateSTKVerFlag, veryLateSTKVerFlag; uint8_t bytes[4], modFormat, numChannels; int16_t i, j, k, ai; uint16_t a, b, period; tonTyp *ton; sampleTyp *s; songMOD31HeaderTyp h_MOD31; songMOD15HeaderTyp h_MOD15; int16_t (*showMsg)(int16_t, const char *, const char *); showMsg = fromExternalThread ? okBoxThreadSafe : okBox; veryLateSTKVerFlag = false; // "DFJ SoundTracker III" nad later lateSTKVerFlag = false; // "TJC SoundTracker II" and later mightBeSTK = false; memset(&songTmp, 0, sizeof (songTmp)); memset(&h_MOD31, 0, sizeof (songMOD31HeaderTyp)); memset(&h_MOD15, 0, sizeof (songMOD15HeaderTyp)); // start loading MOD loadedFormat = FORMAT_MOD; rewind(f); fread(ID, 1, 16, f); fseek(f, 0x1D, SEEK_SET); fread(bytes, 1, 1, f); rewind(f); // since .mod is the last format tested, check if the file is an .it module (Impulse Tracker) if (!memcmp(ID, "IMPM", 4) && bytes[0] == 0) { showMsg(0, "System message", "Error: Impulse Tracker modules are not supported!"); goto modLoadError; } // check if the file to load is a WAV, if so reject it if (!memcmp(ID, "RIFF", 4) && !memcmp(&ID[8], "WAVEfmt", 7)) { showMsg(0, "System message", "Error: Can't load a .wav file as a module!"); goto modLoadError; } if (fileLength < 1596 || fileLength > 20842494) // minimum and maximum possible size for a supported .mod { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } if (fread(&h_MOD31, 1, sizeof (h_MOD31), f) != sizeof (h_MOD31)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } modFormat = getModType(&numChannels, h_MOD31.sig); if (modFormat == FORMAT_FLT && numChannels == 8) { showMsg(0, "System message", "8-channel Startrekker modules are not supported!"); goto modLoadError; } if (modFormat != FORMAT_UNKNOWN) { if (fileLength < sizeof (h_MOD31)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } songTmp.antChn = numChannels; songTmp.len = h_MOD31.len; songTmp.repS = h_MOD31.repS; memcpy(songTmp.songTab, h_MOD31.songTab, 128); ai = 31; } else { mightBeSTK = true; if (fileLength < sizeof (h_MOD15)) { showMsg(0, "System message", "Error: This file is not a module!"); goto modLoadError; } rewind(f); if (fread(&h_MOD15, 1, sizeof (h_MOD15), f) != sizeof (h_MOD15)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } songTmp.antChn = numChannels; songTmp.len = h_MOD15.len; songTmp.repS = h_MOD15.repS; memcpy(songTmp.songTab, h_MOD15.songTab, 128); ai = 15; } if (modFormat == FORMAT_MK && songTmp.len == 129) songTmp.len = 127; // fixes a specific copy of beatwave.mod if (songTmp.antChn == 0 || songTmp.len < 1 || songTmp.len > 128 || (mightBeSTK && songTmp.repS > 220)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } for (a = 0; a < ai; a++) { songMODInstrHeaderTyp *smp = &h_MOD31.instr[a]; if (modFormat != FORMAT_HMNT) // most of "His Master's Noisetracker" songs have junk sample names, so let's not load them { // trim off spaces at end of name for (i = 21; i >= 0; i--) { if (smp->name[i] == ' ' || smp->name[i] == 0x1A) smp->name[i] = '\0'; else break; } memcpy(songTmp.instrName[1+a], smp->name, 22); songTmp.instrName[1+a][22] = '\0'; } /* Only late versions of Ultimate SoundTracker could have samples larger than 9999 bytes. ** If found, we know for sure that this is a late STK module. */ if (mightBeSTK && 2*SWAP16(smp->len) > 9999) lateSTKVerFlag = true; } songTmp.speed = 125; if (mightBeSTK) { /* If we're still here at this point and the mightBeSTK flag is set, ** then it's most likely a proper The Ultimate SoundTracker (STK/UST) module. */ modFormat = FORMAT_STK; if (songTmp.repS == 0) songTmp.repS = 120; // jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored (hackish!) if (!strcmp("jjk55", h_MOD31.name)) songTmp.repS = 120; // The "restart pos" field in STK is the inital tempo (must be converted to BPM first) if (songTmp.repS != 120) // 120 is a special case and means 50Hz (125BPM) { if (songTmp.repS > 220) songTmp.repS = 220; // convert UST tempo to BPM uint16_t ciaPeriod = (240 - songTmp.repS) * 122; double dHz = 709379.0 / ciaPeriod; int32_t BPM = (int32_t)((dHz * 2.5) + 0.5); songTmp.speed = (uint16_t)BPM; } songTmp.repS = 0; } else if (songTmp.repS >= songTmp.len) { songTmp.repS = 0; } // trim off spaces at end of name for (i = 19; i >= 0; i--) { if (h_MOD31.name[i] == ' ' || h_MOD31.name[i] == 0x1A) h_MOD31.name[i] = '\0'; else break; } memcpy(songTmp.name, h_MOD31.name, 20); songTmp.name[20] = '\0'; // count number of patterns b = 0; for (a = 0; a < 128; a++) { if (songTmp.songTab[a] > b) b = songTmp.songTab[a]; } b++; for (a = 0; a < b; a++) { pattTmp[a] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1); if (pattTmp[a] == NULL) { showMsg(0, "System message", "Not enough memory!"); goto modLoadError; } pattLensTmp[a] = 64; for (j = 0; j < 64; j++) { for (k = 0; k < songTmp.antChn; k++) { ton = &pattTmp[a][(j * MAX_VOICES) + k]; if (fread(bytes, 1, 4, f) != 4) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } // period to note period = ((bytes[0] & 0x0F) << 8) | bytes[1]; for (i = 0; i < 8*12; i++) { if (period >= amigaPeriod[i]) { ton->ton = (uint8_t)i + 1; break; } } ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4); ton->effTyp = bytes[2] & 0x0F; ton->eff = bytes[3]; if (modFormat == FORMAT_STK) { if (ton->effTyp == 0xC || ton->effTyp == 0xD || ton->effTyp == 0xE) { // "TJC SoundTracker II" and later lateSTKVerFlag = true; } if (ton->effTyp == 0xF) { // "DFJ SoundTracker III" and later lateSTKVerFlag = true; veryLateSTKVerFlag = true; } } if (ton->effTyp == 0xC) { if (ton->eff > 64) ton->eff = 64; } else if (ton->effTyp == 0x1) { if (ton->eff == 0) ton->effTyp = 0; } else if (ton->effTyp == 0x2) { if (ton->eff == 0) ton->effTyp = 0; } else if (ton->effTyp == 0x5) { if (ton->eff == 0) ton->effTyp = 0x3; } else if (ton->effTyp == 0x6) { if (ton->eff == 0) ton->effTyp = 0x4; } else if (ton->effTyp == 0xA) { if (ton->eff == 0) ton->effTyp = 0; } else if (ton->effTyp == 0xE) { // check if certain E commands are empty if (ton->eff == 0x10 || ton->eff == 0x20 || ton->eff == 0xA0 || ton->eff == 0xB0) { ton->effTyp = 0;Lines 1–500 of 2692. Load more
// for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> #endif #include <stdio.h> #include <stdint.h> #include <stdbool.h> #ifndef _WIN32 #include <unistd.h> #endif #include "ft2_header.h" #include "ft2_config.h" #include "ft2_scopes.h" #include "ft2_trim.h" #include "ft2_inst_ed.h" #include "ft2_sample_ed.h" #include "ft2_wav_renderer.h" #include "ft2_pattern_ed.h" #include "ft2_gui.h" #include "ft2_diskop.h" #include "ft2_sample_loader.h" #include "ft2_mouse.h" #include "ft2_midi.h" #include "ft2_events.h" #include "ft2_video.h" #include "ft2_tables.h" #include "ft2_structs.h" /* This is a *HUGE* mess! ** I hope you never have to modify it, and you probably shouldn't either. ** You will experience a lot of headaches if you dig into this file... ** If something looks to be wrong, it's probably right! ** ** The actual module load routines are ported from FT2 and slightly modified. */ enum { FORMAT_NONE = 0, FORMAT_XM = 1, FORMAT_MOD = 2, FORMAT_S3M = 3, FORMAT_STM = 4 }; // .MOD types enum { FORMAT_MK, // ProTracker or compatible FORMAT_FLT, // StarTrekker (4-channel modules only) FORMAT_FT2, // FT2 (or other trackers, multichannel) FORMAT_STK, // The Ultimate SoundTracker (15 samples) FORMAT_NT, // NoiseTracker FORMAT_HMNT, // His Master's NoiseTracker (special one) FORMAT_UNKNOWN // may be The Ultimate Soundtracker (set to FORMAT_STK later) }; // DO NOT TOUCH THESE STRUCTS! #ifdef _MSC_VER #pragma pack(push) #pragma pack(1) #endif typedef struct songSTMinstrHeaderTyp_t { char name[12]; uint8_t nul, insDisk; uint16_t reserved1, len, repS, repE; uint8_t vol, reserved2; uint16_t rate; int32_t reserved3; uint16_t paraLen; } #ifdef __GNUC__ __attribute__ ((packed)) #endif songSTMinstrHeaderTyp; typedef struct songSTMHeaderTyp_t { char name[20], sig[8]; uint8_t id1a, typ; uint8_t verMajor, verMinor; uint8_t tempo, ap, vol, reserved[13]; songSTMinstrHeaderTyp instr[31]; uint8_t songTab[128]; } #ifdef __GNUC__ __attribute__ ((packed)) #endif songSTMHeaderTyp; typedef struct songS3MinstrHeaderTyp_t { uint8_t typ; char dosName[12]; uint8_t memSegH; uint16_t memSeg; int32_t len, repS, repE; uint8_t vol, dsk, pack, flags; int32_t c2Spd, res1; uint16_t gusPos; uint8_t res2[6]; char name[28], id[4]; } #ifdef __GNUC__ __attribute__ ((packed)) #endif songS3MinstrHeaderTyp; typedef struct songS3MHeaderTyp_t { char name[28]; uint8_t id1a, typ; uint16_t res1; int16_t songTabLen, antInstr, antPatt; uint16_t flags, trackerID, ver; char id[4]; uint8_t globalVol, defSpeed, defTempo, masterVol, res2[12], chanType[32]; } #ifdef __GNUC__ __attribute__ ((packed)) #endif songS3MHeaderTyp; #ifdef _MSC_VER #pragma pack(pop) #endif static volatile uint8_t loadedFormat; static volatile bool linearFreqTable, musicIsLoading, moduleLoaded, moduleFailedToLoad; static uint8_t oldPlayMode, pattBuff[12288], packedPattData[65536]; static const uint8_t stmEff[16] = { 0, 0, 11, 0, 10, 2, 1, 3, 4, 7, 0, 5 ,6, 0, 0, 0 }; static SDL_Thread *thread; // these temporarily read to, then copied to real struct if load was OK (should not need to be volatile'd) static int16_t pattLensTmp[MAX_PATTERNS]; static tonTyp *pattTmp[MAX_PATTERNS]; static instrTyp *instrTmp[1 + MAX_INST]; static songTyp songTmp; static void setupLoadedModule(void); static void freeTmpModule(void); static bool loadInstrHeader(FILE *f, uint16_t i); static bool loadInstrSample(FILE *f, uint16_t i); void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn); static bool tmpPatternEmpty(uint16_t nr); static bool loadPatterns(FILE *f, uint16_t antPtn); void checkSampleRepeat(sampleTyp *s); // ft2_replayer.c extern const char modSig[32][5]; static bool allocateTmpInstr(int16_t nr) { instrTyp *p; if (instrTmp[nr] != NULL) return false; // already allocated p = (instrTyp *)malloc(sizeof (instrTyp)); if (p == NULL) return false; memset(p, 0, sizeof (instrTyp)); for (int8_t i = 0; i < 16; i++) // set standard sample pan/vol { p->samp[i].pan = 128; p->samp[i].vol = 64; } instrTmp[nr] = p; return true; } #define IS_ID(s, b) !strncmp(s, b, 4) static uint8_t getModType(uint8_t *numChannels, const char *id) { uint8_t modFormat = FORMAT_UNKNOWN; *numChannels = 4; if (IS_ID("M.K.", id) || IS_ID("M!K!", id) || IS_ID("NSMS", id) || IS_ID("LARD", id) || IS_ID("PATT", id)) { modFormat = FORMAT_MK; // ProTracker or compatible } else if (id[1] == 'C' && id[2] == 'H' && id[3] == 'N') { modFormat = FORMAT_FT2; // FT2 or generic multichannel *numChannels = id[0] - '0'; } else if (id[2] == 'C' && (id[3] == 'H' || id[3] == 'N')) { modFormat = FORMAT_FT2; // FT2 or generic multichannel *numChannels = ((id[0] - '0') * 10) + (id[1] - '0'); } else if (IS_ID("FLT4", id)) { modFormat = FORMAT_FLT; // StarTrekker (4-channel modules only) } else if (IS_ID("N.T.", id)) { modFormat = FORMAT_NT; // NoiseTracker } else if (IS_ID("M&K!", id) || IS_ID("FEST", id)) { modFormat = FORMAT_HMNT; // His Master's NoiseTracker } return modFormat; } static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) { char ID[16]; bool mightBeSTK, lateSTKVerFlag, veryLateSTKVerFlag; uint8_t bytes[4], modFormat, numChannels; int16_t i, j, k, ai; uint16_t a, b, period; tonTyp *ton; sampleTyp *s; songMOD31HeaderTyp h_MOD31; songMOD15HeaderTyp h_MOD15; int16_t (*showMsg)(int16_t, const char *, const char *); showMsg = fromExternalThread ? okBoxThreadSafe : okBox; veryLateSTKVerFlag = false; // "DFJ SoundTracker III" nad later lateSTKVerFlag = false; // "TJC SoundTracker II" and later mightBeSTK = false; memset(&songTmp, 0, sizeof (songTmp)); memset(&h_MOD31, 0, sizeof (songMOD31HeaderTyp)); memset(&h_MOD15, 0, sizeof (songMOD15HeaderTyp)); // start loading MOD loadedFormat = FORMAT_MOD; rewind(f); fread(ID, 1, 16, f); fseek(f, 0x1D, SEEK_SET); fread(bytes, 1, 1, f); rewind(f); // since .mod is the last format tested, check if the file is an .it module (Impulse Tracker) if (!memcmp(ID, "IMPM", 4) && bytes[0] == 0) { showMsg(0, "System message", "Error: Impulse Tracker modules are not supported!"); goto modLoadError; } // check if the file to load is a WAV, if so reject it if (!memcmp(ID, "RIFF", 4) && !memcmp(&ID[8], "WAVEfmt", 7)) { showMsg(0, "System message", "Error: Can't load a .wav file as a module!"); goto modLoadError; } if (fileLength < 1596 || fileLength > 20842494) // minimum and maximum possible size for a supported .mod { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } if (fread(&h_MOD31, 1, sizeof (h_MOD31), f) != sizeof (h_MOD31)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } modFormat = getModType(&numChannels, h_MOD31.sig); if (modFormat == FORMAT_FLT && numChannels == 8) { showMsg(0, "System message", "8-channel Startrekker modules are not supported!"); goto modLoadError; } if (modFormat != FORMAT_UNKNOWN) { if (fileLength < sizeof (h_MOD31)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } songTmp.antChn = numChannels; songTmp.len = h_MOD31.len; songTmp.repS = h_MOD31.repS; memcpy(songTmp.songTab, h_MOD31.songTab, 128); ai = 31; } else { mightBeSTK = true; if (fileLength < sizeof (h_MOD15)) { showMsg(0, "System message", "Error: This file is not a module!"); goto modLoadError; } rewind(f); if (fread(&h_MOD15, 1, sizeof (h_MOD15), f) != sizeof (h_MOD15)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } songTmp.antChn = numChannels; songTmp.len = h_MOD15.len; songTmp.repS = h_MOD15.repS; memcpy(songTmp.songTab, h_MOD15.songTab, 128); ai = 15; } if (modFormat == FORMAT_MK && songTmp.len == 129) songTmp.len = 127; // fixes a specific copy of beatwave.mod if (songTmp.antChn == 0 || songTmp.len < 1 || songTmp.len > 128 || (mightBeSTK && songTmp.repS > 220)) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } for (a = 0; a < ai; a++) { songMODInstrHeaderTyp *smp = &h_MOD31.instr[a]; if (modFormat != FORMAT_HMNT) // most of "His Master's Noisetracker" songs have junk sample names, so let's not load them { // trim off spaces at end of name for (i = 21; i >= 0; i--) { if (smp->name[i] == ' ' || smp->name[i] == 0x1A) smp->name[i] = '\0'; else break; } memcpy(songTmp.instrName[1+a], smp->name, 22); songTmp.instrName[1+a][22] = '\0'; } /* Only late versions of Ultimate SoundTracker could have samples larger than 9999 bytes. ** If found, we know for sure that this is a late STK module. */ if (mightBeSTK && 2*SWAP16(smp->len) > 9999) lateSTKVerFlag = true; } songTmp.speed = 125; if (mightBeSTK) { /* If we're still here at this point and the mightBeSTK flag is set, ** then it's most likely a proper The Ultimate SoundTracker (STK/UST) module. */ modFormat = FORMAT_STK; if (songTmp.repS == 0) songTmp.repS = 120; // jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored (hackish!) if (!strcmp("jjk55", h_MOD31.name)) songTmp.repS = 120; // The "restart pos" field in STK is the inital tempo (must be converted to BPM first) if (songTmp.repS != 120) // 120 is a special case and means 50Hz (125BPM) { if (songTmp.repS > 220) songTmp.repS = 220; // convert UST tempo to BPM uint16_t ciaPeriod = (240 - songTmp.repS) * 122; double dHz = 709379.0 / ciaPeriod; int32_t BPM = (int32_t)((dHz * 2.5) + 0.5); songTmp.speed = (uint16_t)BPM; } songTmp.repS = 0; } else if (songTmp.repS >= songTmp.len) { songTmp.repS = 0; } // trim off spaces at end of name for (i = 19; i >= 0; i--) { if (h_MOD31.name[i] == ' ' || h_MOD31.name[i] == 0x1A) h_MOD31.name[i] = '\0'; else break; } memcpy(songTmp.name, h_MOD31.name, 20); songTmp.name[20] = '\0'; // count number of patterns b = 0; for (a = 0; a < 128; a++) { if (songTmp.songTab[a] > b) b = songTmp.songTab[a]; } b++; for (a = 0; a < b; a++) { pattTmp[a] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1); if (pattTmp[a] == NULL) { showMsg(0, "System message", "Not enough memory!"); goto modLoadError; } pattLensTmp[a] = 64; for (j = 0; j < 64; j++) { for (k = 0; k < songTmp.antChn; k++) { ton = &pattTmp[a][(j * MAX_VOICES) + k]; if (fread(bytes, 1, 4, f) != 4) { showMsg(0, "System message", "Error: This file is either not a module, or is not supported."); goto modLoadError; } // period to note period = ((bytes[0] & 0x0F) << 8) | bytes[1]; for (i = 0; i < 8*12; i++) { if (period >= amigaPeriod[i]) { ton->ton = (uint8_t)i + 1; break; } } ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4); ton->effTyp = bytes[2] & 0x0F; ton->eff = bytes[3]; if (modFormat == FORMAT_STK) { if (ton->effTyp == 0xC || ton->effTyp == 0xD || ton->effTyp == 0xE) { // "TJC SoundTracker II" and later lateSTKVerFlag = true; } if (ton->effTyp == 0xF) { // "DFJ SoundTracker III" and later lateSTKVerFlag = true; veryLateSTKVerFlag = true; } } if (ton->effTyp == 0xC) { if (ton->eff > 64) ton->eff = 64; } else if (ton->effTyp == 0x1) { if (ton->eff == 0) ton->effTyp = 0; } else if (ton->effTyp == 0x2) { if (ton->eff == 0) ton->effTyp = 0; } else if (ton->effTyp == 0x5) { if (ton->eff == 0) ton->effTyp = 0x3; } else if (ton->effTyp == 0x6) { if (ton->eff == 0) ton->effTyp = 0x4; } else if (ton->effTyp == 0xA) { if (ton->eff == 0) ton->effTyp = 0; } else if (ton->effTyp == 0xE) { // check if certain E commands are empty if (ton->eff == 0x10 || ton->eff == 0x20 || ton->eff == 0xA0 || ton->eff == 0xB0) { ton->effTyp = 0;