Classic MacOS Sound Resource: Go parsing library

Sound resources were introduced in Classic MacOS with the Sound Manager program. They can contain sound commands to generate sounds with given frequencies as well as sampled sound data. They are mostly found in resource forks, but can occasionally appear standalone or embedded in other files.

Application

Sound Manager

KS implementation details

License: MIT

References

This page hosts a formal specification of Classic MacOS Sound Resource 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 Classic MacOS Sound Resource

mac_os_resource_snd.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"
	"io"
)


/**
 * Sound resources were introduced in Classic MacOS with the Sound Manager program.
 * They can contain sound commands to generate sounds with given frequencies as well as sampled sound data.
 * They are mostly found in resource forks, but can occasionally appear standalone or embedded in other files.
 * @see <a href="https://developer.apple.com/library/archive/documentation/mac/pdf/Sound/Sound_Manager.pdf">Source</a>
 */

type MacOsResourceSnd_CmdType int
const (
	MacOsResourceSnd_CmdType__NullCmd MacOsResourceSnd_CmdType = 0
	MacOsResourceSnd_CmdType__QuietCmd MacOsResourceSnd_CmdType = 3
	MacOsResourceSnd_CmdType__FlushCmd MacOsResourceSnd_CmdType = 4
	MacOsResourceSnd_CmdType__ReInitCmd MacOsResourceSnd_CmdType = 5
	MacOsResourceSnd_CmdType__WaitCmd MacOsResourceSnd_CmdType = 10
	MacOsResourceSnd_CmdType__PauseCmd MacOsResourceSnd_CmdType = 11
	MacOsResourceSnd_CmdType__ResumeCmd MacOsResourceSnd_CmdType = 12
	MacOsResourceSnd_CmdType__CallBackCmd MacOsResourceSnd_CmdType = 13
	MacOsResourceSnd_CmdType__SyncCmd MacOsResourceSnd_CmdType = 14
	MacOsResourceSnd_CmdType__EmptyCmd MacOsResourceSnd_CmdType = 15
	MacOsResourceSnd_CmdType__AvailableCmd MacOsResourceSnd_CmdType = 24
	MacOsResourceSnd_CmdType__VersionCmd MacOsResourceSnd_CmdType = 25
	MacOsResourceSnd_CmdType__TotalLoadCmd MacOsResourceSnd_CmdType = 26
	MacOsResourceSnd_CmdType__LoadCmd MacOsResourceSnd_CmdType = 27
	MacOsResourceSnd_CmdType__FreqDurationCmd MacOsResourceSnd_CmdType = 40
	MacOsResourceSnd_CmdType__RestCmd MacOsResourceSnd_CmdType = 41
	MacOsResourceSnd_CmdType__FreqCmd MacOsResourceSnd_CmdType = 42
	MacOsResourceSnd_CmdType__AmpCmd MacOsResourceSnd_CmdType = 43
	MacOsResourceSnd_CmdType__TimbreCmd MacOsResourceSnd_CmdType = 44
	MacOsResourceSnd_CmdType__GetAmpCmd MacOsResourceSnd_CmdType = 45
	MacOsResourceSnd_CmdType__VolumeCmd MacOsResourceSnd_CmdType = 46
	MacOsResourceSnd_CmdType__GetVolumeCmd MacOsResourceSnd_CmdType = 47
	MacOsResourceSnd_CmdType__WaveTableCmd MacOsResourceSnd_CmdType = 60
	MacOsResourceSnd_CmdType__PhaseCmd MacOsResourceSnd_CmdType = 61
	MacOsResourceSnd_CmdType__SoundCmd MacOsResourceSnd_CmdType = 80
	MacOsResourceSnd_CmdType__BufferCmd MacOsResourceSnd_CmdType = 81
	MacOsResourceSnd_CmdType__RateCmd MacOsResourceSnd_CmdType = 82
	MacOsResourceSnd_CmdType__GetRateCmd MacOsResourceSnd_CmdType = 85
)
var values_MacOsResourceSnd_CmdType = map[MacOsResourceSnd_CmdType]struct{}{0: {}, 3: {}, 4: {}, 5: {}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}, 15: {}, 24: {}, 25: {}, 26: {}, 27: {}, 40: {}, 41: {}, 42: {}, 43: {}, 44: {}, 45: {}, 46: {}, 47: {}, 60: {}, 61: {}, 80: {}, 81: {}, 82: {}, 85: {}}
func (v MacOsResourceSnd_CmdType) isDefined() bool {
	_, ok := values_MacOsResourceSnd_CmdType[v]
	return ok
}

type MacOsResourceSnd_CompressionTypeEnum int
const (
	MacOsResourceSnd_CompressionTypeEnum__VariableCompression MacOsResourceSnd_CompressionTypeEnum = -2
	MacOsResourceSnd_CompressionTypeEnum__FixedCompression MacOsResourceSnd_CompressionTypeEnum = -1
	MacOsResourceSnd_CompressionTypeEnum__NotCompressed MacOsResourceSnd_CompressionTypeEnum = 0
	MacOsResourceSnd_CompressionTypeEnum__TwoToOne MacOsResourceSnd_CompressionTypeEnum = 1
	MacOsResourceSnd_CompressionTypeEnum__EightToThree MacOsResourceSnd_CompressionTypeEnum = 2
	MacOsResourceSnd_CompressionTypeEnum__ThreeToOne MacOsResourceSnd_CompressionTypeEnum = 3
	MacOsResourceSnd_CompressionTypeEnum__SixToOne MacOsResourceSnd_CompressionTypeEnum = 4
)
var values_MacOsResourceSnd_CompressionTypeEnum = map[MacOsResourceSnd_CompressionTypeEnum]struct{}{-2: {}, -1: {}, 0: {}, 1: {}, 2: {}, 3: {}, 4: {}}
func (v MacOsResourceSnd_CompressionTypeEnum) isDefined() bool {
	_, ok := values_MacOsResourceSnd_CompressionTypeEnum[v]
	return ok
}

type MacOsResourceSnd_DataType int
const (
	MacOsResourceSnd_DataType__SquareWaveSynth MacOsResourceSnd_DataType = 1
	MacOsResourceSnd_DataType__WaveTableSynth MacOsResourceSnd_DataType = 3
	MacOsResourceSnd_DataType__SampledSynth MacOsResourceSnd_DataType = 5
)
var values_MacOsResourceSnd_DataType = map[MacOsResourceSnd_DataType]struct{}{1: {}, 3: {}, 5: {}}
func (v MacOsResourceSnd_DataType) isDefined() bool {
	_, ok := values_MacOsResourceSnd_DataType[v]
	return ok
}

type MacOsResourceSnd_InitOption int
const (
	MacOsResourceSnd_InitOption__ChanLeft MacOsResourceSnd_InitOption = 2
	MacOsResourceSnd_InitOption__ChanRight MacOsResourceSnd_InitOption = 3
	MacOsResourceSnd_InitOption__NoInterp MacOsResourceSnd_InitOption = 4
	MacOsResourceSnd_InitOption__NoDrop MacOsResourceSnd_InitOption = 8
	MacOsResourceSnd_InitOption__Mono MacOsResourceSnd_InitOption = 128
	MacOsResourceSnd_InitOption__Stereo MacOsResourceSnd_InitOption = 192
	MacOsResourceSnd_InitOption__Mace3 MacOsResourceSnd_InitOption = 768
	MacOsResourceSnd_InitOption__Mace6 MacOsResourceSnd_InitOption = 1024
)
var values_MacOsResourceSnd_InitOption = map[MacOsResourceSnd_InitOption]struct{}{2: {}, 3: {}, 4: {}, 8: {}, 128: {}, 192: {}, 768: {}, 1024: {}}
func (v MacOsResourceSnd_InitOption) isDefined() bool {
	_, ok := values_MacOsResourceSnd_InitOption[v]
	return ok
}

type MacOsResourceSnd_SoundHeaderType int
const (
	MacOsResourceSnd_SoundHeaderType__Standard MacOsResourceSnd_SoundHeaderType = 0
	MacOsResourceSnd_SoundHeaderType__Compressed MacOsResourceSnd_SoundHeaderType = 254
	MacOsResourceSnd_SoundHeaderType__Extended MacOsResourceSnd_SoundHeaderType = 255
)
var values_MacOsResourceSnd_SoundHeaderType = map[MacOsResourceSnd_SoundHeaderType]struct{}{0: {}, 254: {}, 255: {}}
func (v MacOsResourceSnd_SoundHeaderType) isDefined() bool {
	_, ok := values_MacOsResourceSnd_SoundHeaderType[v]
	return ok
}

type MacOsResourceSnd_WaveInitOption int
const (
	MacOsResourceSnd_WaveInitOption__Channel0 MacOsResourceSnd_WaveInitOption = 4
	MacOsResourceSnd_WaveInitOption__Channel1 MacOsResourceSnd_WaveInitOption = 5
	MacOsResourceSnd_WaveInitOption__Channel2 MacOsResourceSnd_WaveInitOption = 6
	MacOsResourceSnd_WaveInitOption__Channel3 MacOsResourceSnd_WaveInitOption = 7
)
var values_MacOsResourceSnd_WaveInitOption = map[MacOsResourceSnd_WaveInitOption]struct{}{4: {}, 5: {}, 6: {}, 7: {}}
func (v MacOsResourceSnd_WaveInitOption) isDefined() bool {
	_, ok := values_MacOsResourceSnd_WaveInitOption[v]
	return ok
}
type MacOsResourceSnd struct {
	Format uint16
	NumDataFormats uint16
	DataFormats []*MacOsResourceSnd_DataFormat
	ReferenceCount uint16
	NumSoundCommands uint16
	SoundCommands []*MacOsResourceSnd_SoundCommand
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent kaitai.Struct
	_f_midiNoteToFrequency bool
	midiNoteToFrequency []float64
}
func NewMacOsResourceSnd() *MacOsResourceSnd {
	return &MacOsResourceSnd{
	}
}

func (this MacOsResourceSnd) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd) Read(io *kaitai.Stream, parent kaitai.Struct, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp1, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Format = uint16(tmp1)
	if (this.Format == 1) {
		tmp2, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.NumDataFormats = uint16(tmp2)
	}
	if (this.Format == 1) {
		for i := 0; i < int(this.NumDataFormats); i++ {
			_ = i
			tmp3 := NewMacOsResourceSnd_DataFormat()
			err = tmp3.Read(this._io, this, this._root)
			if err != nil {
				return err
			}
			this.DataFormats = append(this.DataFormats, tmp3)
		}
	}
	if (this.Format == 2) {
		tmp4, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.ReferenceCount = uint16(tmp4)
	}
	tmp5, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.NumSoundCommands = uint16(tmp5)
	for i := 0; i < int(this.NumSoundCommands); i++ {
		_ = i
		tmp6 := NewMacOsResourceSnd_SoundCommand()
		err = tmp6.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.SoundCommands = append(this.SoundCommands, tmp6)
	}
	return err
}

/**
 * Lookup table to convert a MIDI note into a frequency in Hz
 * The lookup table represents the formula (2 ** ((midi_note - 69) / 12)) * 440
 * @see <a href="https://en.wikipedia.org/wiki/MIDI_tuning_standard">Source</a>
 */
func (this *MacOsResourceSnd) MidiNoteToFrequency() (v []float64, err error) {
	if (this._f_midiNoteToFrequency) {
		return this.midiNoteToFrequency, nil
	}
	this._f_midiNoteToFrequency = true
	this.midiNoteToFrequency = []float64([]float64{8.18, 8.66, 9.18, 9.72, 10.30, 10.91, 11.56, 12.25, 12.98, 13.75, 14.57, 15.43, 16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.50, 25.96, 27.50, 29.14, 30.87, 32.70, 34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00, 58.27, 61.74, 65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47, 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77, 1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760.00, 1864.66, 1975.53, 2093.00, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520.00, 3729.31, 3951.07, 4186.01, 4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040.00, 7458.62, 7902.13, 8372.02, 8869.84, 9397.27, 9956.06, 10548.08, 11175.30, 11839.82, 12543.85})
	return this.midiNoteToFrequency, nil
}
type MacOsResourceSnd_Compressed struct {
	Format string
	Reserved []byte
	StateVarsPtr uint32
	LeftOverSamplesPtr uint32
	CompressionId int16
	PacketSize uint16
	SynthesizerId uint16
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent *MacOsResourceSnd_ExtendedOrCompressed
	_f_compressionType bool
	compressionType MacOsResourceSnd_CompressionTypeEnum
}
func NewMacOsResourceSnd_Compressed() *MacOsResourceSnd_Compressed {
	return &MacOsResourceSnd_Compressed{
	}
}

func (this MacOsResourceSnd_Compressed) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd_Compressed) Read(io *kaitai.Stream, parent *MacOsResourceSnd_ExtendedOrCompressed, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp7, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp7 = tmp7
	this.Format = string(tmp7)
	tmp8, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp8 = tmp8
	this.Reserved = tmp8
	tmp9, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.StateVarsPtr = uint32(tmp9)
	tmp10, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LeftOverSamplesPtr = uint32(tmp10)
	tmp11, err := this._io.ReadS2be()
	if err != nil {
		return err
	}
	this.CompressionId = int16(tmp11)
	tmp12, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.PacketSize = uint16(tmp12)
	tmp13, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.SynthesizerId = uint16(tmp13)
	return err
}
func (this *MacOsResourceSnd_Compressed) CompressionType() (v MacOsResourceSnd_CompressionTypeEnum, err error) {
	if (this._f_compressionType) {
		return this.compressionType, nil
	}
	this._f_compressionType = true
	this.compressionType = MacOsResourceSnd_CompressionTypeEnum(MacOsResourceSnd_CompressionTypeEnum(this.CompressionId))
	return this.compressionType, nil
}

/**
 * data format type
 */

/**
 * pointer to StateBlock
 */

/**
 * pointer to LeftOverBlock
 */

/**
 * ID of compression algorithm
 */

/**
 * number of bits per packet
 */

/**
 * Latest Sound Manager documentation specifies this field as:
 * This field is unused. You should set it to 0.
 * Inside Macintosh (Volume VI, 1991) specifies it as:
 * Indicates the resource ID number of the 'snth' resource that was used to compress the packets contained in the compressed sound header.
 * @see <a href="https://vintageapple.org/inside_o/pdf/Inside_Macintosh_Volume_VI_1991.pdf">Page 22-49, absolute page number 1169 in the PDF</a>
 */
type MacOsResourceSnd_DataFormat struct {
	Id MacOsResourceSnd_DataType
	Options uint32
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent *MacOsResourceSnd
	_f_compInit bool
	compInit MacOsResourceSnd_InitOption
	_f_initCompMask bool
	initCompMask int
	_f_initPanMask bool
	initPanMask int8
	_f_initStereoMask bool
	initStereoMask uint8
	_f_panInit bool
	panInit MacOsResourceSnd_InitOption
	_f_stereoInit bool
	stereoInit MacOsResourceSnd_InitOption
	_f_waveInit bool
	waveInit MacOsResourceSnd_WaveInitOption
	_f_waveInitChannelMask bool
	waveInitChannelMask int8
}
func NewMacOsResourceSnd_DataFormat() *MacOsResourceSnd_DataFormat {
	return &MacOsResourceSnd_DataFormat{
	}
}

func (this MacOsResourceSnd_DataFormat) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd_DataFormat) Read(io *kaitai.Stream, parent *MacOsResourceSnd, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp14, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Id = MacOsResourceSnd_DataType(tmp14)
	tmp15, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Options = uint32(tmp15)
	return err
}
func (this *MacOsResourceSnd_DataFormat) CompInit() (v MacOsResourceSnd_InitOption, err error) {
	if (this._f_compInit) {
		return this.compInit, nil
	}
	this._f_compInit = true
	tmp16, err := this.InitCompMask()
	if err != nil {
		return nil, err
	}
	this.compInit = MacOsResourceSnd_InitOption(MacOsResourceSnd_InitOption(this.Options & tmp16))
	return this.compInit, nil
}

/**
 * mask for compression IDs
 */
func (this *MacOsResourceSnd_DataFormat) InitCompMask() (v int, err error) {
	if (this._f_initCompMask) {
		return this.initCompMask, nil
	}
	this._f_initCompMask = true
	this.initCompMask = int(65280)
	return this.initCompMask, nil
}

/**
 * mask for right/left pan values
 */
func (this *MacOsResourceSnd_DataFormat) InitPanMask() (v int8, err error) {
	if (this._f_initPanMask) {
		return this.initPanMask, nil
	}
	this._f_initPanMask = true
	this.initPanMask = int8(3)
	return this.initPanMask, nil
}

/**
 * mask for mono/stereo values
 */
func (this *MacOsResourceSnd_DataFormat) InitStereoMask() (v uint8, err error) {
	if (this._f_initStereoMask) {
		return this.initStereoMask, nil
	}
	this._f_initStereoMask = true
	this.initStereoMask = uint8(192)
	return this.initStereoMask, nil
}
func (this *MacOsResourceSnd_DataFormat) PanInit() (v MacOsResourceSnd_InitOption, err error) {
	if (this._f_panInit) {
		return this.panInit, nil
	}
	this._f_panInit = true
	tmp17, err := this.InitPanMask()
	if err != nil {
		return nil, err
	}
	this.panInit = MacOsResourceSnd_InitOption(MacOsResourceSnd_InitOption(this.Options & tmp17))
	return this.panInit, nil
}
func (this *MacOsResourceSnd_DataFormat) StereoInit() (v MacOsResourceSnd_InitOption, err error) {
	if (this._f_stereoInit) {
		return this.stereoInit, nil
	}
	this._f_stereoInit = true
	tmp18, err := this.InitStereoMask()
	if err != nil {
		return nil, err
	}
	this.stereoInit = MacOsResourceSnd_InitOption(MacOsResourceSnd_InitOption(this.Options & tmp18))
	return this.stereoInit, nil
}
func (this *MacOsResourceSnd_DataFormat) WaveInit() (v MacOsResourceSnd_WaveInitOption, err error) {
	if (this._f_waveInit) {
		return this.waveInit, nil
	}
	this._f_waveInit = true
	if (this.Id == MacOsResourceSnd_DataType__WaveTableSynth) {
		tmp19, err := this.WaveInitChannelMask()
		if err != nil {
			return nil, err
		}
		this.waveInit = MacOsResourceSnd_WaveInitOption(MacOsResourceSnd_WaveInitOption(this.Options & tmp19))
	}
	return this.waveInit, nil
}

/**
 * wave table only, Sound Manager 2.0 and earlier
 */
func (this *MacOsResourceSnd_DataFormat) WaveInitChannelMask() (v int8, err error) {
	if (this._f_waveInitChannelMask) {
		return this.waveInitChannelMask, nil
	}
	this._f_waveInitChannelMask = true
	this.waveInitChannelMask = int8(7)
	return this.waveInitChannelMask, nil
}

/**
 * contains initialisation options for the SndNewChannel function
 */
type MacOsResourceSnd_Extended struct {
	InstrumentChunkPtr uint32
	AesRecordingPtr uint32
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent *MacOsResourceSnd_ExtendedOrCompressed
}
func NewMacOsResourceSnd_Extended() *MacOsResourceSnd_Extended {
	return &MacOsResourceSnd_Extended{
	}
}

func (this MacOsResourceSnd_Extended) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd_Extended) Read(io *kaitai.Stream, parent *MacOsResourceSnd_ExtendedOrCompressed, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp20, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.InstrumentChunkPtr = uint32(tmp20)
	tmp21, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.AesRecordingPtr = uint32(tmp21)
	return err
}

/**
 * pointer to instrument info
 */

/**
 * pointer to audio info
 */
type MacOsResourceSnd_ExtendedOrCompressed struct {
	NumFrames uint32
	AiffSampleRate []byte
	MarkerChunk uint32
	Extended *MacOsResourceSnd_Extended
	Compressed *MacOsResourceSnd_Compressed
	BitsPerSample uint16
	Reserved []byte
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent *MacOsResourceSnd_SoundHeader
}
func NewMacOsResourceSnd_ExtendedOrCompressed() *MacOsResourceSnd_ExtendedOrCompressed {
	return &MacOsResourceSnd_ExtendedOrCompressed{
	}
}

func (this MacOsResourceSnd_ExtendedOrCompressed) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd_ExtendedOrCompressed) Read(io *kaitai.Stream, parent *MacOsResourceSnd_SoundHeader, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp22, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumFrames = uint32(tmp22)
	tmp23, err := this._io.ReadBytes(int(10))
	if err != nil {
		return err
	}
	tmp23 = tmp23
	this.AiffSampleRate = tmp23
	tmp24, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.MarkerChunk = uint32(tmp24)
	tmp25, err := this._parent.SoundHeaderType()
	if err != nil {
		return err
	}
	if (tmp25 == MacOsResourceSnd_SoundHeaderType__Extended) {
		tmp26 := NewMacOsResourceSnd_Extended()
		err = tmp26.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Extended = tmp26
	}
	tmp27, err := this._parent.SoundHeaderType()
	if err != nil {
		return err
	}
	if (tmp27 == MacOsResourceSnd_SoundHeaderType__Compressed) {
		tmp28 := NewMacOsResourceSnd_Compressed()
		err = tmp28.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Compressed = tmp28
	}
	tmp29, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.BitsPerSample = uint16(tmp29)
	tmp30, err := this._parent.SoundHeaderType()
	if err != nil {
		return err
	}
	if (tmp30 == MacOsResourceSnd_SoundHeaderType__Extended) {
		tmp31, err := this._io.ReadBytes(int(14))
		if err != nil {
			return err
		}
		tmp31 = tmp31
		this.Reserved = tmp31
	}
	return err
}

/**
 * rate of original sample (Extended80)
 */

/**
 * reserved
 */

/**
 * number of bits per sample
 */

/**
 * reserved
 */
type MacOsResourceSnd_SoundCommand struct {
	IsDataOffset bool
	Cmd MacOsResourceSnd_CmdType
	Param1 uint16
	Param2 uint32
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent *MacOsResourceSnd
	_f_soundHeader bool
	soundHeader *MacOsResourceSnd_SoundHeader
}
func NewMacOsResourceSnd_SoundCommand() *MacOsResourceSnd_SoundCommand {
	return &MacOsResourceSnd_SoundCommand{
	}
}

func (this MacOsResourceSnd_SoundCommand) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd_SoundCommand) Read(io *kaitai.Stream, parent *MacOsResourceSnd, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp32, err := this._io.ReadBitsIntBe(1)
	if err != nil {
		return err
	}
	this.IsDataOffset = tmp32 != 0
	tmp33, err := this._io.ReadBitsIntBe(15)
	if err != nil {
		return err
	}
	this.Cmd = MacOsResourceSnd_CmdType(tmp33)
	this._io.AlignToByte()
	tmp34, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Param1 = uint16(tmp34)
	tmp35, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Param2 = uint32(tmp35)
	return err
}
func (this *MacOsResourceSnd_SoundCommand) SoundHeader() (v *MacOsResourceSnd_SoundHeader, err error) {
	if (this._f_soundHeader) {
		return this.soundHeader, nil
	}
	this._f_soundHeader = true
	if ( ((this.IsDataOffset) && (this.Cmd == MacOsResourceSnd_CmdType__BufferCmd)) ) {
		_pos, err := this._io.Pos()
		if err != nil {
			return nil, err
		}
		_, err = this._io.Seek(int64(this.Param2), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp36 := NewMacOsResourceSnd_SoundHeader()
		err = tmp36.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.soundHeader = tmp36
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.soundHeader, nil
}
type MacOsResourceSnd_SoundHeader struct {
	_unnamed0 []byte
	SamplePtr uint32
	NumSamples uint32
	NumChannels uint32
	SampleRate *MacOsResourceSnd_UnsignedFixedPoint
	LoopStart uint32
	LoopEnd uint32
	Encode MacOsResourceSnd_SoundHeaderType
	MidiNote uint8
	ExtendedOrCompressed *MacOsResourceSnd_ExtendedOrCompressed
	SampleArea []byte
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent *MacOsResourceSnd_SoundCommand
	_f_baseFreqeuncy bool
	baseFreqeuncy float64
	_f_soundHeaderType bool
	soundHeaderType MacOsResourceSnd_SoundHeaderType
	_f_startOfs bool
	startOfs int
}
func NewMacOsResourceSnd_SoundHeader() *MacOsResourceSnd_SoundHeader {
	return &MacOsResourceSnd_SoundHeader{
	}
}

func (this MacOsResourceSnd_SoundHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd_SoundHeader) Read(io *kaitai.Stream, parent *MacOsResourceSnd_SoundCommand, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp37, err := this.StartOfs()
	if err != nil {
		return err
	}
	if (tmp37 < 0) {
		tmp38, err := this._io.ReadBytes(int(0))
		if err != nil {
			return err
		}
		tmp38 = tmp38
		this._unnamed0 = tmp38
	}
	tmp39, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SamplePtr = uint32(tmp39)
	tmp40, err := this.SoundHeaderType()
	if err != nil {
		return err
	}
	if (tmp40 == MacOsResourceSnd_SoundHeaderType__Standard) {
		tmp41, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.NumSamples = uint32(tmp41)
	}
	tmp42, err := this.SoundHeaderType()
	if err != nil {
		return err
	}
	tmp43, err := this.SoundHeaderType()
	if err != nil {
		return err
	}
	if ( ((tmp42 == MacOsResourceSnd_SoundHeaderType__Extended) || (tmp43 == MacOsResourceSnd_SoundHeaderType__Compressed)) ) {
		tmp44, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.NumChannels = uint32(tmp44)
	}
	tmp45 := NewMacOsResourceSnd_UnsignedFixedPoint()
	err = tmp45.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.SampleRate = tmp45
	tmp46, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LoopStart = uint32(tmp46)
	tmp47, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LoopEnd = uint32(tmp47)
	tmp48, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Encode = MacOsResourceSnd_SoundHeaderType(tmp48)
	tmp49, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.MidiNote = tmp49
	tmp50, err := this.SoundHeaderType()
	if err != nil {
		return err
	}
	tmp51, err := this.SoundHeaderType()
	if err != nil {
		return err
	}
	if ( ((tmp50 == MacOsResourceSnd_SoundHeaderType__Extended) || (tmp51 == MacOsResourceSnd_SoundHeaderType__Compressed)) ) {
		tmp52 := NewMacOsResourceSnd_ExtendedOrCompressed()
		err = tmp52.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.ExtendedOrCompressed = tmp52
	}
	if (this.SamplePtr == 0) {
		var tmp53 uint32;
		tmp54, err := this.SoundHeaderType()
		if err != nil {
			return err
		}
		if (tmp54 == MacOsResourceSnd_SoundHeaderType__Standard) {
			tmp53 = this.NumSamples
		} else {
			var tmp55 int;
			tmp56, err := this.SoundHeaderType()
			if err != nil {
				return err
			}
			if (tmp56 == MacOsResourceSnd_SoundHeaderType__Extended) {
				tmp55 = ((this.ExtendedOrCompressed.NumFrames * this.NumChannels) * this.ExtendedOrCompressed.BitsPerSample) / 8
			} else {
				tmp57, err := this._io.Size()
				if err != nil {
					return err
				}
				tmp58, err := this._io.Pos()
				if err != nil {
					return err
				}
				tmp55 = tmp57 - tmp58
			}
			tmp53 = tmp55
		}
		tmp59, err := this._io.ReadBytes(int(tmp53))
		if err != nil {
			return err
		}
		tmp59 = tmp59
		this.SampleArea = tmp59
	}
	return err
}

/**
 * base frequency of sample in Hz
 * Calculated with the formula (2 ** ((midi_note - 69) / 12)) * 440
 * @see <a href="https://en.wikipedia.org/wiki/MIDI_tuning_standard">Source</a>
 */
func (this *MacOsResourceSnd_SoundHeader) BaseFreqeuncy() (v float64, err error) {
	if (this._f_baseFreqeuncy) {
		return this.baseFreqeuncy, nil
	}
	this._f_baseFreqeuncy = true
	if ( ((this.MidiNote >= 0) && (this.MidiNote < 128)) ) {
		tmp60, err := this._root.MidiNoteToFrequency()
		if err != nil {
			return 0, err
		}
		this.baseFreqeuncy = float64(tmp60[this.MidiNote])
	}
	return this.baseFreqeuncy, nil
}
func (this *MacOsResourceSnd_SoundHeader) SoundHeaderType() (v MacOsResourceSnd_SoundHeaderType, err error) {
	if (this._f_soundHeaderType) {
		return this.soundHeaderType, nil
	}
	this._f_soundHeaderType = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	tmp61, err := this.StartOfs()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(tmp61 + 20), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp62, err := this._io.ReadU1()
	if err != nil {
		return nil, err
	}
	this.soundHeaderType = MacOsResourceSnd_SoundHeaderType(tmp62)
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.soundHeaderType, nil
}
func (this *MacOsResourceSnd_SoundHeader) StartOfs() (v int, err error) {
	if (this._f_startOfs) {
		return this.startOfs, nil
	}
	this._f_startOfs = true
	tmp63, err := this._io.Pos()
	if err != nil {
		return 0, err
	}
	this.startOfs = int(tmp63)
	return this.startOfs, nil
}

/**
 * pointer to samples (or 0 if samples follow data structure)
 */

/**
 * number of samples
 */

/**
 * number of channels in sample
 */

/**
 * The rate at which the sample was originally recorded.
 */

/**
 * loop point beginning
 */

/**
 * loop point ending
 */

/**
 * sample's encoding option
 */

/**
 * base frequency of sample, expressed as MIDI note values, 60 is middle C
 */

/**
 * sampled-sound data
 */
type MacOsResourceSnd_UnsignedFixedPoint struct {
	IntegerPart uint16
	FractionPart uint16
	_io *kaitai.Stream
	_root *MacOsResourceSnd
	_parent *MacOsResourceSnd_SoundHeader
	_f_value bool
	value float64
}
func NewMacOsResourceSnd_UnsignedFixedPoint() *MacOsResourceSnd_UnsignedFixedPoint {
	return &MacOsResourceSnd_UnsignedFixedPoint{
	}
}

func (this MacOsResourceSnd_UnsignedFixedPoint) IO_() *kaitai.Stream {
	return this._io
}

func (this *MacOsResourceSnd_UnsignedFixedPoint) Read(io *kaitai.Stream, parent *MacOsResourceSnd_SoundHeader, root *MacOsResourceSnd) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp64, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.IntegerPart = uint16(tmp64)
	tmp65, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.FractionPart = uint16(tmp65)
	return err
}
func (this *MacOsResourceSnd_UnsignedFixedPoint) Value() (v float64, err error) {
	if (this._f_value) {
		return this.value, nil
	}
	this._f_value = true
	this.value = float64(this.IntegerPart + this.FractionPart / 65535.0)
	return this.value, nil
}