I believe I know what it's doing, but I don't quite have all the figures yet to back up my suspicion.

The amount of phase shift introduced by the vibrato, has to be proportional to the frequency of the sound. In fact the chip uses an approximation, and it's quite a broad approximation at that.

The FM LFO has a wavelength of 8192 samples, and operates in eight different ways, each for 1024 samples. If I draw up a little list of values, and then go on to explain them, each value is applied for 1024 samples, then it starts again.

+2, +3, +2, 0, -2, -3, -2, 0

In my list, the amplitude of the number represents how many significant bits of F-NUM are added or subtracted to make the phase modulation, the sign of the number indicates whether that's an addition or a subtraction.

So for each of the first 1024 samples, the F-NUM value is modified by adding to it the most significant 2 bits (i.e. the 10-bit F-NUM is shifted 8 bits to the right and then added to F-NUM)For the next 1024 samples, the F-NUM value is modified by adding to it the most significant 3 bits (i.e. the 10-bit F-NUM is shifted 7 bits to the right and then added to F-NUM)

In later samples, the same values will be subtracted rather than added, which means that the waveform drifts in and out of it's original phase over the 8192 sample wavelength.

Note that the above figures are for the greater depth option, the documentation says this is 14%. For the 7% option the shifts are 1 bit further, (+1, +2, +1, 0, -1, -2, -1, 0)

Note that for F-NUM < 128 there is no discernable vibrato at all. This is perhaps significant because you can produce a note from an F-NUM < 128 which is the same frequency as another note with F-NUM > 128 by changing the BLOCK value. But although they are the same frequency, they will show different levels of vibrato.

The MAME emulator does all of this using a 128 entry lookup table. The lookup depends on the most significant 3 bits of F-NUM, the DVB and the 10th bit of the LFO. The resultant looked up value is added to the increment prior to the BLOCK and MULT shifting. I'm sure that this lookup is efficient, and may be the best approach for efficiency, but it doesn't explain where the figures come from. I think that the figures in that lookup table can be explained by what I've described above.

Because this phase modulation depends on F-NUM, it has to be calculated per-sample. Unlike the AM tremolo, for which two values can be calculated for the entire device just once every 64 samples, the VIB values have to be calculated per operator, per sample.

If I have F-NUM = 128, BLOCK = 3without vibrato, the increment is 512 per sample; Which is enough to advance the waveform 1 step per sample.

With deep vibrato enabled.

The F-NUM is 128 + (128 >> 8) for the first 1024 samples. Which is 128. The increment is 512For the next 1024 samples it is 128 + (128 >> 7) or 129. The increment is 516for the next 1024 samples it is 128 + (128 >> 8) or 128. The increment is 512for the next 1024 samples it is 128 + 0for the next 1024 samples it is 128 - (128 >> 8). The increment is 512for the next 1024 samples it is 128 - (128 >> 7) or 127. The increment is 508

etc

So for a period in the 8192 samples, the waveform runs slightly faster, and then half a cycle later, it runs correspondingly slower.

If we change F-NUM to 256 and BLOCK to 2, we have the same fundamental frequency, but now the more more significant bits of F-NUM are 010 instead of 001. This leads to the following:initially the increment is 256 + (256 >> 8) or 257 and an increment of 514then the increment is 256 + (256 >> 7) or 258 and an increment of 516then 514then 512then 510then 508then 510then 512

I thought vibrato to be harder to solve, I haven't even figured out where to start with it. Also amazing that only 3 bits are used and added to FNUM domain, as it could have been done in the phase increment domain with more bits to get more steps while keeping the range.

Yes it makes sense it is proportional to the frequency (FNUM) because that is how it is in real world and synthesizers. For example the portamento depth can be given in semitones and perhaps the vibrato depth is given in cents (100th of a semitone, 1200 cents is octave). So a given amount of cents for 440Hz tone is more in hertz or phase increments than same amount of cents or phase increments for a 220Hz tone because of the logarithmic scale. So they may have mixed cents and percents in documentation. As it seems, for large vibrato depth with FNUM=0x380, vibrato range of +/- 7 meanins 0.78 *percent*, but it rounds being 14 *cents*.

In case you are wondering why low values of FNUM like 128 barely cause any vibrato, the whole idea of the chip is to give the base note with FNUM, and change the octave with BLOCK, perhaps do some tricks with MULTI to make it interesting. Rarely MULTI is changed during a tune, it is more specific to instrument characteristics, while played notes have their FNUMs are taken from note table and BLOCK set by octave.

To get the most accurate frequency, the largest FNUM values as possible are used for different notes. As you have seen the use of Note Select (NTS) bit in register 0x08, it selects what kind of FNUM values are encountered within an octave. You can select with NTS that all FNUM values within an octave have their MSB (0x200) set, so the split point is taken from the second most highest bit (0x100), meaning all FNUM values 0x300..0x3FF are the high notes and all FNUM values 0x200..0x2FF are the low notes. The other selection with NTS bit is to select FNUM values so that notes 0x200..0x3FF are the high half notes of an octave and notes 0x000..0x1FF are the low half notes of an octave. It makes things a bit more hard to use just 8-bit FNUM values as the chip features expect 9 or 10-bit values.

Oh and the vibrato increment based on FNUM does not need to be recalculated every sample, only every Nth sample (1024 you say) when vibrato phase changes, or except if FNUM has been changed. What is best depends on what kind of interface you have for your emulator, but it can be recalculated for each sample as well.

Btw, for what I understand, does it go like this? The vibrato phase could just internally be how much the 3 MSBs are shifted before summing to phase.

I think your code fragment is correct. As to which value is the first value in the lut, I don't know. I'm assuming that the LFO runs from the moment the chip is powered, so I'm not sure how I could actually reliably detect the lut value. Although it might be possible. I'll think about it.

Anyway, below is my code fragment. It calculates the vib-phase change per sample, but that's really a reflection of the emulator architecture that's in my head. As you say, if you trap changes to FNUM, then you can recalculate it there. I used a switch rather than an lut.