kon_delay in snes_spc-0.9.0

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
kon_delay in snes_spc-0.9.0
by on (#125736)
What is this bit of code doing in SPC_DSP.cpp?
Code:
inline VOICE_CLOCK( V2 )
{
...
   if ( !v->kon_delay )
      entry += 2;
...
}

I'm reading the code as, "If the 5 sample KON delay has passed then use the Source Loop Start Address (LSA) instead of the Source Start Address (SA).

If that is the correct interpretation, then my question is why is it doing that? I'm trying to find some reason in apudsp.txt but can't seem to find it...
Re: kon_delay in snes_spc-0.9.0
by on (#126510)
Quote:
I'm reading the code as, "If the 5 sample KON delay has passed then use the Source Loop Start Address (LSA) instead of the Source Start Address (SA).

Yeah. If a KON isn't happening, then the only address it will need is the loop for when it reaches the end.

It only reads one of the two sample addresses (SA, LSA) each time through the DSP loop. When kon_delay is non-zero, a KON is in progress and the sample won't be looping, so it reads SA. Then at some point in the KON process it uses this. Some times through the DSP loop it will read this pointer but not do anything with it, so for those it doesn't matter which it reads.

References:

apudsp.txt wrote:
More specifically, the registers and memory are accessed as follows. Note that
most register values are read once per sample output and cached internally for
use as needed. Note also that the S-DSP may perform some of the "if necessary"
operations unconditionally but only make use of the result "if necessary". For
example, in voice processing step V2 it may load the sample pointer
unconditionally, but this has no effect unless there was a loop or KON.

...

V2. Load the sample pointer (using previously loaded DIR and VxSRCN) if
necessary.


Spc_Dsp.cpp wrote:
Code:
inline VOICE_CLOCK( V2 )
{
    // Read sample pointer (ignored if not needed)
    byte const* entry = &ram [m.t_dir_addr];
    if ( !v->kon_delay )                        // *********
        entry += 2;
    m.t_brr_next_addr = GET_LE16A( entry );     // *********
   
    m.t_adsr0 = VREG(v->regs,adsr0);
   
    // Read pitch, spread over two clocks
    m.t_pitch = VREG(v->regs,pitchl);
}

VOICE_CLOCK( V3c )
{
    // Pitch modulation using previous voice's output
    if ( m.t_pmon & v->vbit )
        m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10;
   
    if ( v->kon_delay )
    {
        // Get ready to start BRR decoding on next sample
        if ( v->kon_delay == 5 )
        {
            v->brr_addr    = m.t_brr_next_addr; // *********
            v->brr_offset  = 1;
            v->buf_pos     = 0;
            m.t_brr_header = 0; // header is ignored on this sample
            kon_check      = true;
        }
    ...
}

VOICE_CLOCK( V4 )
{
    // Decode BRR
    m.t_looped = 0;
    if ( v->interp_pos >= 0x4000 )
    {
        decode_brr( v );
       
        if ( (v->brr_offset += 2) >= brr_block_size )
        {
            // Start decoding next BRR block
            assert( v->brr_offset == brr_block_size );
            v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
            if ( m.t_brr_header & 1 )
            {
                v->brr_addr = m.t_brr_next_addr;// *********
                m.t_looped = v->vbit;
            }
            v->brr_offset = 1;
        }
    }
    ...
}

Re: kon_delay in snes_spc-0.9.0
by on (#126536)
Excellent! Thanks blargg. I need to study this a bit with this new information to make sure I understand it.