Classic MacOS Sound Resource: C++11/STL 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.

Usage

Runtime library

All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.mac_os_resource_snd", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    mac_os_resource_snd_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.midi_note_to_frequency() // => Lookup table to convert a MIDI note into a frequency in Hz
The lookup table represents the formula (2 ** ((midi_note - 69) / 12)) * 440

C++11/STL source code to parse Classic MacOS Sound Resource

mac_os_resource_snd.h

#pragma once

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif

/**
 * 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.
 * \sa https://developer.apple.com/library/archive/documentation/mac/pdf/Sound/Sound_Manager.pdf Source
 */

class mac_os_resource_snd_t : public kaitai::kstruct {

public:
    class extended_t;
    class sound_header_t;
    class unsigned_fixed_point_t;
    class sound_command_t;
    class compressed_t;
    class extended_or_compressed_t;
    class data_format_t;

    enum cmd_type_t {
        CMD_TYPE_NULL_CMD = 0,
        CMD_TYPE_QUIET_CMD = 3,
        CMD_TYPE_FLUSH_CMD = 4,
        CMD_TYPE_RE_INIT_CMD = 5,
        CMD_TYPE_WAIT_CMD = 10,
        CMD_TYPE_PAUSE_CMD = 11,
        CMD_TYPE_RESUME_CMD = 12,
        CMD_TYPE_CALL_BACK_CMD = 13,
        CMD_TYPE_SYNC_CMD = 14,
        CMD_TYPE_EMPTY_CMD = 15,
        CMD_TYPE_AVAILABLE_CMD = 24,
        CMD_TYPE_VERSION_CMD = 25,
        CMD_TYPE_TOTAL_LOAD_CMD = 26,
        CMD_TYPE_LOAD_CMD = 27,
        CMD_TYPE_FREQ_DURATION_CMD = 40,
        CMD_TYPE_REST_CMD = 41,
        CMD_TYPE_FREQ_CMD = 42,
        CMD_TYPE_AMP_CMD = 43,
        CMD_TYPE_TIMBRE_CMD = 44,
        CMD_TYPE_GET_AMP_CMD = 45,
        CMD_TYPE_VOLUME_CMD = 46,
        CMD_TYPE_GET_VOLUME_CMD = 47,
        CMD_TYPE_WAVE_TABLE_CMD = 60,
        CMD_TYPE_PHASE_CMD = 61,
        CMD_TYPE_SOUND_CMD = 80,
        CMD_TYPE_BUFFER_CMD = 81,
        CMD_TYPE_RATE_CMD = 82,
        CMD_TYPE_GET_RATE_CMD = 85
    };

    enum sound_header_type_t {
        SOUND_HEADER_TYPE_STANDARD = 0,
        SOUND_HEADER_TYPE_COMPRESSED = 254,
        SOUND_HEADER_TYPE_EXTENDED = 255
    };

    enum data_type_t {
        DATA_TYPE_SQUARE_WAVE_SYNTH = 1,
        DATA_TYPE_WAVE_TABLE_SYNTH = 3,
        DATA_TYPE_SAMPLED_SYNTH = 5
    };

    enum wave_init_option_t {
        WAVE_INIT_OPTION_CHANNEL0 = 4,
        WAVE_INIT_OPTION_CHANNEL1 = 5,
        WAVE_INIT_OPTION_CHANNEL2 = 6,
        WAVE_INIT_OPTION_CHANNEL3 = 7
    };

    enum init_option_t {
        INIT_OPTION_CHAN_LEFT = 2,
        INIT_OPTION_CHAN_RIGHT = 3,
        INIT_OPTION_NO_INTERP = 4,
        INIT_OPTION_NO_DROP = 8,
        INIT_OPTION_MONO = 128,
        INIT_OPTION_STEREO = 192,
        INIT_OPTION_MACE3 = 768,
        INIT_OPTION_MACE6 = 1024
    };

    enum compression_type_enum_t {
        COMPRESSION_TYPE_ENUM_VARIABLE_COMPRESSION = -2,
        COMPRESSION_TYPE_ENUM_FIXED_COMPRESSION = -1,
        COMPRESSION_TYPE_ENUM_NOT_COMPRESSED = 0,
        COMPRESSION_TYPE_ENUM_TWO_TO_ONE = 1,
        COMPRESSION_TYPE_ENUM_EIGHT_TO_THREE = 2,
        COMPRESSION_TYPE_ENUM_THREE_TO_ONE = 3,
        COMPRESSION_TYPE_ENUM_SIX_TO_ONE = 4
    };

    mac_os_resource_snd_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

private:
    void _read();
    void _clean_up();

public:
    ~mac_os_resource_snd_t();

    class extended_t : public kaitai::kstruct {

    public:

        extended_t(kaitai::kstream* p__io, mac_os_resource_snd_t::extended_or_compressed_t* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~extended_t();

    private:
        uint32_t m_instrument_chunk_ptr;
        uint32_t m_aes_recording_ptr;
        mac_os_resource_snd_t* m__root;
        mac_os_resource_snd_t::extended_or_compressed_t* m__parent;

    public:

        /**
         * pointer to instrument info
         */
        uint32_t instrument_chunk_ptr() const { return m_instrument_chunk_ptr; }

        /**
         * pointer to audio info
         */
        uint32_t aes_recording_ptr() const { return m_aes_recording_ptr; }
        mac_os_resource_snd_t* _root() const { return m__root; }
        mac_os_resource_snd_t::extended_or_compressed_t* _parent() const { return m__parent; }
    };

    class sound_header_t : public kaitai::kstruct {

    public:

        sound_header_t(kaitai::kstream* p__io, mac_os_resource_snd_t::sound_command_t* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~sound_header_t();

    private:
        bool f_start_ofs;
        int32_t m_start_ofs;

    public:
        int32_t start_ofs();

    private:
        bool f_base_freqeuncy;
        double m_base_freqeuncy;
        bool n_base_freqeuncy;

    public:
        bool _is_null_base_freqeuncy() { base_freqeuncy(); return n_base_freqeuncy; };

    private:

    public:

        /**
         * base frequency of sample in Hz
         * Calculated with the formula (2 ** ((midi_note - 69) / 12)) * 440
         * \sa https://en.wikipedia.org/wiki/MIDI_tuning_standard Source
         */
        double base_freqeuncy();

    private:
        bool f_sound_header_type;
        sound_header_type_t m_sound_header_type;

    public:
        sound_header_type_t sound_header_type();

    private:
        std::string m__unnamed0;
        bool n__unnamed0;

    public:
        bool _is_null__unnamed0() { _unnamed0(); return n__unnamed0; };

    private:
        uint32_t m_sample_ptr;
        uint32_t m_num_samples;
        bool n_num_samples;

    public:
        bool _is_null_num_samples() { num_samples(); return n_num_samples; };

    private:
        uint32_t m_num_channels;
        bool n_num_channels;

    public:
        bool _is_null_num_channels() { num_channels(); return n_num_channels; };

    private:
        std::unique_ptr<unsigned_fixed_point_t> m_sample_rate;
        uint32_t m_loop_start;
        uint32_t m_loop_end;
        sound_header_type_t m_encode;
        uint8_t m_midi_note;
        std::unique_ptr<extended_or_compressed_t> m_extended_or_compressed;
        bool n_extended_or_compressed;

    public:
        bool _is_null_extended_or_compressed() { extended_or_compressed(); return n_extended_or_compressed; };

    private:
        std::string m_sample_area;
        bool n_sample_area;

    public:
        bool _is_null_sample_area() { sample_area(); return n_sample_area; };

    private:
        mac_os_resource_snd_t* m__root;
        mac_os_resource_snd_t::sound_command_t* m__parent;

    public:
        std::string _unnamed0() const { return m__unnamed0; }

        /**
         * pointer to samples (or 0 if samples follow data structure)
         */
        uint32_t sample_ptr() const { return m_sample_ptr; }

        /**
         * number of samples
         */
        uint32_t num_samples() const { return m_num_samples; }

        /**
         * number of channels in sample
         */
        uint32_t num_channels() const { return m_num_channels; }

        /**
         * The rate at which the sample was originally recorded.
         */
        unsigned_fixed_point_t* sample_rate() const { return m_sample_rate.get(); }

        /**
         * loop point beginning
         */
        uint32_t loop_start() const { return m_loop_start; }

        /**
         * loop point ending
         */
        uint32_t loop_end() const { return m_loop_end; }

        /**
         * sample's encoding option
         */
        sound_header_type_t encode() const { return m_encode; }

        /**
         * base frequency of sample, expressed as MIDI note values, 60 is middle C
         */
        uint8_t midi_note() const { return m_midi_note; }
        extended_or_compressed_t* extended_or_compressed() const { return m_extended_or_compressed.get(); }

        /**
         * sampled-sound data
         */
        std::string sample_area() const { return m_sample_area; }
        mac_os_resource_snd_t* _root() const { return m__root; }
        mac_os_resource_snd_t::sound_command_t* _parent() const { return m__parent; }
    };

    class unsigned_fixed_point_t : public kaitai::kstruct {

    public:

        unsigned_fixed_point_t(kaitai::kstream* p__io, mac_os_resource_snd_t::sound_header_t* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~unsigned_fixed_point_t();

    private:
        bool f_value;
        double m_value;

    public:
        double value();

    private:
        uint16_t m_integer_part;
        uint16_t m_fraction_part;
        mac_os_resource_snd_t* m__root;
        mac_os_resource_snd_t::sound_header_t* m__parent;

    public:
        uint16_t integer_part() const { return m_integer_part; }
        uint16_t fraction_part() const { return m_fraction_part; }
        mac_os_resource_snd_t* _root() const { return m__root; }
        mac_os_resource_snd_t::sound_header_t* _parent() const { return m__parent; }
    };

    class sound_command_t : public kaitai::kstruct {

    public:

        sound_command_t(kaitai::kstream* p__io, mac_os_resource_snd_t* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~sound_command_t();

    private:
        bool f_sound_header;
        std::unique_ptr<sound_header_t> m_sound_header;
        bool n_sound_header;

    public:
        bool _is_null_sound_header() { sound_header(); return n_sound_header; };

    private:

    public:
        sound_header_t* sound_header();

    private:
        bool m_is_data_offset;
        cmd_type_t m_cmd;
        uint16_t m_param1;
        uint32_t m_param2;
        mac_os_resource_snd_t* m__root;
        mac_os_resource_snd_t* m__parent;

    public:
        bool is_data_offset() const { return m_is_data_offset; }
        cmd_type_t cmd() const { return m_cmd; }
        uint16_t param1() const { return m_param1; }
        uint32_t param2() const { return m_param2; }
        mac_os_resource_snd_t* _root() const { return m__root; }
        mac_os_resource_snd_t* _parent() const { return m__parent; }
    };

    class compressed_t : public kaitai::kstruct {

    public:

        compressed_t(kaitai::kstream* p__io, mac_os_resource_snd_t::extended_or_compressed_t* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~compressed_t();

    private:
        bool f_compression_type;
        compression_type_enum_t m_compression_type;

    public:
        compression_type_enum_t compression_type();

    private:
        std::string m_format;
        std::string m_reserved;
        uint32_t m_state_vars_ptr;
        uint32_t m_left_over_samples_ptr;
        int16_t m_compression_id;
        uint16_t m_packet_size;
        uint16_t m_synthesizer_id;
        mac_os_resource_snd_t* m__root;
        mac_os_resource_snd_t::extended_or_compressed_t* m__parent;

    public:

        /**
         * data format type
         */
        std::string format() const { return m_format; }
        std::string reserved() const { return m_reserved; }

        /**
         * pointer to StateBlock
         */
        uint32_t state_vars_ptr() const { return m_state_vars_ptr; }

        /**
         * pointer to LeftOverBlock
         */
        uint32_t left_over_samples_ptr() const { return m_left_over_samples_ptr; }

        /**
         * ID of compression algorithm
         */
        int16_t compression_id() const { return m_compression_id; }

        /**
         * number of bits per packet
         */
        uint16_t packet_size() const { return m_packet_size; }

        /**
         * 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.
         * \sa https://vintageapple.org/inside_o/pdf/Inside_Macintosh_Volume_VI_1991.pdf Page 22-49, absolute page number 1169 in the PDF
         */
        uint16_t synthesizer_id() const { return m_synthesizer_id; }
        mac_os_resource_snd_t* _root() const { return m__root; }
        mac_os_resource_snd_t::extended_or_compressed_t* _parent() const { return m__parent; }
    };

    class extended_or_compressed_t : public kaitai::kstruct {

    public:

        extended_or_compressed_t(kaitai::kstream* p__io, mac_os_resource_snd_t::sound_header_t* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~extended_or_compressed_t();

    private:
        uint32_t m_num_frames;
        std::string m_aiff_sample_rate;
        uint32_t m_marker_chunk;
        std::unique_ptr<extended_t> m_extended;
        bool n_extended;

    public:
        bool _is_null_extended() { extended(); return n_extended; };

    private:
        std::unique_ptr<compressed_t> m_compressed;
        bool n_compressed;

    public:
        bool _is_null_compressed() { compressed(); return n_compressed; };

    private:
        uint16_t m_bits_per_sample;
        std::string m_reserved;
        bool n_reserved;

    public:
        bool _is_null_reserved() { reserved(); return n_reserved; };

    private:
        mac_os_resource_snd_t* m__root;
        mac_os_resource_snd_t::sound_header_t* m__parent;

    public:
        uint32_t num_frames() const { return m_num_frames; }

        /**
         * rate of original sample (Extended80)
         */
        std::string aiff_sample_rate() const { return m_aiff_sample_rate; }

        /**
         * reserved
         */
        uint32_t marker_chunk() const { return m_marker_chunk; }
        extended_t* extended() const { return m_extended.get(); }
        compressed_t* compressed() const { return m_compressed.get(); }

        /**
         * number of bits per sample
         */
        uint16_t bits_per_sample() const { return m_bits_per_sample; }

        /**
         * reserved
         */
        std::string reserved() const { return m_reserved; }
        mac_os_resource_snd_t* _root() const { return m__root; }
        mac_os_resource_snd_t::sound_header_t* _parent() const { return m__parent; }
    };

    class data_format_t : public kaitai::kstruct {

    public:

        data_format_t(kaitai::kstream* p__io, mac_os_resource_snd_t* p__parent = nullptr, mac_os_resource_snd_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~data_format_t();

    private:
        bool f_init_pan_mask;
        int8_t m_init_pan_mask;

    public:

        /**
         * mask for right/left pan values
         */
        int8_t init_pan_mask();

    private:
        bool f_wave_init_channel_mask;
        int8_t m_wave_init_channel_mask;

    public:

        /**
         * wave table only, Sound Manager 2.0 and earlier
         */
        int8_t wave_init_channel_mask();

    private:
        bool f_init_stereo_mask;
        uint8_t m_init_stereo_mask;

    public:

        /**
         * mask for mono/stereo values
         */
        uint8_t init_stereo_mask();

    private:
        bool f_wave_init;
        wave_init_option_t m_wave_init;
        bool n_wave_init;

    public:
        bool _is_null_wave_init() { wave_init(); return n_wave_init; };

    private:

    public:
        wave_init_option_t wave_init();

    private:
        bool f_pan_init;
        init_option_t m_pan_init;

    public:
        init_option_t pan_init();

    private:
        bool f_init_comp_mask;
        int32_t m_init_comp_mask;

    public:

        /**
         * mask for compression IDs
         */
        int32_t init_comp_mask();

    private:
        bool f_stereo_init;
        init_option_t m_stereo_init;

    public:
        init_option_t stereo_init();

    private:
        bool f_comp_init;
        init_option_t m_comp_init;

    public:
        init_option_t comp_init();

    private:
        data_type_t m_id;
        uint32_t m_options;
        mac_os_resource_snd_t* m__root;
        mac_os_resource_snd_t* m__parent;

    public:
        data_type_t id() const { return m_id; }

        /**
         * contains initialisation options for the SndNewChannel function
         */
        uint32_t options() const { return m_options; }
        mac_os_resource_snd_t* _root() const { return m__root; }
        mac_os_resource_snd_t* _parent() const { return m__parent; }
    };

private:
    bool f_midi_note_to_frequency;
    std::unique_ptr<std::vector<double>> m_midi_note_to_frequency;

public:

    /**
     * Lookup table to convert a MIDI note into a frequency in Hz
     * The lookup table represents the formula (2 ** ((midi_note - 69) / 12)) * 440
     * \sa https://en.wikipedia.org/wiki/MIDI_tuning_standard Source
     */
    std::vector<double>* midi_note_to_frequency();

private:
    uint16_t m_format;
    uint16_t m_num_data_formats;
    bool n_num_data_formats;

public:
    bool _is_null_num_data_formats() { num_data_formats(); return n_num_data_formats; };

private:
    std::unique_ptr<std::vector<std::unique_ptr<data_format_t>>> m_data_formats;
    bool n_data_formats;

public:
    bool _is_null_data_formats() { data_formats(); return n_data_formats; };

private:
    uint16_t m_reference_count;
    bool n_reference_count;

public:
    bool _is_null_reference_count() { reference_count(); return n_reference_count; };

private:
    uint16_t m_num_sound_commands;
    std::unique_ptr<std::vector<std::unique_ptr<sound_command_t>>> m_sound_commands;
    mac_os_resource_snd_t* m__root;
    kaitai::kstruct* m__parent;

public:
    uint16_t format() const { return m_format; }
    uint16_t num_data_formats() const { return m_num_data_formats; }
    std::vector<std::unique_ptr<data_format_t>>* data_formats() const { return m_data_formats.get(); }
    uint16_t reference_count() const { return m_reference_count; }
    uint16_t num_sound_commands() const { return m_num_sound_commands; }
    std::vector<std::unique_ptr<sound_command_t>>* sound_commands() const { return m_sound_commands.get(); }
    mac_os_resource_snd_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

mac_os_resource_snd.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "mac_os_resource_snd.h"

mac_os_resource_snd_t::mac_os_resource_snd_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_data_formats = nullptr;
    m_sound_commands = nullptr;
    f_midi_note_to_frequency = false;
    _read();
}

void mac_os_resource_snd_t::_read() {
    m_format = m__io->read_u2be();
    n_num_data_formats = true;
    if (format() == 1) {
        n_num_data_formats = false;
        m_num_data_formats = m__io->read_u2be();
    }
    n_data_formats = true;
    if (format() == 1) {
        n_data_formats = false;
        int l_data_formats = num_data_formats();
        m_data_formats = std::unique_ptr<std::vector<std::unique_ptr<data_format_t>>>(new std::vector<std::unique_ptr<data_format_t>>());
        m_data_formats->reserve(l_data_formats);
        for (int i = 0; i < l_data_formats; i++) {
            m_data_formats->push_back(std::move(std::unique_ptr<data_format_t>(new data_format_t(m__io, this, m__root))));
        }
    }
    n_reference_count = true;
    if (format() == 2) {
        n_reference_count = false;
        m_reference_count = m__io->read_u2be();
    }
    m_num_sound_commands = m__io->read_u2be();
    int l_sound_commands = num_sound_commands();
    m_sound_commands = std::unique_ptr<std::vector<std::unique_ptr<sound_command_t>>>(new std::vector<std::unique_ptr<sound_command_t>>());
    m_sound_commands->reserve(l_sound_commands);
    for (int i = 0; i < l_sound_commands; i++) {
        m_sound_commands->push_back(std::move(std::unique_ptr<sound_command_t>(new sound_command_t(m__io, this, m__root))));
    }
}

mac_os_resource_snd_t::~mac_os_resource_snd_t() {
    _clean_up();
}

void mac_os_resource_snd_t::_clean_up() {
    if (!n_num_data_formats) {
    }
    if (!n_data_formats) {
    }
    if (!n_reference_count) {
    }
}

mac_os_resource_snd_t::extended_t::extended_t(kaitai::kstream* p__io, mac_os_resource_snd_t::extended_or_compressed_t* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void mac_os_resource_snd_t::extended_t::_read() {
    m_instrument_chunk_ptr = m__io->read_u4be();
    m_aes_recording_ptr = m__io->read_u4be();
}

mac_os_resource_snd_t::extended_t::~extended_t() {
    _clean_up();
}

void mac_os_resource_snd_t::extended_t::_clean_up() {
}

mac_os_resource_snd_t::sound_header_t::sound_header_t(kaitai::kstream* p__io, mac_os_resource_snd_t::sound_command_t* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_sample_rate = nullptr;
    m_extended_or_compressed = nullptr;
    f_start_ofs = false;
    f_base_freqeuncy = false;
    f_sound_header_type = false;
    _read();
}

void mac_os_resource_snd_t::sound_header_t::_read() {
    n__unnamed0 = true;
    if (start_ofs() < 0) {
        n__unnamed0 = false;
        m__unnamed0 = m__io->read_bytes(0);
    }
    m_sample_ptr = m__io->read_u4be();
    n_num_samples = true;
    if (sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_STANDARD) {
        n_num_samples = false;
        m_num_samples = m__io->read_u4be();
    }
    n_num_channels = true;
    if ( ((sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_EXTENDED) || (sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_COMPRESSED)) ) {
        n_num_channels = false;
        m_num_channels = m__io->read_u4be();
    }
    m_sample_rate = std::unique_ptr<unsigned_fixed_point_t>(new unsigned_fixed_point_t(m__io, this, m__root));
    m_loop_start = m__io->read_u4be();
    m_loop_end = m__io->read_u4be();
    m_encode = static_cast<mac_os_resource_snd_t::sound_header_type_t>(m__io->read_u1());
    m_midi_note = m__io->read_u1();
    n_extended_or_compressed = true;
    if ( ((sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_EXTENDED) || (sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_COMPRESSED)) ) {
        n_extended_or_compressed = false;
        m_extended_or_compressed = std::unique_ptr<extended_or_compressed_t>(new extended_or_compressed_t(m__io, this, m__root));
    }
    n_sample_area = true;
    if (sample_ptr() == 0) {
        n_sample_area = false;
        m_sample_area = m__io->read_bytes(((sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_STANDARD) ? (num_samples()) : (((sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_EXTENDED) ? ((((extended_or_compressed()->num_frames() * num_channels()) * extended_or_compressed()->bits_per_sample()) / 8)) : ((_io()->size() - _io()->pos()))))));
    }
}

mac_os_resource_snd_t::sound_header_t::~sound_header_t() {
    _clean_up();
}

void mac_os_resource_snd_t::sound_header_t::_clean_up() {
    if (!n__unnamed0) {
    }
    if (!n_num_samples) {
    }
    if (!n_num_channels) {
    }
    if (!n_extended_or_compressed) {
    }
    if (!n_sample_area) {
    }
    if (f_sound_header_type) {
    }
}

int32_t mac_os_resource_snd_t::sound_header_t::start_ofs() {
    if (f_start_ofs)
        return m_start_ofs;
    m_start_ofs = _io()->pos();
    f_start_ofs = true;
    return m_start_ofs;
}

double mac_os_resource_snd_t::sound_header_t::base_freqeuncy() {
    if (f_base_freqeuncy)
        return m_base_freqeuncy;
    n_base_freqeuncy = true;
    if ( ((midi_note() >= 0) && (midi_note() < 128)) ) {
        n_base_freqeuncy = false;
        m_base_freqeuncy = _root()->midi_note_to_frequency()->at(midi_note());
    }
    f_base_freqeuncy = true;
    return m_base_freqeuncy;
}

mac_os_resource_snd_t::sound_header_type_t mac_os_resource_snd_t::sound_header_t::sound_header_type() {
    if (f_sound_header_type)
        return m_sound_header_type;
    std::streampos _pos = m__io->pos();
    m__io->seek((start_ofs() + 20));
    m_sound_header_type = static_cast<mac_os_resource_snd_t::sound_header_type_t>(m__io->read_u1());
    m__io->seek(_pos);
    f_sound_header_type = true;
    return m_sound_header_type;
}

mac_os_resource_snd_t::unsigned_fixed_point_t::unsigned_fixed_point_t(kaitai::kstream* p__io, mac_os_resource_snd_t::sound_header_t* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_value = false;
    _read();
}

void mac_os_resource_snd_t::unsigned_fixed_point_t::_read() {
    m_integer_part = m__io->read_u2be();
    m_fraction_part = m__io->read_u2be();
}

mac_os_resource_snd_t::unsigned_fixed_point_t::~unsigned_fixed_point_t() {
    _clean_up();
}

void mac_os_resource_snd_t::unsigned_fixed_point_t::_clean_up() {
}

double mac_os_resource_snd_t::unsigned_fixed_point_t::value() {
    if (f_value)
        return m_value;
    m_value = (integer_part() + (fraction_part() / 65535.0));
    f_value = true;
    return m_value;
}

mac_os_resource_snd_t::sound_command_t::sound_command_t(kaitai::kstream* p__io, mac_os_resource_snd_t* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_sound_header = nullptr;
    f_sound_header = false;
    _read();
}

void mac_os_resource_snd_t::sound_command_t::_read() {
    m_is_data_offset = m__io->read_bits_int_be(1);
    m_cmd = static_cast<mac_os_resource_snd_t::cmd_type_t>(m__io->read_bits_int_be(15));
    m__io->align_to_byte();
    m_param1 = m__io->read_u2be();
    m_param2 = m__io->read_u4be();
}

mac_os_resource_snd_t::sound_command_t::~sound_command_t() {
    _clean_up();
}

void mac_os_resource_snd_t::sound_command_t::_clean_up() {
    if (f_sound_header && !n_sound_header) {
    }
}

mac_os_resource_snd_t::sound_header_t* mac_os_resource_snd_t::sound_command_t::sound_header() {
    if (f_sound_header)
        return m_sound_header.get();
    n_sound_header = true;
    if ( ((is_data_offset()) && (cmd() == mac_os_resource_snd_t::CMD_TYPE_BUFFER_CMD)) ) {
        n_sound_header = false;
        std::streampos _pos = m__io->pos();
        m__io->seek(param2());
        m_sound_header = std::unique_ptr<sound_header_t>(new sound_header_t(m__io, this, m__root));
        m__io->seek(_pos);
        f_sound_header = true;
    }
    return m_sound_header.get();
}

mac_os_resource_snd_t::compressed_t::compressed_t(kaitai::kstream* p__io, mac_os_resource_snd_t::extended_or_compressed_t* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_compression_type = false;
    _read();
}

void mac_os_resource_snd_t::compressed_t::_read() {
    m_format = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), std::string("ASCII"));
    m_reserved = m__io->read_bytes(4);
    m_state_vars_ptr = m__io->read_u4be();
    m_left_over_samples_ptr = m__io->read_u4be();
    m_compression_id = m__io->read_s2be();
    m_packet_size = m__io->read_u2be();
    m_synthesizer_id = m__io->read_u2be();
}

mac_os_resource_snd_t::compressed_t::~compressed_t() {
    _clean_up();
}

void mac_os_resource_snd_t::compressed_t::_clean_up() {
}

mac_os_resource_snd_t::compression_type_enum_t mac_os_resource_snd_t::compressed_t::compression_type() {
    if (f_compression_type)
        return m_compression_type;
    m_compression_type = static_cast<mac_os_resource_snd_t::compression_type_enum_t>(compression_id());
    f_compression_type = true;
    return m_compression_type;
}

mac_os_resource_snd_t::extended_or_compressed_t::extended_or_compressed_t(kaitai::kstream* p__io, mac_os_resource_snd_t::sound_header_t* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_extended = nullptr;
    m_compressed = nullptr;
    _read();
}

void mac_os_resource_snd_t::extended_or_compressed_t::_read() {
    m_num_frames = m__io->read_u4be();
    m_aiff_sample_rate = m__io->read_bytes(10);
    m_marker_chunk = m__io->read_u4be();
    n_extended = true;
    if (_parent()->sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_EXTENDED) {
        n_extended = false;
        m_extended = std::unique_ptr<extended_t>(new extended_t(m__io, this, m__root));
    }
    n_compressed = true;
    if (_parent()->sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_COMPRESSED) {
        n_compressed = false;
        m_compressed = std::unique_ptr<compressed_t>(new compressed_t(m__io, this, m__root));
    }
    m_bits_per_sample = m__io->read_u2be();
    n_reserved = true;
    if (_parent()->sound_header_type() == mac_os_resource_snd_t::SOUND_HEADER_TYPE_EXTENDED) {
        n_reserved = false;
        m_reserved = m__io->read_bytes(14);
    }
}

mac_os_resource_snd_t::extended_or_compressed_t::~extended_or_compressed_t() {
    _clean_up();
}

void mac_os_resource_snd_t::extended_or_compressed_t::_clean_up() {
    if (!n_extended) {
    }
    if (!n_compressed) {
    }
    if (!n_reserved) {
    }
}

mac_os_resource_snd_t::data_format_t::data_format_t(kaitai::kstream* p__io, mac_os_resource_snd_t* p__parent, mac_os_resource_snd_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_init_pan_mask = false;
    f_wave_init_channel_mask = false;
    f_init_stereo_mask = false;
    f_wave_init = false;
    f_pan_init = false;
    f_init_comp_mask = false;
    f_stereo_init = false;
    f_comp_init = false;
    _read();
}

void mac_os_resource_snd_t::data_format_t::_read() {
    m_id = static_cast<mac_os_resource_snd_t::data_type_t>(m__io->read_u2be());
    m_options = m__io->read_u4be();
}

mac_os_resource_snd_t::data_format_t::~data_format_t() {
    _clean_up();
}

void mac_os_resource_snd_t::data_format_t::_clean_up() {
}

int8_t mac_os_resource_snd_t::data_format_t::init_pan_mask() {
    if (f_init_pan_mask)
        return m_init_pan_mask;
    m_init_pan_mask = 3;
    f_init_pan_mask = true;
    return m_init_pan_mask;
}

int8_t mac_os_resource_snd_t::data_format_t::wave_init_channel_mask() {
    if (f_wave_init_channel_mask)
        return m_wave_init_channel_mask;
    m_wave_init_channel_mask = 7;
    f_wave_init_channel_mask = true;
    return m_wave_init_channel_mask;
}

uint8_t mac_os_resource_snd_t::data_format_t::init_stereo_mask() {
    if (f_init_stereo_mask)
        return m_init_stereo_mask;
    m_init_stereo_mask = 192;
    f_init_stereo_mask = true;
    return m_init_stereo_mask;
}

mac_os_resource_snd_t::wave_init_option_t mac_os_resource_snd_t::data_format_t::wave_init() {
    if (f_wave_init)
        return m_wave_init;
    n_wave_init = true;
    if (id() == mac_os_resource_snd_t::DATA_TYPE_WAVE_TABLE_SYNTH) {
        n_wave_init = false;
        m_wave_init = static_cast<mac_os_resource_snd_t::wave_init_option_t>((options() & wave_init_channel_mask()));
    }
    f_wave_init = true;
    return m_wave_init;
}

mac_os_resource_snd_t::init_option_t mac_os_resource_snd_t::data_format_t::pan_init() {
    if (f_pan_init)
        return m_pan_init;
    m_pan_init = static_cast<mac_os_resource_snd_t::init_option_t>((options() & init_pan_mask()));
    f_pan_init = true;
    return m_pan_init;
}

int32_t mac_os_resource_snd_t::data_format_t::init_comp_mask() {
    if (f_init_comp_mask)
        return m_init_comp_mask;
    m_init_comp_mask = 65280;
    f_init_comp_mask = true;
    return m_init_comp_mask;
}

mac_os_resource_snd_t::init_option_t mac_os_resource_snd_t::data_format_t::stereo_init() {
    if (f_stereo_init)
        return m_stereo_init;
    m_stereo_init = static_cast<mac_os_resource_snd_t::init_option_t>((options() & init_stereo_mask()));
    f_stereo_init = true;
    return m_stereo_init;
}

mac_os_resource_snd_t::init_option_t mac_os_resource_snd_t::data_format_t::comp_init() {
    if (f_comp_init)
        return m_comp_init;
    m_comp_init = static_cast<mac_os_resource_snd_t::init_option_t>((options() & init_comp_mask()));
    f_comp_init = true;
    return m_comp_init;
}

std::vector<double>* mac_os_resource_snd_t::midi_note_to_frequency() {
    if (f_midi_note_to_frequency)
        return m_midi_note_to_frequency.get();
    m_midi_note_to_frequency = std::unique_ptr<std::vector<double>>(new std::vector<double>{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});
    f_midi_note_to_frequency = true;
    return m_midi_note_to_frequency.get();
}