shithub: ft²

Download patch

ref: f8c0ccfded8a6d486a63061a31e39156332a21c7
parent: f1d002c3f3a0e7792aca42f6731899d8cba02f50
author: Olav Sørensen <olav.sorensen@live.no>
date: Wed May 13 08:52:16 EDT 2020

Pushed v1.24 code

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

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