diff win95kggui/dep/ft2play/pmp_mix.c @ 126:8e4ee43d3b81

remove submodules
author Paper <mrpapersonic@gmail.com>
date Sun, 01 Oct 2023 03:48:43 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/win95kggui/dep/ft2play/pmp_mix.c	Sun Oct 01 03:48:43 2023 -0400
@@ -0,0 +1,381 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "pmplay.h"
+#include "pmp_main.h"
+#include "snd_masm.h"
+#include "tables.h"
+
+// fast 32-bit -> 16-bit clamp
+#define CLAMP16(i) if ((int16_t)(i) != i) i = 0x7FFF ^ (i >> 31)
+
+static bool dump_Flag;
+static int32_t oldReplayRate;
+
+// globalized
+int16_t chnReloc[32];
+int32_t *CDA_MixBuffer = NULL;
+CIType CI[32 * 2];
+// ------------
+
+static void mix_UpdateChannel(int32_t nr, WaveChannelInfoType *WCI);
+
+void P_SetSpeed(uint16_t bpm)
+{
+	// 8bb: added this
+	if (bpm == 0)
+		bpm = 125;
+
+	speedVal = ((realReplayRate + realReplayRate) + (realReplayRate >> 1)) / bpm; // 8bb: same as doing "((realReplayRate * 5) / 2) / bpm"
+}
+
+void P_StartTone(sampleTyp *s, int32_t smpStartPos)
+{
+	WaveChannelInfoType WCI;
+
+	WCI.SStartPos = smpStartPos;
+	WCI.SBase = s->pek;
+	WCI.SLen = s->len;
+	WCI.SRepS = s->repS;
+	WCI.SRepL = s->repL;
+	WCI.SType = s->typ;
+	WCI.Status = Status_StartTone+Status_StopTone;
+
+	mix_UpdateChannel(PMPTmpActiveChannel, &WCI);
+}
+
+// 8bb: added these two
+bool mix_Init(int32_t audioBufferSize)
+{
+	CDA_MixBuffer = (int32_t *)malloc(audioBufferSize * 2 * sizeof (int32_t));
+	if (CDA_MixBuffer == NULL)
+		return false;
+
+	PMPLeft = 0;
+	return true;
+}
+
+void mix_Free(void)
+{
+	if (CDA_MixBuffer != NULL)
+	{
+		free(CDA_MixBuffer);
+		CDA_MixBuffer = NULL;
+	}
+}
+// --------------------
+
+static void updateVolume(CIType *v, int32_t volIPLen)
+{
+	const uint32_t vol = v->SVol * CDA_Amp;
+
+	v->SLVol1 = (vol * panningTab[256-v->SPan]) >> (32-28);
+	v->SRVol1 = (vol * panningTab[    v->SPan]) >> (32-28);
+
+	if (volumeRampingFlag)
+	{
+		v->SLVolIP = (v->SLVol1 - v->SLVol2) / volIPLen;
+		v->SRVolIP = (v->SRVol1 - v->SRVol2) / volIPLen;
+		v->SVolIPLen = volIPLen;
+	}
+}
+
+static void mix_UpdateChannel(int32_t nr, WaveChannelInfoType *WCI)
+{
+	CIType *v = &CI[chnReloc[nr]];
+	const uint8_t status = WCI->Status;
+
+	if (status & Status_StopTone)
+	{
+		if (volumeRampingFlag)
+		{
+			// 8bb: fade out current voice
+			v->SType |= SType_Fadeout;
+			v->SVol = 0;
+			updateVolume(v, quickVolSizeVal);
+
+			// 8bb: swap current voice with neighbor
+			chnReloc[nr] ^= 1;
+			v = &CI[chnReloc[nr]];
+		}
+
+		v->SType = SType_Off;
+	}
+
+	if (status & Status_SetPan)
+		v->SPan = (uint8_t)WCI->SPan;
+
+	if (status & Status_SetVol)
+	{
+		uint16_t vol = WCI->SVol;
+		if (vol > 0) vol--; // 8bb: 0..256 -> 0..255 ( FT2 does this to prevent mul overflow in updateVolume() )
+		v->SVol = (uint8_t)vol;
+	}
+
+	if (status & (Status_SetVol+Status_SetPan))
+		updateVolume(v, (status & Status_QuickVol) ? quickVolSizeVal : speedVal);
+
+	if (status & Status_SetFrq)
+		v->SFrq = WCI->SFrq;
+
+	if (status & Status_StartTone)
+	{
+		int32_t len;
+
+		uint8_t type = WCI->SType;
+		const bool sample16Bit = (type >> 4) & 1;
+
+		if (type & (SType_Fwd+SType_Rev))
+		{
+			int32_t repL = WCI->SRepL;
+			int32_t repS = WCI->SRepS;
+
+			if (sample16Bit)
+			{
+				repL >>= 1;
+				repS >>= 1;
+
+				v->SRevBase = (int16_t *)WCI->SBase + (repS+repS+repL);
+			}
+			else
+			{
+				v->SRevBase = (int8_t *)WCI->SBase + (repS+repS+repL);
+			}
+
+			v->SRepL = repL;
+			v->SRepS = repS;
+
+			len = repS + repL;
+		}
+		else
+		{
+			type &= ~(SType_Fwd+SType_Rev); // 8bb: keep loop flags only
+
+			len = WCI->SLen;
+			if (sample16Bit)
+				len >>= 1;
+
+			if (len == 0)
+				return;
+		}
+		
+		// 8bb: overflown 9xx (set sample offset), cut voice (voice got ended earlier in "if (status & Status_StopTone)")
+		if (WCI->SStartPos >= len)
+			return;
+
+		v->SLen = len;
+		v->SPos = WCI->SStartPos;
+		v->SPosDec = 0;
+		v->SBase = WCI->SBase;
+		v->SMixType = (sample16Bit * 4) + (volumeRampingFlag * 2) + interpolationFlag;
+		v->SType = type;
+	}
+}
+
+static void mix_UpdateChannelVolPanFrq(void)
+{
+	WaveChannelInfoType WCI;
+
+	stmTyp *ch = stm;
+	for (int32_t i = 0; i < song.antChn; i++, ch++)
+	{
+		uint8_t newStatus = 0;
+
+		const uint8_t status = ch->status;
+		ch->status = 0;
+
+		if (status == 0)
+			continue;
+
+		if (status & IS_Vol)
+		{
+			WCI.SVol = ch->finalVol;
+			newStatus |= Status_SetVol;
+		}
+
+		if (status & IS_QuickVol)
+			newStatus |= Status_QuickVol;
+
+		if (status & IS_Pan)
+		{
+			WCI.SPan = ch->finalPan;
+			newStatus |= Status_SetPan;
+		}
+
+		if (status & IS_Period)
+		{
+			WCI.SFrq = getFrequenceValue(ch->finalPeriod);
+			newStatus |= Status_SetFrq;
+		}
+
+		WCI.Status = newStatus;
+		mix_UpdateChannel(i, &WCI);
+	}
+}
+
+void mix_ClearChannels(void) // 8bb: rewritten to handle all voices instead of song.antChn
+{
+	lockMixer();
+
+	memset(CI, 0, sizeof (CI));
+
+	CIType *v = CI;
+	for (int16_t i = 0; i < 32*2; i++, v++)
+	{
+		v->SPan = 128;
+		v->SType = SType_Off;
+	}
+
+	for (int16_t i = 0; i < 32; i++)
+		chnReloc[i] = i+i;
+
+	unlockMixer();
+}
+
+static void mix_SaveIPVolumes(void)
+{
+	CIType *v = CI;
+	for (int32_t i = 0; i < song.antChn*2; i++, v++)
+	{
+		// 8bb: this cuts any active fade-out voices (volume ramping)
+		if (v->SType & SType_Fadeout)
+			v->SType = SType_Off;
+
+		v->SLVol2 = v->SLVol1;
+		v->SRVol2 = v->SRVol1;
+		v->SVolIPLen = 0;
+	}
+}
+
+void mix_UpdateBuffer(int16_t *buffer, int32_t numSamples)
+{
+	if (numSamples <= 0)
+		return;
+
+	if (musicPaused || WAVDump_Flag) // silence output
+	{
+		memset(buffer, 0, numSamples * (2 * sizeof (int16_t)));
+		return;
+	}
+
+	memset(CDA_MixBuffer, 0, numSamples * (2 * sizeof (int32_t)));
+
+	int32_t c = 0;
+	int32_t a = numSamples;
+
+	while (a > 0)
+	{
+		if (PMPLeft == 0)
+		{
+			mix_SaveIPVolumes();
+			mainPlayer();
+			mix_UpdateChannelVolPanFrq();
+			PMPLeft = speedVal;
+		}
+
+		int32_t b = a;
+		if (b > PMPLeft)
+			b = PMPLeft;
+
+		CIType *v = CI;
+		for (int32_t i = 0; i < song.antChn*2; i++, v++)
+			PMPMix32Proc(v, b, c);
+
+		c += b;
+		a -= b;
+		PMPLeft -= b;
+	}
+
+	numSamples *= 2; // 8bb: stereo
+
+	/* 8bb: Done a bit differently since we don't use a
+	** Sound Blaster with its master volume setting.
+	** Instead we change the amplitude here.
+	*/
+
+	if (masterVol == 256) // 8bb: max master volume, no need to change amp
+	{
+		for (int32_t i = 0; i < numSamples; i++)
+		{
+			int32_t out32 = CDA_MixBuffer[i] >> 8;
+			CLAMP16(out32);
+			buffer[i] = (int16_t)out32;
+		}
+	}
+	else
+	{
+		for (int32_t i = 0; i < numSamples; i++)
+		{
+			int32_t out32 = CDA_MixBuffer[i] >> 8;
+			CLAMP16(out32);
+			out32 = (out32 * masterVol) >> 8;
+			buffer[i] = (int16_t)out32;
+		}
+	}
+}
+
+bool dump_Init(int32_t frq, int32_t amp, int16_t songPos)
+{
+	setPos(songPos, 0);
+
+	oldReplayRate = realReplayRate;
+
+	realReplayRate = frq;
+	updateReplayRate();
+	CDA_Amp = 8 * amp;
+
+	mix_ClearChannels();
+	stopVoices();
+	song.globVol = 64;
+	speedVal = (frq*5 / 2) / song.speed;
+	quickVolSizeVal = frq / 200;
+
+	dump_Flag = false;
+	return true;
+}
+
+void dump_Close(void)
+{
+	stopVoices();
+	realReplayRate = oldReplayRate;
+	updateReplayRate();
+}
+
+bool dump_EndOfTune(int32_t endSongPos)
+{
+	bool returnValue = (dump_Flag && song.pattPos == 0 && song.timer == 1) || (song.tempo == 0);
+
+	// 8bb: FT2 bugfix for EEx (pattern delay) on first row of a pattern
+	if (song.pattDelTime2 > 0)
+		returnValue = false;
+
+	if (song.songPos == endSongPos && song.pattPos == 0 && song.timer == 1)
+		dump_Flag = true;
+
+	return returnValue;
+}
+
+int32_t dump_GetFrame(int16_t *p) // 8bb: returns bytes mixed to 16-bit stereo buffer
+{
+	mix_SaveIPVolumes();
+	mainPlayer();
+	mix_UpdateChannelVolPanFrq();
+
+	memset(CDA_MixBuffer, 0, speedVal * (2 * sizeof (int32_t)));
+
+	CIType *v = CI;
+	for (int32_t i = 0; i < song.antChn*2; i++, v++)
+		PMPMix32Proc(v, speedVal, 0);
+
+	const int32_t numSamples = speedVal * 2; // 8bb: *2 for stereo
+	for (int32_t i = 0; i < numSamples; i++)
+	{
+		int32_t out32 = CDA_MixBuffer[i] >> 8;
+		CLAMP16(out32);
+		p[i] = (int16_t)out32;
+	}
+
+	return speedVal * (2 * sizeof (int16_t));
+}