XM (standing for eXtended Module) is a popular module music file format, that was introduced in 1994 in FastTracker2 by Triton demo group. Akin to MOD files, it bundles both digital samples (instruments) and instructions on which note to play at what time (patterns), which provides good audio quality with relatively small file size. Audio is reproducible without relying on the sound of particular hardware samplers or synths.
This page hosts a formal specification of Extended Module using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import (
"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
"bytes"
)
/**
* XM (standing for eXtended Module) is a popular module music file
* format, that was introduced in 1994 in FastTracker2 by Triton demo
* group. Akin to MOD files, it bundles both digital samples
* (instruments) and instructions on which note to play at what time
* (patterns), which provides good audio quality with relatively small
* file size. Audio is reproducible without relying on the sound of
* particular hardware samplers or synths.
* @see <a href="http://sid.ethz.ch/debian/milkytracker/milkytracker-0.90.85%2Bdfsg/resources/reference/xm-form.txt
* ftp://ftp.modland.com/pub/documents/format_documentation/FastTracker%202%20v2.04%20(.xm).html
* ">Source</a>
*/
type FasttrackerXmModule struct {
Preheader *FasttrackerXmModule_Preheader
Header *FasttrackerXmModule_Header
Patterns []*FasttrackerXmModule_Pattern
Instruments []*FasttrackerXmModule_Instrument
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent kaitai.Struct
_raw_Header []byte
}
func NewFasttrackerXmModule() *FasttrackerXmModule {
return &FasttrackerXmModule{
}
}
func (this FasttrackerXmModule) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule) Read(io *kaitai.Stream, parent kaitai.Struct, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1 := NewFasttrackerXmModule_Preheader()
err = tmp1.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Preheader = tmp1
tmp2, err := this._io.ReadBytes(int(this.Preheader.HeaderSize - 4))
if err != nil {
return err
}
tmp2 = tmp2
this._raw_Header = tmp2
_io__raw_Header := kaitai.NewStream(bytes.NewReader(this._raw_Header))
tmp3 := NewFasttrackerXmModule_Header()
err = tmp3.Read(_io__raw_Header, this, this._root)
if err != nil {
return err
}
this.Header = tmp3
for i := 0; i < int(this.Header.NumPatterns); i++ {
_ = i
tmp4 := NewFasttrackerXmModule_Pattern()
err = tmp4.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Patterns = append(this.Patterns, tmp4)
}
for i := 0; i < int(this.Header.NumInstruments); i++ {
_ = i
tmp5 := NewFasttrackerXmModule_Instrument()
err = tmp5.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Instruments = append(this.Instruments, tmp5)
}
return err
}
type FasttrackerXmModule_Flags struct {
Reserved uint64
FreqTableType bool
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Header
}
func NewFasttrackerXmModule_Flags() *FasttrackerXmModule_Flags {
return &FasttrackerXmModule_Flags{
}
}
func (this FasttrackerXmModule_Flags) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Flags) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Header, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp6, err := this._io.ReadBitsIntBe(15)
if err != nil {
return err
}
this.Reserved = tmp6
tmp7, err := this._io.ReadBitsIntBe(1)
if err != nil {
return err
}
this.FreqTableType = tmp7 != 0
return err
}
/**
* 0 = Amiga frequency table (see below); 1 = Linear frequency table
*/
type FasttrackerXmModule_Header struct {
SongLength uint16
RestartPosition uint16
NumChannels uint16
NumPatterns uint16
NumInstruments uint16
Flags *FasttrackerXmModule_Flags
DefaultTempo uint16
DefaultBpm uint16
PatternOrderTable []uint8
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule
}
func NewFasttrackerXmModule_Header() *FasttrackerXmModule_Header {
return &FasttrackerXmModule_Header{
}
}
func (this FasttrackerXmModule_Header) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Header) Read(io *kaitai.Stream, parent *FasttrackerXmModule, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp8, err := this._io.ReadU2le()
if err != nil {
return err
}
this.SongLength = uint16(tmp8)
tmp9, err := this._io.ReadU2le()
if err != nil {
return err
}
this.RestartPosition = uint16(tmp9)
tmp10, err := this._io.ReadU2le()
if err != nil {
return err
}
this.NumChannels = uint16(tmp10)
tmp11, err := this._io.ReadU2le()
if err != nil {
return err
}
this.NumPatterns = uint16(tmp11)
tmp12, err := this._io.ReadU2le()
if err != nil {
return err
}
this.NumInstruments = uint16(tmp12)
tmp13 := NewFasttrackerXmModule_Flags()
err = tmp13.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Flags = tmp13
tmp14, err := this._io.ReadU2le()
if err != nil {
return err
}
this.DefaultTempo = uint16(tmp14)
tmp15, err := this._io.ReadU2le()
if err != nil {
return err
}
this.DefaultBpm = uint16(tmp15)
for i := 0; i < int(256); i++ {
_ = i
tmp16, err := this._io.ReadU1()
if err != nil {
return err
}
this.PatternOrderTable = append(this.PatternOrderTable, tmp16)
}
return err
}
/**
* Song length (in pattern order table)
*/
/**
* (2,4,6,8,10,...,32)
*/
/**
* (max 256)
*/
/**
* (max 128)
*/
/**
* max 256
*/
/**
* XM's notion of "instrument" typically constitutes of a
* instrument metadata and one or several samples. Metadata
* includes:
*
* * instrument's name
* * instruction of which sample to use for which note
* * volume and panning envelopes and looping instructions
* * vibrato settings
*/
type FasttrackerXmModule_Instrument struct {
HeaderSize uint32
Header *FasttrackerXmModule_Instrument_Header
SamplesHeaders []*FasttrackerXmModule_Instrument_SampleHeader
Samples []*FasttrackerXmModule_Instrument_SamplesData
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule
_raw_Header []byte
}
func NewFasttrackerXmModule_Instrument() *FasttrackerXmModule_Instrument {
return &FasttrackerXmModule_Instrument{
}
}
func (this FasttrackerXmModule_Instrument) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Instrument) Read(io *kaitai.Stream, parent *FasttrackerXmModule, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp17, err := this._io.ReadU4le()
if err != nil {
return err
}
this.HeaderSize = uint32(tmp17)
tmp18, err := this._io.ReadBytes(int(this.HeaderSize - 4))
if err != nil {
return err
}
tmp18 = tmp18
this._raw_Header = tmp18
_io__raw_Header := kaitai.NewStream(bytes.NewReader(this._raw_Header))
tmp19 := NewFasttrackerXmModule_Instrument_Header()
err = tmp19.Read(_io__raw_Header, this, this._root)
if err != nil {
return err
}
this.Header = tmp19
for i := 0; i < int(this.Header.NumSamples); i++ {
_ = i
tmp20 := NewFasttrackerXmModule_Instrument_SampleHeader()
err = tmp20.Read(this._io, this, this._root)
if err != nil {
return err
}
this.SamplesHeaders = append(this.SamplesHeaders, tmp20)
}
for i := 0; i < int(this.Header.NumSamples); i++ {
_ = i
tmp21 := NewFasttrackerXmModule_Instrument_SamplesData(this.SamplesHeaders[i])
err = tmp21.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Samples = append(this.Samples, tmp21)
}
return err
}
/**
* Instrument size << header that is >>
* << "Instrument Size" field tends to be more than the actual size of the structure documented here (it includes also the extended instrument sample header above). So remember to check it and skip the additional bytes before the first sample header >>
*/
type FasttrackerXmModule_Instrument_ExtraHeader_Type int
const (
FasttrackerXmModule_Instrument_ExtraHeader_Type__True FasttrackerXmModule_Instrument_ExtraHeader_Type = 0
FasttrackerXmModule_Instrument_ExtraHeader_Type__Sustain FasttrackerXmModule_Instrument_ExtraHeader_Type = 1
FasttrackerXmModule_Instrument_ExtraHeader_Type__Loop FasttrackerXmModule_Instrument_ExtraHeader_Type = 2
)
var values_FasttrackerXmModule_Instrument_ExtraHeader_Type = map[FasttrackerXmModule_Instrument_ExtraHeader_Type]struct{}{0: {}, 1: {}, 2: {}}
func (v FasttrackerXmModule_Instrument_ExtraHeader_Type) isDefined() bool {
_, ok := values_FasttrackerXmModule_Instrument_ExtraHeader_Type[v]
return ok
}
type FasttrackerXmModule_Instrument_ExtraHeader struct {
LenSampleHeader uint32
IdxSamplePerNote []uint8
VolumePoints []*FasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint
PanningPoints []*FasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint
NumVolumePoints uint8
NumPanningPoints uint8
VolumeSustainPoint uint8
VolumeLoopStartPoint uint8
VolumeLoopEndPoint uint8
PanningSustainPoint uint8
PanningLoopStartPoint uint8
PanningLoopEndPoint uint8
VolumeType FasttrackerXmModule_Instrument_ExtraHeader_Type
PanningType FasttrackerXmModule_Instrument_ExtraHeader_Type
VibratoType uint8
VibratoSweep uint8
VibratoDepth uint8
VibratoRate uint8
VolumeFadeout uint16
Reserved uint16
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Instrument_Header
}
func NewFasttrackerXmModule_Instrument_ExtraHeader() *FasttrackerXmModule_Instrument_ExtraHeader {
return &FasttrackerXmModule_Instrument_ExtraHeader{
}
}
func (this FasttrackerXmModule_Instrument_ExtraHeader) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Instrument_ExtraHeader) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Instrument_Header, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp22, err := this._io.ReadU4le()
if err != nil {
return err
}
this.LenSampleHeader = uint32(tmp22)
for i := 0; i < int(96); i++ {
_ = i
tmp23, err := this._io.ReadU1()
if err != nil {
return err
}
this.IdxSamplePerNote = append(this.IdxSamplePerNote, tmp23)
}
for i := 0; i < int(12); i++ {
_ = i
tmp24 := NewFasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint()
err = tmp24.Read(this._io, this, this._root)
if err != nil {
return err
}
this.VolumePoints = append(this.VolumePoints, tmp24)
}
for i := 0; i < int(12); i++ {
_ = i
tmp25 := NewFasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint()
err = tmp25.Read(this._io, this, this._root)
if err != nil {
return err
}
this.PanningPoints = append(this.PanningPoints, tmp25)
}
tmp26, err := this._io.ReadU1()
if err != nil {
return err
}
this.NumVolumePoints = tmp26
tmp27, err := this._io.ReadU1()
if err != nil {
return err
}
this.NumPanningPoints = tmp27
tmp28, err := this._io.ReadU1()
if err != nil {
return err
}
this.VolumeSustainPoint = tmp28
tmp29, err := this._io.ReadU1()
if err != nil {
return err
}
this.VolumeLoopStartPoint = tmp29
tmp30, err := this._io.ReadU1()
if err != nil {
return err
}
this.VolumeLoopEndPoint = tmp30
tmp31, err := this._io.ReadU1()
if err != nil {
return err
}
this.PanningSustainPoint = tmp31
tmp32, err := this._io.ReadU1()
if err != nil {
return err
}
this.PanningLoopStartPoint = tmp32
tmp33, err := this._io.ReadU1()
if err != nil {
return err
}
this.PanningLoopEndPoint = tmp33
tmp34, err := this._io.ReadU1()
if err != nil {
return err
}
this.VolumeType = FasttrackerXmModule_Instrument_ExtraHeader_Type(tmp34)
tmp35, err := this._io.ReadU1()
if err != nil {
return err
}
this.PanningType = FasttrackerXmModule_Instrument_ExtraHeader_Type(tmp35)
tmp36, err := this._io.ReadU1()
if err != nil {
return err
}
this.VibratoType = tmp36
tmp37, err := this._io.ReadU1()
if err != nil {
return err
}
this.VibratoSweep = tmp37
tmp38, err := this._io.ReadU1()
if err != nil {
return err
}
this.VibratoDepth = tmp38
tmp39, err := this._io.ReadU1()
if err != nil {
return err
}
this.VibratoRate = tmp39
tmp40, err := this._io.ReadU2le()
if err != nil {
return err
}
this.VolumeFadeout = uint16(tmp40)
tmp41, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Reserved = uint16(tmp41)
return err
}
/**
* Index of sample that should be used for any particular
* note. In the simplest case, where it's only one sample
* is available, it's an array of full of zeroes.
*/
/**
* Points for volume envelope. Only `num_volume_points` will be actually used.
*/
/**
* Points for panning envelope. Only `num_panning_points` will be actually used.
*/
/**
* Envelope frame-counters work in range 0..FFFFh (0..65535 dec).
* BUT! FT2 only itself supports only range 0..FFh (0..255 dec).
* Some other trackers (like SoundTracker for Unix), however, can use the full range 0..FFFF, so it should be supported.
* !!TIP: This is also a good way to detect if the module has been made with FT2 or not. (In case the tracker name is brain- deadly left unchanged!)
* Of course it does not help if all instruments have the values inside FT2 supported range.
* The value-field of the envelope point is ranged between 00..3Fh (0..64 dec).
*/
type FasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint struct {
X uint16
Y uint16
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Instrument_ExtraHeader
}
func NewFasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint() *FasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint {
return &FasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint{
}
}
func (this FasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Instrument_ExtraHeader_EnvelopePoint) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Instrument_ExtraHeader, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp42, err := this._io.ReadU2le()
if err != nil {
return err
}
this.X = uint16(tmp42)
tmp43, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Y = uint16(tmp43)
return err
}
/**
* Frame number of the point
*/
/**
* Value of the point
*/
type FasttrackerXmModule_Instrument_Header struct {
Name string
Type uint8
NumSamples uint16
ExtraHeader *FasttrackerXmModule_Instrument_ExtraHeader
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Instrument
}
func NewFasttrackerXmModule_Instrument_Header() *FasttrackerXmModule_Instrument_Header {
return &FasttrackerXmModule_Instrument_Header{
}
}
func (this FasttrackerXmModule_Instrument_Header) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Instrument_Header) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Instrument, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp44, err := this._io.ReadBytes(int(22))
if err != nil {
return err
}
tmp44 = kaitai.BytesTerminate(tmp44, 0, false)
this.Name = string(tmp44)
tmp45, err := this._io.ReadU1()
if err != nil {
return err
}
this.Type = tmp45
tmp46, err := this._io.ReadU2le()
if err != nil {
return err
}
this.NumSamples = uint16(tmp46)
if (this.NumSamples > 0) {
tmp47 := NewFasttrackerXmModule_Instrument_ExtraHeader()
err = tmp47.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ExtraHeader = tmp47
}
return err
}
/**
* Usually zero, but this seems pretty random, don't assume it's zero
*/
type FasttrackerXmModule_Instrument_SampleHeader struct {
SampleLength uint32
SampleLoopStart uint32
SampleLoopLength uint32
Volume uint8
FineTune int8
Type *FasttrackerXmModule_Instrument_SampleHeader_LoopType
Panning uint8
RelativeNoteNumber int8
Reserved uint8
Name string
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Instrument
}
func NewFasttrackerXmModule_Instrument_SampleHeader() *FasttrackerXmModule_Instrument_SampleHeader {
return &FasttrackerXmModule_Instrument_SampleHeader{
}
}
func (this FasttrackerXmModule_Instrument_SampleHeader) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Instrument_SampleHeader) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Instrument, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp48, err := this._io.ReadU4le()
if err != nil {
return err
}
this.SampleLength = uint32(tmp48)
tmp49, err := this._io.ReadU4le()
if err != nil {
return err
}
this.SampleLoopStart = uint32(tmp49)
tmp50, err := this._io.ReadU4le()
if err != nil {
return err
}
this.SampleLoopLength = uint32(tmp50)
tmp51, err := this._io.ReadU1()
if err != nil {
return err
}
this.Volume = tmp51
tmp52, err := this._io.ReadS1()
if err != nil {
return err
}
this.FineTune = tmp52
tmp53 := NewFasttrackerXmModule_Instrument_SampleHeader_LoopType()
err = tmp53.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Type = tmp53
tmp54, err := this._io.ReadU1()
if err != nil {
return err
}
this.Panning = tmp54
tmp55, err := this._io.ReadS1()
if err != nil {
return err
}
this.RelativeNoteNumber = tmp55
tmp56, err := this._io.ReadU1()
if err != nil {
return err
}
this.Reserved = tmp56
tmp57, err := this._io.ReadBytes(int(22))
if err != nil {
return err
}
tmp57 = kaitai.BytesTerminate(tmp57, 0, false)
this.Name = string(tmp57)
return err
}
/**
* -16..+15
*/
/**
* (0-255)
*/
type FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType int
const (
FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType__None FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType = 0
FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType__Forward FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType = 1
FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType__PingPong FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType = 2
)
var values_FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType = map[FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType]struct{}{0: {}, 1: {}, 2: {}}
func (v FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType) isDefined() bool {
_, ok := values_FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType[v]
return ok
}
type FasttrackerXmModule_Instrument_SampleHeader_LoopType struct {
Reserved0 uint64
IsSampleData16Bit bool
Reserved1 uint64
LoopType FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Instrument_SampleHeader
}
func NewFasttrackerXmModule_Instrument_SampleHeader_LoopType() *FasttrackerXmModule_Instrument_SampleHeader_LoopType {
return &FasttrackerXmModule_Instrument_SampleHeader_LoopType{
}
}
func (this FasttrackerXmModule_Instrument_SampleHeader_LoopType) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Instrument_SampleHeader_LoopType) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Instrument_SampleHeader, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp58, err := this._io.ReadBitsIntBe(3)
if err != nil {
return err
}
this.Reserved0 = tmp58
tmp59, err := this._io.ReadBitsIntBe(1)
if err != nil {
return err
}
this.IsSampleData16Bit = tmp59 != 0
tmp60, err := this._io.ReadBitsIntBe(2)
if err != nil {
return err
}
this.Reserved1 = tmp60
tmp61, err := this._io.ReadBitsIntBe(2)
if err != nil {
return err
}
this.LoopType = FasttrackerXmModule_Instrument_SampleHeader_LoopType_LoopType(tmp61)
return err
}
/**
* The saved data uses simple delta-encoding to achieve better compression ratios (when compressed with pkzip, etc.)
* Pseudocode for converting the delta-coded data to normal data,
* old = 0;
* for i in range(data_len):
* new = sample[i] + old;
* sample[i] = new;
* old = new;
*/
type FasttrackerXmModule_Instrument_SamplesData struct {
Data []byte
Header *FasttrackerXmModule_Instrument_SampleHeader
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Instrument
}
func NewFasttrackerXmModule_Instrument_SamplesData(header *FasttrackerXmModule_Instrument_SampleHeader) *FasttrackerXmModule_Instrument_SamplesData {
return &FasttrackerXmModule_Instrument_SamplesData{
Header: header,
}
}
func (this FasttrackerXmModule_Instrument_SamplesData) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Instrument_SamplesData) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Instrument, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
var tmp62 int8;
if (this.Header.Type.IsSampleData16Bit) {
tmp62 = 2
} else {
tmp62 = 1
}
tmp63, err := this._io.ReadBytes(int(this.Header.SampleLength * tmp62))
if err != nil {
return err
}
tmp63 = tmp63
this.Data = tmp63
return err
}
type FasttrackerXmModule_Pattern struct {
Header *FasttrackerXmModule_Pattern_Header
PackedData []byte
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule
}
func NewFasttrackerXmModule_Pattern() *FasttrackerXmModule_Pattern {
return &FasttrackerXmModule_Pattern{
}
}
func (this FasttrackerXmModule_Pattern) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Pattern) Read(io *kaitai.Stream, parent *FasttrackerXmModule, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp64 := NewFasttrackerXmModule_Pattern_Header()
err = tmp64.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Header = tmp64
tmp65, err := this._io.ReadBytes(int(this.Header.Main.LenPackedPattern))
if err != nil {
return err
}
tmp65 = tmp65
this.PackedData = tmp65
return err
}
type FasttrackerXmModule_Pattern_Header struct {
HeaderLength uint32
Main *FasttrackerXmModule_Pattern_Header_HeaderMain
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Pattern
_raw_Main []byte
}
func NewFasttrackerXmModule_Pattern_Header() *FasttrackerXmModule_Pattern_Header {
return &FasttrackerXmModule_Pattern_Header{
}
}
func (this FasttrackerXmModule_Pattern_Header) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Pattern_Header) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Pattern, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp66, err := this._io.ReadU4le()
if err != nil {
return err
}
this.HeaderLength = uint32(tmp66)
tmp67, err := this._io.ReadBytes(int(this.HeaderLength - 4))
if err != nil {
return err
}
tmp67 = tmp67
this._raw_Main = tmp67
_io__raw_Main := kaitai.NewStream(bytes.NewReader(this._raw_Main))
tmp68 := NewFasttrackerXmModule_Pattern_Header_HeaderMain()
err = tmp68.Read(_io__raw_Main, this, this._root)
if err != nil {
return err
}
this.Main = tmp68
return err
}
/**
* Pattern header length
*/
type FasttrackerXmModule_Pattern_Header_HeaderMain struct {
PackingType uint8
NumRowsRaw uint16
LenPackedPattern uint16
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Pattern_Header
_f_numRows bool
numRows int
}
func NewFasttrackerXmModule_Pattern_Header_HeaderMain() *FasttrackerXmModule_Pattern_Header_HeaderMain {
return &FasttrackerXmModule_Pattern_Header_HeaderMain{
}
}
func (this FasttrackerXmModule_Pattern_Header_HeaderMain) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Pattern_Header_HeaderMain) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Pattern_Header, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp69, err := this._io.ReadU1()
if err != nil {
return err
}
this.PackingType = tmp69
tmp70, err := this._root.Preheader.VersionNumber.Value()
if err != nil {
return err
}
switch (tmp70) {
case 258:
tmp71, err := this._io.ReadU1()
if err != nil {
return err
}
this.NumRowsRaw = uint16(tmp71)
default:
tmp72, err := this._io.ReadU2le()
if err != nil {
return err
}
this.NumRowsRaw = uint16(tmp72)
}
tmp73, err := this._io.ReadU2le()
if err != nil {
return err
}
this.LenPackedPattern = uint16(tmp73)
return err
}
func (this *FasttrackerXmModule_Pattern_Header_HeaderMain) NumRows() (v int, err error) {
if (this._f_numRows) {
return this.numRows, nil
}
this._f_numRows = true
var tmp74 int8;
tmp75, err := this._root.Preheader.VersionNumber.Value()
if err != nil {
return 0, err
}
if (tmp75 == 258) {
tmp74 = 1
} else {
tmp74 = 0
}
this.numRows = int(this.NumRowsRaw + tmp74)
return this.numRows, nil
}
/**
* Packing type (always 0)
*/
/**
* Number of rows in pattern (1..256)
*/
/**
* Packed pattern data size
*/
type FasttrackerXmModule_Preheader struct {
Signature0 []byte
ModuleName string
Signature1 []byte
TrackerName string
VersionNumber *FasttrackerXmModule_Preheader_Version
HeaderSize uint32
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule
}
func NewFasttrackerXmModule_Preheader() *FasttrackerXmModule_Preheader {
return &FasttrackerXmModule_Preheader{
}
}
func (this FasttrackerXmModule_Preheader) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Preheader) Read(io *kaitai.Stream, parent *FasttrackerXmModule, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp76, err := this._io.ReadBytes(int(17))
if err != nil {
return err
}
tmp76 = tmp76
this.Signature0 = tmp76
if !(bytes.Equal(this.Signature0, []uint8{69, 120, 116, 101, 110, 100, 101, 100, 32, 77, 111, 100, 117, 108, 101, 58, 32})) {
return kaitai.NewValidationNotEqualError([]uint8{69, 120, 116, 101, 110, 100, 101, 100, 32, 77, 111, 100, 117, 108, 101, 58, 32}, this.Signature0, this._io, "/types/preheader/seq/0")
}
tmp77, err := this._io.ReadBytes(int(20))
if err != nil {
return err
}
tmp77 = kaitai.BytesTerminate(tmp77, 0, false)
this.ModuleName = string(tmp77)
tmp78, err := this._io.ReadBytes(int(1))
if err != nil {
return err
}
tmp78 = tmp78
this.Signature1 = tmp78
if !(bytes.Equal(this.Signature1, []uint8{26})) {
return kaitai.NewValidationNotEqualError([]uint8{26}, this.Signature1, this._io, "/types/preheader/seq/2")
}
tmp79, err := this._io.ReadBytes(int(20))
if err != nil {
return err
}
tmp79 = kaitai.BytesTerminate(tmp79, 0, false)
this.TrackerName = string(tmp79)
tmp80 := NewFasttrackerXmModule_Preheader_Version()
err = tmp80.Read(this._io, this, this._root)
if err != nil {
return err
}
this.VersionNumber = tmp80
tmp81, err := this._io.ReadU4le()
if err != nil {
return err
}
this.HeaderSize = uint32(tmp81)
return err
}
/**
* Module name, padded with zeroes
*/
/**
* Tracker name
*/
/**
* Format versions below [0x01, 0x04] have a LOT of differences. Check this field!
*/
/**
* Header size << Calculated FROM THIS OFFSET, not from the beginning of the file! >>
*/
type FasttrackerXmModule_Preheader_Version struct {
Minor uint8
Major uint8
_io *kaitai.Stream
_root *FasttrackerXmModule
_parent *FasttrackerXmModule_Preheader
_f_value bool
value int
}
func NewFasttrackerXmModule_Preheader_Version() *FasttrackerXmModule_Preheader_Version {
return &FasttrackerXmModule_Preheader_Version{
}
}
func (this FasttrackerXmModule_Preheader_Version) IO_() *kaitai.Stream {
return this._io
}
func (this *FasttrackerXmModule_Preheader_Version) Read(io *kaitai.Stream, parent *FasttrackerXmModule_Preheader, root *FasttrackerXmModule) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp82, err := this._io.ReadU1()
if err != nil {
return err
}
this.Minor = tmp82
tmp83, err := this._io.ReadU1()
if err != nil {
return err
}
this.Major = tmp83
return err
}
func (this *FasttrackerXmModule_Preheader_Version) Value() (v int, err error) {
if (this._f_value) {
return this.value, nil
}
this._f_value = true
this.value = int(this.Major << 8 | this.Minor)
return this.value, nil
}
/**
* currently 0x04
*/
/**
* currently 0x01
*/