Now that my port of Conway’s Game of Life on Apple II possess a proper HIRES Title Screen, some kind of music would be great!

In this post, I will present the sound capabilities of the Apple II then explain how I coded a (simple) music library.

This is the fourth post about coding the Game of Life on the Apple II. Here are the previous ones:

  1. Coding in C for an 8 bit 6502 CPU
  2. Coding in Assembly for an Apple II
  3. HIRES Graphics on Apple II

And as usual, the code is available on GitHub!

Where in the world is the dedicated sound hardware?

Do you know the musical abilities of the Apple II? Well… there is none!

OK I am exaggerating a tiny bit. The CPU has direct control of a speaker, called the Beeper!

Most of the 8 bit home computers from the early eighties provided some hardware dedicated to producing pleasant music. Atari 8bits featured 4 voices on which you could play sines and mix some noise. The Commodore C64 came along the legendary SID, which the chiptuners still compose for!

But the Apple II precedes those machines by several years. It was not designed primarily as a game machine (although games were among its very first batch of programs). And, as we know, Woz liked nothing more than using standard chips and cutting their number to the bare minimum. That is why the Beeper is directly driven by the CPU.

Even the IBM PC, which was often derided for its appalling sound capabilities, provided more. In the Apple II’s fashion, the PC’s speaker is directly controlled by the CPU. But the PC also came with a Programmable Interval Timer, which could be used to cadence the program driving the speaker. On the Apple machine, you don’t enjoy such a facility. In order to timely cadence the speaker, you have to count cycles. So, if you don’t rely on very cleaver programming tricks, you will hog 100% of the CPU.

And that’s precisely what I am doing in the library I will expose below! 😉

Producing notes

One caveat: I am not a musician. I apologize in advance if my explanations concerning musical notation, pitch and octaves are a little bit approximate.

Principle

The only interaction a program can have with the Beeper is through a Soft-Switch. Reading or writing to the address 0xC030 will invert the position of the speaker. And that’s it.

By periodically alternating the high and the low positions of the speaker, this switch make it easy to produce a square waveform. The frequency of this vibration will command the musical note produced. Thus, the single most important thing is to control the timing on which I will activate the speaker’s soft-switch.

Unfortunately, as I said, on the Apple II there’s is no other easy way to measure time other than counting cycles. So, the heart of my “note” routine is composed of two loops.

  1. The inner loop controls the pitch of the note to play. It is composed of a number of NOPs, forming the smallest quantum of time for my function. The number of iterations is adjusted so that iterating the loop takes the time of half a period for the desired note. When that amount of time is elapsed, the soft-switch is activated.
  2. The outer loop controls the duration of the note. I want the base duration to be the same for all the notes. Thus, of course, the number of iterations will be different for each one, as their period depends on their pitch.

In order to calculate the number of those iteration to perform, I need to know precisely the duration of each instruction. Inside the loops of course, but also the control instructions: comparisons, conditional branching, etc…

Fortunately, the 6502 behaves predictably. Counting the cycles is only a matter of reading the documentation.

loop_half_period:
  LDA $C030             ;4 cycles //SPEAKER
  LDX half_period       ;3 cycles
loop_nops:
  NOP                   ;2 cycles
  NOP                   ;2 cycles
  NOP                   ;2 cycles
  NOP                   ;2 cycles
  DEX                   ;2 cycles
  BNE loop_nops         ;3 cycles
  ;Testing duration loop
  DEY                   ;2 cycles
  BNE loop_half_period  ;3 cycles
  DEC duration_hi       ;5 cycles
  BNE loop_half_period  ;3 cycles

Controlling the pitch

These loops written, the real trick is to calculate the required number of iteration, depending on the pitch of the desired note. The formula is quite simple. The half period duration is $ \frac{1}{2 \ast Frequency_{NOTE}}$. The duration of the half-period loop is easy to calculate. It’s $ \frac{Number_{cycles}}{Frequency_{CPU}} $.

Thus, to get the number of required iterations:

$$ Nb_{ITERATIONS} = \frac{Frequency_{CPU}}{2 \ast Frequency_{NOTE} * Number_{CYCLES}} $$

In order to help me, I wrote a small spreadsheet to perform the calculus for all the playable notes. Given that the 6502 is an 8 bit CPU, the highest number of iteration is 255. Thus, the the lowest note reproducible by my library is D#3, with 251 iterations.

You can download this spreadsheet from GitHub.

Du to the various approximations and the duration of the inner loop, this method cannot be 100% accurate. Thus, I recorded the notes using Audacity and measured their precise duration, so I could plot their relative distance from the goal.

Error Relative error of the reproduced frequency

Not that bad 😉

At the highest frequencies, less iterations are required to last half a period. Thus, the imprecision raises. I decided that the highest note reproducible would be B4. After that, the imprecision in the reproduction would be so high that those notes would be impracticable to play.

Controlling the duration

Concerning the duration of the note, it’s far easier. A base duration will be one second. It will correspond to a WHOLE note. As the inner loop is in charge for lasting half a period of the note, the number of outer loop’s iterations required is $ 2 \ast Frequency_{NOTE} $.

This base duration will be shifted in order to play HALF notes, QUARTER notes, and so on.

Pauses

In order to differentiate the notes, silence is needed. So, I also wrote a “pause” function. Its principle is the same as the “note” function and its base duration is also one second. But of course, the speaker soft-switch is left untouched.

The result

With my library being able to produce musical notes, control their duration and insert an optional pause between notes, I can play a simple tune. I asked my friend Clint Slate to compose a short one, to be played during my Title Screen:


And the same tune played by emulated Apple IIe:


You can marvel to the characteristic beeps of the machine! And the tune is still quite recognizable! 🙂

More advanced techniques

While quite satisfied by the result, and also by the ease of use of my “Apple II music library“, I know it is possible to do a lot better!

First, my library use 100% of the CPU when playing something. It’s OK for my title screen, but it would be impossible to use it while achieving fluid animations. Good coders of the eighties could do it.

Well, maybe it is easier than playing music, as sound effects may not have to rely on strict timing requirements. But it impresses me nonetheless!

Another weakness of my library, is that it produces the crudest level of 1 bit music: square waves. While it was the quite common back in the time, some talented hackers could do a lot better and played music on more than one channel!

It’s even possible to play sampled sounds, using a technique called “Pulse-Width Modulation“.

Anyway, my music library now fulfills my needs!