X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fay8910.cpp;h=3e5df25803c84c6eca455797bcf06cb425cc5dd0;hb=f36d026c7b8b398b88765ec5b67a3c767fe5fbad;hp=56c03d121cb5d481c432fec46d96a6ee8ed4bba6;hpb=b90c77b56b023d274fc028e449227bd0f6f37e8e;p=apple2 diff --git a/src/ay8910.cpp b/src/ay8910.cpp old mode 100755 new mode 100644 index 56c03d1..3e5df25 --- a/src/ay8910.cpp +++ b/src/ay8910.cpp @@ -9,9 +9,9 @@ ***************************************************************************/ -// +// // From mame.txt (http://www.mame.net/readme.html) -// +// // VI. Reuse of Source Code // -------------------------- // This chapter might not apply to specific portions of MAME (e.g. CPU @@ -25,39 +25,18 @@ // However, given the amount of time and energy it took to collect this // information, if you find new information we would appreciate if you made it // freely available as well. -// +// -// JLH: Removed MAME specific crap +// JLH: Commented out MAME specific crap -#include // for memset() #include "ay8910.h" +#include // for memset() -/////////////////////////////////////////////////////////// -// typedefs & dummy funcs to allow MAME code to compile: -// -//typedef UINT8 (*mem_read_handler)(UINT32); -//typedef void (*mem_write_handler)(UINT32, UINT8); -// -//static void logerror(char* psz, ...) -//{ -//} -// -//static unsigned short activecpu_get_pc() -//{ -// return 0; -//} -// -// -/////////////////////////////////////////////////////////// - -#define MAX_OUTPUT 0x7fff +#define MAX_OUTPUT 0x7FFF // See AY8910_set_clock() for definition of STEP #define STEP 0x8000 -//This is not used at all... -//static int num = 0, ym_num = 0; - struct AY8910 { int Channel; @@ -70,13 +49,13 @@ struct AY8910 unsigned char Regs[16]; int lastEnable; unsigned int UpdateStep; - int PeriodA,PeriodB,PeriodC,PeriodN,PeriodE; - int CountA,CountB,CountC,CountN,CountE; - unsigned int VolA,VolB,VolC,VolE; - unsigned char EnvelopeA,EnvelopeB,EnvelopeC; - unsigned char OutputA,OutputB,OutputC,OutputN; + int PeriodA, PeriodB, PeriodC, PeriodN, PeriodE; + int CountA, CountB, CountC, CountN, CountE; + unsigned int VolA, VolB, VolC, VolE; + unsigned char EnvelopeA, EnvelopeB, EnvelopeC; + unsigned char OutputA, OutputB, OutputC, OutputN; signed char CountEnv; - unsigned char Hold,Alternate,Attack,Holding; + unsigned char Hold, Alternate, Attack, Holding; int RNG; unsigned int VolTable[32]; }; @@ -104,61 +83,79 @@ struct AY8910 static struct AY8910 AYPSG[MAX_8910]; /* array of PSG's */ - void _AYWriteReg(int n, int r, int v) { struct AY8910 *PSG = &AYPSG[n]; int old; - PSG->Regs[r] = v; - /* A note about the period of tones, noise and envelope: for speed reasons,*/ - /* we count down from the period to 0, but careful studies of the chip */ - /* output prove that it instead counts up from 0 until the counter becomes */ - /* greater or equal to the period. This is an important difference when the*/ - /* program is rapidly changing the period to modulate the sound. */ - /* To compensate for the difference, when the period is changed we adjust */ - /* our internal counter. */ - /* Also, note that period = 0 is the same as period = 1. This is mentioned */ - /* in the YM2203 data sheets. However, this does NOT apply to the Envelope */ - /* period. In that case, period = 0 is half as period = 1. */ - switch( r ) + /* A note about the period of tones, noise and envelope: for speed reasons, * + * we count down from the period to 0, but careful studies of the chip * + * output prove that it instead counts up from 0 until the counter becomes * + * greater or equal to the period. This is an important difference when the * + * program is rapidly changing the period to modulate the sound. * + * To compensate for the difference, when the period is changed we adjust * + * our internal counter. * + * Also, note that period = 0 is the same as period = 1. This is mentioned * + * in the YM2203 data sheets. However, this does NOT apply to the Envelope * + * period. In that case, period = 0 is half as period = 1. */ + switch (r) { case AY_AFINE: case AY_ACOARSE: - PSG->Regs[AY_ACOARSE] &= 0x0f; + PSG->Regs[AY_ACOARSE] &= 0x0F; old = PSG->PeriodA; PSG->PeriodA = (PSG->Regs[AY_AFINE] + 256 * PSG->Regs[AY_ACOARSE]) * PSG->UpdateStep; - if (PSG->PeriodA == 0) PSG->PeriodA = PSG->UpdateStep; + + if (PSG->PeriodA == 0) + PSG->PeriodA = PSG->UpdateStep; + PSG->CountA += PSG->PeriodA - old; - if (PSG->CountA <= 0) PSG->CountA = 1; + + if (PSG->CountA <= 0) + PSG->CountA = 1; break; case AY_BFINE: case AY_BCOARSE: - PSG->Regs[AY_BCOARSE] &= 0x0f; + PSG->Regs[AY_BCOARSE] &= 0x0F; old = PSG->PeriodB; PSG->PeriodB = (PSG->Regs[AY_BFINE] + 256 * PSG->Regs[AY_BCOARSE]) * PSG->UpdateStep; - if (PSG->PeriodB == 0) PSG->PeriodB = PSG->UpdateStep; + + if (PSG->PeriodB == 0) + PSG->PeriodB = PSG->UpdateStep; + PSG->CountB += PSG->PeriodB - old; - if (PSG->CountB <= 0) PSG->CountB = 1; + + if (PSG->CountB <= 0) + PSG->CountB = 1; break; case AY_CFINE: case AY_CCOARSE: - PSG->Regs[AY_CCOARSE] &= 0x0f; + PSG->Regs[AY_CCOARSE] &= 0x0F; old = PSG->PeriodC; PSG->PeriodC = (PSG->Regs[AY_CFINE] + 256 * PSG->Regs[AY_CCOARSE]) * PSG->UpdateStep; - if (PSG->PeriodC == 0) PSG->PeriodC = PSG->UpdateStep; + + if (PSG->PeriodC == 0) + PSG->PeriodC = PSG->UpdateStep; + PSG->CountC += PSG->PeriodC - old; - if (PSG->CountC <= 0) PSG->CountC = 1; + + if (PSG->CountC <= 0) + PSG->CountC = 1; break; case AY_NOISEPER: - PSG->Regs[AY_NOISEPER] &= 0x1f; + PSG->Regs[AY_NOISEPER] &= 0x1F; old = PSG->PeriodN; PSG->PeriodN = PSG->Regs[AY_NOISEPER] * PSG->UpdateStep; - if (PSG->PeriodN == 0) PSG->PeriodN = PSG->UpdateStep; + + if (PSG->PeriodN == 0) + PSG->PeriodN = PSG->UpdateStep; + PSG->CountN += PSG->PeriodN - old; - if (PSG->CountN <= 0) PSG->CountN = 1; + + if (PSG->CountN <= 0) + PSG->CountN = 1; break; case AY_ENABLE: if ((PSG->lastEnable == -1) || @@ -180,17 +177,17 @@ void _AYWriteReg(int n, int r, int v) PSG->lastEnable = PSG->Regs[AY_ENABLE]; break; case AY_AVOL: - PSG->Regs[AY_AVOL] &= 0x1f; + PSG->Regs[AY_AVOL] &= 0x1F; PSG->EnvelopeA = PSG->Regs[AY_AVOL] & 0x10; PSG->VolA = PSG->EnvelopeA ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_AVOL] ? PSG->Regs[AY_AVOL]*2+1 : 0]; break; case AY_BVOL: - PSG->Regs[AY_BVOL] &= 0x1f; + PSG->Regs[AY_BVOL] &= 0x1F; PSG->EnvelopeB = PSG->Regs[AY_BVOL] & 0x10; PSG->VolB = PSG->EnvelopeB ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_BVOL] ? PSG->Regs[AY_BVOL]*2+1 : 0]; break; case AY_CVOL: - PSG->Regs[AY_CVOL] &= 0x1f; + PSG->Regs[AY_CVOL] &= 0x1F; PSG->EnvelopeC = PSG->Regs[AY_CVOL] & 0x10; PSG->VolC = PSG->EnvelopeC ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_CVOL] ? PSG->Regs[AY_CVOL]*2+1 : 0]; break; @@ -198,9 +195,14 @@ void _AYWriteReg(int n, int r, int v) case AY_ECOARSE: old = PSG->PeriodE; PSG->PeriodE = ((PSG->Regs[AY_EFINE] + 256 * PSG->Regs[AY_ECOARSE])) * PSG->UpdateStep; - if (PSG->PeriodE == 0) PSG->PeriodE = PSG->UpdateStep / 2; + + if (PSG->PeriodE == 0) + PSG->PeriodE = PSG->UpdateStep / 2; + PSG->CountE += PSG->PeriodE - old; - if (PSG->CountE <= 0) PSG->CountE = 1; + + if (PSG->CountE <= 0) + PSG->CountE = 1; break; case AY_ESHAPE: /* envelope shapes: @@ -229,8 +231,9 @@ void _AYWriteReg(int n, int r, int v) has twice the steps, happening twice as fast. Since the end result is just a smoother curve, we always use the YM2149 behaviour. */ - PSG->Regs[AY_ESHAPE] &= 0x0f; - PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1f : 0x00; + PSG->Regs[AY_ESHAPE] &= 0x0F; + PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1F : 0x00; + if ((PSG->Regs[AY_ESHAPE] & 0x08) == 0) { /* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */ @@ -242,13 +245,20 @@ void _AYWriteReg(int n, int r, int v) PSG->Hold = PSG->Regs[AY_ESHAPE] & 0x01; PSG->Alternate = PSG->Regs[AY_ESHAPE] & 0x02; } + PSG->CountE = PSG->PeriodE; - PSG->CountEnv = 0x1f; + PSG->CountEnv = 0x1F; PSG->Holding = 0; PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack]; - if (PSG->EnvelopeA) PSG->VolA = PSG->VolE; - if (PSG->EnvelopeB) PSG->VolB = PSG->VolE; - if (PSG->EnvelopeC) PSG->VolC = PSG->VolE; + + if (PSG->EnvelopeA) + PSG->VolA = PSG->VolE; + + if (PSG->EnvelopeB) + PSG->VolB = PSG->VolE; + + if (PSG->EnvelopeC) + PSG->VolC = PSG->VolE; break; case AY_PORTA: if (PSG->Regs[AY_ENABLE] & 0x40) @@ -282,78 +292,86 @@ void _AYWriteReg(int n, int r, int v) // /length/ is the number of samples we require // NB. This should be called at twice the 6522 IRQ rate or (eg) 60Hz if no IRQ. -void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static] +void AY8910Update(int chip, int16_t ** buffer, int length) // [TC: Removed static] { - struct AY8910 *PSG = &AYPSG[chip]; - INT16 *buf1,*buf2,*buf3; + struct AY8910 * PSG = &AYPSG[chip]; + int16_t * buf1, * buf2, * buf3; int outn; buf1 = buffer[0]; buf2 = buffer[1]; buf3 = buffer[2]; - - /* The 8910 has three outputs, each output is the mix of one of the three */ - /* tone generators and of the (single) noise generator. The two are mixed */ - /* BEFORE going into the DAC. The formula to mix each channel is: */ - /* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */ - /* Note that this means that if both tone and noise are disabled, the output */ - /* is 1, not 0, and can be modulated changing the volume. */ - - - /* If the channels are disabled, set their output to 1, and increase the */ - /* counter, if necessary, so they will not be inverted during this update. */ - /* Setting the output to 1 is necessary because a disabled channel is locked */ - /* into the ON state (see above); and it has no effect if the volume is 0. */ - /* If the volume is 0, increase the counter, but don't touch the output. */ + /* The 8910 has three outputs, each output is the mix of one of the three * + * tone generators and of the (single) noise generator. The two are mixed * + * BEFORE going into the DAC. The formula to mix each channel is: * + * (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). * + * Note that this means that if both tone and noise are disabled, the output * + * is 1, not 0, and can be modulated changing the volume. * + * * + * If the channels are disabled, set their output to 1, and increase the * + * counter, if necessary, so they will not be inverted during this update. * + * Setting the output to 1 is necessary because a disabled channel is locked * + * into the ON state (see above); and it has no effect if the volume is 0. * + * If the volume is 0, increase the counter, but don't touch the output. */ if (PSG->Regs[AY_ENABLE] & 0x01) { - if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP; + if (PSG->CountA <= length * STEP) + PSG->CountA += length * STEP; + PSG->OutputA = 1; } else if (PSG->Regs[AY_AVOL] == 0) { - /* note that I do count += length, NOT count = length + 1. You might think */ - /* it's the same since the volume is 0, but doing the latter could cause */ - /* interferencies when the program is rapidly modulating the volume. */ - if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP; + /* note that I do count += length, NOT count = length + 1. You might think * + * it's the same since the volume is 0, but doing the latter could cause * + * interferencies when the program is rapidly modulating the volume. */ + if (PSG->CountA <= length * STEP) + PSG->CountA += length * STEP; } + if (PSG->Regs[AY_ENABLE] & 0x02) { - if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP; + if (PSG->CountB <= length * STEP) + PSG->CountB += length * STEP; + PSG->OutputB = 1; } else if (PSG->Regs[AY_BVOL] == 0) { - if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP; + if (PSG->CountB <= length * STEP) + PSG->CountB += length * STEP; } + if (PSG->Regs[AY_ENABLE] & 0x04) { - if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP; + if (PSG->CountC <= length * STEP) + PSG->CountC += length * STEP; + PSG->OutputC = 1; } else if (PSG->Regs[AY_CVOL] == 0) { - if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP; + if (PSG->CountC <= length * STEP) + PSG->CountC += length * STEP; } - /* for the noise channel we must not touch OutputN - it's also not necessary */ - /* since we use outn. */ + /* for the noise channel we must not touch OutputN - it's also not necessary * + * since we use outn. */ if ((PSG->Regs[AY_ENABLE] & 0x38) == 0x38) /* all off */ - if (PSG->CountN <= length*STEP) PSG->CountN += length*STEP; + if (PSG->CountN <= length * STEP) + PSG->CountN += length * STEP; outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]); - /* buffering loop */ while (length) { - int vola,volb,volc; + int vola, volb, volc; int left; - - /* vola, volb and volc keep track of how long each square wave stays */ - /* in the 1 position during the sample period. */ + /* vola, volb and volc keep track of how long each square wave stays * + * in the 1 position during the sample period. */ vola = volb = volc = 0; left = STEP; @@ -361,35 +379,44 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static] { int nextevent; - - if (PSG->CountN < left) nextevent = PSG->CountN; - else nextevent = left; + if (PSG->CountN < left) + nextevent = PSG->CountN; + else + nextevent = left; if (outn & 0x08) { - if (PSG->OutputA) vola += PSG->CountA; + if (PSG->OutputA) + vola += PSG->CountA; + PSG->CountA -= nextevent; - /* PeriodA is the half period of the square wave. Here, in each */ - /* loop I add PeriodA twice, so that at the end of the loop the */ - /* square wave is in the same status (0 or 1) it was at the start. */ - /* vola is also incremented by PeriodA, since the wave has been 1 */ - /* exactly half of the time, regardless of the initial position. */ - /* If we exit the loop in the middle, OutputA has to be inverted */ - /* and vola incremented only if the exit status of the square */ - /* wave is 1. */ + /* PeriodA is the half period of the square wave. Here, in each * + * loop I add PeriodA twice, so that at the end of the loop the * + * square wave is in the same status (0 or 1) it was at the start. * + * vola is also incremented by PeriodA, since the wave has been 1 * + * exactly half of the time, regardless of the initial position. * + * If we exit the loop in the middle, OutputA has to be inverted * + * and vola incremented only if the exit status of the square * + * wave is 1. */ while (PSG->CountA <= 0) { PSG->CountA += PSG->PeriodA; + if (PSG->CountA > 0) { PSG->OutputA ^= 1; - if (PSG->OutputA) vola += PSG->PeriodA; + + if (PSG->OutputA) + vola += PSG->PeriodA; break; } + PSG->CountA += PSG->PeriodA; vola += PSG->PeriodA; } - if (PSG->OutputA) vola -= PSG->CountA; + + if (PSG->OutputA) + vola -= PSG->CountA; } else { @@ -397,119 +424,152 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static] while (PSG->CountA <= 0) { PSG->CountA += PSG->PeriodA; + if (PSG->CountA > 0) { PSG->OutputA ^= 1; break; } + PSG->CountA += PSG->PeriodA; } } if (outn & 0x10) { - if (PSG->OutputB) volb += PSG->CountB; + if (PSG->OutputB) + volb += PSG->CountB; + PSG->CountB -= nextevent; + while (PSG->CountB <= 0) { PSG->CountB += PSG->PeriodB; + if (PSG->CountB > 0) { PSG->OutputB ^= 1; - if (PSG->OutputB) volb += PSG->PeriodB; + + if (PSG->OutputB) + volb += PSG->PeriodB; break; } + PSG->CountB += PSG->PeriodB; volb += PSG->PeriodB; } - if (PSG->OutputB) volb -= PSG->CountB; + + if (PSG->OutputB) + volb -= PSG->CountB; } else { PSG->CountB -= nextevent; + while (PSG->CountB <= 0) { PSG->CountB += PSG->PeriodB; + if (PSG->CountB > 0) { PSG->OutputB ^= 1; break; } + PSG->CountB += PSG->PeriodB; } } if (outn & 0x20) { - if (PSG->OutputC) volc += PSG->CountC; + if (PSG->OutputC) + volc += PSG->CountC; + PSG->CountC -= nextevent; + while (PSG->CountC <= 0) { PSG->CountC += PSG->PeriodC; + if (PSG->CountC > 0) { PSG->OutputC ^= 1; - if (PSG->OutputC) volc += PSG->PeriodC; + + if (PSG->OutputC) + volc += PSG->PeriodC; break; } + PSG->CountC += PSG->PeriodC; volc += PSG->PeriodC; } - if (PSG->OutputC) volc -= PSG->CountC; + + if (PSG->OutputC) + volc -= PSG->CountC; } else { PSG->CountC -= nextevent; + while (PSG->CountC <= 0) { PSG->CountC += PSG->PeriodC; + if (PSG->CountC > 0) { PSG->OutputC ^= 1; break; } + PSG->CountC += PSG->PeriodC; } } PSG->CountN -= nextevent; + if (PSG->CountN <= 0) { /* Is noise output going to change? */ - if ((PSG->RNG + 1) & 2) /* (bit0^bit1)? */ + if ((PSG->RNG + 1) & 0x00002) /* (bit0^bit1)? */ { PSG->OutputN = ~PSG->OutputN; outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]); } - /* The Random Number Generator of the 8910 is a 17-bit shift */ - /* register. The input to the shift register is bit0 XOR bit3 */ - /* (bit0 is the output). This was verified on AY-3-8910 and YM2149 chips. */ + /* The Random Number Generator of the 8910 is a 17-bit shift * + * register. The input to the shift register is bit0 XOR bit3 * + * (bit0 is the output). This was verified on AY-3-8910 and * + * YM2149 chips. * + * * + * The following is a fast way to compute bit17 = bit0^bit3. * + * Instead of doing all the logic operations, we only check * + * bit0, relying on the fact that after three shifts of the * + * register, what now is bit3 will become bit0, and will * + * invert, if necessary, bit14, which previously was bit17. */ + if (PSG->RNG & 0x00001) + PSG->RNG ^= 0x24000; /* This version is called the "Galois configuration". */ - /* The following is a fast way to compute bit17 = bit0^bit3. */ - /* Instead of doing all the logic operations, we only check */ - /* bit0, relying on the fact that after three shifts of the */ - /* register, what now is bit3 will become bit0, and will */ - /* invert, if necessary, bit14, which previously was bit17. */ - if (PSG->RNG & 1) PSG->RNG ^= 0x24000; /* This version is called the "Galois configuration". */ PSG->RNG >>= 1; PSG->CountN += PSG->PeriodN; } left -= nextevent; - } while (left > 0); + } + while (left > 0); /* update envelope */ if (PSG->Holding == 0) { PSG->CountE -= STEP; + if (PSG->CountE <= 0) { do { PSG->CountEnv--; PSG->CountE += PSG->PeriodE; - } while (PSG->CountE <= 0); + } + while (PSG->CountE <= 0); /* check envelope current position */ if (PSG->CountEnv < 0) @@ -517,26 +577,32 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static] if (PSG->Hold) { if (PSG->Alternate) - PSG->Attack ^= 0x1f; + PSG->Attack ^= 0x1F; + PSG->Holding = 1; PSG->CountEnv = 0; } else { - /* if CountEnv has looped an odd number of times (usually 1), */ - /* invert the output. */ + /* if CountEnv has looped an odd number of times (usually 1), * + * invert the output. */ if (PSG->Alternate && (PSG->CountEnv & 0x20)) - PSG->Attack ^= 0x1f; + PSG->Attack ^= 0x1F; - PSG->CountEnv &= 0x1f; + PSG->CountEnv &= 0x1F; } } PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack]; /* reload volume */ - if (PSG->EnvelopeA) PSG->VolA = PSG->VolE; - if (PSG->EnvelopeB) PSG->VolB = PSG->VolE; - if (PSG->EnvelopeC) PSG->VolC = PSG->VolE; + if (PSG->EnvelopeA) + PSG->VolA = PSG->VolE; + + if (PSG->EnvelopeB) + PSG->VolB = PSG->VolE; + + if (PSG->EnvelopeC) + PSG->VolC = PSG->VolE; } } @@ -544,90 +610,77 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static] *(buf1++) = (vola * PSG->VolA) / STEP; *(buf2++) = (volb * PSG->VolB) / STEP; *(buf3++) = (volc * PSG->VolC) / STEP; -#else +#else // [Tom's code...] // Output PCM wave [-32768...32767] instead of MAME's voltage level [0...32767] // - This allows for better s/w mixing - if(PSG->VolA) + if (PSG->VolA) { - if(vola) + if (vola) *(buf1++) = (vola * PSG->VolA) / STEP; else - *(buf1++) = - (int) PSG->VolA; + *(buf1++) = -(int)PSG->VolA; } else - { *(buf1++) = 0; - } - - // - if(PSG->VolB) + if (PSG->VolB) { - if(volb) + if (volb) *(buf2++) = (volb * PSG->VolB) / STEP; else - *(buf2++) = - (int) PSG->VolB; + *(buf2++) = -(int)PSG->VolB; } else - { *(buf2++) = 0; - } - - // - if(PSG->VolC) + if (PSG->VolC) { - if(volc) + if (volc) *(buf3++) = (volc * PSG->VolC) / STEP; else - *(buf3++) = - (int) PSG->VolC; + *(buf3++) = -(int)PSG->VolC; } else - { *(buf3++) = 0; - } #endif - length--; } } -static void AY8910_set_clock(int chip,int clock) +static void AY8910_set_clock(int chip, int clock) { - struct AY8910 *PSG = &AYPSG[chip]; - - /* the step clock for the tone and noise generators is the chip clock */ - /* divided by 8; for the envelope generator of the AY-3-8910, it is half */ - /* that much (clock/16), but the envelope of the YM2149 goes twice as */ - /* fast, therefore again clock/8. */ - /* Here we calculate the number of steps which happen during one sample */ - /* at the given sample rate. No. of events = sample rate / (clock/8). */ - /* STEP is a multiplier used to turn the fraction into a fixed point */ - /* number. */ - PSG->UpdateStep = (unsigned int) (((double)STEP * PSG->SampleRate * 8 + clock/2) / clock); // [TC: unsigned int cast] + struct AY8910 * PSG = &AYPSG[chip]; + + /* The step clock for the tone and noise generators is the chip clock * + * divided by 8; for the envelope generator of the AY-3-8910, it is half * + * that much (clock/16), but the envelope of the YM2149 goes twice as * + * fast, therefore again clock/8. * + * Here we calculate the number of steps which happen during one sample * + * at the given sample rate. No. of events = sample rate / (clock/8). * + * STEP is a multiplier used to turn the fraction into a fixed point * + * number. */ + PSG->UpdateStep = (unsigned int)(((double)STEP * PSG->SampleRate * 8 + clock / 2) / clock); // [TC: unsigned int cast] } static void build_mixer_table(int chip) { - struct AY8910 *PSG = &AYPSG[chip]; - int i; - double out; + struct AY8910 * PSG = &AYPSG[chip]; - - /* calculate the volume->voltage conversion table */ + /* calculate the volume->voltage conversion table */ /* The AY-3-8910 has 16 levels, in a logarithmic scale (3dB per step) */ /* The YM2149 still has 16 levels for the tone generators, but 32 for */ - /* the envelope generator (1.5dB per step). */ - out = MAX_OUTPUT; - for (i = 31;i > 0;i--) - { - PSG->VolTable[i] = (unsigned int) (out + 0.5); /* round to nearest */ // [TC: unsigned int cast] + /* the envelope generator (1.5dB per step). */ + double out = MAX_OUTPUT; + for(int i=31; i>0; i--) + { + PSG->VolTable[i] = (unsigned int)(out + 0.5); /* round to nearest */ // [TC: unsigned int cast] out /= 1.188502227; /* = 10 ^ (1.5/20) = 1.5dB */ } + PSG->VolTable[0] = 0; } @@ -635,59 +688,48 @@ static void build_mixer_table(int chip) void AY8910_reset(int chip) { int i; - struct AY8910 *PSG = &AYPSG[chip]; + struct AY8910 * PSG = &AYPSG[chip]; PSG->register_latch = 0; PSG->RNG = 1; PSG->OutputA = 0; PSG->OutputB = 0; PSG->OutputC = 0; - PSG->OutputN = 0xff; + PSG->OutputN = 0xFF; PSG->lastEnable = -1; /* force a write */ - for (i = 0;i < AY_PORTA;i++) - _AYWriteReg(chip,i,0); /* AYWriteReg() uses the timer system; we cannot */ - /* call it at this time because the timer system */ - /* has not been initialized. */ + + for(i=0; iSampleRate = nSampleRate; + struct AY8910 * PSG = &AYPSG[chip]; -// PSG->PortAread = NULL; -// PSG->PortBread = NULL; -// PSG->PortAwrite = NULL; -// PSG->PortBwrite = NULL; - - AY8910_set_clock(nChip, nClock); - - build_mixer_table(nChip); + memset(PSG, 0, sizeof(struct AY8910)); + PSG->SampleRate = sampleRate; + AY8910_set_clock(chip, clock); + build_mixer_table(chip); } } -//------------------------------------- - -void AY8910_InitClock(int nClock) +void AY8910_InitClock(int clock) { - for(int nChip=0; nChip= MAX_8910) + if (chipNum >= MAX_8910) return NULL; - return &AYPSG[nAyNum].Regs[0]; + return &AYPSG[chipNum].Regs[0]; }