I've added this fix. I haven't updated the windows binary yet and I was hoping to get the increase in patterns, instruments and samples working in this latest update. Maybe next time. I did add your bugfix for ultra low pitch. Thanks for that!KungFuFurby wrote:Your SNESMod has a bug that I had fixed (and got incorporated into an actual updated version of SNESMod)...
The bug that occurs has to do with loading sound effects. It happens when loop points go bad and cause the carry flag to accidentally get set, resulting in the sample pointers to be out of alignment by one byte.
Sound driver fun
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
To save space I think I'll have the vibrato waveform set the tremolo and panbrello waveform as well. I've attached a short tremolo demo to the first post.
-
- Posts: 275
- Joined: Wed Jul 09, 2008 8:46 pm
Re: Sound driver fun
The negative octave handling code is not present in snesmod-1.2.asm. In addition, I added a clrc opcode just past asl a in oct_cont so that negative octaves don't mess anything else up.
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
Yeah, I was a bit sloppy there... the full fix was only in one of the drivers. They're all updated now.
Re: Sound driver fun
Well, have a 404 not found when I try to download your updated version Augustus Blackheart...
-
- Posts: 275
- Joined: Wed Jul 09, 2008 8:46 pm
Re: Sound driver fun
I cheated by replacing a 22 with a 30, realizing that the URL looked wrong since usually it indicated when the file was last updated.alekmaul wrote:Well, have a 404 not found when I try to download your updated version Augustus Blackheart...
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
Today's update has reduced redundancy in the vibrato routine from the ABNOFX driver applied to all of the sound drivers. I'm rewriting how the special features use zeropage. After I make sure all those routine are working properly under the new system I'll be adding tremolo, panbrello, noise frequency sweeps, and possibly swing tempo if I have time. Then I'll rewrite the filter sweep routine. Next up should be... phase inversion and pitch modulation to modify direct gain.
-
- Posts: 275
- Joined: Wed Jul 09, 2008 8:46 pm
Re: Sound driver fun
There are a couple of thoughts coming through my mind in regard to envelopes...
- There is a bug in regard to a note on with a delay freezing the previous instrument's envelope (this existed in the original version as well prior to your modifications).
- Perhaps there should be a "psuedo-gain" method of adjusting the gain on a per-step basis during SNESMod's idle loop (when the driver checks for commands and any ticks) for each of the channels rather than doing so instantly to reduce crackle. Obviously the rate won't be consistent this way, but one thing I do know is that direct gain has double precision of any attack-related gain/ADSR modes (except for bent gain, but only when loud enough). The psuedo-gain can also be applied to the panning, which has no such controls.
You don't need to implement this next part, but I have an extra piece of theory to apply to gain (especially if direct gain gives this a zero where in reality the value is less than a one, but not a zero):
- Exponential decrease can pull off volume levels that direct gain can't touch due to precision. The side effect of pulling this off is that it is prone to hiccups when the volume is increased since there is up to 15 sample's worth of delay in there after setup (especially if we're going all the way down to the lowest possible volume value gain can ever do, which is a sixteenth of what direct gain can pull off for an extreme low). This is because direct gain goes first and is set to 01.
I also have a bugfix in regards to surround failing to be disabled when the volume column uses a panning command:
- There is a bug in regard to a note on with a delay freezing the previous instrument's envelope (this existed in the original version as well prior to your modifications).
- Perhaps there should be a "psuedo-gain" method of adjusting the gain on a per-step basis during SNESMod's idle loop (when the driver checks for commands and any ticks) for each of the channels rather than doing so instantly to reduce crackle. Obviously the rate won't be consistent this way, but one thing I do know is that direct gain has double precision of any attack-related gain/ADSR modes (except for bent gain, but only when loud enough). The psuedo-gain can also be applied to the panning, which has no such controls.
You don't need to implement this next part, but I have an extra piece of theory to apply to gain (especially if direct gain gives this a zero where in reality the value is less than a one, but not a zero):
- Exponential decrease can pull off volume levels that direct gain can't touch due to precision. The side effect of pulling this off is that it is prone to hiccups when the volume is increased since there is up to 15 sample's worth of delay in there after setup (especially if we're going all the way down to the lowest possible volume value gain can ever do, which is a sixteenth of what direct gain can pull off for an extreme low). This is because direct gain goes first and is set to 01.
I also have a bugfix in regards to surround failing to be disabled when the volume column uses a panning command:
Code: Select all
;--------------------------------------------------------
; 128-192 set pan
;--------------------------------------------------------
vcmd_pan:
cmp mod_tick, #0 ; set panning
bne exit_vcmd ;
push a ;
mov a, y ;
sbc a, #128 ;
mov ch_panning+x, a ;
mov a, ch_flags+x ; Bugfix by KungFuFurby 12/20/15
and a, #~CF_SURROUND ; Surround should be disabled
mov ch_flags+x, a ; when panning is set via volume
pop a ; column.
ret ;
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
Anything that reduces crackle is great. I'll have to try it out.KungFuFurby wrote: - Perhaps there should be a "psuedo-gain" method of adjusting the gain on a per-step basis during SNESMod's idle loop (when the driver checks for commands and any ticks) for each of the channels rather than doing so instantly to reduce crackle. Obviously the rate won't be consistent this way, but one thing I do know is that direct gain has double precision of any attack-related gain/ADSR modes (except for bent gain, but only when loud enough). The psuedo-gain can also be applied to the panning, which has no such controls.
You don't need to implement this next part, but I have an extra piece of theory to apply to gain (especially if direct gain gives this a zero where in reality the value is less than a one, but not a zero):
- Exponential decrease can pull off volume levels that direct gain can't touch due to precision. The side effect of pulling this off is that it is prone to hiccups when the volume is increased since there is up to 15 sample's worth of delay in there after setup (especially if we're going all the way down to the lowest possible volume value gain can ever do, which is a sixteenth of what direct gain can pull off for an extreme low). This is because direct gain goes first and is set to 01.
Nice. I have it call the duplicate code from within Command_SetPanning which conviently ends with ret.I also have a bugfix in regards to surround failing to be disabled when the volume column uses a panning command:
Awhile back I changed the default master volume to be much higher and as such, in my own version of the driver, I got rid of the Echo Volume scaled by Master Volume routine. Do you think it's worth keeping that as an option in Super SNESMod? It might be useful is someone is manually setting the master volume lower, however, it takes up a lot of space... although I don't know why people couldn't just use different echo values if it's a concern.
-
- Posts: 275
- Joined: Wed Jul 09, 2008 8:46 pm
Re: Sound driver fun
I actually have something running through my head that might allow you to cut any effects that end up on the chopping block in the actual IT file (and also allows you to circumnavigate the assembler, not counting constant memory locations). Every single IT file must be scanned in the scenario of a soundbank though (or the user will have to manually define which ones to cut and/or keep... where all of them are on by default).Augustus Blackheart wrote:Awhile back I changed the default master volume to be much higher and as such, in my own version of the driver, I got rid of the Echo Volume scaled by Master Volume routine. Do you think it's worth keeping that as an option in Super SNESMod? It might be useful is someone is manually setting the master volume lower, however, it takes up a lot of space... although I don't know why people couldn't just use different echo values if it's a concern.
This is a lovely little file format that I have invented that allows you to pull off relocatable SPC700 code on the SNES (and in your C++ code if you want to make some adjustments) while minding constant memory locations (as defined by the assembler):
SPC700 Portable Code FormatThis might work well for SNESMod in particular (and it also cuts down on the number of copies of code you have to maintain in the process).
Allows you to make relocatable modules of SPC700 code.
Works for blocks of code up to 32,767 bytes in length (unless you want to bend the rules and define where constant memory locations begin).
Most likely SNES implementation is to construct the code in WRAM, then send it to the SPC700. In theory it can also be done on the fly
It is highly recommended to have a master pointer array on hand for the SPC700, as this format works best with re-loadable "modules" (think of a collection of note effects, for example).
Header is the following:
(For standard variety, which has a 32,767 byte limit)
- 15-bit filesize (in SNES bytes, not SPC700 bytes) + 1 bit flag (flag indicates whether or not there are extra details within the code to either modify or handle in a non-standard method)
(For non-standard variety, which requires that you define a constant indicating where constant memory locations end... this is not put in the actual SPC700 file, and is instead usually hard-coded on the SNES's end)
- 2 byte filesize (in SNES bytes, not SPC700 bytes)
- 1 byte flag containing the following bits...
-- (Bit 7) Whether or not the counters are 16-bit.
-- (Bits 6-5 are not defined yet.)
-- (Bit 4) Whether or not there are non-constant values not auto-detected by the code as two-byte pointer offsets
-- (Bit 3) Whether or not there are non-constant values not auto-detected by the code as scattered bytes
-- (Bit 2) Whether or not there are SLEEP opcodes that should be sent to the SPC700
-- (Bit 1) Whether or not there are STOP opcodes that should be sent to the SPC700
-- (Bit 0) Whether or not there are a series of two-byte pointers
The one-byte flag is also there in the standard variety, but it is optional since the one-bit flag will indicate whether or not this flag exists.
The filesize can be omitted, but in substitution for there being no filesize, the file must be ended with a STOP SPC700 opcode. In these scenarios, the one-byte flag is required.
When flag bits are set to account for non-auto-detected opcodes, then extra collections of data will show up after the flag byte.
Each collection contains a counter for the number of pointers to deal with. Counters are 8-bit by default, but they can be set to 16 bits by setting the highest bit for the flag (highly doubtful unless you somehow use more than 256 pointers in one set).
These extra data shall show up when the corresponding bit is set...
- (Bit 4) Two-byte pointers to SPC700 RAM offsets
- (Bit 3) Four-byte pointers to SPC700 RAM offsets (two bytes per pointer to a byte in the order of low byte, followed by high byte)
- (Bit 2) Two-byte pointers to SLEEP opcodes that should not be skipped (this directly affects SPC700 RAM offsets)
- (Bit 1) Two-byte pointers to STOP opcodes that should not be skipped
- (Bit 0) Four-byte pointers to a collection of SPC700 RAM offsets (two bytes indicate the start point, and two bytes indicate the end point)
All opcodes with !a parameters (including indexed parameters) are defined as following...
- Positive values indicate a constant memory location
- Negative values (which in this case means the sign bit is set) indicate an offset from the starting memory location of the code (these values are EORed by $FFFF when sent to the SPC700... meaning $FFFF stands for a zero offset). These offsets are NOT relative to the start of the file on the SNES, as bytes can be skipped and modified.
A SLEEP opcode (which normally should not be executed on the SPC700) does not get sent to the SPC700, and instead marks the beginning of non-SPC700 code. Following the SLEEP opcode is a two-byte filesize indicating how many bytes are not SPC700 code.
A STOP opcode marks the end of the file, and also does not get sent to the SPC700.
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
That would be a much better way of doing things. Speaking of cutting down on multiple versions...KungFuFurby wrote:I actually have something running through my head that might allow you to cut any effects that end up on the chopping block in the actual IT file (and also allows you to circumnavigate the assembler, not counting constant memory locations). Every single IT file must be scanned in the scenario of a soundbank though (or the user will have to manually define which ones to cut and/or keep... where all of them are on by default).
There are a lot of silly errors in that last version of SNESMod. Update coming soon.
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
I have two different issues I can't seem to figure out:
Issue 1:
I have a version of SNESMod that never pushes anything to the stack (except calls of course but it's not like there are a ton of nested calls). In this driver I put 144 bytes of sample data starting at 0100h. This works fine for most of my songs but there are a couple where it is fine for half of the song and than at a certain point something occurs and the stack stops hovering around 235-237 and keeps dropping very rapidly wiping out the 144 bytes at 0100h, continuing to decrease and wraparound endlessly. Other than losing that sample data, the song continues to play fine.
Although I only know the value of the stack register with the SPC player, the samples at 0100h do get destroyed in every emulator I've tried and on real hardware. Other songs tested did not have this issue. Any thoughts on what would cause this to occur? Everything else about the song plays perfectly fine so if it's some sort of bug it is only specific to whatever is going on with the stack. (I've been looking over song data but there was nothing especially noteworthy about this song it uses all of the same commands as other songs I've tested use.)
Anyway, it's not the biggest deal, but it would be nice to save some bytes for module data. In the mean time I've gone back to storing that particular sample data outside of stack space. Maybe this is something that is not possible to do...
Issue 2:
I set up a system to swap out 144 bytes (8 32 sample BRR) in SNESMod. This is stored outside of stack space. It works. Kind of. Here is the test I ran:
1: load sample
2: play module
3: change sample data
4: jump to previous pattern
repeat 3-4
The first two transfers always work, the third is unsuccessful, the fourth transfer works, and after that only the 2nd and 4th transfers are successful. When a transfer is unsuccessful, the result is either a short burst of noise or what sounds like a low pitch sine-ish waveform.
Ideally, I would like to be able to change samples at any time that a song is playing. I'm not sure what the proper way to do this is. If anybody has suggestions for what I should (or shouldn't) be doing that would be helpful. I thought about modifying the SPC streaming code from SNESMod for this task if I can't get it to work using this code, but I'd like to understand why this method isn't working consistently.
code on the SNES side:
code on the SPC-700 side:
Issue 1:
I have a version of SNESMod that never pushes anything to the stack (except calls of course but it's not like there are a ton of nested calls). In this driver I put 144 bytes of sample data starting at 0100h. This works fine for most of my songs but there are a couple where it is fine for half of the song and than at a certain point something occurs and the stack stops hovering around 235-237 and keeps dropping very rapidly wiping out the 144 bytes at 0100h, continuing to decrease and wraparound endlessly. Other than losing that sample data, the song continues to play fine.
Although I only know the value of the stack register with the SPC player, the samples at 0100h do get destroyed in every emulator I've tried and on real hardware. Other songs tested did not have this issue. Any thoughts on what would cause this to occur? Everything else about the song plays perfectly fine so if it's some sort of bug it is only specific to whatever is going on with the stack. (I've been looking over song data but there was nothing especially noteworthy about this song it uses all of the same commands as other songs I've tested use.)
Anyway, it's not the biggest deal, but it would be nice to save some bytes for module data. In the mean time I've gone back to storing that particular sample data outside of stack space. Maybe this is something that is not possible to do...
Issue 2:
I set up a system to swap out 144 bytes (8 32 sample BRR) in SNESMod. This is stored outside of stack space. It works. Kind of. Here is the test I ran:
1: load sample
2: play module
3: change sample data
4: jump to previous pattern
repeat 3-4
The first two transfers always work, the third is unsuccessful, the fourth transfer works, and after that only the 2nd and 4th transfers are successful. When a transfer is unsuccessful, the result is either a short burst of noise or what sounds like a low pitch sine-ish waveform.
Ideally, I would like to be able to change samples at any time that a song is playing. I'm not sure what the proper way to do this is. If anybody has suggestions for what I should (or shouldn't) be doing that would be helpful. I thought about modifying the SPC streaming code from SNESMod for this task if I can't get it to work using this code, but I'd like to understand why this method isn't working consistently.
code on the SNES side:
Code: Select all
; increment memory pointer by 2
.macro incptr
.scope
iny
iny
bne _catch_overflow
inc spc_ptr+2
_catch_overflow:
.endscope
.endmacro
;----------------------------------------------------------------------
spcLoadSample: ; y = sample address
;----------------------------------------------------------------------
phx
jsr spcFlush ; flush fifo!
plx
sty z:spc_ptr
lda sample_bank
sta z:spc_ptr+2
lda z:spc_v ; wait for spc
pha
: cmp REG_APUIO1
bne :-
lda #CMD_SAMPLE ; send SAMPLE message
sta REG_APUIO0
pla
eor #80h
ora #01h
sta z:spc_v
sta REG_APUIO1
: cmp REG_APUIO1 ; wait for spc
bne :-
ldx #144/2 ; x = word length
ldy #0 ; y = index
jsr do_transfer
rts
;--------------------------------------------------------------
; spc_ptr+y: source address
; x = length of transfer (WORDS)
;--------------------------------------------------------------
transfer_again:
eor #80h
sta REG_APUIO1
sta spc_v
incptr
: cmp REG_APUIO1
bne :-
;--------------------------------------------------------------
do_transfer:
;--------------------------------------------------------------
rep #20h ; transfer 1 word
lda [spc_ptr], y
sta REG_APUIO2
sep #20h
lda spc_v
dex
bne transfer_again
incptr
end_transfer:
lda #0 ; final word was transferred
sta REG_APUIO1 ; write p1=0 to terminate
sta spc_v
: cmp REG_APUIO1
bne :-
sta spc_pr+1
rts
Code: Select all
;-------------------------------------------------------------------
CopySample:
;-------------------------------------------------------------------
mov xfer_address, #Sample01&0ffh
mov xfer_address+1, #Sample01>>8
call StartTransfer
mov SPC_PORT1, comms_v
ret
;-------------------------------------------------------------------
StartTransfer:
;-------------------------------------------------------------------
mov x, comms_v ; start transfer
mov y, #0
mov SPC_PORT1, x
;-------------------------------------------------------------------
DoTransfer:
;-------------------------------------------------------------------
cmp x, SPC_PORT1 ; wait for data
beq DoTransfer
mov x, SPC_PORT1
mov a, SPC_PORT2 ; copy data
mov [xfer_address]+y, a
mov a, SPC_PORT3
mov SPC_PORT1, x ;<- reply to snes
inc y
mov [xfer_address]+y, a
inc y
beq _inc_address ; catch index overflow
_cont1: cmp x, #0 ; loop until x=0
bne DoTransfer
mov m0, y
clrc
adc xfer_address, m0
adc xfer_address+1, #0
mov comms_v, x
ret
_inc_address:
inc xfer_address+1
bra _cont1
Re: Sound driver fun
I have something of a working SPC debugger/tracer, if you'd like me to figure out what's going on with the first issue.
I don't have any ideas right off the bat regarding the second one, but I can take a closer look at the code later and see if anything seems suspect.
I don't have any ideas right off the bat regarding the second one, but I can take a closer look at the code later and see if anything seems suspect.
- Augustus Blackheart
- Posts: 61
- Joined: Sat Jul 26, 2014 9:50 am
Re: Sound driver fun
I fixed some of the clicking in SNESMod by using some code from XM2SNES. The issue I was having was with a bass sample and it would play fine unless 8th or 16th notes were used. This has been fixed!
SNESMod is a little less clicky than it was, but still more clicky than XM2SNES. This is still something I hope to fix, I don't have a lot of patience for this sort of thing, I'm always more interested in adding shiny new things than fixing broken things.
SNESMod is a little less clicky than it was, but still more clicky than XM2SNES. This is still something I hope to fix, I don't have a lot of patience for this sort of thing, I'm always more interested in adding shiny new things than fixing broken things.