As RO said, this is the common way of work. If I'm not wrong, most of replayers works the same way (PT3, Trilo, WYZ). They write to a copy of the PSG registers in RAM. This way a SFX replayer can be executed, after the music replayer, and overwrite the values of the registers before will be send. But you need to take in mind how many bytes you copy to the PSG. If I'm not wrong the 13th register (envelope type) is reinitialized every time you write it. So you need to only write this register when you want to "init the envelope". Anyway, if your replayer (or SFX replayer) don't use this feature, you don't need to worry about writing the 13th register. But if you use it, take in mind that its wrong writing could distort the music (although this distortion only last for one note, or until next use of envelope)
correct. So all replayers write to the buffer. The last part is to dump the bytes to PSG. So yeah, it is a mirror, or a cache, or ...well, that
TIP: Yes, dump the (final/secondary...) RAM buffer to PSG registers is the last part of the process but the first task in each INT. Absolute priority even in games.
After this discussion, I modified my PSG replayer to be able to decode 7 voices at each frame:
. 3 for main melody (priority 3)
. 3 for any "jingle" (priority 2)
. 1 for sound effects (priority 1)
They are decoded in that order, so the priority is respected when they write values to the registers mirror, before being dumped to the PSG at each frame.
However, there's something I did not realize : doing so means that you have to have complete control of the registers on ALL voices. For example, if you have an ADSR envelope function (which I have in my replayer), each voice MUST write a volume value in each frame, whether needed or not. A rest, for example, must write 0 to channel volume at each frame. Same after the end of an ADSR envelope. No frame must be left without a value written to the registers, and that's true for each voice, otherwise the other voices will overwrite, and it's gonna be messy.
So at this point, I'm considering keeping the idea of the 7 voices and their priorities, but reverting to my previous solution which was : using a flag bit in the voice number to indicate the voice is "virtualized" because a higher priority voice has taken the channel. When the flag is raised, the voice is decoded, but no value is written to the registers. I think it lowers the load on the CPU, and simplify the process.