Scream Tracker 3 module is a tracker music file format that, as all tracker music, bundles both sound samples and instructions on which notes to play. It originates from a Scream Tracker 3 music editor (1994) by Future Crew, derived from original Scream Tracker 2 (.stm) module format.
Instrument descriptions in S3M format allow to use either digital samples or setup and control AdLib (OPL2) synth.
Music is organized in so called patterns
. "Pattern" is a generally
a 64-row long table, which instructs which notes to play on which
time measure. "Patterns" are played one-by-one in a sequence
determined by orders
, which is essentially an array of pattern IDs
This page hosts a formal specification of Scream Tracker 3 module using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing 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.
Using Kaitai Struct in C++/STL usually consists of 3 steps.
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.s3m", std::ifstream::binary);
#include <sstream>
std::istringstream is(str);
#include <sstream>
const char buf[] = { ... };
std::string str(buf, sizeof buf);
std::istringstream is(str);
#include "kaitai/kaitaistream.h"
kaitai::kstream ks(&is);
s3m_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.num_orders() // => Number of orders in a song
#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
/**
* Scream Tracker 3 module is a tracker music file format that, as all
* tracker music, bundles both sound samples and instructions on which
* notes to play. It originates from a Scream Tracker 3 music editor
* (1994) by Future Crew, derived from original Scream Tracker 2 (.stm)
* module format.
*
* Instrument descriptions in S3M format allow to use either digital
* samples or setup and control AdLib (OPL2) synth.
*
* Music is organized in so called `patterns`. "Pattern" is a generally
* a 64-row long table, which instructs which notes to play on which
* time measure. "Patterns" are played one-by-one in a sequence
* determined by `orders`, which is essentially an array of pattern IDs
* - this way it's possible to reuse certain patterns more than once
* for repetitive musical phrases.
* \sa http://hackipedia.org/browse.cgi/File%20formats/Music%20tracker/S3M%2c%20ScreamTracker%203/Scream%20Tracker%203.20%20by%20Future%20Crew.txt Source
*/
class s3m_t : public kaitai::kstruct {
public:
class channel_pan_t;
class pattern_cell_t;
class pattern_cells_t;
class channel_t;
class swapped_u3_t;
class pattern_t;
class pattern_ptr_t;
class instrument_ptr_t;
class instrument_t;
s3m_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~s3m_t();
class channel_pan_t : public kaitai::kstruct {
public:
channel_pan_t(kaitai::kstream* p__io, s3m_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~channel_pan_t();
private:
uint64_t m_reserved1;
bool m_has_custom_pan;
bool m_reserved2;
uint64_t m_pan;
s3m_t* m__root;
s3m_t* m__parent;
public:
uint64_t reserved1() const { return m_reserved1; }
/**
* If true, then use a custom pan setting provided in the `pan`
* field. If false, the channel would use the default setting
* (0x7 for mono, 0x3 or 0xc for stereo).
*/
bool has_custom_pan() const { return m_has_custom_pan; }
bool reserved2() const { return m_reserved2; }
uint64_t pan() const { return m_pan; }
s3m_t* _root() const { return m__root; }
s3m_t* _parent() const { return m__parent; }
};
class pattern_cell_t : public kaitai::kstruct {
public:
pattern_cell_t(kaitai::kstream* p__io, s3m_t::pattern_cells_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~pattern_cell_t();
private:
bool m_has_fx;
bool m_has_volume;
bool m_has_note_and_instrument;
uint64_t m_channel_num;
uint8_t m_note;
bool n_note;
public:
bool _is_null_note() { note(); return n_note; };
private:
uint8_t m_instrument;
bool n_instrument;
public:
bool _is_null_instrument() { instrument(); return n_instrument; };
private:
uint8_t m_volume;
bool n_volume;
public:
bool _is_null_volume() { volume(); return n_volume; };
private:
uint8_t m_fx_type;
bool n_fx_type;
public:
bool _is_null_fx_type() { fx_type(); return n_fx_type; };
private:
uint8_t m_fx_value;
bool n_fx_value;
public:
bool _is_null_fx_value() { fx_value(); return n_fx_value; };
private:
s3m_t* m__root;
s3m_t::pattern_cells_t* m__parent;
public:
bool has_fx() const { return m_has_fx; }
bool has_volume() const { return m_has_volume; }
bool has_note_and_instrument() const { return m_has_note_and_instrument; }
uint64_t channel_num() const { return m_channel_num; }
uint8_t note() const { return m_note; }
uint8_t instrument() const { return m_instrument; }
uint8_t volume() const { return m_volume; }
uint8_t fx_type() const { return m_fx_type; }
uint8_t fx_value() const { return m_fx_value; }
s3m_t* _root() const { return m__root; }
s3m_t::pattern_cells_t* _parent() const { return m__parent; }
};
class pattern_cells_t : public kaitai::kstruct {
public:
pattern_cells_t(kaitai::kstream* p__io, s3m_t::pattern_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~pattern_cells_t();
private:
std::unique_ptr<std::vector<std::unique_ptr<pattern_cell_t>>> m_cells;
s3m_t* m__root;
s3m_t::pattern_t* m__parent;
public:
std::vector<std::unique_ptr<pattern_cell_t>>* cells() const { return m_cells.get(); }
s3m_t* _root() const { return m__root; }
s3m_t::pattern_t* _parent() const { return m__parent; }
};
class channel_t : public kaitai::kstruct {
public:
channel_t(kaitai::kstream* p__io, s3m_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~channel_t();
private:
bool m_is_disabled;
uint64_t m_ch_type;
s3m_t* m__root;
s3m_t* m__parent;
public:
bool is_disabled() const { return m_is_disabled; }
/**
* Channel type (0..7 = left sample channels, 8..15 = right sample channels, 16..31 = AdLib synth channels)
*/
uint64_t ch_type() const { return m_ch_type; }
s3m_t* _root() const { return m__root; }
s3m_t* _parent() const { return m__parent; }
};
/**
* Custom 3-byte integer, stored in mixed endian manner.
*/
class swapped_u3_t : public kaitai::kstruct {
public:
swapped_u3_t(kaitai::kstream* p__io, s3m_t::instrument_t::sampled_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~swapped_u3_t();
private:
bool f_value;
int32_t m_value;
public:
int32_t value();
private:
uint8_t m_hi;
uint16_t m_lo;
s3m_t* m__root;
s3m_t::instrument_t::sampled_t* m__parent;
public:
uint8_t hi() const { return m_hi; }
uint16_t lo() const { return m_lo; }
s3m_t* _root() const { return m__root; }
s3m_t::instrument_t::sampled_t* _parent() const { return m__parent; }
};
class pattern_t : public kaitai::kstruct {
public:
pattern_t(kaitai::kstream* p__io, s3m_t::pattern_ptr_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~pattern_t();
private:
uint16_t m_size;
std::unique_ptr<pattern_cells_t> m_body;
s3m_t* m__root;
s3m_t::pattern_ptr_t* m__parent;
std::string m__raw_body;
std::unique_ptr<kaitai::kstream> m__io__raw_body;
public:
uint16_t size() const { return m_size; }
pattern_cells_t* body() const { return m_body.get(); }
s3m_t* _root() const { return m__root; }
s3m_t::pattern_ptr_t* _parent() const { return m__parent; }
std::string _raw_body() const { return m__raw_body; }
kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); }
};
class pattern_ptr_t : public kaitai::kstruct {
public:
pattern_ptr_t(kaitai::kstream* p__io, s3m_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~pattern_ptr_t();
private:
bool f_body;
std::unique_ptr<pattern_t> m_body;
public:
pattern_t* body();
private:
uint16_t m_paraptr;
s3m_t* m__root;
s3m_t* m__parent;
public:
uint16_t paraptr() const { return m_paraptr; }
s3m_t* _root() const { return m__root; }
s3m_t* _parent() const { return m__parent; }
};
class instrument_ptr_t : public kaitai::kstruct {
public:
instrument_ptr_t(kaitai::kstream* p__io, s3m_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~instrument_ptr_t();
private:
bool f_body;
std::unique_ptr<instrument_t> m_body;
public:
instrument_t* body();
private:
uint16_t m_paraptr;
s3m_t* m__root;
s3m_t* m__parent;
public:
uint16_t paraptr() const { return m_paraptr; }
s3m_t* _root() const { return m__root; }
s3m_t* _parent() const { return m__parent; }
};
class instrument_t : public kaitai::kstruct {
public:
class sampled_t;
class adlib_t;
enum inst_types_t {
INST_TYPES_SAMPLE = 1,
INST_TYPES_MELODIC = 2,
INST_TYPES_BASS_DRUM = 3,
INST_TYPES_SNARE_DRUM = 4,
INST_TYPES_TOM = 5,
INST_TYPES_CYMBAL = 6,
INST_TYPES_HIHAT = 7
};
instrument_t(kaitai::kstream* p__io, s3m_t::instrument_ptr_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~instrument_t();
class sampled_t : public kaitai::kstruct {
public:
sampled_t(kaitai::kstream* p__io, s3m_t::instrument_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~sampled_t();
private:
bool f_sample;
std::string m_sample;
public:
std::string sample();
private:
std::unique_ptr<swapped_u3_t> m_paraptr_sample;
uint32_t m_len_sample;
uint32_t m_loop_begin;
uint32_t m_loop_end;
uint8_t m_default_volume;
uint8_t m_reserved1;
uint8_t m_is_packed;
uint8_t m_flags;
s3m_t* m__root;
s3m_t::instrument_t* m__parent;
public:
swapped_u3_t* paraptr_sample() const { return m_paraptr_sample.get(); }
uint32_t len_sample() const { return m_len_sample; }
uint32_t loop_begin() const { return m_loop_begin; }
uint32_t loop_end() const { return m_loop_end; }
/**
* Default volume
*/
uint8_t default_volume() const { return m_default_volume; }
uint8_t reserved1() const { return m_reserved1; }
/**
* 0 = unpacked, 1 = DP30ADPCM packing
*/
uint8_t is_packed() const { return m_is_packed; }
uint8_t flags() const { return m_flags; }
s3m_t* _root() const { return m__root; }
s3m_t::instrument_t* _parent() const { return m__parent; }
};
class adlib_t : public kaitai::kstruct {
public:
adlib_t(kaitai::kstream* p__io, s3m_t::instrument_t* p__parent = nullptr, s3m_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~adlib_t();
private:
std::string m_reserved1;
std::string m__unnamed1;
s3m_t* m__root;
s3m_t::instrument_t* m__parent;
public:
std::string reserved1() const { return m_reserved1; }
std::string _unnamed1() const { return m__unnamed1; }
s3m_t* _root() const { return m__root; }
s3m_t::instrument_t* _parent() const { return m__parent; }
};
private:
inst_types_t m_type;
std::string m_filename;
std::unique_ptr<kaitai::kstruct> m_body;
uint32_t m_tuning_hz;
std::string m_reserved2;
std::string m_sample_name;
std::string m_magic;
s3m_t* m__root;
s3m_t::instrument_ptr_t* m__parent;
public:
inst_types_t type() const { return m_type; }
std::string filename() const { return m_filename; }
kaitai::kstruct* body() const { return m_body.get(); }
uint32_t tuning_hz() const { return m_tuning_hz; }
std::string reserved2() const { return m_reserved2; }
std::string sample_name() const { return m_sample_name; }
std::string magic() const { return m_magic; }
s3m_t* _root() const { return m__root; }
s3m_t::instrument_ptr_t* _parent() const { return m__parent; }
};
private:
std::string m_song_name;
std::string m_magic1;
uint8_t m_file_type;
std::string m_reserved1;
uint16_t m_num_orders;
uint16_t m_num_instruments;
uint16_t m_num_patterns;
uint16_t m_flags;
uint16_t m_version;
uint16_t m_samples_format;
std::string m_magic2;
uint8_t m_global_volume;
uint8_t m_initial_speed;
uint8_t m_initial_tempo;
bool m_is_stereo;
uint64_t m_master_volume;
uint8_t m_ultra_click_removal;
uint8_t m_has_custom_pan;
std::string m_reserved2;
uint16_t m_ofs_special;
std::unique_ptr<std::vector<std::unique_ptr<channel_t>>> m_channels;
std::string m_orders;
std::unique_ptr<std::vector<std::unique_ptr<instrument_ptr_t>>> m_instruments;
std::unique_ptr<std::vector<std::unique_ptr<pattern_ptr_t>>> m_patterns;
std::unique_ptr<std::vector<std::unique_ptr<channel_pan_t>>> m_channel_pans;
bool n_channel_pans;
public:
bool _is_null_channel_pans() { channel_pans(); return n_channel_pans; };
private:
s3m_t* m__root;
kaitai::kstruct* m__parent;
public:
std::string song_name() const { return m_song_name; }
std::string magic1() const { return m_magic1; }
uint8_t file_type() const { return m_file_type; }
std::string reserved1() const { return m_reserved1; }
/**
* Number of orders in a song
*/
uint16_t num_orders() const { return m_num_orders; }
/**
* Number of instruments in a song
*/
uint16_t num_instruments() const { return m_num_instruments; }
/**
* Number of patterns in a song
*/
uint16_t num_patterns() const { return m_num_patterns; }
uint16_t flags() const { return m_flags; }
/**
* Scream Tracker version that was used to save this file
*/
uint16_t version() const { return m_version; }
/**
* 1 = signed samples, 2 = unsigned samples
*/
uint16_t samples_format() const { return m_samples_format; }
std::string magic2() const { return m_magic2; }
uint8_t global_volume() const { return m_global_volume; }
uint8_t initial_speed() const { return m_initial_speed; }
uint8_t initial_tempo() const { return m_initial_tempo; }
bool is_stereo() const { return m_is_stereo; }
uint64_t master_volume() const { return m_master_volume; }
uint8_t ultra_click_removal() const { return m_ultra_click_removal; }
uint8_t has_custom_pan() const { return m_has_custom_pan; }
std::string reserved2() const { return m_reserved2; }
/**
* Offset of special data, not used by Scream Tracker directly.
*/
uint16_t ofs_special() const { return m_ofs_special; }
std::vector<std::unique_ptr<channel_t>>* channels() const { return m_channels.get(); }
std::string orders() const { return m_orders; }
std::vector<std::unique_ptr<instrument_ptr_t>>* instruments() const { return m_instruments.get(); }
std::vector<std::unique_ptr<pattern_ptr_t>>* patterns() const { return m_patterns.get(); }
std::vector<std::unique_ptr<channel_pan_t>>* channel_pans() const { return m_channel_pans.get(); }
s3m_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "s3m.h"
#include "kaitai/exceptions.h"
s3m_t::s3m_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_channels = nullptr;
m_instruments = nullptr;
m_patterns = nullptr;
m_channel_pans = nullptr;
_read();
}
void s3m_t::_read() {
m_song_name = kaitai::kstream::bytes_terminate(m__io->read_bytes(28), 0, false);
m_magic1 = m__io->read_bytes(1);
if (!(magic1() == std::string("\x1A", 1))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x1A", 1), magic1(), _io(), std::string("/seq/1"));
}
m_file_type = m__io->read_u1();
m_reserved1 = m__io->read_bytes(2);
m_num_orders = m__io->read_u2le();
m_num_instruments = m__io->read_u2le();
m_num_patterns = m__io->read_u2le();
m_flags = m__io->read_u2le();
m_version = m__io->read_u2le();
m_samples_format = m__io->read_u2le();
m_magic2 = m__io->read_bytes(4);
if (!(magic2() == std::string("\x53\x43\x52\x4D", 4))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x53\x43\x52\x4D", 4), magic2(), _io(), std::string("/seq/10"));
}
m_global_volume = m__io->read_u1();
m_initial_speed = m__io->read_u1();
m_initial_tempo = m__io->read_u1();
m_is_stereo = m__io->read_bits_int_be(1);
m_master_volume = m__io->read_bits_int_be(7);
m__io->align_to_byte();
m_ultra_click_removal = m__io->read_u1();
m_has_custom_pan = m__io->read_u1();
m_reserved2 = m__io->read_bytes(8);
m_ofs_special = m__io->read_u2le();
m_channels = std::unique_ptr<std::vector<std::unique_ptr<channel_t>>>(new std::vector<std::unique_ptr<channel_t>>());
const int l_channels = 32;
for (int i = 0; i < l_channels; i++) {
m_channels->push_back(std::move(std::unique_ptr<channel_t>(new channel_t(m__io, this, m__root))));
}
m_orders = m__io->read_bytes(num_orders());
m_instruments = std::unique_ptr<std::vector<std::unique_ptr<instrument_ptr_t>>>(new std::vector<std::unique_ptr<instrument_ptr_t>>());
const int l_instruments = num_instruments();
for (int i = 0; i < l_instruments; i++) {
m_instruments->push_back(std::move(std::unique_ptr<instrument_ptr_t>(new instrument_ptr_t(m__io, this, m__root))));
}
m_patterns = std::unique_ptr<std::vector<std::unique_ptr<pattern_ptr_t>>>(new std::vector<std::unique_ptr<pattern_ptr_t>>());
const int l_patterns = num_patterns();
for (int i = 0; i < l_patterns; i++) {
m_patterns->push_back(std::move(std::unique_ptr<pattern_ptr_t>(new pattern_ptr_t(m__io, this, m__root))));
}
n_channel_pans = true;
if (has_custom_pan() == 252) {
n_channel_pans = false;
m_channel_pans = std::unique_ptr<std::vector<std::unique_ptr<channel_pan_t>>>(new std::vector<std::unique_ptr<channel_pan_t>>());
const int l_channel_pans = 32;
for (int i = 0; i < l_channel_pans; i++) {
m_channel_pans->push_back(std::move(std::unique_ptr<channel_pan_t>(new channel_pan_t(m__io, this, m__root))));
}
}
}
s3m_t::~s3m_t() {
_clean_up();
}
void s3m_t::_clean_up() {
if (!n_channel_pans) {
}
}
s3m_t::channel_pan_t::channel_pan_t(kaitai::kstream* p__io, s3m_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void s3m_t::channel_pan_t::_read() {
m_reserved1 = m__io->read_bits_int_be(2);
m_has_custom_pan = m__io->read_bits_int_be(1);
m_reserved2 = m__io->read_bits_int_be(1);
m_pan = m__io->read_bits_int_be(4);
}
s3m_t::channel_pan_t::~channel_pan_t() {
_clean_up();
}
void s3m_t::channel_pan_t::_clean_up() {
}
s3m_t::pattern_cell_t::pattern_cell_t(kaitai::kstream* p__io, s3m_t::pattern_cells_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void s3m_t::pattern_cell_t::_read() {
m_has_fx = m__io->read_bits_int_be(1);
m_has_volume = m__io->read_bits_int_be(1);
m_has_note_and_instrument = m__io->read_bits_int_be(1);
m_channel_num = m__io->read_bits_int_be(5);
m__io->align_to_byte();
n_note = true;
if (has_note_and_instrument()) {
n_note = false;
m_note = m__io->read_u1();
}
n_instrument = true;
if (has_note_and_instrument()) {
n_instrument = false;
m_instrument = m__io->read_u1();
}
n_volume = true;
if (has_volume()) {
n_volume = false;
m_volume = m__io->read_u1();
}
n_fx_type = true;
if (has_fx()) {
n_fx_type = false;
m_fx_type = m__io->read_u1();
}
n_fx_value = true;
if (has_fx()) {
n_fx_value = false;
m_fx_value = m__io->read_u1();
}
}
s3m_t::pattern_cell_t::~pattern_cell_t() {
_clean_up();
}
void s3m_t::pattern_cell_t::_clean_up() {
if (!n_note) {
}
if (!n_instrument) {
}
if (!n_volume) {
}
if (!n_fx_type) {
}
if (!n_fx_value) {
}
}
s3m_t::pattern_cells_t::pattern_cells_t(kaitai::kstream* p__io, s3m_t::pattern_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_cells = nullptr;
_read();
}
void s3m_t::pattern_cells_t::_read() {
m_cells = std::unique_ptr<std::vector<std::unique_ptr<pattern_cell_t>>>(new std::vector<std::unique_ptr<pattern_cell_t>>());
{
int i = 0;
while (!m__io->is_eof()) {
m_cells->push_back(std::move(std::unique_ptr<pattern_cell_t>(new pattern_cell_t(m__io, this, m__root))));
i++;
}
}
}
s3m_t::pattern_cells_t::~pattern_cells_t() {
_clean_up();
}
void s3m_t::pattern_cells_t::_clean_up() {
}
s3m_t::channel_t::channel_t(kaitai::kstream* p__io, s3m_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void s3m_t::channel_t::_read() {
m_is_disabled = m__io->read_bits_int_be(1);
m_ch_type = m__io->read_bits_int_be(7);
}
s3m_t::channel_t::~channel_t() {
_clean_up();
}
void s3m_t::channel_t::_clean_up() {
}
s3m_t::swapped_u3_t::swapped_u3_t(kaitai::kstream* p__io, s3m_t::instrument_t::sampled_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
f_value = false;
_read();
}
void s3m_t::swapped_u3_t::_read() {
m_hi = m__io->read_u1();
m_lo = m__io->read_u2le();
}
s3m_t::swapped_u3_t::~swapped_u3_t() {
_clean_up();
}
void s3m_t::swapped_u3_t::_clean_up() {
}
int32_t s3m_t::swapped_u3_t::value() {
if (f_value)
return m_value;
m_value = (lo() | (hi() << 16));
f_value = true;
return m_value;
}
s3m_t::pattern_t::pattern_t(kaitai::kstream* p__io, s3m_t::pattern_ptr_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_body = nullptr;
m__io__raw_body = nullptr;
_read();
}
void s3m_t::pattern_t::_read() {
m_size = m__io->read_u2le();
m__raw_body = m__io->read_bytes((size() - 2));
m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
m_body = std::unique_ptr<pattern_cells_t>(new pattern_cells_t(m__io__raw_body.get(), this, m__root));
}
s3m_t::pattern_t::~pattern_t() {
_clean_up();
}
void s3m_t::pattern_t::_clean_up() {
}
s3m_t::pattern_ptr_t::pattern_ptr_t(kaitai::kstream* p__io, s3m_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_body = nullptr;
f_body = false;
_read();
}
void s3m_t::pattern_ptr_t::_read() {
m_paraptr = m__io->read_u2le();
}
s3m_t::pattern_ptr_t::~pattern_ptr_t() {
_clean_up();
}
void s3m_t::pattern_ptr_t::_clean_up() {
if (f_body) {
}
}
s3m_t::pattern_t* s3m_t::pattern_ptr_t::body() {
if (f_body)
return m_body.get();
std::streampos _pos = m__io->pos();
m__io->seek((paraptr() * 16));
m_body = std::unique_ptr<pattern_t>(new pattern_t(m__io, this, m__root));
m__io->seek(_pos);
f_body = true;
return m_body.get();
}
s3m_t::instrument_ptr_t::instrument_ptr_t(kaitai::kstream* p__io, s3m_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_body = nullptr;
f_body = false;
_read();
}
void s3m_t::instrument_ptr_t::_read() {
m_paraptr = m__io->read_u2le();
}
s3m_t::instrument_ptr_t::~instrument_ptr_t() {
_clean_up();
}
void s3m_t::instrument_ptr_t::_clean_up() {
if (f_body) {
}
}
s3m_t::instrument_t* s3m_t::instrument_ptr_t::body() {
if (f_body)
return m_body.get();
std::streampos _pos = m__io->pos();
m__io->seek((paraptr() * 16));
m_body = std::unique_ptr<instrument_t>(new instrument_t(m__io, this, m__root));
m__io->seek(_pos);
f_body = true;
return m_body.get();
}
s3m_t::instrument_t::instrument_t(kaitai::kstream* p__io, s3m_t::instrument_ptr_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void s3m_t::instrument_t::_read() {
m_type = static_cast<s3m_t::instrument_t::inst_types_t>(m__io->read_u1());
m_filename = kaitai::kstream::bytes_terminate(m__io->read_bytes(12), 0, false);
switch (type()) {
case s3m_t::instrument_t::INST_TYPES_SAMPLE: {
m_body = std::unique_ptr<sampled_t>(new sampled_t(m__io, this, m__root));
break;
}
default: {
m_body = std::unique_ptr<adlib_t>(new adlib_t(m__io, this, m__root));
break;
}
}
m_tuning_hz = m__io->read_u4le();
m_reserved2 = m__io->read_bytes(12);
m_sample_name = kaitai::kstream::bytes_terminate(m__io->read_bytes(28), 0, false);
m_magic = m__io->read_bytes(4);
if (!(magic() == std::string("\x53\x43\x52\x53", 4))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x53\x43\x52\x53", 4), magic(), _io(), std::string("/types/instrument/seq/6"));
}
}
s3m_t::instrument_t::~instrument_t() {
_clean_up();
}
void s3m_t::instrument_t::_clean_up() {
}
s3m_t::instrument_t::sampled_t::sampled_t(kaitai::kstream* p__io, s3m_t::instrument_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_paraptr_sample = nullptr;
f_sample = false;
_read();
}
void s3m_t::instrument_t::sampled_t::_read() {
m_paraptr_sample = std::unique_ptr<swapped_u3_t>(new swapped_u3_t(m__io, this, m__root));
m_len_sample = m__io->read_u4le();
m_loop_begin = m__io->read_u4le();
m_loop_end = m__io->read_u4le();
m_default_volume = m__io->read_u1();
m_reserved1 = m__io->read_u1();
m_is_packed = m__io->read_u1();
m_flags = m__io->read_u1();
}
s3m_t::instrument_t::sampled_t::~sampled_t() {
_clean_up();
}
void s3m_t::instrument_t::sampled_t::_clean_up() {
if (f_sample) {
}
}
std::string s3m_t::instrument_t::sampled_t::sample() {
if (f_sample)
return m_sample;
std::streampos _pos = m__io->pos();
m__io->seek((paraptr_sample()->value() * 16));
m_sample = m__io->read_bytes(len_sample());
m__io->seek(_pos);
f_sample = true;
return m_sample;
}
s3m_t::instrument_t::adlib_t::adlib_t(kaitai::kstream* p__io, s3m_t::instrument_t* p__parent, s3m_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void s3m_t::instrument_t::adlib_t::_read() {
m_reserved1 = m__io->read_bytes(3);
if (!(reserved1() == std::string("\x00\x00\x00", 3))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x00\x00\x00", 3), reserved1(), _io(), std::string("/types/instrument/types/adlib/seq/0"));
}
m__unnamed1 = m__io->read_bytes(16);
}
s3m_t::instrument_t::adlib_t::~adlib_t() {
_clean_up();
}
void s3m_t::instrument_t::adlib_t::_clean_up() {
}