⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 infones_papu.cpp

📁 游戏模拟器InfoNes的原代码。有兴趣的可以将它移植到linux下
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*===================================================================*/
/*                                                                   */
/*  InfoNES_pAPU.cpp : InfoNES Sound Emulation Function              */
/*                                                                   */
/*  2000/05/29  InfoNES Project ( based on DarcNES and NesterJ )     */
/*                                                                   */
/*===================================================================*/

/*-------------------------------------------------------------------*/
/*  Include files                                                    */
/*-------------------------------------------------------------------*/
#include "K6502.h"
#include "InfoNES_System.h"
#include "InfoNES_pAPU.h"
#include <windows.h>
#include <stdio.h>
/*-------------------------------------------------------------------*/
/*  pAPU Event resources                                             */
/*-------------------------------------------------------------------*/

struct ApuEvent_t ApuEventQueue[ APU_EVENT_MAX ];
int  cur_event;
WORD entertime;

/*-------------------------------------------------------------------*/
/*  pAPU Register Write Functions                                    */
/*-------------------------------------------------------------------*/

#define APU_WRITEFUNC(name, evtype) \
void ApuWrite##name(WORD addr, BYTE value) \
{ \
  ApuEventQueue[cur_event].time = entertime - g_wPassedClocks; \
  ApuEventQueue[cur_event].type = APUET_W_##evtype; \
  ApuEventQueue[cur_event].data = value; \
  cur_event++; \
}

APU_WRITEFUNC(C1a, C1A);
APU_WRITEFUNC(C1b, C1B);
APU_WRITEFUNC(C1c, C1C);
APU_WRITEFUNC(C1d, C1D);

APU_WRITEFUNC(C2a, C2A);
APU_WRITEFUNC(C2b, C2B);
APU_WRITEFUNC(C2c, C2C);
APU_WRITEFUNC(C2d, C2D);

APU_WRITEFUNC(C3a, C3A);
APU_WRITEFUNC(C3b, C3B);
APU_WRITEFUNC(C3c, C3C);
APU_WRITEFUNC(C3d, C3D);

APU_WRITEFUNC(C4a, C4A);
APU_WRITEFUNC(C4b, C4B);
APU_WRITEFUNC(C4c, C4C);
APU_WRITEFUNC(C4d, C4D);

APU_WRITEFUNC(Control, CTRL);

ApuWritefunc pAPUSoundRegs[16] =
{
  ApuWriteC1a,
  ApuWriteC1b,
  ApuWriteC1c,
  ApuWriteC1d,
  ApuWriteC2a,
  ApuWriteC2b,
  ApuWriteC2c,
  ApuWriteC2d,
  ApuWriteC3a,
  ApuWriteC3b,
  ApuWriteC3c,
  ApuWriteC3d,
  ApuWriteC4a,
  ApuWriteC4b,
  ApuWriteC4c,
  ApuWriteC4d,
};

/*-------------------------------------------------------------------*/
/*  pAPU resources                                                   */
/*-------------------------------------------------------------------*/

BYTE wave_buffers[4][735];      /* 44100 / 60 = 735 samples per sync */

BYTE ApuCtrl;
BYTE ApuCtrlNew;

/*-------------------------------------------------------------------*/
/*  pAPU Quality resources                                           */
/*-------------------------------------------------------------------*/

int ApuQuality;

DWORD ApuPulseMagic;
DWORD ApuTriangleMagic;
DWORD ApuNoiseMagic;
unsigned int ApuSamplesPerSync;
unsigned int ApuCyclesPerSample;
unsigned int ApuSampleRate;

struct ApuQualityData_t
{
  DWORD pulse_magic;
  DWORD triangle_magic;
  DWORD noise_magic;
  unsigned int samples_per_sync;
  unsigned int cycles_per_sample;
  unsigned int sample_rate;
} ApuQual[] = {

	{ 0xDFE4D259, 0xDFE4D259, 0xDFE4D259, 134, 224, 8000 },
	{ 0xa2567000, 0xa2567000, 0xa2567000, 183, 164, 11025 },
  { 0xa2567000, 0x512b3800, 0x512b3800, 367, 82, 22050 },
  { 0x512b3800, 0x289d9c00, 0x289d9c00, 735, 41, 44100 },
};

/*-------------------------------------------------------------------*/
/*  Rectangle Wave #0 resources                                      */
/*-------------------------------------------------------------------*/
BYTE ApuC1a; BYTE ApuC1b;
BYTE ApuC1c; BYTE ApuC1d;

BYTE* ApuC1Wave;
DWORD ApuC1Skip;
DWORD ApuC1Index;
DWORD ApuC1EnvPhase;
BYTE  ApuC1EnvVol;
BYTE  ApuC1Atl;
DWORD ApuC1SweepPhase;
DWORD ApuC1Freq;

/*-------------------------------------------------------------------*/
/*  Rectangle Wave #1 resources                                      */
/*-------------------------------------------------------------------*/
BYTE ApuC2a; BYTE ApuC2b;
BYTE ApuC2c; BYTE ApuC2d;

BYTE* ApuC2Wave;
DWORD ApuC2Skip;
DWORD ApuC2Index;
DWORD ApuC2EnvPhase;
BYTE  ApuC2EnvVol;
BYTE  ApuC2Atl;
DWORD ApuC2SweepPhase;
DWORD ApuC2Freq;

/*-------------------------------------------------------------------*/
/*  Triangle Wave resources                                          */
/*-------------------------------------------------------------------*/
BYTE ApuC3a; BYTE ApuC3b;
BYTE ApuC3c; BYTE ApuC3d;

DWORD ApuC3Skip;
DWORD ApuC3Index;
BYTE  ApuC3Atl;
DWORD ApuC3Llc;                             /* Linear Length Counter */
BYTE  ApuC3WriteLatency;
BYTE  ApuC3CounterStarted;

/*-------------------------------------------------------------------*/
/*  Noise resources                                                  */
/*-------------------------------------------------------------------*/
BYTE ApuC4a; BYTE ApuC4b;
BYTE ApuC4c; BYTE ApuC4d;

DWORD ApuC4Sr;                                     /* Shift register */
DWORD ApuC4Fdc;                          /* Frequency divide counter */
DWORD ApuC4Skip;
DWORD ApuC4Index;
BYTE  ApuC4Atl;
BYTE  ApuC4EnvVol;
DWORD ApuC4EnvPhase;

/*-------------------------------------------------------------------*/
/*  Wave Data                                                        */
/*-------------------------------------------------------------------*/
BYTE pulse_25[0x20] = {
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
};

BYTE pulse_50[0x20] = {
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
};

BYTE pulse_75[0x20] = {
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
};

BYTE pulse_87[0x20] = {
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x11, 0x11, 0x11, 0x11,
  0x00, 0x00, 0x00, 0x00,
};

BYTE triangle_50[0x20] = {
  0x00, 0x10, 0x20, 0x30,
  0x40, 0x50, 0x60, 0x70,
  0x80, 0x90, 0xa0, 0xb0,
  0xc0, 0xd0, 0xe0, 0xf0,
  0xff, 0xef, 0xdf, 0xcf,
  0xbf, 0xaf, 0x9f, 0x8f,
  0x7f, 0x6f, 0x5f, 0x4f,
  0x3f, 0x2f, 0x1f, 0x0f,
};

BYTE *pulse_waves[4] = {
  pulse_87, pulse_75, pulse_50, pulse_25,
};

/*-------------------------------------------------------------------*/
/*  Active Time Left Data                                            */
/*-------------------------------------------------------------------*/
BYTE ApuAtl[0x20] =
{
  5, 127, 10, 1, 19,  2, 40,  3, 80,  4, 30,  5, 7,  6, 13,  7,
  6,   8, 12, 9, 24, 10, 48, 11, 96, 12, 36, 13, 8, 14, 16, 15,
};

/*-------------------------------------------------------------------*/
/* Frequency Limit of Rectangle Channels                             */
/*-------------------------------------------------------------------*/
WORD ApuFreqLimit[8] =
{
   0x3FF, 0x555, 0x666, 0x71C, 0x787, 0x7C1, 0x7E0, 0x7F0
};

/*-------------------------------------------------------------------*/
/* Noise Frequency Lookup Table                                      */
/*-------------------------------------------------------------------*/
DWORD ApuNoiseFreq[ 16 ] =
{
     4,    8,   16,   32,   64,   96,  128,  160,
   202,  254,  380,  508,  762, 1016, 2034, 4068
};

/*===================================================================*/
/*                                                                   */
/*      InfoNES_pApuWave1() : Rendering Rectangular Wave #0          */
/*                                                                   */
/*===================================================================*/

void InfoNES_pApuWave1( void )
{
  int cycles = 0;
  int event = 0;
  BYTE ctrl = ApuCtrl;

  /* note: 41 CPU cycles occur between increments of i */
  for ( unsigned int i = 0; i < ApuSamplesPerSync; i++ )
  {
    /* pAPU Reg Write Event */
	  cycles += ApuCyclesPerSample;
	  while ( ( event < cur_event ) && ( ApuEventQueue[event].time < cycles ) )
    {
	    if ( ( ApuEventQueue[event].type & APUET_MASK ) == APUET_C1 )
      {
		    switch ( ApuEventQueue[event].type & 0x03 )
        {
		      case 0:
	          ApuC1a    = ApuEventQueue[event].data;
            ApuC1Wave = pulse_waves[ ApuC1DutyCycle >> 6 ];
		        break;

		      case 1:
		        ApuC1b    = ApuEventQueue[event].data;
		        break;

		      case 2:
		        ApuC1c = ApuEventQueue[event].data;
		        ApuC1Freq = ( ( ( (WORD)ApuC1d & 0x07 ) << 8 ) + ApuC1c );
		        ApuC1Atl = ApuAtl[ ( ApuC1d & 0xf8 ) >> 3 ];

		        if ( ApuC1Freq )
            {
			        ApuC1Skip = ApuPulseMagic / ApuC1Freq;
		        } else {
			        ApuC1Skip = 0;
		        }
		        break;

		      case 3:
		        ApuC1d = ApuEventQueue[event].data;
		        ApuC1Freq = ( ( ( (WORD)ApuC1d & 0x07 ) << 8 ) + ApuC1c );
		        ApuC1Atl = ApuAtl[ ( ApuC1d & 0xf8 ) >> 3 ];

		        if ( ApuC1Freq )
            {
			        ApuC1Skip = ApuPulseMagic / ApuC1Freq;
		        } else {
			        ApuC1Skip = 0;
		        }
            break;
		    }
	    }
      else if ( ApuEventQueue[event].type == APUET_W_CTRL )
      {
		    ctrl = ApuEventQueue[event].data;
	    }
	    event++;
	  }

    /* Envelope decay at a rate of ( Envelope Delay + 1 ) / 240 secs */
    ApuC1EnvPhase -= 4;
    while ( ApuC1EnvPhase < 0 )
    {
      ApuC1EnvPhase += ApuC1EnvDelay;

      if ( ApuC1Hold )
      {
        ApuC1EnvVol = ( ApuC1EnvVol + 1 ) & 0x0f;
      }
      else if ( ApuC1EnvVol < 0x0f )
      {
        ApuC1EnvVol++;
      }
    }

    /*
     * TODO: using a table of max frequencies is not technically
     * clean, but it is fast and (or should be) accurate
     */
    if ( ApuC1Freq < 8 || ( !ApuC1SweepIncDec && ApuC1Freq > ApuC1FreqLimit ) )
    {
      wave_buffers[0][i] = 0;
      break;
    }

    /* Frequency sweeping at a rate of ( Sweep Delay + 1) / 120 secs */
    if ( ApuC1SweepOn && ApuC1SweepShifts )
    {
      ApuC1SweepPhase -= 2;           /* 120/60 */
      while ( ApuC1SweepPhase < 0)
      {
        ApuC1SweepPhase += ApuC1SweepDelay;

        if ( ApuC1SweepIncDec ) /* ramp up */
        {
          /* Rectangular #0 */
          ApuC1Freq += ~( ApuC1Freq >> ApuC1SweepShifts );
        } else {
          /* ramp down */
          ApuC1Freq += ( ApuC1Freq >> ApuC1SweepShifts );
        }
      }
      ApuC1Skip = ApuPulseMagic / ApuC1Freq;
    }

    /* Wave Rendering */
	  if ( ( ctrl & 0x01 ) && ( ApuC1Atl || ApuC1Hold ) )
    {
	    ApuC1Index += ApuC1Skip;
	    ApuC1Index &= 0x1fffffff;

      if ( ApuC1Env )
      {
        wave_buffers[0][i] = ApuC1Wave[ApuC1Index >> 24] * ( ApuC1Vol + ApuC1EnvVol );
      } else {
        wave_buffers[0][i] = ApuC1Wave[ApuC1Index >> 24] * ApuC1Vol;
      }
	  } else {
	    wave_buffers[0][i] = 0;
	  }
  }
  if ( ApuC1Atl )
  {
	  ApuC1Atl--;
  }
  ApuCtrlNew = ctrl;
}

/*===================================================================*/
/*                                                                   */
/*      InfoNES_pApuWave2() : Rendering Rectangular Wave #1          */
/*                                                                   */
/*===================================================================*/

void InfoNES_pApuWave2( void )
{
  int cycles = 0;
  int event = 0;
  BYTE ctrl = ApuCtrl;

  /* note: 41 CPU cycles occur between increments of i */
  for ( unsigned int i = 0; i < ApuSamplesPerSync; i++ )
  {
    /* pAPU Reg Write Event */
	  cycles += ApuCyclesPerSample;
	  while ( ( event < cur_event ) && ( ApuEventQueue[event].time < cycles ) )
    {
	    if ( ( ApuEventQueue[event].type & APUET_MASK ) == APUET_C2 )
      {
		    switch ( ApuEventQueue[event].type & 0x03 )
        {
		      case 0:
	          ApuC2a    = ApuEventQueue[event].data;
            ApuC2Wave = pulse_waves[ ApuC2DutyCycle >> 6 ];
		        break;

		      case 1:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -