shithub: ft2-clone

Download patch

ref: 9e6e95166ac606b05631c0ebacd81e93038f073e
parent: 4cb9cdc4475ea90ba9eb591cf00628ec60230f74
author: Olav Sørensen <olav.sorensen@live.no>
date: Mon Apr 6 17:53:03 EDT 2020

Pushed v1.18 code

- Windows: Fixed files >2GB displaying bogus filesizes in Disk Op.
- Fixed a potential crash in the audio mixer on quirky modules (when a
  channel's sampling rate is somehow set to 0).
- Fixed a bug with vertical scrollbars that have a very small thumb (v1.16)

--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -20,8 +20,8 @@
 static int8_t pmpCountDiv, pmpChannels = 2;
 static uint16_t smpBuffSize;
 static int32_t masterVol, oldAudioFreq, speedVal, pmpLeft, randSeed = INITIAL_DITHER_SEED;
-static int32_t prngStateL, prngStateR, oldPeriod, oldSFrq, oldSFrqRev;
-static uint32_t tickTimeLen, tickTimeLenFrac;
+static int32_t prngStateL, prngStateR, oldPeriod;
+static uint32_t tickTimeLen, tickTimeLenFrac, oldSFrq, oldSFrqRev;
 static float fAudioAmpMul;
 static voice_t voice[MAX_VOICES * 2];
 static void (*sendAudSamplesFunc)(uint8_t *, uint32_t, uint8_t); // "send mixed samples" routines
@@ -372,6 +372,8 @@
 		{
 			if (ch->finalPeriod != oldPeriod) // this value will very often be the same as before
 			{
+				oldPeriod = ch->finalPeriod;
+
 				oldSFrq = getFrequenceValue(ch->finalPeriod);
 
 				oldSFrqRev = 0xFFFFFFFF;
--- a/src/ft2_audio.h
+++ b/src/ft2_audio.h
@@ -33,7 +33,7 @@
 	uint32_t freq;
 	uint32_t audLatencyPerfValInt, audLatencyPerfValFrac;
 	uint64_t tickTime64, tickTime64Frac;
-	double dAudioLatencyMs, dSpeedValMul, dScopeFreqMul, dPianoDeltaMul;
+	double dAudioLatencyMs, dSpeedValMul, dPianoDeltaMul;
 	SDL_AudioDeviceID dev;
 	uint32_t wantFreq, haveFreq, wantSamples, haveSamples, wantChannels, haveChannels;
 } audio;
@@ -45,10 +45,9 @@
 	bool backwards, isFadeOutVoice;
 	uint8_t SPan;
 	uint16_t SVol;
-	int32_t SLVol1, SRVol1, SLVol2, SRVol2, SLVolIP, SRVolIP, SVolIPLen;
-	int32_t SPos, SLen, SRepS, SRepL, SFrq, SFrqRev;
-	uint32_t SPosDec;
-
+	int32_t SLVol1, SRVol1, SLVol2, SRVol2, SLVolIP, SRVolIP;
+	int32_t SPos, SLen, SRepS, SRepL;
+	uint32_t SVolIPLen, SPosDec, SFrq, SFrqRev;
 	void (*mixRoutine)(void *, int32_t); // function pointer to mix routine
 } voice_t;
 
--- a/src/ft2_diskop.c
+++ b/src/ft2_diskop.c
@@ -1478,6 +1478,9 @@
 	}
 #endif
 
+	if (searchRec->filesize < -1)
+		searchRec->filesize = -1;
+
 	if (handleEntrySkip(searchRec->nameU, searchRec->isDir))
 	{
 		// skip file
@@ -1557,6 +1560,9 @@
 		}
 	}
 #endif
+
+	if (searchRec->filesize < -1)
+		searchRec->filesize = -1;
 
 	if (handleEntrySkip(searchRec->nameU, searchRec->isDir))
 	{
--- a/src/ft2_header.h
+++ b/src/ft2_header.h
@@ -12,7 +12,7 @@
 #endif
 #include "ft2_replayer.h"
 
-#define PROG_VER_STR "1.17"
+#define PROG_VER_STR "1.18"
 
 // do NOT change these! It will only mess things up...
 
--- a/src/ft2_main.c
+++ b/src/ft2_main.c
@@ -119,7 +119,8 @@
 	/* SDL 2.0.9 for Windows has a serious bug where you need to initialize the joystick subsystem
 	** (even if you don't use it) or else weird things happen like random stutters, keyboard (rarely) being
 	** reinitialized in Windows and what not.
-	** Ref.: https://bugzilla.libsdl.org/show_bug.cgi?id=4391 */
+	** Ref.: https://bugzilla.libsdl.org/show_bug.cgi?id=4391
+	*/
 #if defined _WIN32 && SDL_PATCHLEVEL == 9
 	if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0)
 #else
@@ -133,7 +134,8 @@
 
 	/* Text input is started by default in SDL2, turn it off to remove ~2ms spikes per key press.
 	** We manuallay start it again when a text edit box is activated, and stop it when done.
-	** Ref.: https://bugzilla.libsdl.org/show_bug.cgi?id=4166 */
+	** Ref.: https://bugzilla.libsdl.org/show_bug.cgi?id=4166
+	*/
 	SDL_StopTextInput();
 
 #ifdef __APPLE__
--- a/src/ft2_mix.c
+++ b/src/ft2_mix.c
@@ -38,8 +38,8 @@
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
 	int32_t realPos, sample, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	GET_VOL
 
@@ -50,7 +50,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -102,8 +101,8 @@
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;;
 	int32_t realPos, sample, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	GET_VOL
 
@@ -114,7 +113,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -166,8 +164,8 @@
 {
 	const int8_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
 	int32_t realPos, sample, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 
 	GET_VOL
 
@@ -230,8 +228,8 @@
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
 	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -245,7 +243,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -297,8 +294,8 @@
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
 	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -312,7 +309,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -364,8 +360,8 @@
 {
 	const int8_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
 	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -431,9 +427,9 @@
 static void mix8bRampNoLoop(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -442,7 +438,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -502,9 +497,9 @@
 static void mix8bRampLoop(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;;
-	int32_t realPos, sample, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -513,7 +508,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -573,9 +567,9 @@
 static void mix8bRampBidiLoop(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
-	int32_t realPos, sample, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t realPos, sample, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -645,9 +639,9 @@
 static void mix8bRampNoLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -659,7 +653,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -719,9 +712,9 @@
 static void mix8bRampLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -733,7 +726,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE8
 
 	CDA_BytesLeft = numSamples;
@@ -793,9 +785,9 @@
 static void mix8bRampBidiLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -874,8 +866,8 @@
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
 	int32_t realPos, sample, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	GET_VOL
 
@@ -886,7 +878,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -938,8 +929,8 @@
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
 	int32_t realPos, sample, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	GET_VOL
 
@@ -950,7 +941,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -1002,8 +992,8 @@
 {
 	const int16_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
 	int32_t realPos, sample, *audioMixL, *audioMixR;
-	int32_t  CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 
 	GET_VOL
 
@@ -1067,8 +1057,8 @@
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
 	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -1082,7 +1072,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -1134,8 +1123,8 @@
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
 	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -1149,7 +1138,6 @@
 	}
 
 	GET_MIXER_VARS
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -1201,8 +1189,8 @@
 {
 	const int16_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
 	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
-	int32_t CDA_BytesLeft, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -1268,9 +1256,9 @@
 static void mix16bRampNoLoop(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -1279,7 +1267,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -1339,9 +1326,9 @@
 static void mix16bRampLoop(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -1350,7 +1337,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -1410,9 +1396,9 @@
 static void mix16bRampBidiLoop(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
-	int32_t realPos, sample, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t realPos, sample, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -1482,9 +1468,9 @@
 static void mix16bRampNoLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -1496,7 +1482,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -1556,9 +1541,9 @@
 static void mix16bRampLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos;
+	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
@@ -1570,7 +1555,6 @@
 	}
 
 	GET_MIXER_VARS_RAMP
-	GET_DELTA
 	SET_BASE16
 
 	CDA_BytesLeft = numSamples;
@@ -1630,9 +1614,9 @@
 static void mix16bRampBidiLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR, CDA_BytesLeft;
-	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol, i, samplesToMix;
-	uint32_t pos, delta;
+	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t CDA_LVolIP, CDA_RVolIP, CDA_LVol, CDA_RVol;
+	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
 #ifndef LERPMIX
 	int32_t sample3, sample4;
 #endif
--- a/src/ft2_mix_macros.h
+++ b/src/ft2_mix_macros.h
@@ -14,11 +14,9 @@
 	v->SLVol2 = CDA_LVol; \
 	v->SRVol2 = CDA_RVol; \
 
-#define GET_DELTA \
-	const uint32_t delta = v->SFrq;
-
 #define GET_MIXER_VARS \
-	const int32_t SFrqRev = v->SFrqRev; \
+	const uint32_t SFrq = v->SFrq; \
+	const uint32_t SFrqRev = v->SFrqRev; \
 	audioMixL = audio.mixBufferL; \
 	audioMixR = audio.mixBufferR; \
 	const bool mixInMono = (CDA_LVol == CDA_RVol); \
@@ -26,7 +24,8 @@
 	pos = v->SPosDec; \
 
 #define GET_MIXER_VARS_RAMP \
-	const int32_t SFrqRev = v->SFrqRev; \
+	const uint32_t SFrq = v->SFrq; \
+	const uint32_t SFrqRev = v->SFrqRev; \
 	audioMixL = audio.mixBufferL; \
 	audioMixR = audio.mixBufferR; \
 	CDA_LVolIP = v->SLVolIP; \
@@ -52,7 +51,7 @@
 	CDA_LinAdrRev = v->SRevBase16; \
 
 #define INC_POS \
-	pos += delta; \
+	pos += SFrq; \
 	smpPtr += pos >> 16; \
 	pos &= 0xFFFF; \
 
@@ -243,17 +242,18 @@
 /* ----------------------------------------------------------------------- */
 
 #define LIMIT_MIX_NUM \
-	samplesToMix = (v->SLen - 1) - realPos; \
-	if (samplesToMix > 65535) \
-		samplesToMix = 65535; \
+	i = (v->SLen - 1) - realPos; \
+	if (i > 65535) \
+		i = 65535; \
 	\
-	samplesToMix = (samplesToMix << 16) | (pos ^ 0xFFFF); \
-	samplesToMix = ((int64_t)samplesToMix * SFrqRev) >> 32; \
+	i = (i << 16) | (pos ^ 0xFFFF); \
+	samplesToMix = ((int64_t)i * SFrqRev) >> 32; \
 	samplesToMix++; \
 	\
 	if (samplesToMix > CDA_BytesLeft) \
 		samplesToMix = CDA_BytesLeft; \
 
+
 #define LIMIT_MIX_NUM_RAMP \
 	if (v->SVolIPLen == 0) \
 	{ \
@@ -274,10 +274,31 @@
 		v->SVolIPLen -= samplesToMix; \
 	} \
 
+#define HANDLE_SAMPLE_END \
+	realPos = (int32_t)(smpPtr - CDA_LinearAdr); \
+	if (realPos >= v->SLen) \
+	{ \
+		v->mixRoutine = NULL; \
+		return; \
+	} \
+
+#define WRAP_LOOP \
+	realPos = (int32_t)(smpPtr - CDA_LinearAdr); \
+	while (realPos >= v->SLen) \
+		realPos -= v->SRepL; \
+	smpPtr = CDA_LinearAdr + realPos; \
+
+#define WRAP_BIDI_LOOP \
+	while (realPos >= v->SLen) \
+	{ \
+		realPos -= v->SRepL; \
+		v->backwards ^= 1; \
+	} \
+
 #define START_BIDI \
 	if (v->backwards) \
 	{ \
-		delta = 0 - v->SFrq; \
+		delta = 0 - SFrq; \
 		assert(realPos >= v->SRepS && realPos < v->SLen); \
 		realPos = ~realPos; \
 		smpPtr = CDA_LinAdrRev + realPos; \
@@ -285,7 +306,7 @@
 	} \
 	else \
 	{ \
-		delta = v->SFrq; \
+		delta = SFrq; \
 		assert(realPos >= 0 && realPos < v->SLen); \
 		smpPtr = CDA_LinearAdr + realPos; \
 	} \
@@ -304,31 +325,6 @@
 		realPos = (int32_t)(smpPtr - CDA_LinearAdr); \
 	} \
 	\
-
-/* ----------------------------------------------------------------------- */
-/*                     SAMPLE END/LOOP WRAPPING MACROS                     */
-/* ----------------------------------------------------------------------- */
-
-#define HANDLE_SAMPLE_END \
-	realPos = (int32_t)(smpPtr - CDA_LinearAdr); \
-	if (realPos >= v->SLen) \
-	{ \
-		v->mixRoutine = NULL; \
-		return; \
-	} \
-
-#define WRAP_LOOP \
-	realPos = (int32_t)(smpPtr - CDA_LinearAdr); \
-	while (realPos >= v->SLen) \
-		realPos -= v->SRepL; \
-	smpPtr = CDA_LinearAdr + realPos; \
-
-#define WRAP_BIDI_LOOP \
-	while (realPos >= v->SLen) \
-	{ \
-		realPos -= v->SRepL; \
-		v->backwards ^= 1; \
-	} \
 
 /* ----------------------------------------------------------------------- */
 /*                       VOLUME=0 OPTIMIZATION MACROS                      */
--- a/src/ft2_replayer.c
+++ b/src/ft2_replayer.c
@@ -26,7 +26,8 @@
 */
 
 static bool bxxOverflow;
-static int32_t oldPeriod, oldRate, frequenceDivFactor, frequenceMulFactor;
+static int32_t oldPeriod, oldRate;
+static uint32_t frequenceDivFactor, frequenceMulFactor;
 static tonTyp nilPatternLine;
 
 // globally accessed
@@ -324,27 +325,16 @@
 	if (rate == 0)
 		return;
 
-	// for voice delta calculation
-
-	double dVal, dMul = 1.0 / rate;
-
-	dVal = dMul * (65536.0 * 1712.0 * 8363.0);
-	frequenceDivFactor = (int32_t)(dVal + 0.5);
-
-	dVal = dMul * (256.0 * 65536.0 * 8363.0);
-	frequenceMulFactor = (int32_t)(dVal + 0.5);
-
-	audio.dScopeFreqMul = rate / SCOPE_HZ;
-
-	// for volume ramping (FT2 doesn't round here)
+	// the following calculations are 100% accurate to FT2, do not touch!
+	frequenceDivFactor = (int32_t)round(65536.0 * 1712.0 / rate * 8363.0);
+	frequenceMulFactor = (int32_t)round(256.0 * 65536.0 / rate * 8363.0);
 	audio.quickVolSizeVal = rate / 200;
 
+	// the following are non-FT2 calculations
 	audio.rampQuickVolMul = (int32_t)round((UINT32_MAX + 1.0) / audio.quickVolSizeVal);
+	audio.dSpeedValMul = editor.dPerfFreq / rate; // for audio/video sync
 
-	// for audio/video sync
-	audio.dSpeedValMul = (1.0 / rate) * editor.dPerfFreq;
-
-	uint32_t deltaBase = frequenceDivFactor / (1712 * 16); // exact 16.16 delta base for this audio rate
+	const uint32_t deltaBase = frequenceDivFactor / (1712 * 16); // exact 16.16 delta base
 	audio.dPianoDeltaMul = 1.0 / deltaBase; // for piano in Instr. Ed.
 }
 
--- a/src/ft2_scopedraw.c
+++ b/src/ft2_scopedraw.c
@@ -60,12 +60,12 @@
 	} \
 
 #define SCOPE_UPDATE_DRAWPOS \
-	scopeDrawFrac += s->SFrq >> 6; \
+	scopeDrawFrac += (uint32_t)(s->SFrq >> (SCOPE_FRAC_BITS - 10)); \
 	scopeDrawPos += scopeDrawFrac >> 16; \
 	scopeDrawFrac &= 0xFFFF; \
 
 #define SCOPE_UPDATE_DRAWPOS_PINGPONG \
-	scopeDrawFrac += s->SFrq >> 6; \
+	scopeDrawFrac += (uint32_t)(s->SFrq >> (SCOPE_FRAC_BITS - 10)); \
 	scopeDrawPos += (scopeDrawFrac >> 16) * drawPosDir; \
 	scopeDrawFrac &= 0xFFFF; \
 
--- a/src/ft2_scopes.c
+++ b/src/ft2_scopes.c
@@ -22,6 +22,10 @@
 #include "ft2_scopedraw.h"
 #include "ft2_tables.h"
 
+#if SCOPE_HZ != 64
+#error The SCOPE_HZ definition in ft2_header.h must be 2^n!
+#endif
+
 enum
 {
 	LOOP_NONE = 0,
@@ -40,8 +44,9 @@
 } scopeState_t;
 
 static volatile bool scopesUpdatingFlag, scopesDisplayingFlag;
-static uint32_t oldVoiceDelta, oldSFrq, scopeTimeLen, scopeTimeLenFrac;
-static uint64_t timeNext64, timeNext64Frac;
+static int32_t oldPeriod;
+static uint32_t scopeTimeLen, scopeTimeLenFrac;
+static uint64_t timeNext64, timeNext64Frac, oldSFrq;
 static volatile scope_t scope[MAX_VOICES];
 static SDL_Thread *scopeThread;
 static uint8_t *scopeMuteBMP_Ptrs[16];
@@ -50,7 +55,7 @@
 
 void resetCachedScopeVars(void)
 {
-	oldVoiceDelta = 0xFFFFFFFF;
+	oldPeriod = -1;
 	oldSFrq = 0;
 }
 
@@ -405,8 +410,8 @@
 		// scope position update
 
 		tempState.SPosDec += tempState.SFrq;
-		tempState.SPos += ((tempState.SPosDec >> 16) * tempState.SPosDir);
-		tempState.SPosDec &= 0xFFFF;
+		tempState.SPos += ((int32_t)(tempState.SPosDec >> SCOPE_FRAC_BITS) * tempState.SPosDir);
+		tempState.SPosDec &= SCOPE_FRAC_MASK;
 
 		// handle loop wrapping or sample end
 
@@ -558,10 +563,10 @@
 		// set scope frequency
 		if (status & IS_Period)
 		{
-			if (ch->voiceDelta != oldVoiceDelta)
+			if (ch->finalPeriod != oldPeriod)
 			{
-				oldVoiceDelta = ch->voiceDelta;
-				oldSFrq = (int32_t)(((int32_t)oldVoiceDelta * audio.dScopeFreqMul) + 0.5); // rounded
+				oldPeriod = ch->finalPeriod;
+				oldSFrq = (uint64_t)ch->voiceDelta * audio.freq; // this can very well be higher than 2^32
 			}
 
 			sc->SFrq = oldSFrq;
--- a/src/ft2_scopes.h
+++ b/src/ft2_scopes.h
@@ -4,6 +4,12 @@
 #include <stdbool.h>
 #include "ft2_header.h"
 
+// log2(65536 / SCOPE_HZ) where SCOPE_HZ is 2^n
+#define SCOPE_FRAC_BITS 22
+
+#define SCOPE_FRAC_SCALE (1UL << SCOPE_FRAC_BITS)
+#define SCOPE_FRAC_MASK (SCOPE_FRAC_SCALE-1)
+
 void resetCachedScopeVars(void);
 int32_t getSamplePosition(uint8_t ch);
 void stopAllScopes(void);
@@ -23,7 +29,7 @@
 	bool wasCleared, sample16Bit;
 	uint8_t loopType;
 	int32_t SPosDir, SRepS, SRepL, SLen, SPos;
-	uint32_t SFrq, SPosDec;
+	uint64_t SFrq, SPosDec;
 } scope_t;
 
 typedef struct lastChInstr_t
--- a/src/ft2_scrollbars.c
+++ b/src/ft2_scrollbars.c
@@ -24,7 +24,7 @@
 ** it's difficult to use them. In units of pixels.
 ** Shouldn't be higher than 9!
 */
-#define MIN_THUMB_LENGTH 9
+#define MIN_THUMB_LENGTH 5
 
 scrollBar_t scrollBars[NUM_SCROLLBARS] =
 {
@@ -271,7 +271,7 @@
 		{
 			dTmp = (scrollBar->h / (double)scrollBar->end) * scrollBar->page;
 			tmp32 = (int32_t)(dTmp + 0.5);
-			realThumbLength = (int16_t)CLAMP(tmp32, MIN_THUMB_LENGTH, scrollBar->h);
+			realThumbLength = (int16_t)CLAMP(tmp32, 1, scrollBar->h);
 		}
 		else
 		{
@@ -279,8 +279,8 @@
 		}
 
 		thumbH = realThumbLength;
-		if (thumbW < MIN_THUMB_LENGTH)
-			thumbW = MIN_THUMB_LENGTH;
+		if (thumbH < MIN_THUMB_LENGTH)
+			thumbH = MIN_THUMB_LENGTH;
 
 		if (scrollBar->end > scrollBar->page)
 		{
@@ -578,7 +578,7 @@
 					assert(scrollBar->h > 0);
 					scrollPos = CLAMP(scrollPos, 0, scrollBar->h);
 
-					length = scrollBar->h + (scrollBar->realThumbLength - scrollBar->thumbW);
+					length = scrollBar->h + (scrollBar->realThumbLength - scrollBar->thumbH);
 					if (length < 1)
 						length = 1;
 
@@ -669,6 +669,8 @@
 			mouse.lastScrollY = mouse.y;
 
 			scrollY = mouse.lastScrollY - mouse.saveMouseY - scrollBar->y;
+
+			assert(scrollBar->h > 0);
 			scrollY = CLAMP(scrollY, 0, scrollBar->h);
 
 			length = scrollBar->h + (scrollBar->realThumbLength - scrollBar->thumbH);
--- a/src/ft2_video.c
+++ b/src/ft2_video.c
@@ -162,8 +162,6 @@
 
 void flipFrame(void)
 {
-	uint32_t windowFlags = SDL_GetWindowFlags(video.window);
-
 	renderSprites();
 
 	if (video.showFPSCounter)
@@ -181,6 +179,8 @@
 	}
 	else
 	{
+		uint32_t windowFlags = SDL_GetWindowFlags(video.window);
+
 		/* We have VSync, but it can unexpectedly get inactive in certain scenarios.
 		** We have to force thread sleeping (to ~60Hz) if so.
 		*/