t_dir_addr in snes_spc-0.9.0 and Voice steps V1 and V2

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
t_dir_addr in snes_spc-0.9.0 and Voice steps V1 and V2
by on (#140478)
Can someone please help me understand how the 't_dir_addr' variable is working in Blargg's SNES SPC emulator? The variable is declared in SPC_DSP.h as part of the DSP's state struct and then used in SPC_DSP.cpp.

The 't_dir_addr' variable holds the pointer to the audio source directory and is the result of taking the contents of the DSP's 'DIR' register and the specific voice's 'SRCN' register. Blargg calls these t_dir and t_srcn, respectively. In Blargg's code it correctly calculates the value of 't_dir_addr' as follows in voice processing step 1:
Code:
m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4;

But I don't understand how it can possibly work right because there is only a single t_dir_addr variable for the entire DSP state (i.e. there is only a single t_dir_addr variable to be used by all 8 voices). The problem that I see is that a t_dir_addr value that was calculated for voice N in step V1 can be clobbered by another voice M before it is used in step V2.

A perfect example of this is voice's 6 and 7. If we look in Anomie's apudsp.txt we see (I removed the irrelevant voices to make it clearer):
Code:
 11. Voice steps: 6:V1
 12. Voice steps:
 13. Voice steps:
 14. Voice steps:       7:V1
 15. Voice steps: 6:V2

From the above, in DSP cycle 11 we run voice processing step V1 for voice #6. In this step we calculate the 't_dir_addr' value. And then in DSP cycle 15 we need to use this 't_dir_addr' value in order to get the correct sample pointer. But................in DSP cycle 14 we clobbered the 't_dir_addr' value we needed for voice 6 with the value needed for voice 7. And I have actually confirmed by running the emulator with some debug output enabled that the voice 6 step V1 t_dir_addr assignment really does get clobbered by the assignment in voice 7 step 1.

How can this possibly work right? It seems like you would have to have a separate 't_dir_addr' for each voice in order to ensure that they don't clobber each other.

But obviously the current way that it's coded is correct since Blargg's emulator is extremely accurate. And if I modify the code to have a separate t_dir_addr for each voice then the resulting audio doesn't sound right at all. I really want (need) to understand how/why it works with the t_dir_addr getting clobbered throughout the voice processing steps.

The way I'm thinking about it at a high level is that each voice channel has a separate "directory" of audio data with each DIR+SRCN pair pointing to a unique set of BRR samples. Like so...

DIR+V0SRCN = Pointer to Voice 0 BRR Data
DIR+V1SRCN = Pointer to Voice 1 BRR Data
DIR+V2SRCN = Pointer to Voice 2 BRR Data
...and so on...

But seeing how the t_dir_addr variable gets clobbered across different voices in Blargg's code it doesn't seem to be that simple.
Re: t_dir_addr in snes_spc-0.9.0 and Voice steps V1 and V2
by on (#140546)
It looked broken and I was about to be amazed at such a basic bug I missed, but I think I made sense of it. There is a pipeline in effect so V1 processes some things from the *previous* voice. V1 sets t_dir_addr based on t_dir and t_srcn. t_srcn is the value from the *previous* execution of V1, so t_srcn is for the previous voice. Then it reads the current voice's srcn. V2 uses t_dir_addr.

Code:
8. read srcn into t_srcn for voice 5 in V1
11. calculate t_dir_addr for voice 5 using t_srcn then read srcn for voice 6 into t_srcn
12. use t_dir_addr for voice 5
14. calculate t_dir_addr for voice 6 using t_srcn then read srcn from voice 7 into t_srcn
15. use t_dir_addr for voice 6
Re: t_dir_addr in snes_spc-0.9.0 and Voice steps V1 and V2
by on (#140559)
!!!EUREKA!!! It was like 10 light bulbs all lit up at once in my head after reading your answer. I _never_ would have figured that out on my own. This sheds sooooooooo much light on so many other things in Anomie's apudsp.txt document too.

Thank you so much Blargg! :D :D :D