by opl3 » Thu Sep 22, 2011 6:31 am
I confirm the phase increment calculations. And both operators have different phase counter as they have different multipliers per operator, but FNUM and BLOCK are shared per channel.
I had experimented this a few years ago but did not remember the exact results anymore, so I did some for loop sweeps yesterday with a real chip, where MULTI went between 0..3, BLOCK between 0..3 and FNUM between 0..7, so 128 waveforms in less than 30 seconds.
Basically a base increment for the channel is calculated with FNUM and BLOCK. Then the MULTI is applied per operator.
When BLOCK is 1 and MULTI is 1, the FNUM value is directly the phase increment.
Setting BLOCK to 0 will shift the least significant bit out from the base increment. This implies that the 10-bit FNUM value ends up in base increment value being a 9-bit value at minimum and 16-bit at maximum, as baseinc=(FNUM<<BLOCK)>>1;
Same applies when MULTI is 0, the least significant bit of base increment is shifted out.
Meaning, when both BLOCK and MULTI are 0, two bits are shifted out.
Thus the operator increment is then just multiplied with the multiplier, or in the case of multiplier being 0.5x, it gets truncated when shifted by 1. Your table lookup and shift algorithm does this.
Edit:
But this still does not clarify how many bits from channel's base increment is transmitted to operators for multiply, and how many bits of multiply result is used to add to the phase accumulator. For all we know is that the phase accumulator itself has 9 fractional bits and 10 bits for indexing the table and that is enough, but we do not know how many bits there are in the phase increment. For instance, Yamaha DX7 chips have 14 frequency information bits transmitted between EGS and OPS chips (and 12 bits of envelope information).
For example FNUM=512 BLOCK=7 results into 17-bit number of 0x10000 before shift, is the 16-bit word result gotten from 17-bit internal value of 0x10000>>1=0x8000 or 16-bit internal value of 0x0000>>1=0x0000, so it makes a difference what is used as the source for the multiplier.
Also the multiplier operation still needs to be experimented, as high BLOCK values might shift bits out and MULTI of 0.5x won't shift them back in but just gets high bit zeroed, so having BLOCK=7 MULTI=0.5x does not necessarily match having BLOCK=6 MULTI=1x or BLOCK=5 MULTI=2x even though the formula gives the same increment of 32.
Edit2:
No bits are cropped off - FNUM=512 BLOCK=7 results into base increment of 32768, so the formula is valid when no bits are lost during the FNUM<<BLOCK shift, it must be a variable that can hold all 17 bits, so that the 16-bit result is 32768. Verified this with a for loop where BLOCK varied 4,5,6,7, MULTI varied 0.5,1,2,4,8 and FNUM varied 512,256,128,64. And a very special test case to show that when FNUM=1023, BLOCK=7 and MULTI=8, the phase increment is 0x7FE00 or 1023<<9, which will start indexing the sine wave backwards. Anyway that is a 19-bit increment number added to phase accumulator, and if the increment or phase accumulator were larger, we cannot see that as the bits are beyond the bits used for indexing the waveform table. The formula is perfectly valid over all test cases I can now think of. And, the first output of that wave is taken at wavetab[1023] so it is negative, as if the first output were from wavetab[0], it would be positive. I am using AR=15 so the attack is immediate. So it seems that when KON is set, the phase accumulator is indeed zeroed, but the phase increment is first added to the accumulator before indexing the waveform, as shown from many of the waveforms. Or in fact it may be that the phase accumulator is pre-loaded with the increment when KON is set, it might be simpler to do that in hardware. But as long as the result is identical, it does not matter how we do the emulation, we can use different techniques in C code than in FPGA code what is simplest to implement.