ft2-clone

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

commit f8c0ccfded8a6d486a63061a31e39156332a21c7
parent f1d002c3f3a0e7792aca42f6731899d8cba02f50
Author: Olav Sørensen <olav.sorensen@live.no>
Date:   Wed, 13 May 2020 12:51:49 +0200

Pushed v1.24 code

- Fixed a bug with saving looping 16-bit samples as .RAW/.IFF/.WAV. Two sample
  points somewhere in the waveform would be set to wrong values.
- Linux: Fixed the mouse not working with KMSDRM (hopefully)

Diffstat:
Msrc/ft2_header.h | 2+-
Msrc/ft2_mouse.c | 15+++++++++------
Msrc/ft2_sample_ed.c | 12++++++------
Msrc/ft2_sample_saver.c | 73+++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/ft2_scopes.c | 20++++++++++----------
Msrc/ft2_video.c | 22++++++++++++++--------
Msrc/ft2_video.h | 5+++--
7 files changed, 82 insertions(+), 67 deletions(-)

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.23" +#define PROG_VER_STR "1.24" // do NOT change these! It will only mess things up... diff --git a/src/ft2_mouse.c b/src/ft2_mouse.c @@ -784,8 +784,8 @@ void handleLastGUIObjectDown(void) void updateMouseScaling(void) { - if (video.renderW > 0.0) video.dMouseXMul = (double)SCREEN_W / video.renderW; - if (video.renderH > 0.0) video.dMouseYMul = (double)SCREEN_H / video.renderH; + if (video.renderW > 0.0) video.fMouseXMul = (float)SCREEN_W / video.renderW; + if (video.renderH > 0.0) video.fMouseYMul = (float)SCREEN_H / video.renderH; } void readMouseXY(void) @@ -801,7 +801,10 @@ void readMouseXY(void) return; } - mouse.buttonState = SDL_GetGlobalMouseState(&mx, &my); + if (video.useDesktopMouseCoords) + mouse.buttonState = SDL_GetGlobalMouseState(&mx, &my); + else + mouse.buttonState = SDL_GetMouseState(&mx, &my); if (video.fullscreen) { @@ -848,7 +851,7 @@ void readMouseXY(void) my -= video.renderY; } } - else + else if (video.useDesktopMouseCoords) { // convert desktop coords to window coords @@ -860,8 +863,8 @@ void readMouseXY(void) } // multiply coords by video upscaling factors (don't round) - mouse.x = (int32_t)(mx * video.dMouseXMul); - mouse.y = (int32_t)(my * video.dMouseYMul); + mouse.x = (int32_t)(mx * video.fMouseXMul); + mouse.y = (int32_t)(my * video.fMouseYMul); if (config.specialFlags2 & HARDWARE_MOUSE) { diff --git a/src/ft2_sample_ed.c b/src/ft2_sample_ed.c @@ -76,7 +76,7 @@ void fixSample(sampleTyp *s) if (len < 2) return; - len /= 2; + len >>= 1; ptr16 = (int16_t *)s->pek; // write new values @@ -112,8 +112,8 @@ void fixSample(sampleTyp *s) if (s->repL < 2) return; - loopStart = s->repS / 2; - loopEnd = (s->repS + s->repL) / 2; + loopStart = s->repS >> 1; + loopEnd = (s->repS + s->repL) >> 1; ptr16 = (int16_t *)s->pek; @@ -163,8 +163,8 @@ void fixSample(sampleTyp *s) if (s->repL < 2) return; - loopStart = s->repS / 2; - loopLen = s->repL/ 2; + loopStart = s->repS >> 1; + loopLen = s->repL >> 1; loopEnd = loopStart + loopLen; ptr16 = (int16_t *)s->pek; @@ -229,7 +229,7 @@ void restoreSample(sampleTyp *s) assert(s->pek != NULL); s->fixed = false; - // clear pre-start bytes + // clear pre-start bytes (this is safe, we have allocated room on the left for this) s->pek[-4] = 0; s->pek[-3] = 0; s->pek[-2] = 0; diff --git a/src/ft2_sample_saver.c b/src/ft2_sample_saver.c @@ -54,7 +54,7 @@ static SDL_Thread *thread; // used to restore mixer interpolation fix .RAW/.IFF/.WAV files after save static bool fileRestoreSampleData(UNICHAR *filenameU, int32_t sampleDataOffset, sampleTyp *smp) { - int8_t fixSpar8; + int8_t fixedSmp; FILE *f; if (!smp->fixed) @@ -67,15 +67,15 @@ static bool fileRestoreSampleData(UNICHAR *filenameU, int32_t sampleDataOffset, if (smp->typ & 16) { // 16-bit sample - if (smp->fixedPos < smp->len/2) + if (smp->fixedPos < smp->len) { - fseek(f, sampleDataOffset + (smp->fixedPos * 2), SEEK_SET); + fseek(f, sampleDataOffset + smp->fixedPos, SEEK_SET); fwrite(&smp->fixedSmp1, sizeof (int16_t), 1, f); } - if (smp->fixedPos+2 < smp->len/2) + if (smp->fixedPos+2 < smp->len) { - fseek(f, sampleDataOffset + ((smp->fixedPos + 2) * 2), SEEK_SET); + fseek(f, sampleDataOffset + (smp->fixedPos + 2), SEEK_SET); fwrite(&smp->fixedSmp2, sizeof (int16_t), 1, f); } } @@ -86,22 +86,22 @@ static bool fileRestoreSampleData(UNICHAR *filenameU, int32_t sampleDataOffset, { fseek(f, sampleDataOffset + smp->fixedPos, SEEK_SET); - fixSpar8 = (int8_t)smp->fixedSmp1; + fixedSmp = (int8_t)smp->fixedSmp1; if (editor.sampleSaveMode == SMP_SAVE_MODE_WAV) // on 8-bit WAVs the sample data is unsigned - fixSpar8 ^= 0x80; + fixedSmp ^= 0x80; - fwrite(&fixSpar8, sizeof (int8_t), 1, f); + fwrite(&fixedSmp, sizeof (int8_t), 1, f); } if (smp->fixedPos+1 < smp->len) { fseek(f, sampleDataOffset + (smp->fixedPos + 1), SEEK_SET); - fixSpar8 = (int8_t)smp->fixedSmp2; + fixedSmp = (int8_t)smp->fixedSmp2; if (editor.sampleSaveMode == SMP_SAVE_MODE_WAV) // on 8-bit WAVs the sample data is unsigned - fixSpar8 ^= 0x80; + fixedSmp ^= 0x80; - fwrite(&fixSpar8, sizeof (int8_t), 1, f); + fwrite(&fixedSmp, sizeof (int8_t), 1, f); } } @@ -181,6 +181,17 @@ static void iffWriteUint16(FILE *f, uint16_t value) fwrite(&value, sizeof (int16_t), 1, f); } +static void iffWriteUint8(FILE *f, const uint8_t value) +{ + fwrite(&value, sizeof (int8_t), 1, f); +} + +static void iffWriteChunkData(FILE *f, const void *data, size_t length) +{ + fwrite(data, sizeof (int8_t), length, f); + if (length & 1) fputc(0, f); // write pad byte if chunk size is uneven +} + static bool saveIFFSample(UNICHAR *filenameU, bool saveRangedData) { char *smpNamePtr; @@ -239,12 +250,11 @@ static bool saveIFFSample(UNICHAR *filenameU, bool saveRangedData) // samplesPerSec tmp32 = getSampleMiddleCRate(smp); - if (tmp32 == 0 || tmp32 > 65535) - tmp32 = 16726; - iffWriteUint16(f, tmp32 & 0xFFFF); + if (tmp32 == 0 || tmp32 > 65535) tmp32 = 16726; + iffWriteUint16(f, (uint16_t)tmp32); - fputc(1, f); // ctOctave (number of samples) - fputc(0, f); // sCompression + iffWriteUint8(f, 1); // ctOctave (number of samples) + iffWriteUint8(f, 0); // sCompression iffWriteUint32(f, smp->vol * 1024); // volume (max: 65536/0x10000) // "NAME" chunk @@ -268,38 +278,33 @@ static bool saveIFFSample(UNICHAR *filenameU, bool saveRangedData) } } - if (smpNameLen > 0) + // "NAME" chunk + chunkLen = smpNameLen; + if (chunkLen > 0) { - chunkLen = smpNameLen; iffWriteChunkHeader(f, "NAME", chunkLen); - fwrite(smpNamePtr, 1, chunkLen, f); - if (chunkLen & 1) fputc(0, f); // write pad byte if chunk size is uneven + iffWriteChunkData(f, smpNamePtr, chunkLen); } // "ANNO" chunk (we put the program name here) - if (PROG_NAME_STR[0] != '\0') - { - chunkLen = sizeof (PROG_NAME_STR) - 1; - iffWriteChunkHeader(f, "ANNO", chunkLen); - fwrite(PROG_NAME_STR, 1, chunkLen, f); - if (chunkLen & 1) fputc(0, f); // write pad byte if chunk size is uneven - } + chunkLen = sizeof (PROG_NAME_STR) - 1; + iffWriteChunkHeader(f, "ANNO", chunkLen); + iffWriteChunkData(f, PROG_NAME_STR, chunkLen); // "BODY" chunk chunkLen = sampleLen; iffWriteChunkHeader(f, "BODY", chunkLen); sampleDataPos = ftell(f); - fwrite(samplePtr, 1, chunkLen, f); - if (chunkLen & 1) fputc(0, f); // write pad byte if chunk size is uneven + iffWriteChunkData(f, samplePtr, chunkLen); // go back and fill in "FORM" chunk size - tmp32 = ftell(f) - 8; + chunkLen = ftell(f) - 8; fseek(f, 4, SEEK_SET); - iffWriteUint32(f, tmp32); + iffWriteUint32(f, chunkLen); fclose(f); - // restore mixer interpolation fix + // restore interpolation sample fix (was used for audio mixer) fileRestoreSampleData(filenameU, sampleDataPos, smp); editor.diskOpReadDir = true; // force diskop re-read @@ -395,7 +400,7 @@ static bool saveWAVSample(UNICHAR *filenameU, bool saveRangedData) samplerChunk.chunkID = 0x6C706D73; // "smpl" samplerChunk.chunkSize = sizeof (samplerChunk) - 4 - 4; samplerChunk.dwSamplePeriod = 1000000000 / wavHeader.sampleRate; - samplerChunk.dwMIDIUnityNote = 60; // 60 = C-4 + samplerChunk.dwMIDIUnityNote = 60; // 60 = MIDI middle-C samplerChunk.cSampleLoops = 1; samplerChunk.loop.dwType = (smp->typ & 3) - 1; // 0 = forward, 1 = ping-pong @@ -424,7 +429,7 @@ static bool saveWAVSample(UNICHAR *filenameU, bool saveRangedData) mptExtraChunk.chunkID = 0x61727478; // "xtra" mptExtraChunk.chunkSize = sizeof (mptExtraChunk) - 4 - 4; - mptExtraChunk.flags = 0x20; // set pan flag - used when loading .WAVs in OpenMPT + mptExtraChunk.flags = 0x20; // set pan flag mptExtraChunk.defaultPan = smp->pan; // 0..255 mptExtraChunk.defaultVolume = smp->vol * 4; // 0..256 mptExtraChunk.globalVolume = 64; // 0..64 diff --git a/src/ft2_scopes.c b/src/ft2_scopes.c @@ -368,12 +368,13 @@ static void scopeTrigger(int32_t ch, sampleTyp *s, int32_t playOffset) } // these has to be read - tempState.active = true; tempState.wasCleared = sc->wasCleared; tempState.SFrq = sc->SFrq; tempState.DFrq = sc->DFrq; tempState.SVol = sc->SVol; + tempState.active = true; + /* Update live scope now. ** In theory it -can- be written to in the middle of a cached read, ** then the read thread writes its own non-updated cached copy back and @@ -581,10 +582,6 @@ void handleScopesFromChQueue(chSyncData_t *chSyncData, uint8_t *scopeUpdateStatu static int32_t SDLCALL scopeThreadFunc(void *ptr) { - int32_t time32; - uint32_t diff32; - uint64_t time64; - // this is needed for scope stability (confirmed) SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); @@ -598,16 +595,19 @@ static int32_t SDLCALL scopeThreadFunc(void *ptr) updateScopes(); editor.scopeThreadMutex = false; - time64 = SDL_GetPerformanceCounter(); + uint64_t time64 = SDL_GetPerformanceCounter(); if (time64 < timeNext64) { - assert(timeNext64-time64 <= 0xFFFFFFFFULL); - diff32 = (uint32_t)(timeNext64 - time64); + time64 = timeNext64 - time64; + if (time64 > UINT32_MAX) + time64 = UINT32_MAX; + + const uint32_t diff32 = (uint32_t)time64; // convert to microseconds and round to integer - time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5); + const int32_t time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5); - // delay until we have reached next tick + // delay until we have reached the next frame if (time32 > 0) usleep(time32); } diff --git a/src/ft2_video.c b/src/ft2_video.c @@ -743,20 +743,20 @@ void setupWaitVBL(void) void waitVBL(void) { // this routine almost never delays if we have 60Hz vsync, but it's still needed in some occasions - int32_t time32; - uint32_t diff32; - uint64_t time64; - time64 = SDL_GetPerformanceCounter(); + uint64_t time64 = SDL_GetPerformanceCounter(); if (time64 < timeNext64) { - assert(timeNext64-time64 <= 0xFFFFFFFFULL); - diff32 = (uint32_t)(timeNext64 - time64); + time64 = timeNext64 - time64; + if (time64 > UINT32_MAX) + time64 = UINT32_MAX; + + const uint32_t diff32 = (uint32_t)time64; // convert and round to microseconds - time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5); + const int32_t time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5); - // delay until we have reached next frame + // delay until we have reached the next frame if (time32 > 0) usleep(time32); } @@ -1030,6 +1030,12 @@ bool setupRenderer(void) else SDL_ShowCursor(SDL_FALSE); + // Workaround: SDL_GetGlobalMouseState() doesn't work with KMSDRM + video.useDesktopMouseCoords = true; + const char *videoDriver = SDL_GetCurrentVideoDriver(); + if (videoDriver != NULL && strcmp("KMSDRM", videoDriver) == 0) + video.useDesktopMouseCoords = false; + return true; } diff --git a/src/ft2_video.h b/src/ft2_video.h @@ -18,14 +18,15 @@ enum typedef struct video_t { - bool fullscreen, showFPSCounter; + bool fullscreen, showFPSCounter, useDesktopMouseCoords; uint32_t xScale, yScale; uint32_t *frameBuffer, palette[PAL_NUM], vblankTimeLen, vblankTimeLenFrac; #ifdef _WIN32 HWND hWnd; #endif SDL_Window *window; - double dMonitorRefreshRate, dMouseXMul, dMouseYMul; + double dMonitorRefreshRate; + float fMouseXMul, fMouseYMul; uint8_t upscaleFactor; bool vsync60HzPresent, windowHidden; int32_t renderX, renderY, renderW, renderH, displayW, displayH;