It is currently Wed Dec 13, 2017 4:02 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sun Aug 21, 2016 9:49 am 
Offline

Joined: Fri Mar 02, 2012 11:10 pm
Posts: 35
The code at http://wiki.nesdev.com/w/index.php/APU_ ... ialization had this:
Code:
init_apu:
        lda #$0F
        sta $4015
       
        ldy #0
@loop:  lda @regs,y
        sta $4000,y
        iny
        cpy #$18
        bne @loop
       
        rts
@regs:
        .byte $30,$08,$00,$00
        .byte $30,$08,$00,$00
        .byte $80,$00,$00,$00
        .byte $30,$00,$00,$00
        .byte $00,$00,$00,$00
        .byte $00,$0F,$00,$40


There was an ominous warning saying "Do not alter this code in any way". However, I checked everything and I could find no reason at all to initialize $4015 first or to count up (requiring a CPY instruction) instead of down.

So I disregarded the warning and changed it to this:
Code:
init_apu:
        ldy #$17
@loop:  lda @regs,y
        sta $4000,y
        dey
        bpl @loop
       
        rts
@regs:
        .byte $30,$08,$00,$00
        .byte $30,$08,$00,$00
        .byte $80,$00,$00,$00
        .byte $30,$00,$00,$00
        .byte $00,$00,$00,$00
        .byte $00,$0F,$00,$40


Is there any reason why my change might be wrong, or should we let it stand?


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 9:58 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1393
I would argue that both the old and new code are incorrect, as they write to $4014 and initiate a pointless 512-cycle sprite DMA from zeropage in the middle of the sound initialization code.

The only registers that should be initialized are $4000-$4013, $4015, and $4017 (and of those, $4009 and $400D are pointless because no registers exist there).

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 10:00 am 
Online
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7314
Location: Chexbres, VD, Switzerland
Quote:
There was an ominous warning saying "Do not alter this code in any way"

Don't worry, this is pure bullshit. You are of course free to alter this code in any way you like.

Personally I just initialize by writing $00, then $0f to $4015. I do not think anything else has to be done to initialize sound. (EDIT : Yes, you should also write either $40 or $c0 to $4017 in order to select your sweep clock model - in most cases games just pick one and never change ever again but you could do a sound engine which toggles between both rates if you really wanted to).

EDIT :
Quote:
I would argue that both the old and new code are incorrect, as they write to $4014 and initiate a pointless 512-cycle sprite DMA from zeropage in the middle of the sound initialization code.

Indeed, the very idea of doing this is absolutely awful. This just show once more how unreliable the wiki is. There is also bullshit like "must" being in bold, which was previously declared to be inappropriate for technically documenting something.

EDIT II : Man, the quality of this wiki page is incredibly low, it's barely belivable. There is better docs about APU elsewhere, most notably the main APU page on the wiki. http://wiki.nesdev.com/w/index.php/APU
I guess the page you linked to is some sort of accident and should be permanently removed - this is just my opinion though.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 10:38 am 
Offline

Joined: Fri Mar 02, 2012 11:10 pm
Posts: 35
Yikes. I forgot $4014 is where the OAMDMA register is, just like the programmers before me. I'll bet that write to $4015 was because some earlier version of the code skipped over $4014, then someone didn't realize (or forgot) this needed to be done and added $4015 and $4017 to the table.

OK, I fixed the code and made a note in the hopes nobody will try simplifying it back to the way it was. I also toned down the warning, since I agree that it was a little strong.

Here's how it looks now:
Code:
init_apu:
        ; Init $4000-4013
        ldy #$13
@loop:  lda @regs,y
        sta $4000,y
        dey
        bpl @loop
 
        ; We have to skip over $4014 (OAMDMA)
        lda #$0f
        sta $4015
        lda #$40
        sta $4017
   
        rts
@regs:
        .byte $30,$08,$00,$00
        .byte $30,$08,$00,$00
        .byte $80,$00,$00,$00
        .byte $30,$00,$00,$00
        .byte $00,$00,$00,$00


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 10:59 am 
Online
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7314
Location: Chexbres, VD, Switzerland
Yet, there is no point in writing to $4000-$4013 registers. It doesn't harm like writing to $4014 does, but still, writing $00 to $4015 and $40/$c0 to $4017 is enough to stop all sound and put the APU in a known state. Writing to individual channel registers is not necessary before the first sound has to be emitted.


Last edited by Bregalad on Sun Aug 21, 2016 11:35 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 11:23 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1393
Looking at the edit history of that page, the init code presented there was specifically designed for all of the other samples further down - some revisions had comments on the "init values" table to explain what they did and why, but those got removed for some reason.

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 12:57 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5893
Location: Canada
Bregalad wrote:
Yet, there is no point in writing to $4000-$4013 registers. It doesn't harm like writing to $4014 does, but still, writing $00 to $4015 and $40/$c0 to $4017 is enough to stop all sound and put the APU in a known state. Writing to individual channel registers is not necessary before the first sound has to be emitted.


Other than $4015 and $4017, I think it's important to initialize the two sweep registers ($4001, $4005), especially if your audio engine is going to otherwise ignore them and never write to them. Normally their state is guaranteed by power-on, but a game genie notably breaks this assumption (e.g. causing a problem for Mega Man 2).

All the other registers don't really need initialization, since they're pretty much mandatory to set up to play any particular sound, and simply clearing $4015 will halt them and reset their length counters to 0.

No harm in initializing the rest, though, and there's a utility in putting all the channels into a length-counter-disabled "always on" state before starting, if your music engine works that way.

Personally, I never used a loop for this, just a sequence of explicit stores. I guess the loop saves a few bytes; less now with the special case for skipping $4014.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 4:21 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3968
You need to set proper values to the sweep registers, otherwise you won't be able to play very low notes.

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 5:00 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5893
Location: Canada
Dwedit wrote:
You need to set proper values to the sweep registers, otherwise you won't be able to play very low notes.

Yes. A power-on sweep ($00) basically silences the squares any time you set to top bit of pitch, eliminating the entire bottom half of usable range. Mega Man 2 actually never uses that top bit, apparently. (This may be true of several Capcom games? Mega Man 3 does properly initialize sweep though, so they'd realized the problem by 1990.)

I'm kinda wondering if there are any NES games with "hidden" bass notes because of this? I didn't see any in MM1/MM2.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 6:02 pm 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2982
Location: Tampere, Finland
The page was supposed to present a simplified model of the APU (no sweep, no envelopes, no length counters, ...) for beginning programmers. Those small details of "we have to skip this and that and can't write here" can add a lot of unnecessary cognitive load. I bet this is why the comments about the purpose of the initialization values were removed, and also why it doesn't care about triggering a most likely harmless OAM DMA.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 6:29 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5893
Location: Canada
If the goal is illustration would ditching the loop help? Instead of a very "opaque" table of values, you'd get something you could lightly annotate:
Code:
init_apu:
   lda #$40
   sta $4017 ; disable APU IRQ
   lda #$00
   sta $4015 ; disable all channels
   lda #$30
   sta $4000 ; initialize squares
   sta $4004
   sta $400C ; initialize noise
   lda #$80
   sta $4008 ; initialize triangle
   lda #$08
   sta $4001 ; disable sweep
   sta $4005
   lda #$00
   sta $4002 ; set low pitch to 0
   sta $4006
   sta $400A
   sta $400E
   sta $4003 ; set high pitch to 0
   sta $4007
   sta $400B
   sta $400F
   sta $4010 ; initialize DMC
   sta $4011
   sta $4012
   sta $4013
   lda #$0F
   sta $4015 ; enable all channels
   rts

The loop saves a few bytes and/or lines of code, but for teaching purposes it makes everything that it's actually doing pretty obscure. You could skip the pitch setting in this example, too, if you wanted to make it shorter (initialized pitch isn't important to the examples, AFAIK).

I think the "don't mess with this" statement that follows the code is more vexing than the code itself, though:
Quote:
This writes values that are most useful for basic use of the channels. It's not important exactly what they do, just that they establish a known state. Be careful: if you alter this code, the APU might not behave in the simpler way described on this page.

I don't think telling someone that "it's not important" or not to alter this code is helpful; it kind of gives the impression that this is mysterious and understanding shouldn't be attempted, similar to how I felt about "the skinny about NES scrolling" being presented as this advanced and unapproachable knowledge. I think something like this would suffice:
Quote:
The initialization above will prepare the APU to a known state, ready to be used by the examples below.

Someone who doesn't think they understand that code wouldn't try to alter it anyway, you don't need to pre-load them with an expectation that it's hard to understand to prevent this. Just let them look it up and learn if they're interested.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 9:34 pm 
Offline

Joined: Fri Mar 02, 2012 11:10 pm
Posts: 35
I dunno. I think a coder who is ready to really get into the nitty gritty like that should already be capable of working out what the code does as it is.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 11:33 pm 
Online
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7314
Location: Chexbres, VD, Switzerland
Quote:
The page was supposed to present a simplified model of the APU (no sweep, no envelopes, no length counters, ...) for beginning programmers. Those small details of "we have to skip this and that and can't write here" can add a lot of unnecessary cognitive load. I bet this is why the comments about the purpose of the initialization values were removed, and also why it doesn't care about triggering a most likely harmless OAM DMA.

This page is useless and should be deleted. If the real APU page is not understandable, then it should definitely be fixed. But there's no need for a "simplified" model or whathever. Just describe the APU as it is.

I forgot about sweep registers, because my own sound engine just writes to them on every new note. If you don't use them, then yes, they should be initialized to any value between $08 and $0f.

Quote:
eliminating the entire bottom half of usable range

Actually it just eliminates the lowest octave. Many games doesn't use it and use a sweep value of $00, yet I agree this is a bad approach and add useless limitations to NES sound.


Top
 Profile  
 
PostPosted: Sun Aug 21, 2016 11:45 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5893
Location: Canada
Bregalad wrote:
Quote:
eliminating the entire bottom half of usable range

Actually it just eliminates the lowest octave. Many games doesn't use it and use a sweep value of $00, yet I agree this is a bad approach and add useless limitations to NES sound.

Yes, in linear pitch space, half the range = one octave. I suppose I made it sound slightly worse than it is. ;)

Bregalad wrote:
This page is useless and should be deleted. If the real APU page is not understandable, then it should definitely be fixed.

I think it's supposed to be a tutorial on how to use it. The APU reference is reference, not a tutorial. I can see the purpose of both. Whether it's a good tutorial or not, or appropriately titled, that's another set of problems.


Top
 Profile  
 
PostPosted: Mon Aug 22, 2016 4:28 pm 
Offline

Joined: Fri Mar 02, 2012 11:10 pm
Posts: 35
I'd missed this post earlier:

thefox wrote:
I bet this is why the comments about the purpose of the initialization values were removed, and also why it doesn't care about triggering a most likely harmless OAM DMA.

This is a dangerous attitude to have. For one thing, if you're going to put up a message saying not to modify the code at all, it had better be good code. It wasn't.

Second, you're making a lot of assumptions in calling the OAM DMA "most likely harmless". Sure, it's harmless if another DMA is done right afterward, but there's no reason to presume so. There might be some tutorial (either now or in the future) where DMA is done once during initialization and then ignored, which would make sense for a program without sprites. If that DMA is done before initializing sound, the poor user might waste hours trying to find out why he's getting garbage on the screen when he runs his program. And for what? To save two bytes in the sound initializer?


Bregalad wrote:
This page is useless and should be deleted. If the real APU page is not understandable, then it should definitely be fixed. But there's no need for a "simplified" model or whathever. Just describe the APU as it is.

WTF! Are you mistaking a beginner's tutorial for reference material or what?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot] and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group