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

📄 emu2413.c

📁 最好的任天堂模拟器
💻 C
📖 第 1 页 / 共 3 页
字号:
/***********************************************************************************

  emu2413.c -- YM2413 emulator written by Mitsutaka Okazaki 2001

  2001 01-08 : Version 0.10 -- 1st version.
  2001 01-15 : Version 0.20 -- semi-public version.
  2001 01-16 : Version 0.30 -- 1st public version.
  2001 01-17 : Version 0.31 -- Fixed bassdrum problem.
             : Version 0.32 -- LPF implemented.
  2001 01-18 : Version 0.33 -- Fixed the drum problem, refine the mix-down method.
                            -- Fixed the LFO bug.
  2001 01-24 : Version 0.35 -- Fixed the drum problem, 
                               support undocumented EG behavior.
  2001 02-02 : Version 0.38 -- Improved the performance.
                               Fixed the hi-hat and cymbal model.
                               Fixed the default percussive datas.
                               Noise reduction.
                               Fixed the feedback problem.
  2001 03-03 : Version 0.39 -- Fixed some drum bugs.
                               Improved the performance.
  2001 03-04 : Version 0.40 -- Improved the feedback.
                               Change the default table size.
                               Clock and Rate can be changed during play.
  2001 06-24 : Version 0.50 -- Improved the hi-hat and the cymbal tone.
                               Added VRC7 patch (OPLL_reset_patch is changed).
                               Fix OPLL_reset() bug.
                               Added OPLL_setMask, OPLL_getMask and OPLL_toggleMask.
                               Added OPLL_writeIO.

  References: 
    fmopl.c        -- 1999,2000 written by Tatsuyuki Satoh (MAME development).
    s_opl.c        -- 2001 written by mamiya (NEZplug development).
    fmgen.cpp      -- 1999,2000 written by cisc.
    fmpac.ill      -- 2000 created by NARUTO. 
    MSX-Datapack
    YMU757 data sheet
    YM2143 data sheet

**************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "emu2413.h"

#if defined(_MSC_VER)
#define INLINE __inline
#elif defined(__GNUC__)
#define INLINE __inline__
#else
#define INLINE
#endif

#define OPLL_TONE_NUM 2
static unsigned char default_inst[OPLL_TONE_NUM][(16+3)*16]=
{
  { 
#include "2413tone.h" 
  },
  { 
#include "vrc7tone.h" 
  }
};

/* Size of Sintable ( 1 -- 18 can be used, but 7 -- 14 recommended.)*/
#define PG_BITS 9
#define PG_WIDTH (1<<PG_BITS)

/* Phase increment counter */
#define DP_BITS 18
#define DP_WIDTH (1<<DP_BITS)
#define DP_BASE_BITS (DP_BITS - PG_BITS)

/* Dynamic range */
#define DB_STEP 0.375
#define DB_BITS 7
#define DB_MUTE (1<<DB_BITS)

/* Dynamic range of envelope */
#define EG_STEP 0.375
#define EG_BITS 7
#define EG_MUTE (1<<EB_BITS)

/* Dynamic range of total level */
#define TL_STEP 0.75
#define TL_BITS 6
#define TL_MUTE (1<<TL_BITS)

/* Dynamic range of sustine level */
#define SL_STEP 3.0
#define SL_BITS 4
#define SL_MUTE (1<<SL_BITS)

#define EG2DB(d) ((d)*(int)(EG_STEP/DB_STEP))
#define TL2EG(d) ((d)*(int)(TL_STEP/EG_STEP))
#define SL2EG(d) ((d)*(int)(SL_STEP/EG_STEP))

/* Volume of Noise (dB) */
#define DB_NOISE (24.0)

#define DB_POS(x) (uint32)((x)/DB_STEP)
#define DB_NEG(x) (uint32)(DB_MUTE+DB_MUTE+(x)/DB_STEP)

/* Bits for liner value */
#define DB2LIN_AMP_BITS 10
#define SLOT_AMP_BITS (DB2LIN_AMP_BITS)

/* Bits for envelope phase incremental counter */  
#define EG_DP_BITS 22
#define EG_DP_WIDTH (1<<EG_DP_BITS)

/* Bits for Pitch and Amp modulator */
#define PM_PG_BITS 8
#define PM_PG_WIDTH (1<<PM_PG_BITS)
#define PM_DP_BITS 16
#define PM_DP_WIDTH (1<<PM_DP_BITS)
#define AM_PG_BITS 8
#define AM_PG_WIDTH (1<<AM_PG_BITS)
#define AM_DP_BITS 16
#define AM_DP_WIDTH (1<<AM_DP_BITS)

/* PM table is calcurated by PM_AMP * pow(2,PM_DEPTH*sin(x)/1200) */
#define PM_AMP_BITS 8
#define PM_AMP (1<<PM_AMP_BITS)

/* PM speed(Hz) and depth(cent) */
#define PM_SPEED 6.4
#define PM_DEPTH 13.75

/* AM speed(Hz) and depth(dB) */
#define AM_SPEED 3.7
#define AM_DEPTH 4.8

/* Cut the lower b bit(s) off. */
#define HIGHBITS(c,b) ((c)>>(b))

/* Leave the lower b bit(s). */
#define LOWBITS(c,b) ((c)&((1<<(b))-1))

/* Expand x which is s bits to d bits. */
#define EXPAND_BITS(x,s,d) ((x)<<((d)-(s)))

/* Expand x which is s bits to d bits and fill expanded bits '1' */
#define EXPAND_BITS_X(x,s,d) (((x)<<((d)-(s)))|((1<<((d)-(s)))-1))

/* Adjust envelope speed which depends on sampling rate. */
#define rate_adjust(x) (uint32)((double)(x)*clk/72/rate + 0.5) /* +0.5 to round */

#define MOD(x) ch[x]->mod
#define CAR(x) ch[x]->car

/* Sampling rate */
static uint32 rate ;
/* Input clock */
static uint32 clk ;

/* WaveTable for each envelope amp */
static uint32 fullsintable[PG_WIDTH] ;
static uint32 halfsintable[PG_WIDTH] ;
static uint32 snaretable[PG_WIDTH] ;

static int32 noiseAtable[64] = {
  -1,1,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,
  -1,1,0,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0
} ;

static int32 noiseBtable[8] = {
  -1,1,-1,1,0,0,0,0
} ;

static uint32 *waveform[5] = {fullsintable,halfsintable,snaretable} ;

/* LFO Table */
static int32 pmtable[PM_PG_WIDTH] ;
static int32 amtable[AM_PG_WIDTH] ;

/* Noise and LFO */
static uint32 pm_dphase ;
static uint32 am_dphase ;

/* dB to Liner table */
static int32 DB2LIN_TABLE[(DB_MUTE + DB_MUTE)*2] ;

/* Liner to Log curve conversion table (for Attack rate). */
static uint32 AR_ADJUST_TABLE[1<<EG_BITS] ;

/* Empty voice data */
static OPLL_PATCH null_patch = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ;

/* Basic voice Data */
static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16+3)*2] ; 


/* Definition of envelope mode */
enum { SETTLE,ATTACK,DECAY,SUSHOLD,SUSTINE,RELEASE,FINISH } ;

/* Phase incr table for Attack */
static uint32 dphaseARTable[16][16] ;
/* Phase incr table for Decay and Release */
static uint32 dphaseDRTable[16][16] ;

/* KSL + TL Table */
static uint32 tllTable[16][8][1<<TL_BITS][4] ;
static int32 rksTable[2][8][2] ;

/* Phase incr table for PG */
static uint32 dphaseTable[512][8][16] ; 

/***************************************************
 
                  Create tables
 
****************************************************/
INLINE static int32 Min(int32 i,int32 j)
{
  if(i<j) return i ; else return j ;
}

/* Table for AR to LogCurve. */
static void makeAdjustTable(void)
{
  int i ;

  AR_ADJUST_TABLE[0] = (1<<EG_BITS) ;
  for ( i=1 ; i < 128 ; i++)
    AR_ADJUST_TABLE[i] = (uint32)((double)(1<<EG_BITS) - 1 - (1<<EG_BITS) * log(i) / log(128)) ; 
}


/* Table for dB(0 -- (1<<DB_BITS)) to Liner(0 -- DB2LIN_AMP_WIDTH) */
static void makeDB2LinTable(void)
{
  int i ;

  for( i=0 ; i < DB_MUTE + DB_MUTE ; i++)
  {
    DB2LIN_TABLE[i] = (int32)((double)((1<<DB2LIN_AMP_BITS)-1) * pow(10,-(double)i*DB_STEP/20)) ;
    if(i>=DB_MUTE) DB2LIN_TABLE[i] = 0 ;
    DB2LIN_TABLE[i+ DB_MUTE + DB_MUTE] = -DB2LIN_TABLE[i] ;
  }
}

/* Liner(+0.0 - +1.0) to dB((1<<DB_BITS) - 1 -- 0) */
static int32 lin2db(double d)
{
  if(d == 0) return (DB_MUTE - 1) ;
  else return Min(-(int32)(20.0*log10(d)/DB_STEP), DB_MUTE - 1) ; /* 0 -- 128 */
}

/* Sin Table */
static void makeSinTable(void)
{


  int i ;

  for( i = 0 ; i < PG_WIDTH/4 ; i++ ){
    fullsintable[i] = lin2db(sin(2.0*PI*i/PG_WIDTH)) ;
    snaretable[i] = (int32)((6.0)/DB_STEP) ;
  }

  for( i = 0 ; i < PG_WIDTH/4 ; i++ ){
    fullsintable[PG_WIDTH/2 - 1 - i] = fullsintable[i] ;
    snaretable[PG_WIDTH/2 - 1 - i] = snaretable[i] ;
  }

  for( i = 0 ; i < PG_WIDTH/2 ; i++ ){
    fullsintable[PG_WIDTH/2+i] = DB_MUTE + DB_MUTE + fullsintable[i] ;
    snaretable[PG_WIDTH/2+i] = DB_MUTE + DB_MUTE + snaretable[i] ;
  }
  
  for( i = 0 ; i < PG_WIDTH/2 ; i++ ) halfsintable[i] = fullsintable[i] ;
  for( i = PG_WIDTH/2 ; i< PG_WIDTH ; i++ ) halfsintable[i] = fullsintable[0] ;

  for( i = 0 ; i < 64 ; i++ )
  {
    if(noiseAtable[i]>0) noiseAtable[i] = DB_POS(0) ;
    else if(noiseAtable[i]<0) noiseAtable[i] = DB_NEG(0) ;
    else noiseAtable[i] = DB_MUTE - 1 ;
  }

  for( i = 0 ; i < 8 ; i++ )
  {
    if(noiseBtable[i]>0) noiseBtable[i] = DB_POS(0) ;
    else if(noiseBtable[i]<0) noiseBtable[i] = DB_NEG(0) ;
    else noiseBtable[i] = DB_MUTE - 1 ;
  }

}

/* Table for Pitch Modulator */
static void makePmTable(void)
{
  int i ;

  for(i = 0 ; i < PM_PG_WIDTH ; i++ )
    pmtable[i] = (int32)((double)PM_AMP * pow(2,(double)PM_DEPTH*sin(2.0*PI*i/PM_PG_WIDTH)/1200)) ;
}

/* Table for Amp Modulator */
static void makeAmTable(void)
{
  int i ;

  for(i = 0 ; i < AM_PG_WIDTH ; i++ )
    amtable[i] = (int32)((double)AM_DEPTH/2/DB_STEP * (1.0 + sin(2.0*PI*i/PM_PG_WIDTH))) ;
}

/* Phase increment counter table */ 
static void makeDphaseTable(void)
{
  uint32 fnum, block , ML ;
  uint32 mltable[16]={ 1,1*2,2*2,3*2,4*2,5*2,6*2,7*2,8*2,9*2,10*2,10*2,12*2,12*2,15*2,15*2 } ;

  for(fnum=0; fnum<512; fnum++)
    for(block=0; block<8; block++)
      for(ML=0; ML<16; ML++)
        dphaseTable[fnum][block][ML] = rate_adjust(((fnum * mltable[ML])<<block)>>(20-DP_BITS)) ;
}

static void makeTllTable(void)
{
#define dB2(x) (uint32)((x)*2)

	static uint32 kltable[16] = {
    dB2( 0.000),dB2( 9.000),dB2(12.000),dB2(13.875),dB2(15.000),dB2(16.125),dB2(16.875),dB2(17.625),
    dB2(18.000),dB2(18.750),dB2(19.125),dB2(19.500),dB2(19.875),dB2(20.250),dB2(20.625),dB2(21.000)
	} ;
  
  int32 tmp ;
  int fnum, block ,TL , KL ;

  for(fnum=0; fnum<16; fnum++)
    for(block=0; block<8; block++)
      for(TL=0; TL<64; TL++)
        for(KL=0; KL<4; KL++)
        {
          if(KL==0)
          {
            tllTable[fnum][block][TL][KL] = TL2EG(TL) ;
          }
          else
          {
  	        tmp = kltable[fnum] - dB2(3.000) * (7 - block) ;
            if(tmp <= 0)
              tllTable[fnum][block][TL][KL] = TL2EG(TL) ;
            else 
              tllTable[fnum][block][TL][KL] = (uint32)((tmp>>(3-KL))/EG_STEP) + TL2EG(TL) ;
          }
       }
}

/* Rate Table for Attack */
static void makeDphaseARTable(void)
{
  int AR,Rks,RM,RL ;

  for(AR=0; AR<16; AR++)
    for(Rks=0; Rks<16; Rks++)
    {
      RM = AR + (Rks>>2) ;
      if(RM>15) RM = 15 ;
      RL = Rks&3 ;
      switch(AR)
      { 
        case 0:
          dphaseARTable[AR][Rks] = 0 ;
          break ;
        case 15:
          dphaseARTable[AR][Rks] = EG_DP_WIDTH ;
          break ;
        default:
          dphaseARTable[AR][Rks] = rate_adjust(( 3 * (RL + 4) << (RM + 1))) ;
          break ;
      }
    }
}

/* Rate Table for Decay */
static void makeDphaseDRTable(void)
{
  int DR,Rks,RM,RL ;

  for(DR=0; DR<16; DR++)
    for(Rks=0; Rks<16; Rks++)
    {
      RM = DR + (Rks>>2) ;
      RL = Rks&3 ;
      if(RM>15) RM = 15 ;
      switch(DR)
      { 
        case 0:
          dphaseDRTable[DR][Rks] = 0 ;
          break ;
        default:
          dphaseDRTable[DR][Rks] = rate_adjust((RL + 4) << (RM - 1));
          break ;
      }
    }
}

static void makeRksTable(void)
{

  int fnum8, block, KR ;

  for(fnum8 = 0 ; fnum8 < 2 ; fnum8++)
    for(block = 0 ; block < 8 ; block++)
      for(KR = 0; KR < 2 ; KR++)
      {
        if(KR!=0)
          rksTable[fnum8][block][KR] = ( block << 1 ) + fnum8 ;
        else
          rksTable[fnum8][block][KR] = block >> 1 ;
      }
}


void dump2patch(unsigned char *dump, OPLL_PATCH *patch)
{
  patch[0].AM = (dump[0]>>7)&1 ;
  patch[1].AM = (dump[1]>>7)&1 ;
  patch[0].PM = (dump[0]>>6)&1 ;
  patch[1].PM = (dump[1]>>6)&1 ;
  patch[0].EG = (dump[0]>>5)&1 ;
  patch[1].EG = (dump[1]>>5)&1 ;
  patch[0].KR = (dump[0]>>4)&1 ;
  patch[1].KR = (dump[1]>>4)&1 ;
  patch[0].ML = (dump[0])&15 ;
  patch[1].ML = (dump[1])&15 ;
  patch[0].KL = (dump[2]>>6)&3 ;
  patch[1].KL = (dump[3]>>6)&3 ;
  patch[0].TL = (dump[2])&63 ;
  patch[0].FB = (dump[3])&7 ;
  patch[0].WF = (dump[3]>>3)&1 ;
  patch[1].WF = (dump[3]>>4)&1 ;
  patch[0].AR = (dump[4]>>4)&15 ;
  patch[1].AR = (dump[5]>>4)&15 ;
  patch[0].DR = (dump[4])&15 ;
  patch[1].DR = (dump[5])&15 ;
  patch[0].SL = (dump[6]>>4)&15 ;
  patch[1].SL = (dump[7]>>4)&15 ;
  patch[0].RR = (dump[6])&15 ;
  patch[1].RR = (dump[7])&15 ;
}

static void makeDefaultPatch()
{
  int i, j ;

  for(i=0;i<OPLL_TONE_NUM;i++)
    for(j=0;j<19;j++)
    dump2patch(default_inst[i]+j*16,&default_patch[i][j*2]) ;
}

/************************************************************

                      Calc Parameters

************************************************************/

INLINE static uint32 calc_eg_dphase(OPLL_SLOT *slot)
{

  switch(slot->eg_mode)
  {
    case ATTACK:
      return dphaseARTable[slot->patch->AR][slot->rks] ;
  
    case DECAY:
      return dphaseDRTable[slot->patch->DR][slot->rks] ;
  
    case SUSHOLD:
      return 0 ;

    case SUSTINE:
      return dphaseDRTable[slot->patch->RR][slot->rks] ;
  
    case RELEASE:
      if(slot->sustine)
        return dphaseDRTable[5][slot->rks] ;
      else if(slot->patch->EG)
        return dphaseDRTable[slot->patch->RR][slot->rks] ;
      else 
        return dphaseDRTable[7][slot->rks] ;

    case FINISH:
      return 0 ;

    default:
      return 0 ;
  }
}

/*************************************************************

                    OPLL internal interfaces

*************************************************************/
#define SLOT_BD1 12
#define SLOT_BD2 13
#define SLOT_HH 14
#define SLOT_SD 15
#define SLOT_TOM 16
#define SLOT_CYM 17

#define UPDATE_PG(S)  (S)->dphase = dphaseTable[(S)->fnum][(S)->block][(S)->patch->ML]
#define UPDATE_TLL(S)\
(((S)->type==0)?\
((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->patch->TL][(S)->patch->KL]):\
((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->volume][(S)->patch->KL]))
#define UPDATE_RKS(S) (S)->rks = rksTable[((S)->fnum)>>8][(S)->block][(S)->patch->KR] 
#define UPDATE_WF(S)  (S)->sintbl = waveform[(S)->patch->WF] 
#define UPDATE_EG(S)  (S)->eg_dphase = calc_eg_dphase(S) 
#define UPDATE_ALL(S)\
  UPDATE_PG(S);\

⌨️ 快捷键说明

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