*.bbsong File Format

A Beepola song file usually has the extension ".bbsong" and consists of file header, identifying the version of the file, plus one or more chunks of data. Chunks are identified by a null-terminated "chunk type" string, and end with the null-terminated string ":END" (without quotes).

When reading a file, any chunk names that are unhandled by a program should be ignored. Furthermore, any individual properties within a chunk that are not recognised by the reading program should also be ignored. Chunk type strings, and property identifiers within each chunk, should be considered case-sensitive.

File Header:

File Header 7 bytes "BBSONG" + 0x00
File Version 5 bytes "0001" + 0x00

:INFO Chunk

This chunk holds general information about the song, such as the song title, author and the preferred tone generation engine for the song. It is terminated by the string ":END" + 0x00 and may contain any number of null-terminated string properties, appearing in any order, of the form "PropertyName=PropertyValue". Valid property values for version 0001 files include "Title=...", "Author=..." and "Engine=..."

Chunk ID 6 bytes ":INFO" + 0x00
Song Title Variable, null-terminated "Title=[Full Song Title]" + 0x00
Song Author Variable, null-terminated "Author=[Author of Song]" + 0x00
Preferred Playback Engine Variable, null-terminated "Engine=[Song Engine]" + 0x00

Currently valid values for [Song Engine] are "SFX" for the Special FX engine, "TMB" for The Music Box engine, "MSD" for the Music Studio, "P1D" for Phaser1 with Digital Drums, "P1S" for Phaser1 with Synth Drums, and "SVG" for the Savage engine.
Terminator 5 bytes ":END" + 0x00

:LAYOUT Chunk

This chunk holds details of the song layout, including the position of the loop-start point, the length of the song and the layout of patterns that make up the song.

Chunk ID 8 bytes ":LAYOUT" + 0x00
Loop Start Point Variable, null-terminated "LoopStart=[Start Point]" + 0x00

[Start Point] is an ASCII string representation of the position of the loop start pointer for the song. LoopStart=0 indicates that the song loops back to the beginning, LoopStart=1 indicates that the song loops back to start of the second pattern in the song, and so on. LoopStart should never exceed the value of the Length property of the song layout.
Length Variable, null-terminated "Length=[Length of Song]" + 0x00

[Length of Song] is an ASCII string representation of the number of linked patterns that comprise the song. Note that this is not the same as the number of unique patterns in the song; a song that consists of the patterns 1,2,3,2,3 would have this property set as "Length=5" indicating a total of 5 patterns in the song layout, while the pattern data would contain only 3 patterns (pattern 1, pattern 2, and pattern 3).

The "Length=..." property is always followed immediately by a block of binary data with a length of [Length of Song] bytes. See below.
Song Layout Data [Length of Song] bytes The song layout, consisting of one byte per entry. In the above example of a song consisting of patterns 1,2,3,2,3 the song layout data would consist of 5 bytes: 0x01 0x02 0x03 0x02 0x03.
Terminator 5 bytes ":END" + 0x00

:PATTERNDATA Chunk

This chunk holds the data for each of the patterns in the song. Beepola includes all 127 patterns (numbered 0 to 126) in every song file. The reason for this is that a partially-complete song may include patterns that have not yet been included in the song layout, and these patterns would be lost if there were excluded from the song data. However, it is perfectly valid for a .bbsong file to contain fewer than 127 patterns and this should be allowed for in any reader program.  Early versions of Beepola wrote out 256 patterns in every :PATTERNDATA chunk, so this must also be allowed for (the last 129 patterns will be empty and can safely be ignored in version 0001 files).

Chunk ID 13 bytes ":PATTERNDATA" + 0x00
Pattern Count Variable, null-terminated "PatternCount=[NumPatterns]" + 0x00

[NumPatterns] is an ASCII string representation of the total number of patterns contained in the chunk. For version 0001 bbsong files, this must be a value between 0 and 256.

The "PatternCount=..." property is always followed immediately by a variable-length block of binary data as defined below, followed by the terminating :END +0x00 bytes.
Pattern Data Variable [NumPatterns] blocks of pattern data, as defined below.
Terminator 5 bytes ":END" + 0x00
 

The following Pattern Data block is repeated [NumPatterns] times. Internally, Beepola numbers patterns from 0 to [NumPatterns-1]. This is important when matching pattern data to the song layout contained in the :LAYOUT chunk.

Pattern Name Variable, null-terminated "PatternName=[Name of the Pattern]" + 0x00

Specifies the textual name of the pattern. This property is mandatory and must appear at the start of every pattern data block. If there is no pattern name set, this property is written as "PatternName=" +0x00. Pattern Names in Beepola never exceed 64 characters in length.
Pattern Length 4 bytes A 32-bit integer value containing the length of the pattern. Intel byte ordering is used.
Pattern Tempo 4 bytes A 32-bit integer value containing the tempo of the pattern.
Channel 1 Data [Pattern Length] bytes The note data for channel 1. This consists of [Pattern Length] bytes. The note value is 0 for the lowest note playable by the selected engine and increases by 1 per semitone. For the SFX and TMB engines, therefore, a value of 0x00 is represented in Beepola as F#1, a value of 0x06 is C-2, a value of 0x12 is C-3 and so on. The theoretical maximum is 0x7F giving a maximum range of over 10 octaves. The value 0xFF indicates no note present, and the value 0x82 indicates a "rest" (this is functionally identical to 0xFF for the SFX and TMB engines, but future engines may treat a rest value differently to an empty note value).
Channel 2 Data [Pattern Length] bytes As above, but for channel 2 of the pattern.
Percussion Data [Pattern Length] bytes Percussion channel data for the pattern. 0xFF represents no percussion. The values 0x81 to 0x84 inclusive represent the four currently-supported drum sounds of the SFX engine.
Additional Data for Channel 1 [Pattern Length] bytes Any addition data used by the selected engine. This data is ignored for the TMB engine, and contains the channel 1 sustain values for the SFX engine. A value of 0xFF represents no data, 0x00 to 0xFE are valid sustain values.
Additional Data for Channel 2 [Pattern Length] bytes As above for channel 2.

:P1INSTR Chunk

This chunk holds the data for each of the Phaser1 instruments in the song for songs of type "P1D" or "P1S". Beepola includes all 100 instruments (numbered 0 to 99) for Phaser1 songs.

Chunk ID 14 bytes ":SVGORNAMENTS" + 0x00
Pattern Count Variable, null-terminated "Length=[NumInstr]" + 0x00

[NumInstr] is an ASCII string representation of the total number of instruments contained in the chunk. For version 0001 bbsong files, this must be a value between 0 and 100 inclusive.

The "Length=..." property is always followed immediately by a variable-length block of binary data as defined below, followed by the terminating :END +0x00 bytes.
Instrument Data Variable [NumInstr] blocks of pattern data, as defined below.
Terminator 5 bytes ":END" + 0x00

The following Instrument Data block is repeated [NumInst] times. Internally, Beepola numbers instruments from 0 to [NumIntr-1]. This is important when matching instrument data to the pattern data.

Multiple 1 Byte The "Multiple" property for the instrument. Must be between 0 and 16 inclusive.
Detune 2 Bytes 16 bit unsigned integer containing the "Detune" property for the instrument. Must be between 0 and 9999 inclusive.
Phase 1 Byte The "Phase" property for the instrument. All unsigned byte values are valid.

:SVGORNAMENTS Chunk

This chunk holds the data for each of the ornaments defined in a Savage song (songs of type "SVG").   Beepola includes all 32 instruments (numbered 0 to 31) for Savage songs. Ornament 0 specifies "no ornament" and must always be defined as zero length, containing no data, but it is still written to saved files. Ornaments 1 to 31 are user definable.

Chunk ID 8 bytes ":P1INSTR" + 0x00
Ornament
Count
Variable, null-terminated "OrnamentCount=[NumOrn]" + 0x00

[NumOrn] is an ASCII string representation of the total number of instruments contained in the chunk. For version 0001 bbsong files, this must be a value between 0 and 32 inclusive.

The "OrnamentCount=..." property is always followed immediately by a variable-length block of binary data as defined below, followed by the terminating :END +0x00 bytes.
Ornament Data Variable [NumOrn] blocks of pattern data, as defined below.
Terminator 5 bytes ":END" + 0x00

The following Ornament Data block is repeated [NumOrn] times. Internally, Beepola numbers ornaments from 0 to [NumOrn-1]. This is important when matching instrument data to the pattern data.

Ornament Length 4 bytes A 32-bit integer value containing the length of the ornament. Intel byte ordering is used.
Ornament Data [Ornament Length] bytes Ornament data. Consists of note offsets from the the root note (for example, the three bytes 0,4,7) specify an major chord (root note, root note + 4 semitones, root note + 7 semitones). If the ornament is looped, the final byte of the data must have bit 7 set (e.g. $00,$04,$87 for a looped major chord).

:SVGPATTERNDATA Chunk

This chunk holds additional pattern data to be used alongside the standard :PATTERNDATA chunk for songs using the Savage engine, containing data for four effects per channel: Glissando, Skew, SkewXOR, and Ornament. The number of patterns in this chunk should usually match the number of patterns in the :PATTERNDATA chunk, but this does not have to be the case for the file to be valid (if a file contains fewer SVGPATTERNDATA chunks than PATTERNDATA chunks, the missing SVGPATTERNDATA chunks should be assumed to be empty).

Chunk ID 16 bytes ":SVGPATTERNDATA" + 0x00
Pattern Count Variable, null-terminated "PatternCount=[NumPatterns]" + 0x00

[NumPatterns] is an ASCII string representation of the total number of patterns contained in the chunk. For version 0001 bbsong files, this must be a value between 0 and 256.

The "PatternCount=..." property is always followed immediately by a variable-length block of binary data as defined below, followed by the terminating :END +0x00 bytes.
Savage Pattern Data Variable [NumPatterns] blocks of Savage pattern data, as defined below.
Terminator 5 bytes ":END" + 0x00

The following Savage Pattern Data block is repeated [NumPatterns] times. Internally, Beepola numbers patterns from 0 to [NumPatterns-1]. This is important when matching pattern data to the song layout contained in the :LAYOUT chunk.

Pattern Length 4 bytes A 32-bit integer value containing the length of the pattern. Intel byte ordering is used.
Channel 1 Glissando Data [Pattern Length] bytes * 2 The glissando data for channel 1. This consists of [Pattern Length] 16-bit words (Intel Byte Ordering). Values between 0 and 255 indicate a glissando entry for the row. A value of 256 ($0100 in hex) indicates no glissando value for the row. Values greater than 256 are reserved for future use and should be ignored.
Channel 2 Glissando Data [Pattern Length] bytes * 2 As above, but for channel 2 of the pattern.
Channel 1 Skew Data [Pattern Length] bytes * 2 Skew data for the pattern, in the same format as the glissando data (256 = no skew, 0 - 255 are valid skew values).
Channel 2 Skew Data [Pattern Length] bytes * 2 As above, but for channel 2 of the pattern.
Channel 1 Skew XOR Data [Pattern Length] bytes * 2 Skew XOR data for the pattern, in the same format as the glissando data (256 = no skew, 0 - 255 are valid skew XOR values).
Channel 2 Skew XOR Data [Pattern Length] bytes * 2 As above, but for channel 2 of the pattern.
Channel 1 Ornament Data [Pattern Length] bytes Ornament data for the pattern, in the same format as the glissando data (256 = no skew, 0 - 31 are valid ornament values).
Channel 2 Ornament Data [Pattern Length] bytes * 2 As above, but for channel 2 of the pattern.
     

:SVGWARPDATA Chunk

This chunk holds additional pattern data to be used alongside the standard :PATTERNDATA chunk for songs using the Savage engine, containing data for the "FX" column for each of the two channels.

Chunk ID 13 bytes ":SVGWARPDATA" + 0x00
Pattern Count Variable, null-terminated "PatternCount=[NumPatterns]" + 0x00

[NumPatterns] is an ASCII string representation of the total number of patterns contained in the chunk. For version 0001 bbsong files, this must be a value between 0 and 256.

The "PatternCount=..." property is always followed immediately by a variable-length block of binary data as defined below, followed by the terminating :END +0x00 bytes.
Savage FX Column  Data Variable [NumPatterns] blocks of Savage FX column data, as defined below.
Terminator 5 bytes ":END" + 0x00

The following data block is repeated [NumPatterns] times. Internally, Beepola numbers patterns from 0 to [NumPatterns-1]. This is important when matching pattern data to the song layout contained in the :LAYOUT chunk.

Pattern Length 4 bytes A 32-bit integer value containing the length of the pattern. Intel byte ordering is used.
Channel 1 FX Column Data [Pattern Length] bytes The FX column data for channel 1. This consists of [Pattern Length] bytes of boolean on/off values, cast to bytes, such that a value of 0 specifies that the FX column is "Off" for that row, and 255 specifies that the FX column is "On" for the row.
Channel 2 FX Column Data [Pattern Length] bytes As above, but for channel 2 of the pattern.