Как стать автором
Обновить

Music on the Commodore PET and the Faulty Robots

Время на прочтение26 мин
Количество просмотров2.9K

After completion of the System Beeps, I wasn’t planning to make another stand alone album release with the pseudo polyphonic music, as I felt the topic had been explored enough. This, however, wouldn’t mean I couldn’t apply the experience and skills gained to make more utilitarian stuff, like an actual retro game OST or an old school demoscene project. Such an opportunity arose in Autumn 2020, as David Murray of The 8-bit Guy Youtube channel fame announced his new game to be in development, the Attack of The PETSCII Robots for Commodore PET and some other Commodore 8-bitters. As I previously worked with David on his previous big release, Planet X3 game for MS-DOS, and this was a perfect opportunity to satisfy my interest towards the pre-graphics era PCs as well as apply my vast experience both in the minimalistic computer music and 6502 assembly programming, I offered my services that had been accepted. Besides the sound code I also had hopes to participate as a music composer this time.

Unfortunately, this time the project didn’t went well on my side, and lots of issues of all kinds eventually turned it into a small scale development hell (you can learn more from a series of posts at my Patreon blog)  The end result was that my code and sound effects were only used in the VIC-20 port, and music for other versions has been created by other people. However, I was left with the full working code of the sound system for PET, and a number of music sketches. It would be a pity to file it into the archive, PET projects aren’t a frequent thing these days, so another chance to use the stuff wouldn’t come any time soon. So I got the idea to develop my music sketches into full songs, and release it as an alternative OST, and having David’s approval it has been done and released in the Winter 2021 as Faulty Robots, a small music album for PET that is available as a digital audio release and a runnable program for the actual PET computer.

You can hear and see the whole thing in the action in the video below. The following article tells the story full of epic wins over numerous difficulties on the thorny path to this weird music release.

The Music

This time I decided that good things should come in a small package, thus I limited the ear torture session with just eight short songs. In fact, their length had been severely limited by the technical constraints described below. This resulted in a total play time of 13 minutes.

The core album concept is a deconstruction, an alternative perspective on the game’s contents, the hardship of the robots from the game story, as well as the development difficulties of the project itself. A word to describe it is minimalism. Highbrow aside, something is making beeps to some to love, and some to hate.

A few words about the creative process behind each of the songs, and how the entangled creative mess straightens up into the well ordered structure of the final release.

Faulty Robots — has been envisioned as the title screen song, the melody there is based on chanting the title. It was one of the first sketches, developed up to the second verse. It has got a bridge and the second verse in the finished version.

Rusty Gears — the first fully finished track that has been composed to test out and show up the sound system capabilities. David and I considered it to be difficult to follow and not really match the game stylistically, so we didn’t plan to include it into the game. Has been altered a bit for the album release.

Conveyor Belt — was planned to be a short loop on the level stats screen, when you beat or lose a level. For the album version I added the second verse with the arpeggio starting from the bridge and then running as a counterpoint to the main melody.

Old Model — has been created just about before it became clear that I won’t be making music for the game. So it was changed from an uneventful background music for the gameplay into a song with more melodic content.

Crosswired — the first proposal for the in-game music. It had to be arranged with lots of air, the pauses between the notes, so sound effects would cut through it easily, and it had to be as lengthy as possible considering the memory limitations, to not be much annoying after numerous repeated plays. I was afraid that it lacks melodic content too much, so it won’t be enough for a stand-alone music release, but in fact some album listeners highlighted this one as theirs favorite.

Scraplord — started its life as a riff to serve as a base for one of the in-game songs. It was pretty difficult to figure out how to turn it into a full blown song. Unlike most of the other songs that have been directly written down from the head into the tracker, I had to do this one by improvising on the keyboard, recording it in Reaper, then cutting the best parts together into a single melody.

Bosstown Dynamics — the very last track that has been composed specifically for the album, to make the eight songs total. The work on the melodic part wasn’t going smoothly again, so it also has been cut together from the best parts of improvised pieces. The title is a nod to the Corridor viral videos.

Not Obsolete — interestingly it started as the very first test of the sound engine, just a mere pattern with a few random notes. When I got the track counts up to six, I wanted to add two more to make it (binary) even. So I just added some waveform changes, and as it happens sometimes, it kinda developed its true shape hidden within, so I just had to carve it out, and it made a bit of a sad but affirmative finale. The title is a quote of the world’s most famous cyborg from an unnecessary follow-up.

As the songs were initially intended to be used in a game, they were all seamlessly looped. Once all tracks were done and the player shell programmed, I felt it needed a more definitive conclusion, so I added an extremely basic coda to each of the songs, basically just a couple notes here and there.

In conclusion, I personally like the end result more than the previous one, System Beeps. In both cases I was trying to move away from a much limited but kinda typical chiptune music into the aesthetics of old computers that make their beeping randomly, and that somehow develops into a defined melody. I think I was able to get closer to that feeling this time.

History Reference

While the artsy creative portion of the album mostly appeals to the relatively small community of chiptune fans, the technical portion may have an interest for a wider group of the retro computing enthusiasts.

It should be noted that Commodore computers were mostly absent here, in Russia. Back in late 1980s when home computers started to be more affordable, they were mostly presented with obscure i8080-based Soviet stuff and ZX Spectrum clones, and US or Japanese made computers were a major rarity - if anything, that would be presented with Atari 8-bit and MSX families at best. Unlike the rest of the world, C64 and especially everything prior to it was virtually unknown, besides maybe brief mentions in the books. The situation only changed a bit in the late 90s when second hand Amigas became available, they got their following, but of course it lost the market to much more affordable IBM PC compatibles. So Commodore PET is a total obscurity here.

I don’t have to get into the PET history for the readers from the rest of the world, as it is more or less known there. I’ll just say that it is one of the earliest (1977) fully featured personal computers, complete with its own CPU, display, keyboard, and everything else, as well as one of the first successful mass market computers of this kind. It can barely be defined as a home computer, and it is certainly not designed for video games. It lacks any graphics capabilities, just 40x25 or 80x25 monochrome text mode with a fixed character set that features some pseudographic symbols. First models came without any sound capabilities at all, later ones got a simple speaker added to make system beeps. You likely won’t find a less suitable platform for a computer musician, yet it makes it the more appealing challenge to overcome.

Personal computers of such an early era, when the whole format of such devices has been just getting established, often have lots of personality, and PET is one of the most peculiar. It has a bright retro futuristic appearance, it features a very distinct pseudographic character set called PETSCII, it has an all rectangular keyboard that lacks the now obligatory top row with the numbers, and that offers only two keys to control the cursor movements. It hides even more funny quirks under the hood. Like, when BASIC’s PEEK can only read the RAM under 49152, because the BASIC ROM is located above, and presumably this limitation has been put to prevent users from reading the ROM contents. One of such special quirks of the system was the unusual approach to the sound hardware as well.

There are three common approaches to the sound hardware in the computers of the past.

The sound hardware of the most budget computers is often presented with just a single bit I/O line that is connected directly to the sound speaker. The CPU has to toggle this output bit on and off using carefully timed code to produce a tone of the desired frequency. This normally takes a major chunk of the CPU performance, if not the whole time, to produce the sound, and does not allow running anything else in the background while the sound is playing. In other words, if a game or a program needs to play a music or a sound effect, any screen activity should stop.

Home computers designed to run video games were using the opposite approach, employing relatively complex custom hardware such as sound chips that are specifically aimed to generate multichannel sound in the background. Having a dedicated sound chip allows it to play sounds without stopping the action, the CPU only needs to pass the sound parameters to the sound chip from time to time.

The business targeted machines, and PET can be seen as one of these, were using something in between of these two extremes. They often had a solution similar to the famous PC Speaker of the IBM PC/XT fame - a sound speaker driven by a programmable timer chip, such as the i8255. It can produce simple beeps without stopping the other activity, but the sound capabilities are normally limited to just a single channel of basic square wave.

The Sound Customs

The early PET 30xx models lacked any sound capabilities, neither they had a dedicated sound hardware, nor a built-in speaker. The platform enthusiasts weren’t happy with this, so they came up with a very simple modification that allowed them to produce some sound. This modification has been adopted by Commodore, and implemented in the following, more widespread PET models 40xx and 80xx.

PET uses a MOS 6522 chip, also known as VIA (Versatile Interface Adapter) to communicate with the peripherals. It is a multi-function chip that provides a couple of parallel I/O ports and a very rudimentary serial I/O port. The serial port support is presented with a 8-bit shift register and two programmable timers. It was the software duty to utilize these resources to implement an actual serial interface protocol.

When the PET enthusiasts were adding the sound speaker to the early PET models, they went with quite an original route. One would expect they would use a PIO line, which is a common and simple solution. However, they used the CB2 line, that is the output of the shift register of the serial interface. One of the 6522 timers defines the shift frequency, so if you load the alternating bit pattern such as %11110000 there, you’ll get the square wave, leaving the CPU to do other things. This design kinda looks like the PC Speaker, however, it has more limitations, and an advantage in a way.

The main limitation is the frequency range. The counter of the timer that clocks the shift register is only 8-bit wide. The 6522 clock frequency of 500 kHz gets divided by the programmed 8-bit value (1..255), then by the number of the bits in the shift register, i.e. 8. With %11110000 loaded to the shift register the lowest available frequency would be 500000/8/255, which is about 245 Hz. The shift register could be loaded with %11001100 or %10101010 bit patterns even, however, that would only multiply the resulting frequency by 2 or 4. This means the lowest possible note you can get with the 6522 generated sound is somewhere near the B-3. That omits the whole bass range that is the staple of nearly all modern music, and the pitch of the higher notes gets far from the perfect tuning. This makes it very difficult to make any music that is pleasant for the ear.

The advantage of the MOS 6522 in sound generation is that the shift register can be loaded with any other bit pattern as well, which allows it to have a richer sound variety, not limited to just the classic 50% square wave. In addition, it can generate IRQs using the second, 16-bit timer, as well as at the end of a full shift cycle. The latter allows us to overcome the hardware limitations with software tricks.

During the commercial life of the PET, programming books weren’t going into deep details, mostly providing a table of the three octave range for the two 6522 registers that controls the shift register contents and the 8-bit timer divider. The insufficiency of the information on the serial interface part even has been explicitly acknowledged in one of editions of the original 6522 datasheet. There were a few exceptions, some books did mention the possibilities of improving the sound by using the IRQ to reload the shift register ever so often, or by connecting an external DAC to the parallel port (much like the Covox). However, as the home computer market was progressing rapidly, and PET wasn’t a gaming or home machine to begin with, so there was not much support from the big software development companies, PET became an obsolete artifact way before these ideas were properly explored and used by the not so large community of the PET enthusiasts.

As the result, the better PET games and other software was sounding mostly like this:

Decades later, in the modern time the proposed techniques were explored and employed in the demoscene productions, and pretty amazing results have been achieved. Some are certainly much more impressive than my work that I’m describing here, however, they require nearly the whole CPU time and lots of RAM, which makes them not much applicable to the games. Here is an example:

A Brief History of Failure

Getting started with the project I had a vague idea of the PET architecture, distorted with the previous experience with similar machines, such as Robotron 1715 (a i8080 based text only business machine) - I expected it to have the basic speaker controlled with one I/O line, and sound to be produced with a well timed code. So I envisioned the sound for the game much along the lines of ZX Spectrum 48K or Apple II games - software synthesized sound effects and music pieces that stops the action.

I have a vast background with lots of prior work of this kind that has been used in literally hundreds of retro games created in the past decade. So I expected that I could just adapt it to the PET, and the job would be done quickly and easily. However, soon it turned out that David’s vision is much different, he would like to have a solution much similar to the PC Speaker sound in MS-DOS games - a single channel sound produced by the 6522’s CB2 and played simultaneously with the gameplay, without interrupting it and without taking much CPU time.

The original plan was supposed to have versions of the sound code for Commodore VIC-20, Commodore 64, and eventually Commodore Plus/4. All of these have much more advanced and sound capabilities, full of pretty unique limitations that are only specific for a particular platform. The sound system had to be developed with all of this specific consideration and even it out somehow. The original plan also considered that the exact same sound data would be shared between all the platforms. The PET was considered the primary platform, setting the main limitations, while other versions for the rest of the platforms just had to recreate a similar sound, just with polyphony and minor improvements added on the top.

Another key requirement that affected the system design a lot was the need to save as much memory as possible, because it was severely limited in the VIC-20 version. Both the sound code, and the sound and music data had to be as compact as possible. This automatically would put the limitation on the code and music format complexity, further limiting its capabilities, and ultimately the complexity of the music arrangements. There was just 2.5K or RAM for the whole sound code, all sound effects, and a single reloadable music track. That’s about 2.5 times less than usual. This was the reason that support of the most advanced features of more capable platforms, such as SID waveforms and the filter, was not considered from the beginning - it would take a much more complex format and sound code that would take more RAM.

Yet another specific requirement was the black box style code integration. This means that the sound code wouldn’t be included as the assembly code source into the main program. It rather had to be a loadable separately compiled binary that would communicate with the game code through commands passed via assigned RAM location, rather than the usual jump table approach. This idea was kinda weird to be used in a single CPU architecture (it is a commonplace in multi CPU architectures such as Genesis and SNES), so it didn’t work well in the end.

In the middle of the development process a major priorities shift happened. It has been decided to exclude the music from the PET version altogether, because of the technical difficulties that arose during the development and slowed it down considerably, and because the built-in speaker is just too quiet. The VIC-20 version has been promoted as the primary one, which now would take a much different sound system design. The C64 version got the improved graphics and a totally different sound content with the SID music, up to the common C64 standards, being composed by Noelle using the player from goattracker.

This grand plan with many specific goals and changing priorities ultimately turned into a major failure on my end. Eventually the code that was meeting the requirements has been finished and debugged, a way to produce sound content has been created, all sound effects made, and some of the music has been sketched out, too. It all was working fine in separate test programs that were running in VICE and MAME emulators. However, these tests failed to run properly on David's side, both in the very same emulators and on the real hardware, for an unknown reason. It didn’t work being integrated into the actual game as well. All the deadlines were missed, so there was no time to figure out this mystery, and being put into an awkward position, David had to take a decision to release the first batch of the PET version copies without the sound at all, then implement his own sound code for the PET. As a result, the only version of the game that still featured some of my sound code, sound effects, and a test song, was the VIC-20 one.

Pushing The Limits

The first issue to be solved was the issue with generating the low frequency sounds on the PET. David wouldn’t consider this a problem, but I was sure it is important. I just couldn’t imagine how it is possible to compose the high pitched in-game music without a bass section that wouldn’t get extremely annoying after a few seconds.

As 245 Hz is pretty low, I leaned towards this solution: sounds above 245 Hz would be generated via the regular 6522 means, and for sounds below I would run a software emulation of the 6522 shift register on the IRQ from the second, 16-bit timer. The worst case scenario would be 5 IRQs per TV frame, so it shouldn’t hit the CPU performance too much.

David didn’t like the idea much, as he was worrying it may hurt the performance and be a potential source of trouble in the debug - it turned out to be not too far from the truth. Nevertheless, I implemented  a simple test to the idea, and it worked for the most part, although one major issue had been exposed.

Just like any other 6502-based platform, PET has its IRQ vector located in the ROM. To allow the user to set up his own IRQ handler, a technique known as trampoline is employed - the default IRQ handler optionally calls a custom one whose address is placed to a location in the RAM. It seems, though, that PET firmware developers didn’t take this possibility seriously, as not many were programming the system at the low level. So the trampoline implementation there is quite inefficient - it does not pass the control to the custom handler right away, it rather puts all the CPU registers to the stack first. The code in question looks like this:

; Main IRQ Entry Point

E442        PHA
E443        TXA
E444        PHA
E445        TYA
E446        PHA
E447        TSX
E448        LDA $0104,X
E44B        AND #$10
E44D        BEQ $E452
E44F        JMP ($0092)    ; Vector: BRK Instr. Interrupt
E452        JMP ($0090)    ; Vector: Hardware Interrupt

$0090 is the user IRQ vector that is stored in the Zero Page. This location is different between the BASIC ROM versions, so a program must detect the ROM version first, then use the corresponding location. The vector is set to the standard BASIC interrupt handler by default, it polls the keyboard and updates the system clock. So I had to call it back at the original rate in my custom IRQ handler too, to keep the keyboard and time count working properly. To make this work, I had to first detect what device fired the IRQ request, display controller or the 6522 timer.

Besides the increased CPU load (about 15% for 245 Hz sound) such an inefficient interrupt handler also caused a background hum at ~50 Hz, which interfered with the generated sound, altering the bass notes timbre and frequency to be way out of tune, rendering the whole thing kinda pointless. That’s because the default handler takes quite a long while to finish, and sometimes another IRQ could be fired just before the previous interrupt handler call would get finished. It would help to re-enable IRQs just before passing the control into the default handler, but it failed to work (the program would just freeze) by a reason then unknown to me.

It took a long while to figure out, the attempts to solve this issue were continued simultaneously with the development in all other areas. It kinda stalled, and a solution was nowhere to be seen, but utz came to the rescue, he just mentioned a thing about PET interrupt handling, and helped to configure the MAME emulator properly to run my tests. It turned out that vertical blanking IRQ gets fired by one of the PIA lines, and it would remain set unless the PIA status gets acknowledged manually, by just reading the corresponding PIA register. Re-enabling the IRQ without the acknowledgement to the PIA would just re-fire it right away, so the IRQ handler will immediately get invoked again, putting the program into an infinite loop.

Once the music player code has been finished, a test song prepared, and it has been tested on the real PET computer, another major problem has been found. Some notes of a certain pitch had been missing, presumably those were just on the borderline between the 6522 sound generation and the software one, yet it worked just fine in the VICE. With help from utz and mr287cc I was able to use MAME for testing the code, it turned out to be more precise and reproduced this issue too. utz also pointed out to a text that explained the reason for the issue, the 6522 shift register had to be reloaded in a specific way to make it run right after loading, otherwise it would start to shift the bit pattern after a delay.

Besides the PET challenges, the VIC-20’s limits have been pushed a bit. Its sound chip is normally only capable of generating 50% square wave and white noise. However, it features a pretty unusual inner design, worthy of a whole different article on itself. In short, using a few of precisely timed register writes it is possible to make it generate 15 more waveforms, each of those is basically a 1-bit sequence, each with its own specific sound. This trick has been first discovered by viznut in the early 2000s, however it barely has been employed in the newest development, even though it is supported in the modern emulators.

When I learned about this trick, I attempted to implement it in my sound code, and it kinda worked. However, it turned out that the extra waveforms only added higher harmonics to the signal, and it isn’t very useful for the music, considering the very limited VIC-20’s pitch range. Besides, with the not so perfect precision of the existing emulators I wasn't able to debug it well enough, so it worked a bit unstable, occasionally selecting the wrong waveform. As a result, the VIC-20 music sounds a bit weird in my sound code, and it wasn’t ever fixed properly.

Squeezing It In

Going according to the original plan, I was designing the sound system towards the PET’s limitations, as it has been set as the main target platform. The plan was to make a pseudo polyphonic engine, much like what I did for PC Speaker and Planet X3 before. The idea behind this is that there are a few virtual sound channels playing their parts, but in each particular moment of the time, which is something about 1/50 seconds long, only one of those gets routed towards the sole sound output, according to the part priority. That’s the drums, the melody, and the bass line in the order of the most to least importance. This creates an illusion of a multi channel arrangement, even though the sound always remains monophonic. For the platforms with more capable sound chips the player code logic remains the same, but a different channel manager is used that routes the virtual channels to the available hardware channels, so if a sound chip is capable for polyphony, the music gets polyphonic, while using the same exact music data as the input.

The compact data requirement, which allowed about 1K per one music track, made it impossible to take the easy way with pre-rendered register dumps that System Beeps was relying on. A new super size-efficient format had to be designed, which also would require composing the music and preparing the music data in a very specific way.

To reduce the music data size, a few decisions have been made, which in general meant less of everything on the input: shorter play time for songs, as less notes produces less data; less variable parameters per each note, as less parameters produces less data as well. High degree of reusable repetitive parts such as bass lines and drum patterns has been also considered to be used in order to reduce the data size.

My previous experience with compacting the music data, for example, in the Huby engine (a 100-byte engine for ZX Spectrum 48K) showed that a per-channel order list with 8-16 step patterns will give the best compacting results. Per-channel order has an overhead of the size of the list itself, but allows to reuse parts of the song such as bassline and drum patterns. This provides more compact data compared to the general order list that is used in music formats like MOD, XM, or IT.

To reduce the number of bits required to encode a single note, I employed the idea of different note ranges for channels, suggested by the VIC-20 sound chip design. The chip features three channels, each of those is tuned one octave apart from each other, which was needed to improve the pitch resolution having low resolution (7-bit) frequency dividers.

I did a similar thing: one channel is mostly used for bassline, second one for melodic parts, and third one is for the drums. So the second channel range is shifted one octave up. The lowest possible note is picked to match the VIC-20 capabilities too: it can play as low as 50 Hz, which makes the A-1 note. The pitch range of a channel is 2.5 octaves, roughly 32 semitones. Matching the lowest note to the chip capabilities allowed to not use the software synthesis for the VIC-20 and C64.

Besides the note range, each channel in my sound system also features a set of 7 customizable instruments, unique for each of the channels. I.e., 7 instruments for the bass part, 7 instruments for melodic parts, and 7 drum sounds. The note pitch is encoded with 5 bits, the instrument number is encoded with 3 bits, and the instrument with number 0 encodes the empty position, rest note, and repeating fields using the RLE. Considering the short patterns, it is just enough to encode any number of repeating fields in a pattern. This way any note field or series of repeating notes is encoded with just a single byte, and the smallest order position (all empty fields in each channel) can be encoded with a mere three bytes.

As the same music data was supposed to be used for all versions of the game, it had to be loaded into different RAM locations. So I had to use relative offsets everywhere. It made the player code a bit more complex and increased its size, but improved the versatility.

As the instrument data was extremely simple, it was encoded in the simplest possible way: two envelopes, one byte per update frame, no RLE. First envelope defines the wave shape, duty cycle, or volume changes over the time (depending on the target platform). Second envelope defines semitone offsets or pitch steps from the current note; the pitch/semitone mode gets switched with a special byte in this envelope.

In the initial version of the sound code all the variables were located in the Zero Page. This reduces code size considerably, as the variables get accessed very frequently, and ZP location allows to address them with just a single byte instead of a couple. However, as the firmware (BIOS and such) of all 8-bit Commodore machines prior to C64 put their system variables into ZP as well, filling the majority of its space, and there is no clear documentation on which variables can be used for machine code programs without any side effects, I had to omit this optimization and put the variables into regular RAM.

Debugging Misadventures

The biggest issue in the development of the sound code was the age of the target platforms. While Commodore 64 retains a huge popularity among the retro computing enthusiasts, its ancestors and less successful relatives such as PET, VIC-20, Plus/4, and others, never had a major popularity to begin with, and lost most of its remnants at the present day.

The unfortunate consequence of this is the very scarce amount of reasonably good information on programming for these platforms that can be found today in the webs. It is mostly present with scans of the old books in the unsearchable PDF and DJVU, and the books were mostly dedicated to BASIC programming. So I couldn’t really find a memory map that would explain which ZP locations are safe to be used in my code to not interfere with the BASIC/BIOS routines, and that became a major issue to integrate the sound code with the actual game that also needed some ZP memory to function.

Another unfortunate consequence of the low popularity of said platforms is the lack of software of all kinds. This results in the pretty low emulation quality, and the choice of emulators is very limited. For one, VICE does not emulate all 6522 modes, and MAME implements them with some mistakes - just because the old software wasn’t really using these features, so there is nothing to test out the implementations and improve the emulation precision.

Things get even worse at my end of the pond. Commodore computers were never popular in my country back in the 80s and 90s - up to the point of the total absence - so today the least popular models can only be found in the computer museums. So the first time I’ve seen a PET 8032 in person was in the private MTUCI (a communication technologies university) museum some time after the release of both the game and my album. Even if a real PET was accessible to me during the development process, it would be a major trouble to put my test code to it, as Commodore machines tend to use proprietary incompatible storage media and communication interfaces, which is even harder to find here.

Due to the reasons above, I had to debug my code using the pretty incomplete and imprecise emulators with rudimentary debug functionality. David was running my code from time to time on the actual hardware he owns, but as he’s busy with many other things, the back and forth couldn’t be done quick and frequently enough. This became yet another reason for the project failure, as we ended up with issues that were not possible to iron out using the available emulators, and that were difficult to figure out on the actual hardware, especially without having it within a direct reach.

In order to be able to debug the sound code at least somehow, I implemented support for yet another 6502 powered platform - the NES game console. Unlike the older Commodore series, this platform was and remains hugely popular, so it has dozens of emulators of very high quality, and some of them has the advanced debug functionality. This helped a lot, so I was able to use the much convenient FCEUX debugger for a good chunk of the work. The sound code is designed in a way to have its primary logic a platform independent, so only the part that accesses the sound chip gets changed depending on a platform. Once I got the primary logic working properly on the NES, I added the platform dependent parts for the actual target platforms, which had to be debugged in the respective platform emulators, of course.

Creating The Music And Sound

Having the music data format designed and sound code working, I had to solve the issue of the content authoring pipeline. In other words, how a music can be programmed within the specific constraints set, and the binary music data produced out of it. The less limited format, the easier the problem to solve - one can just adapt an existing music editor via making a format converter (from MIDI or XM, for example), and just compose the music with the constraints in mind. The more limited and quirky the format is, the more difficult a converter from a generic format to create, up to infeasibility due to the major inconvenience. This was the case.

In this situation the usual solution is just to program the music manually - compose the music in any format with all the limitations considered, then convert it into the hex all by hand. This is the common method that the video game music has been created up to the early 90s. Totally legit, but extremely tedious way to do it, that takes a lot of time and leaves too much room for a mistake. We didn’t have much time left for the project, so an editor tool of sorts had to be created in order to speed up the process.

At first, I has been considering to create an editor that would run on the actual PET, which could be programmed reasonably fast using a C compiler. The speed likely wouldn’t be an issue, however, the usability would be pretty bad, especially in the regards to the input (PET keyboard has much less keys than a regular PC keyboard), and file transfer into and from a floppy disk image. The support for other target platforms would have to be also provided somehow, but porting the editor to each of the targets would be pretty inefficient. So I dropped this idea. However, it has been eventually implemented by David himself, as he created a music editor that runs on the PET to create the music for the PET version when it has been decided to not use my code there.

David’s music editor running on the actual Commodore PET.
David’s music editor running on the actual Commodore PET.

Other possible solution was to create a music cross editor for a modern PC, similar to the FamiTracker and alike. It would solve all the issues reliably, however, it would be way too time consuming - the sound chips of the target platforms aren’t well emulated, so I couldn’t just utilize someone’s else code for this project, and making my own sound emulation code for an obscure and poorly documented chip, not even having it at hand, is an R&D task that would take an undefined amount of time with uncertain results. So this idea has been dropped as well.

There was another option, an odd one. A decade back I developed my own experimental cross platform cross target music editor called 1tracker. The whole reason to create it was to simplify creation of chiptune music for the most obscure platforms, which has been ZX Spectrum beeper music back then. The editor gets fully re-configured with external AngelScript based plugins, without recompiling the main code. It has been the best opportunity to utilize it for this project, but there was a catch. 1tracker back end is based on the Game_Music_Emu library that had no support for Commodore’s sound chips, not even SID, let alone VIC-20 and PET. And it couldn’t be added by the reasons given above.

To work around this problem, I got an idea, much similar to the code debugging: use another platform as an intermediate solution, namely utilize some of the supported music formats for a 6502 powered platform, such as NSF (NES music), SAP (POKEY music), or HES (PC Engine music), and just emulate the sound of a Commodore platform inside it via a crude software implementation in the 6502 assembly code that would just provide a somewhat similar sound. Another catch there, however, was that it was the first case of the need to support a 6502 platform inside the 1tracker, and it just was missing the infrastructure required, such as a built-in 6502 cross assembler. Sure it could have been added, but again, it would take a while to go that extra mile, the time that could match with making a custom tracker from scratch.

The ultimate solution to this can of worms has been a quirky compromise that worked, nevertheless: use 1tracker’s existing Z80 infrastructure to re-implement the PET sound code in Z80 assembly code, including a crude CB2 sound imitation written in Z80 code as well. This would allow one to hear a somewhat similar sound during composing the music, and an authentic sound could be then heard in a PET, VIC-20, or C64 emulator one the music data gets exported from the 1tracker.

The weak point of this solution was that ZX Spectrum’s Z80 that is emulated inside the AY file format container, runs at mere 3.5 MHz, and does not feature any timer interrupts besides the standard 50 Hz one. It may be just enough to run a CB2 sound counterpart, but the music player code had to be executed every 1/50 seconds, interrupting the sound,m and introducing a loud hum into the sound. This has been fixed by implementing an unlimited Z80 overclocking inside the Game_Music_Emu that can be enabled from Z80 code by using a dummy opcode such as LD H,H. When the overclocking is enabled, all opcodes take 0 t-states to execute, until the overclocking mode gets disabled. This mode has been enabled before running the music player logic and disabled just before the sound generation loop, so all the unwanted hum was removed.

One of the songs loaded into 1tracker under Windows.
One of the songs loaded into 1tracker under Windows.

This way I ended up writing a full equivalent of the 6502 sound code in Z80 assembly code, complete with a CB2-alike software sound synthesis written in Z80 assembly as well, and implemented the music and SFX authoring system as an external script-based plugin for 1tracker. I also added a few minor improvements to the 1tracker front end, to make the process more convenient. A binary music data export has been added, to be included into a 6502 program later. This was just sufficient for the project. I didn’t have to implement VIC-20 and C64 audition in the tracker, as at this point its support has been excluded from the project goals.

Recording The Audio

Having everything ready, the technical challenges solved, the player shell programmed, and music all composed, it may seem the album is almost ready to release. Only one more step has to be done: prepare the audio files for streaming/digital platforms. As I didn’t have access to a real PET, I could only record the audio from an emulator, which seem like a breeze. However, it turned out to be yet another challenge.

The sound emulation of the PET in the actual version of the WinVICE emulator at the time has been applying a really weird filtering to its audio output. It affected the timbre a lot, and the worst part was that it affected the volume depending on the pitch, reducing it up to almost silence at certain frequencies. Besides that, the latest build of the xpet of the latest WinVICE was simply not working, this particular executable just wasn’t starting at all (all others worked), so I had to stick to the previous release.

MAME’s PET sound emulation quality was much better. However, it was seriously messed up: the CB2 shift register clock was twice higher than it should be, even though the T1 timer was running at proper speed. Besides that, the sound emulation was disabled for all 40xx models for no apparent reason, and I needed a 40xx model to run the player shell that was not designed for 80xx series, and just wouldn’t run there.

To break the circle of trouble, I decided that I have to modify one of the emulators to fix its issues, and get a proper sound output. It turned out that fixing MAME imprecision was easier than removing the filter from VICE. mr287cc helped me to set up the MAME compilation pipeline, and I applied a dirty fix that simply divides the shift register clock by two, and enables sound for all 40xx models. After this I was able to make proper audio and video recording. I added a simple CRT-alike filter to the video using VirtualDub, and applied an impulse response of a small speaker to the audio, to give it a more authentic feel, compared to the clean and harsh idealized sound coming from the emulator

After releasing the album and confirming everything works correctly on different models of the actual hardware, bug reports have been sent to the authors of the respective emulators, supplied with the video proofs. I don’t know if the issues were fixed in the latest versions of the emulators.

The Legacy

It has been a whole year since the past Winter when the game and music album has been released. This article was on the back burner, and took a long while to get finished and translated to English. In the meantime, a number of unexpected things happened to the game and the album, and they both got a legacy of a kind that is worth mentioning.

Attack of the PETSCII Robots has been first released on the three Commodore home computer platforms, as it was planned from the beginning. Even though it looks very simplistic, and has a steep learning curve (without understanding its rules it seems to be lacking any depth), this simplicity combined with the popularity of the author played to its merit: some of David subscribers started to make ports to many other 6502 powered platforms and beyond. At the moment it actually seems to be one of the most ported homebrew games ever, even though it is not an open source or free software project - all the rights reserved to the original author and the source code is only available by a personal request.

At the time there are ten versions of the game available to purchase from David’s web page: PET, VIC-20, C64, Plus/4, C128, Apple II, Atari 8-bit, Amiga, PlayStation Portable, and even ZX Spectrum (more on this below). Each of the ports has its own specific features, different graphics and music, sharing the same general concept and level maps. A dozen more ports are in development, including versions for Sega Genesis, NES, SNES, MS-DOS, Commander X16, and other platforms. The versions and the development process has been covered by David in a video series on his YouTube channel.

In the Autumn 2021, an ensemble game OST was released on a compact cassette. It included the original music from the Commodore 64 version, composed by Noelle Aman, and not one, but two alternative soundtracks: one by Anders Enger Jensen (his music is frequent in David’s videos), composed using modern synthesizers, and another one is my Faulty Robots album in full. This is the first time my music has been published on physical media, so it is an honor to share the release with these respectable composers.

  The alternative sound track on a compact cassette.
  The alternative sound track on a compact cassette.

About the same time, I made a port of the Faulty Robots album to the ESPboy, by the platform maintainer request. No special reason behind this, it has been done just for fun, and because it is just another unusual media to share the album. 

Faulty Robots running on the ESPboy.
Faulty Robots running on the ESPboy.

Unexpectedly, my involvement with the game did not end with the release of the album. In the late 2021 my retro game development fellow mr287cc and I were evaluating the idea of a static assembly source code translation between different classic CPU architectures - it would be a kind of holy grail for some of our projects. As PETSCII Robots was missing a Z80 port, an idea arose to try to make a translator using this game code as a test suite, like do two good things at once. Our idea kinda failed, as it turned out to be pretty tricky to get efficient enough code without bloating it 10 times (yes, 6502 and Z80 are that different), but we’re decided to translate the game code manually, to gain better experience of porting between these architectures. We did the port extremely close to the original code design, including keeping original 6502-optimal data structures, which aren’t really fit to Z80 architecture, so it was pretty inefficient, however, it kept the original gameplay and even original quirks very authentic.

We used our Z80 code port to create a version for ZX Spectrum 48K. mr287cc did the main chunk of the work, I just translated the AI routines, helped to debug some things, created some extra graphics for the ‘mini’ version of the game, and of course I handled all the sound code, including a couple dozens of brand new pretty complex, gameplay-interrupting sound effects (created using my old tool called BeepFX), and three songs from Faulty Robots for the title, lose and win screens. So the sound part of this port is now strictly matched to my vision that I had at the very beginning of the project. Besides the game itself, I also ported the whole album, with all songs included, as a separate program.

Color Mini Bots version of Attack of the PETSCII Robots for ZX Spectrum 48K.
Color Mini Bots version of Attack of the PETSCII Robots for ZX Spectrum 48K.

ZX Spectrum 48K version of the game is available for purchase at David’s web page as well, digital release only at the moment. Hopefully eventually it’ll get a limited physical media release, too.

Near completion of writing of this article, I finally cleaned up and published the full source code of my sound system, now called PeskyTone, that supports PET, VIC-20, C64, and the NES. I don’t think it has any importance outside of the PET realm, but it may serve as a kind of a Hello World example for the said platforms, as it is kinda difficult to find one for these.

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 5: ↑5 и ↓0+5
Комментарии1

Публикации

Истории

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
10 – 11 октября
HR IT & Team Lead конференция «Битва за IT-таланты»
МоскваОнлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн