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

📄 fm.c

📁 十七种模拟器源代码 非常有用的作课程设计不可缺少的
💻 C
📖 第 1 页 / 共 5 页
字号:
#define YM2610B_WARNING/* YM2608 rhythm data is PCM ,not an ADPCM */#define YM2608_RHYTHM_PCM/***** File: fm.c -- software implementation of FM sound generator**** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmurator development**** Version 0.37***//***** change log. (hiro-shi) ****** 08-12-98:** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA** move ROM limit check.(CALC_CH? -> 2610Write1/2)** test program (ADPCMB_TEST)** move ADPCM A/B end check.** ADPCMB repeat flag(no check)** change ADPCM volume rate (8->16) (32->48).**** 09-12-98:** change ADPCM volume. (8->16, 48->64)** replace ym2610 ch0/3 (YM-2610B)** init cur_chip (restart bug fix)** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff.** add ADPCM_SHIFT_MASK** change ADPCMA_DECODE_MIN/MAX.*//*    no check:		YM2608 rhythm sound		OPN SSG type envelope (SEG)		YM2151 CSM speech mode	no support:		status BUSY flag (everytime not busy)		YM2608 status mask (register :0x110)		YM2608 RYTHM sound		YM2608 PCM memory data access , DELTA-T-ADPCM with PCM port		YM2151 CSM speech mode with internal timer	preliminary :		key scale level rate (?)		attack rate time rate , curve		decay  rate time rate , curve		self-feedback algorythm		YM2610 ADPCM-A mixing level , decode algorythm		YM2151 noise mode (CH7.OP4)		LFO contoller (YM2612/YM2610/YM2608/YM2151)	note:                        OPN                           OPM		fnum          fM * 2^20 / (fM/(12*n))		TimerOverA    ( 12*n)*(1024-NA)/fM        64*(1024-Na)/fM		TimerOverB    (192*n)*(256-NB)/fM       1024*(256-Nb)/fM		output bits   10bit<<3bit               16bit * 2ch (YM3012=10bit<<3bit)		sampling rate fFM / (12*priscaler)      fM / 64		lfo freq                                ( fM*2^(LFRQ/16) ) / (4295*10^6)*//************************************************************************//*    comment of hiro-shi(Hiromitsu Shioya)                             *//*    YM2610(B) = (OPN-B                                                *//*    YM2610  : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch      *//*    YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch      *//************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <math.h>#ifndef __RAINE__#include "driver.h"		/* use M.A.M.E. */#else#include "deftypes.h"		/* use RAINE */#include "mame/driver.h"		/* use RAINE */#include "sasound.h"#endif#include "ay8910.h"#include "fm.h"#ifndef PI#define PI 3.14159265358979323846#endif/***** shared function building option ****/#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2612)#define BUILD_OPNB (BUILD_YM2610||BUILD_YM2610B)#define BUILD_FM_ADPCMA (BUILD_YM2608||BUILD_OPNB)#define BUILD_FM_ADPCMB (BUILD_YM2608||BUILD_OPNB)#define BUILD_STEREO (BUILD_YM2608||BUILD_YM2610||BUILD_YM2612||BUILD_YM2151)#define BUILD_LFO (BUILD_YM2608||BUILD_YM2610||BUILD_YM2612||BUILD_YM2151)#if BUILD_FM_ADPCMB/* include external DELTA-T ADPCM unit */#include "ymdeltat.h"		/* DELTA-T ADPCM UNIT */#define DELTAT_MIXING_LEVEL (4) /* DELTA-T ADPCM MIXING LEVEL */#endif/* -------------------- sound quality define selection --------------------- *//* sinwave entries *//* used static memory = SIN_ENT * 4 (byte) */#define SIN_ENT 2048/* lower bits of envelope counter */#define ENV_BITS 16/* envelope output entries */#define EG_ENT   4096#define EG_STEP (96.0/EG_ENT) /* OPL == 0.1875 dB */#if FM_LFO_SUPPORT/* LFO table entries */#define LFO_ENT 512#define LFO_SHIFT (32-9)#define LFO_RATE 0x10000#endif/* -------------------- preliminary define section --------------------- *//* attack/decay rate time rate */#define OPM_ARRATE     399128#define OPM_DRRATE    5514396/* It is not checked , because I haven't YM2203 rate */#define OPN_ARRATE  OPM_ARRATE#define OPN_DRRATE  OPM_DRRATE/* PG output cut off level : 78dB(14bit)? */#define PG_CUT_OFF ((int)(78.0/EG_STEP))/* EG output cut off level : 68dB? */#define EG_CUT_OFF ((int)(68.0/EG_STEP))#define FREQ_BITS 24		/* frequency turn          *//* PG counter is 21bits @oct.7 */#define FREQ_RATE   (1<<(FREQ_BITS-21))#define TL_BITS    (FREQ_BITS+2)/* OPbit = 14(13+sign) : TL_BITS+1(sign) / output = 16bit */#define TL_SHIFT (TL_BITS+1-(14-16))/* output final shift */#define FM_OUTSB  (TL_SHIFT-FM_OUTPUT_BIT)#define FM_MAXOUT ((1<<(TL_SHIFT-1))-1)#define FM_MINOUT (-(1<<(TL_SHIFT-1)))/* -------------------- local defines , macros --------------------- *//* envelope counter position */#define EG_AST   0					/* start of Attack phase */#define EG_AED   (EG_ENT<<ENV_BITS)	/* end   of Attack phase */#define EG_DST   EG_AED				/* start of Decay/Sustain/Release phase */#define EG_DED   (EG_DST+(EG_ENT<<ENV_BITS)-1)	/* end   of Decay/Sustain/Release phase */#define EG_OFF   EG_DED				/* off */#if FM_SEG_SUPPORT#define EG_UST   ((2*EG_ENT)<<ENV_BITS)  /* start of SEG UPSISE */#define EG_UED   ((3*EG_ENT)<<ENV_BITS)  /* end of SEG UPSISE */#endif/* register number to channel number , slot offset */#define OPN_CHAN(N) (N&3)#define OPN_SLOT(N) ((N>>2)&3)#define OPM_CHAN(N) (N&7)#define OPM_SLOT(N) ((N>>3)&3)/* slot number */#define SLOT1 0#define SLOT2 2#define SLOT3 1#define SLOT4 3/* bit0 = Right enable , bit1 = Left enable */#define OUTD_RIGHT  1#define OUTD_LEFT   2#define OUTD_CENTER 3/* FM timer model */#define FM_TIMER_SINGLE (0)#define FM_TIMER_INTERVAL (1)/* ---------- OPN / OPM one channel  ---------- */typedef struct fm_slot {	INT32 *DT;			/* detune          :DT_TABLE[DT]       */	int DT2;			/* multiple,Detune2:(DT2<<4)|ML for OPM*/	int TL;				/* total level     :TL << 8            */	UINT8 KSR;			/* key scale rate  :3-KSR              */	const INT32 *AR;	/* attack rate     :&AR_TABLE[AR<<1]   */	const INT32 *DR;	/* decay rate      :&DR_TABLE[DR<<1]   */	const INT32 *SR;	/* sustin rate     :&DR_TABLE[SR<<1]   */	int   SL;			/* sustin level    :SL_TABLE[SL]       */	const INT32 *RR;	/* release rate    :&DR_TABLE[RR<<2+2] */	UINT8 SEG;			/* SSG EG type     :SSGEG              */	UINT8 ksr;			/* key scale rate  :kcode>>(3-KSR)     */	UINT32 mul;			/* multiple        :ML_TABLE[ML]       */	/* Phase Generator */	UINT32 Cnt;			/* frequency count :                   */	UINT32 Incr;		/* frequency step  :                   */	/* Envelope Generator */	void (*eg_next)(struct fm_slot *SLOT);	/* pointer of phase handler */	INT32 evc;			/* envelope counter                    */	INT32 eve;			/* envelope counter end point          */	INT32 evs;			/* envelope counter step               */	INT32 evsa;			/* envelope step for Attack            */	INT32 evsd;			/* envelope step for Decay             */	INT32 evss;			/* envelope step for Sustain           */	INT32 evsr;			/* envelope step for Release           */	INT32 TLL;			/* adjusted TotalLevel                 */	/* LFO */	UINT8 amon;			/* AMS enable flag              */	UINT32 ams;			/* AMS depth level of this SLOT */}FM_SLOT;typedef struct fm_chan {	FM_SLOT	SLOT[4];	UINT8 PAN;			/* PAN :NONE,LEFT,RIGHT or CENTER */	UINT8 ALGO;			/* Algorythm                      */	UINT8 FB;			/* shift count of self feed back  */	INT32 op1_out[2];	/* op1 output for beedback        */	/* Algorythm (connection) */	INT32 *connect1;		/* pointer of SLOT1 output    */	INT32 *connect2;		/* pointer of SLOT2 output    */	INT32 *connect3;		/* pointer of SLOT3 output    */	INT32 *connect4;		/* pointer of SLOT4 output    */	/* LFO */	INT32 pms;				/* PMS depth level of channel */	UINT32 ams;				/* AMS depth level of channel */	/* Phase Generator */	UINT32 fc;			/* fnum,blk    :adjusted to sampling rate */	UINT8 fn_h;			/* freq latch  :                   */	UINT8 kcode;		/* key code    :                   */} FM_CH;/* OPN/OPM common state */typedef struct fm_state {	UINT8 index;		/* chip index (number of chip) */	int clock;			/* master clock  (Hz)  */	int rate;			/* sampling rate (Hz)  */	double freqbase;	/* frequency base      */	double TimerBase;	/* Timer base time     */	UINT8 address;		/* address register    */	UINT8 irq;			/* interrupt level     */	UINT8 irqmask;		/* irq mask            */	UINT8 status;		/* status flag         */	UINT32 mode;		/* mode  CSM / 3SLOT   */	int TA;				/* timer a             */	int TAC;			/* timer a counter     */	UINT8 TB;			/* timer b             */	int TBC;			/* timer b counter     */	/* speedup customize */	/* local time tables */	INT32 DT_TABLE[8][32];	/* DeTune tables       */	INT32 AR_TABLE[94];		/* Atttack rate tables */	INT32 DR_TABLE[94];		/* Decay rate tables   */	/* Extention Timer and IRQ handler */	FM_TIMERHANDLER	Timer_Handler;	FM_IRQHANDLER	IRQ_Handler;	/* timer model single / interval */	UINT8 timermodel;}FM_ST;/* -------------------- tables --------------------- *//* sustain lebel table (3db per step) *//* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/#define SC(db) (int)((db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST)static const int SL_TABLE[16]={ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)};#undef SC/* size of TL_TABLE = sinwave(max cut_off) + cut_off(tl + ksr + envelope + ams) */#define TL_MAX (PG_CUT_OFF+EG_CUT_OFF+1)/* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) *//* TL_TABLE[ 0      to TL_MAX          ] : plus  section *//* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */static INT32 *TL_TABLE;/* pointers to TL_TABLE with sinwave output offset */static INT32 *SIN_TABLE[SIN_ENT];/* envelope output curve table */#if FM_SEG_SUPPORT/* attack + decay + SSG upside + OFF */static INT32 ENV_CURVE[3*EG_ENT+1];#else/* attack + decay + OFF */static INT32 ENV_CURVE[2*EG_ENT+1];#endif/* envelope counter conversion table when change Decay to Attack phase */static int DRAR_TABLE[EG_ENT];#define OPM_DTTABLE OPN_DTTABLEstatic UINT8 OPN_DTTABLE[4 * 32]={/* this table is YM2151 and YM2612 data *//* FD=0 */  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* FD=1 */  0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,  2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,/* FD=2 */  1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,  5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,/* FD=3 */  2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,  8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22};/* multiple table */#define ML(n) (int)(n*2)static const int MUL_TABLE[4*16]= {/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */   ML(0.50),ML( 1.00),ML( 2.00),ML( 3.00),ML( 4.00),ML( 5.00),ML( 6.00),ML( 7.00),   ML(8.00),ML( 9.00),ML(10.00),ML(11.00),ML(12.00),ML(13.00),ML(14.00),ML(15.00),/* DT2=1 *SQL(2)   */   ML(0.71),ML( 1.41),ML( 2.82),ML( 4.24),ML( 5.65),ML( 7.07),ML( 8.46),ML( 9.89),   ML(11.30),ML(12.72),ML(14.10),ML(15.55),ML(16.96),ML(18.37),ML(19.78),ML(21.20),/* DT2=2 *SQL(2.5) */   ML( 0.78),ML( 1.57),ML( 3.14),ML( 4.71),ML( 6.28),ML( 7.85),ML( 9.42),ML(10.99),   ML(12.56),ML(14.13),ML(15.70),ML(17.27),ML(18.84),ML(20.41),ML(21.98),ML(23.55),/* DT2=3 *SQL(3)   */   ML( 0.87),ML( 1.73),ML( 3.46),ML( 5.19),ML( 6.92),ML( 8.65),ML(10.38),ML(12.11),   ML(13.84),ML(15.57),ML(17.30),ML(19.03),ML(20.76),ML(22.49),ML(24.22),ML(25.95)};#undef ML#if FM_LFO_SUPPORT#define PMS_RATE 0x400/* LFO runtime work */static UINT32 lfo_amd;static INT32 lfo_pmd;#endif/* Dummy table of Attack / Decay rate ( use when rate == 0 ) */static const INT32 RATE_0[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};/* -------------------- state --------------------- *//* some globals */#define TYPE_SSG    0x01    /* SSG support          */#define TYPE_OPN    0x02    /* OPN device           */#define TYPE_LFOPAN 0x04    /* OPN type LFO and PAN */#define TYPE_6CH    0x08    /* FM 6CH / 3CH         */#define TYPE_DAC    0x10    /* YM2612's DAC device  */#define TYPE_ADPCM  0x20    /* two ADPCM unit       */#define TYPE_YM2203 (TYPE_SSG)#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)#define TYPE_YM2610 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)#define TYPE_YM2612 (TYPE_6CH |TYPE_LFOPAN |TYPE_DAC)/* current chip state */static void *cur_chip = 0;		/* pointer of current chip struct */static FM_ST  *State;			/* basic status */static FM_CH  *cch[8];			/* pointer of FM channels */#if (BUILD_LFO)#if FM_LFO_SUPPORTstatic UINT32 LFOCnt,LFOIncr;	/* LFO PhaseGenerator */#endif#endif/* runtime work */static INT32 out_ch[4];		/* channel output NONE,LEFT,RIGHT or CENTER */static INT32 pg_in1,pg_in2,pg_in3,pg_in4;	/* PG input of SLOTs *//* -------------------- log output  -------------------- *//* log output level */#define LOG_ERR  3      /* ERROR       */#define LOG_WAR  2      /* WARNING     */#define LOG_INF  1      /* INFORMATION */#define LOG_LEVEL LOG_INF#ifndef __RAINE__#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x#endif/* ----- limitter ----- */#define Limit(val, max,min) { \	if ( val > max )      val = max; \	else if ( val < min ) val = min; \}/* ----- buffering one of data(STEREO chip) ----- */#if FM_STEREO_MIX/* stereo mixing */#define FM_BUFFERING_STEREO \{														\	/* get left & right output with clipping */			\	out_ch[OUTD_LEFT]  += out_ch[OUTD_CENTER];				\	Limit( out_ch[OUTD_LEFT] , FM_MAXOUT, FM_MINOUT );	\	out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER];				\	Limit( out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT );	\	/* buffering */										\	*bufL++ = out_ch[OUTD_LEFT] >>FM_OUTSB;				\	*bufL++ = out_ch[OUTD_RIGHT]>>FM_OUTSB;				\}#else/* stereo separate */#define FM_BUFFERING_STEREO \{														\	/* get left & right output with clipping */			\	out_ch[OUTD_LEFT]  += out_ch[OUTD_CENTER];				\	Limit( out_ch[OUTD_LEFT] , FM_MAXOUT, FM_MINOUT );	\	out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER];				\	Limit( out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT );	\	/* buffering */										\	bufL[i] = out_ch[OUTD_LEFT] >>FM_OUTSB;				\	bufR[i] = out_ch[OUTD_RIGHT]>>FM_OUTSB;				\}#endif#if FM_INTERNAL_TIMER/* ----- internal timer mode , update timer *//* ---------- calcrate timer A ---------- */#define INTERNAL_TIMER_A(ST,CSM_CH)					\{													\	if( ST->TAC &&  (ST->Timer_Handler==0) )		\		if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 )	\		{											\			TimerAOver( ST );						\			/* CSM mode total level latch and auto key on */	\			if( ST->mode & 0x80 )					\				CSMKeyControll( CSM_CH );			\		}											\}/* ---------- calcrate timer B ---------- */#define INTERNAL_TIMER_B(ST,step)						\{														\	if( ST->TBC && (ST->Timer_Handler==0) )				\		if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 )	\			TimerBOver( ST );							\}#else /* FM_INTERNAL_TIMER *//* external timer mode */#define INTERNAL_TIMER_A(ST,CSM_CH)#define INTERNAL_TIMER_B(ST,step)#endif /* FM_INTERNAL_TIMER *//* --------------------- subroutines  --------------------- *//* status set and IRQ handling */INLINE void FM_STATUS_SET(FM_ST *ST,int flag){	/* set status flag */	ST->status |= flag;	if ( !(ST->irq) && (ST->status & ST->irqmask) )	{		ST->irq = 1;		/* callback user interrupt handler (IRQ is OFF to ON) */		if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,1);	}}/* status reset and IRQ handling */INLINE void FM_STATUS_RESET(FM_ST *ST,int flag){	/* reset status flag */	ST->status &=~flag;	if ( (ST->irq) && !(ST->status & ST->irqmask) )	{		ST->irq = 0;

⌨️ 快捷键说明

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