Extended Module: Go parsing library

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.

Application

["FastTracker 2", "Protracker", "MilkyTracker", "libmodplug", "Mikmod"]

File extension

xm

KS implementation details

License: Unlicense

References

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.

Go source code to parse Extended Module

fasttracker_xm_module.go

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