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

The first bit is a flag:

Value Purpose
0 MIDI In only when selected
1 MIDI In always

The remaining bits are the MIDI channel the module will respond to, shifted left by 1 bit, or 0 if it should respond to all channels that SunVox is globally listening to.

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