Quantcast
Channel: nesdev.org
Viewing all articles
Browse latest Browse all 746

SPC700 sample swapping

$
0
0
Hey, Lex here. Recently I've been trying to learn about programming the SPC700. After a few weeks of studying the
SPC700 and studying the sound drivers of commercial SNES games; I've learned enough to implement a sample swapping
engine.

How does it work? Well on the SNES side, there is code for clearing the SNES CPU's ram, preparing the SPC buffer and uploading
data to the SPC700. What is the SPC buffer? It is a 64KB area at 7F:0000 in the SNES CPU's ram where you can prepare the data that
will be sent to SPC700's ram before sending it to the SPC700's ram. The source directory data, sound program and sample data
are written to this buffer by the SNES CPU. It is basically a mirror of what will end up in the SPC700's ram.

Then there's some code for uploading the SPC buffer to the SPC700.

This basically does the same thing as the code at the link below does:
https://snes.nesdev.org/wiki/Booting_the_SPC700

Then later when 0 is written to $2141 this causes the SPC700 to go to the code that jumps to the main sound program.

On the SPC700 side there is some code that clears the DSP registers.

Code:

arch spc700macro writeToDSP();This is a macro for writing values to the DSP.mov $F2,Y;Move the value in Y to the DSPAddr register.;The value in Y holds the address of the DSP register to write to.mov $F3,A;The A register is what we want to write to the current DSP registeer.endmacroORG $018200clear_DSP_registers:;Clear the direct page to zero.clear_A:mov A,#$00;Clear A.;The value in A, 0x00 is the value we will be writing to;the DSP registers to clear them.clear_Y:;Clear Y.;Y will store the address of the current DSP register.mov Y,#$00clear_DSP_register:;Clear the current DSP register.%writeToDSP();Write values to the DSP registers.INC Y;Increment Y so that it contains the address of the next DSP register.CMP Y,#$79BNE clear_DSP_register;Is Y equal to 0x79 the maximum number of DSP registers? If not loop.RET;Return to the main SPC program code.

There is some code that sets up the DSP registers. It does things such as setting up the main volume, disabling echo,
setting the source directory and setting up the parameters for voice 0.

Code:

arch spc700!pitchLValue = $02!pitchHValue = $03macro writeToDSP2();This is a macro for writing values to the DSP.mov $F2,Y;Move the value in Y to the DSPAddr register.;The value in Y holds the address of the DSP register to write to.mov $F3,A;The A register we want to write to the current DSP registeer.endmacroORG $018400setup_DSP_registers:;Clear the direct page to zero.disable_echo:;Disable echo.mov Y,#$6C;Move the value of the FLG DSP register to Y.;To disable echo we will write a value to the FLG DSP register.mov A,#$20;Set bit 5 of the FLG register.;0x20 in binary is 00100000;bit 5 of FLG is the echo enable bit.%writeToDSP2();Write a value to the FLG DSP register.left_main_volume:;Set the left main volume.mov Y,#$0Cmov A,#$7F;Write 0x7F to the Main Volume Left DSP register.%writeToDSP2()right_main_volume:;Set the right main volume.mov Y,#$1Cmov A,#$7F;Write 0x7F to the Main Volume Right DSP register.%writeToDSP2()set_source_directory:mov Y,#$5Dmov A,#$10;Set the source directory to 0x1000, 0x10*0x100.%writeToDSP2()voice0_volume:;Set the volume for voice 0.mov Y,#$00mov A,#$7F%writeToDSP2();Voice 0 left volume.mov Y,#$01%writeToDSP2();Voice 0 right volume.load_note_value:;Load the value for the note we want to play.mov A,#$4f;Move 0x50 the index for note F5 to A.;0x50 gives you a note value of ASL A;Multiply it by two since each entry in the pitch table is two bytes.mov X,A;Move the noteIndex*2 to X.;The value in X will be used as an index in the pitch table.MOV A,$2000+X    ;Move the 16-bit index for this note to the YA register.MOV!pitchLValue,A    ;Store the Pitch (L) value to ram.MOV A,$2001+X;Store the Pitch(H) value to ram.MOV !pitchHValue,Aload_pitchL_value:MOV A,!pitchLValue;Move the pitchLValue to Y.MOV Y,#$02;Load the address of the Pitch(L) DSP register for voice 0 into A.%writeToDSP2()load_pitchH_value:MOV A,!pitchHValue;Move the pitchLValue to Y.MOV Y,#$03;Load the address of the Pitch(L) DSP register for voice 0 into A.%writeToDSP2()load_source_value:;Load the source value.MOV Y,#$04;Set the source instrument to 0.MOV A,#$00;Write to the SRC register for voice 0.%writeToDSP2()write_ASDR:MOV Y,#$05;Key on voice zero, 00000001.MOV A,#$8F%writeToDSP2()MOV Y,#$06;Key on voice zero, 00000001.MOV A,#$CA%writeToDSP2()write_gain:MOV Y,#$07;Key on voice zero, 00000001.MOV A,#$7F%writeToDSP2()write_key_on:MOV Y,#$4C;Key on voice zero, 00000001.MOV A,#$01%writeToDSP2()RET;Return to the main SPC program code.
After all the DSP registers have been set up, voice 0 is keyed on and the first sample plays.

After that, there is some code to wait and after a certain amount of time has passed voice 0 will be keyed off.

Then there is a jump back to $FFC9, this is where the IPL ROM communicates with the SNES CPU.

On the SNES side I set the rom address where the new sample is as the source address. Then I set the address where
the sample is in the SPC700's ram 0x3000 as the destination address. I basically use the same code that I used
to upload to the SPC700 before, to upload a new sample.

Then once the new sample has been completely uploaded to the SPC700, I key on voice 0 and the newly swapped in sample plays.

With a few modifications this can be used during gameplay as well. The idea is that on a certain scanline, say in the middle of the
screen or something; you would make the SNES CPU check if the SPC700 needs more data. Before that certain scanline, the main code
for the game could run.

One frame however is too short to swap an entire sample, so you would have to send say, 128 bytes to the SPC700 every frame. Until
the entire sample is uploaded, the voice for that sample would have to be muted.

Below you can download a ROM showing off this sample swapping code. It's not much; just a simple rom where you can hear a brass sample
on voice 0 and then later a string sample on the same voice.
sampleSwappingSuccess.sfc

Statistics: Posted by lex — Tue Apr 02, 2024 4:57 pm — Replies 0 — Views 93



Viewing all articles
Browse latest Browse all 746

Trending Articles