From: Shamus Hammons Date: Fri, 25 Jul 2014 01:09:35 +0000 (-0500) Subject: Added missing file. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=thunder;a=commitdiff_plain;h=d22f243fc585a46e4c29d00bd32727d9f9f4055c Added missing file. --- diff --git a/src/sound.cpp b/src/sound.cpp index 3be7683..e366830 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -69,6 +69,7 @@ void InitSound(void) desired.samples = 1024; desired.callback = SoundFunc; desired.userdata = NULL; + // Also, should check to see if it got the hardware it needed, correct sample size, etc. if (SDL_OpenAudio(&desired, &obtained) < 0) { @@ -85,8 +86,8 @@ void InitSound(void) void SpawnSound(int type, int snd, int channel/* = 0*/) { - extern uint32_t psg_lens[16]; - extern uint8_t * psg_adrs[16]; +// extern uint32_t psg_lens[16]; +// extern uint8_t * psg_adrs[16]; // extern uint32_t voc_lens[32]; // extern uint8_t * voc_adrs[32]; // extern uint32_t fm_lens[14]; diff --git a/src/ym2151.cpp b/src/ym2151.cpp new file mode 100644 index 0000000..653d0e5 --- /dev/null +++ b/src/ym2151.cpp @@ -0,0 +1,1451 @@ +// +// Jarek Burczynski's YM2151 emulator +// +// Cleaned of most MAMEisms & cleaned up in general by James Hammons +// (this is mostly a placeholder until I write my own) +// + +#include "ym2151.h" + +#include +#include +#include +#include +#include + + +// Missing shit (from M.A.M.E.) + +#if 1 +#define PI 3.1415629535897932338 +static FILE * errorlog = 0; +//int cpu_scalebyfcount(int); +//void timer_remove(void *); +//void * timer_set(int, int, void (*)(int)); + +// Bogus M.A.M.E. shite +int cpu_scalebyfcount(int f) { return f; } +void timer_remove(void * foo) { printf("STUB: timer_remove()\n"); } +void * timer_set(int foo, int bar, void (* baz)(int)) { printf("STUB: timer_set()\n"); return 0; } + +#endif + + +/* +** some globals ... +*/ + +/* +** 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 */ + +#define ENV_BITS 10 +#define ENV_RES ((int)1< 16 bit sample, 0 -> 8 bit */ + +static int YMBufSize; /* size of sound buffer, in samples */ +static int YMNumChips; /* total # of YM's emulated */ + +static int TimerA[1024]; +static int TimerB[256]; + +/* ASG 980324: added */ +static double TimerATime[1024]; +static double TimerBTime[256]; + +static YM2151 * YMPSG = NULL; /* array of YM's */ + +signed int * BuffTemp = NULL; /*temporary buffer for speedup purposes*/ + +static void (* envelope_calc[5])(OscilRec *); +static void (* register_writes[256])(uint8_t, uint8_t, uint8_t); + +//save output as raw 16-bit sample - just in case you would like to listen to it offline ;-) +//#define SAVE_SAMPLE +//#define SAVE_SEPARATE_CHANNELS + +#ifdef SAVE_SAMPLE +#ifdef SAVE_SEPARATE_CHANNELS +FILE * sample1; +FILE * sample2; +FILE * sample3; +FILE * sample4; +FILE * sample5; +FILE * sample6; +#endif +FILE * samplesum; +#endif + +int PMTab[8]; /*8 channels */ +/* this table is used for PM setup of LFO */ + +int AMTab[8]; /*8 channels */ +/* this table is used for AM setup of LFO */ + +static int decib45[16]; +/*decibel table to convert from D1L values to index in lookup table*/ + +static int attack_curve[ENV_RES]; + +unsigned int divia[64]; //Attack dividers +unsigned int divid[64]; //Decay dividers +static unsigned int A_DELTAS[64+31]; //Attack deltas (64 keycodes + 31 RKS's = 95) +static unsigned int D_DELTAS[64+31]; //Decay deltas (64 keycodes + 31 RKS's = 95) + +float DT1Tab[32][4]={ /* 8 octaves * 4 key codes, 4 DT1 values */ +/* + * Table defines offset in Hertz from base frequency depending on KC and DT1 + * User's Manual page 21 +*/ +/*OCT NOTE DT1=0 DT1=1 DT1=2 DT1=3*/ +/* 0 0*/{0, 0, 0.053, 0.107}, +/* 0 1*/{0, 0, 0.053, 0.107}, +/* 0 2*/{0, 0, 0.053, 0.107}, +/* 0 3*/{0, 0, 0.053, 0.107}, +/* 1 0*/{0, 0.053, 0.107, 0.107}, +/* 1 1*/{0, 0.053, 0.107, 0.160}, +/* 1 2*/{0, 0.053, 0.107, 0.160}, +/* 1 3*/{0, 0.053, 0.107, 0.160}, +/* 2 0*/{0, 0.053, 0.107, 0.213}, +/* 2 1*/{0, 0.053, 0.160, 0.213}, +/* 2 2*/{0, 0.053, 0.160, 0.213}, +/* 2 3*/{0, 0.053, 0.160, 0.267}, +/* 3 0*/{0, 0.107, 0.213, 0.267}, +/* 3 1*/{0, 0.107, 0.213, 0.320}, +/* 3 2*/{0, 0.107, 0.213, 0.320}, +/* 3 3*/{0, 0.107, 0.267, 0.373}, +/* 4 0*/{0, 0.107, 0.267, 0.427}, +/* 4 1*/{0, 0.160, 0.320, 0.427}, +/* 4 2*/{0, 0.160, 0.320, 0.480}, +/* 4 3*/{0, 0.160, 0.373, 0.533}, +/* 5 0*/{0, 0.213, 0.427, 0.587}, +/* 5 1*/{0, 0.213, 0.427, 0.640}, +/* 5 2*/{0, 0.213, 0.480, 0.693}, +/* 5 3*/{0, 0.267, 0.533, 0.747}, +/* 6 0*/{0, 0.267, 0.587, 0.853}, +/* 6 1*/{0, 0.320, 0.640, 0.907}, +/* 6 2*/{0, 0.320, 0.693, 1.013}, +/* 6 3*/{0, 0.373, 0.747, 1.067}, +/* 7 0*/{0, 0.427, 0.853, 1.173}, +/* 7 1*/{0, 0.427, 0.907, 1.173}, +/* 7 2*/{0, 0.480, 1.013, 1.173}, +/* 7 3*/{0, 0.533, 1.067, 1.173} +}; + +static uint16_t DT2Tab[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 +}; + +static uint16_t KC_TO_INDEX[16*8]; /*16 note codes * 8 octaves */ +/*translate key code KC (OCT2 OCT1 OCT0 N3 N2 N1 N0) into index in deltas table*/ + +static signed int DT1deltas[32][8]; + +static signed int deltas[9*12*64];/*9 octaves, 12 semitones, 64 'cents' */ +/*deltas in sintable (fixed point) to get the closest frequency possible */ +/*there're 9 octaves because of DT2 (max 950 cents over base frequency) */ + +static signed int LFOdeltas[256]; /*frequency deltas for LFO*/ + + +void sin_init(void) +{ + int x, i; + float m; + + for(i=0; i -0.0001)) /*is m very close to 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]; /**/ + //if (errorlog) fprintf(errorlog,"sin %i = %i\n",i,sin_tab[i] ); + } + + for(x=0; x> 1; //oct 3 + deltas[i + oct * 2] = deltas[oct * 4 + i] >> 2; //oct 2 + deltas[i + oct * 1] = deltas[oct * 4 + i] >> 3; //oct 1 + deltas[i + oct * 0] = deltas[oct * 4 + i] >> 4; //oct 0 + + //if (errorlog) fprintf(errorlog,"deltas[%04i] = %08x\n",i,deltas[i]); + } + + for(j=0; j<4; j++) + { + for(i=0; i<32; i++) + { + pom = scaler * DT1Tab[i][j]; + //calculate phase increment for above precounted Hertz value + DT1deltas[i][j] = ((pom * SIN_LEN) / (float)YM2151_SAMPFREQ) * mult; /*fixed point*/ + DT1deltas[i][j + 4] = -DT1deltas[i][j]; + } + } + + mult = (long int)1 << LFO_SH; + m = (float)YM2151_CLOCK; + + for(i=0; i<256; i++) + { + j = i & 0x0F; + pom = scaler * fabs((m / 65536 / (1 << (i / 16))) - (m / 65536 / 32 / (1 << (i / 16)) * (j + 1))); + + /*calculate phase increment for above precounted Hertz value*/ + pom2 = ((pom * SIN_LEN) / (float)YM2151_SAMPFREQ) * mult; /*fixed point*/ + LFOdeltas[0xFF - i] = pom2; + //if (errorlog) fprintf(errorlog, "LFO[%02x] = %08x\n",0xff-i, LFOdeltas[0xff-i]); + } + + /* calculate KC to index table */ + j=0; + for(i=0; i<16*8; i++) + { + KC_TO_INDEX[i] = (i >> 4) * 12 * 64 + j * 64 ; + + if ((i & 3) != 3) + j++; /* change note code */ + + if ((i & 15) == 15) + j = 0; /* new octave */ + + //if (errorlog) fprintf(errorlog,"NOTE[%i] = %i\n",i,KC_TO_INDEX[i]); + } + + /* precalculate envelope times */ + for(i=0; i<64; i++) + { + pom = (16 << (i >> 2)) + (4 << (i >> 2)) * (i & 0x03); + + if ((i >> 2) == 0) + pom = 1; //infinity + + if ((i >> 2) == 15) + pom = 524288; //const + + divid[i] = pom; + } + + for(i=0; i<64; i++) + { + pom = ((128+64+32)<<(i>>2))+((32+16+8)<<(i>>2))*(i&0x03); + + if ((i>>2)==0) pom=1; //infinity + + if ((i>>2)==15) + { + if ((i & 0x03) == 3) + pom = 153293300; //zero attack time + else + pom = 6422528; //const attack time + } + + divia[i] = pom; + } + + mult = (long int)1 << ENV_SH; + + for(i=0; i<64; i++) + { + if (divid[i] == 1) + pom = 0; //infinity + else + pom = (scaler * ENV_RES * mult) / ((float)YM2151_SAMPFREQ * ((float)YM2151_CLOCK / 1000.0 / (float)divid[i])); + //if (errorlog) fprintf(errorlog,"i=%03i div=%i time=%f delta=%f\n",i,divid[i], + // (float)YM2151_CLOCK/1000.0/(float)divid[i], pom ); + D_DELTAS[i] = pom; + } + + for (i=0; i<64; i++) + { + if (divia[i] == 1) + pom = 0; //infinity + else + pom = (scaler * ENV_RES * mult) / ((float)YM2151_SAMPFREQ * ((float)YM2151_CLOCK / 1000.0 / (float)divia[i])); + + //if (errorlog) fprintf(errorlog,"i=%03i div=%i time=%f delta=%f\n",i,divia[i], + // (float)YM2151_CLOCK/1000.0/(float)divia[i], pom ); + A_DELTAS[i] = pom; + } + + // This is only for speedup purposes -> to avoid testing if (keycode+RKS is + // over 63) + for(i=0; i<32; i++) + { + D_DELTAS[64 + i] = D_DELTAS[63]; + A_DELTAS[64 + i] = A_DELTAS[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) / YM2151_CLOCK); + TimerATime[i] = pom; + TimerA[i] = pom * YM2151_SAMPFREQ * mult; /*number of samples that timer period should last (fixed point) */ + } + + for(i=0; i<256; i++) + { + /* ASG 980324: changed to compute both TimerB and TimerBTime */ + pom = (1024.0 * (256.0 - i) / YM2151_CLOCK); + TimerBTime[i] = pom; + TimerB[i] = pom * YM2151_SAMPFREQ * mult; /*number of samples that timer period should last (fixed point) */ + } +} + + +void envelope_attack(OscilRec * op) +{ + if ((op->attack_volume -= op->delta_AR) < MIN_VOLUME_INDEX) //is volume index min already ? + { + op->volume = MIN_VOLUME_INDEX; + op->state++; + } + else + op->volume = attack_curve[op->attack_volume>>ENV_SH]; +} + + +void envelope_decay(OscilRec * op) +{ + if ((op->volume += op->delta_D1R) > op->D1L) + { + //op->volume = op->D1L; + op->state++; + } +} + + +void envelope_sustain(OscilRec * op) +{ + if ((op->volume += op->delta_D2R) > MAX_VOLUME_INDEX) + { + op->state = 4; + op->volume = VOLUME_OFF; + } +} + + +void envelope_release(OscilRec * op) +{ + if ((op->volume += op->delta_RR) > MAX_VOLUME_INDEX) + { + op->state = 4; + op->volume = VOLUME_OFF; + } +} + + +void envelope_nothing(OscilRec *op) +{ +} + + +inline void envelope_KOFF(OscilRec * op) +{ + op->state = 3; /*release*/ +} + + +inline void envelope_KON(OscilRec * op) +{ + /*this is to remove the gap time if TL>0*/ + op->volume = VOLUME_OFF; //(ENV_RES - op->TL)<attack_volume = op->volume; + op->phase = 0; + op->state = 0; /*KEY ON = attack*/ + op->OscilFB = 0; /*Clear feedback after key on */ +} + + +void refresh_chip(YM2151 * PSG) +{ + uint16_t kc_index_oscil, kc_index_channel, mul; + uint8_t op,v,kc; + signed char k,chan; + OscilRec * osc; + + for(chan=7; chan>=0; chan--) + { + kc = PSG->KC[chan]; + kc_index_channel = KC_TO_INDEX[kc] + PSG->KF[chan]; + kc >>=2; + + for(k=24; k>=0; k-=8) + { + op = chan + k; + osc = &PSG->Oscils[op]; + +/*calc freq begin*/ + v = (PSG->Regs[YM_DT2_D2R_BASE + op] >> 6) & 0x03; //DT2 value + kc_index_oscil = kc_index_channel + DT2Tab[v]; //DT2 offset + v = PSG->Regs[YM_DT1_MUL_BASE + op]; + mul = (v & 0x0F) << 1; + + if (mul) + osc->freq = deltas[kc_index_oscil] * mul; + else + osc->freq = deltas[kc_index_oscil]; + + osc->freq += DT1deltas[kc][(v >> 4) & 0x07]; //DT1 value +/*calc freq end*/ + +/*calc envelopes begin*/ + v = kc >> PSG->KS[op]; + osc->delta_AR = A_DELTAS[ osc->AR + v]; /* 2*RR + RKS =max 95*/ + osc->delta_D1R = D_DELTAS[osc->D1R + v]; /* 2*RR + RKS =max 95*/ + osc->delta_D2R = D_DELTAS[osc->D2R + v]; /* 2*RR + RKS =max 95*/ + osc->delta_RR = D_DELTAS[ osc->RR + v]; /* 2*RR + RKS =max 95*/ +/*calc envelopes end*/ + } + } +} + + +void write_YM_NON_EMULATED(uint8_t n, uint8_t r, uint8_t v) +{ + if (errorlog) + fprintf(errorlog, "Write to non emulated register %02x value %02x\n", r, v); +} + + +void write_YM_KON(uint8_t n, uint8_t r, uint8_t v) +{ + uint8_t chan; + YM2151 * PSG = &(YMPSG[n]); + + chan = v & 0x07; + + if (v & 0x08) + envelope_KON(&PSG->Oscils[chan]); + else + envelope_KOFF(&PSG->Oscils[chan]); + + if (v & 0x10) + envelope_KON(&PSG->Oscils[chan + 16]); + else + envelope_KOFF(&PSG->Oscils[chan + 16]); + + if (v & 0x20) + envelope_KON(&PSG->Oscils[chan + 8]); + else + envelope_KOFF(&PSG->Oscils[chan + 8]); + + if (v & 0x40) + envelope_KON(&PSG->Oscils[chan + 24]); + else + envelope_KOFF(&PSG->Oscils[chan + 24]); +} + + +void write_YM_CLOCKA1(uint8_t n, uint8_t r, uint8_t v) +{ + YMPSG[n].Regs[r] = v; +} + + +void write_YM_CLOCKA2(uint8_t n, uint8_t r, uint8_t v) +{ + YMPSG[n].Regs[r] = v & 0x03; +} + + +void write_YM_CLOCKB(uint8_t n, uint8_t r, uint8_t v) +{ + YMPSG[n].Regs[r] = v; +} + + +static void timer_callback_a(int n) +{ + YM2151 * PSG = &YMPSG[n]; +// YM2151UpdateOne(n, cpu_scalebyfcount(YMBufSize)); + + if (PSG->handler) + (*PSG->handler)(); + + PSG->TimA = 0; + PSG->TimIRQ |= 1; + PSG->TimATimer = 0; +} + + +static void timer_callback_b(int n) +{ + YM2151 * PSG = &YMPSG[n]; +// YM2151UpdateOne(n, cpu_scalebyfcount(YMBufSize)); + + if (PSG->handler) + (*PSG->handler)(); + + PSG->TimB = 0; + PSG->TimIRQ |= 2; + PSG->TimBTimer = 0; +} + + +void write_YM_CLOCKSET(uint8_t n, uint8_t r, uint8_t v) +{ + YM2151 * PSG = &(YMPSG[n]); + + v &= 0xBF; + //PSG->Regs[r]=v; +// if (errorlog) fprintf(errorlog,"CSM= %01x FRESET=%02x, IRQEN=%02x, LOAD=%02x\n",v>>7,(v>>4)&0x03,(v>>2)&0x03,v&0x03 ); + + if (v & 0x80) //CSM + {} + + /* ASG 980324: remove the timers if they exist */ + if (PSG->TimATimer) + timer_remove(PSG->TimATimer); + + if (PSG->TimBTimer) + timer_remove(PSG->TimBTimer); + + PSG->TimATimer = 0; + PSG->TimBTimer = 0; + + if (v & 0x01) //LOAD A + { + PSG->TimA = 1; + PSG->TimAVal = TimerA[(PSG->Regs[YM_CLOCKA1] << 2) | PSG->Regs[YM_CLOCKA2]]; + /* ASG 980324: added a real timer if we have a handler */ + + if (PSG->handler) + PSG->TimATimer = timer_set(TimerATime[(PSG->Regs[YM_CLOCKA1] << 2) | PSG->Regs[YM_CLOCKA2]], n, timer_callback_a); + } + else + PSG->TimA = 0; + + if (v & 0x02) //load B + { + PSG->TimB = 1; + PSG->TimBVal = TimerB[PSG->Regs[YM_CLOCKB]]; + + /* ASG 980324: added a real timer if we have a handler */ + if (PSG->handler) + PSG->TimBTimer = timer_set (TimerBTime[PSG->Regs[YM_CLOCKB]], n, timer_callback_b); + } + else + PSG->TimB = 0; + + if (v & 0x04) //IRQEN A + {} + + if (v & 0x08) //IRQEN B + {} + + if (v & 0x10) //FRESET A + { + PSG->TimIRQ &= 0xFE; + } + + if (v & 0x20) //FRESET B + { + PSG->TimIRQ &= 0xFD; + } +} + + +void write_YM_CT1_CT2_W(uint8_t n, uint8_t r, uint8_t v) +{ + YMPSG[n].Regs[r] = v; +} + + +void write_YM_CONNECT_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + // NOTE: L/R Channel enables are ignored! This emu is mono! + YM2151 * PSG = &(YMPSG[n]); + + //PSG->Regs[r] = v; + uint8_t chan = r - YM_CONNECT_BASE; + + PSG->ConnectTab[chan] = v & 7; /*connection number*/ + PSG->FeedBack[chan] = FEED[(v >> 3) & 7]; +} + + +void write_YM_KC_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + YMPSG[n].KC[r - YM_KC_BASE] = v; + //freq_calc(chan,PSG); +} + + +void write_YM_KF_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + YMPSG[n].KF[r - YM_KF_BASE] = v >> 2; + //freq_calc(chan,PSG); +} + + +void write_YM_PMS_AMS_BASE(uint8_t n, uint8_t r, uint8_t v) +{ +// uint8_t chan, i; + YM2151 * PSG = &(YMPSG[n]); + PSG->Regs[r] = v; + uint8_t chan = r - YM_PMS_AMS_BASE; + + PMTab[chan] = v >> 4; //PMS; + +// if (i && errorlog) +// fprintf(errorlog,"PMS CHN %02x =%02x\n", chan, i); + + AMTab[chan] = v & 0x03; //AMS; + +// if (i && errorlog) +// fprintf(errorlog,"AMS CHN %02x =%02x\n", chan, i); + +} + + +void write_YM_DT1_MUL_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + YMPSG[n].Regs[r] = v; + //freq_calc(chan,PSG); +} + + +void write_YM_TL_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + v &= 0x7F; + YMPSG[n].Oscils[r - YM_TL_BASE].TL = v << (ENV_BITS - 7); /*7bit TL*/ +} + + +void write_YM_KS_AR_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + uint8_t op; + YM2151 * PSG; + + op = r - YM_KS_AR_BASE; + PSG = &(YMPSG[n]); + + PSG->KS[op] = 3 - (v >> 6); + PSG->Oscils[op].AR = (v & 0x1F) << 1; +} + + +void write_YM_AMS_D1R_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + uint8_t op = r - YM_AMS_D1R_BASE; + + if ((v & 0x80) && errorlog) + fprintf(errorlog,"AMS ON oper%02x\n", op); + + //HERE something to do with AMS; + + YMPSG[n].Oscils[op].D1R = (v & 0x1F) << 1; +} + + +void write_YM_DT2_D2R_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + YM2151 * PSG = &(YMPSG[n]); + OscilRec * osc = &PSG->Oscils[r - YM_DT2_D2R_BASE]; + PSG->Regs[r] = v; + + osc->D2R = (v & 0x1F) << 1; + //freq_calc(chan,PSG); +} + + +void write_YM_D1L_RR_BASE(uint8_t n, uint8_t r, uint8_t v) +{ + OscilRec * osc = &YMPSG[n].Oscils[r - YM_D1L_RR_BASE]; + + osc->D1L = decib45[(v >> 4) & 0x0F]; + osc->RR = ((v & 0x0F) << 2) | 0x02; +} + + +/* +** Initialize YM2151 emulator(s). +** +** 'num' is the number of virtual YM2151's to allocate +** 'clock' is the chip clock +** 'rate' is sampling rate and 'bufsiz' is the size of the +** buffer that should be updated at each interval +*/ +int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz)//, SAMPLE ** buffer) +{ + int i; + + if (YMPSG) + return (-1); /* duplicate init. */ + + YMNumChips = num; + YM2151_SAMPFREQ = rate; + +#if 0 + if (sample_bits == 16) + sample_16bit = 1; + else + sample_16bit = 0; +#endif + + YM2151_CLOCK = clock; + YMBufSize = bufsiz; + + envelope_calc[0] = envelope_attack; + envelope_calc[1] = envelope_decay; + envelope_calc[2] = envelope_sustain; + envelope_calc[3] = envelope_release; + envelope_calc[4] = envelope_nothing; + + for(i=0; i<256; i++) + register_writes[i] = write_YM_NON_EMULATED; + + register_writes[YM_KON] = write_YM_KON; + register_writes[YM_CLOCKA1] = write_YM_CLOCKA1; + register_writes[YM_CLOCKA2] = write_YM_CLOCKA2; + register_writes[YM_CLOCKB] = write_YM_CLOCKB; + register_writes[YM_CLOCKSET] = write_YM_CLOCKSET; + register_writes[YM_CT1_CT2_W] = write_YM_CT1_CT2_W; + + for(i=YM_CONNECT_BASE; iBuf, '\0', YMBufSize); + + /* ASG 980324 -- reset the timers before writing to the registers */ + PSG->TimATimer = 0; + PSG->TimBTimer = 0; + + /* initialize hardware registers */ + for(i=0; i<256; i++) + PSG->Regs[i] = 0; + + for(i=0; i<32; i++) + { + memset(&PSG->Oscils[i], '\0', sizeof(OscilRec)); + PSG->Oscils[i].volume = VOLUME_OFF; + PSG->Oscils[i].state = 4; //envelope off + } + + for(i=0; i<8; i++) + { + PSG->ConnectTab[i] = 0; + PSG->FeedBack[i] = 0; + } + + PSG->TimA = 0; + PSG->TimB = 0; + PSG->TimAVal = 0; + PSG->TimBVal = 0; + PSG->TimIRQ = 0; +} + + +static inline signed int op_calc(OscilRec * OP, signed int pm) +{ + return sin_tab[(((OP->phase += OP->freq) >> FREQ_SH) + (pm)) & SIN_MASK] + [OP->TL + (OP->volume >> ENV_SH)]; +} + + +//void YM2151UpdateOne(int num, int endp) +void YM2151UpdateOne(void * BUF, int endp) +{ +// YM2151 * PSG = &(YMPSG[num]); + YM2151 * PSG = &(YMPSG[0]); + PSG->bufp = 0; +// SAMPLE * BUF; + signed int * PSGBUF; + OscilRec * OP0, * OP1, * OP2, * OP3; + uint16_t i; + signed int k, wy; +#ifdef SAVE_SEPARATE_CHANNELS + signed int pom; +#endif + + refresh_chip(PSG); + + //calculate timers... + if (PSG->TimA) + { + PSG->TimAVal -= ((endp - PSG->bufp) << TIMER_SH); + + if (PSG->TimAVal <= 0) + { + PSG->TimA = 0; + PSG->TimIRQ |= 1; + /* ASG 980324 - handled by real timers now + if (PSG->handler !=0) PSG->handler();*/ + } + } + + if (PSG->TimB) + { + PSG->TimBVal -= ((endp - PSG->bufp) << TIMER_SH); + + if (PSG->TimBVal <= 0) + { + PSG->TimB = 0; + PSG->TimIRQ |= 2; + /* ASG 980324 - handled by real timers now + if (PSG->handler !=0) PSG->handler();*/ + } + } + + OP0 = &PSG->Oscils[0 ]; + OP1 = &PSG->Oscils[0 + 8]; + OP2 = &PSG->Oscils[0 + 16]; + OP3 = &PSG->Oscils[0 + 24]; + + for(PSGBUF=&BuffTemp[PSG->bufp]; PSGBUF<&BuffTemp[endp]; PSGBUF++) + { + //chan0 + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + + if (PSG->FeedBack[0]) + OP0->OscilFB = wy >> PSG->FeedBack[0]; + else + OP0->OscilFB = 0; + + switch(PSG->ConnectTab[0]) + { + case 0: *(PSGBUF) = op_calc(OP3, op_calc(OP1, op_calc(OP2, wy))); break; + case 1: *(PSGBUF) = op_calc(OP3, op_calc(OP1, op_calc(OP2, 0) + wy)); break; + case 2: *(PSGBUF) = op_calc(OP3, op_calc(OP1, op_calc(OP2, 0)) + wy); break; + case 3: *(PSGBUF) = op_calc(OP3, op_calc(OP2, wy) + op_calc(OP1, 0)); break; + case 4: *(PSGBUF) = op_calc(OP2, wy) + op_calc(OP3, op_calc(OP1, 0)); break; + case 5: *(PSGBUF) = op_calc(OP2, wy) + op_calc(OP1, wy) + op_calc(OP3, wy); break; + case 6: *(PSGBUF) = op_calc(OP2, wy) + op_calc(OP1, 0) + op_calc(OP3, 0); break; + default: *(PSGBUF) = wy + op_calc(OP2, 0) + op_calc(OP1, 0) + op_calc(OP3, 0); break; + } +#ifdef SAVE_SEPARATE_CHANNELS +fputc((uint16_t)(*PSGBUF) & 0xFF, sample1); +fputc(((uint16_t)(*PSGBUF) >> 8) & 0xFF, sample1); +#endif + } + + //chan1 + OP0 = &PSG->Oscils[1 ]; + OP1 = &PSG->Oscils[1 + 8]; + OP2 = &PSG->Oscils[1 + 16]; + OP3 = &PSG->Oscils[1 + 24]; + + for(PSGBUF=&BuffTemp[PSG->bufp]; PSGBUF<&BuffTemp[endp]; PSGBUF++) + { + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + + if (PSG->FeedBack[1]) + OP0->OscilFB = wy >> PSG->FeedBack[1]; + else + OP0->OscilFB = 0; + +#ifdef SAVE_SEPARATE_CHANNELS +pom = *(PSGBUF); +#endif + switch(PSG->ConnectTab[1]) + { + case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break; + case 1: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)+wy ) ); break; + case 2: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)) +wy ); break; + case 3: *(PSGBUF) += op_calc(OP3, op_calc(OP2, wy)+op_calc(OP1,0) ); break; + case 4: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP3, op_calc(OP1,0)); break; + case 5: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1, wy) + op_calc(OP3,wy); break; + case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break; + default: *(PSGBUF) += wy + op_calc(OP2, 0) + op_calc(OP1, 0) + op_calc(OP3, 0); break; + } + +#ifdef SAVE_SEPARATE_CHANNELS +fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample2); +fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample2); +#endif + } + +//chan2 + OP0 = &PSG->Oscils[2 ]; + OP1 = &PSG->Oscils[2 + 8]; + OP2 = &PSG->Oscils[2 + 16]; + OP3 = &PSG->Oscils[2 + 24]; + +for( PSGBUF = &BuffTemp[PSG->bufp]; PSGBUF < &BuffTemp[endp]; PSGBUF++ ) +{ + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + if (PSG->FeedBack[2]) + OP0->OscilFB = wy >> PSG->FeedBack[2]; + else + OP0->OscilFB = 0; + +#ifdef SAVE_SEPARATE_CHANNELS + pom=*(PSGBUF); +#endif + switch(PSG->ConnectTab[2]) + { + case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break; + case 1: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)+wy ) ); break; + case 2: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)) +wy ); break; + case 3: *(PSGBUF) += op_calc(OP3, op_calc(OP2, wy)+op_calc(OP1,0) ); break; + case 4: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP3, op_calc(OP1,0)); break; + case 5: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1, wy) + op_calc(OP3,wy); break; + case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break; + default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break; + } +#ifdef SAVE_SEPARATE_CHANNELS +fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample3); +fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample3); +#endif +} + +//chan3 + OP0 = &PSG->Oscils[3 ]; + OP1 = &PSG->Oscils[3 + 8]; + OP2 = &PSG->Oscils[3 + 16]; + OP3 = &PSG->Oscils[3 + 24]; + +for( PSGBUF = &BuffTemp[PSG->bufp]; PSGBUF < &BuffTemp[endp]; PSGBUF++ ) +{ + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + if (PSG->FeedBack[3]) + OP0->OscilFB = wy >> PSG->FeedBack[3]; + else + OP0->OscilFB = 0; + +#ifdef SAVE_SEPARATE_CHANNELS + pom=*(PSGBUF); +#endif + switch(PSG->ConnectTab[3]) + { + case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break; + case 1: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)+wy ) ); break; + case 2: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)) +wy ); break; + case 3: *(PSGBUF) += op_calc(OP3, op_calc(OP2, wy)+op_calc(OP1,0) ); break; + case 4: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP3, op_calc(OP1,0)); break; + case 5: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1, wy) + op_calc(OP3,wy); break; + case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break; + default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break; + } +#ifdef SAVE_SEPARATE_CHANNELS +fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample4); +fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample4); +#endif +} + + //chan4 + OP0 = &PSG->Oscils[4 ]; + OP1 = &PSG->Oscils[4 + 8]; + OP2 = &PSG->Oscils[4 + 16]; + OP3 = &PSG->Oscils[4 + 24]; + + for(PSGBUF=&BuffTemp[PSG->bufp]; PSGBUF<&BuffTemp[endp]; PSGBUF++) + { + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + + if (PSG->FeedBack[4]) + OP0->OscilFB = wy >> PSG->FeedBack[4]; + else + OP0->OscilFB = 0; + + #ifdef SAVE_SEPARATE_CHANNELS + pom = *(PSGBUF); + #endif + + switch(PSG->ConnectTab[4]) + { + case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break; + case 1: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)+wy ) ); break; + case 2: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)) +wy ); break; + case 3: *(PSGBUF) += op_calc(OP3, op_calc(OP2, wy)+op_calc(OP1,0) ); break; + case 4: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP3, op_calc(OP1,0)); break; + case 5: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1, wy) + op_calc(OP3,wy); break; + case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break; + default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break; + } + +#ifdef SAVE_SEPARATE_CHANNELS +fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample5); +fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample5); +#endif + } + + //chan5 + OP0 = &PSG->Oscils[5 ]; + OP1 = &PSG->Oscils[5 + 8]; + OP2 = &PSG->Oscils[5 + 16]; + OP3 = &PSG->Oscils[5 + 24]; + +for( PSGBUF = &BuffTemp[PSG->bufp]; PSGBUF < &BuffTemp[endp]; PSGBUF++ ) +{ + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + if (PSG->FeedBack[5]) + OP0->OscilFB = wy >> PSG->FeedBack[5]; + else + OP0->OscilFB = 0; + +#ifdef SAVE_SEPARATE_CHANNELS + pom=*(PSGBUF); +#endif + switch(PSG->ConnectTab[5]) + { + case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break; + case 1: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)+wy ) ); break; + case 2: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)) +wy ); break; + case 3: *(PSGBUF) += op_calc(OP3, op_calc(OP2, wy)+op_calc(OP1,0) ); break; + case 4: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP3, op_calc(OP1,0)); break; + case 5: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1, wy) + op_calc(OP3,wy); break; + case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break; + default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break; + } +#ifdef SAVE_SEPARATE_CHANNELS +fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample6); +fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample6); +#endif +} + +//chan6 + OP0 = &PSG->Oscils[6 ]; + OP1 = &PSG->Oscils[6 + 8]; + OP2 = &PSG->Oscils[6 + 16]; + OP3 = &PSG->Oscils[6 + 24]; + +for( PSGBUF = &BuffTemp[PSG->bufp]; PSGBUF < &BuffTemp[endp]; PSGBUF++ ) +{ + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + if (PSG->FeedBack[6]) + OP0->OscilFB = wy >> PSG->FeedBack[6]; + else + OP0->OscilFB = 0; + + switch(PSG->ConnectTab[6]) + { + case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break; + case 1: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)+wy ) ); break; + case 2: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)) +wy ); break; + case 3: *(PSGBUF) += op_calc(OP3, op_calc(OP2, wy)+op_calc(OP1,0) ); break; + case 4: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP3, op_calc(OP1,0)); break; + case 5: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1, wy) + op_calc(OP3,wy); break; + case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break; + default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break; + } +} + + //chan7 + OP0 = &PSG->Oscils[7 ]; + OP1 = &PSG->Oscils[7 + 8]; + OP2 = &PSG->Oscils[7 + 16]; + OP3 = &PSG->Oscils[7 + 24]; + + for(PSGBUF=&BuffTemp[PSG->bufp]; PSGBUF<&BuffTemp[endp]; PSGBUF++) + { + envelope_calc[OP0->state](OP0); + envelope_calc[OP1->state](OP1); + envelope_calc[OP2->state](OP2); + envelope_calc[OP3->state](OP3); + + wy = op_calc(OP0, OP0->OscilFB); + + if (PSG->FeedBack[7]) + OP0->OscilFB = wy >> PSG->FeedBack[7]; + else + OP0->OscilFB = 0; + + switch(PSG->ConnectTab[7]) + { + case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break; + case 1: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)+wy ) ); break; + case 2: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,0)) +wy ); break; + case 3: *(PSGBUF) += op_calc(OP3, op_calc(OP2, wy)+op_calc(OP1,0) ); break; + case 4: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP3, op_calc(OP1,0)); break; + case 5: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1, wy) + op_calc(OP3,wy); break; + case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break; + default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break; + } + } + +// BUF = PSG->Buf; + PSGBUF = &BuffTemp[PSG->bufp]; + + for(i=PSG->bufp; i> 8) & 0xFF, samplesum); +#endif + +#if 1 +// if (sample_16bit) + { + /*16 bit mode*/ + k >>= FINAL_SH16; //AUDIO_CONV + k <<= 2; + + if (k > 32767) + k = 32767; + else if (k < -32768) + k = -32768; + + ((uint16_t *)BUF)[i] = (uint16_t)k; + } +#else +// else + { + /*8 bit mode*/ + k >>= FINAL_SH8; //AUDIO_CONV + + if (k > 127) + k = 127; + else if (k < -128) + k = -128; + + ((uint8_t *)BUF)[i] = (uint8_t)k; + } +#endif + } + + PSG->bufp = endp; +} + + +/* +** called to update all chips +*/ +void YM2151Update(void) +{ + int i; + for(i=0; i