*.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. |