Skip to content
Techniques & Technology

Interrupt-Driven Music

Sound without blocking

Interrupt-driven music used timer interrupts to update sound chips at regular intervals, allowing music playback while the CPU handled game logic.

C64zx-spectrumAmigaNES audioprogrammingtechnique 1980–present

Overview

Early games faced a choice: play music or run the game. Interrupt-driven music solved this by using hardware interrupts to call music routines at fixed intervals. The main game loop ran uninterrupted while music played in the background, enabling the rich soundtracks that defined 8-bit gaming.

The problem

Without interrupts:

main_loop:
    jsr update_game
    jsr play_music_note    ; Blocks game
    jsr update_graphics
    jmp main_loop

Music timing depends on game speed.

The solution

With interrupts:

; Interrupt handler (called by hardware)
irq_handler:
    jsr update_music       ; Quick update
    rti

; Main loop runs freely
main_loop:
    jsr update_game
    jsr update_graphics
    jmp main_loop

C64 implementation

Using CIA timer

    lda #<irq_handler
    sta $0314
    lda #>irq_handler
    sta $0315

    lda #$00              ; Timer low byte
    sta $dc04
    lda #$40              ; Timer high byte (~50Hz)
    sta $dc05

    lda #$01              ; Enable timer interrupt
    sta $dc0d

    cli                   ; Enable interrupts

Music routine requirements

RequirementReason
Fast executionDon’t block too long
Register preservationDon’t corrupt game state
Consistent timingMusical accuracy

NES implementation

Using NMI

The NES uses NMI (Non-Maskable Interrupt) during VBlank:

nmi_handler:
    pha                   ; Save registers
    txa
    pha
    tya
    pha

    jsr update_music      ; Call music routine

    pla                   ; Restore registers
    tay
    pla
    tax
    pla
    rti

Amiga implementation

Using CIA or VBlank

SourceFrequency
VBlank50/60 Hz
CIA timerProgrammable

Paula handles sample playback; CPU sets up patterns.

Music routine structure

Typical update routine:

update_music:
    dec frame_counter
    bne .no_update

    lda #speed
    sta frame_counter

    ; Update each channel
    jsr update_channel_1
    jsr update_channel_2
    jsr update_channel_3

.no_update:
    rts

Timing considerations

FactorImpact
Interrupt frequencyMusical tempo
Routine lengthCPU availability
Nested interruptsComplexity

Professional music drivers

DriverPlatformCreator
CustomC64Rob Hubbard
FamiTracker driverNESVarious
ProTrackerAmigaVarious

See also