Easier APU documentation?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Easier APU documentation?
by on (#65060)
I'm trying to learn how to use the APU and I've been trying to read the wiki pages about it, but I'm finding everything terribly confusing. The information is scattered across several pages, and they are linked in a very unintuitive manner. And the explanations are very low level, full of stuff that doesn't interest me as a NES coder (they are probably useful to emulator authors, though) and only make it harder for me to understand how to interact with the APU.

I can't avoid thinking that those pages assume that the person who is reading already knows a great deal about the APU, and just needs those pages for a quick reference of which bits go where or the order in which certain things happen. I wonder if this is how a newbie feels like when looking at PPU information, for example.

Anyway, I was wondering if anyone knows about documents where APU information is displayed in a more straightforward way, much like the PPU page is, with the complete list of registers and what results a programmer should expect when writing to or reading from them. I don't care about the mixer, the sequencer, what kind of algorithm is used to generate the noise or any of that internal information, I want a bare bones document showing that when I write X to register Y the result is Z, without telling me everything that happens behind the scenes. Is there anything like that around?

EDIT 1: Just to make it clear, I understand what the APU can do, I know what periods I should use for each note, I know what the duty cycle is, that part is fine (I learned most of it by playing with Famitracker). What I need to find out is how I can get the APU to play the notes I want, at the volume I want and with the duty cycle I want without the hardware sweeps and envelopes getting in my way, because I have those implemented in software.

EDIT 2: I just found this in the Nerdy Nights sound tutorial:
Code:
SQ2_ENV ($4004)

76543210
||||||||
||||++++- Volume
|||+----- Saw Envelope Disable (0: use internal counter for volume; 1: use Volume for volume)
||+------ Length Counter Disable (0: use Length Counter; 1: disable Length Counter)
++------- Duty Cycle

Now this is perfectly easy to understand, exactly like the PPU pages in the wiki. Does anyone know if this was copied from a more complete document and where it can be found?

by on (#65062)
Taking one of the pulse-wave channels:

Register 0 ($4000)
----------------------
Controls amplitude, duty, envelope/length counter.

%DDxxxxx = duty
%xxxxAAAA = amplitude

but you need to set bit 5 and 4 to stop the envelope/length counter. So;

lda amplitude ($00-$0F)
ora duty
ora #$30
sta $4000


Register 1 ($4001)
----------------------

To turn off the hardware pitch sweep;

lda #$08
sta $4001

by on (#65066)
So once I turn those things off I don't have to worry about them again? I mean, the envelope and length counter I'll probably disable whenever I rewrite the volume and duty cycle, but what about the sweeps? Can I just disable them once and forget about it?

I still would like to have more information about the other channels (triangle and noise), so if there is a document out there that doesn't use the cryptic names used in the wiki (why would it call the volume "envelope"? that's just misleading...), please let me know.

by on (#65068)
I agree....I need/want to write a sound engine for my future complex games but the sound really really scares me since all this stuff seems just to...well....just is so un-interlaced. Nothing seems to goto together with good examples. I would love for a better description of registers and how to control them but I know that is asking alot :/


Maybe it'll get there piece by piece ^_^

by on (#65071)
tokumaru wrote:
So once I turn those things off I don't have to worry about them again? I mean, the envelope and length counter I'll probably disable whenever I rewrite the volume and duty cycle, but what about the sweeps? Can I just disable them once and forget about it?

I still would like to have more information about the other channels (triangle and noise), so if there is a document out there that doesn't use the cryptic names used in the wiki (why would it call the volume "envelope"? that's just misleading...), please let me know.


You can just disable the sweeps once and never touch them again, yes.

I'll see if I can put something together later, just the facts that will get you going rather than a technical reference :)

Edited to add : this is where I got all my information from to write my code;

http://nesdev.com/apu_ref.txt

That and a lot of trial and error :)

by on (#65072)
65024U wrote:
I would love for a better description of registers and how to control them but I know that is asking alot :/

From what I've read so far, the Nerdy Nights sound tutorial is pretty straightforward and tells exactly what you have to do to get things going without much trouble, along with simple register descriptions. Assuming it's accurate, I guess it's a really good intro to sound programming.

I still would like I concise register description to use as reference, but if there isn't any the tutorial itself will have to do. I have most of my sound engine done, I just have to write the final data to the registers now.

EDIT: Thanks again, Neil. I guess you are the guy to get help from when the issue is sound/music! :D

EDIT 2: That's Blargg's document, right? It looks better than the wiki (even though the wiki says its info is based on this doc), but there's still a lot of cryptic information we have to dig through in order to find the basics of interfacing with the registers.

EDIT 3: It seems to me that what makes the APU complex are the things I'm not interested in (envelopes, sweeps, etc.), and these in depth documents have a lot of information on them, which I don't need. Once you take those out, the APU seems to be pretty easy to use actually. What I find difficult to do is filtering what's relevant and what isn't from these in depth documents.

by on (#65076)
I know what you mean. Going back a long, long time, once I'd figured out how to turn off the envelopes/length counter and hardware sweep, i never touched them again until recently when I added hardware sweep feature to NTRQ.

Yeah, the Nerdy Nights is pretty good stuff. I'd forgotten about that.

by on (#65080)
Done! APU basics on the Wiki.

I managed to greatly simplify the conceptual model without sacrificing any essential features. By not even covering the length counters/linear counter/sweep/volume envelopes, things are very simple. You can do all those things in software anyway, so you don't even need them. I believe as long as you follow the model described, you won't ever run into these other features.

Thanks for the inspiration, tokumaru. While writing this, I looked at the current triangle wave page on the Wiki to be sure I got the frequency formula correct, and saw how bad it was as a programming reference. :)

by on (#65082)
tokumaru wrote:
The information is scattered across several pages

If three different channels have a given component, why repeat the full description of that component on the three separate pages about the three different channels? For example, the channels Pulse 1, Pulse 2, and Noise have the volume envelope generator.

tokumaru wrote:
So once I turn those things off I don't have to worry about them again? I mean, the envelope and length counter I'll probably disable whenever I rewrite the volume and duty cycle, but what about the sweeps? Can I just disable them once and forget about it?

Yes. If you plan to do all frequency changing in software, do this to disable hardware sweep:
Code:
  lda #$08
  sta $4001
  sta $4005


Quote:
I still would like to have more information about the other channels (triangle and noise), so if there is a document out there that doesn't use the cryptic names used in the wiki (why would it call the volume "envelope"?

The volume section has two modes: decay mode and constant mode. Decay mode acts like the decay phase in an ADSR envelope.

by on (#65083)
The main point is that you have two audiences with different needs. Emulator authors need to know every detail. Duplicating information in this detailed description is a violation of the DRY principle, and leads to inconsistencies. Programmers generally only need to know how to make the desired sounds, so a different format is called for. The new page hopefully serves many programmers.

by on (#65101)
Thanks for the new page, blargg, it's much appreciated.

by on (#70183)
I think I'm going a bit mental. It's not like I haven't programmed NES audio before but if I do this;

Code:
lda #$0F
sta $4015
lda #%00111111
sta $400c
lda #$00
sta $400e


I get nothing. But if I do;

Code:
lda #$0F
sta $4015
lda #%00111111
sta $400c
lda #$00
sta $400e
sta $400f


I get noise, as expected.

I'm pretty sure in the past I've always just wrote the noise pitch to $400e and $400f but I can't remember why.

by on (#70184)
There is also Brad Taylor's 2A03 reference, which covers the sound aspects of it as well.
http://nesdev.com/2A03%20technical%20reference.txt

neilbaldwin wrote:
I'm pretty sure in the past I've always just wrote the noise pitch to $400e and $400f but I can't remember why.


Because $400F (same as $4003/$4007/$400B) contains the length counter, IIRC setting D3 enables it, but with a stopped counter or infinite length. Writing there also re-triggers hardware volume envelopes. I treat it like a "note on" register, but I think with the noise channel you would only have to write to it once.

Some sound engines used D3 of those registers to stop the sound (or they set the frequency to zeros, or they set the volume to zero, lots choices if the length counter isn't being used, heheh).

by on (#70185)
Here's a big APU gotcha: Even if you're not using the sweep unit, you must still write 0x08 to the sweep register, otherwise it won't play the lowest notes.

There are features in the APU that stop a note when the current period + "whatever sweep would add" becomes too high, and writing that value to the sweep register stops that.

by on (#70186)
Dwedit wrote:
Here's a big APU gotcha: Even if you're not using the sweep unit, you must still write 0x08 to the sweep register, otherwise it won't play the lowest notes.


Yep, nasty one for the beginner that.

Re. the noise thing. I need to do another test (just about to run out the door) but if you copy the apu init routine from the wiki, you won't get any noise. But if you just tack an extra lda #0, sta $400F on the end it works. Is there something in the order that you write the registers?

by on (#70188)
The code from the Wiki works fine for me (testing on a PAL NES at the moment). I do notice that your code plays a very quiet noise either way, maybe that's the problem.

by on (#70192)
blargg wrote:
The code from the Wiki works fine for me (testing on a PAL NES at the moment). I do notice that your code plays a very quiet noise either way, maybe that's the problem.


Odd. It plays full volume here. Definitely not a volume issue.

*shrugs* I'm baffled.

by on (#70195)
Can you show the complete code that you're using? Maybe the error is elsewhere. I just verified it on an NTSC NES as well, with the code running at reset.

by on (#70196)
Just stripped it all down to this;

Code:
reset:
   sei
   ldx #$FF
   txs
   lda #$00
   sta PPU0
   sta PPU1
   
        jsr init_APU

mainLoop:
   jmp mainLoop
   
nmi:   rti
irq:  rti

init_APU:
   
   lda #$00
   sta $4015
   
   ldx #$00
@a:   lda @apu_regs,x
   sta $4000,x
   inx
   cpx #$18
   bne @a

   lda #$0F
   sta $4015
   
   lda #%00111111
   sta $400c
   lda #$01
   sta $400e
   ;sta $400f
   rts

@apu_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
   


Which produces no sound until you put the 'sta $400f' line back in.

by on (#70197)
Here's the problem; your init_apu routine is different than the one on the wiki:
Code:
init_apu:
        lda #$00   ; should be $0F
        sta $4015

I've added a note to the Wiki as to not altering the init routine in any way. Using the above was preventing the length counters from being loaded properly by the loop.

by on (#70213)
That's very odd.

I originally had the init routine from the wiki, verbatim, and I wasn't getting any noise output unless I wrote something to $400F at the time of writing the frequency register ($0E).

So then I added the lines to write $00 to $4015 before the loop and $0F after the loop, just clutching at straws really. It didn't seem to have any effect.

Now I've restored the init back to the wiki version, removed the extra write to $400f and it's now working.

*shrugs* Ghosts in the machine maybe....

by on (#70444)
tokumaru wrote:
From what I've read so far, the Nerdy Nights sound tutorial is pretty straightforward and tells exactly what you have to do to get things going without much trouble, along with simple register descriptions. Assuming it's accurate, I guess it's a really good intro to sound programming.


Thanks! I wrote those tutorials to help people learn how to program the APU. The tech docs are great but dense. A lot of new homebrewers were coming in and posting ROMs of their games in progress, but they were all silent. I had just figured the APU out so I wanted to help out.

BTW, if anyone wants to host or copy/paste the Nerdy Nights sound tutorials somewhere in the nesdev wiki, you have my blessing. The more accessible they are to nes homebrewers the better.