shithub: pt2-clone

Download patch

ref: ba9a38b8266fd42f2bc327b7e6e60866812cbb92
parent: 462b3d46f1cb6d0e26539d4f8d5de7a85afeb430
author: Olav Sørensen <olav.sorensen@live.no>
date: Wed Jun 7 13:08:12 EDT 2023

A couple of minor changes to the visuals

--- a/src/pt2_edit.c
+++ b/src/pt2_edit.c
@@ -793,6 +793,7 @@
 				gotoNextMulti();
 		}
 
+		// PT quirk: spectrum analyzer is still handled here even if channel is muted
 		updateSpectrumAnalyzer(s->volume, tempPeriod);
 	}
 	else if (noteVal == -2)
--- 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.58"
+#define PROG_VER_STR "1.59"
 
 #ifdef _WIN32
 #define DIR_DELIMITER '\\'
--- a/src/pt2_keyboard.c
+++ b/src/pt2_keyboard.c
@@ -3467,10 +3467,10 @@
 		break;
 	}
 
-	keyb.repeatFrac += keyb.repeatDelta; // 32.32 fixed-point counter
-	if (keyb.repeatFrac > UINT32_MAX)
+	keyb.repeatFrac += video.amigaVblankDelta;  // 0.52 fixed-point
+	if (keyb.repeatFrac > 1ULL<<52)
 	{
-		keyb.repeatFrac &= UINT32_MAX;
+		keyb.repeatFrac &= (1ULL<<52)-1;
 		keyb.repeatCounter++;
 	}
 }
--- a/src/pt2_main.c
+++ b/src/pt2_main.c
@@ -493,9 +493,9 @@
 
 	editor.repeatKeyFlag = (SDL_GetModState() & KMOD_CAPS) ? true : false;
 
-	// set key repeat rate to 49.9204Hz (Amiga PAL vblank rate)
-	const double dVblankHzRatio = AMIGA_PAL_VBLANK_HZ / (double)VBLANK_HZ;
-	keyb.repeatDelta = (uint64_t)floor((UINT32_MAX+1.0) * dVblankHzRatio);
+	// 0.52 fixed-point delta for Amiga PAL vblank (~49.92Hz) at VBLANK_HZ (60.0Hz)
+	const double dRatio = AMIGA_PAL_VBLANK_HZ / (double)VBLANK_HZ;
+	video.amigaVblankDelta = (uint64_t)((dRatio * (1ULL << 52)) + 0.5);
 
 	strcpy(editor.mixText, "MIX 01+02 TO 03");
 
--- a/src/pt2_replayer.c
+++ b/src/pt2_replayer.c
@@ -374,9 +374,10 @@
 	setVisualsDataPtr(ch->n_chanindex, ch->n_loopstart);
 	setVisualsLength(ch->n_chanindex, ch->n_replen);
 
+	// set spectrum analyzer state for this channel
 	ch->syncAnalyzerVolume = ch->n_volume;
 	ch->syncAnalyzerPeriod = ch->n_period;
-	ch->syncFlags |= UPDATE_ANALYZER;
+	ch->syncFlags |= UPDATE_SPECTRUM_ANALYZER;
 
 	setVUMeterHeight(ch);
 }
@@ -988,6 +989,14 @@
 			setVisualsLength(ch->n_chanindex, 1);
 
 		setVisualsPeriod(ch->n_chanindex, ch->n_period);
+
+		// set spectrum analyzer state for this channel
+		if (!editor.muted[ch->n_chanindex])
+		{
+			ch->syncAnalyzerVolume = ch->n_volume;
+			ch->syncAnalyzerPeriod = ch->n_period;
+			ch->syncFlags |= UPDATE_SPECTRUM_ANALYZER;
+		}
 	}
 
 	checkMoreEffects(ch);
@@ -1247,13 +1256,7 @@
 	for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
 	{
 		if (DMACONtemp & ch->n_dmabit) // handle visuals on sample trigger
-		{
-			ch->syncAnalyzerVolume = ch->n_volume;
-			ch->syncAnalyzerPeriod = ch->n_period;
-			ch->syncFlags |= UPDATE_ANALYZER;
-
 			setVUMeterHeight(ch);
-		}
 
 		// these take effect after the current DMA cycle is done
 		const uint32_t voiceAddr = 0xDFF0A0 + (i * 16);
--- a/src/pt2_sampler.c
+++ b/src/pt2_sampler.c
@@ -1833,6 +1833,7 @@
 
 	unlockAudio();
 
+	// PT quirk: spectrum analyzer is still handled here even if channel is muted
 	updateSpectrumAnalyzer(ch->n_volume, ch->n_period);
 }
 
--- a/src/pt2_scopes.c
+++ b/src/pt2_scopes.c
@@ -84,7 +84,11 @@
 
 void scopeSetPeriod(int32_t ch, int32_t period)
 {
-	assert(period >= 113 && period <= 65535);
+	period &= 0xFFFF;
+
+	if (period < 113) // just in case, should already be clamped
+		period = 113;
+
 	scope[ch].dDelta = (PAULA_PAL_CLK / (double)SCOPE_HZ) / period;
 }
 
@@ -180,7 +184,7 @@
 		if (!tmpScope.active || tmpScope.data == NULL || tmpScope.volume == 0 || tmpScope.length == 0)
 			continue;
 
-		// amount of integer samples getting skipped every frame
+		// amount of integer samples getting skipped every frame (periods < 113 are clamped, this number can't get big)
 		const int32_t samplesToScan = (const int32_t)tmpScope.dDelta;
 		if (samplesToScan <= 0)
 			continue;
@@ -246,7 +250,7 @@
 			int16_t scopeData;
 			int32_t pos = tmpScope.pos;
 			int32_t length = tmpScope.length;
-			const int16_t volume = -(tmpScope.volume << 7);
+			const int8_t volume = -(tmpScope.volume >> 1);
 			const int8_t *data = tmpScope.data;
 			uint32_t *scopeDrawPtr = &video.frameBuffer[(71 * SCREEN_W) + scopeX];
 
@@ -254,7 +258,7 @@
 			{
 				scopeData = 0;
 				if (data != NULL)
-					scopeData = (data[pos] * volume) >> 16;
+					scopeData = (data[pos] * volume) >> 8;
 
 				scopeDrawPtr[(scopeData * SCREEN_W) + x] = fgColor;
 
--- a/src/pt2_structs.h
+++ b/src/pt2_structs.h
@@ -112,7 +112,7 @@
 	bool shiftPressed, leftCtrlPressed, leftAltPressed;
 	bool leftCommandPressed, leftAmigaPressed, keypadEnterPressed;
 	uint8_t repeatCounter, delayCounter;
-	uint64_t repeatDelta, repeatFrac;
+	uint64_t repeatFrac;
 	SDL_Scancode lastRepKey, lastKey;
 } keyb_t;
 
@@ -135,6 +135,7 @@
 	hpc_t vblankHpc;
 	SDL_PixelFormat *pixelFormat;
 	uint32_t *frameBuffer;
+	uint64_t amigaVblankDelta; // 0.52 fixed-point
 
 	SDL_Window *window;
 	SDL_Renderer *renderer;
@@ -149,7 +150,7 @@
 
 typedef struct editor_t
 {
-	volatile int8_t vuMeterVolumes[PAULA_VOICES], spectrumVolumes[SPECTRUM_BAR_NUM];
+	volatile uint8_t vuMeterVolumes[PAULA_VOICES], spectrumVolumes[SPECTRUM_BAR_NUM];
 	volatile int8_t *sampleFromDisp, *sampleToDisp, *currSampleDisp, realVuMeterVolumes[PAULA_VOICES], mod2WavNumLoops, mod2WavFadeOutSeconds;
 	volatile bool songPlaying, programRunning, mod2WavOngoing, pat2SmpOngoing, mainLoopOngoing, abortMod2Wav, mod2WavFadeOut;
 	volatile uint16_t *quantizeValueDisp, *metroSpeedDisp, *metroChannelDisp, *sampleVolDisp;
--- a/src/pt2_visuals.c
+++ b/src/pt2_visuals.c
@@ -1731,55 +1731,66 @@
 		audio.resetSyncTickTimeFlag = true;
 }
 
-void updateSpectrumAnalyzer(int8_t vol, int16_t period)
+void updateSpectrumAnalyzer(uint8_t vol, uint16_t period)
 {
-	const uint8_t maxHeight = SPECTRUM_BAR_HEIGHT + 1; // +1 because of audio latency - allows full height to be seen
+	if (ui.visualizerMode != VISUAL_SPECTRUM || vol == 0)
+		return;
 
-	if (ui.visualizerMode != VISUAL_SPECTRUM || vol <= 0)
+	/* This routine is buggy in real PT. Behavior for periods outside of 108..907 is undefined.
+	** Behavior for sane input outside of 113..856 (B-3 finetune > 0 and C-1 finetune < 0)
+	** seems to be defined, and we simulate this.
+	*/
+	if (period < 108 || period > 907)
+		return; // we don't really know what to do here
+
+	// C-1 with finetune < 0 is ignored (confirmed behavior)
+	if (period > 856)
 		return;
 
-	uint16_t scaledVol = ((uint16_t)vol * 24576) >> 16; // scaledVol = vol / 2.66667 (0..64 -> 0..24)
+	// B-3 with finetune > 0 behaves like finetune 0 (confirmed behavior)
+	if (period < 113)
+		period = 113;
 
-	period = CLAMP(period, 113, 856);
-	period -= 113;
+	// just in case
+	if (vol > 64)
+		vol = 64;
 
-	uint32_t scaledNote = 743 - period;
-	scaledNote *= scaledNote;
-	scaledNote /= 25093; // scaledNote now ranges 0..22, no need to clamp
+	const uint8_t vol24 = (vol * 24) >> 6; // 0..64 -> 0..24
 
-	// increment main spectrum bar
-	editor.spectrumVolumes[scaledNote] += (uint8_t)scaledVol;
-	if (editor.spectrumVolumes[scaledNote] > maxHeight)
-		editor.spectrumVolumes[scaledNote] = maxHeight;
+	// convert period from log (113..856) to linear (0..22)
+	period = (856 - 113) - (period - 113); // 0..743 (inverted)
+	const uint32_t index = (period * period) / 25093; // 0..22 (25093 = round[743^2 / 22])
 
-	// increment left side of spectrum bar with half volume
-	if (scaledNote > 0)
+	// increment bar
+	editor.spectrumVolumes[index] += vol24;
+	if (editor.spectrumVolumes[index] > SPECTRUM_BAR_HEIGHT)
+		editor.spectrumVolumes[index] = SPECTRUM_BAR_HEIGHT;
+
+	// increment left and right neighbor bars with half the volume
+
+	if (index > 0)
 	{
-		editor.spectrumVolumes[scaledNote-1] += (uint8_t)(scaledVol >> 1);
-		if (editor.spectrumVolumes[scaledNote-1] > maxHeight)
-			editor.spectrumVolumes[scaledNote-1] = maxHeight;
+		editor.spectrumVolumes[index-1] += vol24 / 2;
+		if (editor.spectrumVolumes[index-1] > SPECTRUM_BAR_HEIGHT)
+			editor.spectrumVolumes[index-1] = SPECTRUM_BAR_HEIGHT;
 	}
 
-	// increment right side of spectrum bar with half volume
-	if (scaledNote < SPECTRUM_BAR_NUM-1)
+	if (index < SPECTRUM_BAR_NUM-1)
 	{
-		editor.spectrumVolumes[scaledNote+1] += (uint8_t)(scaledVol >> 1);
-		if (editor.spectrumVolumes[scaledNote+1] > maxHeight)
-			editor.spectrumVolumes[scaledNote+1] = maxHeight;
+		editor.spectrumVolumes[index+1] += vol24 / 2;
+		if (editor.spectrumVolumes[index+1] > SPECTRUM_BAR_HEIGHT)
+			editor.spectrumVolumes[index+1] = SPECTRUM_BAR_HEIGHT;
 	}
 }
 
-void sinkVisualizerBars(void)
+void sinkVisualizerBars(void) // sinks visualizer bars @ 49.92Hz (Amiga PAL) rate
 {
-	// sink visualizer bars @ 49.92Hz (Amiga PAL) rate
+	static uint64_t counter50Hz; // pre-initialized to zero because of static
 
-	static uint64_t counter50Hz;
-	const uint64_t counter50HzDelta = (uint64_t)(((UINT32_MAX+1.0) * (AMIGA_PAL_VBLANK_HZ / (double)VBLANK_HZ)) + 0.5);
-
-	counter50Hz += counter50HzDelta; // 32.32 fixed-point counter
-	if (counter50Hz > UINT32_MAX)
+	counter50Hz += video.amigaVblankDelta; // 0.52 fixed-point
+	if (counter50Hz > 1ULL<<52)
 	{
-		counter50Hz &= UINT32_MAX;
+		counter50Hz &= (1ULL<<52)-1;
 
 		// sink VU-meters
 		for (int32_t i = 0; i < PAULA_VOICES; i++)
--- a/src/pt2_visuals.h
+++ b/src/pt2_visuals.h
@@ -43,7 +43,7 @@
 void renderFrame2(void);
 void renderFrame(void);
 void flipFrame(void);
-void updateSpectrumAnalyzer(int8_t vol, int16_t period);
+void updateSpectrumAnalyzer(uint8_t vol, uint16_t period);
 void sinkVisualizerBars(void);
 void updatePosEd(void);
 void updateVisualizer(void);
--- a/src/pt2_visuals_sync.c
+++ b/src/pt2_visuals_sync.c
@@ -375,7 +375,7 @@
 
 			// ---------------------------------------------------------------
 
-			if (flags & UPDATE_ANALYZER)
+			if (flags & UPDATE_SPECTRUM_ANALYZER)
 				updateSpectrumAnalyzer(c->analyzerVolume, c ->analyzerPeriod);
 
 			if (flags & UPDATE_VUMETER) // for fake VU-meters only
--- a/src/pt2_visuals_sync.h
+++ b/src/pt2_visuals_sync.h
@@ -14,7 +14,7 @@
 	STOP_SCOPE = 32,
 
 	UPDATE_VUMETER = 64,
-	UPDATE_ANALYZER = 128
+	UPDATE_SPECTRUM_ANALYZER = 128
 };
 
 // 2^n-1 - don't change this! Total queue buffer length is already big.