Yep, sound. It's actually not that hard to make the NES output a sound. One can make a simple (perhaps ugly) sound by just messing with the necessary mem. regs and turning on the channel in $4015.
Please note that this pretty much just a rewording of Brad Taylor's Sound Doc in more words that will, hopefully, make it a small bit easier to understand.
So please read that doc a few times and then come back. Don't worry, this isn't going anywhere! ;)
One last thing before we begin, bits are always numbered from #0 on the right and #7 on the far left.
Square Wave/Channel #1
I'm not sure what the technical description of a square wave is, but it probably (based on the name) looks something like this: _|-|_|-|_ assuming the |s are shorter.
The Square Wave Channel 1 has the following features:
- 54.6 Hz to 12.4 KHz in frequency.
- Frequency sweep or constant tone.
- output duty cycle adjustment (anyone have any idea what this means?).
The easiest thing to do is get a constant tone. The second hardest is actually having control over the frequency, the most hardest is the frequency sweep as it took me several tries to get to work. Also, please note that I use 2 emulators for code testing FCEU (FCE Ultra) and Rew if it works on either one, I consider the code "working".
The registers that are for Channel #1 are $4000-$4003 and as usual $4015 for enabling the channel. Please use the sound doc for the specific bit definitions.
Register $4000 controls (as far as I can tell from all Taylor's tech mumbo-jumbo), starting frequency, and can enable/disable the channel. Most of the time I don't bother with it and just write #$FF to it like so:
lda #$FF ; typical
sta $4000 ; write
The important bits here are #0-3 and #5, bits #0-3 (according to the doc) are the volume / envelope decay rate, I'm not sure exactly what this means so I just set all the bits. Bit #5 seems to enable and disable the channel (yes, you still need to enable the channel in $4015 for sound to come out). The others I'm assuming can be set so just send #$FF to $4000 if you don't want too much to worry about.
Register $4001 controls the sweep feature. Sweep (if you didn't know) is when the sound fades in or out.
Because we need good control over individual bits here, we'll load A in binary instead of hex.
- Bits #0-2
- control how much $4002 is shifted by to get the new frequency.
- Bit #3
- controls whether to increase or decrease frequency for sweep. (1=increase, 0=decrease).
- Bits #4-6
- control how fast the sweep runs (range is 0-7).
- Bit #7
- enables sweep, if sweep is off, the channel will output continuous tone.
So if we want a shift value of 3, the sweep to run at speed 5, increase frequency, and (of course) enable sweep, here's the code:
lda #%11011011 ; % means binary number, remember the '#' for immediate values.
sta $4001 ; immediate means "not an address, just a number".
Register $4002 is just the first 8bits of the frequency. Set it to whatever ya want, the higher the number the lower the frequency (I think).
I'll write $A5 to it (a rather low sound):
Register $4003 contains some wavelength stuff in bits #0-2, which I leave set to 2. And bits #3-7 load the down-counter (thing that tells NES when its time to shut off the sweep), with a value. I leave bits #3-7 loaded with 13.
I'm not too sure what any of the stuff in this register means, but #$AB seems to be a fairly good value to store in $4003. Code:
I'm just going to discuss register $4015 once in this "Day". $4015 controls which channels are enabled, the bit layout is as follows:
- Bit 0
- = Square Wave Channel 1
- Bit 1
- = Square Wave Channel 2
- Bit 2
- = Triangle Wave Channel 3
- Bit 3
- = Noise Channel 4
- Bit 4
- = DMC/PCM Playback Channel
- Bits 5-7
- = unused
So to turn on Square Wave Ch. 1 we go like so:
The Full Code
I think you should be able to put sample code into a skeleton code file by now, but I'll make a full code listing just because I'm way too much of a nice guy. Here it is:
.inesprg 1 .inesmap 0 .inesmir 1 .ineschr 0 ; note that we have no CHR-ROM bank in this code .bank 1 .org $FFFA .dw 0 ; no VBlank routine .dw Start .dw 0 ; we'll get to this at a later time .bank 0 .org $8000 ; note that I just copy/pasted code from the register sections Start: lda #$FF ; typical sta $4000 ; write lda #%11011011 ; % means binary number, remember the '#' for immediate values. sta $4001 ; immediate means "not an address, just a number". lda #$A5 sta $4002 lda #$AB sta $4003 lda #%00000001 sta $4015
infinite: jmp infinite
;;--- END OF CODE FILE ---;; </code>
Assemble and Listen! Note that we don't even setup the PPU because we didn't do anything graphical. The code should output a nice rising sweep.
Square Wave Channel 2
Square Wave 2 is nearly exactly the same as Square Wave 1, we won't discuss the (VERY small difference) here. Square Wave 2 uses the exact same bit layout as Square Wave 1 except for different registers at $4004-4007. Here's how the registers compare to Square Wave 1's registers:
- $4004 is same as $4000
- $4005 is same as $4001
- $4006 is same as $4002
- $4007 is same as $4003
And to turn on the channel, write a 1 to bit #2 of $4015.
Triangle Wave Channel 3
Ah, a new type of channel to discuss, I don't know the technical description of what a "Triangle Wave" is, but I'd bet it looks something like this: /\/\/\/\/\/
The features of the Triangle Wave Channel are:
- 27.3 Hz to 55.9 KHz
- analog triangle wave output (I don't know what this means)
- linear counter (Taylor's doc infers that you can make timed tones with this channel.)
The Triangle Wave Channel's registers are at $4008-$400B.
Register $4008 contains whether or not to time the tone or make it continuous and the load to the timer that .. well, does the timing.
- Bits #0-6
- is the timer load value.
- Bit 7
- enables/disables timing (1=enable)
As I haven't used the Triangle Wave Channel much yet I haven't tried this yet so this infered info should be considered *UNTESTED/POSSIBLY INACCURATE*.
Register $4009 is unused.
Register $400A is the same as $4002.
Note: I'm not sure if Triangle Wave supports sweep or not.
Register $400B is the same as $4003.
Enabling Triangle Wave Channel 3
To enable the Triangle Wave Channel, set (to 1) bit #2 in $4015.
You should be able to come up with something from that, I hope.
This Day In Review
I hope the code works for you, and that you enjoyed today's info. I'll do the noise channel in a separate Day tomorrow (it may or may not be short).
-Mike H a.k.a GbaGuy