Getting around the DPCM bug in a ROM hack

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
za909
Posts: 224
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

Re: Getting around the DPCM bug in a ROM hack

Post by za909 » Sun Jan 26, 2014 8:47 am

Actually that's fine because getting rid of the code for the second controller is of no consequence really.
But yeah, I've been meaning to learn all this, it's just that when I think about how much stuff there is, suddenly there's no wonder why there were so many people developing a single game. I just can't work on everything at once. It's no good that I'm interested in the APU features, and some of the PPU features, because there's still everything else to do.
And I really don't want much, just getting some sort of a NROM-based clone game done is the way to go at first I guess.

Edit: Ok, I came up with something, but it's not even willing to compile it, saying I have illegal instructions in lines 7 and 9.
But it doesn't matter because it wouldn't work anyway.

Code: Select all

this_frame = $00
prev_frame = $14
usable_frame = $16
.org $C545

controller_beg:
; Store two consecutive reads and then compare them
rts joyinit
sta this_frame
rts joyinit
tax 
lda this_frame
sta prev_frame
txa 
sta this_frame
lda prev_frame
cmp this_frame
bne controller_beg ; If reads don't match, start over
sta usable_frame
ldx #$00
stx this_frame
stx prev_frame
rts

joyinit: ; Get all 8 bits from the controller port
ldx #$01
stx $4016
dex
stx $4016
ldx #$08
getbits:
lda $4016
and #$03
cmp #$01
ror this_frame
dex
bne getbits
rts


tepples
Posts: 22233
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Getting around the DPCM bug in a ROM hack

Post by tepples » Sun Jan 26, 2014 10:18 am

RTS takes no operand. Were you thinking of JSR?

User avatar
za909
Posts: 224
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

Re: Getting around the DPCM bug in a ROM hack

Post by za909 » Sun Jan 26, 2014 10:25 am

Oh I'm an idiot, yeah that's probably what I meant, thanks.

Edit: Yeah, this doesn't really work either. The bits are kind of the wrong way around now, and in the original game, my input is always seen at $16, flashes for a fraction of a second at $14 and I can't see a thing at $00 when I press something.
So actually, I don't even know which one of these the rest of the game gets the input from.
Last edited by za909 on Sun Jan 26, 2014 10:31 am, edited 1 time in total.

User avatar
tokumaru
Posts: 11944
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Getting around the DPCM bug in a ROM hack

Post by tokumaru » Sun Jan 26, 2014 10:30 am

za909 wrote:I have illegal instructions in lines 7 and 9.
That's because you tried to use an operand with the RTS operator, but RTS doesn't take any operators. You probably meant to use JSR here, to call the same subroutine twice. OK, now let's see what else is wrong:

The actual joyinit looks correct, but unlike your first call to it suggests, it doesn't return any results in the accumulator, it stores the controller bits directly into the this_frame variable. This means that there's no point in having "sta this_frame" after the call. If the bits are already in this_frame, you're actually trashing them with the STA. Which leads to another problem:

If the joyinit routine is overwriting the contents of this_frame, you have to back that up to prev_frame BEFORE calling it, otherwise you'll lose the previous frame's bits. Just do the "lda this_frame; sta prev_frame" before the calls to joyinit. Similarly, you will trash the first call's bits if you don't back them up before the second call to joyinit. You don't seem to be using the Y register, so that seems like a good place to temporarily put the bits in (put "ldy this_frame" between the two calls to joyinit).

Now, after the second call, you already have the previous frame's bits in prev_frame, this frame's first read in Y and this frame's second read in this_frame. There's no need to store and load a bunch of stuff like you did, you can simply compare Y to this_frame with "cpy this_frame". Now, the original suggestion was that you used the previous frame's bits in case the new reads didn't agree, but it seem you are trying to do the two reads again. Both are possible solution, and if you want to try again you have to jump back to the part after you have backed up last frame's bits, otherwise you'll trash them (if you think about it, you won't even the need the previous frame's bits y=if you're reading the joypad over and over, so you can get rid of everything related to prev_frame). If you just want to use the old bits, you can "lda prev_frame; sta this frame". I see no need for the usable_frame variable, because the contents of this_frame will be the usable data.

I guess this is all I can see wrong with your code. I have to agree that it looks very chaotic, and that you haven't planned the execution order very well in your head. Keep in mind that instructions in a program are executed in order, so it's easy to do a preliminary run of it in your head to see whether variables are being overwritten and where all the data is going when you move it around.

User avatar
rainwarrior
Posts: 7979
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Getting around the DPCM bug in a ROM hack

Post by rainwarrior » Sun Jan 26, 2014 6:30 pm

Getting started on a game from scratch is much easier than getting started on a non-trivial hack. However, getting a game finished from scratch is much harder than most hacks, I'd say.

There are several popular 6502 assemblers that will run on modern windows. I strongly prefer cc65, myself. cc65 comes with a disassembler, and you can use its linker's "segment" feature to easily align the code you are replacing in your hack.

My advice is just to break your task down into small increments. Do a little bit at a time and make sure it works before moving on. Learn how to use FCEUX's debugger, or some other NES emulator's debugger as you're doing this.

Another thing might help is generating a "code data log". FCEUX can do this. It creates a map of what memory is code and which is data. This can help a lot when creating a disassembly.

unregistered
Posts: 1112
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Getting around the DPCM bug in a ROM hack

Post by unregistered » Sun Jan 26, 2014 8:27 pm

thefox wrote:
tokumaru wrote:
unregistered wrote:When I'm stumped I pray. : )
I'm not a religious person, but if I were I wouldn't bother God with my NES ROM Hacking problems while so much bad stuff is happening all around the world!
God is omnipotent though, so he wouldn't care.

(P.S. I'm not religious either.)
Oh, God is interested in what each one of us has to say to Him. :)

User avatar
za909
Posts: 224
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

Re: Getting around the DPCM bug in a ROM hack

Post by za909 » Sat Feb 01, 2014 3:32 am

Alrighty, update!
After a good 1 week of failing and only getting so close that I actually made a turbo controller out of the basic one, I decided to go ahead and use the code from tepples. (Thanks for that!) It still involved a tiny bit of work because I had to chop the code up and spread the pieces across the last two banks, so that I could avoid having to lose any space for samples.

Before moving on to creating the DPCM player, I'll try to remove everything second controller-related (that'll be a thing...) on one hand because this way players won't be able to use the cheat features, plus I'll get a few bytes in the zero page to work with in my player routine.

Please don't help me with this unless I'm tearing my hair out. The whole point of this should be that I figure things out myself, which I've already failed at doing.

EDIT:Oh, never mind, that was pathetically easy. Right! Now comes the fun part with the DPCM samples.

User avatar
za909
Posts: 224
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

Re: Getting around the DPCM bug in a ROM hack

Post by za909 » Mon Feb 03, 2014 7:50 am

I might get warning for double posting now or something, but noone's going to notice otherwise.
I sort of got it to work, but the rythmization isn't quite there, maybe you can spot some sort of a problem in my code, or it might be related to how and when the routine is called by the sound engine. The recording is supposed to be a single beat of two bass samples, and two kick drums, but it gets a little mixed up.

VirtuaNES Recording

Current playback code:

Code: Select all

.org $8570

eff_param = $C3
freq = $15
id = $17
ch_enable = $4015
dpcm_freq = $4010
dpcm_dc = $4011
dpcm_add = $4012
dpcm_len = $4013
	
	; The engine saves the parameter to $C3
	jmp main 

	; There's only 9 bytes of space here, so we're off to
	; some other place!
	
.org $8c9d
main:
	
	; Save all 3 registers
	; See if it's a sample (or a silence command (FF)). 	
	; If not, disable channel and return
	; If yes, stop currently playing sample, and play a new 	; one.
	
	pha
	txa
	pha
	tya
	pha
	lda eff_param
	ldx #$0f
	stx ch_enable
	cmp #$ff
	bne new_sample
	jmp end
	
new_sample:

	; Reset delta counter
	
	ldx #$00
	stx dpcm_dc
	
	; Get sample ID and frequency
	
	and #$0f
	sta freq
	lda eff_param
	and #$F0
	clc
	ror
	ror
	ror
	ror
	sta id

find_then_play:
	
	; Locate sample address and length in a lookup table
	
	ldx id
	lda add_tbl,x
	ldy len_tbl,x
	sta dpcm_add
	sty dpcm_len
	lda freq
	sta dpcm_freq

	; Re-enable channel to start playback

	ldx #$1f
	stx ch_enable

	; Clear used RAM & restore registers
	lda #$00
	sta freq
	sta id
	
end:
	pla
	tay
	pla
	tax
	pla
	rts

	; I decided to make room for a maximum of 8 samples, in
	; case this will be used in something else

add_tbl:
	.db $cd,$d2,$f7,$09,$ff,$ff,$ff,$ff
len_tbl:
	.db $11,$0f,$04,$05,$00,$00,$00,$00
	
	
	
	
	

strat
Posts: 385
Joined: Mon Apr 07, 2008 6:08 pm
Location: Missouri

Re: Getting around the DPCM bug in a ROM hack

Post by strat » Tue Feb 04, 2014 5:33 pm


unregistered
Posts: 1112
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Getting around the DPCM bug in a ROM hack

Post by unregistered » Sat Feb 08, 2014 12:24 am

za909 wrote:I might get warning for double posting now or something, but noone's going to notice otherwise.
No I haven't recieved any warnings for double posting, a few times I have quad posted :( ...in my own thread though. As long as you are making progress it's ok here, I think. :)
za909 wrote:I sort of got it to work, but the rythmization isn't quite there, maybe you can spot some sort of a problem in my code, or it might be related to how and when the routine is called by the sound engine. The recording is supposed to be a single beat of two bass samples, and two kick drums, but it gets a little mixed up.
When I was recieving odd sounding music from my .nes file I revisited the page where I had found the sound engine famiTone that Shiru made. He had a good introduction webpage... and I read it slowly and it turned out that I hadn't setup one of the basic things he had talked about. I had read his webpage quickly many times. That slow read helped my song to sound correct! Thought I should share this with you... hope you succeed too! :)

User avatar
za909
Posts: 224
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

Re: Getting around the DPCM bug in a ROM hack

Post by za909 » Sun Feb 09, 2014 1:46 am

Oh, yeah I figured out that it wasn't actually my programming that failed, but rather me translating the sequence data to hex, so things got uneven. I decided to throw a PHP-PLP in there just to be safe, and now it's working perfectly!

The thing is though, that since I make it reset the delta counter for every new sample to avoid getting to $7F with the signal level by accident, the popping noise seems to differ a lot depending on certain emulators. In Famitracker it's next to inaudible, because the two bass samples leave the counter at $18 and $26 respectively. In VirtuaNES and VirtuaNSF, the popping is made even quieter. In FCEUX 2.2.2 everything is popping like mad. Nestopia is kind of ok. How bad could it be on a real console? I might have to add another comparison, so it resets to $00 only for the drum samples, and to $20 for the rest.

User avatar
thefox
Posts: 3141
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Getting around the DPCM bug in a ROM hack

Post by thefox » Sun Feb 09, 2014 2:14 am

za909 wrote:The thing is though, that since I make it reset the delta counter for every new sample to avoid getting to $7F with the signal level by accident, the popping noise seems to differ a lot depending on certain emulators. In Famitracker it's next to inaudible, because the two bass samples leave the counter at $18 and $26 respectively. In VirtuaNES and VirtuaNSF, the popping is made even quieter. In FCEUX 2.2.2 everything is popping like mad. Nestopia is kind of ok. How bad could it be on a real console? I might have to add another comparison, so it resets to $00 only for the drum samples, and to $20 for the rest.
Some emulators have built-in DPCM pop filters. I would trust FCEUX in this case, I have found that its audio emulation seems to be quite accurate. Not sure what's going on with Nestopia, it doesn't have a pop filter as far as I know, but I could be wrong.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi

User avatar
rainwarrior
Posts: 7979
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Getting around the DPCM bug in a ROM hack

Post by rainwarrior » Sun Feb 09, 2014 9:14 am

Famitracker does not suppress DPCM pops. Its only filters are the usual lowpass on the whole circuit + DC filter highpass, which are pretty standard for emulating the NES.

Because the DPCM pop is an all-band sound, it's affected by just about any subtle tweaks you could make to the overall signal. An emulator doesn't have to have specific DPCM pop suppression, a subtly different filter setup can make a quite audible difference. Even trying a few different NES or Famicom units, the pops will sound a little different.

Some emulators do have methods specifically to suppress the DPCM pop, but if they do it should be an option and not on by default. I don't believe FCEUX, Nestopia, or VirtuaNES does this by default. I think in general the underlying digital emulation of DPCM pops is more or less the same across the board, but the subtle difference in analog filter implementations makes a bit of a difference on pops.

Famitracker generally has very accurate sound emulation. I've compared it directly against hardware recordings many times. As I said above, though, the hardware is a bit of a moving target. DPCM pops are one of the most volatile sounds in terms of consistency across machines.

Post Reply