📄 fm.c
字号:
#define ADPCMA_VOLUME_RATE (8) /* DELTA-T volume rate */
#define ADPCMB_VOLUME_RATE (32) /* ADOCM volume rate */
#define ADPCMA_CURVE_DIVIDE 8 /* DELTA-T curve rate */
#define ADPCMB_CURVE_DIVIDE 1 /* ADPCM curve rate */
/*
**
** File: fm.c -- software implementation of FM sound generator
**
** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
**
** Version 0.34M
**
*/
/*
no check:
OPN SSG type envelope
YM2612 DAC output mode
YM2151 CSM speech mode
no support:
status busy flag (already not busy )
LFO contoller (YM2612/YM2610/YM2608/YM2151)
YM2151 noise mode
YM2151 output pins (CT0 and CT1)
YM2608/YM2610 Expansion status/Expansion interrupt
YM2608 DELTA-T-ADPCM and RYTHM
YM2610 DELTA-T-ADPCM with PCM port
YM2610 PCM memory data access
preliminary :
key scale level rate (?)
attack rate time rate , curve (?)
decay rate time rate , curve (?)
self feedback calcration
YM2610 ADPCM mixing level
Problem :
is sometime hiss noize heard ?
note:
OPN OPM
fnum fMus * 2^20 / (fM/(12*n))
TimerOverA (12*n)*(1024-NA)/fFM 64*(1024-Na)/fm
TimerOverB (12*n)*(256-NB)/fFM 1024*(256-Nb)/fm
output bits 10bit<<3bit 16bit * 2ch (YM3012=10bit<<3bit)
sampling rate fFM / (12*6) ? fFM / 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 "support.h" /* use RAINE */
#endif
#include "ay8910.h"
#include "fm.h"
#ifndef PI
#define PI 3.14159265357989
#endif
#define ADPCM_SHIFT (10)
#ifdef SIGNED_SAMPLES
#define AUDIO_CONV(A) ((A))
#define AUDIO_CONV16(A) ((A))
#else
#define AUDIO_CONV(A) ((A)^0x80)
#define AUDIO_CONV16(A) ((A)^0x8000)
#endif
/* ------------------------------------------------------------------ */
#ifdef __RAINE__
#define INTERNAL_TIMER /* use internal timer */
#endif
/* -------------------- speed up optimize switch -------------------- */
/* ---------- Enable ---------- */
#define TL_SAVE_MEM /* save some memories for total level */
/* ---------- Disable ---------- */
#if 0
#define SEG_SUPPORT /* OPN SSG type envelope support */
#define LFO_SUPPORT /* LFO support */
#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
#define FREQ_BITS 24 /* frequency turn */
/* counter bits = 21 , octerve 7 */
#define FREQ_RATE (1<<(FREQ_BITS-21))
#define TL_BITS (FREQ_BITS+2)
/* final output shift */
#define OPN_OUTSB (TL_BITS+2-16) /* OPN output final shift 16bit */
#define OPN_OUTSB_8 (OPN_OUTSB+8) /* OPN output final shift 8bit */
#define OPM_OUTSB (TL_BITS+2-16) /* OPM output final shift 16bit */
#define OPM_OUTSB_8 (OPM_OUTSB+8) /* OPM output final shift 8bit */
/* limit minimum and maximum */
#define OPN_MAXOUT (0x7fff<<OPN_OUTSB)
#define OPN_MINOUT (-0x8000<<OPN_OUTSB)
#define OPM_MAXOUT (0x7fff<<OPM_OUTSB)
#define OPM_MINOUT (-0x8000<<OPM_OUTSB)
#define OPNBAD_MAXOUT (0x7fff)
#define OPNBAD_MINOUT (-0x8000)
/* -------------------- quality selection --------------------- */
/* sinwave entries */
/* used static memory = SIN_ENT * 4 (byte) */
#define SIN_ENT 2048
/* output level entries (envelope,sinwave) */
/* envelope counter lower bits */
#define ENV_BITS 16
/* envelope output entries */
#define EG_ENT 4096
/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
/* used static memory = EG_ENT*4 (byte) */
#ifdef SEG_SUPPORT
#define EG_OFF ((3*EG_ENT)<<ENV_BITS) /* OFF */
#define EG_UED EG_OFF
#define EG_UST ((2*EG_ENT)<<ENV_BITS) /* UPSISE START */
#define EG_DED EG_UST
#else
#define EG_OFF ((2*EG_ENT)<<ENV_BITS) /* OFF */
#define EG_DED EG_OFF
#endif
#define EG_DST (EG_ENT<<ENV_BITS) /* DECAY START */
#define EG_AED EG_DST
#define EG_AST 0 /* ATTACK START */
#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step */
/* LFO table entries */
#define LFO_ENT 512
/* -------------------- local defines , macros --------------------- */
/* number of maximum envelope counter */
/* #define ENV_OFF ((EG_ENT<<ENV_BITS)-1) */
/* 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
/* envelope phase */
#define ENV_MOD_OFF 0x00
#define ENV_MOD_RR 0x01
#define ENV_MOD_SR 0x02
#define ENV_MOD_DR 0x03
#define ENV_MOD_AR 0x04
#define ENV_SSG_SR 0x05
#define ENV_SSG_DR 0x06
#define ENV_SSG_AR 0x07
/* bit0 = right enable , bit1 = left enable (FOR YM2612) */
#define OPN_RIGHT 1
#define OPN_LEFT 2
#define OPN_CENTER 3
/* bit0 = left enable , bit1 = right enable */
#define OPM_LEFT 1
#define OPM_RIGHT 2
#define OPM_CENTER 3
/* */
/* YM2608 Rhythm Number */
#define RY_BD 0
#define RY_SD 1
#define RY_TOP 2
#define RY_HH 3
#define RY_TOM 4
#define RY_RIM 5
/* ---------- OPN / OPM one channel ---------- */
typedef struct fm_slot {
int *DT; /* detune :DT_TABLE[DT] */
int DT2; /* multiple,Detune2:(DT2<<4)|ML for OPM*/
int TL; /* total level :TL << 8 */
signed int TLL; /* adjusted now TL */
unsigned char KSR; /* key scale rate :3-KSR */
int *AR; /* attack rate :&AR_TABLE[AR<<1] */
int *DR; /* decay rate :&DR_TALBE[DR<<1] */
int *SR; /* sustin rate :&DR_TABLE[SR<<1] */
int SL; /* sustin level :SL_TALBE[SL] */
int *RR; /* release rate :&DR_TABLE[RR<<2+2] */
unsigned char SEG; /* SSG EG type :SSGEG */
unsigned char ksr; /* key scale rate :kcode>>(3-KSR) */
unsigned int mul; /* multiple :ML_TABLE[ML] */
unsigned int Cnt; /* frequency count : */
unsigned int Incr; /* frequency step : */
/* envelope generator state */
unsigned char evm; /* envelope phase */
signed int evc; /* envelope counter */
signed int eve; /* envelope counter end point */
signed int evs; /* envelope counter step */
signed int evsa; /* envelope step for AR */
signed int evsd; /* envelope step for DR */
signed int evss; /* envelope step for SR */
signed int evsr; /* envelope step for RR */
/* LFO */
unsigned char ams;
unsigned char pms;
}FM_SLOT;
typedef struct fm_chan {
FM_SLOT SLOT[4];
unsigned char PAN; /* PAN NONE,LEFT,RIGHT or CENTER */
unsigned char ALGO; /* algorythm */
unsigned char FB; /* feed back :&FB_TABLE[FB<<8] */
int op1_out; /* op1 output foe beedback */
/* algorythm state */
int *connect1; /* operator 1 connection pointer */
int *connect2; /* operator 2 connection pointer */
int *connect3; /* operator 3 connection pointer */
int *connect4; /* operator 4 connection pointer */
/* phase generator state */
unsigned int fc; /* fnum,blk :calcrated */
unsigned char fn_h; /* freq latch : */
unsigned char kcode; /* key code : */
} FM_CH;
/* OPN/OPM common state */
typedef struct fm_state {
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
int freqbase; /* frequency base */
double TimerBase; /* Timer base time */
unsigned char address; /* address register */
unsigned char irq; /* interrupt level */
unsigned char irqmask; /* irq mask */
unsigned char status; /* status flag */
unsigned int mode; /* mode CSM / 3SLOT */
int TA; /* timer a */
int TAC; /* timer a counter */
unsigned char TB; /* timer b */
int TBC; /* timer b counter */
void *timer_a_timer; /* timer for a */
void *timer_b_timer; /* timer for b */
/* speedup customize */
/* time tables */
signed int DT_TABLE[8][32]; /* detune tables */
signed int AR_TABLE[94]; /* atttack rate tables */
signed int DR_TABLE[94]; /* decay rate tables */
/* LFO */
unsigned int LFOCnt;
unsigned int LFOIncr;
/* Extention Timer and IRQ handler */
FM_TIMERHANDLER Timer_Handler;
FM_IRQHANDLER IRQ_Handler;
}FM_ST;
/* OPN 3slot struct */
typedef struct opn_3slot {
unsigned int fc[3]; /* fnum3,blk3 :calcrated */
unsigned char fn_h[3]; /* freq3 latch */
unsigned char kcode[3]; /* key code : */
}FM_3SLOT;
typedef struct adpcm_state {
unsigned char flag;
unsigned char flagMask;
unsigned int now_addr;
unsigned int step;
unsigned int start;
unsigned int end;
unsigned int delta;
int IL;
int volume;
int *pan; /* &outd[OPN_xxxx] */
int adpcmx, adpcmd;
}ADPCM_CH;
/* OPN/A/B common state */
typedef struct opn_f {
unsigned char type; /* chip type */
unsigned char index; /* chip index (number of chip) */
FM_ST ST; /* general state */
FM_3SLOT SL3; /* 3 slot mode state */
FM_CH *P_CH; /* pointer of CH */
unsigned int FN_TABLE[2048]; /* fnumber -> increment counter */
} FM_OPN;
/* here's the virtual YM2203(OPN) (Used by YM2608 / YM2612) */
typedef struct ym2203_f {
FM_OPN OPN; /* OPN state */
/* FMSAMPLE *Buf;*/ /* sound buffer */
FM_CH CH[3]; /* channel state */
} YM2203;
/* here's the virtual YM2608 */
typedef struct ym2608_f {
FM_OPN OPN; /* OPN state */
/* FMSAMPLE *Buf[YM2608_NUMBUF];*/ /* sound buffer */
FM_CH CH[6]; /* channel state */
int address1; /* additional address register */
/* PCM Part (YM2608) */
int ADMode; /* mode of ADPCM unit */
int ADPAN; /* PAN */
int ADStart; /* Start address */
int ADStop; /* Stop address */
int ADDelta; /* Playback sampling rate */
int ADTL; /* output level */
int ADLimit; /* Limit address */
int ADData; /* PCM data */
/* Rhythm Part (YM2608) */
int RTL; /* Total level */
int RPAN[6]; /* PAN */
int RIL[6]; /* IL */
} YM2608;
/* here's the virtual YM2610 */
typedef struct ym2610_f {
FM_OPN OPN; /* OPN state */
/* FMSAMPLE *Buf[YM2610_NUMBUF];*/ /* sound buffer */
FM_CH CH[6]; /* channel state */
int address1; /* address register1 */
/**** ADPCM control ****/
char *pcmbuf[2];
unsigned int pcm_size[2];
int *TL_adpcmb;
ADPCM_CH adpcm[7]; /* normal ADPCM & deltaT ADPCM */
unsigned int adpcmreg[2][0x30];
int port0state, port0control, port0shift;
int port1state, port1control, port1shift;
unsigned char adpcm_justfinished,adpcm_statusmask;
} YM2610;
/* here's the virtual YM2612 */
typedef struct ym2612_f {
FM_OPN OPN; /* OPN state */
/* FMSAMPLE *Buf[YM2612_NUMBUF];*/ /* sound buffer */
FM_CH CH[6]; /* channel state */
int address1; /* address register1 */
/* dac output (YM2612) */
int dacen;
int dacout;
} YM2612;
/* here's the virtual YM2151(OPM) */
typedef struct ym2151_f {
/* FMSAMPLE *Buf[YM2151_NUMBUF];*/ /* sound buffers */
FM_ST ST; /* general state */
FM_CH CH[8]; /* channel state */
unsigned char NReg; /* noise enable,freq */
unsigned char pmd; /* LFO pmd level */
unsigned char amd; /* LFO amd level */
unsigned char ctw; /* CT0,1 and waveform */
unsigned int KC_TABLE[8*12*64+950];/* keycode,keyfunction -> count */
void (*PortWrite)(int offset,int data);/* callback when write CT0/CT1 */
} YM2151;
/* -------------------- tables --------------------- */
/* key scale level */
/* !!!!! preliminary !!!!! */
#define DV (1/EG_STEP)
static const unsigned char KSL[32]=
{
#if 1
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
#else
0.000/DV , 0.000/DV , 0.000/DV , 0.000/DV , /* OCT 0 */
0.000/DV , 0.000/DV , 0.000/DV , 1.875/DV , /* OCT 1 */
0.000/DV , 0.000/DV , 3.000/DV , 4.875/DV , /* OCT 2 */
0.000/DV , 3.000/DV , 6.000/DV , 7.875/DV , /* OCT 3 */
0.000/DV , 6.000/DV , 9.000/DV ,10.875/DV , /* OCT 4 */
0.000/DV , 9.000/DV ,12.000/DV ,13.875/DV , /* OCT 5 */
0.000/DV ,12.000/DV ,15.000/DV ,16.875/DV , /* OCT 6 */
0.000/DV ,15.000/DV ,18.000/DV ,19.875/DV /* OCT 7 */
#endif
};
#undef DV
/* OPN key frequency number -> key code follow table */
/* fnum higher 4bit -> keycode lower 2bit */
static const char OPN_FKTABLE[16]={0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3};
static const int KC_TO_SEMITONE[16]={
/*translate note code KC into more usable number of semitone*/
0*64, 1*64, 2*64, 3*64,
3*64, 4*64, 5*64, 6*64,
6*64, 7*64, 8*64, 9*64,
9*64,10*64,11*64,12*64
};
static const int DT2_TABLE[4]={ /* 4 DT2 values */
/*
* DT2 defines offset in cents from base note
*
* The table below defines offset in deltas table...
* User's Manual page 22
* Values below were calculated using formula: value = orig.val * 1.5625
*
* DT2=0 DT2=1 DT2=2 DT2=3
* 0 600 781 950
*/
0, 384, 500, 608
};
/* 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) (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
#ifdef TL_SAVE_MEM
#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
#else
#define TL_MAX (EG_ENT*4) /* tl + ksr + envelope + sinwave */
#endif
/* 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 int *TL_TABLE;
/* pointers to TL_TABLE with sinwave output offset */
static signed int *SIN_TABLE[SIN_ENT];
/* envelope output curve table */
#ifdef SEG_SUPPORT
/* attack + decay + SSG upside + OFF */
static int ENV_CURVE[3*EG_ENT+1];
#else
/* attack + decay + OFF */
static int 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_DTTABLE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -