Skip to content

Arpeggio

Chords from a single channel

A sound chip with three voices cannot spare three of them for a chord. An arpeggio plays the chord's notes one after another on a single voice, changing pitch every frame or every tick, so fast that listeners hear a buzzing chord. It became part of the sound of the C64's SID, the AY chips, the NES and Amiga trackers.

The Commodore 64’s SID has three voices. So does the AY chip in the Spectrum 128 and the Amstrad CPC, and the NES has two pulse channels and a triangle for its tunes. Spend three voices on one chord and there is nothing left for the melody, the bass or the drums. The answer that came to define the sound of these machines was to play the chord’s notes one after another on a single voice, changing the pitch every frame.

The Games Machine described Rob Hubbard’s version of the trick in its first issue, in October 1987: “‘toggling’, alternating rapidly from one note to another to produce the illusion of chords.” Martin Galway, looking back in 2012, went further: “I believe I invented the fast arpeggiation technique for mimicking chords, first released in Kong Strikes Back in 1984.” That is his recollection; no public source settles who used it first.

How it works

The music player runs once a frame, usually from an interrupt, and each time it sets the voice’s pitch to the next note of the chord:

Code
Frame 0: C
Frame 1: E
Frame 2: G
Frame 3: C  (the cycle starts again)

A three-note chord at one note per frame repeats 50 / 3 ≈ 16.7 times a second on a 50 Hz PAL machine and 20 times a second at 60 Hz. Slow the player down to two frames a note and the cycle drops to about 8 a second on PAL, where the separate notes are easier to hear. A four-note chord cycles more slowly than a three-note one at the same speed.

Players store chords as semitone offsets above the note being played. Amiga Shopper’s 1993 OctaMED tutorial listed the ones a composer needs most:

Chord Offsets (semitones)
Major 0, 4, 7
Minor 0, 3, 7
Diminished 0, 3, 6
Augmented 0, 4, 8
Suspended fourth 0, 5, 7

Opinions of the result differed. The tutorial said the pitch changes so quickly “that it’s perceived as a simultaneous chord”. The community specification of the MOD music format, written for programmers, was blunter: arpeggios “are usually used to simulate chords, but this doesn’t work too well.”

On the SID

C64 music players are, in Cadaver’s words, “frame-based. That means they’re called from a raster interrupt during each frame (50 times/second for PAL)”. This complete program plays a C major arpeggio on voice 1 from a raster interrupt. It assembles with ACME (acme -f cbm -o arp.prg arp.a) and starts with RUN:

Assembly
; C major arpeggio on SID voice 1, one note per frame (PAL C64)
        * = $0801
        !word next, 10
        !byte $9e
        !text "2061"
        !byte 0
next    !word 0

        * = $080d
start   sei
        lda #$7f
        sta $dc0d       ; stop CIA 1's timer interrupt
        lda $dc0d       ; and clear any that is pending
        lda #<irq
        sta $0314       ; point the KERNAL's IRQ vector at our handler
        lda #>irq
        sta $0315
        lda #$1b
        sta $d011       ; bit 7 = raster line bit 8 = 0
        lda #250
        sta $d012       ; interrupt on raster line 250, once a frame
        lda #$01
        sta $d01a       ; enable the VIC-II raster interrupt
        lda #$0f
        sta $d418       ; full volume, no filter
        lda #$00
        sta $d405       ; voice 1 attack 0, decay 0
        lda #$f0
        sta $d406       ; sustain 15, release 0
        jsr update_arp  ; set the first pitch before the gate opens
        lda #$21
        sta $d404       ; sawtooth, gate on
        cli
        rts             ; back to BASIC; the interrupt keeps playing

irq     lda #$01
        sta $d019       ; acknowledge the raster interrupt
        jsr update_arp
        jmp $ea81       ; restore registers and return (KERNAL)

update_arp
        ldx arp_pos
        lda arp_offsets,x
        clc
        adc base_note   ; semitone number within the table
        tay
        lda note_lo,y
        sta $d400       ; voice 1 frequency, low byte
        lda note_hi,y
        sta $d401       ; voice 1 frequency, high byte
        inx
        cpx #3          ; three notes in the chord
        bcc +
        ldx #0
+       stx arp_pos
        rts

arp_pos     !byte 0
base_note   !byte 0             ; 0 = C4 in this table
arp_offsets !byte 0, 4, 7       ; major triad: root, +4, +7 semitones

; PAL values, C4 to C5: round(Hz * 16777216 / 985248)
note_lo !byte $67,$70,$89,$b2,$ed,$3b,$9c,$13,$a0,$45,$02,$da,$ce
note_hi !byte $11,$12,$13,$14,$15,$17,$18,$1a,$1b,$1d,$1f,$20,$22

The frequency values come from the SID data sheet’s formula for the PAL clock; the SID entry has full tables for PAL and NTSC. Changing arp_offsets to 0, 3, 7 gives a minor chord, and raising base_note moves the chord up the table (as far as 5 for a major chord, since this table stops at C5).

Real players were more elaborate. Anthony McSweeney’s 1993 disassembly of the player from Monty on the Run, a routine Hubbard used with small changes in Thing on a Spring, Commando, Thrust, International Karate and many others, found only an octave arpeggio. An instrument flag turns it on, and “for the first 50th of a second, the current note is played, and for the next 50th of a second, current note+12 is played”. McSweeney called it “a very limited arpeggio routine”, and pointed listeners to the arpeggio “and the skydive when combined”, a downward pitch slide, “which is used alot in Hubbard songs”.

Later players made the arpeggio part of the instrument. In Cadaver’s description, an instrument owns a table of byte pairs, a waveform and “the note number; either relative (arpeggios) or absolute (drumsounds)”, which the player steps through each frame. A command in the pattern data can move the table’s start “to play different chords without having to create an own instrument for each of them.” Composers kept finding more in it. Martin Walker, keeping a diary for ZZAP!64 while writing music in 1988, noted “A multiplexed chord using one channel”, and added: “It’s amazing just how many new and different sounds are possible on the 64.”

On the AY chips

The AY-3-8912 in the Spectrum 128 and the CPC works the same way: the player rewrites a channel’s 12-bit tone period each frame. The catch is the clock. The Spectrum 128 runs its AY at 1.7734 MHz and the CPC at 1.00 MHz, so the same period plays a different note on each machine, and an arpeggio routine moved from one to the other needs a new table of periods, not new logic.

On the NES

The NES’s APU has no help to offer beyond its registers. A game’s sound engine usually runs once a frame from the vertical blank interrupt, and an arpeggio on a pulse channel means rewriting the channel’s 11-bit period each frame. There is a trap. Writing the high byte of the period, at $4003 or $4007, restarts the note: it reloads the length counter, restarts the envelope and resets the waveform to its first step, which can be heard as a click. Rewriting only the low byte changes the pitch cleanly, but that only reaches notes whose periods share the same top three bits.

In Amiga trackers

On the Amiga, arpeggio became a command in the pattern data. In the MOD format of Soundtracker and ProTracker, effect 0xy plays the row’s note, then the note plus x semitones, then plus y. ProTracker’s player works in ticks, fifty a second at the default tempo of 125, and steps the arpeggio by the tick counter: the tick that starts a row plays the plain note, the next adds x, the next adds y, and the pattern repeats until the next row. At the default speed of six ticks a row, that is two full cycles per row. OctaMED used the same command: Amiga Shopper explained that it “changes the pitch of the note very quickly — six times during each note in fact”, and gave 047 for a C major chord above C-3.

Paula plays samples, though, so a composer could also sample a real chord. Hubbard, newly at work on the Amiga, told The Games Machine in 1987 that “instead of farting about writing algorithms to work out additive notes and stuff like that to get chords, I can just sample three chords from a DX synth using a Future Sound sampler”.

Sources

  • The Games Machine issue 1, October 1987, pp. 111-112, Rob Hubbard feature: “toggling” and the illusion of chords; sampling chords on the Amiga.
  • Retro Gamer: The Commodore 64 Book (2012), C64 composers’ panel: Martin Galway on arpeggios in Kong Strikes Back.
  • Anthony McSweeney, “Rob Hubbard’s Music: Disassembled, Commented and Explained”, C= Hacking issue 5, 1993: the routine and the games that used it, the octave arpeggio and the skydive.
  • Cadaver (Lasse Öörni), “Building a musicroutine”, Codebase64 (web, secondary): frame-based players, the waveform/arpeggio table and the table-start command. https://codebase64.net/wiki/
  • ZZAP!64 issue 39, July 1988, p. 97: Martin Walker’s diary, “A multiplexed chord using one channel”.
  • MOS Technology, 6581 SID data sheet: the frequency formula, output frequency = value × clock ÷ 16,777,216.
  • Sinclair ZX Spectrum +2 manual (Amstrad), Part 29: the AY-3-8912’s 1.7734 MHz clock. CPC464 Firmware (AMSOFT, 1984), appendix XII: its 1.00 MHz clock on the CPC.
  • NESdev Wiki, “APU Pulse” (community reference, web, secondary): the effects of writing $4003 and $4007. https://www.nesdev.org/wiki/APU_Pulse
  • Andrew Scott, “Noisetracker/Soundtracker/Protracker Module Format”, 4th revision, 2003 (web, secondary): effect 0xy, “this doesn’t work too well”, and the default speed and tempo.
  • Frank Wille, ProTracker 2.3B replay routine (public domain; web, secondary): mt_arpeggio and its tick table.
  • Amiga Shopper issue 28, August 1993, pp. 95-96: OctaMED tutorial, the arpeggio command and chord values.

See also

Checked. Verified against primary sources and signed off by a person.