shithub: ft2-clone

Download patch

ref: b9d63e21780f167ce06a3ed8d92f2534d0545cec
parent: 9e6e95166ac606b05631c0ebacd81e93038f073e
author: Olav Sørensen <olav.sorensen@live.no>
date: Wed Apr 8 11:25:46 EDT 2020

Pushed v1.19 code

- The "Trim" function had been 100% broken (and crashes the program) for a
  very long time. Sorry for this! This happened after instruments were
  changed to be allocated as needed.
- macOS: 48kHz is now the default audio output rate (instead of 44.1kHz)
- For x86_64/amd64 users: The audio channel mixer now has higher fractional
  precision on mixing deltas, which is beneficial for 96kHz audio frequency
  mode.

--- a/HOW-TO-COMPILE.txt
+++ b/HOW-TO-COMPILE.txt
@@ -24,10 +24,6 @@
     
  Note: If you don't have libstdc++ and/or can't compile rtmidi, try running
        make-linux-nomidi.sh instead.
-    
- Note: If you want faster audio mixing (for SLOW devices), pass -DLERPMIX
-       to the GCC command line (edit make-linux.sh/make-linux-nomidi.sh). This
-       will lower the resampling interpolation quality, though...
        
  Known issues: Audio recording (sampling) can update VERY slowly or not work at
                all... I have no idea why, it works really well on Windows/maCOS.
--- a/make-linux-nomidi.sh
+++ b/make-linux-nomidi.sh
@@ -3,10 +3,6 @@
 rm release/other/ft2-clone &> /dev/null
 echo Compiling \(with no MIDI functionality\), please wait patiently...
 
-# If you're compiling for *SLOW* devices, try adding -DLERPMIX right after gcc
-# This will activate 2-tap linear interpolation mixing (blurrier sound) instead
-# of 3-tap quadratic interpolation mixing (sharper sound)
-
 gcc -DNDEBUG src/gfxdata/*.c src/*.c -lSDL2 -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone
 
 rm src/gfxdata/*.o src/*.o &> /dev/null
--- a/make-linux.sh
+++ b/make-linux.sh
@@ -3,10 +3,6 @@
 rm release/other/ft2-clone &> /dev/null
 echo Compiling, please wait patiently...
 
-# If you're compiling for *SLOW* devices, try adding -DLERPMIX right after gcc
-# This will activate 2-tap linear interpolation mixing (blurrier sound) instead
-# of 3-tap quadratic interpolation mixing (sharper sound)
-
 gcc -DNDEBUG -DHAS_MIDI -D__LINUX_ALSA__ src/rtmidi/*.cpp src/gfxdata/*.c src/*.c -lSDL2 -lpthread -lasound -lstdc++ -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone
 
 rm src/rtmidi/*.o src/gfxdata/*.o src/*.o &> /dev/null
--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -20,17 +20,23 @@
 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;
-static uint32_t tickTimeLen, tickTimeLenFrac, oldSFrq, oldSFrqRev;
+static int32_t prngStateL, prngStateR;
+static uint32_t tickTimeLen, tickTimeLenFrac;
 static float fAudioAmpMul;
 static voice_t voice[MAX_VOICES * 2];
 static void (*sendAudSamplesFunc)(uint8_t *, uint32_t, uint8_t); // "send mixed samples" routines
 
+#if !defined __amd64__ && !defined _WIN64
+static int32_t oldPeriod;
+static uint32_t oldSFrq, oldSFrqRev;
+#endif
+
 pattSyncData_t *pattSyncEntry;
 chSyncData_t *chSyncEntry;
 
 volatile bool pattQueueReading, pattQueueClearing, chQueueReading, chQueueClearing;
 
+#if !defined __amd64__ && !defined _WIN64
 void resetCachedMixerVars(void)
 {
 	oldPeriod = -1;
@@ -37,6 +43,7 @@
 	oldSFrq = 0;
 	oldSFrqRev = 0xFFFFFFFF;
 }
+#endif
 
 void stopVoice(uint8_t i)
 {
@@ -367,10 +374,14 @@
 		if (status & (IS_Vol + IS_Pan))
 			voiceUpdateVolumes(i, status);
 
-		// frequency change
+		// frequency change (received even if the period didn't change!)
 		if (status & IS_Period)
 		{
-			if (ch->finalPeriod != oldPeriod) // this value will very often be the same as before
+#if defined __amd64__ || defined _WIN64
+			v->SFrq = getFrequenceValue(ch->finalPeriod);
+#else
+			// use cached values to prevent a 32-bit divsion all the time
+			if (ch->finalPeriod != oldPeriod)
 			{
 				oldPeriod = ch->finalPeriod;
 
@@ -383,6 +394,7 @@
 
 			v->SFrq = oldSFrq;
 			v->SFrqRev = oldSFrqRev;
+#endif
 		}
 
 		// sample trigger (note)
@@ -1098,11 +1110,7 @@
 	if (config.audioFreq < MIN_AUDIO_FREQ || config.audioFreq > MAX_AUDIO_FREQ)
 	{
 		// set default rate
-#ifdef __APPLE__
-		config.audioFreq = 44100;
-#else
 		config.audioFreq = 48000;
-#endif
 	}
 
 	// get audio buffer size from config special flags
--- a/src/ft2_audio.h
+++ b/src/ft2_audio.h
@@ -8,9 +8,27 @@
 enum
 {
 	FREQ_TABLE_LINEAR = 0,
-	FREQ_TABLE_AMIGA  = 1,
+	FREQ_TABLE_AMIGA = 1,
 };
 
+/* Warning: MIXER_FRAC_BITS must NOT be higher than 22!
+** This can create an overflow in certain calculations.
+**
+** Use 16 on non-x86_64 platforms so that we can avoid a
+** 64-bit division in the outside mixer loop. x86_64 users
+** are lucky and will get higher fractional delta precision.
+** This is beneficial in 96kHz mode, where deltas are lower
+** in value.
+*/
+#if defined __amd64__ || defined _WIN64
+#define MIXER_FRAC_BITS 22
+#else
+#define MIXER_FRAC_BITS 16
+#endif
+
+#define MIXER_FRAC_SCALE (1L << MIXER_FRAC_BITS)
+#define MIXER_FRAC_MASK (MIXER_FRAC_SCALE-1)
+
 // for audio/video sync queue. (2^n-1 - don't change this! Queue buffer is already ~2.7MB in size)
 #define SYNC_QUEUE_LEN 4095
 
@@ -19,8 +37,6 @@
 #define MIN_AUDIO_FREQ 44100
 #define MAX_AUDIO_FREQ 96000
 
-#define CUBIC_TABLE_LEN (8192+1)
-
 struct audio_t
 {
 	char *currInputDevice, *currOutputDevice, *lastWorkingAudioDeviceName;
@@ -47,7 +63,12 @@
 	uint16_t SVol;
 	int32_t SLVol1, SRVol1, SLVol2, SRVol2, SLVolIP, SRVolIP;
 	int32_t SPos, SLen, SRepS, SRepL;
-	uint32_t SVolIPLen, SPosDec, SFrq, SFrqRev;
+	uint32_t SVolIPLen, SPosDec, SFrq;
+	
+#if !defined __amd64__ && !defined _WIN64
+	uint32_t SFrqRev;
+#endif
+
 	void (*mixRoutine)(void *, int32_t); // function pointer to mix routine
 } voice_t;
 
@@ -80,7 +101,10 @@
 
 extern volatile bool pattQueueReading, pattQueueClearing, chQueueReading, chQueueClearing;
 
+#if !defined __amd64__ && !defined _WIN64
 void resetCachedMixerVars(void);
+#endif
+
 int32_t pattQueueReadSize(void);
 int32_t pattQueueWriteSize(void);
 bool pattQueuePush(pattSyncData_t t);
--- a/src/ft2_config.c
+++ b/src/ft2_config.c
@@ -71,7 +71,7 @@
 	return checksum;
 }
 
-static void loadConfigFromBuffer(uint8_t defaults)
+static void loadConfigFromBuffer(void)
 {
 	int32_t i, checksum;
 
@@ -79,13 +79,6 @@
 
 	memcpy(&config, configBuffer, CONFIG_FILE_SIZE);
 
-#ifdef __APPLE__
-	if (defaults)
-		config.audioFreq = 44100;
-#else
-	(void)defaults; // prevent warning
-#endif
-
 	// if Nibbles highscore table checksum is incorrect, load default highscore table instead
 	checksum = calcChecksum((uint8_t *)&config.NI_HighScore, sizeof (config.NI_HighScore));
 	if (config.NI_HighScoreChecksum != checksum)
@@ -143,23 +136,10 @@
 	}
 
 	if (config.audioFreq != 44100 && config.audioFreq != 48000 && config.audioFreq != 96000)
-	{
-		// set default
-#ifdef __APPLE__
-		config.audioFreq = 44100;
-#else
 		config.audioFreq = 48000;
-#endif
-	}
 
 	if (config.audioInputFreq <= 1) // default value from FT2 (this was cdr_Sync) - set defaults
-	{
-#ifdef __APPLE__
-		config.audioInputFreq = INPUT_FREQ_44KHZ;
-#else
 		config.audioInputFreq = INPUT_FREQ_48KHZ;
-#endif
-	}
 
 	if (config.specialFlags == 64) // default value from FT2 (this was ptnDefaultLen byte #1) - set defaults
 		config.specialFlags = BUFFSIZE_1024 | BITDEPTH_16;
@@ -204,7 +184,7 @@
 static void setDefaultConfigSettings(void)
 {
 	memcpy(configBuffer, defConfigData, CONFIG_FILE_SIZE);
-	loadConfigFromBuffer(true);
+	loadConfigFromBuffer();
 }
 
 void resetConfig(void)
@@ -344,7 +324,7 @@
 		return false;
 	}
 
-	loadConfigFromBuffer(false);
+	loadConfigFromBuffer();
 	return true;
 }
 
@@ -736,7 +716,7 @@
 		return;
 	}
 
-	loadConfigFromBuffer(false);
+	loadConfigFromBuffer();
 }
 
 static void drawQuantValue(void)
@@ -833,13 +813,8 @@
 	uncheckRadioButtonGroup(RB_GROUP_CONFIG_AUDIO_FREQ);
 	switch (config.audioFreq)
 	{
-#ifdef __APPLE__
-		default: case 44100: tmpID = RB_CONFIG_AUDIO_44KHZ; break;
-		         case 48000: tmpID = RB_CONFIG_AUDIO_48KHZ; break;
-#else
 		         case 44100: tmpID = RB_CONFIG_AUDIO_44KHZ; break;
 		default: case 48000: tmpID = RB_CONFIG_AUDIO_48KHZ; break;
-#endif
 		         case 96000: tmpID = RB_CONFIG_AUDIO_96KHZ; break;
 	}
 	radioButtons[tmpID].state = RADIOBUTTON_CHECKED;
@@ -848,13 +823,8 @@
 	uncheckRadioButtonGroup(RB_GROUP_CONFIG_AUDIO_INPUT_FREQ);
 	switch (config.audioInputFreq)
 	{
-#ifdef __APPLE__
-		default: case INPUT_FREQ_44KHZ: tmpID = RB_CONFIG_AUDIO_INPUT_44KHZ; break;
-		         case INPUT_FREQ_48KHZ: tmpID = RB_CONFIG_AUDIO_INPUT_48KHZ; break;
-#else
 		         case INPUT_FREQ_44KHZ: tmpID = RB_CONFIG_AUDIO_INPUT_44KHZ; break;
 		default: case INPUT_FREQ_48KHZ: tmpID = RB_CONFIG_AUDIO_INPUT_48KHZ; break;
-#endif
 		         case INPUT_FREQ_96KHZ: tmpID = RB_CONFIG_AUDIO_INPUT_96KHZ; break;
 	}
 	radioButtons[tmpID].state = RADIOBUTTON_CHECKED;
@@ -1172,13 +1142,8 @@
 			textOutShadow(406, 160, PAL_FORGRND, PAL_DSKTOP2, "1-bit dither");
 
 			textOutShadow(509,   3, PAL_FORGRND, PAL_DSKTOP2, "Mixing frequency:");
-#ifdef __APPLE__
-			textOutShadow(525,  17, PAL_FORGRND, PAL_DSKTOP2, "44100Hz (default)");
-			textOutShadow(525,  31, PAL_FORGRND, PAL_DSKTOP2, "48000Hz");
-#else
 			textOutShadow(525,  17, PAL_FORGRND, PAL_DSKTOP2, "44100Hz");
 			textOutShadow(525,  31, PAL_FORGRND, PAL_DSKTOP2, "48000Hz (default)");
-#endif
 			textOutShadow(525,  45, PAL_FORGRND, PAL_DSKTOP2, "96000Hz");
 
 			textOutShadow(509,  76, PAL_FORGRND, PAL_DSKTOP2, "Frequency table:");
--- a/src/ft2_header.h
+++ b/src/ft2_header.h
@@ -12,7 +12,7 @@
 #endif
 #include "ft2_replayer.h"
 
-#define PROG_VER_STR "1.18"
+#define PROG_VER_STR "1.19"
 
 // do NOT change these! It will only mess things up...
 
--- a/src/ft2_intrp_table.h
+++ b/src/ft2_intrp_table.h
@@ -2,8 +2,7 @@
 
 #include <stdint.h>
 
-// number of bits for fractional sample position in audio mixer
-#define FRAC_BITS 16
+#include "ft2_audio.h"
 
 #define CUBIC_WIDTH 4
 #define CUBIC_WIDTH_BITS 2
@@ -10,7 +9,7 @@
 #define CUBIC_PHASES 4096
 #define CUBIC_PHASES_BITS 12
 
-#define CUBIC_FSHIFT (FRAC_BITS-(CUBIC_PHASES_BITS+CUBIC_WIDTH_BITS))
+#define CUBIC_FSHIFT (MIXER_FRAC_BITS-(CUBIC_PHASES_BITS+CUBIC_WIDTH_BITS))
 #define CUBIC_FMASK ((CUBIC_WIDTH*CUBIC_PHASES)-CUBIC_WIDTH)
 #define CUBIC_QUANTSHIFT 15
 
--- a/src/ft2_main.c
+++ b/src/ft2_main.c
@@ -179,11 +179,8 @@
 	if (!setupAudio(CONFIG_HIDE_ERRORS))
 	{
 		// one LAST attempt (with default audio device and settings)
-#ifdef __APPLE__
-		config.audioFreq = 44100;
-#else
 		config.audioFreq = 48000;
-#endif
+
 		// try 16-bit audio at 1024 samples (44.1kHz/48kHz)
 		config.specialFlags &= ~(BITDEPTH_24 + BUFFSIZE_512 + BUFFSIZE_2048);
 		config.specialFlags |=  (BITDEPTH_16 + BUFFSIZE_1024);
--- a/src/ft2_mix.c
+++ b/src/ft2_mix.c
@@ -227,12 +227,9 @@
 static void mix8bNoLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *audioMixL, *audioMixR;
 	int32_t CDA_LVol, CDA_RVol;
 	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
-#ifndef LERPMIX
-	int32_t sample3, sample4;
-#endif
 
 	GET_VOL
 
@@ -293,12 +290,9 @@
 static void mix8bLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *audioMixL, *audioMixR;
 	int32_t CDA_LVol, CDA_RVol;
 	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
-#ifndef LERPMIX
-	int32_t sample3, sample4;
-#endif
 
 	GET_VOL
 
@@ -359,12 +353,9 @@
 static void mix8bBidiLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *audioMixL, *audioMixR;
 	int32_t CDA_LVol, CDA_RVol;
 	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
-#ifndef LERPMIX
-	int32_t sample3, sample4;
-#endif
 
 	GET_VOL
 
@@ -639,12 +630,9 @@
 static void mix8bRampNoLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *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
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -712,12 +700,9 @@
 static void mix8bRampLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int8_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *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
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -785,12 +770,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;
+	int32_t realPos, sample, sample2, sample3, sample4, *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
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -1056,12 +1038,9 @@
 static void mix16bNoLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *audioMixL, *audioMixR;
 	int32_t CDA_LVol, CDA_RVol;
 	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
-#ifndef LERPMIX
-	int32_t sample3, sample4;
-#endif
 
 	GET_VOL
 
@@ -1122,12 +1101,9 @@
 static void mix16bLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *audioMixL, *audioMixR;
 	int32_t CDA_LVol, CDA_RVol;
 	uint32_t pos, i, samplesToMix, CDA_BytesLeft;
-#ifndef LERPMIX
-	int32_t sample3, sample4;
-#endif
 
 	GET_VOL
 
@@ -1188,12 +1164,9 @@
 static void mix16bBidiLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *CDA_LinAdrRev, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *audioMixL, *audioMixR;
 	int32_t CDA_LVol, CDA_RVol;
 	uint32_t pos, delta, i, samplesToMix, CDA_BytesLeft;
-#ifndef LERPMIX
-	int32_t sample3, sample4;
-#endif
 
 	GET_VOL
 
@@ -1468,12 +1441,9 @@
 static void mix16bRampNoLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *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
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -1541,12 +1511,9 @@
 static void mix16bRampLoopIntrp(voice_t *v, uint32_t numSamples)
 {
 	const int16_t *CDA_LinearAdr, *smpPtr;
-	int32_t realPos, sample, sample2, *audioMixL, *audioMixR;
+	int32_t realPos, sample, sample2, sample3, sample4, *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
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
@@ -1614,12 +1581,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;
+	int32_t realPos, sample, sample2, sample3, sample4, *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
 
 	if ((v->SLVol1 | v->SRVol1 | v->SLVol2 | v->SRVol2) == 0)
 	{
--- a/src/ft2_mix_macros.h
+++ b/src/ft2_mix_macros.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "ft2_header.h"
+#include "ft2_audio.h"
 
 /* ----------------------------------------------------------------------- */
 /*                          GENERAL MIXER MACROS                           */
@@ -14,9 +15,10 @@
 	v->SLVol2 = CDA_LVol; \
 	v->SRVol2 = CDA_RVol; \
 
+#if defined __amd64__ || defined _WIN64
+
 #define GET_MIXER_VARS \
 	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); \
@@ -25,7 +27,6 @@
 
 #define GET_MIXER_VARS_RAMP \
 	const uint32_t SFrq = v->SFrq; \
-	const uint32_t SFrqRev = v->SFrqRev; \
 	audioMixL = audio.mixBufferL; \
 	audioMixR = audio.mixBufferR; \
 	CDA_LVolIP = v->SLVolIP; \
@@ -34,6 +35,28 @@
 	realPos = v->SPos; \
 	pos = v->SPosDec; \
 
+#else
+
+#define GET_MIXER_VARS \
+	const uint32_t SFrq = v->SFrq; \
+	audioMixL = audio.mixBufferL; \
+	audioMixR = audio.mixBufferR; \
+	const bool mixInMono = (CDA_LVol == CDA_RVol); \
+	realPos = v->SPos; \
+	pos = v->SPosDec; \
+
+#define GET_MIXER_VARS_RAMP \
+	const uint32_t SFrq = v->SFrq; \
+	audioMixL = audio.mixBufferL; \
+	audioMixR = audio.mixBufferR; \
+	CDA_LVolIP = v->SLVolIP; \
+	CDA_RVolIP = v->SRVolIP; \
+	const bool mixInMono = (v->SLVol2 == v->SRVol2) && (CDA_LVolIP == CDA_RVolIP); \
+	realPos = v->SPos; \
+	pos = v->SPosDec; \
+
+#endif
+
 #define SET_BASE8 \
 	CDA_LinearAdr = v->SBase8; \
 	smpPtr = CDA_LinearAdr + realPos; \
@@ -52,14 +75,14 @@
 
 #define INC_POS \
 	pos += SFrq; \
-	smpPtr += pos >> 16; \
-	pos &= 0xFFFF; \
+	smpPtr += pos >> MIXER_FRAC_BITS; \
+	pos &= MIXER_FRAC_MASK; \
 
 #define INC_POS_BIDI \
 	pos += CDA_IPValL; \
-	smpPtr += pos >> 16; \
+	smpPtr += pos >> MIXER_FRAC_BITS; \
 	smpPtr += CDA_IPValH; \
-	pos &= 0xFFFF; \
+	pos &= MIXER_FRAC_MASK; \
 
 #define SET_BACK_MIXER_POS \
 	v->SPosDec = pos; \
@@ -101,8 +124,6 @@
 	*audioMixL++ += sample; \
 	*audioMixR++ += sample; \
 
-#ifndef LERPMIX
-
 // 4-tap cubic spline interpolation (default - slower than linear, but better quality)
 
 // in: int32_t s0,s1,s2,s3 = -128..127 | f = 0..65535 (frac) | out: 16-bit s0 (will exceed 16-bits because of overshoot)
@@ -175,84 +196,41 @@
 	*audioMixL++ += sample; \
 	*audioMixR++ += sample; \
 
-#else
-
-// 2-tap linear interpolation (like FT2 - faster, but bad quality)
-
-// in: int32_t s1,s2 = -128..127 | f = 0..65535 (frac) | out: s1 = -32768..32767
-#define INTERPOLATE8(s1, s2, f) \
-	s2 -= s1; \
-	s2 = (s2 * (int32_t)f) >> (16 - 8); \
-	s1 <<= 8; \
-	s1 += s2; \
-
-// in: int32_t s1,s2 = -32768..32767 | f = 0..65535 (frac) | out: s1 = -32768..32767
-#define INTERPOLATE16(s1, s2, f) \
-	s2 = (s2 - s1) >> 1; \
-	s2 = (s2 * (int32_t)f) >> (16 - 1); \
-	s1 += s2; \
-
-/* 8bitbubsy: It may look like we are potentially going out of bounds by looking up sample point
-** 1, but the sample data is actually padded on the right side, where a correct sample is stored
-** according to loop mode (or no loop). This is how original FT2 (MS-DOS) does it as well.
-*/
-
-#define RENDER_8BIT_SMP_INTRP \
-	assert(smpPtr >= CDA_LinearAdr && smpPtr < CDA_LinearAdr+v->SLen); \
-	sample = smpPtr[0]; \
-	sample2 = smpPtr[1]; \
-	INTERPOLATE8(sample, sample2, pos) \
-	sample <<= 12; \
-	*audioMixL++ += ((int64_t)sample * CDA_LVol) >> 32; \
-	*audioMixR++ += ((int64_t)sample * CDA_RVol) >> 32; \
-
-#define RENDER_8BIT_SMP_MONO_INTRP \
-	assert(smpPtr >= CDA_LinearAdr && smpPtr < CDA_LinearAdr+v->SLen); \
-	sample = smpPtr[0]; \
-	sample2 = smpPtr[1]; \
-	INTERPOLATE8(sample, sample2, pos) \
-	sample <<= 12; \
-	sample = ((int64_t)sample * CDA_LVol) >> 32; \
-	*audioMixL++ += sample; \
-	*audioMixR++ += sample; \
-
-#define RENDER_16BIT_SMP_INTRP \
-	assert(smpPtr >= CDA_LinearAdr && smpPtr < CDA_LinearAdr+v->SLen); \
-	sample = smpPtr[0]; \
-	sample2 = smpPtr[1]; \
-	INTERPOLATE16(sample, sample2, pos) \
-	sample <<= 12; \
-	*audioMixL++ += ((int64_t)sample * CDA_LVol) >> 32; \
-	*audioMixR++ += ((int64_t)sample * CDA_RVol) >> 32; \
-
-#define RENDER_16BIT_SMP_MONO_INTRP \
-	assert(smpPtr >= CDA_LinearAdr && smpPtr < CDA_LinearAdr+v->SLen); \
-	sample = smpPtr[0]; \
-	sample2 = smpPtr[1]; \
-	INTERPOLATE16(sample, sample2, pos) \
-	sample <<= 12; \
-	sample = ((int64_t)sample * CDA_LVol) >> 32; \
-	*audioMixL++ += sample; \
-	*audioMixR++ += sample; \
-
-#endif
-
 /* ----------------------------------------------------------------------- */
 /*                      SAMPLES-TO-MIX LIMITING MACROS                     */
 /* ----------------------------------------------------------------------- */
 
+#if defined __amd64__ || defined _WIN64
+
 #define LIMIT_MIX_NUM \
+	samplesToMix = UINT32_MAX; \
 	i = (v->SLen - 1) - realPos; \
-	if (i > 65535) \
-		i = 65535; \
 	\
-	i = (i << 16) | (pos ^ 0xFFFF); \
-	samplesToMix = ((int64_t)i * SFrqRev) >> 32; \
+	if (SFrq > i>>MIXER_FRAC_BITS) \
+	{ \
+		const uint64_t tmp64 = ((uint64_t)i << MIXER_FRAC_BITS) | (pos ^ MIXER_FRAC_MASK); \
+		samplesToMix = (uint32_t)(tmp64 / SFrq); \
+		samplesToMix++; \
+	} \
+	\
+	if (samplesToMix > CDA_BytesLeft) \
+		samplesToMix = CDA_BytesLeft; \
+
+#else
+
+#define LIMIT_MIX_NUM \
+	i = (v->SLen - 1) - realPos; \
+	if (i > (1UL << (32-MIXER_FRAC_BITS))) \
+		i = 1UL << (32-MIXER_FRAC_BITS); \
+	\
+	i = (i << MIXER_FRAC_BITS) | (pos ^ MIXER_FRAC_MASK); \
+	samplesToMix = ((int64_t)i * v->SFrqRev) >> 32; \
 	samplesToMix++; \
 	\
 	if (samplesToMix > CDA_BytesLeft) \
 		samplesToMix = CDA_BytesLeft; \
 
+#endif
 
 #define LIMIT_MIX_NUM_RAMP \
 	if (v->SVolIPLen == 0) \
@@ -302,7 +280,7 @@
 		assert(realPos >= v->SRepS && realPos < v->SLen); \
 		realPos = ~realPos; \
 		smpPtr = CDA_LinAdrRev + realPos; \
-		pos ^= 0xFFFF; \
+		pos ^= MIXER_FRAC_MASK; \
 	} \
 	else \
 	{ \
@@ -311,13 +289,13 @@
 		smpPtr = CDA_LinearAdr + realPos; \
 	} \
 	\
-	const int32_t CDA_IPValH = (int32_t)delta >> 16; \
-	const int32_t CDA_IPValL = delta & 0xFFFF; \
+	const int32_t CDA_IPValH = (int32_t)delta >> MIXER_FRAC_BITS; \
+	const int32_t CDA_IPValL = delta & MIXER_FRAC_MASK; \
 
 #define END_BIDI \
 	if (v->backwards) \
 	{ \
-		pos ^= 0xFFFF; \
+		pos ^= MIXER_FRAC_MASK; \
 		realPos = ~(int32_t)(smpPtr - CDA_LinAdrRev); \
 	} \
 	else \
@@ -330,12 +308,17 @@
 /*                       VOLUME=0 OPTIMIZATION MACROS                      */
 /* ----------------------------------------------------------------------- */
 
-#define VOL0_OPTIMIZATION_NO_LOOP \
-	assert(numSamples <= 65536); \
+#define	VOL0_INC_POS \
+	const uint64_t newPos = (uint64_t)v->SFrq * numSamples; \
+	const uint32_t addPos = (uint32_t)(newPos >> MIXER_FRAC_BITS); \
+	uint32_t addFrac = (uint32_t)(newPos & MIXER_FRAC_MASK); \
 	\
-	pos = v->SPosDec + ((v->SFrq & 0xFFFF) * numSamples); \
-	realPos = v->SPos + ((v->SFrq >> 16) * numSamples) + (pos >> 16); \
-	\
+	addFrac += v->SPosDec; \
+	realPos = v->SPos + addPos + (addFrac >> MIXER_FRAC_BITS); \
+	pos = addFrac & MIXER_FRAC_MASK; \
+
+#define VOL0_OPTIMIZATION_NO_LOOP \
+	VOL0_INC_POS \
 	if (realPos >= v->SLen) \
 	{ \
 		v->mixRoutine = NULL; /* shut down voice */ \
@@ -342,27 +325,17 @@
 		return; \
 	} \
 	\
-	pos &= 0xFFFF; \
 	SET_BACK_MIXER_POS
 
 #define VOL0_OPTIMIZATION_LOOP \
-	assert(numSamples <= 65536); \
-	\
-	pos = v->SPosDec + ((v->SFrq & 0xFFFF) * numSamples); \
-	realPos = v->SPos + ((v->SFrq >> 16) * numSamples) + (pos >> 16); \
-	\
+	VOL0_INC_POS \
 	while (realPos >= v->SLen) \
 		realPos -= v->SRepL; \
 	\
-	pos &= 0xFFFF; \
 	SET_BACK_MIXER_POS
 
 #define VOL0_OPTIMIZATION_BIDI_LOOP \
-	assert(numSamples <= 65536); \
-	\
-	pos = v->SPosDec + ((v->SFrq & 0xFFFF) * numSamples); \
-	realPos = v->SPos + ((v->SFrq >> 16) * numSamples) + (pos >> 16); \
-	\
+	VOL0_INC_POS \
 	while (realPos >= v->SLen) \
 	{ \
 		realPos -= v->SRepL; \
@@ -369,5 +342,4 @@
 		v->backwards ^= 1; \
 	} \
 	\
-	pos &= 0xFFFF; \
 	SET_BACK_MIXER_POS
--- a/src/ft2_radiobuttons.c
+++ b/src/ft2_radiobuttons.c
@@ -85,13 +85,8 @@
 
 	// audio output frequency
 	//x,   y,   w,  group,                      funcOnUp
-#ifdef __APPLE__
-	{ 509, 16, 121, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio44kHz },
-	{ 509, 30,  66, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio48kHz },
-#else
 	{ 509, 16,  66, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio44kHz },
 	{ 509, 30, 121, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio48kHz },
-#endif
 	{ 509, 44,  66, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio96kHz },
 
 	// audio input frequency
--- a/src/ft2_replayer.c
+++ b/src/ft2_replayer.c
@@ -26,8 +26,9 @@
 */
 
 static bool bxxOverflow;
-static int32_t oldPeriod, oldRate;
-static uint32_t frequenceDivFactor, frequenceMulFactor;
+static int32_t oldPeriod;
+static uint32_t period2DeltaTab[768][32], oldDelta;
+static double dAmigaPeriodDiv;
 static tonTyp nilPatternLine;
 
 // globally accessed
@@ -320,68 +321,78 @@
 	}
 }
 
-void calcReplayRate(int32_t rate) // 100% FT2-accurate routine, do not touch!
+void calcReplayRate(int32_t rate)
 {
 	if (rate == 0)
 		return;
 
-	// 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;
+	const double dRateFactor = (double)MIXER_FRAC_SCALE / rate;
 
-	// the following are non-FT2 calculations
+	// generate period-to-delta table
+	const double dMul = dRateFactor * (8363.0 * 256.0);
+	for (int32_t i = 0; i < 768; i++)
+	{
+		const double dHz = exp2(i * (1.0 / 768.0)) * dMul;
+		for (int32_t j = 0; j < 32; j++)
+		{
+			const double dOut = dHz * exp2(-j);
+			period2DeltaTab[i][j] = (int32_t)(dOut + 0.5);
+		}
+	}
+
+	dAmigaPeriodDiv = dRateFactor * (8363.0 * 1712.0);
+
+	audio.quickVolSizeVal = rate / 200; // FT2 truncates here
 	audio.rampQuickVolMul = (int32_t)round((UINT32_MAX + 1.0) / audio.quickVolSizeVal);
 	audio.dSpeedValMul = editor.dPerfFreq / rate; // for audio/video sync
 
-	const uint32_t deltaBase = frequenceDivFactor / (1712 * 16); // exact 16.16 delta base
-	audio.dPianoDeltaMul = 1.0 / deltaBase; // for piano in Instr. Ed.
+	// exact integer fixed-point delta base for piano in Instr. Ed.
+	int32_t deltaBase = (int32_t)round(dAmigaPeriodDiv / (1712 * 16));
+	audio.dPianoDeltaMul = 1.0 / deltaBase;
 }
 
-// 100% FT2-accurate routine, do not touch!
 uint32_t getFrequenceValue(uint16_t period)
 {
-	uint8_t shift;
-	uint16_t index;
-	int32_t indexQuotient, indexRemainder;
-	uint32_t rate;
+	uint32_t delta;
 
 	if (period == 0)
 		return 0;
 
 	if (period == oldPeriod)
-		return oldRate; // added check: prevent this calculation if it would yield the same
+		return oldDelta; // we have already calculated this delta
 
 	if (linearFrqTab)
 	{
-		index = (12 * 192 * 4) - period;
-		indexQuotient = index / 768;
-		indexRemainder = index % 768;
+		const uint16_t invPeriod = (12 * 192 * 4) - period; // this intentionally overflows uint16_t to be accurate to FT2
 
-		rate = ((int64_t)logTab[indexRemainder] * frequenceMulFactor) >> LOG_TABLE_BITS;
+		const int32_t quotient = invPeriod / 768;
+		const int32_t remainder = invPeriod % 768;
+		
+		const int32_t octave = (14 - quotient) & 0x1F; // this is accurate to FT2 (it can go crazy on very high periods)
 
-		shift = (14 - indexQuotient) & 0x1F;
-		if (shift != 0)
-			rate >>= shift;
+		delta = period2DeltaTab[remainder][octave];
 	}
 	else
 	{
-		rate = frequenceDivFactor / period;
+		const double dHz = dAmigaPeriodDiv / period;
+		delta = (int32_t)(dHz + 0.5); // rounded (don't cast to uint32_t as it will avoid SSE2 usage, and delta is <= 2^31 anyway)
 	}
 
 	oldPeriod = period;
-	oldRate = rate;
+	oldDelta = delta;
 
-	return rate;
+	return delta;
 }
 
 void resetCachedFrequencyVars(void)
 {
 	oldPeriod = -1;
-	oldRate = 0;
+	oldDelta = 0;
 
 	resetCachedScopeVars();
+#if !defined __amd64__ && !defined _WIN64
 	resetCachedMixerVars();
+#endif
 }
 
 static void startTone(uint8_t ton, uint8_t effTyp, uint8_t eff, stmTyp *ch)
--- a/src/ft2_replayer.h
+++ b/src/ft2_replayer.h
@@ -166,10 +166,7 @@
 	bool fixed;
 	int8_t fine, relTon, *pek, *origPek;
 	uint8_t vol, typ, pan;
-	int16_t fixedSmp1;
-#ifndef LERPMIX
-	int16_t fixedSmp2;
-#endif
+	int16_t fixedSmp1, fixedSmp2;
 	int32_t fixedPos, len, repS, repL;
 } sampleTyp;
 
--- a/src/ft2_sample_ed.c
+++ b/src/ft2_sample_ed.c
@@ -81,9 +81,7 @@
 			// write new values
 			ptr16[-1] = 0;
 			ptr16[len+0] = 0;
-#ifndef LERPMIX
 			ptr16[len+1] = 0;
-#endif
 		}
 		else
 		{
@@ -93,9 +91,7 @@
 			// write new values
 			s->pek[-1] = 0;
 			s->pek[len+0] = 0;
-#ifndef LERPMIX
 			s->pek[len+1] = 0;
-#endif
 		}
 
 		return;
@@ -123,17 +119,14 @@
 			// store old fix position and old values
 			s->fixedPos = s->repS + s->repL;
 			s->fixedSmp1 = ptr16[loopEnd+0];
-#ifndef LERPMIX
 			s->fixedSmp2 = ptr16[loopEnd+1];
-#endif
+
 			// write new values
 			ptr16[loopEnd+0] = ptr16[loopStart+0];
-#ifndef LERPMIX
 			if (loopStart == 0 && loopEnd > 0)
 				ptr16[-1] = ptr16[loopEnd-1];
 
 			ptr16[loopEnd+1] = ptr16[loopStart+1];
-#endif
 		}
 		else
 		{
@@ -148,17 +141,14 @@
 			// store old fix position and old values
 			s->fixedPos = loopEnd;
 			s->fixedSmp1 = s->pek[loopEnd+0];
-#ifndef LERPMIX
 			s->fixedSmp2 = s->pek[loopEnd+1];
-#endif
+
 			// write new values
 			s->pek[loopEnd+0] = s->pek[loopStart+0];
-#ifndef LERPMIX
 			if (loopStart == 0 && loopEnd > 0)
 				s->pek[-1] = s->pek[loopEnd-1];
 
 			s->pek[loopEnd+1] = s->pek[loopStart+1];
-#endif
 		}
 	}
 	else
@@ -181,12 +171,10 @@
 			// store old fix position and old values
 			s->fixedPos = s->repS + s->repL;
 			s->fixedSmp1 = ptr16[loopEnd+0];
-#ifndef LERPMIX
 			s->fixedSmp2 = ptr16[loopEnd+1];
-#endif
+
 			// write new values
 			ptr16[loopEnd+0] = ptr16[loopEnd-1];
-#ifndef LERPMIX
 			if (loopStart == 0)
 				ptr16[-1] = ptr16[0];
 
@@ -194,7 +182,6 @@
 				ptr16[loopEnd+1] = ptr16[loopEnd-2];
 			else
 				ptr16[loopEnd+1] = ptr16[loopStart+0];
-#endif
 		}
 		else
 		{
@@ -211,12 +198,10 @@
 			// store old fix position and old values
 			s->fixedPos = loopEnd;
 			s->fixedSmp1 = s->pek[loopEnd+0];
-#ifndef LERPMIX
 			s->fixedSmp2 = s->pek[loopEnd+1];
-#endif
+
 			// write new values
 			s->pek[loopEnd+0] = s->pek[loopEnd-1];
-#ifndef LERPMIX
 			if (loopStart == 0)
 				s->pek[-1] = s->pek[0];
 
@@ -224,7 +209,6 @@
 				s->pek[loopEnd+1] = s->pek[loopEnd-2];
 			else
 				s->pek[loopEnd+1] = s->pek[loopStart+0];
-#endif
 		}
 	}
 
@@ -258,9 +242,7 @@
 		fixedPos16 = s->fixedPos >> 1;
 
 		ptr16[fixedPos16+0] = s->fixedSmp1;
-#ifndef LERPMIX
 		ptr16[fixedPos16+1] = s->fixedSmp2;
-#endif
 	}
 	else
 	{
@@ -267,9 +249,7 @@
 		// 8-bit sample
 
 		s->pek[s->fixedPos+0] = (int8_t)s->fixedSmp1;
-#ifndef LERPMIX
 		s->pek[s->fixedPos+1] = (int8_t)s->fixedSmp2;
-#endif
 	}
 }
 
@@ -646,10 +626,8 @@
 		{
 			if (index == s->fixedPos)
 				tmp32 = s->fixedSmp1;
-#ifndef LERPMIX
 			else if (index == s->fixedPos+2)
 				tmp32 = s->fixedSmp2;
-#endif
 			else
 				tmp32 = ptr16[index >> 1];
 		}
@@ -669,10 +647,8 @@
 		{
 			if (index == s->fixedPos)
 				tmp32 = s->fixedSmp1;
-#ifndef LERPMIX
 			else if (index == s->fixedPos+1)
 				tmp32 = s->fixedSmp2;
-#endif
 			else
 				tmp32 = ptr8[index];
 		}
--- a/src/ft2_sample_saver.c
+++ b/src/ft2_sample_saver.c
@@ -72,13 +72,11 @@
 			fwrite(&smp->fixedSmp1, sizeof (int16_t), 1, f);
 		}
 
-#ifndef LERPMIX
 		if (smp->fixedPos+2 < smp->len/2)
 		{
 			fseek(f, sampleDataOffset + ((smp->fixedPos + 2) * 2), SEEK_SET);
 			fwrite(&smp->fixedSmp2, sizeof (int16_t), 1, f);
 		}
-#endif
 	}
 	else
 	{
@@ -94,7 +92,6 @@
 			fwrite(&fixSpar8, sizeof (int8_t), 1, f);
 		}
 
-#ifndef LERPMIX
 		if (smp->fixedPos+1 < smp->len)
 		{
 			fseek(f, sampleDataOffset + (smp->fixedPos + 1), SEEK_SET);
@@ -105,7 +102,6 @@
 
 			fwrite(&fixSpar8, sizeof (int8_t), 1, f);
 		}
-#endif
 	}
 
 	fclose(f);
--- a/src/ft2_sampling.c
+++ b/src/ft2_sampling.c
@@ -370,14 +370,8 @@
 	switch (config.audioInputFreq)
 	{
 		case INPUT_FREQ_96KHZ: samplingRate = 96000; break;
-
-#ifdef __APPLE__
-		case INPUT_FREQ_48KHZ: samplingRate = 48000; break;
-		default: samplingRate = 44100; break;
-#else
 		case INPUT_FREQ_44KHZ: samplingRate = 44100; break;
 		default: samplingRate = 48000; break;
-#endif
 	}
 
 	memset(&want, 0, sizeof (SDL_AudioSpec));
--- a/src/ft2_scopes.h
+++ b/src/ft2_scopes.h
@@ -3,11 +3,12 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include "ft2_header.h"
+#include "ft2_audio.h"
 
-// log2(65536 / SCOPE_HZ) where SCOPE_HZ is 2^n
-#define SCOPE_FRAC_BITS 22
+// 6 = log2(SCOPE_HZ) where SCOPE_HZ is 2^n
+#define SCOPE_FRAC_BITS (MIXER_FRAC_BITS+6)
 
-#define SCOPE_FRAC_SCALE (1UL << SCOPE_FRAC_BITS)
+#define SCOPE_FRAC_SCALE (1L << SCOPE_FRAC_BITS)
 #define SCOPE_FRAC_MASK (SCOPE_FRAC_SCALE-1)
 
 void resetCachedScopeVars(void);
--- a/src/ft2_tables.c
+++ b/src/ft2_tables.c
@@ -311,106 +311,6 @@
 	   // the last 17 values are off (but identical to FT2) because of a bug in how FT2 calculates this table
 };
 
-const uint32_t logTab[768] = // bit-exact to FT2 table
-{
-	16777216, 16792365, 16807527, 16822704, 16837894, 16853097, 16868315, 16883546,
-	16898791, 16914049, 16929322, 16944608, 16959908, 16975222, 16990549, 17005891,
-	17021246, 17036615, 17051999, 17067396, 17082806, 17098231, 17113670, 17129123,
-	17144589, 17160070, 17175564, 17191073, 17206595, 17222132, 17237683, 17253247,
-	17268826, 17284419, 17300026, 17315646, 17331282, 17346931, 17362594, 17378271,
-	17393963, 17409669, 17425389, 17441123, 17456871, 17472634, 17488410, 17504202,
-	17520007, 17535826, 17551660, 17567508, 17583371, 17599248, 17615139, 17631044,
-	17646964, 17662898, 17678847, 17694810, 17710787, 17726779, 17742785, 17758806,
-	17774841, 17790891, 17806955, 17823034, 17839127, 17855235, 17871357, 17887494,
-	17903645, 17919811, 17935992, 17952187, 17968397, 17984621, 18000860, 18017114,
-	18033382, 18049665, 18065963, 18082276, 18098603, 18114945, 18131302, 18147673,
-	18164060, 18180461, 18196877, 18213307, 18229753, 18246213, 18262689, 18279179,
-	18295684, 18312204, 18328739, 18345288, 18361853, 18378433, 18395028, 18411637,
-	18428262, 18444902, 18461556, 18478226, 18494911, 18511611, 18528325, 18545056,
-	18561801, 18578561, 18595336, 18612127, 18628932, 18645753, 18662589, 18679441,
-	18696307, 18713189, 18730086, 18746998, 18763925, 18780868, 18797826, 18814800,
-	18831788, 18848792, 18865812, 18882846, 18899897, 18916962, 18934043, 18951139,
-	18968251, 18985378, 19002521, 19019679, 19036853, 19054042, 19071247, 19088467,
-	19105703, 19122954, 19140221, 19157504, 19174802, 19192116, 19209445, 19226790,
-	19244151, 19261527, 19278919, 19296327, 19313750, 19331190, 19348645, 19366115,
-	19383602, 19401104, 19418622, 19436156, 19453706, 19471271, 19488853, 19506450,
-	19524063, 19541692, 19559337, 19576998, 19594675, 19612368, 19630077, 19647802,
-	19665543, 19683300, 19701072, 19718861, 19736666, 19754488, 19772325, 19790178,
-	19808047, 19825933, 19843835, 19861752, 19879686, 19897637, 19915603, 19933586,
-	19951585, 19969600, 19987631, 20005679, 20023743, 20041823, 20059920, 20078033,
-	20096162, 20114308, 20132470, 20150648, 20168843, 20187054, 20205282, 20223526,
-	20241787, 20260064, 20278358, 20296668, 20314995, 20333338, 20351698, 20370074,
-	20388467, 20406877, 20425303, 20443746, 20462206, 20480682, 20499175, 20517684,
-	20536211, 20554754, 20573313, 20591890, 20610483, 20629093, 20647720, 20666364,
-	20685025, 20703702, 20722396, 20741107, 20759835, 20778580, 20797342, 20816121,
-	20834917, 20853729, 20872559, 20891406, 20910270, 20929150, 20948048, 20966963,
-	20985895, 21004844, 21023810, 21042794, 21061794, 21080812, 21099846, 21118898,
-	21137968, 21157054, 21176158, 21195278, 21214417, 21233572, 21252745, 21271935,
-	21291142, 21310367, 21329609, 21348868, 21368145, 21387439, 21406751, 21426080,
-	21445426, 21464790, 21484172, 21503571, 21522987, 21542421, 21561873, 21581342,
-	21600829, 21620333, 21639855, 21659395, 21678952, 21698527, 21718119, 21737729,
-	21757357, 21777003, 21796666, 21816348, 21836046, 21855763, 21875498, 21895250,
-	21915020, 21934808, 21954614, 21974438, 21994279, 22014139, 22034016, 22053912,
-	22073825, 22093757, 22113706, 22133674, 22153659, 22173663, 22193684, 22213724,
-	22233781, 22253857, 22273951, 22294063, 22314194, 22334342, 22354509, 22374693,
-	22394897, 22415118, 22435357, 22455615, 22475891, 22496186, 22516499, 22536830,
-	22557179, 22577547, 22597933, 22618338, 22638761, 22659202, 22679662, 22700141,
-	22720638, 22741153, 22761687, 22782240, 22802811, 22823400, 22844009, 22864635,
-	22885281, 22905945, 22926628, 22947329, 22968049, 22988788, 23009546, 23030322,
-	23051117, 23071931, 23092764, 23113615, 23134485, 23155374, 23176282, 23197209,
-	23218155, 23239120, 23260103, 23281106, 23302127, 23323168, 23344227, 23365306,
-	23386403, 23407520, 23428656, 23449810, 23470984, 23492177, 23513389, 23534620,
-	23555871, 23577140, 23598429, 23619737, 23641065, 23662411, 23683777, 23705162,
-	23726566, 23747990, 23769433, 23790896, 23812377, 23833879, 23855399, 23876939,
-	23898499, 23920078, 23941676, 23963294, 23984932, 24006589, 24028265, 24049962,
-	24071677, 24093413, 24115168, 24136942, 24158736, 24180550, 24202384, 24224237,
-	24246111, 24268003, 24289916, 24311848, 24333801, 24355773, 24377765, 24399776,
-	24421808, 24443859, 24465931, 24488022, 24510133, 24532265, 24554416, 24576587,
-	24598778, 24620990, 24643221, 24665472, 24687744, 24710036, 24732347, 24754679,
-	24777031, 24799403, 24821796, 24844209, 24866641, 24889095, 24911568, 24934062,
-	24956576, 24979110, 25001665, 25024240, 25046835, 25069451, 25092088, 25114744,
-	25137421, 25160119, 25182837, 25205576, 25228335, 25251115, 25273915, 25296736,
-	25319578, 25342440, 25365322, 25388226, 25411150, 25434095, 25457060, 25480047,
-	25503054, 25526081, 25549130, 25572199, 25595290, 25618401, 25641533, 25664686,
-	25687859, 25711054, 25734270, 25757506, 25780764, 25804042, 25827342, 25850662,
-	25874004, 25897367, 25920751, 25944156, 25967582, 25991029, 26014497, 26037987,
-	26061498, 26085030, 26108583, 26132158, 26155754, 26179371, 26203009, 26226669,
-	26250350, 26274053, 26297777, 26321522, 26345289, 26369077, 26392887, 26416718,
-	26440571, 26464445, 26488341, 26512259, 26536198, 26560158, 26584141, 26608145,
-	26632170, 26656218, 26680287, 26704377, 26728490, 26752624, 26776780, 26800958,
-	26825158, 26849380, 26873623, 26897888, 26922176, 26946485, 26970816, 26995169,
-	27019544, 27043941, 27068360, 27092802, 27117265, 27141750, 27166258, 27190787,
-	27215339, 27239913, 27264509, 27289127, 27313768, 27338430, 27363116, 27387823,
-	27412552, 27437304, 27462079, 27486875, 27511695, 27536536, 27561400, 27586286,
-	27611195, 27636126, 27661080, 27686057, 27711056, 27736077, 27761121, 27786188,
-	27811277, 27836389, 27861524, 27886681, 27911861, 27937064, 27962290, 27987538,
-	28012809, 28038103, 28063420, 28088760, 28114122, 28139508, 28164916, 28190347,
-	28215802, 28241279, 28266779, 28292302, 28317849, 28343418, 28369011, 28394626,
-	28420265, 28445927, 28471612, 28497320, 28523052, 28548806, 28574584, 28600385,
-	28626210, 28652058, 28677929, 28703823, 28729741, 28755683, 28781647, 28807636,
-	28833647, 28859682, 28885741, 28911823, 28937929, 28964058, 28990211, 29016388,
-	29042588, 29068811, 29095059, 29121330, 29147625, 29173944, 29200286, 29226652,
-	29253042, 29279456, 29305894, 29332355, 29358841, 29385350, 29411883, 29438441,
-	29465022, 29491627, 29518256, 29544910, 29571587, 29598288, 29625014, 29651764,
-	29678538, 29705336, 29732158, 29759004, 29785875, 29812770, 29839689, 29866633,
-	29893600, 29920593, 29947609, 29974650, 30001716, 30028805, 30055920, 30083059,
-	30110222, 30137410, 30164622, 30191859, 30219120, 30246407, 30273717, 30301053,
-	30328413, 30355798, 30383207, 30410642, 30438101, 30465584, 30493093, 30520627,
-	30548185, 30575768, 30603377, 30631010, 30658668, 30686351, 30714059, 30741792,
-	30769550, 30797333, 30825141, 30852975, 30880833, 30908717, 30936625, 30964559,
-	30992519, 31020503, 31048513, 31076548, 31104608, 31132694, 31160805, 31188941,
-	31217103, 31245290, 31273503, 31301741, 31330005, 31358294, 31386609, 31414949,
-	31443315, 31471707, 31500124, 31528567, 31557035, 31585529, 31614049, 31642595,
-	31671166, 31699764, 31728387, 31757036, 31785710, 31814411, 31843138, 31871890,
-	31900669, 31929473, 31958304, 31987160, 32016043, 32044951, 32073886, 32102847,
-	32131834, 32160847, 32189887, 32218952, 32248044, 32277162, 32306307, 32335478,
-	32364675, 32393898, 32423148, 32452424, 32481727, 32511056, 32540412, 32569794,
-	32599202, 32628638, 32658099, 32687588, 32717103, 32746645, 32776213, 32805808,
-	32835430, 32865078, 32894754, 32924456, 32954184, 32983940, 33013723, 33043532,
-	33073369, 33103232, 33133122, 33163040, 33192984, 33222955, 33252954, 33282979,
-	33313032, 33343112, 33373219, 33403353, 33433514, 33463703, 33493919, 33524162
-};
-
 /* ----------------------------------------------------------------------- */
 /*                           AUDIO MIXER TABLES                            */
 /* ----------------------------------------------------------------------- */
--- a/src/ft2_tables.h
+++ b/src/ft2_tables.h
@@ -6,8 +6,6 @@
 #include "ft2_header.h" // MAX_VOICES
 #include "ft2_config.h" // CONFIG_FILE_SIZE
 
-#define LOG_TABLE_BITS 24
-
 #define KEY2VOL_ENTRIES (signed)(sizeof (key2VolTab) / sizeof (SDL_Keycode))
 #define KEY2EFX_ENTRIES (signed)(sizeof (key2EfxTab) / sizeof (SDL_Keycode))
 #define KEY2HEX_ENTRIES (signed)(sizeof (key2HexTab) / sizeof (SDL_Keycode))
@@ -18,7 +16,6 @@
 extern const uint16_t amigaFinePeriod[12 * 8];
 extern const int16_t linearPeriods[1936];
 extern const int16_t amigaPeriods[1936];
-extern const uint32_t logTab[768];
 
 extern const uint32_t panningTab[257];
 
--- a/src/ft2_trim.c
+++ b/src/ft2_trim.c
@@ -31,7 +31,7 @@
 
 static void freeTmpInstruments(void)
 {
-	for (int16_t i = 0; i <= MAX_INST; i++)
+	for (int32_t i = 0; i <= MAX_INST; i++)
 	{
 		if (tmpInstr[i] != NULL)
 		{
@@ -47,7 +47,7 @@
 {
 	freeTmpInstruments();
 
-	for (int16_t i = 0; i <= MAX_INST; i++)
+	for (int32_t i = 0; i <= MAX_INST; i++)
 	{
 		if (instr[i] != NULL)
 		{
@@ -58,7 +58,7 @@
 				return false;
 			}
 
-			tmpInstr[i] = instr[i];
+			*tmpInstr[i] = *instr[i];
 		}
 	}
 
--- a/src/ft2_video.c
+++ b/src/ft2_video.c
@@ -953,7 +953,7 @@
 		return false;
 	}
 
-#ifdef __APPLE__ // for macOS we need to do this here for reasons I can't be bothered to explain
+#ifdef __APPLE__ // for macOS we need to do this here for reasons I have forgotten
 	SDL_PumpEvents();
 	SDL_ShowWindow(video.window);
 #endif