shithub: pt2-clone

Download patch

ref: fd5d4165735a0881ef0ccb9e52f22fb0f4f1bcc4
parent: 03d0c96c3f0070c59150c1d53c884ff6db6268c8
author: Olav Sørensen <olav.sorensen@live.no>
date: Sun Oct 10 16:36:04 EDT 2021

Pushed v1.35 code

- Implemented a config entry in protracker.ini for disabling the 2x downsample dialog that shows up when attempting to load >22kHz samples (NO_DWNSMP_ON_SMP_LOAD)
- Don't attempt to center window after leaving fullscreen mode. This could lead to issues on multi-monitor setups.
- Further accuracy changes to the Paula emulator. Read two samples at once into the AUDxDAT buffer. This is a minor change, but it can have a very small impact on sample-changing commands (EFx/E8x).

--- a/release/macos/protracker.ini
+++ b/release/macos/protracker.ini
@@ -80,6 +80,12 @@
 HWMOUSE=TRUE
 
 [GENERAL SETTINGS]
+; Don't show downsample dialog after loading a sample whose frequency is >22kHz.
+;        Syntax: TRUE or FALSE
+; Default value: FALSE
+;
+NO_DWNSMP_ON_SMP_LOAD=FALSE
+
 ; Hide last modification dates in Disk Op. to get longer dir/file names
 ;        Syntax: TRUE or FALSE
 ; Default value: FALSE
--- a/release/other/protracker.ini
+++ b/release/other/protracker.ini
@@ -80,6 +80,12 @@
 HWMOUSE=TRUE
 
 [GENERAL SETTINGS]
+; Don't show downsample dialog after loading a sample whose frequency is >22kHz.
+;        Syntax: TRUE or FALSE
+; Default value: FALSE
+;
+NO_DWNSMP_ON_SMP_LOAD=FALSE
+
 ; Hide last modification dates in Disk Op. to get longer dir/file names
 ;        Syntax: TRUE or FALSE
 ; Default value: FALSE
--- a/release/win32/protracker.ini
+++ b/release/win32/protracker.ini
@@ -80,6 +80,12 @@
 HWMOUSE=TRUE
 
 [GENERAL SETTINGS]
+; Don't show downsample dialog after loading a sample whose frequency is >22kHz.
+;        Syntax: TRUE or FALSE
+; Default value: FALSE
+;
+NO_DWNSMP_ON_SMP_LOAD=FALSE
+
 ; Hide last modification dates in Disk Op. to get longer dir/file names
 ;        Syntax: TRUE or FALSE
 ; Default value: FALSE
--- a/release/win64/protracker.ini
+++ b/release/win64/protracker.ini
@@ -80,6 +80,12 @@
 HWMOUSE=TRUE
 
 [GENERAL SETTINGS]
+; Don't show downsample dialog after loading a sample whose frequency is >22kHz.
+;        Syntax: TRUE or FALSE
+; Default value: FALSE
+;
+NO_DWNSMP_ON_SMP_LOAD=FALSE
+
 ; Hide last modification dates in Disk Op. to get longer dir/file names
 ;        Syntax: TRUE or FALSE
 ; Default value: FALSE
--- a/src/pt2_audio.c
+++ b/src/pt2_audio.c
@@ -277,13 +277,12 @@
 		v->dOldVoiceDeltaMul = 1.0 / v->dOldVoiceDelta;
 	}
 
-	v->dNewDelta = v->dOldVoiceDelta;
-	if (v->dLastDelta == 0.0) // for BLEP
-		v->dLastDelta = v->dNewDelta;
-
-	v->dNewDeltaMul = v->dOldVoiceDeltaMul;
-	if (v->dLastDeltaMul == 0.0) // for BLEP
-		v->dLastDeltaMul = v->dNewDeltaMul;
+	v->AUD_PER_delta = v->dOldVoiceDelta;
+	
+	// set BLEP stuff
+	v->dDeltaMul = v->dOldVoiceDeltaMul;
+	if (v->dLastDelta == 0.0)
+		v->dLastDelta = v->AUD_PER_delta;
 }
 
 void paulaSetVolume(int32_t ch, uint16_t vol)
@@ -299,7 +298,7 @@
 	// ------------------------
 
 	// multiplying by this also scales the sample from -128..127 -> -1.0 .. ~0.99
-	v->dScaledVolume = realVol * (1.0 / (128.0 * 64.0));
+	v->AUD_VOL = realVol * (1.0 / (128.0 * 64.0));
 
 	if (editor.songPlaying)
 	{
@@ -316,26 +315,12 @@
 {
 	paulaVoice_t *v = &paula[ch];
 
-	int32_t realLength = len;
-	if (realLength == 0)
-	{
-		realLength = 1+65535;
-		/* Confirmed behavior on real Amiga. We have room for this
-		** even at the last sample slot, so it will never overflow!
-		**
-		** PS: I don't really know if it's possible for ProTracker to
-		** set a Paula length of 0, but I fully support this Paula
-		** behavior just in case.
-		*/
-	}
+	v->AUD_LEN = len;
 
-	realLength <<= 1; // we work with bytes, not words
-
-	v->newLength = realLength;
 	if (editor.songPlaying)
 		v->syncFlags |= SET_SCOPE_LENGTH;
 	else
-		scope[ch].newLength = realLength;
+		scope[ch].newLength = len*2;
 }
 
 void paulaSetData(int32_t ch, const int8_t *src)
@@ -345,7 +330,8 @@
 	if (src == NULL)
 		src = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample
 
-	v->newData = src;
+	v->AUD_LC = src;
+
 	if (editor.songPlaying)
 		v->syncFlags |= SET_SCOPE_DATA;
 	else
@@ -368,34 +354,33 @@
 {
 	paulaVoice_t *v = &paula[ch];
 
-	const int8_t *dat = v->newData;
+	const int8_t *dat = v->AUD_LC;
 	if (dat == NULL)
 		dat = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample
 
-	int32_t length = v->newLength; // in bytes, not words
-	if (length == 0)
-		length = 1+65535;
+	/* This is not really accurate to what happens on Paula
+	** during DMA start, but it's good enough.
+	*/
 
-	v->dPhase = v->dLastPhase = 0.0;
-	v->pos = 0;
-	v->data = dat;
-	v->length = length;
-	v->dDelta = v->dLastDelta = v->dNewDelta;
-	v->dDeltaMul = v->dLastDeltaMul = v->dNewDeltaMul;
+	v->dDelta = v->AUD_PER_delta;
+	v->location = v->AUD_LC;
+	v->lengthCounter = v->AUD_LEN;
 
-	/* Read first sample data point into cache now.
-	**
-	** (multiplying by dScaledVolume will also change the scale
-	**  from -128..127 to -1.0 .. ~0.99.)
-	*/
-	v->dCachedSamplePoint = v->data[0] * v->dScaledVolume;
+	v->dSample = 0.0;
+	v->sampleCounter = 0; // read new DMA data samples ASAP
 
+	// set BLEP stuff
+	v->dLastPhase = 0.0;
+	v->dLastDelta = v->dDelta;
+	v->dBlepOffset = 0.0;
+
+	v->dPhase = 0.0;
 	v->DMA_active = true;
 
 	if (editor.songPlaying)
 	{
 		v->syncTriggerData = dat;
-		v->syncTriggerLength = length;
+		v->syncTriggerLength = v->AUD_LEN * 2;
 		v->syncFlags |= TRIGGER_SCOPE;
 	}
 	else
@@ -402,7 +387,7 @@
 	{
 		scope_t *s = &scope[ch];
 		s->newData = dat;
-		s->newLength = length;
+		s->newLength = v->AUD_LEN * 2;
 		scopeTrigger(ch);
 	}
 }
@@ -448,20 +433,17 @@
 		** is temporarily forced offline, and its voice pointers are
 		** cleared to prevent expired pointer addresses.
 		*/
-		if (!v->DMA_active || v->data == NULL)
+		if (!v->DMA_active || v->location == NULL || v->AUD_LC == NULL)
 			continue;
 
 		double *dMixBuf = dMixBufSelect[i]; // what output channel to mix into (L, R, R, L)
 		for (int32_t j = 0; j < numSamples; j++)
 		{
-			double dSmp = v->dCachedSamplePoint;
+			double dSmp = v->dSample;
 			if (dSmp != bSmp->dLastValue)
 			{
 				if (v->dLastDelta > v->dLastPhase)
-				{
-					// v->dLastDeltaMul is (1.0 / v->dLastDelta) (pre-computed for speed, div -> mul)
-					blepAdd(bSmp, v->dLastPhase * v->dLastDeltaMul, bSmp->dLastValue - dSmp);
-				}
+					blepAdd(bSmp, v->dBlepOffset, bSmp->dLastValue - dSmp);
 
 				bSmp->dLastValue = dSmp;
 			}
@@ -476,33 +458,40 @@
 			{
 				v->dPhase -= 1.0;
 
-				// Paula only updates period (delta) during sample fetching
-				v->dDelta = v->dNewDelta;
-				v->dDeltaMul = v->dNewDeltaMul;
-				// --------------------------------------------------------
+				// Paula only updates period (delta) during period refetching (this stage)
+				v->dDelta = v->AUD_PER_delta;
 
-				v->dLastPhase = v->dPhase;
-				v->dLastDelta = v->dDelta;
-				v->dLastDeltaMul = v->dDeltaMul;
-
-				if (++v->pos >= v->length)
+				if (v->sampleCounter == 0)
 				{
-					v->pos = 0;
+					// it's time to read new samples from DMA
 
-					// re-fetch new Paula register values now
-					v->length = v->newLength;
-					v->data = v->newData;
+					if (--v->lengthCounter == 0)
+					{
+						v->lengthCounter = v->AUD_LEN;
+						v->location = v->AUD_LC;
+					}
+
+					// fill DMA data buffer
+					v->AUD_DAT[0] = *v->location++;
+					v->AUD_DAT[1] = *v->location++;
+					v->sampleCounter = 2;
 				}
 
-				/* Read sample into cache now.
-				** Also change volume here as well. It has recently been
-				** discovered that Paula only updates its volume during period
-				** fetching (when it's reading the next sample point).
-				**
-				** (multiplying by dScaledVolume will also change the scale
-				**  from -128..127 to -1.0 .. ~0.99.)
+				/* Pre-compute current sample point.
+				** Output volume is only read from AUDxVOL at this stage,
+				** and we don't emulate volume PWM anyway, so we can
+				** pre-multiply by volume at this point.
 				*/
-				v->dCachedSamplePoint = v->data[v->pos] * v->dScaledVolume;
+				v->dSample = v->AUD_DAT[0] * v->AUD_VOL; // -128..127 * 0.0 .. 1.0
+
+				// progress AUD_DAT buffer
+				v->AUD_DAT[0] = v->AUD_DAT[1];
+				v->sampleCounter--;
+
+				// setup BLEP stuff
+				v->dBlepOffset = v->dPhase * v->dDeltaMul;
+				v->dLastPhase = v->dPhase;
+				v->dLastDelta = v->dDelta;
 			}
 		}
 	}
@@ -881,7 +870,6 @@
 				}
 			}
 		}
-
 	}
 }
 
@@ -910,8 +898,8 @@
 		s->period = v->syncPeriod;
 		s->triggerData = v->syncTriggerData;
 		s->triggerLength = v->syncTriggerLength;
-		s->newData = v->newData;
-		s->newLength = v->newLength;
+		s->newData = v->AUD_LC;
+		s->newLength = v->AUD_LEN * 2;
 		s->vuVolume = c->syncVuVolume;
 		s->analyzerVolume = c->syncAnalyzerVolume;
 		s->analyzerPeriod = c->syncAnalyzerPeriod;
--- a/src/pt2_audio.h
+++ b/src/pt2_audio.h
@@ -27,11 +27,21 @@
 {
 	volatile bool DMA_active;
 
-	const int8_t *data, *newData;
-	int32_t length, newLength, pos;
+	// internal values (don't modify directly!)
+	int8_t AUD_DAT[2]; // DMA data buffer
+	const int8_t* location; // current location
+	uint16_t lengthCounter; // current length
+	int32_t sampleCounter; // how many bytes left in AUD_DAT
+	double dSample; // current sample point
 
-	double dDelta, dDeltaMul, dPhase, dLastDelta, dLastDeltaMul, dLastPhase;
-	double dCachedSamplePoint, dScaledVolume, dNewDelta, dNewDeltaMul;
+	// registers modified by Paula functions
+	const int8_t* AUD_LC; // location
+	uint16_t AUD_LEN; // length (in words)
+	double AUD_PER_delta; // delta
+	double AUD_VOL; // volume
+
+	double dBlepOffset, dDelta, dPhase, dLastDelta, dLastPhase;
+	double dScaledVolume, dDeltaMul;
 
 	// period cache
 	int32_t oldPeriod;
--- a/src/pt2_config.c
+++ b/src/pt2_config.c
@@ -42,6 +42,7 @@
 	FILE *f;
 
 	// set default config values first
+	config.noDownsampleOnSmpLoad = false;
 	config.disableE8xEffect = false;
 	config.fullScreenStretch = false;
 	config.pattDots = false;
@@ -191,6 +192,13 @@
 		{
 			configLine = strtok(NULL, "\n");
 			continue;
+		}
+
+		// NO_DWNSMP_ON_SMP_LOAD (no dialog for 2x downsample after >22kHz sample load)
+		else if (!_strnicmp(configLine, "NO_DWNSMP_ON_SMP_LOAD=", 22))
+		{
+			if (!_strnicmp(&configLine[22], "TRUE", 4)) config.noDownsampleOnSmpLoad = true;
+			else if (!_strnicmp(&configLine[22], "FALSE", 5)) config.noDownsampleOnSmpLoad = false;
 		}
 
 		// DISABLE_E8X (Karplus-Strong command)
--- a/src/pt2_config.h
+++ b/src/pt2_config.h
@@ -15,7 +15,7 @@
 	char *defModulesDir, *defSamplesDir;
 	bool waveformCenterLine, pattDots, compoMode, autoCloseDiskOp, hideDiskOpDates, hwMouse;
 	bool transDel, fullScreenStretch, vsyncOff, modDot, blankZeroFlag, realVuMeters, rememberPlayMode;
-	bool startInFullscreen, integerScaling, disableE8xEffect;
+	bool startInFullscreen, integerScaling, disableE8xEffect, noDownsampleOnSmpLoad;
 	int8_t stereoSeparation, videoScaleFactor, accidental;
 	uint8_t pixelFilter, filterModel;
 	uint16_t quantizeValue;
--- a/src/pt2_header.h
+++ b/src/pt2_header.h
@@ -14,7 +14,7 @@
 #include "pt2_unicode.h"
 #include "pt2_palette.h"
 
-#define PROG_VER_STR "1.34"
+#define PROG_VER_STR "1.35"
 
 #ifdef _WIN32
 #define DIR_DELIMITER '\\'
--- a/src/pt2_sample_loader.c
+++ b/src/pt2_sample_loader.c
@@ -239,7 +239,7 @@
 		return false;
 	}
 
-	if (sampleRate > 22050)
+	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
 	{
 		if (forceDownSampling == -1)
 		{
@@ -884,7 +884,7 @@
 		return false;
 	}
 
-	if (sampleRate > 22050)
+	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
 	{
 		if (forceDownSampling == -1)
 		{
@@ -1322,7 +1322,7 @@
 		return false;
 	}
 
-	if (sampleRate > 22050)
+	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
 	{
 		if (forceDownSampling == -1)
 		{
--- a/src/pt2_visuals.c
+++ b/src/pt2_visuals.c
@@ -342,7 +342,7 @@
 	renderBigAskDialog();
 
 	textOutTight(133, 49, "THE SAMPLE'S FREQUENCY IS", video.palette[PAL_BACKGRD]);
-	textOutTight(178, 57, "ABOVE 22KHZ.", video.palette[PAL_BACKGRD]);
+	textOutTight(154, 57, "HIGH (ABOVE 22KHZ).", video.palette[PAL_BACKGRD]);
 	textOutTight(133, 65, "DO YOU WANT TO DOWNSAMPLE", video.palette[PAL_BACKGRD]);
 	textOutTight(156, 73, "BEFORE LOADING IT?", video.palette[PAL_BACKGRD]);
 }
@@ -2304,7 +2304,10 @@
 		SDL_SetWindowFullscreen(video.window, 0);
 		SDL_RenderSetLogicalSize(video.renderer, SCREEN_W, SCREEN_H);
 		SDL_SetWindowSize(video.window, SCREEN_W * config.videoScaleFactor, SCREEN_H * config.videoScaleFactor);
-		SDL_SetWindowPosition(video.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+
+		// this is not sensible on a multi-monitor setup
+		//SDL_SetWindowPosition(video.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+
 		SDL_SetWindowGrab(video.window, SDL_FALSE);
 	}
 
--- a/vs2019_project/pt2-clone/protracker.ini
+++ b/vs2019_project/pt2-clone/protracker.ini
@@ -80,6 +80,12 @@
 HWMOUSE=TRUE
 
 [GENERAL SETTINGS]
+; Don't show downsample dialog after loading a sample whose frequency is >22kHz.
+;        Syntax: TRUE or FALSE
+; Default value: FALSE
+;
+NO_DWNSMP_ON_SMP_LOAD=FALSE
+
 ; Hide last modification dates in Disk Op. to get longer dir/file names
 ;        Syntax: TRUE or FALSE
 ; Default value: FALSE