In recent months, between the new posts, I have been posting update versions of content previously published on my Patreon. This one is slightly different as I have effectively recreated the Patreon post using some new kit. More info on that later, but I will hand you over to past me writing on Patreon.....
I have been writing a few games for the Commodore PET / Mini PET recently, and I wanted to add sound to them.
The PET has a 1 bit sound output, A piezo transducer which can be set as on or off. To create sounds, you turn it on and off quickly.
And that's the end of today's post. Goodbye.
OK, so maybe you want some more detail. I couldn't find much information on how exactly to achieve the "turn it on and off quickly" bit, so I thought I would document what I worked out.
Back in the days of the first PETs (to be precise, all the 9" non-CRTC PETs), the PET didn't have any built in sound capability. Games like Space Invaders benefited greatly from sound, so the PET implementation contained instructions on how to wire up a speaker to your PET so that when you hit an alien you heard the noise.
The idea is basically taking the output from the CB2 pin on the user port and feeding it to an audio amplifier. This concept was taken onboard by Commodore when they produced the 12" CRTC Based CBM machines (which we all still call PETs anyway - see a future post for the long and detailed story behind that).
Here they took the CB2 output but also ANDed it with the DIAG pin on the user port, PA7 on the keyboard PIA. This is the pin that should be pulled low to activate the machine code monitor on boot. Not quite sure why they did that, it means you can drive the speaker from two different outputs, so I suppose you could technically have two voices or create some kind of tremelo effect?
For the Mini PET, I wired up a piezo transducer to the same signals.
Whilst the diag pin is an option, I will concentrate on the CB2 pin, as this will also work on any PETs adapted as per the Space Invaders instructions.
Method one - bit bashing
One way to make sounds is to turn the CB2 pin on and off quickly. CB2 is designed for handshaking, so it needs to be driven differently to a normal IO PIN.
The VIA PCR (Peripheral Control Register) is at address 0xE84C (59468). This controls 4 pins, CA1, CA2, CB1 and CB2.
CA1 and CB1 are input only, and can't even be read directly, all they can do is trigger an interrupt. CA2 is used to control the video character set, low is uppercase / graphics, high is lowercase / uppercase. Any changes made to that register need to keep these other settings intact.
The values for normal operation are 0xCC (204) for off, 0xEC (236) for on. The first thing to tryis a simple BASIC program.
However, that's not particularly fast, and the output is switching at just under 50Hz. Congratulations you have created a mains hum simulator. Take the rest of the day off.
Here it is interesting to look at some of the speed improvements you can get by optimising the simple BASIC program.
I thought putting everything on a single line might make any difference, but it didn't, so lets try a few more tricks. Here I am using abbreviated commands and assigning a variable to the address being POKEd at.
That's more like it. 100Hz, double what we previously achieved.
I next tried using variables for the two POKEd values as well.
Again a doubling in speed, now 200Hz.
That is still only 200Hz, a low, annoying hum. To create something more tuneful, we need to look to assembly language. I've been doing a lot of 6502 coding recently, so I just typed this in, but it probably needs more explanation.
This is a listing of the same code (looks like I got it right)
I picked 1000 as the base address as that is normally free, but the code could have been based anywhere. This does the same thing as the BASIC program, POKE one value, POKE the other value, go back to the start. Only in assembler, it does it a whole lot faster.
This is now 66.7KHz, well outside of my hearing range. To make it audible, all it needs is a delay between the on and off pulses.
Using the simplest delay loops counting to 256 gets that down to around 400Hz, so you can see it's just a case of fine tuning the delay values to get around the tone you want.
There are a few problems with this. Firstly, it ties up the processor in loops and also, you can might just be able to make out some of the gaps are slightly longer than the others. This is more obvious on the higher frequency version without the delay. These are caused by the system timer interrupts, and you can actually change the tone of the sound by pressing keys (which extends the interrupt slightly).
Zooming in on the gap, the interrupt routine lasts around 640uS, during which time, there is no sound output. So this approach is not really viable in practice.
Method Two - Shift Register
Using the CB2 pin for sound wasn't just an arbitrary choice of an available I/O pin. The other thing the CB2 pin has going for it is that it can be configured as a shift register output, which will shift out at a speed determined by a counter running directly from the system clock. This has the advantage that it doesn't tie up the processor, and is not disrupted by interrupts.
This is controlled by three registers, the first of which is the ACR (Auxiliary Control Register) at 0xE84B (59467).
The option we want here is "shift out free running at T2 rate". So the ACR is set to 0x10.
The second register is the shift register value, at 0xE84A (59466). This controls what bits get sent to the port. The three most useful values here are:
- 0x0F - 00001111
- 0x33 - 00110011
- 0x55 - 01010101
You can also use the inverse of those (0xF0, 0xCC or 0xAA). Other values (such as 0x01, 0x03 etc. will alter the mark space ratio of the output pulse and produce a less pure note (which may be what you want).
If you think about it as they are drawing the output waveform, so the output is high when there are 1s, and low with 0s. So, the way they are shifted out, 0x33 will look the same as 0x0F if shifted out twice as fast. So shift is set to 0x0F.
The final register is the lower byte of timer T2 in the VIA chip. This controls how long it is before the next bit is shifted out. The high the value, the lower the note.
This note will continue to play as you get on with other things, so it can all be controlled from BASIC. The final POKE 59467,0 turns off the shift register output.
As an example, 0xEE will cause bits to be shifted out so that 8 bits takes 3.84mS. With the 0x0F pattern in the shift register, that forms 4 lows and 4 highs, which creates a square wave of 260Hz, which is almost the 261 Hz of middle C.
If I try to mark out the byte that is being shifted out, you can see the 00001111 of 0x0F.
If I leave everything else the same, but change the shift register to output 0x33 instead of 0x0F, the frequency is doubled to 520Hz (C5).
And again, changing it to 0x55, we get C6.
So that is that's all there is to it. The counter value sets the note, and the shift register pattern sets the octave. (or rather, the lowest octave - you can get about three octaves from each setting with different counter values)
So what was all this for?
Well, I have been working on an adaptation of David Stephenson's Tut-Tut. That was originally written for the ZX Spectrum (as a type in listing in Paleotronic magazine - https://paleotronic.com/2019/11/05/tut-tut-a-new-game-for-the-zx-spectrum/), and then for ZX81 (https://www.zx81keyboardadventure.com/2019/10/zx81-game-tut-tut.html) and then an improved ZX Spectrum version (https://www.zx81keyboardadventure.com/2020/04/zx-spectrum-game-tut-tut-2020-ed.html) and finally a port for the Jupiter Ace / Minstrel 4th (https://www.zx81keyboardadventure.com/2020/05/tut-tut-on-jupiter-ace-part-1.html).
This is a great game, reminds me of my old favourite Repton.
The ZX Spectrum versions had a little tune (almost, but not quite, entirely unlike "Walk like an Egyptian"). In the Spectrum version, this was done as a series of BEEP commands, with a parameter selecting the full or brief version:
if ubFull then
beep .25,-2 : beep .125,8 : beep .125,5 : beep .25,5 : beep .25,-2 : beep .25,5
beep .25,-2 : beep .125,3 : beep .125,3 : beep .25,8 : beep .125,-2 : beep .125,-2
Beep takes two values, a duration in seconds, and a note with middle C being 0.
- -2 = A#
- 0 = C4
- 3 = D#4
- 5 = F4
- 8 = G#4
I had the mechanism to play the notes, just needed to set the duration. That wasn't too critical, so I just used a simple counter.
I added a 5mS gap between notes as that was what the Spectrum was producing.
And there was the finished song, and it sounds just like the Spectrum. (side note, I had to cheat as I couldn't quite get the A#3 note, but it's closer to that than B3.
But Dave, you said a couple of games?
Yes, well, I did try to add sound to my remake of 3D Monster Maze from the ZX81.
I tried to do the sound of footsteps and also tried a sort of Jaws type sting, but both ended up quite low notes, and sounded comically awful on the tinny piezo speaker in a PET, so it remains true to the original, silent. All you can here are the tormented screams of the player.
If you just want to play "music", or makes some noise, have a look at PET Synth,
The website has gone, but here is an archived link:
See also this video by Sam at Look Mum, No Computer, who built a Mini PET kit and then had a go at circuit bending it. See also most of the other videos on the channel if you like unusual ways of making electronic music.
A big thank you to Keysight who have generously donated the oscilloscope I used to get the screenshots in this post.
There will be a full review on this once I learn how to use more of it, but so far it is doing an excellent job. Expect to see a lot more screenshots in future posts as these are so much better than my previous attempts to take photos of my 30 year old CRT scope.
(N.B. yes there is a plastic keycap stuck over the speaker with a bit of blu tak. Most of the tones I was producing today were not the most pleasant to listen to.)
The Mini PET 40/80 kits to build a PET like the one I used in this article have now all sold out, but there are still some Mini PET 40/80D pre-assembled drop in replacement PET boards available from The Future Was 8 bit:
You can see that board and these games being played on this video by The 8 bit Guy
Tut-Tut and 3D Monster Maze are available on cassette from The Future Was 8 bit:
Or digital downloads from my itch.io store
The original version of this posts and many other advance previews and behind the scenes progress on new projects, can be found on my Patreon. I am very grateful for the support I have received from my Patreons over the last few years. If you would like to support me, here is the link:
I know very little about music, so I may have all got the terms wrong, please forgive me.