NESynth - NES Step Sequencer Synthesizer (6502 Assembly)


A step sequencer synthesizer for the NES, written entirely in 6502 assembly. 4 channels, 16-step patterns, 4 segments per channel, a piano roll editor, and multiple sound presets.

Download the ROM: nesynth.nes — runs on any NES emulator or flash cart.

The source code can be found on GitHub.

This was another fun AI exploration while I was exploring how to make music for the NES for Ninja Turdle II.

Demo

How It Works

The NES has a built-in Audio Processing Unit (APU) with 5 sound channels. NESynth uses 4 of them:

ChannelTypeDescription
C1Pulse 1Square wave with configurable duty cycle (12.5%, 25%, 50%, 75%)
C2Pulse 2Second pulse oscillator, same capabilities as C1
C3TriangleFixed triangle waveform — clean bass and sustained tones
C4NoisePseudo-random noise generator — drums and percussion

Each channel has its own 16-step grid, sound preset, envelope mode, tempo, and segment selection. Notes are placed on an E minor pentatonic scale spanning 4 octaves (20 pitch levels: E, G, A, B, D).

The sequencer runs in a loop driven by the NMI (VBLANK) interrupt. Every frame, the code advances the step counter, reads the sequence data for each channel, and writes directly to the APU registers to produce sound. I haven't overly stress-tested it, but it seems to support pretty fast sounds.

Sound Presets

Each channel type has its own set of sound presets that configure the APU registers differently:

Pulse Channels (C1/C2) — 8 presets:

PresetCharacter
LEDWarm lead (50% duty, full volume)
STBBright stab (12.5% duty)
BASFat bass (75% duty)
PADChaos pad (75% duty, low volume)
BUZThin buzz (12.5% duty, mid volume)
SQRSquare medium (50% duty)
FULFull power (75% duty, max volume)
TNKBright tonk (25% duty)

Triangle Channel (C3) - 4 presets: NRM (normal), STC (staccato), SHT (short), PLS (ultra-short pulse)

Noise Channel (C4) — 6 presets: KCK (kick), SNR (snare), HTC (closed hi-hat), HTO (open hi-hat), TOM (tom), RIM (rimshot)

Excuse my names for some of the sound settings, I was a bit of a loss for how to appropriately name things and took some creative liberties. :)

Envelope Modes

The pulse channels support 4 envelope modes that shape how notes decay over time:

ModeBehavior
SUSSustain — constant volume for the full step
PLKPluck — fast volume decay (~0.5s), like a plucked string
TRMTremolo — volume oscillation (~1.3s cycle)
SLWSlow fade — long gradual decay (~2.4s)

These are implemented by writing new volume values to the APU on every frame.

Controls

PLAY Mode (default)

ButtonAction
SelectCycle active channel (C1 → C2 → C3 → C4)
Up/DownCycle parameter (SND, WAV, SEQ, SEG, SPD, LCK)
Left/RightChange parameter value
StartEnter EDIT mode

EDIT Mode

ButtonAction
Left/RightMove cursor across the 16-step grid
Up/DownChange pitch at cursor
A (tap)Place or remove note
A + Left/RightExtend note with hold/tie markers for sustain
B (tap)Clear step at cursor
B + Left/RightErase sweep — clears steps as you move
SelectCycle channel
StartReturn to PLAY mode

Segments

Each channel has 4 independent 16-step segments. With SEQ set to ALL, the sequencer auto-advances through all 4 segments,skipping empty segments, giving you 64 steps of total sequence length per channel. Set SEQ to SEG to loop a single segment, or OFF to silence the channel.

Architecture

The entire program is a single 6502 assembly file assembled with ca65 (from the cc65 suite) and linked with ld65. It targets the simplest NES mapper — NROM (mapper 0) — with 16KB of PRG ROM and 8KB of CHR ROM. Total ROM size is 24KB.

Sequence data lives in 256 bytes of RAM at $0300, organized as 4 channels x 4 segments x 16 steps. Each step stores a pitch index (1-20 for notes, 0 for empty, $FE/$FF for hold/tie markers).

The display uses phased nametable updates split across 2 frames to stay within the NES's tight VBLANK budget. Frame 1 updates the step indicators and grids for channels 1-2. Frame 2 updates channels 3-4 and the parameter display. This keeps all PPU writes fast enough to avoid visual glitches.

Building

Requires cc65 (ca65 assembler + ld65 linker).

make

Produces nesynth.nes.



Projects

Site

Games

Tags