📄 ym2151.c
字号:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "driver.h"
#include "ym2151.h"
/*
** some globals ...
*/
#define USE_MAME_TIMERS
/*undef this if you don't want MAME timer system to be used*/
typedef struct{ /*oscillator data */
unsigned int phase; /*accumulated oscillator phase (in indexes) (fixed point)*/
unsigned int freq; /*oscillator frequency (in indexes per sample) (fixed point)*/
signed int LFOpm; /*phase modulation from LFO*/
unsigned int volume; /*oscillator volume (fixed point) */
signed int attack_volume;/*used for attack phase calculations*/
unsigned int TL; /*Total attenuation Level*/
unsigned int delta_AR; /*volume delta for attack phase (fixed point)*/
unsigned int delta_D1R; /*volume delta for decay phase (fixed point)*/
unsigned int D1L; /*when envelope reaches this level Envelope Generator goes into D2R*/
unsigned int delta_D2R; /*volume delta for sustain phase (fixed point)*/
unsigned int delta_RR; /*volume delta for release phase (fixed point)*/
unsigned int state; /*Envelope state: 4-attack(AR) 3-decay(D1R) 2-sustain(D2R) 1-release(RR) 0-off*/
unsigned int AMSmask; /*LFO AMS enable mask*/
signed int * connect; /*oscillator output direction*/
/*Begin of channel specific data*/
/*The trick : each operator number 0 contains channel specific data*/
signed int OscilFB; /*oscillator self feedback value used only by operators 0*/
unsigned int FeedBack; /*feedback shift value for operators 0 in each channel*/
unsigned int KC; /*KC for each channel*/
unsigned int KF; /*KF for each channel*/
unsigned int PMS; /*PMS for each channel*/
unsigned int AMS; /*AMS for each channel*/
unsigned int PAN; /*bit 7-right enable, bit 6-left enable: 0-off, 1-on*/
/*End of channel specific data*/
unsigned int key; /*0=last key was KEYOFF, 1=last key was KEON*/
unsigned int KS; /*Key Scale*/
unsigned int AR; /*Attack rate*/
unsigned int D1R; /*Decay rate*/
unsigned int D2R; /*Sustain rate*/
unsigned int RR; /*Release rate*/
unsigned int mul; /*phase multiply*/
unsigned int DT1; /*DT1 index*32 */
unsigned int DT2; /*DT2 index*/
unsigned int KCindex; /*Used for LFO pm calculations ...........*/
unsigned int DT1val; /*used for LFO pm calculations ...........*/
} OscilRec;
/* here's the virtual YM2151 */
typedef struct ym2151_v{
int status; /*chip status (BUSY, IRQ Flags)*/
OscilRec Oscils[32]; /*there are 32 operators in YM2151*/
unsigned int LFOphase; /*accumulated LFO phase (in indexes) (fixed point)*/
unsigned int LFOfrq; /*LFO frequency (in indexes per sample) (fixed point)*/
unsigned int PMD; /*LFO Phase Modulation Depth*/
unsigned int AMD; /*LFO Amplitude Modulation Depth*/
unsigned int LFOwave; /*LFO waveform (0-saw, 1-square, 2-triangle, 3-random noise)*/
unsigned int LFA; /*current AM from LFO*/
signed int LFP; /*current PM from LFO*/
unsigned int CT; /*output control pins (bit7 CT2, bit6 CT1)*/
unsigned int noise; /*noise register (bit 7 - noise enable, bits 4-0 - noise freq*/
unsigned int IRQenable; /*IRQ enable for timer B (bit 3) and timer A (bit 2)*/
#ifdef USE_MAME_TIMERS
void *TimATimer,*TimBTimer; /* ASG 980324 -- added for tracking timers */
double TimerATime[1024]; /*Timer A times for MAME*/
double TimerBTime[256]; /*Timer B times for MAME*/
#else
int TimA,TimB; /*timer A,B enable (0-disabled)*/
signed int TimAVal,TimBVal; /*current value of timer*/
unsigned int TimerA[1024]; /*Timer A deltas*/
unsigned int TimerB[256]; /*Timer B deltas*/
#endif
unsigned int TimAIndex,TimBIndex;/*timers' indexes*/
void (*handler)(void); /*IRQ function handler*/
void (*porthandler)(int offset,int data); /*port write handler*/
unsigned int freq[11*12*64]; /*11 octaves, 12 semitones, 64 'cents' */
/*
* Frequency-deltas to get the closest frequency possible.
* There're 11 octaves because of DT2 (max 950 cents over base frequency)
* and LFO phase modulation (max 700 cents _over_ AND _below_ base frequency)
* Summary: octave explanation
* 0 note code - LFO PM
* 1 note code
* 2 note code
* 3 note code
* 4 note code
* 5 note code
* 6 note code
* 7 note code
* 8 note code
* 9 note code + DT2 + LFO PM
* 10 note code + DT2 + LFO PM
*/
signed int DT1freq[8*32];
/*
* Frequency deltas for DT1. These deltas alter operator frequency
* after it has been taken from frequency-deltas table.
*/
unsigned int LFOfreq[256]; /*frequency deltas for LFO*/
unsigned int A_Time[64+32]; /*attack deltas (64 keycodes + 32 RKS's = 96)*/
unsigned int D_Time[64+32]; /*decay deltas (64 keycodes + 32 RKS's = 96)*/
unsigned int clock; /* this will be passed from 2151intf.c */
unsigned int sampfreq; /* this will be passed from 2151intf.c */
unsigned int need_refresh; /* 1 if emulator needs refreshing before calculating new samples*/
} YM2151;
/*
** Shifts below are subject to change if sampling frequency changes...
*/
#define FREQ_SH 16 /* 16.16 fixed point for frequency calculations */
#define LFO_SH 24 /* 8.24 fixed point for LFO frequency calculations */
#define ENV_SH 16 /* 16.16 fixed point for envelope calculations */
#define TIMER_SH 16 /* 16.16 fixed point for timers calculations */
/*if you change these values (ENV_SOMETHING) you have to take care of attack_curve*/
#define ENV_BITS 10
#define ENV_RES ((int)1<<ENV_BITS)
#define ENV_STEP (96.0/ENV_RES)
#define MAX_VOLUME_INDEX ((ENV_RES-1)<<ENV_SH)
#define MIN_VOLUME_INDEX ((1<<ENV_SH)-1)
#define VOLUME_OFF (ENV_RES<<ENV_SH)
#define SIN_BITS 12
#define SIN_LEN ((int)1<<SIN_BITS)
#define SIN_MASK (SIN_LEN-1)
#define LFO_BITS 8
#define LFO_LEN ((int)1<<LFO_BITS)
#define LFO_MASK (LFO_LEN-1)
#define FINAL_SH16 0 /*this shift is applied to final output of all channels to get 16-bit sample*/
#define FINAL_SH8 8 /*this shift is applied to final output of all channels to get 8-bit sample*/
#define TL_TAB_LEN (2*(ENV_RES + ENV_RES + ENV_RES + SIN_LEN))
static signed int * TL_TAB = NULL;
/*
* Offset in this table is calculated as:
*
* 1st ENV_RES:
* TL- main offset (Total attenuation Level), range 0 to 1023 (0-96 dB)
* 2nd ENV_RES:
* current envelope value of the operator, range 0 to 1023 (0-96 dB)
* 3rd ENV_RES:
* Amplitude Modulation from LFO, range 0 to 1023 (0-96dB)
* 4th SIN_LEN:
* Sin Wave Offset from sin_tab, range 0 to about 56 dB only, but lets
* simplify things and assume sin could be 96 dB, range 0 to 1023
*
* Length of this table is doubled because we have two separate parts
* for positive and negative halves of sin wave (above and below X axis).
*/
static signed int * sin_tab[SIN_LEN];
/* sin waveform table in decibel scale */
static unsigned int D1LTab[16];
/*decibel table to convert from D1L values to volume index*/
static unsigned int attack_curve[ENV_RES];
/*attack curve for envelope attack phase*/
static unsigned int KC_TO_INDEX[16*8]; /*8 octaves * 16 note codes*/
/*
* Translate from key code KC (OCT2 OCT1 OCT0 N3 N2 N1 N0) to
* index in frequency-deltas table.
*/
#define EG_ATT 4
#define EG_DEC 3
#define EG_SUS 2
#define EG_REL 1
#define EG_OFF 0
static unsigned char sample_16bit; /* 1 -> 16 bit sample, 0 -> 8 bit */
static unsigned int YMNumChips; /* total # of YM2151's emulated */
/*these variables stay here because of speedup purposes only */
static SAMP *bufL, *bufR;
static unsigned int mask[16];
static signed int c1,m2,c2; /*Phase Modulation input for operators 2,3,4*/
static signed int chanout;
static YM2151 * PSG;
static YM2151 * YMPSG = NULL; /* array of YM2151's */
static unsigned char DT1Tab[4*32]={ /* 4*32 DT1 values */
/*
* DT1 defines offset in Hertz from base note * mul
*
* This table is converted while initialization...
*/
/* DT1=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,
/* DT1=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, 9,10,
/* DT1=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,17,19,20,
/* DT1=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
};
static unsigned int DT2Tab[4]={ /* 4 DT2 values */
/*
* DT2 defines offset in cents from base note
*
* This table defines offset in frequency-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
};
static unsigned int AttackTab[73]={
/*
* This data is valid ONLY for YM2151. Other Yamaha's FM chips seems to use
* different shape of envelope attack phase. I'm quite sure that curve of OPL2/3
* is *similiar*, but much smoother. These chips seem to use something
* like "a 42dB curve".
*
* This data was reverse-engineered by me (Jarek Burczynski). Keep in mind
* that I spent a _lot_ of time researching this information, so be so kind as
* to send me an e-mail before you use it, please.
*/
0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,16, /*16*/
18 ,20 ,22 ,24 ,26 ,28 ,31 ,34 ,37 ,40 ,43 ,46 ,50 ,54 ,58 ,63, /*16*/
68 ,73 ,78 ,84 ,90 ,97 ,104,111,120,129,138,148,158,168,180,193, /*16*/
207,222,238,254,271,289,308,329,352,377,404,433,464,498,535,575, /*16*/
618,664,713,766,823,884,950,1021,1023 /*9*/
};
static unsigned char MULTab[16]={1,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30};
void init_tables(void)
{
signed int x,i;
double m;
for(i=0; i<SIN_LEN; i++){
m = sin(2*/*PI*/3.14159265358979323846*i/SIN_LEN); /*count sin value*/
if ( (m<0.0001) && (m>-0.0001) ){ /*is m near zero ?*/
m = ENV_RES-1;
}else{
if (m>0.0){
m = 20*log10(1.0/m); /*and how many decibels is it?*/
m = m / ENV_STEP;
}else{
m = 20*log10(-1.0/m); /*and how many decibels is it?*/
m = (m / ENV_STEP) + TL_TAB_LEN/2;
}
}
sin_tab[ i ] = &TL_TAB[ (unsigned int)m ];
}
for( x=0; x<TL_TAB_LEN/2; x++ ){
if (x<ENV_RES)
m = ((1<<(SIN_BITS+2))-1) / pow(10, x * ENV_STEP /20);
else
m = 0;
TL_TAB[ x ] = m;
TL_TAB[ x + TL_TAB_LEN/2 ] = -m;
}
/* create (almost perfect) attack curve */
for (i=0; i<ENV_RES; i++) /*clear the curve*/
attack_curve[i] = MAX_VOLUME_INDEX;
for (i=0; i<73; i++){ /*create curve*/
for (x=i*14; x<i*14+14; x++){
attack_curve[x] = AttackTab[i] << ENV_SH;
}
}
for (i=0; i<16; i++){
m = (i<15?i:i+16) * (3.0/ENV_STEP); /*every 3 dB except for all bits = '1' = 45dB+48dB*/
x = m * (double)(1<<ENV_SH);
D1LTab[i] = x;
}
/* calculate KC to index table */
x=0;
for (i=0; i<16*8; i++){
KC_TO_INDEX[i]=((i>>4)*12*64) + x*64 + 12*64;
if ((i&3)!=3) x++; /* change note code */
if ((i&15)==15) x=0; /* new octave */
}
}
void init_chip_tables(YM2151 *chip)
{
int i,j,oct;
double mult,pom,pom2,clk;
double scaler; /* formula below is true for chip clock=3579545 */
/* so we need to scale its output accordingly to the chip clock */
scaler= (double)chip->clock / 3579545.0;
/*this loop calculates Hertz values for notes from c#0 to c-8*/
/*including 64 'cents' (100/64 that is 1.5625 of real cent) for each semitone*/
oct = 12*64;
mult = (int)1<<FREQ_SH;
for (i=0; i<11*12*64; i++){
pom = scaler * 6.875 * pow (2, ((i+4*64)*1.5625/1200.0) ); /*13.75Hz is note A 12semitones below A-0, so C#0 is 4 semitones above then*/
/*calculate phase increment for above precounted Hertz value*/
j = ( (pom*SIN_LEN) / (double)chip->sampfreq )*mult; /*fixed point*/
j /= 2.0; /*divided by 2, because our first octave is one octave below standard */
chip->freq[i] = j;
}
mult = (int)1<<FREQ_SH;
for (j=0; j<4; j++){
for (i=0; i<32; i++){
pom = ( (double)DT1Tab[j*32+i] * ((double)chip->clock/4.0) ) / (double)(1<<24);
/*calculate phase increment for above precounted Hertz value*/
chip->DT1freq[j*32+i] = ( (pom*SIN_LEN) / (double)chip->sampfreq )*mult; /*fixed point*/
chip->DT1freq[(j+4)*32+i] = -chip->DT1freq[j*32+i];
}
}
mult = (int)1<<LFO_SH;
clk = (double)chip->clock;
for (i=0; i<256; i++){
j = i & 0x0f;
pom = fabs( (clk/65536/(1<<(i/16)) ) - (clk/65536/32/(1<<(i/16)) * (j+1)) );
/*calculate phase increment for above precounted Hertz value*/
chip->LFOfreq[0xff-i] = ( (pom*LFO_LEN) / (double)chip->sampfreq ) * mult; /*fixed point*/
}
for (i=0; i<4; i++)
chip->A_Time[i] = chip->D_Time[i] = 0; /*infinity*/
for (i=4; i<64; i++){
pom2 = ( (double)chip->clock / (double)chip->sampfreq );
if (i<60) pom2 *= 1.0 + (i&3)*0.25;
pom2 *= 1<<((i>>2)-1);
pom2 *= (double)(1<<ENV_SH);
if (i<52){
pom = pom2 / 27876.0; /*AR scale value 0-12*/
}else{
if ( (i>=52) && (i<56) ){
pom = pom2 / 30600.0; /*AR scale value 13*/
}else{
if ( (i>=56) && (i<60) ){
pom = pom2 / 32200.0; /*AR scale value 14*/
}else{
pom = pom2 / 30400.0; /*AR scale value 15*/
}
}
}
if (i==63) pom=(ENV_RES<<ENV_SH);
pom2 = pom2 / 385303.0; /*DR scale value*/
chip->A_Time[i] = pom;
chip->D_Time[i] = pom2;
}
for (i=0; i<32; i++){
chip->A_Time[64+i]=chip->A_Time[63];
chip->D_Time[64+i]=chip->D_Time[63];
}
/* precalculate timers' deltas */
/* User's Manual pages 15,16 */
mult = (int)1<<TIMER_SH;
for (i=0; i<1024; i++){
/* ASG 980324: changed to compute both TimerA and TimerATime */
pom= ( 64.0 * (1024.0-i) / chip->clock ) ;
#ifdef USE_MAME_TIMERS
chip->TimerATime[i] = pom;
#else
chip->TimerA[i] = pom * chip->sampfreq * mult; /*number of samples that timer period takes (fixed point) */
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -