SunVox File Format

This document describes the SunVox file format in a way that is useful to developers of any app that wants to read/write SunVox files.

Special thanks to Alexander Zolotov for helping complete this document, and for sharing SunVox and his other creative works with the world.

This document reflects SunVox 1.9.4.

Little-endian

Multi-byte integer values are always encoded in little-endian format.

IFF-style containers

All SunVox files use a variation of the Interchange File Format.

Each file is a stream of chunks.

Each chunk consists of a 4-byte ASCII string known as a “Type ID”, then a unsigned int32 known as the “Length”, and finally a blob of that length (if length was not 0).

Some chunks are specified as being containers themselves, such as when a SunVox project is embedded within a MetaModule. In this case, the length of the outer chunk is for the entire project data. Then, the data is parsed as a separate container.

Note

You can use Radiant Voices to quickly inspect the IFF structure of a SunVox file:

$ python -m rv.lib.iff myproject.sunvox

SVOX

VERS  00000000: 00 03 09 01                                       ....

BVER  00000000: 00 02 09 01                                       ....

BPM   00000000: 7D 00 00 00                                       }...

[ ... ]

String encoding

All strings are UTF-8 encoded C-style strings.

File extensions

sunvox

Contains an entire SunVox project, with chunks in this order:

  1. Empty chunk of type SVOX.

  2. Project chunks.

  3. Pattern chunks for each pattern.

  4. Module chunks for each module.

sunsynth

Contains a single SunVox module, with chunks in this order:

  1. Empty chunk of type SSYN.

  2. SunVox version: VERS type, unsigned int32. (e.g. 0x01090300 for v1.9.3.0)

  3. Module chunks.

sunpat

Used by SunVox for copying and pasting selections of pattern data in the pattern editor, via the .sunvox_clipboard.sunpat file.

Contains a selection of pattern data, encoded in a single SVOX chunk.

The chunk contents are as follows:

Offset

Type

Purpose

0x00

unsigned int32

Number of tracks in pattern

0x04

unsigned int32

Number of lines in pattern

0x08

note[lines][tracks]

2-D array of notes

sunpats

Used by SunVox for copying and pasting patterns in the timeline, via the .sunvox_clipboard.sunpats file.

Contains multiple patterns, with chunks in this order:

  1. Empty chunk of type SVOX.

  2. Project chunks for the project that the patterns were copied from.

  3. Pattern chunks for each pattern.

Project chunks

Type ID

Format

Purpose

VERS

unsigned int32

SunVox version (e.g. 0x01090300 for v1.9.3.0)

BVER

unsigned int32

Based-on version

``BPM ``

unsigned int32

Initial BPM (beats per minute)

SPED

unsigned int32

Initial TPL (ticks per line)

TGRD

unsigned int32

Time grid (number of lines per “beat”)

TGD2

unsigned int32

Time grid 2 (number of “beats” per “measure”)

GVOL

unsigned int32

Global volume

NAME

cstring

Project name

MSCL

unsigned int32

Modules scale

MZOO

unsigned int32

Modules zoom

MXOF

signed int32

Modules X offset

MYOF

signed int32

Modules Y offset

LMSK

unsigned int32

Modules layer mask

CURL

unsigned int32

Modules current layer (0 to 7)

TIME

signed int32

Current timeline position

REPS

signed int32

Restart position

SELS

unsigned int32

Index of Last selected module

LGEN

unsigned int32

Index of last selected generator module

PATN

unsigned int32

Pattern cursor: index of pattern being edited

PATT

unsigned int32

Pattern cursor: track index

PATL

unsigned int32

Pattern cursor: line index

Modules layer mask

The first byte of this value is a bitmask of layers visible in the modules. When a bit is on, the corresponding layer will always be visible regardless of whether that layer is the current layer.

Pattern chunks

If a pattern doesn’t exist at a given index, the only chunk present will be PEND.

Patterns

Type ID

Format

Purpose

PDTA

note[lines][tracks]

2-D array of notes

PNME

cstring

Pattern name (optional)

PCHN

unsigned int32

Number of tracks in pattern

PLIN

unsigned int32

Number of lines in pattern

PYSZ

unsigned int32

Height of pattern in timeline

PFLG

bitmap (4 bytes)

Pattern appearance flags

PICO

bitmap (32 bytes)

Pattern icon (16×16 bitmap, with top-left origin)

PFGC

unsigned int8[3]

Foreground color (RGB)

PBGC

unsigned int8[3]

Background color (RGB)

PFFF

bitmap (4 bytes)

Pattern flags

PXXX

signed int32

X position in timeline

PYYY

signed int32

Y position in timeline

Pattern clones

Type ID

Format

Purpose

PPAR

unsigned int32

Index of source pattern

PFFF

bitmap (4 bytes)

Pattern flags

PXXX

signed int32

X position in timeline

PYYY

signed int32

Y position in timeline

Notes

Each note is an 8-byte structure:

Offset

Type

Purpose

0x00

byte

NOTECMD number

0x01

unsigned int8

Velocity (0x00 = empty, 0x01 = silent, 0x81 = max)

0x02

unsigned int8

Module index (0x00 = empty)

0x03

zero byte

Reserved

0x04

unsigned int8

Controller

0x05

unsigned int8

Effect

0x06

unsigned int16

XXYY value

0x06

unsigned int8

XX value

0x07

unsigned int8

YY value

NOTECMD

Value

Purpose

0x00

Empty

0x01

C-0

0x79

B-9

0x80

Note off

0x85

Set pitch

0x86

Effect previous track

Pattern appearance flags

Value

Purpose

0x01

No icon

Pattern flags

Value

Purpose

0x01

Clone of another pattern

0x02

Pattern is selected

0x08

Mute

0x10

Solo

Module chunks

If a module doesn’t exist at a given index, the only chunk present will be SEND.

Type ID

Format

Purpose

SFFF

bitmap (4 bytes)

Module flags

SNAM

string[32]

Module name (zero-padded)

STYP

cstring

Module type (not present for “Output” module)

SFIN

signed int32

Finetune

SREL

signed int32

Relative note

SXXX

signed int32

X position (not in sunsynth files)

SYYY

signed int32

Y position (not in sunsynth files)

SZZZ

signed int32

Layer (not in sunsynth files)

SSCL

unsigned int32

Scale

SVPR

bitmap (4 bytes)

Module visualization bitmap (not in sunsynth files)

SCOL

bytes[3]

Color (RGB)

SMII

unsigned int32

MIDI in

SMIN

cstring

MIDI Out name (not present if none selected)

SMIC

unsigned int32

MIDI Out channel (0 for all channels)

SMIB

signed int32

MIDI Out bank (-1 for none)

SMIP

signed int32

MIDI Out program (-1 for none)

SLNK

signed int32[n]

Module indexes of incoming links, optionally terminated with -1

CVAL

unsigned int32

Controller value for controller 1

CVAL

unsigned int32

Controller value for controller n

CMID

bytes[8]

Controller MIDI mappings for controller 1

CMID

bytes[8]

Controller MIDI mappings for controller n

CHNK

unsigned int32

CHNK value for the module, if applicable

multiple

Module-specific chunks, if applicable

Module flags

User-accessible module flags:

Value

Purpose

0x80

Mute

0x100

Solo

0x4000

Bypass

Internal module flags:

Value

Purpose

0x000001

Exists

0x000002

Output

0x000008

Generator

0x000010

Effect

0x000040

Initialized

0x000400

Get speed changes

0x000800

Hidden

0x001000

Multi

0x002000

Don’t fill input

0x008000

Use mutex

0x010000

Ignore mute

0x020000

No scope buffer

0x040000

Output is empty

0x080000

Open

0x100000

Get play commands

0x200000

Get render setup commands

0x400000

Feedback

0x800000

Get stop commands

Default flags for each module type:

Module type

Default

Amplifier

0x000051

Analog generator

0x000049

Compressor

0x002051

DC Blocker

0x000051

Delay

0x000451

Distortion

0x000051

DrumSynth

0x000049

Echo

0x000451

EQ

0x000051

Feedback

0x600051

Filter

0x000451

Filter Pro

0x000451

Flanger

0x000451

FM

0x000049

Generator

0x000059

Glide

0x021049

GPIO

0x000051

Input

0x000049

Kicker

0x000049

LFO

0x000451

Loop

0x000451

MetaModule

0x008051

Modulator

0x002051

MultiCtl

0x020051

MultiSynth

0x021049

Output

0x000043

Pitch shifter

0x000051

Pitch2Ctl

0x020049

Reverb

0x000051

Sampler

0x008459

Sound2Ctl

0x600051

SpectraVoice

0x000049

Velocity2Ctl

0x020049

Vibrato

0x000451

Vocal filter

0x000051

Vorbis player

0x008049

WaveShaper

0x000051

Module visualization bitmap

Bits

Purpose

0-4

Level mode

5-7

Level flags

8-12

Oscilloscope mode

13-15

Reserved for oscilloscope flags

16-23

Oscilloscope size in ms (unsigned int8)

24-25

BG transparency (0 = visible, 3 = invisible)

26-27

Shadow opacity (0 = invisible, 3 = visible)

28-31

Reserved for other flags

Level mode

Value

Purpose

0x00

Off

0x01

Mono

0x02

Stereo

0x03

Color

0x04

Glow

Level flags

Value

Purpose

0x01

Orientation (0 = horizontal, 1 = vertical)

Oscilloscope mode

Value

Purpose

0x00

Off

0x01

Points

0x02

Lines

0x03

Bars

0x04

Bars 2 (symmetrical)

0x05

Stereo Phase Scope × 1

0x06

Stereo Phase Scope × 2

0x07

XY

MIDI in

Bit structure:

Bit

Purpose

0

Always flag (1 = MIDI In always)

1-5

MIDI channel (0 = all channels)

6

Never flag (1 = MIDI In never)

The MIDI input behavior is determined by the flags:

  • always=0, never=0: MIDI In only when selected

  • always=1, never=0: MIDI In always

  • always=0, never=1: MIDI In never

Controller MIDI mappings

Offset

Type

Purpose

0x00

byte

MIDI message type

0x01

unsigned int8

Channel (0 for all channels)

0x02

byte

MIDI mapping slope

0x03

zero byte

Reserved

0x04

unsigned int16

Message parameter

0x06

zero byte

Reserved

0x07

unsigned int8

0xff if message type is unset; 0xc8 if other value

MIDI message type

Value

Purpose

0

Unset

1

Note

2

Key Pressure

3

Control Change

4

NRPN

5

RPN

6

Program Change

7

Channel Pressure

8

Pitch Bend

MIDI mapping slope

Value

Purpose

0

Linear

1

Exp. 1

2

Exp. 2

3

S-Curve

4

Cut

5

Toggle

CHNK value

This must be at least 1 more than the maximum CHNM used by the module.

It is used to allocate space in SunVox, and the audio engine will stop if the CHNM is too small.

Module-specific chunks

General format

Type ID

Format

Purpose

CHNM

unsigned int32

Module-specific chunk number

CHDT

(module-dependent)

Module-specific chunk data

Options chunks

Modules that have options store them as an array of boolean bytes in a module-specific CHNM number, padded with zeros to 64 bytes.

Most options are flags. The default is off, represented by 0x00, and the alternative is on, represented by 0x01.

Some options are inverted. The default is on, represented by 0x00, and the alternative is off, represented by 0x01.

Some options are integers.

Module type

Options CHNM number

Analog Generator

0x01

MetaModule

0x02

MultiSynth

0x01

Sampler

0x0101

Sound2Ctl

0x00

Analog Generator options

Offset

Type

Purpose

0x00

flag

Volume envelope scaling per key

0x01

flag

Filter envelope scaling per key

0x02

flag

Volume scaling per key

0x03

flag

Filter frequency scaling per key

0x04

flag

Velocity dependent filter frequency

0x05

flag

Frequency / 2

0x06

inverted

Smooth frequency change

0x07

flag

Filter frequency scaling per key reverse

0x08

flag

Retain phase

0x09

flag

Random phase

0x0a

flag

Filter frequency equals note frequency

0x0b

flag

Velocity dependent filter resonance

MetaModule options

Offset

Type

Purpose

0x00

integer

Number of user defined controllers (0 to 27)

0x01

flag

Arpeggiator

0x02

flag

Apply velocity to project

0x03

inverted

Event output

MultiSynth options

Offset

Type

Purpose

0x00

flag

Use static note C5

0x01

flag

Ignore notes with zero velocity

0x02

flag

0x00 = note/velocity curve, 0x01 = velocity/velocity curve

0x03

flag

Trigger (ignore note off)

Sampler

Offset

Type

Purpose

0x00

flag

Record on play

0x01

flag

Record in mono

0x02

flag

Record with reduced sample rate

0x03

flag

Record in 16-bit

0x04

flag

Stop recording on project stop

0x05

flag

Ignore velocity for volume

Sound2Ctl

Offset

Type

Purpose

0x00

flag

Record values

Array chunk

Some module-specific chunks are in the form of an array. Such an array will be described using these attributes:

  • CHNM number

  • Length (in values)

  • Data type

  • Minimum value

  • Maximum value

  • Default value

Array values are stored in the CHDT in row order.

Waveform chunk

These types of chunks contain sample data in their CHDT, and have two additional IFF chunks:

Type ID

Format

Purpose

CHFF

bitmap (4 bytes)

Chunk audio format bitmap

CHFR

unsigned int32

Chunk audio freq (default 44100; not written if default)

Chunk audio format bitmap

The first 3 bits specify the format, and the 4th bit is a stereo flag:

Value

Format

Stereo

0x00

?

?

0x01

8-bit signed int

No

0x02

16-bit signed int

No

0x04

32-bit float

No

0x09

8-bit signed int

Yes

0x0a

16-bit signed int

Yes

0x0c

32-bit float

Yes

Drawn waveform chunk

This is a waveform chunk that has some restrictions:

  • Fixed length of 32 frames

  • Fixed format of mono, 8-bit

  • Fixed freq of 44100

SunVox assigns a default waveform:

00 9C A6 00 5A 89 EC 2D 02 EC 6F E9 02 9E 3C 20
64 32 00 CE 41 62 32 20 A6 88 64 5A 3B 15 00 36

Analog Generator module-specific chunks

Analog Generator drawn waveform (CHNM 0)

This is a drawn waveform chunk.

Generator module-specific chunks

Generator drawn waveform (CHNM 0)

This is a drawn waveform chunk.

MetaModule module-specific chunks

MetaModule embedded project (CHNM 0)

The CHDT contains the binary data for the embedded SunVox project, in the same format as a sunvox file.

MetaModule user defined controller mappings (CHNM 1)

This is an array chunk:

  • Length (in values): 64

  • Data type: 4-byte structure (see below)

Each item in the array describes a mapping between a user-defined controller and a target module/controller in the embedded project.

Only the first 27 items are used, as that is the maximum number of user defined controllers. The remaining items are always unset.

Offset

Type

Purpose

0x00

unsigned int16

Target module index (0x00 for unset)

0x02

unsigned int16

Target controller number (1-based, 0x00 for unset)

MetaModule user defined controller names (CHNM 8+n)

Where n is the 0-based index of the user-defined controller.

The CHDT contains a cstring with the controller name.

MultiCtl module-specific chunks

MultiCtl mapping array (CHNM 0)

This is an array chunk:

  • Length (in values): 16

  • Data type: 32-byte structure (see below)

Each item in the array corresponds to a downstream module. Items are ordered by module index. Items past the number of connected downstream modules are ignored.

Offset

Type

Purpose

0x00

unsigned int32

Minimum value

0x02

unsigned int32

Maximum value

0x04

unsigned int32

Controller number (1-based index)

0x06

unsigned int32

Reserved (0x00 value)

0x08

unsigned int32

Reserved (0x00 value)

0x0a

unsigned int32

Reserved (0x00 value)

0x0c

unsigned int32

Reserved (0x00 value)

0x0e

unsigned int32

Reserved (0x00 value)

MultiCtl value curve (CHNM 1)

This is an array chunk:

  • Length (in values): 257

  • Data type: unsigned int16

  • Minimum value: 0x0000

  • Maximum value: 0x8000

  • Default value: Linear curve, x * 0x80

MultiSynth module-specific chunks

MultiSynth note/velocity curve (CHNM 0)

This is an array chunk:

  • Length (in values): 128

  • Data type: unsigned int8

  • Minimum value: 0x00

  • Maximum value: 0xff

  • Default value: 0xff

MultiSynth velocity/velocity curve (CHNM 2)

This is an array chunk:

  • Length (in values): 257

  • Data type: unsigned int8

  • Minimum value: 0x00

  • Maximum value: 0xff

  • Default value: Linear curve, min(x, 255)

Sampler module-specific chunks

Sampler global configuration (CHNM 0)

The CHDT chunk for this section contains global sampler configuration such as options, envelopes, and note mappings.

Offset

Type

Purpose

0x00

zeros

Reserved (offset 0x00 to 0x1b)

0x1c

unsigned int32

Max sample index + 1 (0 for no samples)

0x20

zeros

Reserved (offset 0x20 to 0x23)

0x24

unsigned int8

Legacy sample number for note C-0 (note 0)

0x83

unsigned int8

Legacy sample number for note B-8 (note 95)

0x84

Legacy volume envelope point 0

0x84

unsigned int16

  • X Position (always 0 for point 0)

0x86

unsigned int16

  • Y Position (0x00 to 0x40)

0x88

Legacy volume envelope point 1

0x8c

Legacy volume envelope point 2

0x90

Legacy volume envelope point 3

0x94

Legacy volume envelope point 4

0x98

Legacy volume envelope point 5

0x9c

Legacy volume envelope point 6

0xa0

Legacy volume envelope point 7

0xa4

Legacy volume envelope point 8

0xa8

Legacy volume envelope point 9

0xac

Legacy volume envelope point 10

0xb0

Legacy volume envelope point 11

0xb4

Legacy panning envelope point 0

0xb4

unsigned int16

  • X Position (always 0 for point 0)

0xb6

unsigned int16

  • Y Position (0x00 to 0x40, center at 0x20)

0xb8

Legacy panning envelope point 1

0xbc

Legacy panning envelope point 2

0xc0

Legacy panning envelope point 3

0xc4

Legacy panning envelope point 4

0xc8

Legacy panning envelope point 5

0xcc

Legacy panning envelope point 6

0xd0

Legacy panning envelope point 7

0xd4

Legacy panning envelope point 8

0xd8

Legacy panning envelope point 9

0xdc

Legacy panning envelope point 10

0xe0

Legacy panning envelope point 11

0xe4

unsigned int8

Legacy number of active volume envelope points

0xe5

unsigned int8

Legacy number of active panning envelope points

0xe6

unsigned int8

Legacy volume sustain point

0xe7

unsigned int8

Legacy volume loop start point

0xe8

unsigned int8

Legacy volume loop end point

0xe9

unsigned int8

Legacy pan sustain point

0xea

unsigned int8

Legacy pan loop start point

0xeb

unsigned int8

Legacy pan loop end point

0xec

bitmap

Legacy volume envelope bitmap

0xed

bitmask

Legacy panning envelope bitmap

0xee

unsigned int8

Vibrato type (0 = sin, 1 = saw, 2 = square)

0xef

unsigned int8

Vibrato attack

0xf0

unsigned int8

Vibrato depth

0xf1

unsigned int8

Vibrato rate (0x00 to 0x3f)

0xf2

unsigned int16

Volume fadeout (0x0000 to 0x2000)

0xf4

constant

Hex bytes 40 00 80 00 00 00 00 00

0xfc

constant

ASCII string ‘PMAS’

0x100

constant

Hex bytes 04 00 00 00

0x104

unsigned int8

Sample number for note C-0 (note 0)

0x17a

unsigned int8

Sample number for note b-9 (note 118)

0x17b

zeros

Reserved (offset 0x17b to 0x183)

Envelope bitmap

Value

Purpose

0x01

Enable

0x02

Sustain

0x04

Loop

Sample configuration chunk (CHNM n*2+1)

(Where n is the sample index, starting at 0.)

The CHDT chunk for these sections contains sample-specific configuration such as loop points, panning, and relative note information.

Offset

Type

Purpose

0x00

unsigned int32

Sample length, in frames

0x04

unsigned int32

Loop start frame

0x08

unsigned int32

Loop end frame

0x0c

unsigned int8

Volume (0 to 64)

0x0d

signed int8

Finetune (-128 to 127, center at 0)

0x0e

bitmap

Loop and format bitmap

0x0f

unsigned int8

Panning (0 to 255, center at 128)

0x10

signed int8

Relative note (-128 to 127, center at 0)

0x11

zeros

Reserved (offset 0x11 to 0x27)

Loop and format bitmap

Bits 0-2 specify looping options:

Value

Purpose

0x00

No loop

0x01

Loop

0x02

Ping-pong loop

Bits 3-5 specify sample format:

Value

Purpose

0x00

8-bit signed int

0x10

16-bit signed int

0x20

32-bit float

Bit 6 is a stereo flag:

Value

Purpose

0x00

mono

0x40

stereo

Sample waveform (CHNM n*2+2)

(Where n is the sample index, starting at 0.)

This is a waveform chunk.

Sample envelope chunk

Offset

Type

Purpose

0x00

unsigned int16

Sample envelope flags

0x02

unsigned int8

Controller number (0x00 to 0x1f)

0x03

unsigned int8

Gain percentage (0x00 to 0x64)

0x04

unsigned int8

Velocity (0x00 to 0x64)

0x05

unknown

00 00 00

0x08

unsigned int16

Number of points in envelope

0x0a

unsigned int16

Sustain point

0x0c

unsigned int16

Loop start point

0x0e

unsigned int16

Loop end point

0x10

unknown

00 00 00 00

0x14

unsigned int16

X position of point 1 (in ticks)

0x16

unsigned int16

Y position of point 1 (0x0000 to 0x8000)

unsigned int16

X position of point n

unsigned int16

Y position of point n

Sample envelope flags

Value

Purpose

0x01

enabled

0x02

sustain

0x04

loop

Volume envelope (CHNM 0x102)

This is a sample envelope chunk.

Panning envelope (CHNM 0x103)

This is a sample envelope chunk.

Pitch envelope (CHNM 0x104)

This is a sample envelope chunk.

Effect control 1 envelope (CHNM 0x105)

This is a sample envelope chunk.

Effect control 2 envelope (CHNM 0x106)

This is a sample envelope chunk.

Effect control 3 envelope (CHNM 0x107)

This is a sample envelope chunk.

Effect control 4 envelope (CHNM 0x108)

This is a sample envelope chunk.

Sampler effect module (CHNM 0x10a)

This contains the selected effect, serialized as a sunsynth.

SpectraVoice module-specific chunks

SpectraVoice harmonic frequencies (CHNM 0)

This is an array chunk:

  • Length (in values): 16

  • Data type: unsigned int16

  • Minimum value: 0x0000

  • Maximum value: 0x8000

  • Default value: [0x044a, 0x00, …]

SpectraVoice harmonic volumes (CHNM 1)

This is an array chunk:

  • Length (in values): 16

  • Data type: unsigned int8

  • Minimum value: 0x00

  • Maximum value: 0xff

  • Default value: [0xff, 0x00, …]

SpectraVoice harmonic widths (CHNM 2)

This is an array chunk:

  • Length (in values): 16

  • Data type: unsigned int8

  • Minimum value: 0x00

  • Maximum value: 0xff

  • Default value: [0x03, 0x00, …]

SpectraVoice harmonic types (CHNM 3)

This is an array chunk:

  • Length (in values): 16

  • Data type: byte enumeration (see below)

  • Default value: [hsin, …]

Value

Purpose

0x00

hsin

0x01

rect

0x02

org1

0x03

org2

0x04

org3

0x05

org4

0x06

sin

0x07

random

0x08

triangle1

0x09

triangle2

0x0a

overtones1

0x0b

overtones2

0x0c

overtones3

0x0d

overtones4

Vorbis player module-specific chunks

Vorbis player file data chunk (CHNM 0)

CHDT contains the Vorbis file content, or is empty if no file has been loaded.

WaveShaper module-specific chunks

WaveShaper curve chunk (CHNM 0)

This is an array chunk:

  • Length (in values): 256

  • Data type: unsigned int16

  • Minimum value: 0x0000

  • Maximum value: 0xffff

  • Default value: Linear curve, x * 0x100