shithub: ft²

Download patch

ref: cf882314685613d8ede6f8c3ac27b1af7186871c
parent: f2f8ebf77b23d54ce91915df7dd4ae9dd938382b
parent: 4f7f08a867b7e448ce9580279134f4cf7ff82d03
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Apr 14 04:05:46 EDT 2021

Merge remote-tracking branch 'upstream/master'

--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@
 *.db-wal
 *.recipe
 vs2019_project/ft2-clone/Release/ft2-clone-win64.iobj
+vs2019_project/ft2-clone/Release/ft2-clone-win32.iobj
--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -20,6 +20,11 @@
 #include "mixer/ft2_silence_mix.h"
 // --------------------------------
 
+// hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
 #define INITIAL_DITHER_SEED 0x12345000
 
 static int8_t pmpCountDiv, pmpChannels = 2;
@@ -87,14 +92,7 @@
 				audio.currOutputDevice = NULL;
 			}
 
-			const uint32_t stringLen = (uint32_t)strlen(audio.lastWorkingAudioDeviceName);
-
-			audio.currOutputDevice = (char *)malloc(stringLen + 2);
-			if (audio.currOutputDevice != NULL)
-			{
-				strcpy(audio.currOutputDevice, audio.lastWorkingAudioDeviceName);
-				audio.currOutputDevice[stringLen + 1] = '\0'; // UTF-8 needs double null termination
-			}
+			audio.currOutputDevice = strdup(audio.lastWorkingAudioDeviceName);
 		}
 
 		// also update config audio radio buttons if we're on that screen at the moment
@@ -1050,17 +1048,7 @@
 	}
 
 	if (audio.currOutputDevice != NULL)
-	{
-		const uint32_t stringLen = (uint32_t)strlen(audio.currOutputDevice);
-
-		audio.lastWorkingAudioDeviceName = (char *)malloc(stringLen + 2);
-		if (audio.lastWorkingAudioDeviceName != NULL)
-		{
-			if (stringLen > 0)
-				strcpy(audio.lastWorkingAudioDeviceName, audio.currOutputDevice);
-			audio.lastWorkingAudioDeviceName[stringLen + 1] = '\0'; // UTF-8 needs double null termination
-		}
-	}
+		audio.lastWorkingAudioDeviceName = strdup(audio.currOutputDevice);
 }
 
 bool setupAudio(bool showErrorMsg)
--- a/src/ft2_audioselector.c
+++ b/src/ft2_audioselector.c
@@ -13,44 +13,75 @@
 #include "ft2_audioselector.h"
 #include "ft2_structs.h"
 
-char *getAudioOutputDeviceFromConfig(void)
+enum
 {
+	INPUT_DEVICE = 0,
+	OUTPUT_DEVICE = 1
+};
+
 #define MAX_DEV_STR_LEN 256
 
-	char *devString = (char *)calloc(MAX_DEV_STR_LEN + 1, sizeof (char));
-	if (devString == NULL)
+// hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+static char *getReasonableAudioDevice(int32_t iscapture) // can and will return NULL
+{
+	int32_t numAudioDevs = SDL_GetNumAudioDevices(iscapture);
+	if (numAudioDevs == 0 || numAudioDevs > 1)
+		return NULL; // we don't know which audio output device is the default device
+
+	const char *devName = SDL_GetAudioDeviceName(0, iscapture);
+	if (devName == NULL)
 		return NULL;
 
-	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocation, "r");
-	if (f == NULL)
+	return strdup(devName);
+}
+
+char *getAudioOutputDeviceFromConfig(void)
+{
+	bool audioDeviceRead = false;
+	char *devString = NULL;
+
+	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "r");
+	if (f != NULL)
 	{
-		const char *devStringTmp = SDL_GetAudioDeviceName(0, false);
-		if (devStringTmp == NULL)
+		devString = (char *)malloc(MAX_DEV_STR_LEN+1);
+		if (devString == NULL)
 		{
-			free(devString);
-			return NULL;
+			fclose(f);
+			return NULL; // out of memory
 		}
 
-		const uint32_t devStringLen = (uint32_t)strlen(devStringTmp);
+		devString[0] = '\0';
+		fgets(devString, MAX_DEV_STR_LEN, f);
+		fclose(f);
+
+		const int32_t devStringLen = (int32_t)strlen(devString);
 		if (devStringLen > 0)
-			strncpy(devString, devStringTmp, MAX_DEV_STR_LEN);
-		devString[devStringLen+1] = '\0'; // UTF-8 needs double null termination
+		{
+			if (devString[devStringLen-1] == '\n')
+				devString[devStringLen-1] = '\0';
+
+			if (!(devStringLen == 1 && devString[0] == ' ')) // space only = no device
+				audioDeviceRead = true;
+		}
 	}
-	else
+
+	if (!audioDeviceRead)
 	{
-		if (fgets(devString, MAX_DEV_STR_LEN, f) == NULL)
-		{
+		if (devString != NULL)
 			free(devString);
-			fclose(f);
-			return NULL;
-		}
 
-		const uint32_t devStringLen = (uint32_t)strlen(devString);
-		if (devString[devStringLen-1] == '\n')
-			devString[devStringLen-1]  = '\0';
-		devString[devStringLen+1] = '\0'; // UTF-8 needs double null termination
+		devString = getReasonableAudioDevice(OUTPUT_DEVICE);
+	}
 
-		fclose(f);
+	// SDL_OpenAudioDevice() doesn't seem to like an empty audio device string
+	if (devString != NULL && devString[0] == '\0')
+	{
+		free(devString);
+		return NULL;
 	}
 
 	return devString;
@@ -58,50 +89,48 @@
 
 char *getAudioInputDeviceFromConfig(void)
 {
-#define MAX_DEV_STR_LEN 256
+	bool audioDeviceRead = false;
+	char *devString = NULL;
 
-	char *devString = (char *)calloc(MAX_DEV_STR_LEN + 1, sizeof (char));
-	if (devString == NULL)
-		return NULL;
-
-	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocation, "r");
-	if (f == NULL)
+	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "r");
+	if (f != NULL)
 	{
-		const char *devStringTmp = SDL_GetAudioDeviceName(0, true);
-		if (devStringTmp == NULL)
+		devString = (char *)malloc(MAX_DEV_STR_LEN+1);
+		if (devString == NULL)
 		{
-			free(devString);
-			return NULL;
+			fclose(f);
+			return NULL; // out of memory
 		}
 
-		const uint32_t devStringLen = (uint32_t)strlen(devStringTmp);
+		devString[0] = '\0';
+		fgets(devString, MAX_DEV_STR_LEN, f); // skip first line (we want the input device)
+		fgets(devString, MAX_DEV_STR_LEN, f);
+		fclose(f);
+
+		const int32_t devStringLen = (int32_t)strlen(devString);
 		if (devStringLen > 0)
-			strncpy(devString, devStringTmp, MAX_DEV_STR_LEN);
-		devString[devStringLen+1] = '\0'; // UTF-8 needs double null termination
-	}
-	else
-	{
-		if (fgets(devString, MAX_DEV_STR_LEN, f) == NULL)
 		{
-			free(devString);
-			fclose(f);
-			return NULL;
+			if (devString[devStringLen-1] == '\n')
+				devString[devStringLen-1] = '\0';
+
+			if (!(devStringLen == 1 && devString[0] == ' ')) // space only = no device
+				audioDeviceRead = true;
 		}
+	}
 
-		// do it one more time (next line)
-		if (fgets(devString, MAX_DEV_STR_LEN, f) == NULL)
-		{
+	if (!audioDeviceRead)
+	{
+		if (devString != NULL)
 			free(devString);
-			fclose(f);
-			return NULL;
-		}
 
-		const uint32_t devStringLen = (uint32_t)strlen(devString);
-		if (devString[devStringLen-1] == '\n')
-			devString[devStringLen-1]  = '\0';
-		devString[devStringLen+1] = '\0'; // UTF-8 needs double null termination
+		devString = getReasonableAudioDevice(INPUT_DEVICE);
+	}
 
-		fclose(f);
+	// SDL_OpenAudioDevice() doesn't seem to like an empty audio device string
+	if (devString != NULL && devString[0] == '\0')
+	{
+		free(devString);
+		return NULL;
 	}
 
 	return devString;
@@ -109,15 +138,21 @@
 
 bool saveAudioDevicesToConfig(const char *outputDevice, const char *inputDevice)
 {
-	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocation, "w");
+	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "w");
 	if (f == NULL)
 		return false;
 
 	if (outputDevice != NULL)
 		fputs(outputDevice, f);
+	else
+		fputc(' ', f);
+
 	fputc('\n', f);
+
 	if (inputDevice != NULL)
 		fputs(inputDevice, f);
+	else
+		fputc(' ', f);
 
 	fclose(f);
 	return true;
@@ -222,13 +257,14 @@
 
 			const uint32_t devStringLen = (uint32_t)strlen(devString);
 
-			audio.currOutputDevice = (char *)malloc(devStringLen + 2);
+			audio.currOutputDevice = (char *)malloc(devStringLen+1);
 			if (audio.currOutputDevice == NULL)
 				return true;
 
+			audio.currOutputDevice[0] = '\0';
+
 			if (devStringLen > 0)
 				strcpy(audio.currOutputDevice, devString);
-			audio.currOutputDevice[devStringLen+1] = '\0'; // UTF-8 needs double null termination
 
 			if (!setNewAudioSettings())
 				okBox(0, "System message", "Couldn't open audio input device!");
@@ -254,13 +290,14 @@
 
 			const uint32_t devStringLen = (uint32_t)strlen(devString);
 
-			audio.currInputDevice = (char *)malloc(devStringLen + 2);
+			audio.currInputDevice = (char *)malloc(devStringLen+1);
 			if (audio.currInputDevice == NULL)
 				return true;
 
+			audio.currInputDevice[0] = '\0';
+
 			if (devStringLen > 0)
 				strcpy(audio.currInputDevice, devString);
-			audio.currInputDevice[devStringLen+1] = '\0'; // UTF-8 needs double null termination
 
 			drawAudioInputList();
 		}
@@ -294,10 +331,10 @@
 
 void freeAudioDeviceSelectorBuffers(void)
 {
-	if (editor.audioDevConfigFileLocation != NULL)
+	if (editor.audioDevConfigFileLocationU != NULL)
 	{
-		free(editor.audioDevConfigFileLocation);
-		editor.audioDevConfigFileLocation = NULL;
+		free(editor.audioDevConfigFileLocationU);
+		editor.audioDevConfigFileLocationU = NULL;
 	}
 
 	if (audio.currOutputDevice != NULL)
@@ -343,14 +380,12 @@
 		audio.currOutputDevice = NULL;
 	}
 
-	audio.currOutputDevice = (char *)malloc(stringLen + 2);
+	audio.currOutputDevice = (char *)malloc(stringLen + 1);
 	if (audio.currOutputDevice == NULL)
 		return;
 
 	if (stringLen > 0)
 		strcpy(audio.currOutputDevice, devString);
-
-	audio.currOutputDevice[stringLen+1] = '\0'; // UTF-8 needs double null termination
 }
 
 void setToDefaultAudioInputDevice(void)
@@ -375,14 +410,12 @@
 		audio.currInputDevice = NULL;
 	}
 
-	audio.currInputDevice = (char *)malloc(stringLen + 2);
+	audio.currInputDevice = (char *)malloc(stringLen + 1);
 	if (audio.currInputDevice == NULL)
 		return;
 
 	if (stringLen > 0)
 		strcpy(audio.currInputDevice, devString);
-
-	audio.currInputDevice[stringLen+1] = '\0'; // UTF-8 needs double null termination
 }
 
 void rescanAudioDevices(void)
@@ -408,14 +441,12 @@
 
 		const uint32_t stringLen = (uint32_t)strlen(deviceName);
 
-		audio.outputDeviceNames[i] = (char *)malloc(stringLen + 2);
+		audio.outputDeviceNames[i] = (char *)malloc(stringLen + 1);
 		if (audio.outputDeviceNames[i] == NULL)
 			break;
 
 		if (stringLen > 0)
 			strcpy(audio.outputDeviceNames[i], deviceName);
-
-		audio.outputDeviceNames[i][stringLen+1] = '\0'; // UTF-8 needs double null termination
 	}
 
 	// GET AUDIO INPUT DEVICES
@@ -435,14 +466,12 @@
 
 		const uint32_t stringLen = (uint32_t)strlen(deviceName);
 
-		audio.inputDeviceNames[i] = (char *)malloc(stringLen + 2);
+		audio.inputDeviceNames[i] = (char *)malloc(stringLen + 1);
 		if (audio.inputDeviceNames[i] == NULL)
 			break;
 
 		if (stringLen > 0)
 			strcpy(audio.inputDeviceNames[i], deviceName);
-
-		audio.inputDeviceNames[i][stringLen+1] = '\0'; // UTF-8 needs double null termination
 	}
 
 	setScrollBarEnd(SB_AUDIO_OUTPUT_SCROLL, audio.outputDeviceNum);
--- a/src/ft2_config.c
+++ b/src/ft2_config.c
@@ -264,7 +264,7 @@
 	}
 #endif
 
-	if (editor.configFileLocation == NULL)
+	if (editor.configFileLocationU == NULL)
 	{
 		if (showErrorFlag)
 			okBox(0, "System message", "Error opening config file for reading!");
@@ -272,7 +272,7 @@
 		return false;
 	}
 
-	FILE *f = UNICHAR_FOPEN(editor.configFileLocation, "rb");
+	FILE *f = UNICHAR_FOPEN(editor.configFileLocationU, "rb");
 	if (f == NULL)
 	{
 		if (showErrorFlag)
@@ -353,7 +353,7 @@
 
 bool saveConfig(bool showErrorFlag)
 {
-	if (editor.configFileLocation == NULL)
+	if (editor.configFileLocationU == NULL)
 	{
 		if (showErrorFlag)
 			okBox(0, "System message", "General I/O error during saving! Is the file in use?");
@@ -366,7 +366,7 @@
 	saveMidiInputDeviceToConfig();
 #endif
 
-	FILE *f = UNICHAR_FOPEN(editor.configFileLocation, "wb");
+	FILE *f = UNICHAR_FOPEN(editor.configFileLocationU, "wb");
 	if (f == NULL)
 	{
 		if (showErrorFlag)
@@ -410,14 +410,14 @@
 	saveConfig(CONFIG_SHOW_ERRORS);
 }
 
-static UNICHAR *getFullAudDevConfigPath(void) // kinda hackish
+static UNICHAR *getFullAudDevConfigPathU(void) // kinda hackish
 {
 	int32_t audiodevDotIniStrLen, ft2DotCfgStrLen;
 
-	if (editor.configFileLocation == NULL)
+	if (editor.configFileLocationU == NULL)
 		return NULL;
 
-	const int32_t ft2ConfPathLen = (int32_t)UNICHAR_STRLEN(editor.configFileLocation);
+	const int32_t ft2ConfPathLen = (int32_t)UNICHAR_STRLEN(editor.configFileLocationU);
 
 #ifdef _WIN32
 	audiodevDotIniStrLen = (int32_t)UNICHAR_STRLEN(L"audiodev.ini");
@@ -427,31 +427,29 @@
 	ft2DotCfgStrLen = (int32_t)UNICHAR_STRLEN("FT2.CFG");
 #endif
 
-	UNICHAR *filePath = (UNICHAR *)calloc(ft2ConfPathLen + audiodevDotIniStrLen + 2, sizeof (UNICHAR));
+	UNICHAR *filePathU = (UNICHAR *)malloc((ft2ConfPathLen + audiodevDotIniStrLen + 1) * sizeof (UNICHAR));
+	filePathU[0] = 0;
 
-	UNICHAR_STRCPY(filePath, editor.configFileLocation);
+	UNICHAR_STRCPY(filePathU, editor.configFileLocationU);
+	filePathU[ft2ConfPathLen-ft2DotCfgStrLen] = 0;
 
-	const int32_t stringOffset = ft2ConfPathLen - ft2DotCfgStrLen;
-	filePath[stringOffset+0] = '\0';
-	filePath[stringOffset+1] = '\0';
-
 #ifdef _WIN32
-	UNICHAR_STRCAT(filePath, L"audiodev.ini");
+	UNICHAR_STRCAT(filePathU, L"audiodev.ini");
 #else
-	UNICHAR_STRCAT(filePath, "audiodev.ini");
+	UNICHAR_STRCAT(filePathU, "audiodev.ini");
 #endif
 
-	return filePath;
+	return filePathU;
 }
 
-static UNICHAR *getFullMidiDevConfigPath(void) // kinda hackish
+static UNICHAR *getFullMidiDevConfigPathU(void) // kinda hackish
 {
 	int32_t mididevDotIniStrLen, ft2DotCfgStrLen;
 
-	if (editor.configFileLocation == NULL)
+	if (editor.configFileLocationU == NULL)
 		return NULL;
 
-	const int32_t ft2ConfPathLen = (int32_t)UNICHAR_STRLEN(editor.configFileLocation);
+	const int32_t ft2ConfPathLen = (int32_t)UNICHAR_STRLEN(editor.configFileLocationU);
 
 #ifdef _WIN32
 	mididevDotIniStrLen = (int32_t)UNICHAR_STRLEN(L"mididev.ini");
@@ -461,21 +459,19 @@
 	ft2DotCfgStrLen = (int32_t)UNICHAR_STRLEN("FT2.CFG");
 #endif
 
-	UNICHAR *filePath = (UNICHAR *)calloc(ft2ConfPathLen + mididevDotIniStrLen + 2, sizeof (UNICHAR));
+	UNICHAR *filePathU = (UNICHAR *)malloc((ft2ConfPathLen + mididevDotIniStrLen + 1) * sizeof (UNICHAR));
+	filePathU[0] = 0;
 
-	UNICHAR_STRCPY(filePath, editor.configFileLocation);
+	UNICHAR_STRCPY(filePathU, editor.configFileLocationU);
+	filePathU[ft2ConfPathLen-ft2DotCfgStrLen] = 0;
 
-	const int32_t stringOffset = ft2ConfPathLen - ft2DotCfgStrLen;
-	filePath[stringOffset+0] = '\0';
-	filePath[stringOffset+1] = '\0';
-
 #ifdef _WIN32
-	UNICHAR_STRCAT(filePath, L"mididev.ini");
+	UNICHAR_STRCAT(filePathU, L"mididev.ini");
 #else
-	UNICHAR_STRCAT(filePath, "mididev.ini");
+	UNICHAR_STRCAT(filePathU, "mididev.ini");
 #endif
 
-	return filePath;
+	return filePathU;
 }
 
 static void setConfigFileLocation(void) // kinda hackish
@@ -484,41 +480,44 @@
 #ifdef _WIN32
 	int32_t ft2DotCfgStrLen = (int32_t)UNICHAR_STRLEN(L"FT2.CFG");
 
-	UNICHAR *oldPath = (UNICHAR *)calloc(PATH_MAX + 8 + 2, sizeof (UNICHAR));
-	UNICHAR *tmpPath = (UNICHAR *)calloc(PATH_MAX + 8 + 2, sizeof (UNICHAR));
-	editor.configFileLocation = (UNICHAR *)calloc(PATH_MAX + ft2DotCfgStrLen + 2, sizeof (UNICHAR));
+	UNICHAR *oldPathU = (UNICHAR *)malloc((PATH_MAX + 8 + 1) * sizeof (UNICHAR));
+	UNICHAR *tmpPathU = (UNICHAR *)malloc((PATH_MAX + 8 + 1) * sizeof (UNICHAR));
+	editor.configFileLocationU = (UNICHAR *)malloc((PATH_MAX + ft2DotCfgStrLen + 1) * sizeof (UNICHAR));
 
-	if (oldPath == NULL || tmpPath == NULL || editor.configFileLocation == NULL)
+	if (oldPathU == NULL || tmpPathU == NULL || editor.configFileLocationU == NULL)
 	{
-		if (oldPath != NULL) free(oldPath);
-		if (tmpPath != NULL) free(tmpPath);
-		if (editor.configFileLocation != NULL) free(editor.configFileLocation);
+		if (oldPathU != NULL) free(oldPathU);
+		if (tmpPathU != NULL) free(tmpPathU);
+		if (editor.configFileLocationU != NULL) free(editor.configFileLocationU);
 
-		editor.configFileLocation = NULL;
+		editor.configFileLocationU = NULL;
 		showErrorMsgBox("Error: Couldn't set config file location. You can't load/save the config!");
 		return;
 	}
 
-	if (GetCurrentDirectoryW(PATH_MAX - ft2DotCfgStrLen - 1, oldPath) == 0)
+	oldPathU[0] = 0;
+	tmpPathU[0] = 0;
+
+	if (GetCurrentDirectoryW(PATH_MAX - ft2DotCfgStrLen - 1, oldPathU) == 0)
 	{
-		free(oldPath);
-		free(tmpPath);
-		free(editor.configFileLocation);
+		free(oldPathU);
+		free(tmpPathU);
+		free(editor.configFileLocationU);
 
-		editor.configFileLocation = NULL;
+		editor.configFileLocationU = NULL;
 		showErrorMsgBox("Error: Couldn't set config file location. You can't load/save the config!");
 		return;
 	}
 
-	UNICHAR_STRCPY(editor.configFileLocation, oldPath);
+	UNICHAR_STRCPY(editor.configFileLocationU, oldPathU);
 
 	FILE *f = fopen("FT2.CFG", "rb");
 	if (f == NULL) // FT2.CFG not found in current dir, try default config dir
 	{
-		int32_t result = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, tmpPath);
+		int32_t result = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, tmpPathU);
 		if (result == S_OK)
 		{
-			if (SetCurrentDirectoryW(tmpPath) != 0)
+			if (SetCurrentDirectoryW(tmpPathU) != 0)
 			{
 				result = chdir("FT2 clone");
 				if (result != 0)
@@ -528,7 +527,7 @@
 				}
 
 				if (result == 0)
-					GetCurrentDirectoryW(PATH_MAX - ft2DotCfgStrLen - 1, editor.configFileLocation); // we can, set it
+					GetCurrentDirectoryW(PATH_MAX - ft2DotCfgStrLen - 1, editor.configFileLocationU); // we can, set it
 			}
 		}
 	}
@@ -537,27 +536,29 @@
 		fclose(f);
 	}
 
-	free(tmpPath);
-	SetCurrentDirectoryW(oldPath);
-	free(oldPath);
+	free(tmpPathU);
+	SetCurrentDirectoryW(oldPathU);
+	free(oldPathU);
 
-	UNICHAR_STRCAT(editor.configFileLocation, L"\\FT2.CFG");
+	UNICHAR_STRCAT(editor.configFileLocationU, L"\\FT2.CFG");
 
 	// OS X / macOS
 #elif defined __APPLE__
 	int32_t ft2DotCfgStrLen = (int32_t)UNICHAR_STRLEN("FT2.CFG");
 
-	editor.configFileLocation = (UNICHAR *)calloc(PATH_MAX + ft2DotCfgStrLen + 2, sizeof (UNICHAR));
-	if (editor.configFileLocation == NULL)
+	editor.configFileLocationU = (UNICHAR *)malloc((PATH_MAX + ft2DotCfgStrLen + 1) * sizeof (UNICHAR));
+	if (editor.configFileLocationU == NULL)
 	{
 		showErrorMsgBox("Error: Couldn't set config file location. You can't load/save the config!");
 		return;
 	}
 
-	if (getcwd(editor.configFileLocation, PATH_MAX - ft2DotCfgStrLen - 1) == NULL)
+	editor.configFileLocationU[0] = 0;
+
+	if (getcwd(editor.configFileLocationU, PATH_MAX - ft2DotCfgStrLen - 1) == NULL)
 	{
-		free(editor.configFileLocation);
-		editor.configFileLocation = NULL;
+		free(editor.configFileLocationU);
+		editor.configFileLocationU = NULL;
 		showErrorMsgBox("Error: Couldn't set config file location. You can't load/save the config!");
 		return;
 	}
@@ -578,7 +579,7 @@
 				}
 
 				if (result == 0)
-					getcwd(editor.configFileLocation, PATH_MAX - ft2DotCfgStrLen - 1);
+					getcwd(editor.configFileLocationU, PATH_MAX - ft2DotCfgStrLen - 1);
 			}
 		}
 	}
@@ -587,23 +588,25 @@
 		fclose(f);
 	}
 
-	strcat(editor.configFileLocation, "/FT2.CFG");
+	strcat(editor.configFileLocationU, "/FT2.CFG");
 
 	// Linux etc
 #else
 	int32_t ft2DotCfgStrLen = (int32_t)UNICHAR_STRLEN("FT2.CFG");
 
-	editor.configFileLocation = (UNICHAR *)calloc(PATH_MAX + ft2DotCfgStrLen + 2, sizeof (UNICHAR));
-	if (editor.configFileLocation == NULL)
+	editor.configFileLocationU = (UNICHAR *)malloc((PATH_MAX + ft2DotCfgStrLen + 1) * sizeof (UNICHAR));
+	if (editor.configFileLocationU == NULL)
 	{
 		showErrorMsgBox("Error: Couldn't set config file location. You can't load/save the config!");
 		return;
 	}
 
-	if (getcwd(editor.configFileLocation, PATH_MAX - ft2DotCfgStrLen - 1) == NULL)
+	editor.configFileLocationU[0] = 0;
+
+	if (getcwd(editor.configFileLocationU, PATH_MAX - ft2DotCfgStrLen - 1) == NULL)
 	{
-		free(editor.configFileLocation);
-		editor.configFileLocation = NULL;
+		free(editor.configFileLocationU);
+		editor.configFileLocationU = NULL;
 		showErrorMsgBox("Error: Couldn't set config file location. You can't load/save the config!");
 		return;
 	}
@@ -632,7 +635,7 @@
 			}
 
 			if (result == 0)
-				getcwd(editor.configFileLocation, PATH_MAX - ft2DotCfgStrLen - 1);
+				getcwd(editor.configFileLocationU, PATH_MAX - ft2DotCfgStrLen - 1);
 		}
 	}
 	else
@@ -640,23 +643,23 @@
 		fclose(f);
 	}
 
-	strcat(editor.configFileLocation, "/FT2.CFG");
+	strcat(editor.configFileLocationU, "/FT2.CFG");
 #endif
 
-	editor.midiConfigFileLocation = getFullMidiDevConfigPath();
-	editor.audioDevConfigFileLocation = getFullAudDevConfigPath();
+	editor.midiConfigFileLocationU = getFullMidiDevConfigPathU();
+	editor.audioDevConfigFileLocationU = getFullAudDevConfigPathU();
 }
 
 void loadConfigOrSetDefaults(void)
 {
 	setConfigFileLocation();
-	if (editor.configFileLocation == NULL)
+	if (editor.configFileLocationU == NULL)
 	{
 		setDefaultConfigSettings();
 		return;
 	}
 
-	FILE *f = UNICHAR_FOPEN(editor.configFileLocation, "rb");
+	FILE *f = UNICHAR_FOPEN(editor.configFileLocationU, "rb");
 	if (f == NULL)
 	{
 		setDefaultConfigSettings();
--- a/src/ft2_diskop.c
+++ b/src/ft2_diskop.c
@@ -72,7 +72,7 @@
 	int32_t filesize;
 } DirRec;
 
-static char FReq_SysReqText[196], *FReq_FileName, *FReq_NameTemp;
+static char FReq_SysReqText[256], *FReq_FileName, *FReq_NameTemp;
 static char *modTmpFName, *insTmpFName, *smpTmpFName, *patTmpFName, *trkTmpFName;
 static char *modTmpFNameUTF8; // for window title
 static uint8_t FReq_Item;
@@ -84,6 +84,18 @@
 
 static void setDiskOpItem(uint8_t item);
 
+bool setupExecutablePath(void)
+{
+	editor.binaryPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+	if (editor.binaryPathU == NULL)
+		return false;
+
+	editor.binaryPathU[0] = 0;
+	UNICHAR_GETCWD(editor.binaryPathU, PATH_MAX);
+
+	return true;
+}
+
 int32_t getFileSize(UNICHAR *fileNameU) // returning -1 = filesize over 2GB
 {
 	int64_t fSize;
@@ -173,11 +185,15 @@
 
 #ifdef _WIN32
 	if (config.modulesPath[0] != '\0')
+	{
 		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.modulesPath, -1, FReq_ModCurPathU, 80);
+		FReq_ModCurPathU[80] = 0;
+	}
 
 	if (config.instrPath[0] != '\0')
 	{
 		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.instrPath, -1, FReq_InsCurPathU, 80);
+		FReq_InsCurPathU[80] = 0;
 		insPathSet = true;
 	}
 
@@ -184,6 +200,7 @@
 	if (config.samplesPath[0] != '\0')
 	{
 		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.samplesPath, -1, FReq_SmpCurPathU, 80);
+		FReq_SmpCurPathU[80] = 0;
 		smpPathSet = true;
 	}
 
@@ -190,6 +207,7 @@
 	if (config.patternsPath[0] != '\0')
 	{
 		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.patternsPath, -1, FReq_PatCurPathU, 80);
+		FReq_PatCurPathU[80] = 0;
 		patPathSet = true;
 	}
 
@@ -196,15 +214,20 @@
 	if (config.tracksPath[0] != '\0')
 	{
 		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, config.tracksPath, -1, FReq_TrkCurPathU, 80);
+		FReq_TrkCurPathU[80] = 0;
 		trkPathSet = true;
 	}
 #else
 	if (config.modulesPath[0] != '\0')
+	{
 		strncpy(FReq_ModCurPathU, config.modulesPath, 80);
+		FReq_ModCurPathU[80] = 0;
+	}
 
 	if (config.instrPath[0] != '\0')
 	{
 		strncpy(FReq_InsCurPathU, config.instrPath, 80);
+		FReq_InsCurPathU[80] = 0;
 		insPathSet = true;
 	}
 
@@ -211,6 +234,7 @@
 	if (config.samplesPath[0] != '\0')
 	{
 		strncpy(FReq_SmpCurPathU, config.samplesPath, 80);
+		FReq_SmpCurPathU[80] = 0;
 		smpPathSet = true;
 	}
 
@@ -217,6 +241,7 @@
 	if (config.patternsPath[0] != '\0')
 	{
 		strncpy(FReq_PatCurPathU, config.patternsPath, 80);
+		FReq_PatCurPathU[80] = 0;
 		patPathSet = true;
 	}
 
@@ -223,6 +248,7 @@
 	if (config.tracksPath[0] != '\0')
 	{
 		strncpy(FReq_TrkCurPathU, config.tracksPath, 80);
+		FReq_TrkCurPathU[80] = 0;
 		trkPathSet = true;
 	}
 #endif
@@ -277,22 +303,23 @@
 
 bool setupDiskOp(void)
 {
-	modTmpFName = (char *)calloc(PATH_MAX + 1, sizeof (char));
-	insTmpFName = (char *)calloc(PATH_MAX + 1, sizeof (char));
-	smpTmpFName = (char *)calloc(PATH_MAX + 1, sizeof (char));
-	patTmpFName = (char *)calloc(PATH_MAX + 1, sizeof (char));
-	trkTmpFName = (char *)calloc(PATH_MAX + 1, sizeof (char));
-	FReq_NameTemp = (char *)calloc(PATH_MAX + 1, sizeof (char));
-	FReq_ModCurPathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
-	FReq_InsCurPathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
-	FReq_SmpCurPathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
-	FReq_PatCurPathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
-	FReq_TrkCurPathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
+	modTmpFName = (char *)malloc((PATH_MAX + 1) * sizeof (char));
+	insTmpFName = (char *)malloc((PATH_MAX + 1) * sizeof (char));
+	smpTmpFName = (char *)malloc((PATH_MAX + 1) * sizeof (char));
+	patTmpFName = (char *)malloc((PATH_MAX + 1) * sizeof (char));
+	trkTmpFName = (char *)malloc((PATH_MAX + 1) * sizeof (char));
+	FReq_NameTemp = (char *)malloc((PATH_MAX + 1) * sizeof (char));
 
-	if (modTmpFName == NULL || insTmpFName == NULL || smpTmpFName == NULL || patTmpFName == NULL ||
-		trkTmpFName == NULL || FReq_NameTemp == NULL || FReq_ModCurPathU == NULL ||
-		FReq_InsCurPathU == NULL || FReq_SmpCurPathU == NULL || FReq_PatCurPathU == NULL ||
-		FReq_TrkCurPathU == NULL)
+	FReq_ModCurPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+	FReq_InsCurPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+	FReq_SmpCurPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+	FReq_PatCurPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+	FReq_TrkCurPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+
+	if (modTmpFName      == NULL || insTmpFName      == NULL || smpTmpFName      == NULL ||
+		patTmpFName      == NULL || trkTmpFName      == NULL || FReq_NameTemp    == NULL ||
+		FReq_ModCurPathU == NULL || FReq_InsCurPathU == NULL || FReq_SmpCurPathU == NULL ||
+		FReq_PatCurPathU == NULL || FReq_TrkCurPathU == NULL)
 	{
 		// allocated memory is free'd lateron
 		showErrorMsgBox("Not enough memory!");
@@ -299,6 +326,19 @@
 		return false;
 	}
 
+	// clear first entry of strings
+	modTmpFName[0] = '\0';
+	insTmpFName[0] = '\0';
+	smpTmpFName[0] = '\0';
+	patTmpFName[0] = '\0';
+	trkTmpFName[0] = '\0';
+	FReq_NameTemp[0] = '\0';
+	FReq_ModCurPathU[0] = 0;
+	FReq_InsCurPathU[0] = 0;
+	FReq_SmpCurPathU[0] = 0;
+	FReq_PatCurPathU[0] = 0;
+	FReq_TrkCurPathU[0] = 0;
+
 	strcpy(modTmpFName, "untitled.xm");
 	strcpy(insTmpFName, "untitled.xi");
 	strcpy(smpTmpFName, "untitled.wav");
@@ -602,7 +642,7 @@
 	char *filename = getFilenameFromPath(ansiPath);
 	uint32_t filenameLen = (uint32_t)strlen(filename);
 
-	if (filenameLen > PATH_MAX-1)
+	if (filenameLen > PATH_MAX)
 	{
 		free(ansiPath);
 		return; // filename is too long, don't bother to copy it over
@@ -693,9 +733,9 @@
 		{
 			if (songModifiedCheck && song.isModified)
 			{
-				// remove file selection
+				// remove file selection before okBox() opens up
 				FReq_EntrySelected = -1;
-				diskOp_DrawDirectory();
+				diskOp_DrawFilelist();
 
 				if (okBox(2, "System request", "You have unsaved changes in your song. Load new song and lose all changes?") != 1)
 					return;
@@ -758,8 +798,6 @@
 void diskOpChangeFilenameExt(char *ext)
 {
 	changeFilenameExt(FReq_FileName, ext, PATH_MAX);
-	if (ui.diskOpShown)
-		diskOp_DrawDirectory();
 }
 
 void trimEntryName(char *name, bool isDir)
@@ -1011,7 +1049,7 @@
 
 	// remove file selection
 	FReq_EntrySelected = -1;
-	diskOp_DrawDirectory();
+	diskOp_DrawFilelist();
 
 	DirRec *dirEntry = &FReq_Buffer[entryIndex];
 	switch (mode)
@@ -1077,15 +1115,16 @@
 				if (nameTmp == NULL)
 					break;
 
-				strncpy(FReq_NameTemp, nameTmp, PATH_MAX - 1);
+				strncpy(FReq_NameTemp, nameTmp, PATH_MAX);
+				FReq_NameTemp[PATH_MAX] = '\0';
 				free(nameTmp);
 
 				// in case of UTF8 -> CP437 encoding failure, there can be question marks. Remove them...
 				removeQuestionmarksFromString(FReq_NameTemp);
 
-				if (inputBox(1, dirEntry->isDir ? "Enter new directory name:" : "Enter new filename:", FReq_NameTemp, PATH_MAX - 1) == 1)
+				if (inputBox(1, dirEntry->isDir ? "Enter new directory name:" : "Enter new filename:", FReq_NameTemp, PATH_MAX) == 1)
 				{
-					if ((FReq_NameTemp == NULL) || (FReq_NameTemp[0] == '\0'))
+					if (FReq_NameTemp == NULL || FReq_NameTemp[0] == '\0')
 					{
 						okBox(0, "System message", "New name can't be empty!");
 						break;
@@ -1120,7 +1159,7 @@
 	if (max > DISKOP_ENTRY_NUM) // needed kludge when mouse-scrolling
 		max = DISKOP_ENTRY_NUM;
 
-	if (!mouseHeldDlown)
+	if (!mouseHeldDlown) // select file
 	{
 		FReq_EntrySelected = -1;
 
@@ -1130,7 +1169,7 @@
 			if (tmpEntry >= 0 && tmpEntry < max)
 			{
 				FReq_EntrySelected = tmpEntry;
-				diskOp_DrawDirectory();
+				diskOp_DrawFilelist();
 			}
 
 			mouse.lastUsedObjectType = OBJECT_DISKOPLIST;
@@ -1161,7 +1200,7 @@
 	if (mouse.x < 169 || mouse.x > 331 || mouse.y < 4 || tmpEntry < 0 || tmpEntry >= max)
 	{
 		FReq_EntrySelected = -1;
-		diskOp_DrawDirectory();
+		diskOp_DrawFilelist();
 
 		return true;
 	}
@@ -1169,7 +1208,7 @@
 	if (tmpEntry != FReq_EntrySelected)
 	{
 		FReq_EntrySelected = tmpEntry;
-		diskOp_DrawDirectory();
+		diskOp_DrawFilelist();
 	}
 
 	return true;
@@ -1183,7 +1222,7 @@
 			fileListPressed((mouse.y - 4) / (FONT1_CHAR_H + 1));
 
 		FReq_EntrySelected = -1;
-		diskOp_DrawDirectory();
+		diskOp_DrawFilelist();
 	}
 }
 
@@ -1537,7 +1576,7 @@
 		return NULL;
 	}
 
-	char *p = (char *)malloc(nameLen + 2);
+	char *p = (char *)malloc(nameLen+1+1);
 	if (p == NULL)
 	{
 		free(name);
@@ -1701,6 +1740,9 @@
 {
 	fillRect(4, 145, 162, 10, PAL_DESKTOP);
 
+	if (FReq_CurPathU == NULL)
+		return;
+
 	const uint32_t pathLen = (uint32_t)UNICHAR_STRLEN(FReq_CurPathU);
 	if (pathLen == 0)
 		return;
@@ -1722,11 +1764,14 @@
 	{
 		// path doesn't fit, print drive + ".." + last directory
 
-		memset(FReq_NameTemp, 0, PATH_MAX + 1);
 #ifdef _WIN32
-		strncpy(FReq_NameTemp, p, 3);
+		memcpy(FReq_NameTemp, p, 3); // get drive (f.ex. C:\)
+		FReq_NameTemp[3] = '\0';
+
 		strcat(FReq_NameTemp, ".\001"); // special character in font
+		FReq_NameTemp[5] = '\0';
 #else
+		FReq_NameTemp[0] = '\0';
 		strcpy(FReq_NameTemp, "/");
 		strcat(FReq_NameTemp, "..");
 #endif
@@ -1735,7 +1780,7 @@
 		if (delimiter != NULL)
 		{
 #ifdef _WIN32
-			strcat(FReq_NameTemp, delimiter + 1);
+			strcat(FReq_NameTemp, delimiter+1);
 #else
 			strcat(FReq_NameTemp, delimiter);
 #endif
@@ -1749,9 +1794,9 @@
 			p = FReq_NameTemp;
 			while (j >= 6 && textWidth(p) >= 162)
 			{
-				p[j - 2] = '.';
-				p[j - 1] = '.';
-				p[j - 0] = '\0';
+				p[j-2] = '.';
+				p[j-1] = '.';
+				p[j-0] = '\0';
 				j--;
 			}
 		}
@@ -1762,11 +1807,14 @@
 	free(asciiPath);
 }
 
-void diskOp_DrawDirectory(void)
+void diskOp_DrawFilelist(void)
 {
-	clearRect(FILENAME_TEXT_X - 1, 4, 162, 164);
-	drawTextBox(TB_DISKOP_FILENAME);
+	clearRect(FILENAME_TEXT_X-1, 4, 162, 164);
 
+	if (FReq_FileCount == 0)
+		return;
+
+	// draw "selected file" rectangle
 	if (FReq_EntrySelected != -1)
 	{
 		const uint16_t y = 4 + (uint16_t)((FONT1_CHAR_H + 1) * FReq_EntrySelected);
@@ -1773,14 +1821,6 @@
 		fillRect(FILENAME_TEXT_X - 1, y, 162, FONT1_CHAR_H, PAL_PATTEXT);
 	}
 
-	displayCurrPath();
-#ifdef _WIN32
-	setupDiskOpDrives();
-#endif
-
-	if (FReq_FileCount == 0)
-		return;
-
 	for (uint16_t i = 0; i < DISKOP_ENTRY_NUM; i++)
 	{
 		const int32_t bufEntry = FReq_DirPos + i;
@@ -1817,9 +1857,21 @@
 		if (!FReq_Buffer[bufEntry].isDir)
 			printFormattedFilesize(FILESIZE_TEXT_X, y, bufEntry);
 	}
+}
 
-	setScrollBarPos(SB_DISKOP_LIST, FReq_DirPos, true);
+void diskOp_DrawDirectory(void)
+{
+	drawTextBox(TB_DISKOP_FILENAME);
+
+	displayCurrPath();
+#ifdef _WIN32
+	setupDiskOpDrives();
+#endif
+
 	setScrollBarEnd(SB_DISKOP_LIST, FReq_FileCount);
+	setScrollBarPos(SB_DISKOP_LIST, FReq_DirPos, false);
+
+	diskOp_DrawFilelist();
 }
 
 static DirRec *bufferCreateEmptyDir(void) // special case: creates a dir entry with a ".." directory
@@ -2035,7 +2087,7 @@
 			// FReq_ModCurPathU is always set at this point
 
 			FReq_CurPathU = FReq_ModCurPathU;
-			if (FReq_CurPathU != NULL)
+			if (FReq_CurPathU != NULL && FReq_CurPathU[0] != '\0')
 				UNICHAR_CHDIR(FReq_CurPathU);
 		}
 		break;
@@ -2044,7 +2096,7 @@
 		{
 			FReq_FileName = insTmpFName;
 
-			if (!insPathSet)
+			if (!insPathSet && FReq_CurPathU != NULL && FReq_CurPathU[0] != '\0')
 			{
 				UNICHAR_STRCPY(FReq_InsCurPathU, FReq_CurPathU);
 				insPathSet = true;
@@ -2060,7 +2112,7 @@
 		{
 			FReq_FileName = smpTmpFName;
 
-			if (!smpPathSet)
+			if (!smpPathSet && FReq_CurPathU != NULL && FReq_CurPathU[0] != '\0')
 			{
 				UNICHAR_STRCPY(FReq_SmpCurPathU, FReq_CurPathU);
 				smpPathSet = true;
@@ -2076,7 +2128,7 @@
 		{
 			FReq_FileName = patTmpFName;
 
-			if (!patPathSet)
+			if (!patPathSet && FReq_CurPathU != NULL && FReq_CurPathU[0] != '\0')
 			{
 				UNICHAR_STRCPY(FReq_PatCurPathU, FReq_CurPathU);
 				patPathSet = true;
@@ -2092,7 +2144,7 @@
 		{
 			FReq_FileName = trkTmpFName;
 
-			if (!trkPathSet)
+			if (!trkPathSet && FReq_CurPathU != NULL && FReq_CurPathU[0] != '\0')
 			{
 				UNICHAR_STRCPY(FReq_TrkCurPathU, FReq_CurPathU);
 				trkPathSet = true;
@@ -2105,15 +2157,13 @@
 		break;
 	}
 
-	const int32_t pathLen = (int32_t)UNICHAR_STRLEN(FReq_CurPathU);
-	if (pathLen == 0)
+	if (FReq_CurPathU != NULL && FReq_ModCurPathU != NULL)
 	{
-		memset(FReq_CurPathU, 0, (PATH_MAX + 2) * sizeof (UNICHAR));
-		UNICHAR_STRCPY(FReq_CurPathU, FReq_ModCurPathU);
+		if (FReq_CurPathU[0] == '\0' && FReq_ModCurPathU[0] != '\0')
+			UNICHAR_STRCPY(FReq_CurPathU, FReq_ModCurPathU);
 	}
 
 	textBoxes[TB_DISKOP_FILENAME].textPtr = FReq_FileName;
-
 	FReq_ShowAllFiles = false;
 
 	if (ui.diskOpShown)
@@ -2199,14 +2249,15 @@
 		assert(FReq_ModCurPathU != NULL);
 
 		// first test if we can change the dir to the one stored in the config (if present)
-		if (UNICHAR_STRLEN(FReq_ModCurPathU) == 0 || UNICHAR_CHDIR(FReq_ModCurPathU) != 0)
+		if (FReq_ModCurPathU[0] == '\0' || UNICHAR_CHDIR(FReq_ModCurPathU) != 0)
 		{
 			// nope, couldn't do that, set Disk Op. path to user/home directory
 #ifdef _WIN32
 			SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, FReq_ModCurPathU);
 #else
-			if (getenv("HOME") != NULL)
-				UNICHAR_STRCPY(FReq_ModCurPathU, getenv("HOME"));
+			char *home = getenv("HOME");
+			if (home != NULL)
+				UNICHAR_STRCPY(FReq_ModCurPathU, home);
 #endif
 			UNICHAR_CHDIR(FReq_ModCurPathU);
 		}
@@ -2285,7 +2336,7 @@
 	if ((int32_t)pos != FReq_DirPos && FReq_FileCount > DISKOP_ENTRY_NUM)
 	{
 		FReq_DirPos = (int32_t)pos;
-		diskOp_DrawDirectory();
+		diskOp_DrawFilelist();
 	}
 }
 
@@ -2345,7 +2396,7 @@
 void pbDiskOpMakeDir(void)
 {
 	FReq_NameTemp[0] = '\0';
-	if (inputBox(1, "Enter directory name:", FReq_NameTemp, PATH_MAX - 1) == 1)
+	if (inputBox(1, "Enter directory name:", FReq_NameTemp, PATH_MAX) == 1)
 	{
 		if (FReq_NameTemp[0] == '\0')
 		{
@@ -2371,7 +2422,7 @@
 void pbDiskOpSetPath(void)
 {
 	FReq_NameTemp[0] = '\0';
-	if (inputBox(1, "Enter new directory path:", FReq_NameTemp, PATH_MAX - 1) == 1)
+	if (inputBox(1, "Enter new directory path:", FReq_NameTemp, PATH_MAX) == 1)
 	{
 		if (FReq_NameTemp[0] == '\0')
 		{
--- a/src/ft2_diskop.h
+++ b/src/ft2_diskop.h
@@ -21,6 +21,7 @@
 	SMP_SAVE_MODE_WAV = 2
 };
 
+bool setupExecutablePath(void);
 int32_t getFileSize(UNICHAR *fileNameU);
 uint8_t getDiskOpItem(void);
 void updateCurrSongFilename(void); // for window title
@@ -41,6 +42,7 @@
 bool testDiskOpMouseDown(bool mouseHeldDown);
 void testDiskOpMouseRelease(void);
 void diskOp_StartDirReadThread(void);
+void diskOp_DrawFilelist(void);
 void diskOp_DrawDirectory(void);
 void showDiskOpScreen(void);
 void hideDiskOpScreen(void);
--- a/src/ft2_events.c
+++ b/src/ft2_events.c
@@ -35,13 +35,14 @@
 
 #define CRASH_TEXT "Oh no!\nThe Fasttracker II clone has crashed...\n\nA backup .xm was hopefully " \
                    "saved to the current module directory.\n\nPlease report this bug if you can.\n" \
-                   "Try to mention what you did before the crash happened."
+                   "Try to mention what you did before the crash happened.\n" \
+                   "My email can be found at the bottom of 16-bits.org."
 
 static bool backupMadeAfterCrash;
 
 #ifdef _WIN32
-#define SYSMSG_FILE_ARG (WM_USER + 1)
-#define ARGV_SHARED_MEM_MAX_LEN ((MAX_PATH * 2) + 2)
+#define SYSMSG_FILE_ARG (WM_USER+1)
+#define ARGV_SHARED_MEM_MAX_LEN ((PATH_MAX+1) * sizeof (WCHAR))
 #define SHARED_HWND_NAME TEXT("Local\\FT2CloneHwnd")
 #define SHARED_FILENAME TEXT("Local\\FT2CloneFilename")
 static HWND hWnd;
--- a/src/ft2_gui.c
+++ b/src/ft2_gui.c
@@ -127,20 +127,21 @@
 
 bool setupGUI(void)
 {
-	int32_t i;
-
 	// all memory will be NULL-tested and free'd if we return false somewhere in this function
 
-	editor.tmpFilenameU = (UNICHAR *)calloc(PATH_MAX + 1, sizeof (UNICHAR));
-	editor.tmpInstrFilenameU = (UNICHAR *)calloc(PATH_MAX + 1, sizeof (UNICHAR));
+	editor.tmpFilenameU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+	editor.tmpInstrFilenameU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
 
 	if (editor.tmpFilenameU == NULL || editor.tmpInstrFilenameU == NULL)
 		goto setupGUI_OOM;
 
+	editor.tmpFilenameU[0] = 0;
+	editor.tmpInstrFilenameU[0] = 0;
+
 	// set uninitialized GUI struct entries
 
 	textBox_t *t = &textBoxes[1]; // skip first entry, it's reserved for inputBox())
-	for (i = 1; i < NUM_TEXTBOXES; i++, t++)
+	for (int32_t i = 1; i < NUM_TEXTBOXES; i++, t++)
 	{
 		t->visible = false;
 		t->bufOffset = 0;
@@ -156,7 +157,7 @@
 	}
 
 	pushButton_t *p = pushButtons;
-	for (i = 0; i < NUM_PUSHBUTTONS; i++, p++)
+	for (int32_t i = 0; i < NUM_PUSHBUTTONS; i++, p++)
 	{
 		p->state = 0;
 		p->visible = false;
@@ -174,7 +175,7 @@
 	}
 
 	checkBox_t *c = checkBoxes;
-	for (i = 0; i < NUM_CHECKBOXES; i++, c++)
+	for (int32_t i = 0; i < NUM_CHECKBOXES; i++, c++)
 	{
 		c->state = 0;
 		c->checked = false;
@@ -182,7 +183,7 @@
 	}
 
 	radioButton_t *r = radioButtons;
-	for (i = 0; i < NUM_RADIOBUTTONS; i++, r++)
+	for (int32_t i = 0; i < NUM_RADIOBUTTONS; i++, r++)
 	{
 		r->state = 0;
 		r->visible = false;
@@ -189,7 +190,7 @@
 	}
 
 	scrollBar_t *s = scrollBars;
-	for (i = 0; i < NUM_SCROLLBARS; i++, s++)
+	for (int32_t i = 0; i < NUM_SCROLLBARS; i++, s++)
 	{
 		s->visible = false;
 		s->state = 0;
--- a/src/ft2_header.h
+++ b/src/ft2_header.h
@@ -12,7 +12,7 @@
 #endif
 #include "ft2_replayer.h"
 
-#define PROG_VER_STR "1.45"
+#define PROG_VER_STR "1.46"
 
 // do NOT change these! It will only mess things up...
 
--- a/src/ft2_keyboard.c
+++ b/src/ft2_keyboard.c
@@ -122,7 +122,8 @@
 			return; // do NOT repeat keys in Nibbles or if keyRepeat is disabled
 	}
 
-	keyb.keyRepeat = true;
+	if (scancode != SDL_SCANCODE_ESCAPE)
+		keyb.keyRepeat = true;
 
 	// handle certain keys (home/end/left/right etc) when editing text
 	if (editor.editTextFlag)
@@ -669,6 +670,7 @@
 
 		case SDLK_KP_ENTER:
 		case SDLK_RETURN:
+		{
 			if (keyb.leftAltPressed)
 			{
 				toggleFullScreen();
@@ -679,9 +681,11 @@
 #endif
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_F9:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[0]);
@@ -692,9 +696,11 @@
 				editor.ptnJumpPos[0] = (uint8_t)editor.pattPos;
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_F10:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[1]);
@@ -705,9 +711,11 @@
 				editor.ptnJumpPos[1] = (uint8_t)editor.pattPos;
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_F11:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[2]);
@@ -718,9 +726,11 @@
 				editor.ptnJumpPos[2] = (uint8_t)editor.pattPos;
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_F12:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[3]);
@@ -731,9 +741,11 @@
 				editor.ptnJumpPos[3] = (uint8_t)editor.pattPos;
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_a:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				if (ui.sampleEditorShown)
@@ -752,9 +764,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_b:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				if (!ui.aboutScreenShown)
@@ -762,9 +776,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_c:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (ui.sampleEditorShown)
@@ -793,9 +809,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_d:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(10);
@@ -808,9 +826,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_e:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(2);
@@ -826,9 +846,11 @@
 				showSampleEditorExt();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_f:
+		{
 #ifdef __APPLE__
 			if (keyb.leftCommandPressed && keyb.leftCtrlPressed)
 			{
@@ -854,17 +876,21 @@
 				jumpToChannel(11);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_g:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(12);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_h:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(13);
@@ -875,9 +901,11 @@
 				showHelpScreen();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_i:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(7);
@@ -888,25 +916,31 @@
 				showInstEditor();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_j:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(14);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_k:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(15);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_m:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				if (ui.aboutScreenShown)  hideAboutScreen();
@@ -918,17 +952,21 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_n:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				showNibblesScreen();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_p:
+		{
 			if (keyb.leftCtrlPressed)
 			{
 				if (!ui.patternEditorShown)
@@ -942,17 +980,21 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_q:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(0);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_r:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (ui.sampleEditorShown)
@@ -967,9 +1009,11 @@
 				showTrimScreen();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_s:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (ui.sampleEditorShown)
@@ -984,9 +1028,11 @@
 				showSampleEditor();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_t:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(4);
@@ -997,17 +1043,21 @@
 				showTranspose();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_u:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(6);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_v:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (ui.sampleEditorShown)
@@ -1036,17 +1086,21 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_w:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(1);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_x:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (ui.sampleEditorShown)
@@ -1080,17 +1134,21 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_y:
+		{
 			if (keyb.leftAltPressed)
 			{
 				jumpToChannel(5);
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_z:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (ui.sampleEditorShown)
@@ -1103,9 +1161,11 @@
 				togglePatternEditorExtended();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_1:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1123,9 +1183,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_2:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1143,9 +1205,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_3:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1163,9 +1227,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_4:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1185,9 +1251,11 @@
 				return true;
 			}
 #endif
-			break;
+		}
+		break;
 
 		case SDLK_5:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1197,9 +1265,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_6:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1209,9 +1279,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_7:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1221,9 +1293,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_8:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1233,9 +1307,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_9:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1245,9 +1321,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_0:
+		{
 			if (keyb.leftAltPressed)
 			{
 				if (keyb.leftShiftPressed)
@@ -1257,9 +1335,11 @@
 
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_LEFT:
+		{
 			if (keyb.leftShiftPressed)
 			{
 				decSongPos();
@@ -1275,9 +1355,11 @@
 				keybPattMarkLeft();
 				return true;
 			}
-			break;
+		}
+		break;
 
 		case SDLK_RIGHT:
+		{
 			if (keyb.leftShiftPressed)
 			{
 				incSongPos();
@@ -1293,7 +1375,8 @@
 				keybPattMarkRight();
 				return true;
 			}
-			break;
+		}
+		break;
 	}
 
 	return false;
--- a/src/ft2_main.c
+++ b/src/ft2_main.c
@@ -147,9 +147,7 @@
 #ifdef __APPLE__
 	osxSetDirToProgramDirFromArgs(argv);
 #endif
-	UNICHAR_GETCWD(editor.binaryPathU, PATH_MAX);
-
-	if (!loadBMPs())
+	if (!setupExecutablePath() || !loadBMPs())
 	{
 		cleanUpAndExit();
 		return 1;
@@ -351,22 +349,28 @@
 	}
 #endif
 
-	if (editor.audioDevConfigFileLocation != NULL)
+	if (editor.audioDevConfigFileLocationU != NULL)
 	{
-		free(editor.audioDevConfigFileLocation);
-		editor.audioDevConfigFileLocation = NULL;
+		free(editor.audioDevConfigFileLocationU);
+		editor.audioDevConfigFileLocationU = NULL;
 	}
 
-	if (editor.configFileLocation != NULL)
+	if (editor.configFileLocationU != NULL)
 	{
-		free(editor.configFileLocation);
-		editor.configFileLocation = NULL;
+		free(editor.configFileLocationU);
+		editor.configFileLocationU = NULL;
 	}
 
-	if (editor.midiConfigFileLocation != NULL)
+	if (editor.midiConfigFileLocationU != NULL)
 	{
-		free(editor.midiConfigFileLocation);
-		editor.midiConfigFileLocation = NULL;
+		free(editor.midiConfigFileLocationU);
+		editor.midiConfigFileLocationU = NULL;
+	}
+
+	if (editor.binaryPathU != NULL)
+	{
+		free(editor.binaryPathU);
+		editor.binaryPathU = NULL;
 	}
 
 #ifdef _WIN32
--- a/src/ft2_midi.c
+++ b/src/ft2_midi.c
@@ -18,6 +18,8 @@
 #include "ft2_structs.h"
 #include "rtmidi/rtmidi_c.h"
 
+#define MAX_DEV_STR_LEN 256
+
 // hide POSIX warnings
 #ifdef _MSC_VER
 #pragma warning(disable: 4996)
@@ -265,7 +267,7 @@
 	if (midiInStr == NULL)
 		return false;
 
-	FILE *f = UNICHAR_FOPEN(editor.midiConfigFileLocation, "w");
+	FILE *f = UNICHAR_FOPEN(editor.midiConfigFileLocationU, "w");
 	if (f == NULL)
 	{
 		free(midiInStr);
@@ -281,8 +283,6 @@
 
 bool setMidiInputDeviceFromConfig(void)
 {
-#define MAX_DEV_STR_LEN 1024
-
 	uint32_t i;
 
 	if (midi.inputDeviceName != NULL)
@@ -292,16 +292,18 @@
 	if (numDevices == 0)
 		goto setDefMidiInputDev;
 
-	FILE *f = UNICHAR_FOPEN(editor.midiConfigFileLocation, "r");
+	FILE *f = UNICHAR_FOPEN(editor.midiConfigFileLocationU, "r");
 	if (f == NULL)
 		goto setDefMidiInputDev;
 
-	char *devString = (char *)calloc(MAX_DEV_STR_LEN+4, sizeof (char));
+	char *devString = (char *)malloc((MAX_DEV_STR_LEN+4) * sizeof (char));
 	if (devString == NULL)
 	{
 		fclose(f);
 		goto setDefMidiInputDev;
 	}
+
+	devString[0] = '\0';
 
 	if (fgets(devString, MAX_DEV_STR_LEN, f) == NULL)
 	{
--- a/src/ft2_module_loader.c
+++ b/src/ft2_module_loader.c
@@ -526,10 +526,8 @@
 
 bool handleModuleLoadFromArg(int argc, char **argv)
 {
-	UNICHAR tmpPathU[PATH_MAX+2];
+	// we always expect only one parameter, and that it is the module
 
-	// this is crude, we always expect only one parameter, and that it is the module.
-
 	if (argc != 2 || argv[1] == NULL || argv[1][0] == '\0')
 		return false;
 
@@ -540,15 +538,26 @@
 
 	const uint32_t filenameLen = (const uint32_t)strlen(argv[1]);
 
-	UNICHAR *filenameU = (UNICHAR *)calloc(filenameLen+1, sizeof (UNICHAR));
+	UNICHAR *tmpPathU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));
+	if (tmpPathU == NULL)
+	{
+		okBox(0, "System message", "Not enough memory!");
+		return false;
+	}
+
+	UNICHAR *filenameU = (UNICHAR *)malloc((filenameLen + 1) * sizeof (UNICHAR));
 	if (filenameU == NULL)
 	{
+		free(tmpPathU);
 		okBox(0, "System message", "Not enough memory!");
 		return false;
 	}
 
+	tmpPathU[0] = 0;
+	filenameU[0] = 0;
+
 #ifdef _WIN32
-	MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, filenameU, filenameLen);
+	MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, filenameU, filenameLen+1);
 #else
 	strcpy(filenameU, argv[1]);
 #endif
@@ -562,9 +571,11 @@
 	const int32_t filesize = getFileSize(filenameU);
 	if (filesize == -1 || filesize >= 512L*1024*1024) // 1) >=2GB   2) >=512MB
 	{
-		okBox(0, "System message", "Error: The module is too big to be loaded!");
 		free(filenameU);
 		UNICHAR_CHDIR(tmpPathU); // set old path back
+		free(tmpPathU);
+
+		okBox(0, "System message", "Error: The module is too big to be loaded!");
 		return false;
 	}
 
@@ -572,6 +583,8 @@
 
 	free(filenameU);
 	UNICHAR_CHDIR(tmpPathU); // set old path back
+	free(tmpPathU);
+
 	return result;
 }
 
@@ -642,7 +655,7 @@
 	if (fullPathLen == 0)
 		return;
 
-	UNICHAR *fullPathU = (UNICHAR *)calloc(fullPathLen + 2, sizeof (UNICHAR));
+	UNICHAR *fullPathU = (UNICHAR *)malloc((fullPathLen + 1) * sizeof (UNICHAR));
 	if (fullPathU == NULL)
 	{
 		okBox(0, "System message", "Not enough memory!");
@@ -649,8 +662,10 @@
 		return;
 	}
 
+	fullPathU[0] = 0;
+
 #ifdef _WIN32
-	MultiByteToWideChar(CP_UTF8, 0, fullPathUTF8, -1, fullPathU, fullPathLen);
+	MultiByteToWideChar(CP_UTF8, 0, fullPathUTF8, -1, fullPathU, fullPathLen+1);
 #else
 	strcpy(fullPathU, fullPathUTF8);
 #endif
--- a/src/ft2_mouse.c
+++ b/src/ft2_mouse.c
@@ -301,7 +301,7 @@
 	textBox_t *t = textBoxes;
 	for (i = 0; i < NUM_TEXTBOXES; i++, t++)
 	{
-		if (ui.sysReqShown && i > 0)
+		if (ui.sysReqShown && i != 0) // Sys. Req can only have one (special) text box
 			continue;
 
 		if (!t->visible)
@@ -313,7 +313,10 @@
 		if (my >= t->y && my < t->y+t->h && mx >= t->x && mx < t->x+t->w)
 		{
 			mouse.mouseOverTextBox = true;
-			setTextEditMouse();
+
+			if (mouseShape != MOUSE_IDLE_TEXT_EDIT)
+				setTextEditMouse();
+
 			return;
 		}
 	}
--- a/src/ft2_replayer.c
+++ b/src/ft2_replayer.c
@@ -528,8 +528,8 @@
 
 	if (ton != 0)
 	{
-		const uint16_t tmpTon = ((ton-1) << 4) + (((int8_t)ch->fineTune >> 3) + 16);
-		if (tmpTon < MAX_NOTES)
+		const uint16_t tmpTon = ((ton-1) << 4) + (((int8_t)ch->fineTune >> 3) + 16); // 0..1935
+		if (tmpTon < MAX_NOTES) // tmpTon is *always* below MAX_NOTES here, so this check is not really needed
 		{
 			assert(note2Period != NULL);
 			ch->outPeriod = ch->realPeriod = note2Period[tmpTon];
--- a/src/ft2_structs.h
+++ b/src/ft2_structs.h
@@ -11,9 +11,8 @@
 
 typedef struct editor_t
 {
-	UNICHAR binaryPathU[PATH_MAX + 2];
-	UNICHAR *tmpFilenameU, *tmpInstrFilenameU; // used by saving/loading threads
-	UNICHAR *configFileLocation, *audioDevConfigFileLocation, *midiConfigFileLocation;
+	UNICHAR *binaryPathU, *tmpFilenameU, *tmpInstrFilenameU; // used by saving/loading threads
+	UNICHAR *configFileLocationU, *audioDevConfigFileLocationU, *midiConfigFileLocationU;
 
 	volatile bool mainLoopOngoing;
 	volatile bool busy, scopeThreadMutex, programRunning, wavIsRendering, wavReachedEndFlag;
--- a/src/ft2_sysreqs.c
+++ b/src/ft2_sysreqs.c
@@ -299,8 +299,11 @@
 			{
 				if (inputEvent.key.keysym.sym == SDLK_ESCAPE)
 				{
-					returnVal = 0;
-					ui.sysReqShown = false;
+					if (!inputEvent.key.repeat) // don't let previously held-down ESC immediately close the box
+					{
+						returnVal = 0;
+						ui.sysReqShown = false;
+					}
 				}
 				else if (inputEvent.key.keysym.sym == SDLK_RETURN)
 				{
--- a/src/ft2_textboxes.c
+++ b/src/ft2_textboxes.c
@@ -52,7 +52,7 @@
 
 	// ------ DISK OP. TEXTBOXES ------
 	// x,   y,   w,   h,  tx,ty, maxc,       rmb,   cmc
-	{   31, 158, 134,  12, 2, 1, PATH_MAX-1, false, true },
+	{   31, 158, 134,  12, 2, 1, PATH_MAX,   false, true },
 
 	// ------ CONFIG TEXTBOXES ------
 	// x,   y,   w,   h,  tx,ty, maxc,       rmb,   cmc
--- a/src/ft2_unicode.c
+++ b/src/ft2_unicode.c
@@ -57,7 +57,7 @@
 		return NULL;
 	}
 
-	char *x = (char *)malloc((reqSize + 2) * sizeof (char));
+	char *x = (char *)malloc((reqSize + 1) * sizeof (char));
 	if (x == NULL)
 	{
 		free(w);
@@ -64,8 +64,7 @@
 		return NULL;
 	}
 
-	x[reqSize+0] = '\0';
-	x[reqSize+1] = '\0';
+	x[reqSize] = '\0';
 
 	retVal = WideCharToMultiByte(CP_UTF8, 0, w, srcLen, x, reqSize, 0, 0);
 	free(w);
@@ -148,7 +147,7 @@
 		return NULL;
 	}
 
-	char *x = (char *)calloc(reqSize + 1, sizeof (char));
+	char *x = (char *)malloc((reqSize + 1) * sizeof (char));
 	if (x == NULL)
 	{
 		free(w);
@@ -216,7 +215,7 @@
 		{
 			const int8_t ch = (const int8_t)x[i];
 			if (ch < 32 && ch != 0 && ch != -124 && ch != -108 &&
-			    ch != -122 && ch != -114 && ch != -103 && ch != -113)
+				ch != -122 && ch != -114 && ch != -103 && ch != -113)
 			{
 				x[i] = ' '; // character not allowed, turn it into space
 			}
@@ -244,7 +243,7 @@
 
 	size_t outLen = srcLen * 2; // should be sufficient
 
-	char *outBuf = (char *)calloc(outLen + 2, sizeof (char));
+	char *outBuf = (char *)malloc((outLen + 1) * sizeof (char));
 	if (outBuf == NULL)
 		return NULL;
 
@@ -266,6 +265,8 @@
 		return NULL;
 	}
 
+	outBuf[outLen] = '\0';
+
 	return outBuf;
 }
 
@@ -290,7 +291,7 @@
 
 	size_t outLen = srcLen * 2; // should be sufficient
 
-	char *outBuf = (char *)calloc(outLen + 1, sizeof (char));
+	char *outBuf = (char *)malloc((outLen + 1) * sizeof (char));
 	if (outBuf == NULL)
 		return NULL;
 
@@ -312,6 +313,8 @@
 		return NULL;
 	}
 
+	outBuf[outLen] = '\0';
+
 	if (removeIllegalChars)
 	{
 		// remove illegal characters (only allow certain nordic ones)
@@ -319,7 +322,7 @@
 		{
 			const int8_t ch = (const int8_t)outBuf[i];
 			if (ch < 32 && ch != 0 && ch != -124 && ch != -108 &&
-			    ch != -122 && ch != -114 && ch != -103 && ch != -113)
+				ch != -122 && ch != -114 && ch != -103 && ch != -113)
 			{
 				outBuf[i] = ' '; // character not allowed, turn it into space
 			}
--- a/src/ft2_video.c
+++ b/src/ft2_video.c
@@ -46,7 +46,7 @@
 video_t video; // globalized
 
 static bool songIsModified;
-static char wndTitle[128 + PATH_MAX];
+static char wndTitle[256];
 static uint64_t timeNext64, timeNext64Frac;
 static sprite_t sprites[SPRITE_NUM];
 
@@ -845,10 +845,14 @@
 	char *songTitle = getCurrSongFilename();
 	if (songTitle != NULL)
 	{
+		char songTitleTrunc[128];
+		strncpy(songTitleTrunc, songTitle, sizeof (songTitleTrunc)-1);
+		songTitleTrunc[sizeof (songTitleTrunc)-1] = '\0';
+
 		if (song.isModified)
-			sprintf(wndTitle, "Fasttracker II clone v%s - \"%s\" (unsaved)", PROG_VER_STR, songTitle);
+			sprintf(wndTitle, "Fasttracker II clone v%s - \"%s\" (unsaved)", PROG_VER_STR, songTitleTrunc);
 		else
-			sprintf(wndTitle, "Fasttracker II clone v%s - \"%s\"", PROG_VER_STR, songTitle);
+			sprintf(wndTitle, "Fasttracker II clone v%s - \"%s\"", PROG_VER_STR, songTitleTrunc);
 	}
 	else
 	{
--- a/src/helpdata/FT2.HLP
+++ b/src/helpdata/FT2.HLP
@@ -923,10 +923,6 @@
 and you need to press a key or click the mouse to abort the render when you want
 it to.
 >@X010
->@C001Mouse / keyboard:
->
->@C002- Linux: The mouse cursor graphics can be glitchy at times...
->@X010
 >@C001Video:
 >@C002
 >@X010- Fullscreen mode can be unbearably slow on a Raspberry Pi (even on RPi 4)
--- a/src/helpdata/ft2_help_data.h
+++ b/src/helpdata/ft2_help_data.h
@@ -3,9 +3,9 @@
 
 #include <stdint.h>
 
-#define HELP_DATA_LEN 27486
+#define HELP_DATA_LEN 27385
 
-const uint8_t helpData[27486] =
+const uint8_t helpData[27385] =
 {
 	0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
 	0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
@@ -2258,46 +2258,38 @@
 	0x74,0x6F,0x20,0x61,0x62,0x6F,0x72,0x74,0x20,0x74,0x68,0x65,
 	0x20,0x72,0x65,0x6E,0x64,0x65,0x72,0x20,0x77,0x68,0x65,0x6E,
 	0x20,0x79,0x6F,0x75,0x20,0x77,0x61,0x6E,0x74,0x06,0x69,0x74,
-	0x20,0x74,0x6F,0x2E,0x06,0x3E,0x40,0x58,0x30,0x31,0x30,0x17,
-	0x3E,0x40,0x43,0x30,0x30,0x31,0x4D,0x6F,0x75,0x73,0x65,0x20,
-	0x2F,0x20,0x6B,0x65,0x79,0x62,0x6F,0x61,0x72,0x64,0x3A,0x01,
-	0x3E,0x43,0x3E,0x40,0x43,0x30,0x30,0x32,0x2D,0x20,0x4C,0x69,
-	0x6E,0x75,0x78,0x3A,0x20,0x54,0x68,0x65,0x20,0x6D,0x6F,0x75,
-	0x73,0x65,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x20,0x67,0x72,
-	0x61,0x70,0x68,0x69,0x63,0x73,0x20,0x63,0x61,0x6E,0x20,0x62,
-	0x65,0x20,0x67,0x6C,0x69,0x74,0x63,0x68,0x79,0x20,0x61,0x74,
-	0x20,0x74,0x69,0x6D,0x65,0x73,0x2E,0x2E,0x2E,0x06,0x3E,0x40,
-	0x58,0x30,0x31,0x30,0x0C,0x3E,0x40,0x43,0x30,0x30,0x31,0x56,
-	0x69,0x64,0x65,0x6F,0x3A,0x06,0x3E,0x40,0x43,0x30,0x30,0x32,
-	0x50,0x3E,0x40,0x58,0x30,0x31,0x30,0x2D,0x20,0x46,0x75,0x6C,
-	0x6C,0x73,0x63,0x72,0x65,0x65,0x6E,0x20,0x6D,0x6F,0x64,0x65,
-	0x20,0x63,0x61,0x6E,0x20,0x62,0x65,0x20,0x75,0x6E,0x62,0x65,
-	0x61,0x72,0x61,0x62,0x6C,0x79,0x20,0x73,0x6C,0x6F,0x77,0x20,
-	0x6F,0x6E,0x20,0x61,0x20,0x52,0x61,0x73,0x70,0x62,0x65,0x72,
-	0x72,0x79,0x20,0x50,0x69,0x20,0x28,0x65,0x76,0x65,0x6E,0x20,
-	0x6F,0x6E,0x20,0x52,0x50,0x69,0x20,0x34,0x29,0x01,0x3E,0x52,
-	0x3E,0x40,0x58,0x30,0x31,0x30,0x2D,0x20,0x4E,0x6F,0x74,0x20,
-	0x61,0x20,0x62,0x75,0x67,0x2C,0x20,0x62,0x75,0x74,0x20,0x69,
-	0x66,0x20,0x79,0x6F,0x75,0x72,0x20,0x6D,0x6F,0x6E,0x69,0x74,
-	0x6F,0x72,0x27,0x73,0x20,0x72,0x65,0x66,0x72,0x65,0x73,0x68,
-	0x20,0x72,0x61,0x74,0x65,0x20,0x69,0x73,0x20,0x6E,0x6F,0x74,
-	0x20,0x73,0x65,0x74,0x20,0x74,0x6F,0x20,0x36,0x30,0x48,0x7A,
-	0x20,0x28,0x6F,0x72,0x20,0x35,0x39,0x48,0x7A,0x29,0x4F,0x3E,
-	0x40,0x58,0x30,0x32,0x31,0x79,0x6F,0x75,0x20,0x6D,0x61,0x79,
-	0x20,0x65,0x78,0x70,0x65,0x72,0x69,0x65,0x6E,0x63,0x65,0x20,
-	0x76,0x69,0x73,0x75,0x61,0x6C,0x20,0x73,0x74,0x75,0x74,0x74,
-	0x65,0x72,0x69,0x6E,0x67,0x20,0x62,0x65,0x63,0x61,0x75,0x73,
-	0x65,0x20,0x56,0x53,0x79,0x6E,0x63,0x20,0x77,0x69,0x6C,0x6C,
-	0x20,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,
-	0x20,0x74,0x68,0x65,0x6E,0x2E,0x51,0x49,0x20,0x68,0x69,0x67,
-	0x68,0x6C,0x79,0x20,0x72,0x65,0x63,0x6F,0x6D,0x6D,0x65,0x6E,
-	0x64,0x20,0x72,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x79,0x6F,
-	0x75,0x72,0x20,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x20,0x61,
-	0x74,0x20,0x36,0x30,0x48,0x7A,0x20,0x69,0x66,0x20,0x79,0x6F,
-	0x75,0x27,0x72,0x65,0x20,0x61,0x20,0x68,0x61,0x72,0x64,0x63,
-	0x6F,0x72,0x65,0x20,0x75,0x73,0x65,0x72,0x20,0x6F,0x66,0x20,
-	0x74,0x68,0x69,0x73,0x08,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,
-	0x2E,0x00,0x03,0x45,0x4E,0x44
+	0x20,0x74,0x6F,0x2E,0x06,0x3E,0x40,0x58,0x30,0x31,0x30,0x0C,
+	0x3E,0x40,0x43,0x30,0x30,0x31,0x56,0x69,0x64,0x65,0x6F,0x3A,
+	0x06,0x3E,0x40,0x43,0x30,0x30,0x32,0x50,0x3E,0x40,0x58,0x30,
+	0x31,0x30,0x2D,0x20,0x46,0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,
+	0x65,0x6E,0x20,0x6D,0x6F,0x64,0x65,0x20,0x63,0x61,0x6E,0x20,
+	0x62,0x65,0x20,0x75,0x6E,0x62,0x65,0x61,0x72,0x61,0x62,0x6C,
+	0x79,0x20,0x73,0x6C,0x6F,0x77,0x20,0x6F,0x6E,0x20,0x61,0x20,
+	0x52,0x61,0x73,0x70,0x62,0x65,0x72,0x72,0x79,0x20,0x50,0x69,
+	0x20,0x28,0x65,0x76,0x65,0x6E,0x20,0x6F,0x6E,0x20,0x52,0x50,
+	0x69,0x20,0x34,0x29,0x01,0x3E,0x52,0x3E,0x40,0x58,0x30,0x31,
+	0x30,0x2D,0x20,0x4E,0x6F,0x74,0x20,0x61,0x20,0x62,0x75,0x67,
+	0x2C,0x20,0x62,0x75,0x74,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,
+	0x72,0x20,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x27,0x73,0x20,
+	0x72,0x65,0x66,0x72,0x65,0x73,0x68,0x20,0x72,0x61,0x74,0x65,
+	0x20,0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x73,0x65,0x74,0x20,
+	0x74,0x6F,0x20,0x36,0x30,0x48,0x7A,0x20,0x28,0x6F,0x72,0x20,
+	0x35,0x39,0x48,0x7A,0x29,0x4F,0x3E,0x40,0x58,0x30,0x32,0x31,
+	0x79,0x6F,0x75,0x20,0x6D,0x61,0x79,0x20,0x65,0x78,0x70,0x65,
+	0x72,0x69,0x65,0x6E,0x63,0x65,0x20,0x76,0x69,0x73,0x75,0x61,
+	0x6C,0x20,0x73,0x74,0x75,0x74,0x74,0x65,0x72,0x69,0x6E,0x67,
+	0x20,0x62,0x65,0x63,0x61,0x75,0x73,0x65,0x20,0x56,0x53,0x79,
+	0x6E,0x63,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6E,0x6F,0x74,0x20,
+	0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74,0x68,0x65,0x6E,
+	0x2E,0x51,0x49,0x20,0x68,0x69,0x67,0x68,0x6C,0x79,0x20,0x72,
+	0x65,0x63,0x6F,0x6D,0x6D,0x65,0x6E,0x64,0x20,0x72,0x75,0x6E,
+	0x6E,0x69,0x6E,0x67,0x20,0x79,0x6F,0x75,0x72,0x20,0x6D,0x6F,
+	0x6E,0x69,0x74,0x6F,0x72,0x20,0x61,0x74,0x20,0x36,0x30,0x48,
+	0x7A,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x27,0x72,0x65,0x20,
+	0x61,0x20,0x68,0x61,0x72,0x64,0x63,0x6F,0x72,0x65,0x20,0x75,
+	0x73,0x65,0x72,0x20,0x6F,0x66,0x20,0x74,0x68,0x69,0x73,0x08,
+	0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x2E,0x00,0x03,0x45,0x4E,
+	0x44
 };
 
 #endif
--- a/src/modloaders/ft2_load_s3m.c
+++ b/src/modloaders/ft2_load_s3m.c
@@ -287,10 +287,14 @@
 							case 1: // A
 							{
 								ton.effTyp = 0xF;
-								if (ton.eff == 0 || ton.eff > 0x1F)
+								if (ton.eff == 0)
 								{
 									ton.effTyp = 0;
 									ton.eff = 0;
+								}
+								else if (ton.eff > 0x1F)
+								{
+									ton.eff = 0x1F;
 								}
 							}
 							break;
--- a/vs2019_project/ft2-clone/ft2-clone.vcxproj.filters
+++ b/vs2019_project/ft2-clone/ft2-clone.vcxproj.filters
@@ -274,9 +274,6 @@
     <Filter Include="graphics">
       <UniqueIdentifier>{c6fad604-509b-4072-b181-d47835f08428}</UniqueIdentifier>
     </Filter>
-    <Filter Include="rtmidi">
-      <UniqueIdentifier>{95e882a1-e589-4684-a3cb-48e0a1d073aa}</UniqueIdentifier>
-    </Filter>
     <Filter Include="mixer">
       <UniqueIdentifier>{5c40c417-c4bb-4cf2-b71b-c557bf0a86cd}</UniqueIdentifier>
     </Filter>
@@ -285,6 +282,9 @@
     </Filter>
     <Filter Include="smploaders">
       <UniqueIdentifier>{62e7f7c0-f7ae-4b85-bd62-2c83f74e3953}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="rtmidi">
+      <UniqueIdentifier>{95e882a1-e589-4684-a3cb-48e0a1d073aa}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
   <ItemGroup>