summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/sidenvel.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/sidenvel.c')
-rw-r--r--trunk/src/emu/sound/sidenvel.c586
1 files changed, 586 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/sidenvel.c b/trunk/src/emu/sound/sidenvel.c
new file mode 100644
index 00000000000..5d49df6f20d
--- /dev/null
+++ b/trunk/src/emu/sound/sidenvel.c
@@ -0,0 +1,586 @@
+/*========================================================================= */
+/* This source implements the ADSR volume envelope of the SID-chip. */
+/* Two different envelope shapes are implemented, an exponential */
+/* approximation and the linear shape, which can easily be determined */
+/* by reading the registers of the third SID operator. */
+/* */
+/* Accurate volume envelope times as of November 1994 are used */
+/* courtesy of George W. Taylor <aa601@cfn.cs.dal.ca>, <yurik@io.org> */
+/* They are slightly modified. */
+/* */
+/* To use the rounded envelope times from the C64 Programmers Reference */
+/* Book define SID_REFTIMES at the Makefile level. */
+/* */
+/* To perform realtime calculations with floating point precision define */
+/* SID_FPUENVE at the Makefile level. On high-end FPUs (not Pentium !), */
+/* this can result in speed improvement. Default is integer fixpoint. */
+/* */
+/* Global Makefile definables: */
+/* */
+/* DIRECT_FIXPOINT - use a union to access integer fixpoint operands */
+/* in memory. This makes an assumption about the */
+/* hardware and software architecture and therefore */
+/* is considered a hack ! */
+/* */
+/* Local (or Makefile) definables: */
+/* */
+/* SID_REFTIMES - use rounded envelope times */
+/* SID_FPUENVE - use floating point precision for calculations */
+/* (will override the global DIRECT_FIXPOINT setting !) */
+/* */
+/*========================================================================= */
+
+#include "emu.h"
+#include "sidvoice.h"
+#include "sid.h"
+
+#include "side6581.h"
+#include "sidenvel.h"
+
+const UINT8 masterVolumeLevels[16] =
+{
+ 0, 17, 34, 51, 68, 85, 102, 119,
+ 136, 153, 170, 187, 204, 221, 238, 255
+};
+
+static UINT16 masterAmplModTable[16*256];
+
+static const float attackTimes[16] =
+{
+ /* milliseconds */
+#if defined(SID_REFTIMES)
+ 2.0f, 8.0f, 16.0f, 24.0f, 38.0f, 56.0f, 68.0f, 80.0f,
+ 100.0f, 250.0f, 500.0f, 800.0f, 1000.0f, 3000.0f, 5000.0f, 8000.0f
+#else
+ 2.2528606f, 8.0099577f, 15.7696042f, 23.7795619f, 37.2963655f, 55.0684591f,
+ 66.8330845f, 78.3473987f,
+ 98.1219818f, 244.554021f, 489.108042f, 782.472742f, 977.715461f, 2933.64701f,
+ 4889.07793f, 7822.72493f
+#endif
+};
+
+static const float decayReleaseTimes[16] =
+{
+ /* milliseconds */
+#if defined(SID_REFTIMES)
+ 8.0f, 24.0f, 48.0f, 72.0f, 114.0f, 168.0f, 204.0f, 240.0f,
+ 300.0f, 750.0f, 1500.0f, 2400.0f, 3000.0f, 9000.0f, 15000.0f, 24000.0f
+#else
+ 8.91777693f, 24.594051f, 48.4185907f, 73.0116639f, 114.512475f, 169.078356f,
+ 205.199432f, 240.551975f,
+ 301.266125f, 750.858245f, 1501.71551f, 2402.43682f, 3001.89298f, 9007.21405f,
+ 15010.998f, 24018.2111f
+#endif
+};
+
+#ifdef SID_FPUENVE
+ static float attackRates[16];
+ static float decayReleaseRates[16];
+#elif defined(DIRECT_FIXPOINT)
+ static UINT32 attackRates[16];
+ static UINT32 decayReleaseRates[16];
+#else
+ static UINT32 attackRates[16];
+ static UINT32 attackRatesP[16];
+ static UINT32 decayReleaseRates[16];
+ static UINT32 decayReleaseRatesP[16];
+#endif
+
+static const UINT32 attackTabLen = 255;
+static UINT32 releaseTabLen;
+static UINT32 releasePos[256];
+
+
+void enveEmuInit( UINT32 updateFreq, int measuredValues )
+{
+ UINT32 i, j, k;
+
+ releaseTabLen = sizeof(releaseTab);
+ for ( i = 0; i < 256; i++ )
+ {
+ j = 0;
+ while (( j < releaseTabLen ) && (releaseTab[j] > i) )
+ {
+ j++;
+ }
+ if ( j < releaseTabLen )
+ {
+ releasePos[i] = j;
+ }
+ else
+ {
+ releasePos[i] = releaseTabLen -1;
+ }
+ }
+
+ k = 0;
+ for ( i = 0; i < 16; i++ )
+ {
+ for ( j = 0; j < 256; j++ )
+ {
+ UINT16 tmpVol = j;
+ if (measuredValues)
+ {
+ tmpVol = (UINT16) ((293.0*(1-exp(j/-130.0)))+4.0);
+ if (j == 0)
+ tmpVol = 0;
+ if (tmpVol > 255)
+ tmpVol = 255;
+ }
+ /* Want the modulated volume value in the high byte. */
+ masterAmplModTable[k++] = ((tmpVol * masterVolumeLevels[i]) / 255) << 8;
+ }
+ }
+
+ for ( i = 0; i < 16; i++ )
+ {
+#ifdef SID_FPUENVE
+ double scaledenvelen = floor(( attackTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ attackRates[i] = attackTabLen / scaledenvelen;
+
+ scaledenvelen = floor(( decayReleaseTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ decayReleaseRates[i] = releaseTabLen / scaledenvelen;
+#elif defined(DIRECT_FIXPOINT)
+ UINT32 scaledenvelen = (UINT32)floor(( attackTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ attackRates[i] = (attackTabLen << 16) / scaledenvelen;
+
+ scaledenvelen = (UINT32)floor(( decayReleaseTimes[i] * updateFreq ) / 1000UL );
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ decayReleaseRates[i] = (releaseTabLen << 16) / scaledenvelen;
+#else
+ UINT32 scaledenvelen = (UINT32)(/*floor*/(( attackTimes[i] * updateFreq ) / 1000UL ));
+
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ attackRates[i] = attackTabLen / scaledenvelen;
+ attackRatesP[i] = (( attackTabLen % scaledenvelen ) * 65536UL ) / scaledenvelen;
+
+ scaledenvelen = (UINT32)(/*floor*/(( decayReleaseTimes[i] * updateFreq ) / 1000UL ));
+ if (scaledenvelen == 0)
+ scaledenvelen = 1;
+ decayReleaseRates[i] = releaseTabLen / scaledenvelen;
+ decayReleaseRatesP[i] = (( releaseTabLen % scaledenvelen ) * 65536UL ) / scaledenvelen;
+#endif
+ }
+}
+
+/* Reset op. */
+
+void enveEmuResetOperator(sidOperator* pVoice)
+{
+ /* mute, end of R-phase */
+ pVoice->ADSRctrl = ENVE_MUTE;
+// pVoice->gateOnCtrl = (pVoice->gateOffCtrl = false);
+
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = (pVoice->fenveStepAdd = 0);
+ pVoice->enveStep = 0;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.l = (pVoice->enveStepAdd.l = 0);
+#else
+ pVoice->enveStep = (pVoice->enveStepPnt = 0);
+ pVoice->enveStepAdd = (pVoice->enveStepAddPnt = 0);
+#endif
+ pVoice->enveSusVol = 0;
+ pVoice->enveVol = 0;
+ pVoice->enveShortAttackCount = 0;
+}
+
+INLINE UINT16 enveEmuStartAttack(sidOperator*);
+INLINE UINT16 enveEmuStartDecay(sidOperator*);
+INLINE UINT16 enveEmuStartRelease(sidOperator*);
+INLINE UINT16 enveEmuAlterAttack(sidOperator*);
+INLINE UINT16 enveEmuAlterDecay(sidOperator*);
+INLINE UINT16 enveEmuAlterSustain(sidOperator*);
+INLINE UINT16 enveEmuAlterSustainDecay(sidOperator*);
+INLINE UINT16 enveEmuAlterRelease(sidOperator*);
+INLINE UINT16 enveEmuAttack(sidOperator*);
+INLINE UINT16 enveEmuDecay(sidOperator*);
+INLINE UINT16 enveEmuSustain(sidOperator*);
+INLINE UINT16 enveEmuSustainDecay(sidOperator*);
+INLINE UINT16 enveEmuRelease(sidOperator*);
+INLINE UINT16 enveEmuMute(sidOperator*);
+
+INLINE UINT16 enveEmuStartShortAttack(sidOperator*);
+INLINE UINT16 enveEmuAlterShortAttack(sidOperator*);
+INLINE UINT16 enveEmuShortAttack(sidOperator*);
+
+
+const ptr2sidUwordFunc enveModeTable[] =
+{
+ /* 0 */
+ &enveEmuStartAttack, &enveEmuStartRelease,
+ &enveEmuAttack, &enveEmuDecay, &enveEmuSustain, &enveEmuRelease,
+ &enveEmuSustainDecay, &enveEmuMute,
+ /* 16 */
+ &enveEmuStartShortAttack,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute, &enveEmuMute,
+ /* 32 */
+ &enveEmuStartAttack, &enveEmuStartRelease,
+ &enveEmuAlterAttack, &enveEmuAlterDecay, &enveEmuAlterSustain, &enveEmuAlterRelease,
+ &enveEmuAlterSustainDecay, &enveEmuMute,
+ /* 48 */
+ &enveEmuStartShortAttack,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute,
+ &enveEmuMute, &enveEmuMute, &enveEmuMute, &enveEmuMute
+};
+
+/* Real-time functions. */
+/* Order is important because of inline optimizations. */
+/* */
+/* ADSRctrl is (index*2) to enveModeTable[], because of KEY-bit. */
+
+INLINE void enveEmuEnveAdvance(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->fenveStep += pVoice->fenveStepAdd;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.l += pVoice->enveStepAdd.l;
+#else
+ pVoice->enveStepPnt += pVoice->enveStepAddPnt;
+ pVoice->enveStep += pVoice->enveStepAdd + ( pVoice->enveStepPnt > 65535 );
+ pVoice->enveStepPnt &= 0xFFFF;
+#endif
+}
+
+/* */
+/* Mute/Idle. */
+/* */
+
+/* Only used in the beginning. */
+INLINE UINT16 enveEmuMute(sidOperator* pVoice)
+{
+ return 0;
+}
+
+/* */
+/* Release */
+/* */
+
+INLINE UINT16 enveEmuRelease(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] >= releaseTabLen )
+#else
+ if ( pVoice->enveStep >= releaseTabLen )
+#endif
+ {
+ pVoice->enveVol = releaseTab[releaseTabLen -1];
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]];
+#else
+ pVoice->enveVol = releaseTab[pVoice->enveStep];
+#endif
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+}
+
+INLINE UINT16 enveEmuAlterRelease(sidOperator* pVoice)
+{
+ UINT8 release = pVoice->SIDSR & 0x0F;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = decayReleaseRates[release];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = decayReleaseRates[release];
+#else
+ pVoice->enveStepAdd = decayReleaseRates[release];
+ pVoice->enveStepAddPnt = decayReleaseRatesP[release];
+#endif
+ pVoice->ADSRproc = &enveEmuRelease;
+ return enveEmuRelease(pVoice);
+}
+
+INLINE UINT16 enveEmuStartRelease(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_RELEASE;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = releasePos[pVoice->enveVol];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.w[HI] = releasePos[pVoice->enveVol];
+ pVoice->enveStep.w[LO] = 0;
+#else
+ pVoice->enveStep = releasePos[pVoice->enveVol];
+ pVoice->enveStepPnt = 0;
+#endif
+ return enveEmuAlterRelease(pVoice);
+}
+
+/* */
+/* Sustain */
+/* */
+
+INLINE UINT16 enveEmuSustain(sidOperator* pVoice)
+{
+ return masterAmplModTable[pVoice->sid->masterVolumeAmplIndex+pVoice->enveVol];
+}
+
+INLINE UINT16 enveEmuSustainDecay(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] >= releaseTabLen )
+#else
+ if ( pVoice->enveStep >= releaseTabLen )
+#endif
+ {
+ pVoice->enveVol = releaseTab[releaseTabLen-1];
+ return enveEmuAlterSustain(pVoice);
+ }
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]];
+#else
+ pVoice->enveVol = releaseTab[pVoice->enveStep];
+#endif
+ /* Will be controlled from sidEmuSet2(). */
+ if ( pVoice->enveVol <= pVoice->enveSusVol )
+ {
+ pVoice->enveVol = pVoice->enveSusVol;
+ return enveEmuAlterSustain(pVoice);
+ }
+ else
+ {
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+ }
+}
+
+/* This is the same as enveEmuStartSustainDecay(). */
+INLINE UINT16 enveEmuAlterSustainDecay(sidOperator* pVoice)
+{
+ UINT8 decay = pVoice->SIDAD & 0x0F ;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = decayReleaseRates[decay];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = decayReleaseRates[decay];
+#else
+ pVoice->enveStepAdd = decayReleaseRates[decay];
+ pVoice->enveStepAddPnt = decayReleaseRatesP[decay];
+#endif
+ pVoice->ADSRproc = &enveEmuSustainDecay;
+ return enveEmuSustainDecay(pVoice);
+}
+
+/* This is the same as enveEmuStartSustain(). */
+INLINE UINT16 enveEmuAlterSustain(sidOperator* pVoice)
+{
+ if ( pVoice->enveVol > pVoice->enveSusVol )
+ {
+ pVoice->ADSRctrl = ENVE_SUSTAINDECAY;
+ pVoice->ADSRproc = &enveEmuSustainDecay;
+ return enveEmuAlterSustainDecay(pVoice);
+ }
+ else
+ {
+ pVoice->ADSRctrl = ENVE_SUSTAIN;
+ pVoice->ADSRproc = &enveEmuSustain;
+ return enveEmuSustain(pVoice);
+ }
+}
+
+/* */
+/* Decay */
+/* */
+
+INLINE UINT16 enveEmuDecay(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] >= releaseTabLen )
+#else
+ if ( pVoice->enveStep >= releaseTabLen )
+#endif
+ {
+ pVoice->enveVol = pVoice->enveSusVol;
+ return enveEmuAlterSustain(pVoice); /* start sustain */
+ }
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]];
+#else
+ pVoice->enveVol = releaseTab[pVoice->enveStep];
+#endif
+ /* Will be controlled from sidEmuSet2(). */
+ if ( pVoice->enveVol <= pVoice->enveSusVol )
+ {
+ pVoice->enveVol = pVoice->enveSusVol;
+ return enveEmuAlterSustain(pVoice); /* start sustain */
+ }
+ else
+ {
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+ }
+}
+
+INLINE UINT16 enveEmuAlterDecay(sidOperator* pVoice)
+{
+ UINT8 decay = pVoice->SIDAD & 0x0F ;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = decayReleaseRates[decay];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = decayReleaseRates[decay];
+#else
+ pVoice->enveStepAdd = decayReleaseRates[decay];
+ pVoice->enveStepAddPnt = decayReleaseRatesP[decay];
+#endif
+ pVoice->ADSRproc = &enveEmuDecay;
+ return enveEmuDecay(pVoice);
+}
+
+INLINE UINT16 enveEmuStartDecay(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_DECAY;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = 0;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.l = 0;
+#else
+ pVoice->enveStep = (pVoice->enveStepPnt = 0);
+#endif
+ return enveEmuAlterDecay(pVoice);
+}
+
+/* */
+/* Attack */
+/* */
+
+INLINE UINT16 enveEmuAttack(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ( pVoice->enveStep.w[HI] > attackTabLen )
+#else
+ if ( pVoice->enveStep >= attackTabLen )
+#endif
+ return enveEmuStartDecay(pVoice);
+ else
+ {
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = pVoice->enveStep.w[HI];
+#else
+ pVoice->enveVol = pVoice->enveStep;
+#endif
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+ }
+}
+
+INLINE UINT16 enveEmuAlterAttack(sidOperator* pVoice)
+{
+ UINT8 attack = pVoice->SIDAD >> 4;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = attackRates[attack];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = attackRates[attack];
+#else
+ pVoice->enveStepAdd = attackRates[attack];
+ pVoice->enveStepAddPnt = attackRatesP[attack];
+#endif
+ pVoice->ADSRproc = &enveEmuAttack;
+ return enveEmuAttack(pVoice);
+}
+
+INLINE UINT16 enveEmuStartAttack(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_ATTACK;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = (float)pVoice->enveVol;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.w[HI] = pVoice->enveVol;
+ pVoice->enveStep.w[LO] = 0;
+#else
+ pVoice->enveStep = pVoice->enveVol;
+ pVoice->enveStepPnt = 0;
+#endif
+ return enveEmuAlterAttack(pVoice);
+}
+
+/* */
+/* Experimental. */
+/* */
+
+/*#include <iostream.h> */
+/*#include <iomanip.h> */
+
+INLINE UINT16 enveEmuShortAttack(sidOperator* pVoice)
+{
+#ifdef SID_FPUENVE
+ pVoice->enveStep = (UINT16)pVoice->fenveStep;
+#endif
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ if ((pVoice->enveStep.w[HI] > attackTabLen) ||
+ (pVoice->enveShortAttackCount == 0))
+#else
+ if ((pVoice->enveStep >= attackTabLen) ||
+ (pVoice->enveShortAttackCount == 0))
+#endif
+/* return enveEmuStartRelease(pVoice); */
+ return enveEmuStartDecay(pVoice);
+#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE)
+ pVoice->enveVol = pVoice->enveStep.w[HI];
+#else
+ pVoice->enveVol = pVoice->enveStep;
+#endif
+ pVoice->enveShortAttackCount--;
+/* cout << hex << pVoice->enveShortAttackCount << " / " << pVoice->enveVol << endl; */
+ enveEmuEnveAdvance(pVoice);
+ return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ];
+}
+
+INLINE UINT16 enveEmuAlterShortAttack(sidOperator* pVoice)
+{
+ UINT8 attack = pVoice->SIDAD >> 4;
+#ifdef SID_FPUENVE
+ pVoice->fenveStepAdd = attackRates[attack];
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStepAdd.l = attackRates[attack];
+#else
+ pVoice->enveStepAdd = attackRates[attack];
+ pVoice->enveStepAddPnt = attackRatesP[attack];
+#endif
+ pVoice->ADSRproc = &enveEmuShortAttack;
+ return enveEmuShortAttack(pVoice);
+}
+
+INLINE UINT16 enveEmuStartShortAttack(sidOperator* pVoice)
+{
+ pVoice->ADSRctrl = ENVE_SHORTATTACK;
+#ifdef SID_FPUENVE
+ pVoice->fenveStep = (float)pVoice->enveVol;
+#elif defined(DIRECT_FIXPOINT)
+ pVoice->enveStep.w[HI] = pVoice->enveVol;
+ pVoice->enveStep.w[LO] = 0;
+#else
+ pVoice->enveStep = pVoice->enveVol;
+ pVoice->enveStepPnt = 0;
+#endif
+ pVoice->enveShortAttackCount = 65535; /* unused */
+ return enveEmuAlterShortAttack(pVoice);
+}