ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

commit 15897be81442299876efd399c7b14f8110e65879
parent 659ffaa46c783451aa0c7e29ac33d8767569b3be
Author: Olav Sørensen <olav.sorensen@live.no>
Date:   Mon, 27 Apr 2020 20:13:49 +0200

Pushed v1.22 code

- Fixed crash when loading XMs with pattern lengths above 256. They are now
  safely truncated, and the user gets a warning message about the truncation.
- Allow loading overflown BPM/speed values from quirky XMs, up to BPM 999
  and speed 99 ("jk_error_txt.xm" is an example for quirky BPM/speed values).
- Tiny code cleanup

Diffstat:
Msrc/ft2_audio.c | 2+-
Msrc/ft2_audio.h | 3++-
Msrc/ft2_header.h | 2+-
Msrc/ft2_module_loader.c | 40+++++++++++++++++-----------------------
Msrc/ft2_pattern_ed.c | 27++++++++++++++++++++++++---
Msrc/ft2_replayer.c | 11++++++-----
Msrc/ft2_tables.c | 17+++--------------
Msrc/ft2_tables.h | 1-
Msrc/ft2_wav_renderer.c | 10+++++-----
9 files changed, 59 insertions(+), 54 deletions(-)

diff --git a/src/ft2_audio.c b/src/ft2_audio.c @@ -921,7 +921,7 @@ static void SDLCALL mixCallback(void *userdata, Uint8 *stream, int len) pattSyncData.patternPos = song.curReplayerPattPos; pattSyncData.pattern = song.curReplayerPattNr; pattSyncData.songPos = song.curReplayerSongPos; - pattSyncData.speed = (uint8_t)song.speed; + pattSyncData.speed = song.speed; pattSyncData.tempo = (uint8_t)song.tempo; pattSyncData.globalVol = (uint8_t)song.globVol; pattSyncData.timestamp = audio.tickTime64; diff --git a/src/ft2_audio.h b/src/ft2_audio.h @@ -81,7 +81,8 @@ typedef struct typedef struct pattSyncData_t { - uint8_t pattern, globalVol, songPos, timer, speed, tempo, patternPos; + uint8_t pattern, globalVol, songPos, timer, tempo, patternPos; + uint16_t speed; uint64_t timestamp; } pattSyncData_t; diff --git a/src/ft2_header.h b/src/ft2_header.h @@ -12,7 +12,7 @@ #endif #include "ft2_replayer.h" -#define PROG_VER_STR "1.21" +#define PROG_VER_STR "1.22" // do NOT change these! It will only mess things up... diff --git a/src/ft2_module_loader.c b/src/ft2_module_loader.c @@ -129,7 +129,7 @@ songS3MHeaderTyp; static volatile uint8_t loadedFormat; static volatile bool linearFreqTable, musicIsLoading, moduleLoaded, moduleFailedToLoad; -static uint8_t oldPlayMode, pattBuff[12288]; +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; @@ -143,7 +143,7 @@ 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, uint16_t inn, uint16_t len, int32_t antChn); +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); @@ -1752,8 +1752,8 @@ bool doLoadMusic(bool fromExternalThread) songTmp.ver = h.ver; linearFreqTable = h.flags & 1; - songTmp.speed = CLAMP(songTmp.speed, 32, 255); - songTmp.tempo = CLAMP(songTmp.tempo, 1, 31); + songTmp.speed = CLAMP(songTmp.speed, 1, 999); + songTmp.tempo = CLAMP(songTmp.tempo, 1, 99); songTmp.initialTempo = songTmp.tempo; @@ -2192,15 +2192,14 @@ static bool loadInstrSample(FILE *f, uint16_t i) return true; } -void unpackPatt(uint8_t *dst, uint16_t inn, uint16_t len, int32_t antChn) +void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn) { - uint8_t note, data, *src; + uint8_t note, data; int32_t srcEnd, srcIdx; if (dst == NULL) return; - src = dst + inn; srcEnd = len * TRACK_WIDTH; srcIdx = 0; @@ -2280,8 +2279,8 @@ void clearUnusedChannels(tonTyp *p, int16_t pattLen, int32_t antChn) static bool loadPatterns(FILE *f, uint16_t antPtn) { bool pattLenWarn; - uint8_t tmpLen, *pattPtr; - uint16_t i, a; + uint8_t tmpLen; + uint16_t i; patternHeaderTyp ph; pattLenWarn = false; @@ -2324,6 +2323,11 @@ static bool loadPatterns(FILE *f, uint16_t antPtn) goto pattCorrupt; pattLensTmp[i] = ph.pattLen; + if (pattLensTmp[i] > MAX_PATT_LEN) + { + pattLensTmp[i] = MAX_PATT_LEN; + pattLenWarn = true; + } if (ph.dataLen > 0) { @@ -2334,15 +2338,11 @@ static bool loadPatterns(FILE *f, uint16_t antPtn) return false; } - a = ph.pattLen * TRACK_WIDTH; - - pattPtr = (uint8_t *)pattTmp[i]; - memset(pattPtr, 0, a); - - if (fread(&pattPtr[a - ph.dataLen], 1, ph.dataLen, f) != ph.dataLen) + if (fread(packedPattData, 1, ph.dataLen, f) != ph.dataLen) goto pattCorrupt; - unpackPatt(pattPtr, a - ph.dataLen, ph.pattLen, songTmp.antChn); + unpackPatt((uint8_t *)pattTmp[i], packedPattData, pattLensTmp[i], songTmp.antChn); + clearUnusedChannels(pattTmp[i], pattLensTmp[i], songTmp.antChn); } @@ -2356,16 +2356,10 @@ static bool loadPatterns(FILE *f, uint16_t antPtn) pattLensTmp[i] = 64; } - - if (pattLensTmp[i] > 256) - { - pattLensTmp[i] = 64; - pattLenWarn = true; - } } if (pattLenWarn) - okBoxThreadSafe(0, "System message", "The module contains pattern lengths above 256! They will be set to 64."); + okBoxThreadSafe(0, "System message", "This module contains pattern(s) with a length above 256! They will be truncated."); return true; diff --git a/src/ft2_pattern_ed.c b/src/ft2_pattern_ed.c @@ -2182,11 +2182,30 @@ void drawSongRepS(void) void drawSongBPM(uint16_t val) { + char str[4]; + const char *strOut; + if (editor.ui.extended) return; - assert(val < 256); - textOutFixed(145, 36, PAL_FORGRND, PAL_DESKTOP, dec3StrTab[val]); + if (val <= 255) + { + strOut = dec3StrTab[val]; + } + else + { + if (val > 999) + val = 999; + + str[0] = '0' + (char)(val / 100); + str[1] = '0' + ((val / 10) % 10); + str[2] = '0' + (val % 10); + str[3] = 0; + + strOut = str; + } + + textOutFixed(145, 36, PAL_FORGRND, PAL_DESKTOP, strOut); } void drawSongSpeed(uint16_t val) @@ -2194,7 +2213,9 @@ void drawSongSpeed(uint16_t val) if (editor.ui.extended) return; - assert(val < 32); + if (val > 99) + val = 99; + textOutFixed(152, 50, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[val]); } diff --git a/src/ft2_replayer.c b/src/ft2_replayer.c @@ -29,7 +29,7 @@ ** FT2 obviously didn't have such big tables. */ -static uint32_t musicTimeTab[256-32]; +static uint32_t musicTimeTab[1000]; static uint64_t period2ScopeDeltaTab[65536]; static double dLogTab[768], dLogTabMul[32], dAudioRateFactor; @@ -412,11 +412,12 @@ void calcReplayRate(int32_t rate) // calculate table used to count replayer time (displayed as hours/minutes/seconds) const double dMul = (UINT32_MAX + 1.0) / rate; - for (i = 32; i < 256; i++) + musicTimeTab[0] = UINT32_MAX; + for (i = 1; i < 1000; i++) { uint32_t samplesPerTick = ((rate + rate) + (rate >> 1)) / i; // exactly how setSpeed() calculates it const double dVal = samplesPerTick * dMul; - musicTimeTab[i-32] = (int32_t)(dVal + 0.5); + musicTimeTab[i] = (uint32_t)(dVal + 0.5); } calcPeriod2DeltaTables(); @@ -2139,8 +2140,8 @@ void mainPlayer(void) // periodically called from audio callback return; } - assert(song.speed >= 32 && song.speed <= 255); - song.musicTime64 += musicTimeTab[song.speed-32]; // for playback counter + assert(song.speed >= 1 && song.speed <= 999); + song.musicTime64 += musicTimeTab[song.speed]; // for playback counter readNewNote = false; if (--song.timer == 0) diff --git a/src/ft2_tables.c b/src/ft2_tables.c @@ -38,13 +38,13 @@ const int8_t vibSineTab[256] = // for auto-vibrato 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2 }; -const uint8_t vibTab[32] = +const uint8_t vibTab[32] = // for normal vibrato/tremolo { 0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253, 255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24 }; -const uint16_t amigaPeriod[12 * 8] = +const uint16_t amigaPeriod[12 * 8] = // used for .MOD loading/saving { 6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624, 3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1812, @@ -56,18 +56,6 @@ const uint16_t amigaPeriod[12 * 8] = 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28 }; -const uint16_t amigaFinePeriod[12 * 8] = -{ - 907, 900, 894, 887, 881, 875, 868, 862, 856, 850, 844, 838, - 832, 826, 820, 814, 808, 802, 796, 791, 785, 779, 774, 768, - 762, 757, 752, 746, 741, 736, 730, 725, 720, 715, 709, 704, - 699, 694, 689, 684, 678, 675, 670, 665, 660, 655, 651, 646, - 640, 636, 632, 628, 623, 619, 614, 610, 604, 601, 597, 592, - 588, 584, 580, 575, 570, 567, 563, 559, 555, 551, 547, 543, - 538, 535, 532, 528, 524, 520, 516, 513, 508, 505, 502, 498, - 494, 491, 487, 484, 480, 477, 474, 470, 467, 463, 460, 457 -}; - const uint16_t linearPeriods[1936] = // bit-exact to FT2 table { 7744, 7740, 7736, 7732, 7728, 7724, 7720, 7716, 7712, 7708, 7704, 7700, 7696, 7692, 7688, 7684, @@ -704,6 +692,7 @@ const uint8_t pattCursorWTab[2 * 4 * 8] = 24, 4, 4, 4, 4, 4, 4, 4 // 12 columns visible }; +// these two are for channel numbering on pattern data/scopes const char chDecTab1[MAX_VOICES+1] = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', diff --git a/src/ft2_tables.h b/src/ft2_tables.h @@ -14,7 +14,6 @@ extern const uint8_t arpTab[32]; extern const int8_t vibSineTab[256]; // for auto-vibrato extern const uint8_t vibTab[32]; extern const uint16_t amigaPeriod[12 * 8]; -extern const uint16_t amigaFinePeriod[12 * 8]; extern const uint16_t linearPeriods[1936]; extern const uint16_t amigaPeriods[1936]; diff --git a/src/ft2_wav_renderer.c b/src/ft2_wav_renderer.c @@ -215,7 +215,7 @@ static void dump_Close(FILE *f, uint32_t totalSamples) tmpLen = ftell(f) - 8; // go back and fill in WAV header - fseek(f, 0, SEEK_SET); + rewind(f); wavHeader.chunkID = 0x46464952; // "RIFF" wavHeader.chunkSize = tmpLen; @@ -322,10 +322,10 @@ static int32_t SDLCALL renderWavThread(void *ptr) sampleCounter = 0; renderDone = false; - loopCounter = 0; + loopCounter = 8; editor.wavReachedEndFlag = false; - while (!renderDone && editor.wavIsRendering) + while (!renderDone) { samplesInChunk = 0; @@ -339,7 +339,7 @@ static int32_t SDLCALL renderWavThread(void *ptr) break; } - tickSamples = dump_RenderTick(ptr8) * 2; // *2 for stereo + tickSamples = dump_RenderTick(ptr8) << 1; // *2 for stereo samplesInChunk += tickSamples; sampleCounter += tickSamples; @@ -350,7 +350,7 @@ static int32_t SDLCALL renderWavThread(void *ptr) else ptr8 += (tickSamples * sizeof (float)); - if (++loopCounter > 16) + if (++loopCounter >= 8) { loopCounter = 0; updateVisuals();