Family BASIC noise channel

Started by zmaster18, August 25, 2015, 07:59:57 pm

Previous topic - Next topic


The PLAY command in BASIC only allows you to use the 2 square channels and the triangle channel. But how do you use the noise? I know it is done by POKEing the registers for the Famicom's Audio Processing Unit, &H400C, &H400E, and &H400F. I briefly looked at Nerdy Nights' sound tutorials but I couldn't figure it out myself. I tried writing the values to the registers but the program would just be stuck in an infinite loop or something - nothing was happening on screen (no OK message).

I know this is a simple task, how is it done? I really think that BASIC should have had some kind of control for the noise channel. I find it weird how it was left out!  ???


August 26, 2015, 12:57:53 am #1 Last Edit: April 30, 2021, 01:23:18 pm by P
Edit: Cleaned up post to make it more clear. Removed some mistakes.

The Noise Channel is controlled by CPU registers &H400C, &H400E and &H400F. Also it's enabled in &H4015. We can write to these registers using the POKE command (example program bellow). Each register has 8 bits (one byte) and each of these bits may have meaning.

To set a bit means to write 1 to it.
To clear a bit means to write 0 to it (also reset is a synonym to clear in this context).

Hexadecimal Number System
Setting or clearing certain bits in a register is easiest done by writing the value in hexadecimal (which is done with the &H prefix in BASIC). For example if we want to set all 8 bits we write &HFF because binary 11111111 is FF in hexadecimal. If we want to set the 4 higher bits but clear the 4 lower bits, we write &HF0 because binary 11110000 is F0 in hexadecimal. Modern operating systems like Windows 7 can convert between binary, decimal and hexadecimal numbers using the programmer mode of the calculator that comes with the OS.
Googling "learn hexadecimal" should be enough to find a good guide on hexadecimal numbers.

The bits are numbered from right to left 0 to 7 like so:
|||||||+- Bit 0
||||||+-- Bit 1
|||||+--- Bit 2
||||+---- Bit 3
|||+----- Bit 4
||+------ Bit 5
|+------- Bit 6
+-------- Bit 7
Bit 0 is called the least significant bit and bit 7 called the most significant bit.


   ||||+- Square Channel 1 Enable
   |||+-- Square Channel 2 Enable
   ||+--- Triangle Channel Enable
   |+---- Noise Channel Enable
   +----- DPCM Channel Enable
First we must enable the Noise channel before we can use it. Each bit in this register enables a sound channel when set and disables it when cleared. The three most significant bits (bits 7, 6 and 5) are unused, so nothing happens if we write to them (they should be 0).
Family BASIC seems to enable and disable channels before and after using them (like when executing the BEEP command).
To only enable Noise it's enough to write 8 to this register, because binary 00001000 = 8.

  ||++++- Volume (0~15, 0 = silent and 15 = max volume)
  |+----- Constant Volume (0: internal saw envelope, 1: constant volume)
  +------ Length Counter Halt (0: use length counter, 1: halt length counter)
L - Length Counter Halt
If this bit is set, the Length Counter set at &H400F will be ignored.

C - Constant Volume
If this bit is clear an internal volume envelope will be used and the Volume value will be ignored. If this bit is set, the Volume value can be controlled in software to make any kind of volume envelope (to simulate different instruments for instance).

V - Volume
Volume value 0~15. The Constant Volume needs to be set for this to be used. Volume 0 is silent and volume 15 (&HF) is the loudest. By changing this value in software over several frames we can create any kind of envelope (an envelope is the change of volume over time).

For example we can set it to:
binary 00111111 = &H3F
This means we halt the Length Counter and set volume manually to maximum.
One hexadecimal digit is one nibble (4 bits) so the rightmost (lower) digit here controls volume &H0~&HF (0~15).

|   ++++- Period (0~15)
+-------- Looped Noise Mode Flag (0: white noise, 1: looped noise)
P - Period
Period of a sound wave is the same as pitch. There's only 16 different kinds of pitches (0~F) for the Noise channel.

M - Looped Noise Mode
Looped noise mode means that the sound becomes electric/metallic (like heard in Fireman's stage music in Rockman) instead of the normal "white noise".

For example if we want pitch to be 7:
00000111 = &H07 Pitch 7 and looped noise OFF.
10000111 = &H87 Pitch 7 and looped noise ON. (see the leftmost (upper) 8/0 controls the looped noise setting)
Old model Famicoms doesn't support looped noise so these will both sound the same on those.

Length counter value for Noise Channel.
++++-+---- Length Counter Value (0~31)
This is length of sound. It will be ignored if it's disabled in &H400C (but it seems you still need to set initialize it to 0). You can control length in software by enabling and disabling the sound or using the Volume value (set to 0 to mute).
It's a 5 bit value (using the upper bits) that will count down to zero, when it reaches zero the sound will stop playing.

Example Program
This program will play a white noise until a key is pressed.
10 POKE &H4015,8
20 POKE &H400C,&H3F
30 POKE &H400E,&H03
40 POKE &H400F,0
60 POKE &H400C,&H30
Try changing the value in line 30 to &H83 and the metallic "looped noise" will be heard instead.
Try changing the value in line 20 to &H20 to hear the internal saw envelope (volume setting will be ignored in this case).
Try changing the value in line 20 to &H1F to unhalt the Length Counter and then change the value in line 40 to &HF8 to set the sound length. Now the noise will only be played for a short while instead of looping forever (you still need to press a key to end the program however).

That's the basics of the Noise channel. Play around with these registers to make noise. You could even code a drum engine for your sound engine using these registers.

I was thinking of how to make the DPCM channel work, but I wonder if it's possible. DPCM samples must be placed within &HC000 and &HDFFF to work. But that's in the ROM area so we can't store sample data there. Samples would take a good chunk of the memory anyway.