Learn Multi platform 6502 Assembly Programming... For Monsters!

Platform Specific Lessons


Platform Specific Series - Now we know the basics, lets look at the details of the platforms we're covering!
    Lesson P1 - Bitmap Functions on the BBC

Lesson P2 - Bitmap Functions on the Atari 800 / 5200

Lesson P3 - Bitmap Functions on the Apple II

Lesson P4 - Bitmap Functions on the Atari Lynx

Lesson P5 - Bitmap Functions on the PC Engine (TurboGrafx-16)

Lesson P6 - Bitmap Functions on the NES / Famicom

Lesson P7 - Bitmap Functions on the SNES / Super Famicom

Lesson P8 - Bitmap Functions on the VIC-20

Lesson P9 - Bitmap Functions on the C64

Lesson P10 - Joystick Reading on the BBC

Lesson P11 - Joystick Reading on the Atari 800 / 5200

Lesson P12 - Joystick Reading on the Apple II

Lesson P13 - Joystick Reading on the Atari Lynx

Lesson P14 - Joystick Reading on the PC Engine (TurboGrafx-16)

Lesson P15 - Joystick Reading on the NES / Famicom and SNES

Lesson P16 - Joystick Reading on the VIC-20

Lesson P17 - Palette definitions on the BBC

Lesson P18 - Palette definitions on the Atari 800 / 5200

Lesson P19 - Palette definitions on the Atari Lynx

Lesson P20 - Palette definitions on the PC Engine (TurboGrafx-16)

Lesson P21 - Palette Definitions on the NES

Lesson P22 - Palette Definitions on the SNES / Super Famicom

Lesson P22 (z80) - Sound with the SN76489 on the BBC Micro

Lesson P23 - Sound on the Atari 800 / 5200

Lesson P23 (Z80) - Sound with the 'Beeper' on the Apple II

Lesson P24 - Sound on the Atari Lynx

Lesson P25 - Sound on the PC Engine (TurboGrafx-16)

Lesson P26 - Sound on the NES / Famicom

Lesson P27 - Sound on the SNES / Super Famicom: the SPC700

Lesson P28 - Sound on the SNES / Super Famicom: Writing ChibiSound

Lesson P29 - Sound on the on the VIC-20

Lesson P30 - Sound on the C64

Lesson P31 - Hardware Sprites on the Atari 800 / 5200

Lesson P32 - Hardware sprites on the Atari Lynx

Lesson P33 - Hardware Sprites on the PC Engine (TurboGrafx-16)

Lesson P34 - Hardware Sprites on the NES / Famicom

Lesson P35 - Hardware Sprites on the SNES / Super Famicom

Lesson P36 - Hardware Sprites on the C64

Lesson P37 - Screen settings with the CRTC on the BBC Micro!

Lesson P38 - Character Block Graphics on the PET

Lesson P39 - Key reading on the PET

Lesson P40 - Sound on the PET

Lesson P41 - Multiple layers on the SNES

Lesson P42 - Color maths on the Super Nintendo

Lesson P43 - Splitscreen scrolling and Sprite 0 Hit on the NES!

Lesson P44 - The NES Zapper!


Lesson P41 - Multiple layers on the SNES
We've learned how to use a single tilemap layer in the past, but the SNES is capable of much more!

This time we'll take a look at a more complex setup, with 3 layers... 2x 16 color and 1x 4 color.

SNS_MultipleTilemaps.asm



These are the proper colors for Chibi yuurei Reida... The colors in the snes example are wrong, do not be decieved by their lies! The SNES is capable of up to 4 background layers, but only when all four are in 4 color mode.

We're using 3, allowing 2 to have 16 colors, and a third with just 4, which will give a good number of layers, with a nice set of colors!... If you want a different screen mode, it should be easy enough to tweak this example.

Setup! 3 Tilemaps are better than one!

We're going to define a screen with three layers.

We've got a 4 color layer which we won't move ( (though we could)

we've got 2 16 color layers with 'Chibiko' bitmaps (the graphic uses 4 colors, but the layer is capable of 16!)

All the graphics were created with AkuSprite Editor
We're going to need to set up our screen! First we'll define the 'pattern addresses'... we're going to use the same bitmap data for all our layers (VRAM address $2000 in words)
While all the layers can share pattern data, they need different tilemaps to define what is shown.

We define three 32x32 tilemaps, at word addresses $0000,$0400 and $0800
We need to set up our screen mode - we're using Screen mode 3, and defining all our tilemaps as using 8x8 tiles

Using our Tilemaps

We're going to need to clear all our tilemaps!

We'll create a function to zero each one.... setting all the tiles to tile zero (Vram address $2000)
We use this function to clear each tilemap separately
We need to define the tiles for our two bitmaps.

Strangely both will start from tile 128!?!

How is this possible?
Well, our tile patterns start from word address $2000, and 16 color tiles use 32 bytes per tile pattern.... so tile 128 is at address $2800,

BUT... 4 color tiles use 16 bytes per tile pattern.... so tile 128 is at address $2400...

This means we can have 'Chibiko' at 16 color tile 128+ ($2800) and 'Reida' at 4 color tile 128+ ($2400)
We're using the same 'FillAreaWithTiles' as the simple series, We just specify a 'TilemapBase' in the Zero page as the base of the tilemap we're setting.
We can scroll each layer using the registers from $210D+

Each controls the X or Y axis of a layer... each takes 2 bytes (16 bits), both bytes are written to the same port, Low byte then High byte.

Here we're just using low bytes of the 16 bit pair.


Lesson P42 - Color maths on the Super Nintendo
Last time we used 3 layers, but the SNES has some tricks up its sleeve,

We can split these layers into two groups, then use 'color maths' to achieve transparency and masking effects... lets see it in action!

SNS_MultipleTilemapsFX.asm


The effects!

We'll be trying a variety of effects today!

We split our layers into 2 screens, the 'Main screen', and the 'Sub Screen'... the resulting colors are calculated from the two plus a calculation.

Note the resulting 'calculated colors' are calculated by adding or subtracting the RGB values, not the palette entry numbers.

We've got things set up so the 2 'Chibikos' are on the 'Main Screen'. the 1 'Reida' is on the sub screen




Here we've calculated Main+Sub
The colors gets brighter where the two overlap
Here we've calculated Main-Sub
Sub is hidden, and the colors gets darker where the two overlap
Here we've calculated (Main+Sub)/2
The colors are blended (mixed) where the two overlap
Here we've calculated Main+Sub
however the sub screen maths does not apply to the background so is only visible when pixels of the other layers overlap

Using the effects

First, We need to split our layers into the Main screen and the Sub screen.

We use $212C and $212D to do this... here we've put BG1+2 on the Main screen (The 2 Chibikos) and BG3 on the Sub screen (The 1 Reida)
We use $2130 to define how the color math applies to the window (a mask we're not using) and the background color.

We only want to enable the Sub screen - via bit 2
We can configure a background color for the subscreen with $2132... we've just set it to black
all the rest of the work is done with $2131 - this selects the layers the SUB screen color maths affect,
Here we've performed Main+Sub
By setting bit 7, we can perform subtraction.
Here we've performed Main-Sub
By setting bit 6, we can divide the result by 2
Here we've performed (Main+Sub)/2
if we clear bit 5, the SUB screen does not show on the background - but still affects the BG1/BG2 layer!
Spooky!
this time we've removed bit 1 - meaning the color maths doesn't affect BG2
Here the Left chibiko is affected by color maths, but the bottom one isn't!
The Color Maths of the SNES give the SNES the ability for transparency effects that most other 16 bit systems couldn't achieve in hardware.

Color effects can also be combined with 'Windows' which can be used to mask areas of the screen. The SNES has two windows, which we'll look at another time!

Lesson P43 - Splitscreen scrolling and Sprite 0 Hit on the NES!
The NES only has one tilemap, but we can change the scroll midscreen to do a splitscreen effect.... unfortunately it's a bit tricky!

With Mapper 3 we can use a line IRQ to cause an interrupt midscreen to do the work... on other mappers, we may have to use the Sprite0Hit to detect the line.

NES_Splitscreen.asm


By the power of Mapper-3... I have the IRQ!
For reasons best known to itself, the Mapper 3 line interrupt requires the Sprite and Tile addresses to be different, we add $20 (Sprites VRam at $1000) to $80 (Vblank on) and write this to port $2000
During NMI we need to set the line interrupt up...

Here we've set it to occur on line 116... we write this to $C000

We also write any value to $C001 and $E001 to reset and start the interrupt
The IRQ handler address needs to be stored at $FFFE in your cartridge.

The interrupt handler disables the IRQ with a write to $E000 - it's reset during the next vblank
Here's the result

Hit me with your Sprite 0 Bit!

The early NES games could not do line interrupts, but there's a trick!

Bit 6 of status port $2002 will be set to 1 the FIRST TIME* a pixel of sprite 0 hits a pixel of the background... this can be used to detect the current line.

The pixel must be colored, and the sprite can be in front of, or behind the background.

Super mario uses this to keep the score still, but scroll the play area... Sprite 0 is the bottom of the 'coin' and is 'hidden' below the one drawn on the tilemap!

The Sprite0Hit does not cause an interrupt, so we need to check for it in software.

*Note... The bit does not clear until AFTER the next Vblank, so this can only be done once per screen... also note that the bit does not clear until the END of VBLANK, so if our NMI routine is short, it may end before the bit is cleared, which could cause problems if we immediately test for the bit being set again.
We're going to define two variables... We'll need to turn off the split during setup and the like - hitcheckEnabled does this.

Our 'Detection' routine will be in the main loop, but once we've found Sprite0 this line we'll stop checking, 'hitcheck' will do this
During our main loop, we'll check 'HitCheck' - If it's nonzero (%01000000), we AND this with $2002 to test the Sprite0Hit bit.

When this is nonzero we do our scroll... we then set HitCheck to zero, so we don't check again until the next frame.
During the Vblank NMI  we need to reset the HitCheck, but the Sprite0Hit bit (bit 6 of $2002) doesn't clear until the END of Vblank...  if our NMI routine is short, the mainloop may run again before it clears.

To solve this we wait for bit 6 of $2002 to clear before we return, so the Sprite0Hit flag will only be set again once the sprite is drawn.
Here is the result!



Horizontal split screen scroll

Horizontal scroll is easy, we just write two new scroll bytes to $2005.

This will set the X scroll fine, but unfortunately the Y-scroll is ignored, as the hardware only properly responds during a new screen redraw.
Here is a Horizontal scroll


Vertical split screen scroll

Vertical (or Horizontal+Vertical) scrolling is more tricky, but by calculating the 4 correct values, and writing them
The formulas for the 4 writes are:

[2006h.1st S1]=(X/256)*4 + (Y/240)*8
[2005h.2nd S2]=((Y MOD 240) AND C7h)
[2005h.1st S3]=(X AND 07h)
[2006h.2nd S4]=(X AND F8h)/8 + ((Y MOD 240) AND 38h)*4
Here is a 2 direction scroll.


As the author of these tutorials is a bit of a thicky, The formulas above were taken from the 'EveryNes' documentation!

While these tutorials are the best the author can do... Please see that far better document for more info on split screen scrolling!!!


Lesson P44 - The NES Zapper!
The NES has a Lightgun... it detects light, and is also a gun!

Let's lock and load, and learn how to zap us some chibis!

NES_Zapper.asm


This lesson assumes you know how to set tiles on the tilemap, and do hardware sprites...
or you're going to figure it out yourself... or you simply don't care how to do anything!
Check out the other NES tutorials on this site... Sorry for the extra work, but we can't explain the whole program every single tutorial!!

The Light Gun... a light sensor, a trigger and nothing else!

Lightguns are typically pretty simple... there's a light sensor at the front with a lens, and a trigger for us to shoot.

All the work has to be done by us, we have to flash parts of the screen black and white to work out what the gun is pointing at.

Super smart lightguns (Like the SNES and SMS one) can spot the exact pixel the gun is pointing at as the screen raster redraws... then NES light gun is NOT one of those!

Reading the gun is easy, we read in from the Joystick port and check two bits, one for the trigger, and one for the light sensor

7 6 5 4 3 2 1 0  Details                
Joystick port
($4016/7)
- - - F L - - -   F=Fire (1=Yes)
  L=Light (0=Yes)
Todays example is programmed for a lightgun on Port 2... you can change $4017 to $4016 if you want to use Port 1

It's been tested with the Nestopia emulator... Your mileage may vary with other emulators.

Reading the Lightgun

Here the lightgun is shown in the A register.

If we press fire bit 4 will change to 1 ($48 -> $58)

The gun reads light even when fire isn't pressed... we'll see bit 3 change to 0 ($48 -> $40)

Notice that the 'Light' bit flickers on and off when pointing at the light, this is because the 'raster beam' is constantly moving, and the screen is flickering faster than our eyes can see (and emulator emulates)
The trouble is, the lightgun is so dumb it'll detect our text, or even the lighbulb of a cheating player!... we therefore need to black the screen, Test, then illuminate the screen to check if the player's pointing at a target.

To get around this we'll test and wait for a change... in later versions we'll take the minimum value during a loop... so if any light was seen during the frame, it is 'captured' in the result.

Detecting a target has been shot

If we only have a simple "Duck hunt" style game with one or two targets, we can use a simple reading routine:

1. Wait for the trigger to be pressed.
2. Blackout the screen, and test the light sensor... if the sensor sees light the gun isn't pointed at the screen (Give up)
3. White out one of the targets - if the gun sees light the player shot the target.
4. Repeat 3 for any other sprites.
Here's our "New and improved" gun test routine.

We wait for Vblank, to ensure the screens showing what we expect.
We then scan the lightgun for a full frame, if at any point the gun saw light, we return that value in the accumulator
Here's our example code for this procedure.

This example uses the tilemap for graphics.

We show "Hit" if the player shot chibiko.

We show "Cheat" if light was seen when the screen should be black
(You can test this by 'shooting' the text)

Detecting an X,Y position of the gun

Super smart games like "Operation Wolf" are smarter than your lowly Duck hunts

When the trigger is pressed, the screen flashes white... and the game waits until the gun sees the white... counting the scanlines to work out the Y-position.

The Nes is too slow to work out the Xpos in this way, so it shows sprites along the screen until the gun sees it to get the Xpos.
We can do it too!***

Here' we're doing the same thing in the same way...

we're so smart and original!
our NMI will check the 'LightGunY'... We set this to 255 to flash the screen, and check the Ypos.


The scan involves flashing the screen, by switching the palette to one thats 'all white', we then count up, and wait until the light sensor sees the beam - That's our Y-Pos



We wait for fire to be pressed...

Then we set the LightGunY to 255, This tells the NMI to do a scan. We wait for that scan to occur.

OK, we've got our Y, but we now need to restore the proper palette!

Next we're going to scan for the X-position.... we need to black out the screen, so we turn of the background tilemap, and just use sprites.

We use a grid of 4x3 sprites to make a block... we put this on our known Ypos at the far left, and do a scan of the lightgun.

If we didn't detect a hit, we move the block to the right, and repeat until the lightgun detects a hit (we now know our Xpos) - or the block reaches the end of the screen (The gun has moved?)
*** OK we haven't actually done as good a job as OpWolf!

Notice there's two sprites moving along the screen on Opwolf?... well as soon as one of the two detects a hit, one disappears, and another test is done, so they can see which of the two was detected... they've effectively halved the scan time!

Ah well... we've been out coded!... But this example isn't so bad either!



Lesson P45 - Sound on the BBC (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

BBC_V1_ChibiSoundPro.asm
ChibiSoundPro_Test.asm


ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


The new driver is a big improvement on the old one but doesn't really deserve the PRO suffix!

It's a parody of the early 'Soundblaster Pro' sound cards, which could only do 8 bit digital sound, so weren't really of 'pro spec' either!

Sound Controller - SN76489
The Sound Chip shares a port with the keybord... Before we can send any data to the sound chip, we have to set the port to WRITE... we do this by writing 255 to address $FE43 (we only do this once)

We've covered the sound chip in the Z80 tutorials here

Once we've done that, we can write our data to $FE41 in the format below


Bits
Command Bit Details  7  6  5  4  3  2  1  0
Format Template L=Latch C=Channel T=Type XXXX=Data L C C T D D D D










Tone - Command 1/2 C=Channel L=tone Low data 1 C C 0 L L L L
Tone - Command 2/2 H= High tone data (Higher numbers = lower tone) 0 - H H H H H H
Volume C=Channel (0-2)  V=Volume (15=silent 0=max) 1 C C 1 V V V V
Noise Channel (Channel 3)  M=Noise mode (1=white) R=Rate (3=use tone 2) 1 1 1 0 - M R R


Chibisound PRO requires each channel to be capable of noise, but the SN76489 sound chip only has one noise channel.

We'll have to track the noise state for each 'virtual noise channel' and update the actual noise channel accordingly

The ChibiSound Pro driver

The BBC/SMS driver has two options which can be enabled.

SmsSimpleNoise:
The SMS/BBC has two noise options, a noise pitch of 0-2, or a noise pitch set by channel 2 (losing a tone channel). We can enable this option to avoid using tone channel 2, or sacrifice tone functionality for better noise.

SmsTranspose:
The SMS/BBC can't produce accurate low tones, we have two options, use 'off tone' ones, or transpose everything up an octave.
We need some ram to keep track of the nose state, and a lookup table for the 3 channels available to the hardware.
Our first task is to set port $FE43 to write by writing 255.

Next we check the noise bit of our passed L parameter and branch if needed
We need to set bits 5-6 of our sound parameters to a channel number.

We may be passed a channel 0-127, so we use a 4 bit lookup table to 'map' these to actual channels 0-2
The noise state may have changed, so we check the previous noise state, and see if we now need to turn it off.

If we do, we do so by setting the volume of channel 3 (noise) to 15 (silent)
if noise is on, we set the channels noise flag.
If we're using simple noise, we need to set the volume of channel 3, and the bottom two bits of the frequency setting - which can only take a value of 0-2 (3 sets it to use channel 2's frequency setting)

We're done, so we just return.
If we're using advanced noise, we need to set the frequency of channel 2, but the volume of channel 3

We set up the noise setting here - setting the rate to 3.
First we set our frequency.

The DE pair passes 16 bits, but we can only use 10, and we need to split those into 6 and 4 and send them to the hardware in two separate parts.
If we're not using simple noise, we need to set the frequency of channel 2, but the volume of channel 3

We then shift the 8 volume bits into position to pass the 4 bits to the hardware.
We also flip those bits, as on the hardware 15 is silent, and 0 is loudest.
The ChibiOctave lookup table provides matched notes which can be loaded into DE to give consistent tones across all systems.

Sharps and flats can be calculated by adding two values and dividing them by two.




Lesson P46 - Sound on the C64 (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

C64_V1_ChibiSoundPro.asm
ChibiSoundPro_Test.asm


ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


The new driver is a big improvement on the old one but doesn't really deserve the PRO suffix!

It's a parody of the early 'Soundblaster Pro' sound cards, which could only do 8 bit digital sound, so weren't really of 'pro spec' either!

SID sound chip
The SID chip uses memory addresses $D400-$D41C
Address Description Bits Meaning
$D400 Voice #1 frequency L LLLLLLLL
$D401 Voice #1 frequency H HHHHHHHH Higher values=higher pitch
$D402 Voice #1 pulse width L LLLLLLLL
$D403 Voice #1 pulse width H ----HHHH
$D404 Voice #1 control register NPST-RSG Noise / Pulse / Saw-tooth / Triangle / - test / Ring mod / Sync /Gate
$D405 Voice #1 Attack and Decay length AAAADDDD Attack / Decay (0=fastest)
$D406 Voice #1 Sustain volume and Release length. VVVVRRRR Sustain Volume / Release (0=fastest)
$D407 Voice #2 frequency L LLLLLLLL
$D408 Voice #2 frequency H HHHHHHHH Higher values=higher pitch
$D409 Voice #2 pulse width L LLLLLLLL
$D40A Voice #2 pulse width H ----HHHH
$D40B Voice #2 control register NPST-RSG Noise / Pulse / Saw-tooth / Triangle / - test / Ring mod / Sync /Gate
$D40C Voice #2 Attack and Decay length AAAADDDD Attack / Decay (0=fastest)
$D40D Voice #2 Sustain volume and Release length. VVVVRRRR Sustain Volume / Release rate (0=fastest)
$D40E Voice #3 frequency L LLLLLLLL
$D40F Voice #3 frequency H HHHHHHHH Higher values=higher pitch
$D410 Voice #3 pulse width L LLLLLLLL
$D411 Voice #3 pulse width H ----HHHH
$D412 Voice #3 control register. NPST-RSG Noise / Pulse / Saw-tooth / Triangle / - test / Ring mod / Sync /Gate
$D413 Voice #3 Attack and Decay length. AAAADDDD Attack / Decay (0=fastest)
$D414 Voice #3 Sustain volume and Release length. VVVVRRRR Sustain Volume / Release (0=fastest)
$D415 Filter cut off frequency L -----LLL Cut off frequency
$D416 Filter cut off frequency H HHHHHHHH Cut off frequency
$D417 Filter control RRRREVVV R=Resonance (0=off) / External / V= Voice 3-1
$D418 Volume and filter modes MHBLVVVV Mute3 / Highpass / Bandpass / Lowpass / Volume (0=silent)
$D41B Voice #3 waveform output. (Read only) DDDDDDDD
$D41C Voice #3 ADSR output. (Read only) DDDDDDDD


We'll only be using one kind of wave for our sounds (Pulse), as well as noise of course!

We'll use all 3 channels for our sound.

The ChibiSound Pro driver

We have 3 channels available to us, and the registers of these have bases of $D400,$D407,$D40E

We have a lookup table to select one of these depending on the passed channel number
We need to set up some sound parameters once before we use the driver.

We set the general volume to max, and some of the other parameters to zero
At the start of our setsound routine, we first select a sound register set to use for the passed channel number.

Our lookup table has 4 entries, so we read in using only the bottom two bits.

Throughout this routine the BC pair in the zero page point to the registers for the channel.
We check the Noise bit.

Frequencies for noise are very different to tones, so we bitshift the frequency a bit if noise is enabled.
We now set the frequency from the channel from D and E.

Y is used to point to the sound register we're currently changing, we go through them in order.
Next we set the Pulse length - this is needed for the pulse wave type.
We check the volume byte, if this is zero we need to silence the channel.


If the top bit of L is 1, we need to enable Noise,
Otherwise we use the Pulse tone
We set the attack and delay to zero. This makes the tone start and stop instantly.
Finally, we set the Volume.

The C64 takes a 4 bit volume, but volumes <3 are very quiet, so we only use the top two bits of the H register.




Lesson P47 - Sound on the NES (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

NES_V1_ChibiSoundPro.asm
ChibiSoundPro_Test.asm


ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


The new driver is a big improvement on the old one but doesn't really deserve the PRO suffix!

It's a parody of the early 'Soundblaster Pro' sound cards, which could only do 8 bit digital sound, so weren't really of 'pro spec' either!

The NES Sound Hardware

We'll need to use the ports $4000+ to control the sound hardware.

The ChibiTracks software want's 3 channels, so we'll use the two rectangle and triangle channels for general sound (even though it doesn't allow volume to be set), and the Noise channel when noise is required.

Address   Purpose Bits Detail
4000h APU Channel 1 (Rectangle) Volume/Decay (W) CCLEVVVV Volume, Envelope Length counter,duty Cycle
4001h APU Channel 1 (Rectangle) Sweep (W) EUUUDSSS Sweep, Direction,Upadte rate, Enabled
4002h APU Channel 1 (Rectangle) Frequency (W) LLLLLLLL frequency L byte
4003h APU Channel 1 (Rectangle) Length (W) CCCCCHHH frequency H byte, length Counter load register
4004h APU Channel 2 (Rectangle) Volume/Decay (W) CCLEVVVV Volume, Envelope Length counter,duty Cycle
4005h APU Channel 2 (Rectangle) Sweep (W) EUUUDSSS Sweep, Direction,Upadte rate, Enabled
4006h APU Channel 2 (Rectangle) Frequency (W) LLLLLLLL frequency L byte
4007h APU Channel 2 (Rectangle) Length (W) CCCCCHHH frequency H byte, length Counter load register
4008h APU Channel 3 (Triangle) Linear Counter (W) SLLLLLLL L=Linear Counter Load S=Start
4009h APU Channel 3 (Triangle) N/A (-) --------

400Ah APU Channel 3 (Triangle) Frequency (W) LLLLLLLL frequency L byte
400Bh APU Channel 3 (Triangle) Length (W) CCCCCHHH frequency H byte, length Counter load register
400Ch APU Channel 4 (Noise) Volume/Decay (W) CCLEVVVV Volume, Envelope Length counter,duty Cycle
400Dh APU Channel 4 (Noise) N/A (-)

400Eh APU Channel 4 (Noise) Frequency (W) N---FFFF N=Noise type, F=Frequency
400Fh APU Channel 4 (Noise) Length (W) CCCCC---  length Counter load register
4010h APU Channel 5 (DMC) Play mode and DMA frequency (W)

4011h APU Channel 5 (DMC) Delta counter load register (W)

4012h APU Channel 5 (DMC) Address load register (W)

4013h APU Channel 5 (DMC) Length register (W)

4014h SPR-RAM DMA Register (W) HHHHHHHH
 High byte of ram address to copy to OAM, eg $02 copies $0200-$02FF
4015h DMC/IRQ/length counter status/Sound channel enable register (RW) DF-54321 Dmc irq status / Frame irq status / Channel 12345 on (Writing resets Frequency)
4016h Joypad #1 (RW)

4017h Joypad #2/APU SOFTCLK (RW)

The channel number could be anything from 0-127, but we'll only look at the bottom 4 bits, so we'll only work with 4 'channels'
We need some lookup tables to work with the channels

The first maps the 4 virtual channels to the addresses $4000,$4004 and $4008
The second is a bitmask for the 'sound on' bits of port $4015

We only have one noise channel, but ChibisoundPro want's one for each channel, we therefore track these 'virtual noise channels' with 4 bytes of ram, so we know when to turn the actual noise off.

Finally we keep a copy of the enabled mixer channels in $4015

Before we run ChibiSound we run the Init routine 'chibisoundpro_init' which zeros this mixer cache.


When we want to set a channel, we first need to set z_bc to point to the start of the sound registers, we set this pair to $4000/4/8 from the Channelmask lookup,

We also load X with the mask for the channel bit in the mixer of $4015
Next we check if we need to turn on the noise (bit 7 of L)

If we need noise on, we set the flag for the 'virtual channel' to something nonzero (so we can simulate 3/4 noise channels)

We then need to set the volume of channel 4, and the frequency of $400E and the counter of $400F
If we're not using noise, we check the noise flag. If noise was previously on, then we need to turn it off and clear the flag.
Now we need to set the tone!
First we set the volume for the channel, and turn it on - we need to do this before we set the frequency.

We then shift our 16 bits of z_de into 10 bits. and set the frequency of $4003/2 or equivalent
To silence a channel, we clear it's bit of port $4015

To sound a channel, we set it's bit of port $4015
When we want to set the volume we set the $4000/4 register using the top 4 bits of H

If the volume is zero, we silence the channel.

The Triangle channel doesn't actually have a volume, and we need to adjust the frequency, so we have a special routine for that
The triangle routine sets the linear counter of the triangle channel, and tweaks the frequency in DE, as the triangle channel is very different in pitch!
As it's using the triangle wave, The 3rd channel probably won't sound the same as the first two.
On the CPC, channel 1 is the Center channel, and 2/3 are Left/Right panned.
As there's no guarantee how many channels there are, The rule of thumb is that in ChibiTracks, you should use Channel 1 first as your main music, 2 second, and 3 only if 1 and 2 are doing something else.
The author of these tutorials always uses channel 1 for the main theme, 2 for accompanying music, and 3 for Drum sounds and other very minor sfx.






Lesson P48 - Sound on the PC Engine (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

PCE_V1_ChibiSoundPro.asm
ChibiSoundPro_Test.asm

ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


The new driver is a big improvement on the old one but doesn't really deserve the PRO suffix!

It's a parody of the early 'Soundblaster Pro' sound cards, which could only do 8 bit digital sound, so weren't really of 'pro spec' either!

The PC Engine Sound Hardware

The PC Engine PSG has 6 wave based sound channels... each one uses 32 wave samples, of 5 bits each.
We have to snd some commands to $0804 to tell the PSG we're going to write data.. then send the data to $0806
We also need to set the volumes correctly.

The PSG is controlled by 10 registers... first a channel should be selected with Register 0... Channels are numbered 0-5 (written 1-6 in the manuals)

Reg Address Meaning Channels 7 6 5 4 3 2 1 0 Bit Meaning
0 $0800 Channel Select All - - - - - C C C Channel Select
1 $0801 Main Amplitude Level All L L L L R R R R L/R Volume
2 $0802 Frequency L 0-5 L L L L L L L L
3 $0803 Frequency H 0-5 - - - - H H H H
4 $0804 Channel On/Write 0-5 E D - V V V V V Enable/data addr... reset or DirectDA� Volume
5 $0805 LR Volume 0-5 L L L L R R R R L/R Volume
6 $0806 Waveform Data 0-5 - - - W W W W W Wave data (write 32 times)
7 $0807 Noise Enable 4-5 E - - N N N N N Enable noise� Noise freq
8 $0808 LFO Freq All F F F F F F F F lfo Frequency
9 $0809 LFO Control All T - - - - - C C lfo Trigger� Control


We're going to use channels 0-3 as tone channels, and channel 4 as for Noise.

We'll detect when the driver is told to turn a noise channel on, and 'redirect' it to channel 4.

The Chibisound Pro driver

Before we can use Chibisound we need to set up the channels.
We set the main volume level to the maximum with port $0801

Next we set up all the channels using X as a channel number. We select the channel with port $0800
We set each channel's Left/Right volume to max with port $0805, but we set the channel to silent with $0804

We need to define a wave sample or we'll hear no sound - it has 32 5 bit samples, We set half of these to %00011111, and half to %00000000 - effectively a square wave.
As we only use channel 4 for noise, We need a few bytes of memory (4) to keep track of the virtual noise channels

We only use the bottom two bits of the channel number (L), so we only work with channels 0-3



if the top bit of L is one, we need to turn on the noise.

In this case, we need to flag this channel as having the noise on.... we also need to silence the tone channel, then select channel 4 as the actual recipient of the frequency and volume settings.
If the noise is now off, we check what the previous state was.

If the noise was on, but is now off, we need to silence channel 4, and turn off the noise
We select the channel number with port $0800

We need to set the volume level. We are provided an 8 bit volume in H, we need a 5 bit volume for port $8004 - we also need to set the top 'enable' bit to one.
We set the 5 bit frequency setting for noise with port $0807, but only enable it if the top bit of L is one.
Finally we set the 12 bit tone pitch, we use port $0802 and $0803 for this.

The frequencies are the opposite of what we want, so we flip the bits of the DE pair after shifting them to the correct bit position

We've now done everything to set the tone
We have a lookup table to define the notes of the octave, we can calculate sharps or flats by taking two tones, and dividing them by two.





Lesson P49 - Sound on the Commodore PET (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

PET_V1_ChibiSoundPro.asm
ChibiSoundPro_Test.asm

ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


The new driver is a big improvement on the old one but doesn't really deserve the PRO suffix!

It's a parody of the early 'Soundblaster Pro' sound cards, which could only do 8 bit digital sound, so weren't really of 'pro spec' either!

PET Sound

The PET did not have any built in sound, but a speaker can be connected to the IO port.

The PET is capable of up to 4 octaves... one of 3 possible pairs can be selected with $E84A

Address $E84B will turn the sound on or off... we write #16 to turn it on, #0 to turn it off.
Address $E84A can be used to select the Octave with value 15/51/85
Address $E848 can be used to select the note, a value of 64-255 should be passed.

It is not possible to set the volume, or play multiple tones at the same time.

Note Freq octave=15 octave=51 octave=85
Octave 0 Octave 1 Octave 1 Octave 2 Octave 2 Octave 3
B 251 125 251 125 251 125
C 238 118 238 118 238 118
C# 224 110 224 110 224 110
D 210 104 210 104 210 104
D# 199 99 199 99 199 99
E 188 93 188 93 188 93
F 177 88 177 88 177 88
F# 168 83 168 83 168 83
G 158 78 158 78 158 78
G# 149 74 149 74 149 74
A 140 69 140 69 140 69
A# 133 65 133 65 133 65
(Sound info taken from the PetFaq)

The Pet can't really do noise... or volume... or multiple channels... or a wide range of octaves (only 4!)...

Uh... well, we'll do the best we can!

The Chibisound Pro driver

Our music software wants at least 3 channels, but we only have 1... what to do??

One option would be to ignore all but channel 1....

The other is to remember what all 3 channels want to play, then play the loudest one... That's what we'll do!

Here we take the request, and store it's settings in a 'virtual channel' for later (4 in total).


The 'Update' Procedure will step through the 4 virtual channels, find the loudest and load it's settings into the 4 zero page entries.

First we need to turn sound ON or OFF with port $E84B

We can't do volume levels, so if our volume is <15 we'll treat it as off and write 0, otherwise we'll turn it on by writing 16
We need to set the octave, we do this with port $E84A.

We look at the top bit of our DE pair, if it's 0 we'll use Octave 0/1 by writing #15 ... if it's 1 we'll use Octave 2/3 by writing #85
We need to write a tone value to $E848, the value should be in the range 64-255

To achive this we take the bottom 7 bits of D, add 64, and add half of D.

We write this value to port $E848... and we're done!
We have a lookup table to define the notes of the octave, we can calculate sharps or flats by taking two tones, and dividing them by two.





Lesson P50 - Sound on the VIC-20 (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

VIC_V1_ChibiSoundPro.asm

ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


The new driver is a big improvement on the old one but doesn't really deserve the PRO suffix!

It's a parody of the early 'Soundblaster Pro' sound cards, which could only do 8 bit digital sound, so weren't really of 'pro spec' either!

VIC Sound

There are 3 sound channels for the 3 different frequencies, one for random noise, and a volume setting...
As well as volume The top 4 bits of the $900E also handles color

Address Meaning Bits Details
$900A Frequency for oscillator 1 (Bass) OFFFFFFF O=On F=Frequency
$900B Frequency for oscillator 2 (medium) OFFFFFFF O=On F=Frequency
$900C Frequency for oscillator 3 (high freq) OFFFFFFF O=On F=Frequency
$900D Frequency of noise source OFFFFFFF O=On F=Frequency
$900E Volume of all sound / Auxiliary color information CCCCVVVV V=Volume C=Aux color


We'll need to use all 3 oscillators to get the widest range of tones possible, but while octave $900B has a partial overlap with the octaves of $900A/C, we won't try to use it to play a second tone, as this would be hard to do consistently, so we'll only play one tone at a time.

The Chibisound Pro driver

Our music software wants at least 3 channels, but we only have 1... what to do??

One option would be to ignore all but channel 1....

The other is to remember what all 3 channels want to play, then play the loudest one... That's what we'll do!

We also need an octave lookup, with the bottom byte of the sound register addresses ($900A/B/C)

We need to clear the cache before we start








Here we take the request, and store it's settings in a 'virtual channel' for later (4 in total).

If the noise is now off, we need to check if it was on before... if it was we'll silence the nosie now.
The 'Update' Procedure will step through the 4 virtual channels, find the loudest and load it's settings into the 4 zero page entries.

We set BC to $9000... we'll use Y to specify an offset to specify the actual channel we want to use.

First, We silence all the channels
We need to set the volume, we do this with $900E

It only takes a 4 bit volume level
If the noise is on, we need to set the 7 bit frequency with port $900D

Once we have, we're done!
We use the top 3 pitch bits to calculate an address in the lookup table.

Each entry has two bytes



We need to convert the remaining pitch bits for the selected octave.

As the octave goes up, we need to halve the frequency to get an 'equal' tone.

We send this to the port number of the chosen octave.
We have a lookup table to define the notes of the octave, we can calculate sharps or flats by taking two tones, and dividing them by two.