From cb57f3a1329d9c542aad19cb3fa1acf1d8e83290 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 13 Jun 2026 14:41:50 +0200 Subject: [PATCH 01/52] Add Kaitai 2KXL SND parser #342 Not wired up beyond unit tests yet. --- CMakeLists.txt | 12 +- src/main/file/kaitai/generated/mpc2000snd.cpp | 87 +++++++++++ src/main/file/kaitai/generated/mpc2000snd.h | 78 ++++++++++ src/test/KaitaiSndTest.cpp | 142 ++++++++++++++++++ .../KaitaiSnd/mpc2000snd_mono_loop_off.SND | Bin 0 -> 16066 bytes .../KaitaiSnd/mpc2000snd_stereo_loop_off.SND | Bin 0 -> 32090 bytes 6 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 src/main/file/kaitai/generated/mpc2000snd.cpp create mode 100644 src/main/file/kaitai/generated/mpc2000snd.h create mode 100644 src/test/KaitaiSndTest.cpp create mode 100755 test-resources/KaitaiSnd/mpc2000snd_mono_loop_off.SND create mode 100755 test-resources/KaitaiSnd/mpc2000snd_stereo_loop_off.SND diff --git a/CMakeLists.txt b/CMakeLists.txt index 94a1bbe8..7c780ad9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,11 @@ FetchContent_Declare(readerwriterqueue SOURCE_DIR ${CMAKE_SOURCE_DIR}/deps/readerwriterqueue ) +FetchContent_Declare(kaitai_runtime + GIT_REPOSITORY https://github.com/izzyreal/kaitai_struct_cpp_stl_runtime + GIT_TAG cpp-serialization +) + FetchContent_Declare(json-schema-validator GIT_REPOSITORY https://github.com/pboettch/json-schema-validator.git GIT_TAG 2.3.0 @@ -101,6 +106,11 @@ target_include_directories(platform_folders INTERFACE $ ) +message(STATUS "Downloading kaitai runtime...") +set(BUILD_TESTS OFF CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(kaitai_runtime) +unset(BUILD_TESTS CACHE) + if(NOT TARGET nlohmann_json::nlohmann_json) FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz @@ -179,7 +189,7 @@ target_include_directories(mpc PUBLIC ${readerwriterqueue_SOURCE_DIR} ) -target_link_libraries(mpc akaifat ghc_filesystem rtmidi samplerate platform_folders nlohmann_json::nlohmann_json nlohmann_json_schema_validator lodepng) +target_link_libraries(mpc akaifat ghc_filesystem rtmidi samplerate platform_folders nlohmann_json::nlohmann_json nlohmann_json_schema_validator lodepng kaitai_struct_cpp_stl_runtime) if(MSVC) target_compile_options(mpc PRIVATE "/MP") diff --git a/src/main/file/kaitai/generated/mpc2000snd.cpp b/src/main/file/kaitai/generated/mpc2000snd.cpp new file mode 100644 index 00000000..09e5e7ad --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000snd.cpp @@ -0,0 +1,87 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "mpc2000snd.h" +#include "kaitai/exceptions.h" +#include +#include + +mpc2000snd_t::mpc2000snd_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mpc2000snd_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; +} + +void mpc2000snd_t::_read() { + m_magic = m__io->read_bytes(2); + if (!(m_magic == std::string("\x01\x04", 2))) { + throw kaitai::validation_not_equal_error(std::string("\x01\x04", 2), m_magic, m__io, std::string("/seq/0")); + } + m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"); + m_level = m__io->read_u1(); + m_tune = m__io->read_s1(); + m_stereo = m__io->read_bits_int_le(1); + m_start = m__io->read_u4le(); + m_end = m__io->read_u4le(); + m_frame_count = m__io->read_u4le(); + m_loop_frame_count = m__io->read_u4le(); + m_loop_enabled = m__io->read_bits_int_le(1); + m_beat_count = m__io->read_u1(); + m_sample_rate = m__io->read_u2le(); + m_frames = std::unique_ptr>(new std::vector()); + const int l_frames = frame_count(); + for (int i = 0; i < l_frames; i++) { + m_frames->push_back(std::move(m__io->read_s2le())); + } + m__dirty = false; +} + +void mpc2000snd_t::_fetch_instances() { + for (std::size_t i = 0; i < m_frames->size(); ++i) { + } +} + +void mpc2000snd_t::_write() { + m__io->write_bytes(m_magic); + m__io->write_bytes(m_name); + m__io->write_u1(m_level); + m__io->write_s1(m_tune); + m__io->write_bits_int_le(1, ((m_stereo) ? 1 : 0)); + m__io->write_u4le(m_start); + m__io->write_u4le(m_end); + m__io->write_u4le(m_frame_count); + m__io->write_u4le(m_loop_frame_count); + m__io->write_bits_int_le(1, ((m_loop_enabled) ? 1 : 0)); + m__io->write_u1(m_beat_count); + m__io->write_u2le(m_sample_rate); + if (m_frames == nullptr) { + throw std::runtime_error("/seq/12: repeated field is not set"); + } + for (std::vector::const_iterator it = m_frames->begin(); it != m_frames->end(); ++it) { + m__io->write_s2le((*it)); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000snd_t::_check() { + if (m_magic.size() != static_cast(2)) { + throw std::runtime_error("/seq/0: size mismatch"); + } + if (!(m_magic == std::string("\x01\x04", 2))) { + throw kaitai::validation_not_equal_error(std::string("\x01\x04", 2), m_magic, m__io, std::string("/seq/0")); + } + if (m_name.size() != static_cast(17)) { + throw std::runtime_error("/seq/1: size mismatch"); + } + if (m_frames == nullptr) { + throw std::runtime_error("/seq/12: repeated field is not set"); + } + if (m_frames->size() != static_cast(frame_count())) { + throw std::runtime_error("/seq/12: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_frames->begin(); it != m_frames->end(); ++it) { + } + m__dirty = false; +} + +mpc2000snd_t::~mpc2000snd_t() {} diff --git a/src/main/file/kaitai/generated/mpc2000snd.h b/src/main/file/kaitai/generated/mpc2000snd.h new file mode 100644 index 00000000..10b92702 --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000snd.h @@ -0,0 +1,78 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class mpc2000snd_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +class mpc2000snd_t : public kaitai::kstruct { + +public: + +private: + bool m__dirty; + +public: + + mpc2000snd_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mpc2000snd_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~mpc2000snd_t(); + std::string magic() const { return m_magic; } + void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } + std::string name() const { return m_name; } + void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } + uint8_t level() const { return m_level; } + void set_level(uint8_t _v) { m__dirty = true; m_level = std::move(_v); } + int8_t tune() const { return m_tune; } + void set_tune(int8_t _v) { m__dirty = true; m_tune = std::move(_v); } + bool stereo() const { return m_stereo; } + void set_stereo(bool _v) { m__dirty = true; m_stereo = std::move(_v); } + uint32_t start() const { return m_start; } + void set_start(uint32_t _v) { m__dirty = true; m_start = std::move(_v); } + uint32_t end() const { return m_end; } + void set_end(uint32_t _v) { m__dirty = true; m_end = std::move(_v); } + uint32_t frame_count() const { return m_frame_count; } + void set_frame_count(uint32_t _v) { m__dirty = true; m_frame_count = std::move(_v); } + uint32_t loop_frame_count() const { return m_loop_frame_count; } + void set_loop_frame_count(uint32_t _v) { m__dirty = true; m_loop_frame_count = std::move(_v); } + bool loop_enabled() const { return m_loop_enabled; } + void set_loop_enabled(bool _v) { m__dirty = true; m_loop_enabled = std::move(_v); } + uint8_t beat_count() const { return m_beat_count; } + void set_beat_count(uint8_t _v) { m__dirty = true; m_beat_count = std::move(_v); } + uint16_t sample_rate() const { return m_sample_rate; } + void set_sample_rate(uint16_t _v) { m__dirty = true; m_sample_rate = std::move(_v); } + std::vector* frames() const { return m_frames.get(); } + void set_frames(std::unique_ptr> _v) { m__dirty = true; m_frames = std::move(_v); } + mpc2000snd_t* _root() const { return m__root; } + void set__root(mpc2000snd_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; m__parent = std::move(_v); } + +private: + std::string m_magic; + std::string m_name; + uint8_t m_level; + int8_t m_tune; + bool m_stereo; + uint32_t m_start; + uint32_t m_end; + uint32_t m_frame_count; + uint32_t m_loop_frame_count; + bool m_loop_enabled; + uint8_t m_beat_count; + uint16_t m_sample_rate; + std::unique_ptr> m_frames; + mpc2000snd_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/test/KaitaiSndTest.cpp b/src/test/KaitaiSndTest.cpp new file mode 100644 index 00000000..23aa6eb2 --- /dev/null +++ b/src/test/KaitaiSndTest.cpp @@ -0,0 +1,142 @@ +#include + +#include "SampleOps.hpp" +#include "file/kaitai/generated/mpc2000snd.h" +#include "file/sndreader/SndReader.hpp" +#include "file/sndwriter/SndWriter.hpp" +#include "sampler/Sound.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +using namespace mpc::file::sndreader; +using namespace mpc::file::sndwriter; +using namespace mpc::sampleops; + +TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") +{ + mpc::sampler::Sound sound(44100); + sound.setName("KICK_01"); + sound.setMono(true); + sound.setLevel(100); + sound.setTune(-2); + + auto inputData = sound.getMutableSampleData(); + inputData->push_back(short_to_float(static_cast(1234))); + inputData->push_back(short_to_float(static_cast(-1234))); + + sound.setStart(0); + sound.setEnd(2); + sound.setLoopTo(1); + sound.setLoopEnabled(true); + sound.setBeatCount(4); + + SndWriter handwrittenWriter(&sound); + const auto handwrittenBytes = handwrittenWriter.getSndFileArray(); + + std::stringstream parseStream( + std::string(handwrittenBytes.begin(), handwrittenBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000snd_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.magic() == std::string("\x01\x04", 2)); + REQUIRE(parsed.name() == std::string(handwrittenBytes.begin() + 2, handwrittenBytes.begin() + 19)); + REQUIRE(parsed.level() == 100); + REQUIRE(parsed.tune() == -2); + REQUIRE(parsed.stereo() == false); + REQUIRE(parsed.start() == 0U); + REQUIRE(parsed.end() == 2U); + REQUIRE(parsed.frame_count() == 2U); + REQUIRE(parsed.loop_frame_count() == 1U); + REQUIRE(parsed.loop_enabled() == true); + REQUIRE(parsed.beat_count() == 4); + REQUIRE(parsed.sample_rate() == 44100); + REQUIRE(parsed.frames() != nullptr); + REQUIRE(parsed.frames()->size() == 2U); + REQUIRE(parsed.frames()->at(0) == 1234); + REQUIRE(parsed.frames()->at(1) == -1234); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto kaitaiBytes = writeStream.str(); + REQUIRE(kaitaiBytes == std::string(handwrittenBytes.begin(), handwrittenBytes.end())); + + std::vector kaitaiBytesVec(kaitaiBytes.begin(), kaitaiBytes.end()); + SndReader handwrittenReader(kaitaiBytesVec); + auto outputData = std::make_shared>(); + handwrittenReader.readData(outputData); + + REQUIRE(handwrittenReader.isHeaderValid()); + REQUIRE(handwrittenReader.getName() == "KICK_01"); + REQUIRE(handwrittenReader.isMono()); + REQUIRE(handwrittenReader.getLevel() == 100); + REQUIRE(handwrittenReader.getTune() == -2); + REQUIRE(handwrittenReader.getStart() == 0); + REQUIRE(handwrittenReader.getEnd() == 2); + REQUIRE(handwrittenReader.getLoopLength() == 1); + REQUIRE(handwrittenReader.isLoopEnabled()); + REQUIRE(handwrittenReader.getNumberOfBeats() == 4); + REQUIRE(handwrittenReader.getSampleRate() == 44100); + REQUIRE(outputData->size() == inputData->size()); + REQUIRE((*outputData)[0] == (*inputData)[0]); + REQUIRE((*outputData)[1] == (*inputData)[1]); +} + +TEST_CASE("Kaitai MPC2000 SND parses real mono and stereo files", "[kaitai-snd][hardware-files]") +{ + auto parseFile = [](const std::string& resourcePath, auto&& assertions) { + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open(resourcePath); + std::stringstream stream( + std::string( + std::string_view(file.begin(), file.end() - file.begin()) + ), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream ks(&stream); + mpc2000snd_t parsed(&ks); + parsed._read(); + assertions(parsed); + }; + + parseFile("test/KaitaiSnd/mpc2000snd_mono_loop_off.SND", [](const mpc2000snd_t& mono) { + REQUIRE(mono.magic() == std::string("\x01\x04", 2)); + REQUIRE(mono.level() == 100); + REQUIRE(mono.tune() == 0); + REQUIRE(mono.start() == 0U); + REQUIRE(mono.end() == 8012U); + REQUIRE(mono.frame_count() == 8012U); + REQUIRE(mono.loop_frame_count() == 8012U); + REQUIRE(mono.beat_count() == 4); + REQUIRE(mono.sample_rate() == 44100); + REQUIRE(mono.stereo() == false); + }); + + parseFile("test/KaitaiSnd/mpc2000snd_stereo_loop_off.SND", [](const mpc2000snd_t& stereo) { + REQUIRE(stereo.magic() == std::string("\x01\x04", 2)); + REQUIRE(stereo.level() == 100); + REQUIRE(stereo.tune() == 0); + REQUIRE(stereo.start() == 0U); + REQUIRE(stereo.end() == 8012U); + REQUIRE(stereo.frame_count() == 8012U); + REQUIRE(stereo.loop_frame_count() == 8012U); + REQUIRE(stereo.beat_count() == 4); + REQUIRE(stereo.sample_rate() == 44100); + REQUIRE(stereo.stereo() == true); + }); +} diff --git a/test-resources/KaitaiSnd/mpc2000snd_mono_loop_off.SND b/test-resources/KaitaiSnd/mpc2000snd_mono_loop_off.SND new file mode 100755 index 0000000000000000000000000000000000000000..1ce0f1ed7eeaf425120d691b0e9fcdd39c25ba62 GIT binary patch literal 16066 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 b>HZa8p$E3? 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 literal 0 HcmV?d00001 From 733ea1cbfb0c0d65342b10dc76f9a0c57242b6a0 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 13 Jun 2026 15:41:08 +0200 Subject: [PATCH 02/52] Add Kaitai 2KXL PGM parser #342 --- .../file/kaitai/generated/mpc2000xl_pgm.cpp | 401 ++++++++++++++++++ .../file/kaitai/generated/mpc2000xl_pgm.h | 341 +++++++++++++++ src/test/KaitaiPgmTest.cpp | 218 ++++++++++ src/test/KaitaiSndTest.cpp | 6 +- test-resources/RealMpc2000xl/Pgm/NEWPGM-A.PGM | Bin 0 -> 2324 bytes .../Snd/mono_loop_off.SND} | Bin .../Snd/stereo_loop_off.SND} | Bin 7 files changed, 963 insertions(+), 3 deletions(-) create mode 100644 src/main/file/kaitai/generated/mpc2000xl_pgm.cpp create mode 100644 src/main/file/kaitai/generated/mpc2000xl_pgm.h create mode 100644 src/test/KaitaiPgmTest.cpp create mode 100755 test-resources/RealMpc2000xl/Pgm/NEWPGM-A.PGM rename test-resources/{KaitaiSnd/mpc2000snd_mono_loop_off.SND => RealMpc2000xl/Snd/mono_loop_off.SND} (100%) rename test-resources/{KaitaiSnd/mpc2000snd_stereo_loop_off.SND => RealMpc2000xl/Snd/stereo_loop_off.SND} (100%) diff --git a/src/main/file/kaitai/generated/mpc2000xl_pgm.cpp b/src/main/file/kaitai/generated/mpc2000xl_pgm.cpp new file mode 100644 index 00000000..5d91f8b1 --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_pgm.cpp @@ -0,0 +1,401 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "mpc2000xl_pgm.h" +#include "kaitai/exceptions.h" +#include +#include +const std::set mpc2000xl_pgm_t::_values_decay_mode_t{ + mpc2000xl_pgm_t::DECAY_MODE_END, + mpc2000xl_pgm_t::DECAY_MODE_START, +}; +bool mpc2000xl_pgm_t::_is_defined_decay_mode_t(mpc2000xl_pgm_t::decay_mode_t v) { + return mpc2000xl_pgm_t::_values_decay_mode_t.find(v) != mpc2000xl_pgm_t::_values_decay_mode_t.end(); +} +const std::set mpc2000xl_pgm_t::_values_fx_output_t{ + mpc2000xl_pgm_t::FX_OUTPUT_NONE, + mpc2000xl_pgm_t::FX_OUTPUT_M1, + mpc2000xl_pgm_t::FX_OUTPUT_M2, + mpc2000xl_pgm_t::FX_OUTPUT_R1, + mpc2000xl_pgm_t::FX_OUTPUT_R2, +}; +bool mpc2000xl_pgm_t::_is_defined_fx_output_t(mpc2000xl_pgm_t::fx_output_t v) { + return mpc2000xl_pgm_t::_values_fx_output_t.find(v) != mpc2000xl_pgm_t::_values_fx_output_t.end(); +} +const std::set mpc2000xl_pgm_t::_values_slider_parameter_t{ + mpc2000xl_pgm_t::SLIDER_PARAMETER_TUNING, + mpc2000xl_pgm_t::SLIDER_PARAMETER_DECAY, + mpc2000xl_pgm_t::SLIDER_PARAMETER_ATTACK, + mpc2000xl_pgm_t::SLIDER_PARAMETER_FILTER, +}; +bool mpc2000xl_pgm_t::_is_defined_slider_parameter_t(mpc2000xl_pgm_t::slider_parameter_t v) { + return mpc2000xl_pgm_t::_values_slider_parameter_t.find(v) != mpc2000xl_pgm_t::_values_slider_parameter_t.end(); +} +const std::set mpc2000xl_pgm_t::_values_sound_generation_mode_t{ + mpc2000xl_pgm_t::SOUND_GENERATION_MODE_NORMAL, + mpc2000xl_pgm_t::SOUND_GENERATION_MODE_SIMULT, + mpc2000xl_pgm_t::SOUND_GENERATION_MODE_VEL_SW, +}; +bool mpc2000xl_pgm_t::_is_defined_sound_generation_mode_t(mpc2000xl_pgm_t::sound_generation_mode_t v) { + return mpc2000xl_pgm_t::_values_sound_generation_mode_t.find(v) != mpc2000xl_pgm_t::_values_sound_generation_mode_t.end(); +} +const std::set mpc2000xl_pgm_t::_values_voice_overlap_mode_t{ + mpc2000xl_pgm_t::VOICE_OVERLAP_MODE_POLY, + mpc2000xl_pgm_t::VOICE_OVERLAP_MODE_MONO, + mpc2000xl_pgm_t::VOICE_OVERLAP_MODE_NOTE_OFF, +}; +bool mpc2000xl_pgm_t::_is_defined_voice_overlap_mode_t(mpc2000xl_pgm_t::voice_overlap_mode_t v) { + return mpc2000xl_pgm_t::_values_voice_overlap_mode_t.find(v) != mpc2000xl_pgm_t::_values_voice_overlap_mode_t.end(); +} + +mpc2000xl_pgm_t::mpc2000xl_pgm_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mpc2000xl_pgm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; +} + +void mpc2000xl_pgm_t::_read() { + m_magic = m__io->read_bytes(2); + if (!(m_magic == std::string("\x07\x04", 2))) { + throw kaitai::validation_not_equal_error(std::string("\x07\x04", 2), m_magic, m__io, std::string("/seq/0")); + } + m_sound_count = m__io->read_u2le(); + m_sound_names = std::unique_ptr>(new std::vector()); + const int l_sound_names = sound_count(); + for (int i = 0; i < l_sound_names; i++) { + m_sound_names->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"))); + } + m__unnamed3 = m__io->read_bytes(2); + m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"); + m_slider = std::unique_ptr(new slider_t(m__io, this, m__root)); + m_slider->_read(); + m_program_change = m__io->read_u1(); + m__unnamed7 = m__io->read_bytes(5); + m_note_parameters = std::unique_ptr>>(new std::vector>()); + const int l_note_parameters = 64; + for (int i = 0; i < l_note_parameters; i++) { + std::unique_ptr _t_note_parameters = std::unique_ptr(new note_t(m__io, this, m__root)); + try { + _t_note_parameters->_read(); + } catch(...) { + m_note_parameters->push_back(std::move(_t_note_parameters)); + throw; + } + m_note_parameters->push_back(std::move(_t_note_parameters)); + } + m__unnamed9 = m__io->read_bytes(1); + m_pad_mixers = std::unique_ptr>>(new std::vector>()); + const int l_pad_mixers = 64; + for (int i = 0; i < l_pad_mixers; i++) { + std::unique_ptr _t_pad_mixers = std::unique_ptr(new pad_mixer_t(m__io, this, m__root)); + try { + _t_pad_mixers->_read(); + } catch(...) { + m_pad_mixers->push_back(std::move(_t_pad_mixers)); + throw; + } + m_pad_mixers->push_back(std::move(_t_pad_mixers)); + } + m__unnamed11 = m__io->read_bytes(3); + m_pad_to_note_mapping = std::unique_ptr>(new std::vector()); + const int l_pad_to_note_mapping = 64; + for (int i = 0; i < l_pad_to_note_mapping; i++) { + m_pad_to_note_mapping->push_back(std::move(m__io->read_s1())); + } + m__unnamed13 = m__io->read_bytes(200); + m__dirty = false; +} + +void mpc2000xl_pgm_t::_fetch_instances() { + for (std::size_t i = 0; i < m_sound_names->size(); ++i) { + } + m_slider.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_note_parameters->size(); ++i) { + m_note_parameters->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_pad_mixers->size(); ++i) { + m_pad_mixers->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_pad_to_note_mapping->size(); ++i) { + } +} + +void mpc2000xl_pgm_t::_write() { + m__io->write_bytes(m_magic); + m__io->write_u2le(m_sound_count); + if (m_sound_names == nullptr) { + throw std::runtime_error("/seq/2: repeated field is not set"); + } + for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { + m__io->write_bytes((*it)); + } + m__io->write_bytes(m__unnamed3); + m__io->write_bytes(m_name); + if (m_slider.get() == nullptr) { + throw std::runtime_error("/seq/5: nested object is not set"); + } + m_slider.get()->_set_io(m__io); + m_slider.get()->_write(); + m__io->write_u1(m_program_change); + m__io->write_bytes(m__unnamed7); + if (m_note_parameters == nullptr) { + throw std::runtime_error("/seq/8: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_note_parameters->begin(); it != m_note_parameters->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/8: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed9); + if (m_pad_mixers == nullptr) { + throw std::runtime_error("/seq/10: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_pad_mixers->begin(); it != m_pad_mixers->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/10: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed11); + if (m_pad_to_note_mapping == nullptr) { + throw std::runtime_error("/seq/12: repeated field is not set"); + } + for (std::vector::const_iterator it = m_pad_to_note_mapping->begin(); it != m_pad_to_note_mapping->end(); ++it) { + m__io->write_s1((*it)); + } + m__io->write_bytes(m__unnamed13); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_pgm_t::_check() { + if (m_magic.size() != static_cast(2)) { + throw std::runtime_error("/seq/0: size mismatch"); + } + if (!(m_magic == std::string("\x07\x04", 2))) { + throw kaitai::validation_not_equal_error(std::string("\x07\x04", 2), m_magic, m__io, std::string("/seq/0")); + } + if (m_sound_names == nullptr) { + throw std::runtime_error("/seq/2: repeated field is not set"); + } + if (m_sound_names->size() != static_cast(sound_count())) { + throw std::runtime_error("/seq/2: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { + if ((*it).size() != static_cast(17)) { + throw std::runtime_error("/seq/2: size mismatch"); + } + } + if (m__unnamed3.size() != static_cast(2)) { + throw std::runtime_error("/seq/3: size mismatch"); + } + if (m_name.size() != static_cast(17)) { + throw std::runtime_error("/seq/4: size mismatch"); + } + if (m_slider.get() == nullptr) { + throw std::runtime_error("/seq/5: nested object is not set"); + } + m_slider.get()->_set_io(m__io); + m_slider.get()->_check(); + if (m__unnamed7.size() != static_cast(5)) { + throw std::runtime_error("/seq/7: size mismatch"); + } + if (m_note_parameters == nullptr) { + throw std::runtime_error("/seq/8: repeated field is not set"); + } + if (m_note_parameters->size() != static_cast(64)) { + throw std::runtime_error("/seq/8: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_note_parameters->begin(); it != m_note_parameters->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/8: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed9.size() != static_cast(1)) { + throw std::runtime_error("/seq/9: size mismatch"); + } + if (m_pad_mixers == nullptr) { + throw std::runtime_error("/seq/10: repeated field is not set"); + } + if (m_pad_mixers->size() != static_cast(64)) { + throw std::runtime_error("/seq/10: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_pad_mixers->begin(); it != m_pad_mixers->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/10: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed11.size() != static_cast(3)) { + throw std::runtime_error("/seq/11: size mismatch"); + } + if (m_pad_to_note_mapping == nullptr) { + throw std::runtime_error("/seq/12: repeated field is not set"); + } + if (m_pad_to_note_mapping->size() != static_cast(64)) { + throw std::runtime_error("/seq/12: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_pad_to_note_mapping->begin(); it != m_pad_to_note_mapping->end(); ++it) { + } + if (m__unnamed13.size() != static_cast(200)) { + throw std::runtime_error("/seq/13: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_pgm_t::~mpc2000xl_pgm_t() {} + +mpc2000xl_pgm_t::note_t::note_t(kaitai::kstream* p__io, mpc2000xl_pgm_t* p__parent, mpc2000xl_pgm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_pgm_t::note_t::_read() { + m_sound_index = m__io->read_u1(); + m_sound_generation_mode = static_cast(m__io->read_u1()); + m_velocity_range_lower = m__io->read_u1(); + m_also_play_use_note_1 = m__io->read_u1(); + m_velocity_range_upper = m__io->read_u1(); + m_also_play_use_note_2 = m__io->read_u1(); + m_voice_overlap_mode = static_cast(m__io->read_u1()); + m_mute_assign_1 = m__io->read_u1(); + m_mute_assign_2 = m__io->read_u1(); + m_tune = m__io->read_s2le(); + m_attack = m__io->read_u1(); + m_decay = m__io->read_u1(); + m_decay_mode = static_cast(m__io->read_u1()); + m_cutoff = m__io->read_u1(); + m_resonance = m__io->read_u1(); + m_velocity_envelope_to_filter_attack = m__io->read_u1(); + m_velocity_envelope_to_filter_decay = m__io->read_u1(); + m_velocity_envelope_to_filter_amount = m__io->read_u1(); + m_velocity_to_level = m__io->read_u1(); + m_velocity_to_attack = m__io->read_u1(); + m_velocity_to_start = m__io->read_u1(); + m_velocity_to_cutoff = m__io->read_u1(); + m_slider_parameter = static_cast(m__io->read_u1()); + m_velocity_to_pitch = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_pgm_t::note_t::_fetch_instances() { +} + +void mpc2000xl_pgm_t::note_t::_write() { + m__io->write_u1(m_sound_index); + m__io->write_u1(static_cast(m_sound_generation_mode)); + m__io->write_u1(m_velocity_range_lower); + m__io->write_u1(m_also_play_use_note_1); + m__io->write_u1(m_velocity_range_upper); + m__io->write_u1(m_also_play_use_note_2); + m__io->write_u1(static_cast(m_voice_overlap_mode)); + m__io->write_u1(m_mute_assign_1); + m__io->write_u1(m_mute_assign_2); + m__io->write_s2le(m_tune); + m__io->write_u1(m_attack); + m__io->write_u1(m_decay); + m__io->write_u1(static_cast(m_decay_mode)); + m__io->write_u1(m_cutoff); + m__io->write_u1(m_resonance); + m__io->write_u1(m_velocity_envelope_to_filter_attack); + m__io->write_u1(m_velocity_envelope_to_filter_decay); + m__io->write_u1(m_velocity_envelope_to_filter_amount); + m__io->write_u1(m_velocity_to_level); + m__io->write_u1(m_velocity_to_attack); + m__io->write_u1(m_velocity_to_start); + m__io->write_u1(m_velocity_to_cutoff); + m__io->write_u1(static_cast(m_slider_parameter)); + m__io->write_u1(m_velocity_to_pitch); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_pgm_t::note_t::_check() { + m__dirty = false; +} + +mpc2000xl_pgm_t::note_t::~note_t() {} + +mpc2000xl_pgm_t::pad_mixer_t::pad_mixer_t(kaitai::kstream* p__io, mpc2000xl_pgm_t* p__parent, mpc2000xl_pgm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_pgm_t::pad_mixer_t::_read() { + m_fx_output = static_cast(m__io->read_u1()); + m_volume = m__io->read_u1(); + m_pan = m__io->read_u1(); + m_volume_individual = m__io->read_u1(); + m_output = m__io->read_u1(); + m_effects_send_level = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_pgm_t::pad_mixer_t::_fetch_instances() { +} + +void mpc2000xl_pgm_t::pad_mixer_t::_write() { + m__io->write_u1(static_cast(m_fx_output)); + m__io->write_u1(m_volume); + m__io->write_u1(m_pan); + m__io->write_u1(m_volume_individual); + m__io->write_u1(m_output); + m__io->write_u1(m_effects_send_level); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_pgm_t::pad_mixer_t::_check() { + m__dirty = false; +} + +mpc2000xl_pgm_t::pad_mixer_t::~pad_mixer_t() {} + +mpc2000xl_pgm_t::slider_t::slider_t(kaitai::kstream* p__io, mpc2000xl_pgm_t* p__parent, mpc2000xl_pgm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_pgm_t::slider_t::_read() { + m_note = m__io->read_u1(); + m_tune_low = m__io->read_s1(); + m_tune_high = m__io->read_s1(); + m_decay_low = m__io->read_s1(); + m_decay_high = m__io->read_s1(); + m_attack_low = m__io->read_s1(); + m_attack_high = m__io->read_s1(); + m_filter_low = m__io->read_s1(); + m_filter_high = m__io->read_s1(); + m__dirty = false; +} + +void mpc2000xl_pgm_t::slider_t::_fetch_instances() { +} + +void mpc2000xl_pgm_t::slider_t::_write() { + m__io->write_u1(m_note); + m__io->write_s1(m_tune_low); + m__io->write_s1(m_tune_high); + m__io->write_s1(m_decay_low); + m__io->write_s1(m_decay_high); + m__io->write_s1(m_attack_low); + m__io->write_s1(m_attack_high); + m__io->write_s1(m_filter_low); + m__io->write_s1(m_filter_high); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_pgm_t::slider_t::_check() { + m__dirty = false; +} + +mpc2000xl_pgm_t::slider_t::~slider_t() {} diff --git a/src/main/file/kaitai/generated/mpc2000xl_pgm.h b/src/main/file/kaitai/generated/mpc2000xl_pgm.h new file mode 100644 index 00000000..8725d2ca --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_pgm.h @@ -0,0 +1,341 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class mpc2000xl_pgm_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +class mpc2000xl_pgm_t : public kaitai::kstruct { + +public: + class note_t; + class pad_mixer_t; + class slider_t; + + enum decay_mode_t { + DECAY_MODE_END = 0, + DECAY_MODE_START = 1 + }; + static bool _is_defined_decay_mode_t(decay_mode_t v); + +private: + static const std::set _values_decay_mode_t; + +public: + + enum fx_output_t { + FX_OUTPUT_NONE = 0, + FX_OUTPUT_M1 = 1, + FX_OUTPUT_M2 = 2, + FX_OUTPUT_R1 = 3, + FX_OUTPUT_R2 = 4 + }; + static bool _is_defined_fx_output_t(fx_output_t v); + +private: + static const std::set _values_fx_output_t; + +public: + + enum slider_parameter_t { + SLIDER_PARAMETER_TUNING = 0, + SLIDER_PARAMETER_DECAY = 1, + SLIDER_PARAMETER_ATTACK = 2, + SLIDER_PARAMETER_FILTER = 3 + }; + static bool _is_defined_slider_parameter_t(slider_parameter_t v); + +private: + static const std::set _values_slider_parameter_t; + +public: + + enum sound_generation_mode_t { + SOUND_GENERATION_MODE_NORMAL = 0, + SOUND_GENERATION_MODE_SIMULT = 1, + SOUND_GENERATION_MODE_VEL_SW = 2 + }; + static bool _is_defined_sound_generation_mode_t(sound_generation_mode_t v); + +private: + static const std::set _values_sound_generation_mode_t; + +public: + + enum voice_overlap_mode_t { + VOICE_OVERLAP_MODE_POLY = 0, + VOICE_OVERLAP_MODE_MONO = 1, + VOICE_OVERLAP_MODE_NOTE_OFF = 2 + }; + static bool _is_defined_voice_overlap_mode_t(voice_overlap_mode_t v); + +private: + static const std::set _values_voice_overlap_mode_t; + +public: + +private: + bool m__dirty; + +public: + + mpc2000xl_pgm_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mpc2000xl_pgm_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~mpc2000xl_pgm_t(); + + class note_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + note_t(kaitai::kstream* p__io, mpc2000xl_pgm_t* p__parent = nullptr, mpc2000xl_pgm_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~note_t(); + uint8_t sound_index() const { return m_sound_index; } + void set_sound_index(uint8_t _v) { m__dirty = true; m_sound_index = std::move(_v); } + sound_generation_mode_t sound_generation_mode() const { return m_sound_generation_mode; } + void set_sound_generation_mode(sound_generation_mode_t _v) { m__dirty = true; m_sound_generation_mode = std::move(_v); } + uint8_t velocity_range_lower() const { return m_velocity_range_lower; } + void set_velocity_range_lower(uint8_t _v) { m__dirty = true; m_velocity_range_lower = std::move(_v); } + uint8_t also_play_use_note_1() const { return m_also_play_use_note_1; } + void set_also_play_use_note_1(uint8_t _v) { m__dirty = true; m_also_play_use_note_1 = std::move(_v); } + uint8_t velocity_range_upper() const { return m_velocity_range_upper; } + void set_velocity_range_upper(uint8_t _v) { m__dirty = true; m_velocity_range_upper = std::move(_v); } + uint8_t also_play_use_note_2() const { return m_also_play_use_note_2; } + void set_also_play_use_note_2(uint8_t _v) { m__dirty = true; m_also_play_use_note_2 = std::move(_v); } + voice_overlap_mode_t voice_overlap_mode() const { return m_voice_overlap_mode; } + void set_voice_overlap_mode(voice_overlap_mode_t _v) { m__dirty = true; m_voice_overlap_mode = std::move(_v); } + uint8_t mute_assign_1() const { return m_mute_assign_1; } + void set_mute_assign_1(uint8_t _v) { m__dirty = true; m_mute_assign_1 = std::move(_v); } + uint8_t mute_assign_2() const { return m_mute_assign_2; } + void set_mute_assign_2(uint8_t _v) { m__dirty = true; m_mute_assign_2 = std::move(_v); } + int16_t tune() const { return m_tune; } + void set_tune(int16_t _v) { m__dirty = true; m_tune = std::move(_v); } + uint8_t attack() const { return m_attack; } + void set_attack(uint8_t _v) { m__dirty = true; m_attack = std::move(_v); } + uint8_t decay() const { return m_decay; } + void set_decay(uint8_t _v) { m__dirty = true; m_decay = std::move(_v); } + decay_mode_t decay_mode() const { return m_decay_mode; } + void set_decay_mode(decay_mode_t _v) { m__dirty = true; m_decay_mode = std::move(_v); } + uint8_t cutoff() const { return m_cutoff; } + void set_cutoff(uint8_t _v) { m__dirty = true; m_cutoff = std::move(_v); } + uint8_t resonance() const { return m_resonance; } + void set_resonance(uint8_t _v) { m__dirty = true; m_resonance = std::move(_v); } + uint8_t velocity_envelope_to_filter_attack() const { return m_velocity_envelope_to_filter_attack; } + void set_velocity_envelope_to_filter_attack(uint8_t _v) { m__dirty = true; m_velocity_envelope_to_filter_attack = std::move(_v); } + uint8_t velocity_envelope_to_filter_decay() const { return m_velocity_envelope_to_filter_decay; } + void set_velocity_envelope_to_filter_decay(uint8_t _v) { m__dirty = true; m_velocity_envelope_to_filter_decay = std::move(_v); } + uint8_t velocity_envelope_to_filter_amount() const { return m_velocity_envelope_to_filter_amount; } + void set_velocity_envelope_to_filter_amount(uint8_t _v) { m__dirty = true; m_velocity_envelope_to_filter_amount = std::move(_v); } + uint8_t velocity_to_level() const { return m_velocity_to_level; } + void set_velocity_to_level(uint8_t _v) { m__dirty = true; m_velocity_to_level = std::move(_v); } + uint8_t velocity_to_attack() const { return m_velocity_to_attack; } + void set_velocity_to_attack(uint8_t _v) { m__dirty = true; m_velocity_to_attack = std::move(_v); } + uint8_t velocity_to_start() const { return m_velocity_to_start; } + void set_velocity_to_start(uint8_t _v) { m__dirty = true; m_velocity_to_start = std::move(_v); } + uint8_t velocity_to_cutoff() const { return m_velocity_to_cutoff; } + void set_velocity_to_cutoff(uint8_t _v) { m__dirty = true; m_velocity_to_cutoff = std::move(_v); } + slider_parameter_t slider_parameter() const { return m_slider_parameter; } + void set_slider_parameter(slider_parameter_t _v) { m__dirty = true; m_slider_parameter = std::move(_v); } + uint8_t velocity_to_pitch() const { return m_velocity_to_pitch; } + void set_velocity_to_pitch(uint8_t _v) { m__dirty = true; m_velocity_to_pitch = std::move(_v); } + mpc2000xl_pgm_t* _root() const { return m__root; } + void set__root(mpc2000xl_pgm_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_pgm_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_pgm_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_sound_index; + sound_generation_mode_t m_sound_generation_mode; + uint8_t m_velocity_range_lower; + uint8_t m_also_play_use_note_1; + uint8_t m_velocity_range_upper; + uint8_t m_also_play_use_note_2; + voice_overlap_mode_t m_voice_overlap_mode; + uint8_t m_mute_assign_1; + uint8_t m_mute_assign_2; + int16_t m_tune; + uint8_t m_attack; + uint8_t m_decay; + decay_mode_t m_decay_mode; + uint8_t m_cutoff; + uint8_t m_resonance; + uint8_t m_velocity_envelope_to_filter_attack; + uint8_t m_velocity_envelope_to_filter_decay; + uint8_t m_velocity_envelope_to_filter_amount; + uint8_t m_velocity_to_level; + uint8_t m_velocity_to_attack; + uint8_t m_velocity_to_start; + uint8_t m_velocity_to_cutoff; + slider_parameter_t m_slider_parameter; + uint8_t m_velocity_to_pitch; + mpc2000xl_pgm_t* m__root; + mpc2000xl_pgm_t* m__parent; + }; + + class pad_mixer_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + pad_mixer_t(kaitai::kstream* p__io, mpc2000xl_pgm_t* p__parent = nullptr, mpc2000xl_pgm_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~pad_mixer_t(); + fx_output_t fx_output() const { return m_fx_output; } + void set_fx_output(fx_output_t _v) { m__dirty = true; m_fx_output = std::move(_v); } + uint8_t volume() const { return m_volume; } + void set_volume(uint8_t _v) { m__dirty = true; m_volume = std::move(_v); } + uint8_t pan() const { return m_pan; } + void set_pan(uint8_t _v) { m__dirty = true; m_pan = std::move(_v); } + uint8_t volume_individual() const { return m_volume_individual; } + void set_volume_individual(uint8_t _v) { m__dirty = true; m_volume_individual = std::move(_v); } + uint8_t output() const { return m_output; } + void set_output(uint8_t _v) { m__dirty = true; m_output = std::move(_v); } + uint8_t effects_send_level() const { return m_effects_send_level; } + void set_effects_send_level(uint8_t _v) { m__dirty = true; m_effects_send_level = std::move(_v); } + mpc2000xl_pgm_t* _root() const { return m__root; } + void set__root(mpc2000xl_pgm_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_pgm_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_pgm_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + fx_output_t m_fx_output; + uint8_t m_volume; + uint8_t m_pan; + uint8_t m_volume_individual; + uint8_t m_output; + uint8_t m_effects_send_level; + mpc2000xl_pgm_t* m__root; + mpc2000xl_pgm_t* m__parent; + }; + + class slider_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + slider_t(kaitai::kstream* p__io, mpc2000xl_pgm_t* p__parent = nullptr, mpc2000xl_pgm_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~slider_t(); + uint8_t note() const { return m_note; } + void set_note(uint8_t _v) { m__dirty = true; m_note = std::move(_v); } + int8_t tune_low() const { return m_tune_low; } + void set_tune_low(int8_t _v) { m__dirty = true; m_tune_low = std::move(_v); } + int8_t tune_high() const { return m_tune_high; } + void set_tune_high(int8_t _v) { m__dirty = true; m_tune_high = std::move(_v); } + int8_t decay_low() const { return m_decay_low; } + void set_decay_low(int8_t _v) { m__dirty = true; m_decay_low = std::move(_v); } + int8_t decay_high() const { return m_decay_high; } + void set_decay_high(int8_t _v) { m__dirty = true; m_decay_high = std::move(_v); } + int8_t attack_low() const { return m_attack_low; } + void set_attack_low(int8_t _v) { m__dirty = true; m_attack_low = std::move(_v); } + int8_t attack_high() const { return m_attack_high; } + void set_attack_high(int8_t _v) { m__dirty = true; m_attack_high = std::move(_v); } + int8_t filter_low() const { return m_filter_low; } + void set_filter_low(int8_t _v) { m__dirty = true; m_filter_low = std::move(_v); } + int8_t filter_high() const { return m_filter_high; } + void set_filter_high(int8_t _v) { m__dirty = true; m_filter_high = std::move(_v); } + mpc2000xl_pgm_t* _root() const { return m__root; } + void set__root(mpc2000xl_pgm_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_pgm_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_pgm_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_note; + int8_t m_tune_low; + int8_t m_tune_high; + int8_t m_decay_low; + int8_t m_decay_high; + int8_t m_attack_low; + int8_t m_attack_high; + int8_t m_filter_low; + int8_t m_filter_high; + mpc2000xl_pgm_t* m__root; + mpc2000xl_pgm_t* m__parent; + }; + +public: + std::string magic() const { return m_magic; } + void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } + uint16_t sound_count() const { return m_sound_count; } + void set_sound_count(uint16_t _v) { m__dirty = true; m_sound_count = std::move(_v); } + std::vector* sound_names() const { return m_sound_names.get(); } + void set_sound_names(std::unique_ptr> _v) { m__dirty = true; m_sound_names = std::move(_v); } + std::string _unnamed3() const { return m__unnamed3; } + void set__unnamed3(std::string _v) { m__dirty = true; m__unnamed3 = std::move(_v); } + std::string name() const { return m_name; } + void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } + slider_t* slider() const { return m_slider.get(); } + void set_slider(std::unique_ptr _v) { m__dirty = true; m_slider = std::move(_v); } + uint8_t program_change() const { return m_program_change; } + void set_program_change(uint8_t _v) { m__dirty = true; m_program_change = std::move(_v); } + std::string _unnamed7() const { return m__unnamed7; } + void set__unnamed7(std::string _v) { m__dirty = true; m__unnamed7 = std::move(_v); } + std::vector>* note_parameters() const { return m_note_parameters.get(); } + void set_note_parameters(std::unique_ptr>> _v) { m__dirty = true; m_note_parameters = std::move(_v); } + std::string _unnamed9() const { return m__unnamed9; } + void set__unnamed9(std::string _v) { m__dirty = true; m__unnamed9 = std::move(_v); } + std::vector>* pad_mixers() const { return m_pad_mixers.get(); } + void set_pad_mixers(std::unique_ptr>> _v) { m__dirty = true; m_pad_mixers = std::move(_v); } + std::string _unnamed11() const { return m__unnamed11; } + void set__unnamed11(std::string _v) { m__dirty = true; m__unnamed11 = std::move(_v); } + std::vector* pad_to_note_mapping() const { return m_pad_to_note_mapping.get(); } + void set_pad_to_note_mapping(std::unique_ptr> _v) { m__dirty = true; m_pad_to_note_mapping = std::move(_v); } + std::string _unnamed13() const { return m__unnamed13; } + void set__unnamed13(std::string _v) { m__dirty = true; m__unnamed13 = std::move(_v); } + mpc2000xl_pgm_t* _root() const { return m__root; } + void set__root(mpc2000xl_pgm_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; m__parent = std::move(_v); } + +private: + std::string m_magic; + uint16_t m_sound_count; + std::unique_ptr> m_sound_names; + std::string m__unnamed3; + std::string m_name; + std::unique_ptr m_slider; + uint8_t m_program_change; + std::string m__unnamed7; + std::unique_ptr>> m_note_parameters; + std::string m__unnamed9; + std::unique_ptr>> m_pad_mixers; + std::string m__unnamed11; + std::unique_ptr> m_pad_to_note_mapping; + std::string m__unnamed13; + mpc2000xl_pgm_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp new file mode 100644 index 00000000..1b72a34e --- /dev/null +++ b/src/test/KaitaiPgmTest.cpp @@ -0,0 +1,218 @@ +#include + +#include "TestMpc.hpp" +#include "Mpc.hpp" +#include "disk/AbstractDisk.hpp" +#include "disk/MpcFile.hpp" +#include "disk/ProgramLoader.hpp" +#include "engine/EngineHost.hpp" +#include "file/kaitai/generated/mpc2000xl_pgm.h" +#include "file/pgmwriter/PgmWriter.hpp" +#include "sampler/Program.hpp" +#include "sampler/Sampler.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +namespace { + +void prepareProgramLoadingResources(mpc::Mpc& mpc) +{ + auto disk = mpc.getDisk(); + auto fs = cmrc::mpctest::get_filesystem(); + + for (auto&& entry : fs.iterate_directory("test/ProgramLoading")) { + disk->newFolder(entry.filename()); + disk->initFiles(); + disk->moveForward(entry.filename()); + disk->initFiles(); + + for (auto&& entry2 : fs.iterate_directory("test/ProgramLoading/" + entry.filename())) { + auto file = fs.open("test/ProgramLoading/" + entry.filename() + "/" + entry2.filename()); + std::vector data(file.begin(), file.end()); + auto newFile = disk->newFile(entry2.filename()); + newFile->setFileData(data); + } + + disk->moveBack(); + disk->initFiles(); + } +} + +std::shared_ptr loadProgram1(mpc::Mpc& mpc) +{ + prepareProgramLoadingResources(mpc); + + auto disk = mpc.getDisk(); + disk->moveForward("program1"); + disk->initFiles(); + auto pgmFile = disk->getFile("PROGRAM1.PGM"); + + auto sampler = mpc.getSampler(); + sampler->deleteAllPrograms(false); + sampler->deleteAllSamples(); + + auto program = sampler->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + (void)mpc::disk::ProgramLoader::loadProgram(mpc, pgmFile, program, 0); + mpc.getEngineHost()->prepareProcessBlock(512); + return program; +} + +} + +TEST_CASE("Kaitai MPC2000 PGM parses and rewrites PROGRAM1", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.magic() == std::string("\x07\x04", 2)); + REQUIRE(parsed.sound_count() == 2); + REQUIRE(parsed.sound_names() != nullptr); + REQUIRE(parsed.sound_names()->size() == 2U); + REQUIRE(parsed.sound_names()->at(0).size() == 17U); + REQUIRE(parsed.sound_names()->at(0).substr(0, 6) == "sound1"); + REQUIRE(parsed.sound_names()->at(0).back() == '\0'); + REQUIRE(parsed.sound_names()->at(1).size() == 17U); + REQUIRE(parsed.sound_names()->at(1).substr(0, 6) == "sound2"); + REQUIRE(parsed.sound_names()->at(1).back() == '\0'); + REQUIRE(parsed.name().size() == 17U); + REQUIRE(parsed.name().substr(0, 16) == "VMPCTESTPROGRAM1"); + REQUIRE(parsed.name().back() == '\0'); + REQUIRE(parsed.note_parameters() != nullptr); + REQUIRE(parsed.note_parameters()->size() == 64U); + REQUIRE(parsed.note_parameters()->at(0)->sound_index() == 0); + REQUIRE(parsed.note_parameters()->at(1)->sound_index() == 1); + REQUIRE(parsed.pad_to_note_mapping() != nullptr); + REQUIRE(parsed.pad_to_note_mapping()->size() == 64U); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + REQUIRE(writeStream.str() == originalBytes); +} + +TEST_CASE("Kaitai MPC2000 PGM parses and rewrites real 2KXL NEWPGM-A", "[kaitai-pgm][real-2kxl]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc2000xl/Pgm/NEWPGM-A.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.magic() == std::string("\x07\x04", 2)); + REQUIRE(parsed.sound_count() == 2); + REQUIRE(parsed.sound_names() != nullptr); + REQUIRE(parsed.sound_names()->size() == 2U); + REQUIRE(parsed.sound_names()->at(0).substr(0, 2) == "ML"); + REQUIRE(parsed.sound_names()->at(0).back() == '\0'); + REQUIRE(parsed.sound_names()->at(1).substr(0, 1) == "M"); + REQUIRE(parsed.sound_names()->at(1).back() == '\0'); + REQUIRE(parsed.name().size() == 17U); + REQUIRE(parsed.name().substr(0, 8) == "NewPgm-A"); + REQUIRE(parsed.name().back() == '\0'); + REQUIRE(parsed.note_parameters() != nullptr); + REQUIRE(parsed.note_parameters()->size() == 64U); + REQUIRE(parsed.note_parameters()->at(0)->sound_index() == 255); + REQUIRE(parsed.note_parameters()->at(1)->sound_index() == 0); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + REQUIRE(writeStream.str() == originalBytes); +} + +TEST_CASE("Kaitai MPC2000 PGM matches handwritten PGM bytes", "[kaitai-pgm]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + + auto program = loadProgram1(mpc); + REQUIRE(program != nullptr); + REQUIRE(program->getName() == "PROGRAM1"); + + mpc::file::pgmwriter::PgmWriter handwrittenWriter(program.get(), mpc.getSampler()); + const auto handwrittenBytes = handwrittenWriter.get(); + + std::stringstream parseStream( + std::string(handwrittenBytes.begin(), handwrittenBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.magic() == std::string("\x07\x04", 2)); + REQUIRE(parsed.sound_count() == 2); + REQUIRE(parsed.sound_names() != nullptr); + REQUIRE(parsed.sound_names()->size() == 2U); + REQUIRE(parsed.sound_names()->at(0).substr(0, 6) == "sound1"); + REQUIRE(parsed.sound_names()->at(1).substr(0, 6) == "sound2"); + REQUIRE(parsed.name().substr(0, 8) == "PROGRAM1"); + REQUIRE(parsed.note_parameters() != nullptr); + REQUIRE(parsed.note_parameters()->at(0)->sound_index() == 0); + REQUIRE(parsed.note_parameters()->at(1)->sound_index() == 1); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto kaitaiBytes = writeStream.str(); + REQUIRE(kaitaiBytes == std::string(handwrittenBytes.begin(), handwrittenBytes.end())); + + auto disk = mpc.getDisk(); + auto kaitaiFile = disk->newFile("KPGM.PGM"); + std::vector kaitaiBytesVec(kaitaiBytes.begin(), kaitaiBytes.end()); + kaitaiFile->setFileData(kaitaiBytesVec); + disk->initFiles(); + + auto sampler = mpc.getSampler(); + sampler->deleteAllPrograms(false); + sampler->deleteAllSamples(); + + auto reparsedProgram = sampler->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + (void)mpc::disk::ProgramLoader::loadProgram(mpc, kaitaiFile, reparsedProgram, 0); + mpc.getEngineHost()->prepareProcessBlock(512); + + REQUIRE(reparsedProgram != nullptr); + REQUIRE(reparsedProgram->getName() == "KPGM"); + REQUIRE(sampler->getSoundCount() == 2); + REQUIRE(sampler->getSoundName(0) == "sound1"); + REQUIRE(sampler->getSoundName(1) == "sound2"); + REQUIRE(reparsedProgram->getNoteParameters(35)->getSoundIndex() == 0); + REQUIRE(reparsedProgram->getNoteParameters(36)->getSoundIndex() == 1); +} diff --git a/src/test/KaitaiSndTest.cpp b/src/test/KaitaiSndTest.cpp index 23aa6eb2..95f3e604 100644 --- a/src/test/KaitaiSndTest.cpp +++ b/src/test/KaitaiSndTest.cpp @@ -97,7 +97,7 @@ TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") REQUIRE((*outputData)[1] == (*inputData)[1]); } -TEST_CASE("Kaitai MPC2000 SND parses real mono and stereo files", "[kaitai-snd][hardware-files]") +TEST_CASE("Kaitai MPC2000 SND parses real 2KXL mono and stereo files", "[kaitai-snd][real-2kxl]") { auto parseFile = [](const std::string& resourcePath, auto&& assertions) { auto fs = cmrc::mpctest::get_filesystem(); @@ -114,7 +114,7 @@ TEST_CASE("Kaitai MPC2000 SND parses real mono and stereo files", "[kaitai-snd][ assertions(parsed); }; - parseFile("test/KaitaiSnd/mpc2000snd_mono_loop_off.SND", [](const mpc2000snd_t& mono) { + parseFile("test/RealMpc2000xl/Snd/mono_loop_off.SND", [](const mpc2000snd_t& mono) { REQUIRE(mono.magic() == std::string("\x01\x04", 2)); REQUIRE(mono.level() == 100); REQUIRE(mono.tune() == 0); @@ -127,7 +127,7 @@ TEST_CASE("Kaitai MPC2000 SND parses real mono and stereo files", "[kaitai-snd][ REQUIRE(mono.stereo() == false); }); - parseFile("test/KaitaiSnd/mpc2000snd_stereo_loop_off.SND", [](const mpc2000snd_t& stereo) { + parseFile("test/RealMpc2000xl/Snd/stereo_loop_off.SND", [](const mpc2000snd_t& stereo) { REQUIRE(stereo.magic() == std::string("\x01\x04", 2)); REQUIRE(stereo.level() == 100); REQUIRE(stereo.tune() == 0); diff --git a/test-resources/RealMpc2000xl/Pgm/NEWPGM-A.PGM b/test-resources/RealMpc2000xl/Pgm/NEWPGM-A.PGM new file mode 100755 index 0000000000000000000000000000000000000000..042089c89b8e6bc5cb224eed4d4583742a67f292 GIT binary patch literal 2324 zcmZQ)VPf$0Q9uCm<$6$M+J{AgUC4}24x2ZNrwLnIt&pE z5Wvci0%Cv(AdN$U5tjr`qedk_!HN>Pqd_tnB)|}WWVO-6Fq#;KYGPnxNHGGX;!$#- zLcoDRRYfaELrqV|Kwnqe(A?P6%r!8;(aFcx!p`2o)5~4m#L~*z#@5-z&BNQzUs=;A zI3zSIJR&kGIwm$QJ|QuQiNS;60y_gkGNTBG>>ndzCL Date: Sat, 13 Jun 2026 16:40:32 +0200 Subject: [PATCH 03/52] Add Kaitai 2KXL APS parser #342 --- .../file/kaitai/generated/mpc2000xl_aps.cpp | 742 ++++++++++++++++++ .../file/kaitai/generated/mpc2000xl_aps.h | 456 +++++++++++ src/test/KaitaiApsTest.cpp | 207 +++++ test-resources/RealMpc2000xl/Aps/ALL_PGMS.APS | Bin 0 -> 4073 bytes 4 files changed, 1405 insertions(+) create mode 100644 src/main/file/kaitai/generated/mpc2000xl_aps.cpp create mode 100644 src/main/file/kaitai/generated/mpc2000xl_aps.h create mode 100644 src/test/KaitaiApsTest.cpp create mode 100755 test-resources/RealMpc2000xl/Aps/ALL_PGMS.APS diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp new file mode 100644 index 00000000..4153c90b --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp @@ -0,0 +1,742 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "mpc2000xl_aps.h" +#include "kaitai/exceptions.h" +#include +#include +const std::set mpc2000xl_aps_t::_values_mix_source_t{ + mpc2000xl_aps_t::MIX_SOURCE_PROGRAM, + mpc2000xl_aps_t::MIX_SOURCE_DRUM, +}; +bool mpc2000xl_aps_t::_is_defined_mix_source_t(mpc2000xl_aps_t::mix_source_t v) { + return mpc2000xl_aps_t::_values_mix_source_t.find(v) != mpc2000xl_aps_t::_values_mix_source_t.end(); +} +const std::set mpc2000xl_aps_t::_values_no_yes_t{ + mpc2000xl_aps_t::NO_YES_FALSE, + mpc2000xl_aps_t::NO_YES_TRUE, +}; +bool mpc2000xl_aps_t::_is_defined_no_yes_t(mpc2000xl_aps_t::no_yes_t v) { + return mpc2000xl_aps_t::_values_no_yes_t.find(v) != mpc2000xl_aps_t::_values_no_yes_t.end(); +} +const std::set mpc2000xl_aps_t::_values_pad_assign_t{ + mpc2000xl_aps_t::PAD_ASSIGN_PROGRAM, + mpc2000xl_aps_t::PAD_ASSIGN_MASTERS, +}; +bool mpc2000xl_aps_t::_is_defined_pad_assign_t(mpc2000xl_aps_t::pad_assign_t v) { + return mpc2000xl_aps_t::_values_pad_assign_t.find(v) != mpc2000xl_aps_t::_values_pad_assign_t.end(); +} + +mpc2000xl_aps_t::mpc2000xl_aps_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mpc2000xl_aps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; +} + +void mpc2000xl_aps_t::_read() { + m_magic = m__io->read_bytes(2); + if (!(m_magic == std::string("\x0A\x05", 2))) { + throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); + } + m_sound_count = m__io->read_u1(); + m__unnamed2 = m__io->read_bytes(1); + m_sound_names = std::unique_ptr>(new std::vector()); + const int l_sound_names = sound_count(); + for (int i = 0; i < l_sound_names; i++) { + m_sound_names->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"))); + } + m__unnamed4 = m__io->read_bytes(2); + m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"); + m_global_parameters = std::unique_ptr(new global_parameters_t(m__io, this, m__root)); + m_global_parameters->_read(); + m__unnamed7 = m__io->read_bytes(1); + m_master_pad_to_note_mapping = std::unique_ptr>(new std::vector()); + const int l_master_pad_to_note_mapping = 64; + for (int i = 0; i < l_master_pad_to_note_mapping; i++) { + m_master_pad_to_note_mapping->push_back(std::move(m__io->read_s1())); + } + m__unnamed9 = m__io->read_bytes(7); + m_drum1 = std::unique_ptr(new drum_t(m__io, this, m__root)); + m_drum1->_read(); + m__unnamed11 = m__io->read_bytes(4); + m_drum2 = std::unique_ptr(new drum_t(m__io, this, m__root)); + m_drum2->_read(); + m__unnamed13 = m__io->read_bytes(4); + m_drum3 = std::unique_ptr(new drum_t(m__io, this, m__root)); + m_drum3->_read(); + m__unnamed15 = m__io->read_bytes(4); + m_drum4 = std::unique_ptr(new drum_t(m__io, this, m__root)); + m_drum4->_read(); + m__unnamed17 = m__io->read_bytes(1); + m_aps_programs = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + while (!m__io->is_eof()) { + std::unique_ptr _t_aps_programs = std::unique_ptr(new aps_program_meta_t(m__io, this, m__root)); + try { + _t_aps_programs->_read(); + } catch(...) { + m_aps_programs->push_back(std::move(_t_aps_programs)); + throw; + } + m_aps_programs->push_back(std::move(_t_aps_programs)); + i++; + } + } + m__dirty = false; +} + +void mpc2000xl_aps_t::_fetch_instances() { + for (std::size_t i = 0; i < m_sound_names->size(); ++i) { + } + m_global_parameters.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_master_pad_to_note_mapping->size(); ++i) { + } + m_drum1.get()->_fetch_instances(); + m_drum2.get()->_fetch_instances(); + m_drum3.get()->_fetch_instances(); + m_drum4.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_aps_programs->size(); ++i) { + m_aps_programs->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_aps_t::_write() { + m__io->write_bytes(m_magic); + m__io->write_u1(m_sound_count); + m__io->write_bytes(m__unnamed2); + if (m_sound_names == nullptr) { + throw std::runtime_error("/seq/3: repeated field is not set"); + } + for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { + m__io->write_bytes((*it)); + } + m__io->write_bytes(m__unnamed4); + m__io->write_bytes(m_name); + if (m_global_parameters.get() == nullptr) { + throw std::runtime_error("/seq/6: nested object is not set"); + } + m_global_parameters.get()->_set_io(m__io); + m_global_parameters.get()->_write(); + m__io->write_bytes(m__unnamed7); + if (m_master_pad_to_note_mapping == nullptr) { + throw std::runtime_error("/seq/8: repeated field is not set"); + } + for (std::vector::const_iterator it = m_master_pad_to_note_mapping->begin(); it != m_master_pad_to_note_mapping->end(); ++it) { + m__io->write_s1((*it)); + } + m__io->write_bytes(m__unnamed9); + if (m_drum1.get() == nullptr) { + throw std::runtime_error("/seq/10: nested object is not set"); + } + m_drum1.get()->_set_io(m__io); + m_drum1.get()->_write(); + m__io->write_bytes(m__unnamed11); + if (m_drum2.get() == nullptr) { + throw std::runtime_error("/seq/12: nested object is not set"); + } + m_drum2.get()->_set_io(m__io); + m_drum2.get()->_write(); + m__io->write_bytes(m__unnamed13); + if (m_drum3.get() == nullptr) { + throw std::runtime_error("/seq/14: nested object is not set"); + } + m_drum3.get()->_set_io(m__io); + m_drum3.get()->_write(); + m__io->write_bytes(m__unnamed15); + if (m_drum4.get() == nullptr) { + throw std::runtime_error("/seq/16: nested object is not set"); + } + m_drum4.get()->_set_io(m__io); + m_drum4.get()->_write(); + m__io->write_bytes(m__unnamed17); + if (m_aps_programs == nullptr) { + throw std::runtime_error("/seq/18: repeated field is not set"); + } + if (m_aps_programs == nullptr) { + throw std::runtime_error("/seq/18: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_aps_programs->begin(); it != m_aps_programs->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/18: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_aps_t::_check() { + if (m_magic.size() != static_cast(2)) { + throw std::runtime_error("/seq/0: size mismatch"); + } + if (!(m_magic == std::string("\x0A\x05", 2))) { + throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); + } + if (m__unnamed2.size() != static_cast(1)) { + throw std::runtime_error("/seq/2: size mismatch"); + } + if (m_sound_names == nullptr) { + throw std::runtime_error("/seq/3: repeated field is not set"); + } + if (m_sound_names->size() != static_cast(sound_count())) { + throw std::runtime_error("/seq/3: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { + if ((*it).size() != static_cast(17)) { + throw std::runtime_error("/seq/3: size mismatch"); + } + } + if (m__unnamed4.size() != static_cast(2)) { + throw std::runtime_error("/seq/4: size mismatch"); + } + if (m_name.size() != static_cast(17)) { + throw std::runtime_error("/seq/5: size mismatch"); + } + if (m_global_parameters.get() == nullptr) { + throw std::runtime_error("/seq/6: nested object is not set"); + } + m_global_parameters.get()->_set_io(m__io); + m_global_parameters.get()->_check(); + if (m__unnamed7.size() != static_cast(1)) { + throw std::runtime_error("/seq/7: size mismatch"); + } + if (m_master_pad_to_note_mapping == nullptr) { + throw std::runtime_error("/seq/8: repeated field is not set"); + } + if (m_master_pad_to_note_mapping->size() != static_cast(64)) { + throw std::runtime_error("/seq/8: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_master_pad_to_note_mapping->begin(); it != m_master_pad_to_note_mapping->end(); ++it) { + } + if (m__unnamed9.size() != static_cast(7)) { + throw std::runtime_error("/seq/9: size mismatch"); + } + if (m_drum1.get() == nullptr) { + throw std::runtime_error("/seq/10: nested object is not set"); + } + m_drum1.get()->_set_io(m__io); + m_drum1.get()->_check(); + if (m__unnamed11.size() != static_cast(4)) { + throw std::runtime_error("/seq/11: size mismatch"); + } + if (m_drum2.get() == nullptr) { + throw std::runtime_error("/seq/12: nested object is not set"); + } + m_drum2.get()->_set_io(m__io); + m_drum2.get()->_check(); + if (m__unnamed13.size() != static_cast(4)) { + throw std::runtime_error("/seq/13: size mismatch"); + } + if (m_drum3.get() == nullptr) { + throw std::runtime_error("/seq/14: nested object is not set"); + } + m_drum3.get()->_set_io(m__io); + m_drum3.get()->_check(); + if (m__unnamed15.size() != static_cast(4)) { + throw std::runtime_error("/seq/15: size mismatch"); + } + if (m_drum4.get() == nullptr) { + throw std::runtime_error("/seq/16: nested object is not set"); + } + m_drum4.get()->_set_io(m__io); + m_drum4.get()->_check(); + if (m__unnamed17.size() != static_cast(1)) { + throw std::runtime_error("/seq/17: size mismatch"); + } + if (m_aps_programs == nullptr) { + throw std::runtime_error("/seq/18: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_aps_programs->begin(); it != m_aps_programs->end(); ++it) { + const std::size_t i = static_cast(it - m_aps_programs->begin()); + const aps_program_meta_t* _ = (*it).get(); + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/18: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + m__dirty = false; +} + +mpc2000xl_aps_t::~mpc2000xl_aps_t() {} + +mpc2000xl_aps_t::aps_program_body_t::aps_program_body_t(kaitai::kstream* p__io, mpc2000xl_aps_t::aps_program_meta_t* p__parent, mpc2000xl_aps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_aps_t::aps_program_body_t::_read() { + m__unnamed0 = m__io->read_bytes(5); + m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"); + m_slider = std::unique_ptr(new mpc2000xl_pgm_t::slider_t(m__io)); + m_slider->_read(); + m_program_change = m__io->read_u1(); + m__unnamed4 = m__io->read_bytes(5); + m_note_parameters = std::unique_ptr>>(new std::vector>()); + const int l_note_parameters = 64; + for (int i = 0; i < l_note_parameters; i++) { + std::unique_ptr _t_note_parameters = std::unique_ptr(new note_t(m__io, this, m__root)); + try { + _t_note_parameters->_read(); + } catch(...) { + m_note_parameters->push_back(std::move(_t_note_parameters)); + throw; + } + m_note_parameters->push_back(std::move(_t_note_parameters)); + } + m__unnamed6 = m__io->read_bytes(1); + m_pad_mixers = std::unique_ptr>>(new std::vector>()); + const int l_pad_mixers = 64; + for (int i = 0; i < l_pad_mixers; i++) { + std::unique_ptr _t_pad_mixers = std::unique_ptr(new mpc2000xl_pgm_t::pad_mixer_t(m__io)); + try { + _t_pad_mixers->_read(); + } catch(...) { + m_pad_mixers->push_back(std::move(_t_pad_mixers)); + throw; + } + m_pad_mixers->push_back(std::move(_t_pad_mixers)); + } + m__unnamed8 = m__io->read_bytes(3); + m_pad_to_note_mapping = std::unique_ptr>(new std::vector()); + const int l_pad_to_note_mapping = 64; + for (int i = 0; i < l_pad_to_note_mapping; i++) { + m_pad_to_note_mapping->push_back(std::move(m__io->read_s1())); + } + m__unnamed10 = m__io->read_bytes(200); + m__dirty = false; +} + +void mpc2000xl_aps_t::aps_program_body_t::_fetch_instances() { + m_slider.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_note_parameters->size(); ++i) { + m_note_parameters->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_pad_mixers->size(); ++i) { + m_pad_mixers->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_pad_to_note_mapping->size(); ++i) { + } +} + +void mpc2000xl_aps_t::aps_program_body_t::_write() { + m__io->write_bytes(m__unnamed0); + m__io->write_bytes(m_name); + if (m_slider.get() == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/2: nested object is not set"); + } + m_slider.get()->_set_io(m__io); + m_slider.get()->_write(); + m__io->write_u1(m_program_change); + m__io->write_bytes(m__unnamed4); + if (m_note_parameters == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/5: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_note_parameters->begin(); it != m_note_parameters->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/5: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed6); + if (m_pad_mixers == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/7: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_pad_mixers->begin(); it != m_pad_mixers->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/7: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed8); + if (m_pad_to_note_mapping == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/9: repeated field is not set"); + } + for (std::vector::const_iterator it = m_pad_to_note_mapping->begin(); it != m_pad_to_note_mapping->end(); ++it) { + m__io->write_s1((*it)); + } + m__io->write_bytes(m__unnamed10); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_aps_t::aps_program_body_t::_check() { + if (m__unnamed0.size() != static_cast(5)) { + throw std::runtime_error("/types/aps_program_body/seq/0: size mismatch"); + } + if (m_name.size() != static_cast(17)) { + throw std::runtime_error("/types/aps_program_body/seq/1: size mismatch"); + } + if (m_slider.get() == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/2: nested object is not set"); + } + m_slider.get()->_set_io(m__io); + m_slider.get()->_check(); + if (m__unnamed4.size() != static_cast(5)) { + throw std::runtime_error("/types/aps_program_body/seq/4: size mismatch"); + } + if (m_note_parameters == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/5: repeated field is not set"); + } + if (m_note_parameters->size() != static_cast(64)) { + throw std::runtime_error("/types/aps_program_body/seq/5: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_note_parameters->begin(); it != m_note_parameters->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/5: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed6.size() != static_cast(1)) { + throw std::runtime_error("/types/aps_program_body/seq/6: size mismatch"); + } + if (m_pad_mixers == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/7: repeated field is not set"); + } + if (m_pad_mixers->size() != static_cast(64)) { + throw std::runtime_error("/types/aps_program_body/seq/7: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_pad_mixers->begin(); it != m_pad_mixers->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/7: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed8.size() != static_cast(3)) { + throw std::runtime_error("/types/aps_program_body/seq/8: size mismatch"); + } + if (m_pad_to_note_mapping == nullptr) { + throw std::runtime_error("/types/aps_program_body/seq/9: repeated field is not set"); + } + if (m_pad_to_note_mapping->size() != static_cast(64)) { + throw std::runtime_error("/types/aps_program_body/seq/9: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_pad_to_note_mapping->begin(); it != m_pad_to_note_mapping->end(); ++it) { + } + if (m__unnamed10.size() != static_cast(200)) { + throw std::runtime_error("/types/aps_program_body/seq/10: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_aps_t::aps_program_body_t::~aps_program_body_t() {} + +mpc2000xl_aps_t::aps_program_meta_t::aps_program_meta_t(kaitai::kstream* p__io, mpc2000xl_aps_t* p__parent, mpc2000xl_aps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_aps_t::aps_program_meta_t::_read() { + m_index = m__io->read_u1(); + if (index() < 24) { + m_body = std::unique_ptr(new aps_program_body_t(m__io, this, m__root)); + m_body->_read(); + } + if (index() > 23) { + m__unnamed2 = std::unique_ptr>(new std::vector()); + { + int i = 0; + while (!m__io->is_eof()) { + m__unnamed2->push_back(std::move(m__io->read_u1())); + i++; + } + } + } + m__dirty = false; +} + +void mpc2000xl_aps_t::aps_program_meta_t::_fetch_instances() { + if (index() < 24) { + m_body.get()->_fetch_instances(); + } + if (index() > 23) { + for (std::size_t i = 0; i < m__unnamed2->size(); ++i) { + } + } +} + +void mpc2000xl_aps_t::aps_program_meta_t::_write() { + m__io->write_u1(m_index); + if (index() < 24) { + if (m_body.get() == nullptr) { + throw std::runtime_error("/types/aps_program_meta/seq/1: nested object is not set"); + } + m_body.get()->_set_io(m__io); + m_body.get()->_write(); + } + if (index() > 23) { + if (m__unnamed2 == nullptr) { + throw std::runtime_error("/types/aps_program_meta/seq/2: repeated field is not set"); + } + const std::size_t _remaining = static_cast(m__io->size() - m__io->pos()); + const std::size_t _actual = m__unnamed2->size() * static_cast(1); + if (_remaining != 0 && _remaining != _actual) { + throw std::runtime_error("/types/aps_program_meta/seq/2: expected: " + kaitai::kstream::to_string(_remaining) + ", actual: " + kaitai::kstream::to_string(_actual)); + } + if (m__unnamed2 == nullptr) { + throw std::runtime_error("/types/aps_program_meta/seq/2: repeated field is not set"); + } + for (std::vector::const_iterator it = m__unnamed2->begin(); it != m__unnamed2->end(); ++it) { + m__io->write_u1((*it)); + } + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_aps_t::aps_program_meta_t::_check() { + if (index() < 24) { + if (!(m_body.get() != nullptr)) { + throw std::runtime_error("/types/aps_program_meta/seq/1: conditional field is not set"); + } + if (m_body.get() == nullptr) { + throw std::runtime_error("/types/aps_program_meta/seq/1: nested object is not set"); + } + m_body.get()->_set_io(m__io); + m_body.get()->_check(); + } else { + if (m_body.get() != nullptr) { + throw std::runtime_error("/types/aps_program_meta/seq/1: conditional field should be absent"); + } + } + if (index() > 23) { + if (!(m__unnamed2 != nullptr)) { + throw std::runtime_error("/types/aps_program_meta/seq/2: conditional field is not set"); + } + if (m__unnamed2 == nullptr) { + throw std::runtime_error("/types/aps_program_meta/seq/2: repeated field is not set"); + } + for (std::vector::const_iterator it = m__unnamed2->begin(); it != m__unnamed2->end(); ++it) { + const std::size_t i = static_cast(it - m__unnamed2->begin()); + const uint8_t _ = (*it); + } + } else { + if (m__unnamed2 != nullptr) { + throw std::runtime_error("/types/aps_program_meta/seq/2: conditional field should be absent"); + } + } + m__dirty = false; +} + +mpc2000xl_aps_t::aps_program_meta_t::~aps_program_meta_t() {} + +mpc2000xl_aps_t::drum_t::drum_t(kaitai::kstream* p__io, mpc2000xl_aps_t* p__parent, mpc2000xl_aps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_aps_t::drum_t::_read() { + m_pad_mixers = std::unique_ptr>>(new std::vector>()); + const int l_pad_mixers = 64; + for (int i = 0; i < l_pad_mixers; i++) { + std::unique_ptr _t_pad_mixers = std::unique_ptr(new mpc2000xl_pgm_t::pad_mixer_t(m__io)); + try { + _t_pad_mixers->_read(); + } catch(...) { + m_pad_mixers->push_back(std::move(_t_pad_mixers)); + throw; + } + m_pad_mixers->push_back(std::move(_t_pad_mixers)); + } + m__unnamed1 = m__io->read_bytes(2); + m_receive_program_change = static_cast(m__io->read_u1()); + m_receive_midi_volume = static_cast(m__io->read_u1()); + m__unnamed4 = m__io->read_bytes(1); + m_program = m__io->read_u1(); + m_receive_program_change_duplicate = static_cast(m__io->read_u1()); + m_receive_midi_volume_duplicate = static_cast(m__io->read_u1()); + m__dirty = false; +} + +void mpc2000xl_aps_t::drum_t::_fetch_instances() { + for (std::size_t i = 0; i < m_pad_mixers->size(); ++i) { + m_pad_mixers->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_aps_t::drum_t::_write() { + if (m_pad_mixers == nullptr) { + throw std::runtime_error("/types/drum/seq/0: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_pad_mixers->begin(); it != m_pad_mixers->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/drum/seq/0: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed1); + m__io->write_u1(static_cast(m_receive_program_change)); + m__io->write_u1(static_cast(m_receive_midi_volume)); + m__io->write_bytes(m__unnamed4); + m__io->write_u1(m_program); + m__io->write_u1(static_cast(m_receive_program_change_duplicate)); + m__io->write_u1(static_cast(m_receive_midi_volume_duplicate)); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_aps_t::drum_t::_check() { + if (m_pad_mixers == nullptr) { + throw std::runtime_error("/types/drum/seq/0: repeated field is not set"); + } + if (m_pad_mixers->size() != static_cast(64)) { + throw std::runtime_error("/types/drum/seq/0: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_pad_mixers->begin(); it != m_pad_mixers->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/drum/seq/0: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed1.size() != static_cast(2)) { + throw std::runtime_error("/types/drum/seq/1: size mismatch"); + } + if (m__unnamed4.size() != static_cast(1)) { + throw std::runtime_error("/types/drum/seq/4: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_aps_t::drum_t::~drum_t() {} + +mpc2000xl_aps_t::global_parameters_t::global_parameters_t(kaitai::kstream* p__io, mpc2000xl_aps_t* p__parent, mpc2000xl_aps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_aps_t::global_parameters_t::_read() { + m__unnamed0 = m__io->read_bits_int_be(7); + m_pad_to_internal_sound = static_cast(m__io->read_bits_int_be(1)); + m__unnamed2 = m__io->read_bits_int_be(7); + m_pad_assign = static_cast(m__io->read_bits_int_be(1)); + m__unnamed4 = m__io->read_bits_int_be(6); + m_indiv_fx_source = static_cast(m__io->read_bits_int_be(1)); + m_stereo_mix_source = static_cast(m__io->read_bits_int_be(1)); + m__unnamed7 = m__io->read_bits_int_be(3); + m_record_mix_changes = static_cast(m__io->read_bits_int_be(1)); + m_copy_pgm_mix_to_drum = static_cast(m__io->read_bits_int_be(1)); + m__unnamed10 = m__io->read_bits_int_be(3); + m_fx_drum = m__io->read_u1(); + m__unnamed12 = m__io->read_bytes(1); + m_master_level = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_aps_t::global_parameters_t::_fetch_instances() { +} + +void mpc2000xl_aps_t::global_parameters_t::_write() { + m__io->write_bits_int_be(7, m__unnamed0); + m__io->write_bits_int_be(1, static_cast(m_pad_to_internal_sound)); + m__io->write_bits_int_be(7, m__unnamed2); + m__io->write_bits_int_be(1, static_cast(m_pad_assign)); + m__io->write_bits_int_be(6, m__unnamed4); + m__io->write_bits_int_be(1, static_cast(m_indiv_fx_source)); + m__io->write_bits_int_be(1, static_cast(m_stereo_mix_source)); + m__io->write_bits_int_be(3, m__unnamed7); + m__io->write_bits_int_be(1, static_cast(m_record_mix_changes)); + m__io->write_bits_int_be(1, static_cast(m_copy_pgm_mix_to_drum)); + m__io->write_bits_int_be(3, m__unnamed10); + m__io->write_u1(m_fx_drum); + m__io->write_bytes(m__unnamed12); + m__io->write_u1(m_master_level); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_aps_t::global_parameters_t::_check() { + if (m__unnamed12.size() != static_cast(1)) { + throw std::runtime_error("/types/global_parameters/seq/12: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_aps_t::global_parameters_t::~global_parameters_t() {} + +mpc2000xl_aps_t::note_t::note_t(kaitai::kstream* p__io, mpc2000xl_aps_t::aps_program_body_t* p__parent, mpc2000xl_aps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_aps_t::note_t::_read() { + m_sound_index = m__io->read_u1(); + m__unnamed1 = m__io->read_bytes(1); + m_sound_generation_mode = static_cast(m__io->read_u1()); + m_velocity_range_lower = m__io->read_u1(); + m_also_play_use_note_1 = m__io->read_u1(); + m_velocity_range_upper = m__io->read_u1(); + m_also_play_use_note_2 = m__io->read_u1(); + m_voice_overlap_mode = static_cast(m__io->read_u1()); + m_mute_assign_1 = m__io->read_u1(); + m_mute_assign_2 = m__io->read_u1(); + m_tune = m__io->read_s2le(); + m_attack = m__io->read_u1(); + m_decay = m__io->read_u1(); + m_decay_mode = static_cast(m__io->read_u1()); + m_cutoff = m__io->read_u1(); + m_resonance = m__io->read_u1(); + m_velocity_envelope_to_filter_attack = m__io->read_u1(); + m_velocity_envelope_to_filter_decay = m__io->read_u1(); + m_velocity_envelope_to_filter_amount = m__io->read_u1(); + m_velocity_to_level = m__io->read_u1(); + m_velocity_to_attack = m__io->read_u1(); + m_velocity_to_start = m__io->read_u1(); + m_velocity_to_cutoff = m__io->read_u1(); + m_slider_parameter = static_cast(m__io->read_u1()); + m_velocity_to_pitch = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_aps_t::note_t::_fetch_instances() { +} + +void mpc2000xl_aps_t::note_t::_write() { + m__io->write_u1(m_sound_index); + m__io->write_bytes(m__unnamed1); + m__io->write_u1(static_cast(m_sound_generation_mode)); + m__io->write_u1(m_velocity_range_lower); + m__io->write_u1(m_also_play_use_note_1); + m__io->write_u1(m_velocity_range_upper); + m__io->write_u1(m_also_play_use_note_2); + m__io->write_u1(static_cast(m_voice_overlap_mode)); + m__io->write_u1(m_mute_assign_1); + m__io->write_u1(m_mute_assign_2); + m__io->write_s2le(m_tune); + m__io->write_u1(m_attack); + m__io->write_u1(m_decay); + m__io->write_u1(static_cast(m_decay_mode)); + m__io->write_u1(m_cutoff); + m__io->write_u1(m_resonance); + m__io->write_u1(m_velocity_envelope_to_filter_attack); + m__io->write_u1(m_velocity_envelope_to_filter_decay); + m__io->write_u1(m_velocity_envelope_to_filter_amount); + m__io->write_u1(m_velocity_to_level); + m__io->write_u1(m_velocity_to_attack); + m__io->write_u1(m_velocity_to_start); + m__io->write_u1(m_velocity_to_cutoff); + m__io->write_u1(static_cast(m_slider_parameter)); + m__io->write_u1(m_velocity_to_pitch); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_aps_t::note_t::_check() { + if (m__unnamed1.size() != static_cast(1)) { + throw std::runtime_error("/types/note/seq/1: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_aps_t::note_t::~note_t() {} diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.h b/src/main/file/kaitai/generated/mpc2000xl_aps.h new file mode 100644 index 00000000..7d2c2abe --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.h @@ -0,0 +1,456 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class mpc2000xl_aps_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include "mpc2000xl_pgm.h" +#include +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +class mpc2000xl_aps_t : public kaitai::kstruct { + +public: + class aps_program_body_t; + class aps_program_meta_t; + class drum_t; + class global_parameters_t; + class note_t; + + enum mix_source_t { + MIX_SOURCE_PROGRAM = 0, + MIX_SOURCE_DRUM = 1 + }; + static bool _is_defined_mix_source_t(mix_source_t v); + +private: + static const std::set _values_mix_source_t; + +public: + + enum no_yes_t { + NO_YES_FALSE = 0, + NO_YES_TRUE = 1 + }; + static bool _is_defined_no_yes_t(no_yes_t v); + +private: + static const std::set _values_no_yes_t; + +public: + + enum pad_assign_t { + PAD_ASSIGN_PROGRAM = 0, + PAD_ASSIGN_MASTERS = 1 + }; + static bool _is_defined_pad_assign_t(pad_assign_t v); + +private: + static const std::set _values_pad_assign_t; + +public: + +private: + bool m__dirty; + +public: + + mpc2000xl_aps_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mpc2000xl_aps_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~mpc2000xl_aps_t(); + + class aps_program_body_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + aps_program_body_t(kaitai::kstream* p__io, mpc2000xl_aps_t::aps_program_meta_t* p__parent = nullptr, mpc2000xl_aps_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~aps_program_body_t(); + std::string _unnamed0() const { return m__unnamed0; } + void set__unnamed0(std::string _v) { m__dirty = true; m__unnamed0 = std::move(_v); } + std::string name() const { return m_name; } + void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } + mpc2000xl_pgm_t::slider_t* slider() const { return m_slider.get(); } + void set_slider(std::unique_ptr _v) { m__dirty = true; m_slider = std::move(_v); } + uint8_t program_change() const { return m_program_change; } + void set_program_change(uint8_t _v) { m__dirty = true; m_program_change = std::move(_v); } + std::string _unnamed4() const { return m__unnamed4; } + void set__unnamed4(std::string _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + std::vector>* note_parameters() const { return m_note_parameters.get(); } + void set_note_parameters(std::unique_ptr>> _v) { m__dirty = true; m_note_parameters = std::move(_v); } + std::string _unnamed6() const { return m__unnamed6; } + void set__unnamed6(std::string _v) { m__dirty = true; m__unnamed6 = std::move(_v); } + std::vector>* pad_mixers() const { return m_pad_mixers.get(); } + void set_pad_mixers(std::unique_ptr>> _v) { m__dirty = true; m_pad_mixers = std::move(_v); } + std::string _unnamed8() const { return m__unnamed8; } + void set__unnamed8(std::string _v) { m__dirty = true; m__unnamed8 = std::move(_v); } + std::vector* pad_to_note_mapping() const { return m_pad_to_note_mapping.get(); } + void set_pad_to_note_mapping(std::unique_ptr> _v) { m__dirty = true; m_pad_to_note_mapping = std::move(_v); } + std::string _unnamed10() const { return m__unnamed10; } + void set__unnamed10(std::string _v) { m__dirty = true; m__unnamed10 = std::move(_v); } + mpc2000xl_aps_t* _root() const { return m__root; } + void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_aps_t::aps_program_meta_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_aps_t::aps_program_meta_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m__unnamed0; + std::string m_name; + std::unique_ptr m_slider; + uint8_t m_program_change; + std::string m__unnamed4; + std::unique_ptr>> m_note_parameters; + std::string m__unnamed6; + std::unique_ptr>> m_pad_mixers; + std::string m__unnamed8; + std::unique_ptr> m_pad_to_note_mapping; + std::string m__unnamed10; + mpc2000xl_aps_t* m__root; + mpc2000xl_aps_t::aps_program_meta_t* m__parent; + }; + + class aps_program_meta_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + aps_program_meta_t(kaitai::kstream* p__io, mpc2000xl_aps_t* p__parent = nullptr, mpc2000xl_aps_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~aps_program_meta_t(); + uint8_t index() const { return m_index; } + void set_index(uint8_t _v) { m__dirty = true; m_index = std::move(_v); } + aps_program_body_t* body() const { return m_body.get(); } + void set_body(std::unique_ptr _v) { m__dirty = true; m_body = std::move(_v); } + std::vector* _unnamed2() const { return m__unnamed2.get(); } + void set__unnamed2(std::unique_ptr> _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + mpc2000xl_aps_t* _root() const { return m__root; } + void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_aps_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_aps_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_index; + std::unique_ptr m_body; + + public: + bool _is_null_body() { return !body(); }; + + private: + std::unique_ptr> m__unnamed2; + + public: + bool _is_null__unnamed2() { return !_unnamed2(); }; + + private: + mpc2000xl_aps_t* m__root; + mpc2000xl_aps_t* m__parent; + }; + + class drum_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + drum_t(kaitai::kstream* p__io, mpc2000xl_aps_t* p__parent = nullptr, mpc2000xl_aps_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~drum_t(); + std::vector>* pad_mixers() const { return m_pad_mixers.get(); } + void set_pad_mixers(std::unique_ptr>> _v) { m__dirty = true; m_pad_mixers = std::move(_v); } + std::string _unnamed1() const { return m__unnamed1; } + void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + no_yes_t receive_program_change() const { return m_receive_program_change; } + void set_receive_program_change(no_yes_t _v) { m__dirty = true; m_receive_program_change = std::move(_v); } + no_yes_t receive_midi_volume() const { return m_receive_midi_volume; } + void set_receive_midi_volume(no_yes_t _v) { m__dirty = true; m_receive_midi_volume = std::move(_v); } + std::string _unnamed4() const { return m__unnamed4; } + void set__unnamed4(std::string _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + uint8_t program() const { return m_program; } + void set_program(uint8_t _v) { m__dirty = true; m_program = std::move(_v); } + no_yes_t receive_program_change_duplicate() const { return m_receive_program_change_duplicate; } + void set_receive_program_change_duplicate(no_yes_t _v) { m__dirty = true; m_receive_program_change_duplicate = std::move(_v); } + no_yes_t receive_midi_volume_duplicate() const { return m_receive_midi_volume_duplicate; } + void set_receive_midi_volume_duplicate(no_yes_t _v) { m__dirty = true; m_receive_midi_volume_duplicate = std::move(_v); } + mpc2000xl_aps_t* _root() const { return m__root; } + void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_aps_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_aps_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::unique_ptr>> m_pad_mixers; + std::string m__unnamed1; + no_yes_t m_receive_program_change; + no_yes_t m_receive_midi_volume; + std::string m__unnamed4; + uint8_t m_program; + no_yes_t m_receive_program_change_duplicate; + no_yes_t m_receive_midi_volume_duplicate; + mpc2000xl_aps_t* m__root; + mpc2000xl_aps_t* m__parent; + }; + + class global_parameters_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + global_parameters_t(kaitai::kstream* p__io, mpc2000xl_aps_t* p__parent = nullptr, mpc2000xl_aps_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~global_parameters_t(); + uint64_t _unnamed0() const { return m__unnamed0; } + void set__unnamed0(uint64_t _v) { m__dirty = true; m__unnamed0 = std::move(_v); } + no_yes_t pad_to_internal_sound() const { return m_pad_to_internal_sound; } + void set_pad_to_internal_sound(no_yes_t _v) { m__dirty = true; m_pad_to_internal_sound = std::move(_v); } + uint64_t _unnamed2() const { return m__unnamed2; } + void set__unnamed2(uint64_t _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + pad_assign_t pad_assign() const { return m_pad_assign; } + void set_pad_assign(pad_assign_t _v) { m__dirty = true; m_pad_assign = std::move(_v); } + uint64_t _unnamed4() const { return m__unnamed4; } + void set__unnamed4(uint64_t _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + mix_source_t indiv_fx_source() const { return m_indiv_fx_source; } + void set_indiv_fx_source(mix_source_t _v) { m__dirty = true; m_indiv_fx_source = std::move(_v); } + mix_source_t stereo_mix_source() const { return m_stereo_mix_source; } + void set_stereo_mix_source(mix_source_t _v) { m__dirty = true; m_stereo_mix_source = std::move(_v); } + uint64_t _unnamed7() const { return m__unnamed7; } + void set__unnamed7(uint64_t _v) { m__dirty = true; m__unnamed7 = std::move(_v); } + no_yes_t record_mix_changes() const { return m_record_mix_changes; } + void set_record_mix_changes(no_yes_t _v) { m__dirty = true; m_record_mix_changes = std::move(_v); } + no_yes_t copy_pgm_mix_to_drum() const { return m_copy_pgm_mix_to_drum; } + void set_copy_pgm_mix_to_drum(no_yes_t _v) { m__dirty = true; m_copy_pgm_mix_to_drum = std::move(_v); } + uint64_t _unnamed10() const { return m__unnamed10; } + void set__unnamed10(uint64_t _v) { m__dirty = true; m__unnamed10 = std::move(_v); } + uint8_t fx_drum() const { return m_fx_drum; } + void set_fx_drum(uint8_t _v) { m__dirty = true; m_fx_drum = std::move(_v); } + std::string _unnamed12() const { return m__unnamed12; } + void set__unnamed12(std::string _v) { m__dirty = true; m__unnamed12 = std::move(_v); } + uint8_t master_level() const { return m_master_level; } + void set_master_level(uint8_t _v) { m__dirty = true; m_master_level = std::move(_v); } + mpc2000xl_aps_t* _root() const { return m__root; } + void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_aps_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_aps_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint64_t m__unnamed0; + no_yes_t m_pad_to_internal_sound; + uint64_t m__unnamed2; + pad_assign_t m_pad_assign; + uint64_t m__unnamed4; + mix_source_t m_indiv_fx_source; + mix_source_t m_stereo_mix_source; + uint64_t m__unnamed7; + no_yes_t m_record_mix_changes; + no_yes_t m_copy_pgm_mix_to_drum; + uint64_t m__unnamed10; + uint8_t m_fx_drum; + std::string m__unnamed12; + uint8_t m_master_level; + mpc2000xl_aps_t* m__root; + mpc2000xl_aps_t* m__parent; + }; + + class note_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + note_t(kaitai::kstream* p__io, mpc2000xl_aps_t::aps_program_body_t* p__parent = nullptr, mpc2000xl_aps_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~note_t(); + uint8_t sound_index() const { return m_sound_index; } + void set_sound_index(uint8_t _v) { m__dirty = true; m_sound_index = std::move(_v); } + std::string _unnamed1() const { return m__unnamed1; } + void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + mpc2000xl_pgm_t::sound_generation_mode_t sound_generation_mode() const { return m_sound_generation_mode; } + void set_sound_generation_mode(mpc2000xl_pgm_t::sound_generation_mode_t _v) { m__dirty = true; m_sound_generation_mode = std::move(_v); } + uint8_t velocity_range_lower() const { return m_velocity_range_lower; } + void set_velocity_range_lower(uint8_t _v) { m__dirty = true; m_velocity_range_lower = std::move(_v); } + uint8_t also_play_use_note_1() const { return m_also_play_use_note_1; } + void set_also_play_use_note_1(uint8_t _v) { m__dirty = true; m_also_play_use_note_1 = std::move(_v); } + uint8_t velocity_range_upper() const { return m_velocity_range_upper; } + void set_velocity_range_upper(uint8_t _v) { m__dirty = true; m_velocity_range_upper = std::move(_v); } + uint8_t also_play_use_note_2() const { return m_also_play_use_note_2; } + void set_also_play_use_note_2(uint8_t _v) { m__dirty = true; m_also_play_use_note_2 = std::move(_v); } + mpc2000xl_pgm_t::voice_overlap_mode_t voice_overlap_mode() const { return m_voice_overlap_mode; } + void set_voice_overlap_mode(mpc2000xl_pgm_t::voice_overlap_mode_t _v) { m__dirty = true; m_voice_overlap_mode = std::move(_v); } + uint8_t mute_assign_1() const { return m_mute_assign_1; } + void set_mute_assign_1(uint8_t _v) { m__dirty = true; m_mute_assign_1 = std::move(_v); } + uint8_t mute_assign_2() const { return m_mute_assign_2; } + void set_mute_assign_2(uint8_t _v) { m__dirty = true; m_mute_assign_2 = std::move(_v); } + int16_t tune() const { return m_tune; } + void set_tune(int16_t _v) { m__dirty = true; m_tune = std::move(_v); } + uint8_t attack() const { return m_attack; } + void set_attack(uint8_t _v) { m__dirty = true; m_attack = std::move(_v); } + uint8_t decay() const { return m_decay; } + void set_decay(uint8_t _v) { m__dirty = true; m_decay = std::move(_v); } + mpc2000xl_pgm_t::decay_mode_t decay_mode() const { return m_decay_mode; } + void set_decay_mode(mpc2000xl_pgm_t::decay_mode_t _v) { m__dirty = true; m_decay_mode = std::move(_v); } + uint8_t cutoff() const { return m_cutoff; } + void set_cutoff(uint8_t _v) { m__dirty = true; m_cutoff = std::move(_v); } + uint8_t resonance() const { return m_resonance; } + void set_resonance(uint8_t _v) { m__dirty = true; m_resonance = std::move(_v); } + uint8_t velocity_envelope_to_filter_attack() const { return m_velocity_envelope_to_filter_attack; } + void set_velocity_envelope_to_filter_attack(uint8_t _v) { m__dirty = true; m_velocity_envelope_to_filter_attack = std::move(_v); } + uint8_t velocity_envelope_to_filter_decay() const { return m_velocity_envelope_to_filter_decay; } + void set_velocity_envelope_to_filter_decay(uint8_t _v) { m__dirty = true; m_velocity_envelope_to_filter_decay = std::move(_v); } + uint8_t velocity_envelope_to_filter_amount() const { return m_velocity_envelope_to_filter_amount; } + void set_velocity_envelope_to_filter_amount(uint8_t _v) { m__dirty = true; m_velocity_envelope_to_filter_amount = std::move(_v); } + uint8_t velocity_to_level() const { return m_velocity_to_level; } + void set_velocity_to_level(uint8_t _v) { m__dirty = true; m_velocity_to_level = std::move(_v); } + uint8_t velocity_to_attack() const { return m_velocity_to_attack; } + void set_velocity_to_attack(uint8_t _v) { m__dirty = true; m_velocity_to_attack = std::move(_v); } + uint8_t velocity_to_start() const { return m_velocity_to_start; } + void set_velocity_to_start(uint8_t _v) { m__dirty = true; m_velocity_to_start = std::move(_v); } + uint8_t velocity_to_cutoff() const { return m_velocity_to_cutoff; } + void set_velocity_to_cutoff(uint8_t _v) { m__dirty = true; m_velocity_to_cutoff = std::move(_v); } + mpc2000xl_pgm_t::slider_parameter_t slider_parameter() const { return m_slider_parameter; } + void set_slider_parameter(mpc2000xl_pgm_t::slider_parameter_t _v) { m__dirty = true; m_slider_parameter = std::move(_v); } + uint8_t velocity_to_pitch() const { return m_velocity_to_pitch; } + void set_velocity_to_pitch(uint8_t _v) { m__dirty = true; m_velocity_to_pitch = std::move(_v); } + mpc2000xl_aps_t* _root() const { return m__root; } + void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_aps_t::aps_program_body_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_aps_t::aps_program_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_sound_index; + std::string m__unnamed1; + mpc2000xl_pgm_t::sound_generation_mode_t m_sound_generation_mode; + uint8_t m_velocity_range_lower; + uint8_t m_also_play_use_note_1; + uint8_t m_velocity_range_upper; + uint8_t m_also_play_use_note_2; + mpc2000xl_pgm_t::voice_overlap_mode_t m_voice_overlap_mode; + uint8_t m_mute_assign_1; + uint8_t m_mute_assign_2; + int16_t m_tune; + uint8_t m_attack; + uint8_t m_decay; + mpc2000xl_pgm_t::decay_mode_t m_decay_mode; + uint8_t m_cutoff; + uint8_t m_resonance; + uint8_t m_velocity_envelope_to_filter_attack; + uint8_t m_velocity_envelope_to_filter_decay; + uint8_t m_velocity_envelope_to_filter_amount; + uint8_t m_velocity_to_level; + uint8_t m_velocity_to_attack; + uint8_t m_velocity_to_start; + uint8_t m_velocity_to_cutoff; + mpc2000xl_pgm_t::slider_parameter_t m_slider_parameter; + uint8_t m_velocity_to_pitch; + mpc2000xl_aps_t* m__root; + mpc2000xl_aps_t::aps_program_body_t* m__parent; + }; + +public: + std::string magic() const { return m_magic; } + void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } + uint8_t sound_count() const { return m_sound_count; } + void set_sound_count(uint8_t _v) { m__dirty = true; m_sound_count = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + std::vector* sound_names() const { return m_sound_names.get(); } + void set_sound_names(std::unique_ptr> _v) { m__dirty = true; m_sound_names = std::move(_v); } + std::string _unnamed4() const { return m__unnamed4; } + void set__unnamed4(std::string _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + std::string name() const { return m_name; } + void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } + global_parameters_t* global_parameters() const { return m_global_parameters.get(); } + void set_global_parameters(std::unique_ptr _v) { m__dirty = true; m_global_parameters = std::move(_v); } + std::string _unnamed7() const { return m__unnamed7; } + void set__unnamed7(std::string _v) { m__dirty = true; m__unnamed7 = std::move(_v); } + std::vector* master_pad_to_note_mapping() const { return m_master_pad_to_note_mapping.get(); } + void set_master_pad_to_note_mapping(std::unique_ptr> _v) { m__dirty = true; m_master_pad_to_note_mapping = std::move(_v); } + std::string _unnamed9() const { return m__unnamed9; } + void set__unnamed9(std::string _v) { m__dirty = true; m__unnamed9 = std::move(_v); } + drum_t* drum1() const { return m_drum1.get(); } + void set_drum1(std::unique_ptr _v) { m__dirty = true; m_drum1 = std::move(_v); } + std::string _unnamed11() const { return m__unnamed11; } + void set__unnamed11(std::string _v) { m__dirty = true; m__unnamed11 = std::move(_v); } + drum_t* drum2() const { return m_drum2.get(); } + void set_drum2(std::unique_ptr _v) { m__dirty = true; m_drum2 = std::move(_v); } + std::string _unnamed13() const { return m__unnamed13; } + void set__unnamed13(std::string _v) { m__dirty = true; m__unnamed13 = std::move(_v); } + drum_t* drum3() const { return m_drum3.get(); } + void set_drum3(std::unique_ptr _v) { m__dirty = true; m_drum3 = std::move(_v); } + std::string _unnamed15() const { return m__unnamed15; } + void set__unnamed15(std::string _v) { m__dirty = true; m__unnamed15 = std::move(_v); } + drum_t* drum4() const { return m_drum4.get(); } + void set_drum4(std::unique_ptr _v) { m__dirty = true; m_drum4 = std::move(_v); } + std::string _unnamed17() const { return m__unnamed17; } + void set__unnamed17(std::string _v) { m__dirty = true; m__unnamed17 = std::move(_v); } + std::vector>* aps_programs() const { return m_aps_programs.get(); } + void set_aps_programs(std::unique_ptr>> _v) { m__dirty = true; m_aps_programs = std::move(_v); } + mpc2000xl_aps_t* _root() const { return m__root; } + void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; m__parent = std::move(_v); } + +private: + std::string m_magic; + uint8_t m_sound_count; + std::string m__unnamed2; + std::unique_ptr> m_sound_names; + std::string m__unnamed4; + std::string m_name; + std::unique_ptr m_global_parameters; + std::string m__unnamed7; + std::unique_ptr> m_master_pad_to_note_mapping; + std::string m__unnamed9; + std::unique_ptr m_drum1; + std::string m__unnamed11; + std::unique_ptr m_drum2; + std::string m__unnamed13; + std::unique_ptr m_drum3; + std::string m__unnamed15; + std::unique_ptr m_drum4; + std::string m__unnamed17; + std::unique_ptr>> m_aps_programs; + mpc2000xl_aps_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp new file mode 100644 index 00000000..1096bd3d --- /dev/null +++ b/src/test/KaitaiApsTest.cpp @@ -0,0 +1,207 @@ +#include + +#include "TestMpc.hpp" +#include "Mpc.hpp" +#include "disk/AbstractDisk.hpp" +#include "disk/ApsLoader.hpp" +#include "disk/MpcFile.hpp" +#include "engine/EngineHost.hpp" +#include "file/aps/ApsParser.hpp" +#include "file/kaitai/generated/mpc2000xl_aps.h" +#include "sampler/Program.hpp" +#include "sampler/Sampler.hpp" + +#include +#include + +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +namespace { + +void prepareApsResources(mpc::Mpc& mpc) +{ + auto disk = mpc.getDisk(); + auto fs = cmrc::mpctest::get_filesystem(); + + for (auto&& entry : fs.iterate_directory("test/ApsLoading")) { + auto file = fs.open("test/ApsLoading/" + entry.filename()); + std::vector data(file.begin(), file.end()); + auto newFile = disk->newFile(entry.filename()); + newFile->setFileData(data); + } + + disk->initFiles(); +} + +void loadAllPgmsAps(mpc::Mpc& mpc) +{ + prepareApsResources(mpc); + auto apsFile = mpc.getDisk()->getFile("ALL_PGMS.APS"); + constexpr bool headless = true; + mpc::disk::ApsLoader::load(mpc, apsFile, headless); + mpc.getEngineHost()->prepareProcessBlock(512); +} + +} + +TEST_CASE("Kaitai MPC2000 APS parses and rewrites ALL_PGMS", "[kaitai-aps]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ApsLoading/ALL_PGMS.APS"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.magic() == std::string("\x0a\x05", 2)); + REQUIRE(parsed.sound_count() == 3); + REQUIRE(parsed.sound_names() != nullptr); + REQUIRE(parsed.sound_names()->size() == 3U); + REQUIRE(parsed.sound_names()->at(0).substr(0, 6) == "sound1"); + REQUIRE(parsed.sound_names()->at(1).substr(0, 6) == "sound2"); + REQUIRE(parsed.sound_names()->at(2).substr(0, 6) == "sound3"); + REQUIRE(parsed.aps_programs() != nullptr); + REQUIRE(parsed.aps_programs()->size() >= 2U); + REQUIRE(parsed.aps_programs()->at(0)->index() == 0); + REQUIRE(parsed.aps_programs()->at(0)->body() != nullptr); + REQUIRE(parsed.aps_programs()->at(0)->body()->name().substr(0, 8) == "PROGRAM1"); + REQUIRE(parsed.aps_programs()->at(0)->body()->note_parameters()->at(0)->sound_index() == 0); + REQUIRE(parsed.aps_programs()->at(0)->body()->note_parameters()->at(1)->sound_index() == 1); + REQUIRE(parsed.aps_programs()->at(1)->index() == 1); + REQUIRE(parsed.aps_programs()->at(1)->body() != nullptr); + REQUIRE(parsed.aps_programs()->at(1)->body()->name().substr(0, 8) == "PROGRAM2"); + REQUIRE(parsed.aps_programs()->at(1)->body()->note_parameters()->at(0)->sound_index() == 1); + REQUIRE(parsed.aps_programs()->at(1)->body()->note_parameters()->at(1)->sound_index() == 2); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + REQUIRE(rewrittenBytes.size() == originalBytes.size()); + REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); +} + +TEST_CASE("Kaitai MPC2000 APS parses and rewrites real 2KXL ALL_PGMS", "[kaitai-aps][real-2kxl]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc2000xl/Aps/ALL_PGMS.APS"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.magic() == std::string("\x0a\x05", 2)); + REQUIRE(parsed.sound_count() == 2); + REQUIRE(parsed.sound_names() != nullptr); + REQUIRE(parsed.sound_names()->size() == 2U); + REQUIRE(parsed.sound_names()->at(0).substr(0, 1) == "M"); + REQUIRE(parsed.sound_names()->at(1).substr(0, 2) == "ML"); + REQUIRE(parsed.name().substr(0, 8) == "ALL_PGMS"); + REQUIRE(parsed.aps_programs() != nullptr); + REQUIRE(parsed.aps_programs()->size() >= 1U); + REQUIRE(parsed.aps_programs()->at(0)->index() == 0); + REQUIRE(parsed.aps_programs()->at(0)->body() != nullptr); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + REQUIRE(rewrittenBytes.size() == originalBytes.size()); + REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); +} + +TEST_CASE("Kaitai MPC2000 APS matches handwritten APS bytes", "[kaitai-aps]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + loadAllPgmsAps(mpc); + + REQUIRE(mpc.getSampler()->getProgramCount() == 2); + REQUIRE(mpc.getSampler()->getSoundCount() == 3); + + mpc::file::aps::ApsParser handwrittenWriter(mpc, "ALL_PGMS"); + const auto handwrittenBytes = handwrittenWriter.getBytes(); + + std::stringstream parseStream( + std::string(handwrittenBytes.begin(), handwrittenBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.magic() == std::string("\x0a\x05", 2)); + REQUIRE(parsed.sound_count() == 3); + REQUIRE(parsed.sound_names() != nullptr); + REQUIRE(parsed.sound_names()->at(0).substr(0, 6) == "sound1"); + REQUIRE(parsed.sound_names()->at(1).substr(0, 6) == "sound2"); + REQUIRE(parsed.sound_names()->at(2).substr(0, 6) == "sound3"); + REQUIRE(parsed.aps_programs() != nullptr); + REQUIRE(parsed.aps_programs()->at(0)->body() != nullptr); + REQUIRE(parsed.aps_programs()->at(0)->body()->name().substr(0, 8) == "PROGRAM1"); + REQUIRE(parsed.aps_programs()->at(1)->body() != nullptr); + REQUIRE(parsed.aps_programs()->at(1)->body()->name().substr(0, 8) == "PROGRAM2"); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto kaitaiBytes = writeStream.str(); + REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); + + auto sampler = mpc.getSampler(); + sampler->deleteAllPrograms(false); + sampler->deleteAllSamples(); + + auto disk = mpc.getDisk(); + auto kaitaiFile = disk->newFile("KAPS.APS"); + std::vector kaitaiBytesVec(kaitaiBytes.begin(), kaitaiBytes.end()); + kaitaiFile->setFileData(kaitaiBytesVec); + disk->initFiles(); + + constexpr bool headless = true; + mpc::disk::ApsLoader::load(mpc, kaitaiFile, headless); + mpc.getEngineHost()->prepareProcessBlock(512); + + auto p1 = sampler->getProgram(0); + auto p2 = sampler->getProgram(1); + REQUIRE(sampler->getProgramCount() == 2); + REQUIRE(p1->getName() == "PROGRAM1"); + REQUIRE(p2->getName() == "PROGRAM2"); + REQUIRE(sampler->getSoundCount() == 3); + REQUIRE(sampler->getSoundName(0) == "sound1"); + REQUIRE(sampler->getSoundName(1) == "sound2"); + REQUIRE(sampler->getSoundName(2) == "sound3"); + REQUIRE(p1->getNoteParameters(35)->getSoundIndex() == 0); + REQUIRE(p1->getNoteParameters(36)->getSoundIndex() == 1); + REQUIRE(p2->getNoteParameters(35)->getSoundIndex() == 1); + REQUIRE(p2->getNoteParameters(36)->getSoundIndex() == 2); +} diff --git a/test-resources/RealMpc2000xl/Aps/ALL_PGMS.APS b/test-resources/RealMpc2000xl/Aps/ALL_PGMS.APS new file mode 100755 index 0000000000000000000000000000000000000000..23e1efb4d35298015746bf3e257d658f37538dec GIT binary patch literal 4073 zcmd;LWn%DEKm`oGK4=0G430iN@d56>!7vGi|CbmN85kHGR8_QsG}QET4D@xi4b6>B z&0GTm9G!f8E$r+aJiXl2O)RafZET%g+&sMf{FOD0fX!XqN1qGMv?;u8{+SQt7O z9T?acQjAi7#*LB#6#@*5jP)Qq8W#hf4oBl+pmG7Gy`yn~872cI0*ea<26h%X2EWwu zfb?8lM|hRQ&{4so%OG;jh(XzbL5ku3e+C_f2wEY3`SNu812&xbbro)fzsY76N3lC1$G98WJVDV**`|cOhz^w ztXv`@Mhpy0{E`f;jv{i5tiaYqGQ*euJfP$a1WXM6jQ)%aPB3i5kgUOA!$382SQtPy S0UJ3CcE(XgB1EzO{|5jX*IZHn literal 0 HcmV?d00001 From d4920a24d5649b65da3f9e772d1d9f0bf8f221b9 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 13 Jun 2026 19:37:11 +0200 Subject: [PATCH 04/52] Add Kaitai 2KXL ALL parser #342 --- .../file/kaitai/generated/mpc2000xl_all.cpp | 3170 +++++++++++++++++ .../file/kaitai/generated/mpc2000xl_all.h | 2136 +++++++++++ src/test/KaitaiAllTest.cpp | 166 + test-resources/RealMpc2000xl/All/ALL.ALL | Bin 0 -> 34918 bytes 4 files changed, 5472 insertions(+) create mode 100644 src/main/file/kaitai/generated/mpc2000xl_all.cpp create mode 100644 src/main/file/kaitai/generated/mpc2000xl_all.h create mode 100644 src/test/KaitaiAllTest.cpp create mode 100755 test-resources/RealMpc2000xl/All/ALL.ALL diff --git a/src/main/file/kaitai/generated/mpc2000xl_all.cpp b/src/main/file/kaitai/generated/mpc2000xl_all.cpp new file mode 100644 index 00000000..a17f0d65 --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_all.cpp @@ -0,0 +1,3170 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "mpc2000xl_all.h" +#include "kaitai/exceptions.h" +#include +#include +const std::set mpc2000xl_all_t::_values_bus_t{ + mpc2000xl_all_t::BUS_MIDI, + mpc2000xl_all_t::BUS_DRUM1, + mpc2000xl_all_t::BUS_DRUM2, + mpc2000xl_all_t::BUS_DRUM3, + mpc2000xl_all_t::BUS_DRUM4, +}; +bool mpc2000xl_all_t::_is_defined_bus_t(mpc2000xl_all_t::bus_t v) { + return mpc2000xl_all_t::_values_bus_t.find(v) != mpc2000xl_all_t::_values_bus_t.end(); +} +const std::set mpc2000xl_all_t::_values_click_output_t{ + mpc2000xl_all_t::CLICK_OUTPUT_STEREO, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV1, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV2, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV3, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV4, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV5, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV6, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV7, + mpc2000xl_all_t::CLICK_OUTPUT_INDIV8, +}; +bool mpc2000xl_all_t::_is_defined_click_output_t(mpc2000xl_all_t::click_output_t v) { + return mpc2000xl_all_t::_values_click_output_t.find(v) != mpc2000xl_all_t::_values_click_output_t.end(); +} +const std::set mpc2000xl_all_t::_values_controller_t{ + mpc2000xl_all_t::CONTROLLER_BANK_SEL_MSB, + mpc2000xl_all_t::CONTROLLER_MOD_WHEEL, + mpc2000xl_all_t::CONTROLLER_BREATH_CONT, + mpc2000xl_all_t::CONTROLLER_CC3, + mpc2000xl_all_t::CONTROLLER_FOOT_CONTROL, + mpc2000xl_all_t::CONTROLLER_PORTA_TIME, + mpc2000xl_all_t::CONTROLLER_DATA_ENTRY, + mpc2000xl_all_t::CONTROLLER_MAIN_VOLUME, + mpc2000xl_all_t::CONTROLLER_BALANCE, + mpc2000xl_all_t::CONTROLLER_CC9, + mpc2000xl_all_t::CONTROLLER_PAN, + mpc2000xl_all_t::CONTROLLER_EXPRESSION, + mpc2000xl_all_t::CONTROLLER_EFFECT_1, + mpc2000xl_all_t::CONTROLLER_EFFECT_2, + mpc2000xl_all_t::CONTROLLER_CC14, + mpc2000xl_all_t::CONTROLLER_CC15, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_1, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_2, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_3, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_4, + mpc2000xl_all_t::CONTROLLER_CC20, + mpc2000xl_all_t::CONTROLLER_CC21, + mpc2000xl_all_t::CONTROLLER_CC22, + mpc2000xl_all_t::CONTROLLER_CC23, + mpc2000xl_all_t::CONTROLLER_CC24, + mpc2000xl_all_t::CONTROLLER_CC25, + mpc2000xl_all_t::CONTROLLER_CC26, + mpc2000xl_all_t::CONTROLLER_CC27, + mpc2000xl_all_t::CONTROLLER_CC28, + mpc2000xl_all_t::CONTROLLER_CC29, + mpc2000xl_all_t::CONTROLLER_CC30, + mpc2000xl_all_t::CONTROLLER_CC31, + mpc2000xl_all_t::CONTROLLER_BANK_SEL_LSB, + mpc2000xl_all_t::CONTROLLER_MOD_WHEL_LSB, + mpc2000xl_all_t::CONTROLLER_BREATH_LSB, + mpc2000xl_all_t::CONTROLLER_CC35, + mpc2000xl_all_t::CONTROLLER_FOOT_CNT_LSB, + mpc2000xl_all_t::CONTROLLER_PORT_TIME_LS, + mpc2000xl_all_t::CONTROLLER_DATA_ENT_LSB, + mpc2000xl_all_t::CONTROLLER_MAIN_VOL_LSB, + mpc2000xl_all_t::CONTROLLER_BALANCE_LSB, + mpc2000xl_all_t::CONTROLLER_CC41, + mpc2000xl_all_t::CONTROLLER_PAN_LSB, + mpc2000xl_all_t::CONTROLLER_EXPRESS_LSB, + mpc2000xl_all_t::CONTROLLER_EFFECT_1_LSB, + mpc2000xl_all_t::CONTROLLER_EFFECT_2_MSB, + mpc2000xl_all_t::CONTROLLER_CC46, + mpc2000xl_all_t::CONTROLLER_CC47, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_1_LS, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_2_LS, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_3_LS, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_4_LS, + mpc2000xl_all_t::CONTROLLER_CC52, + mpc2000xl_all_t::CONTROLLER_CC53, + mpc2000xl_all_t::CONTROLLER_CC54, + mpc2000xl_all_t::CONTROLLER_CC55, + mpc2000xl_all_t::CONTROLLER_CC56, + mpc2000xl_all_t::CONTROLLER_CC57, + mpc2000xl_all_t::CONTROLLER_CC58, + mpc2000xl_all_t::CONTROLLER_CC59, + mpc2000xl_all_t::CONTROLLER_CC60, + mpc2000xl_all_t::CONTROLLER_CC61, + mpc2000xl_all_t::CONTROLLER_CC62, + mpc2000xl_all_t::CONTROLLER_CC63, + mpc2000xl_all_t::CONTROLLER_SUSTAIN_PDL, + mpc2000xl_all_t::CONTROLLER_PORTA_PEDAL, + mpc2000xl_all_t::CONTROLLER_SOSTENUTO, + mpc2000xl_all_t::CONTROLLER_SOFT_PEDAL, + mpc2000xl_all_t::CONTROLLER_LEGATO_FT_SW, + mpc2000xl_all_t::CONTROLLER_HOLD_2, + mpc2000xl_all_t::CONTROLLER_SOUND_VARI, + mpc2000xl_all_t::CONTROLLER_TIMBER_HARMO, + mpc2000xl_all_t::CONTROLLER_RELEASE_TIME, + mpc2000xl_all_t::CONTROLLER_ATTACK_TIME, + mpc2000xl_all_t::CONTROLLER_BRIGHTNESS, + mpc2000xl_all_t::CONTROLLER_SOUND_CONT_6, + mpc2000xl_all_t::CONTROLLER_SOUND_CONT_7, + mpc2000xl_all_t::CONTROLLER_SOUND_CONT_8, + mpc2000xl_all_t::CONTROLLER_SOUND_CONT_9, + mpc2000xl_all_t::CONTROLLER_SOUND_CONT10, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_5, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_6, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_7, + mpc2000xl_all_t::CONTROLLER_GEN_PUR_8, + mpc2000xl_all_t::CONTROLLER_PORTA_CNTRL, + mpc2000xl_all_t::CONTROLLER_CC85, + mpc2000xl_all_t::CONTROLLER_CC86, + mpc2000xl_all_t::CONTROLLER_CC87, + mpc2000xl_all_t::CONTROLLER_CC88, + mpc2000xl_all_t::CONTROLLER_CC89, + mpc2000xl_all_t::CONTROLLER_CC90, + mpc2000xl_all_t::CONTROLLER_EXT_EFF_DPTH, + mpc2000xl_all_t::CONTROLLER_TREMOLO_DPTH, + mpc2000xl_all_t::CONTROLLER_CHORUS_DEPTH, + mpc2000xl_all_t::CONTROLLER_DETUNE_DEPTH, + mpc2000xl_all_t::CONTROLLER_PHASER_DEPTH, + mpc2000xl_all_t::CONTROLLER_DATA_INCRE, + mpc2000xl_all_t::CONTROLLER_DATA_DECRE, + mpc2000xl_all_t::CONTROLLER_NRPN_LSB, + mpc2000xl_all_t::CONTROLLER_NRPN_MSB, + mpc2000xl_all_t::CONTROLLER_RPN_LSB, + mpc2000xl_all_t::CONTROLLER_RPN_MSB, + mpc2000xl_all_t::CONTROLLER_CC102, + mpc2000xl_all_t::CONTROLLER_CC103, + mpc2000xl_all_t::CONTROLLER_CC104, + mpc2000xl_all_t::CONTROLLER_CC105, + mpc2000xl_all_t::CONTROLLER_CC106, + mpc2000xl_all_t::CONTROLLER_CC107, + mpc2000xl_all_t::CONTROLLER_CC108, + mpc2000xl_all_t::CONTROLLER_CC109, + mpc2000xl_all_t::CONTROLLER_CC110, + mpc2000xl_all_t::CONTROLLER_CC111, + mpc2000xl_all_t::CONTROLLER_CC112, + mpc2000xl_all_t::CONTROLLER_CC113, + mpc2000xl_all_t::CONTROLLER_CC114, + mpc2000xl_all_t::CONTROLLER_CC115, + mpc2000xl_all_t::CONTROLLER_CC116, + mpc2000xl_all_t::CONTROLLER_CC117, + mpc2000xl_all_t::CONTROLLER_CC118, + mpc2000xl_all_t::CONTROLLER_CC119, + mpc2000xl_all_t::CONTROLLER_ALL_SND_OFF, + mpc2000xl_all_t::CONTROLLER_RESET_CONTRL, + mpc2000xl_all_t::CONTROLLER_LOCAL_ON_OFF, + mpc2000xl_all_t::CONTROLLER_ALL_NOTE_OFF, + mpc2000xl_all_t::CONTROLLER_OMNI_OFF, + mpc2000xl_all_t::CONTROLLER_OMNI_ON, + mpc2000xl_all_t::CONTROLLER_MONO_MODE_ON, + mpc2000xl_all_t::CONTROLLER_POLY_MODE_ON, +}; +bool mpc2000xl_all_t::_is_defined_controller_t(mpc2000xl_all_t::controller_t v) { + return mpc2000xl_all_t::_values_controller_t.find(v) != mpc2000xl_all_t::_values_controller_t.end(); +} +const std::set mpc2000xl_all_t::_values_count_in_mode_t{ + mpc2000xl_all_t::COUNT_IN_MODE_FALSE, + mpc2000xl_all_t::COUNT_IN_MODE_REC_ONLY, + mpc2000xl_all_t::COUNT_IN_MODE_REC_AND_PLAY, +}; +bool mpc2000xl_all_t::_is_defined_count_in_mode_t(mpc2000xl_all_t::count_in_mode_t v) { + return mpc2000xl_all_t::_values_count_in_mode_t.find(v) != mpc2000xl_all_t::_values_count_in_mode_t.end(); +} +const std::set mpc2000xl_all_t::_values_duration_of_recorded_notes_t{ + mpc2000xl_all_t::DURATION_OF_RECORDED_NOTES_AS_PLAYED, + mpc2000xl_all_t::DURATION_OF_RECORDED_NOTES_TC_VALUE, +}; +bool mpc2000xl_all_t::_is_defined_duration_of_recorded_notes_t(mpc2000xl_all_t::duration_of_recorded_notes_t v) { + return mpc2000xl_all_t::_values_duration_of_recorded_notes_t.find(v) != mpc2000xl_all_t::_values_duration_of_recorded_notes_t.end(); +} +const std::set mpc2000xl_all_t::_values_frame_rate_t{ + mpc2000xl_all_t::FRAME_RATE_FPS_24, + mpc2000xl_all_t::FRAME_RATE_FPS_25, + mpc2000xl_all_t::FRAME_RATE_FPS_30D, + mpc2000xl_all_t::FRAME_RATE_FPS_30, +}; +bool mpc2000xl_all_t::_is_defined_frame_rate_t(mpc2000xl_all_t::frame_rate_t v) { + return mpc2000xl_all_t::_values_frame_rate_t.find(v) != mpc2000xl_all_t::_values_frame_rate_t.end(); +} +const std::set mpc2000xl_all_t::_values_midi_input_filter_type_t{ + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_NOTES, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_PITCH_BEND, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_PROG_CHANGE, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CH_PRESSURE, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_POLY_PRESS, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_EXCLUSIVE, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC0_BANK_SEL_MSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC1_MOD_WHEEL, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC2_BREATH_CONT, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC3, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC4_FOOT_CONTROL, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC5_PORTA_TIME, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC6_DATA_ENTRY, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC7_MAIN_VOLUME, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC8_BALANCE, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC9, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC10_PAN, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC11_EXPRESSION, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC12_EFFECT_1, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC13_EFFECT_2, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC14, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC15, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC16_GEN_PUR_1, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC17_GEN_PUR_2, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC18_GEN_PUR_3, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC19_GEN_PUR_4, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC20, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC21, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC22, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC23, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC24, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC25, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC26, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC27, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC28, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC29, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC30, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC31, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC32_BANK_SEL_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC33_MOD_WHEL_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC34_BREATH_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC35, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC36_FOOT_CNT_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC37_PORT_TIME_LS, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC38_DATA_ENT_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC39_MAIN_VOL_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC40_BALANCE_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC41, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC42_PAN_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC43_EXPRESS_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC44_EFFECT_1_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC45_EFFECT_2_MSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC46, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC47, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC48_GEN_PUR_1_LS, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC49_GEN_PUR_2_LS, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC50_GEN_PUR_3_LS, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC51_GEN_PUR_4_LS, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC52, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC53, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC54, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC55, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC56, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC57, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC58, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC59, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC60, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC61, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC62, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC63, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC64_SUSTAIN_PDL, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC65_PORTA_PEDAL, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC66_SOSTENUTO, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC67_SOFT_PEDAL, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC68_LEGATO_FT_SW, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC69_HOLD_2, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC70_SOUND_VARI, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC71_TIMBER_HARMO, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC72_RELEASE_TIME, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC73_ATTACK_TIME, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC74_BRIGHTNESS, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC75_SOUND_CONT_6, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC76_SOUND_CONT_7, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC77_SOUND_CONT_8, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC78_SOUND_CONT_9, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC79_SOUND_CONT10, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC80_GEN_PUR_5, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC81_GEN_PUR_6, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC82_GEN_PUR_7, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC83_GEN_PUR_8, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC84_PORTA_CNTRL, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC85, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC86, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC87, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC88, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC89, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC90, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC91_EXT_EFF_DPTH, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC92_TREMOLO_DPTH, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC93_CHORUS_DEPTH, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC94_DETUNE_DEPTH, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC95_PHASER_DEPTH, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC96_DATA_INCRE, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC97_DATA_DECRE, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC98_NRPN_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC99_NRPN_MSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC100_RPN_LSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC101_RPN_MSB, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC102, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC103, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC104, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC105, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC106, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC107, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC108, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC109, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC110, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC111, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC112, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC113, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC114, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC115, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC116, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC117, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC118, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC119, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC120_ALL_SND_OFF, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC121_RESET_CONTRL, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC122_LOCAL_ON_OFF, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC123_ALL_NOTE_OFF, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC124_OMNI_OFF, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC125_OMNI_ON, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC126_MONO_MODE_ON, + mpc2000xl_all_t::MIDI_INPUT_FILTER_TYPE_CC127_POLY_MODE_ON, +}; +bool mpc2000xl_all_t::_is_defined_midi_input_filter_type_t(mpc2000xl_all_t::midi_input_filter_type_t v) { + return mpc2000xl_all_t::_values_midi_input_filter_type_t.find(v) != mpc2000xl_all_t::_values_midi_input_filter_type_t.end(); +} +const std::set mpc2000xl_all_t::_values_midi_input_receive_channel_t{ + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_ALL, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH1, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH2, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH3, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH4, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH5, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH6, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH7, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH8, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH9, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH10, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH11, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH12, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH13, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH14, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH15, + mpc2000xl_all_t::MIDI_INPUT_RECEIVE_CHANNEL_CH16, +}; +bool mpc2000xl_all_t::_is_defined_midi_input_receive_channel_t(mpc2000xl_all_t::midi_input_receive_channel_t v) { + return mpc2000xl_all_t::_values_midi_input_receive_channel_t.find(v) != mpc2000xl_all_t::_values_midi_input_receive_channel_t.end(); +} +const std::set mpc2000xl_all_t::_values_midi_switch_function_t{ + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PLAY_STRT, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PLAY, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_STOP, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_REC_AND_PLAY, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_ODUB_AND_PLAY, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_REC_PUNCH, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_ODUB_PNCH, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_TAP, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_BNK_A, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_BNK_B, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_BNK_C, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_BNK_D, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_1, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_2, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_3, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_4, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_5, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_6, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_7, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_8, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_9, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_10, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_11, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_12, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_13, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_14, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_15, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_PAD_16, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_F1, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_F2, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_F3, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_F4, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_F5, + mpc2000xl_all_t::MIDI_SWITCH_FUNCTION_F6, +}; +bool mpc2000xl_all_t::_is_defined_midi_switch_function_t(mpc2000xl_all_t::midi_switch_function_t v) { + return mpc2000xl_all_t::_values_midi_switch_function_t.find(v) != mpc2000xl_all_t::_values_midi_switch_function_t.end(); +} +const std::set mpc2000xl_all_t::_values_midi_sync_mode_t{ + mpc2000xl_all_t::MIDI_SYNC_MODE_FALSE, + mpc2000xl_all_t::MIDI_SYNC_MODE_MIDI_CLOCK, + mpc2000xl_all_t::MIDI_SYNC_MODE_TIME_CODE, +}; +bool mpc2000xl_all_t::_is_defined_midi_sync_mode_t(mpc2000xl_all_t::midi_sync_mode_t v) { + return mpc2000xl_all_t::_values_midi_sync_mode_t.find(v) != mpc2000xl_all_t::_values_midi_sync_mode_t.end(); +} +const std::set mpc2000xl_all_t::_values_midi_sync_output_t{ + mpc2000xl_all_t::MIDI_SYNC_OUTPUT_A, + mpc2000xl_all_t::MIDI_SYNC_OUTPUT_B, + mpc2000xl_all_t::MIDI_SYNC_OUTPUT_A_AND_B, +}; +bool mpc2000xl_all_t::_is_defined_midi_sync_output_t(mpc2000xl_all_t::midi_sync_output_t v) { + return mpc2000xl_all_t::_values_midi_sync_output_t.find(v) != mpc2000xl_all_t::_values_midi_sync_output_t.end(); +} +const std::set mpc2000xl_all_t::_values_mixer_event_param_t{ + mpc2000xl_all_t::MIXER_EVENT_PARAM_STEREO_LEVEL, + mpc2000xl_all_t::MIXER_EVENT_PARAM_STEREO_PAN, + mpc2000xl_all_t::MIXER_EVENT_PARAM_FXSEND_LEVEL, + mpc2000xl_all_t::MIXER_EVENT_PARAM_INDIV_LEVEL, +}; +bool mpc2000xl_all_t::_is_defined_mixer_event_param_t(mpc2000xl_all_t::mixer_event_param_t v) { + return mpc2000xl_all_t::_values_mixer_event_param_t.find(v) != mpc2000xl_all_t::_values_mixer_event_param_t.end(); +} +const std::set mpc2000xl_all_t::_values_off_on_t{ + mpc2000xl_all_t::OFF_ON_FALSE, + mpc2000xl_all_t::OFF_ON_TRUE, +}; +bool mpc2000xl_all_t::_is_defined_off_on_t(mpc2000xl_all_t::off_on_t v) { + return mpc2000xl_all_t::_values_off_on_t.find(v) != mpc2000xl_all_t::_values_off_on_t.end(); +} +const std::set mpc2000xl_all_t::_values_rate_t{ + mpc2000xl_all_t::RATE_ONE_4, + mpc2000xl_all_t::RATE_ONE_4_3, + mpc2000xl_all_t::RATE_ONE_8, + mpc2000xl_all_t::RATE_ONE_8_3, + mpc2000xl_all_t::RATE_ONE_16, + mpc2000xl_all_t::RATE_ONE_16_3, + mpc2000xl_all_t::RATE_ONE_32, + mpc2000xl_all_t::RATE_ONE_32_3, +}; +bool mpc2000xl_all_t::_is_defined_rate_t(mpc2000xl_all_t::rate_t v) { + return mpc2000xl_all_t::_values_rate_t.find(v) != mpc2000xl_all_t::_values_rate_t.end(); +} +const std::set mpc2000xl_all_t::_values_sequence_is_used_t{ + mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE, + mpc2000xl_all_t::SEQUENCE_IS_USED_TRUE, +}; +bool mpc2000xl_all_t::_is_defined_sequence_is_used_t(mpc2000xl_all_t::sequence_is_used_t v) { + return mpc2000xl_all_t::_values_sequence_is_used_t.find(v) != mpc2000xl_all_t::_values_sequence_is_used_t.end(); +} +const std::set mpc2000xl_all_t::_values_soft_thru_mode_t{ + mpc2000xl_all_t::SOFT_THRU_MODE_FALSE, + mpc2000xl_all_t::SOFT_THRU_MODE_AS_TRACK, + mpc2000xl_all_t::SOFT_THRU_MODE_OMNI_A, + mpc2000xl_all_t::SOFT_THRU_MODE_OMNI_B, + mpc2000xl_all_t::SOFT_THRU_MODE_OMNI_AB, +}; +bool mpc2000xl_all_t::_is_defined_soft_thru_mode_t(mpc2000xl_all_t::soft_thru_mode_t v) { + return mpc2000xl_all_t::_values_soft_thru_mode_t.find(v) != mpc2000xl_all_t::_values_soft_thru_mode_t.end(); +} +const std::set mpc2000xl_all_t::_values_sound_source_t{ + mpc2000xl_all_t::SOUND_SOURCE_CLICK, + mpc2000xl_all_t::SOUND_SOURCE_DRUM1, + mpc2000xl_all_t::SOUND_SOURCE_DRUM2, + mpc2000xl_all_t::SOUND_SOURCE_DRUM3, + mpc2000xl_all_t::SOUND_SOURCE_DRUM4, +}; +bool mpc2000xl_all_t::_is_defined_sound_source_t(mpc2000xl_all_t::sound_source_t v) { + return mpc2000xl_all_t::_values_sound_source_t.find(v) != mpc2000xl_all_t::_values_sound_source_t.end(); +} +const std::set mpc2000xl_all_t::_values_tap_averaging_t{ + mpc2000xl_all_t::TAP_AVERAGING_TAP_AVG_2, + mpc2000xl_all_t::TAP_AVERAGING_TAP_AVG_3, + mpc2000xl_all_t::TAP_AVERAGING_TAP_AVG_4, +}; +bool mpc2000xl_all_t::_is_defined_tap_averaging_t(mpc2000xl_all_t::tap_averaging_t v) { + return mpc2000xl_all_t::_values_tap_averaging_t.find(v) != mpc2000xl_all_t::_values_tap_averaging_t.end(); +} +const std::set mpc2000xl_all_t::_values_time_display_style_t{ + mpc2000xl_all_t::TIME_DISPLAY_STYLE_BAR_BEAT_CLOCK, + mpc2000xl_all_t::TIME_DISPLAY_STYLE_HOUR_MINUTE_SEC, +}; +bool mpc2000xl_all_t::_is_defined_time_display_style_t(mpc2000xl_all_t::time_display_style_t v) { + return mpc2000xl_all_t::_values_time_display_style_t.find(v) != mpc2000xl_all_t::_values_time_display_style_t.end(); +} +const std::set mpc2000xl_all_t::_values_timing_correct_t{ + mpc2000xl_all_t::TIMING_CORRECT_FALSE, + mpc2000xl_all_t::TIMING_CORRECT_ONE_8, + mpc2000xl_all_t::TIMING_CORRECT_ONE_8_3, + mpc2000xl_all_t::TIMING_CORRECT_ONE_16, + mpc2000xl_all_t::TIMING_CORRECT_ONE_16_3, + mpc2000xl_all_t::TIMING_CORRECT_ONE_32, + mpc2000xl_all_t::TIMING_CORRECT_ONE_32_3, +}; +bool mpc2000xl_all_t::_is_defined_timing_correct_t(mpc2000xl_all_t::timing_correct_t v) { + return mpc2000xl_all_t::_values_timing_correct_t.find(v) != mpc2000xl_all_t::_values_timing_correct_t.end(); +} +const std::set mpc2000xl_all_t::_values_unused_used_t{ + mpc2000xl_all_t::UNUSED_USED_UNUSED, + mpc2000xl_all_t::UNUSED_USED_USED, +}; +bool mpc2000xl_all_t::_is_defined_unused_used_t(mpc2000xl_all_t::unused_used_t v) { + return mpc2000xl_all_t::_values_unused_used_t.find(v) != mpc2000xl_all_t::_values_unused_used_t.end(); +} + +mpc2000xl_all_t::mpc2000xl_all_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; +} + +void mpc2000xl_all_t::_read() { + m_magic = m__io->read_bytes(16); + if (!(m_magic == std::string("\x4D\x50\x43\x32\x4B\x58\x4C\x20\x41\x4C\x4C\x20\x31\x2E\x30\x30", 16))) { + throw kaitai::validation_not_equal_error(std::string("\x4D\x50\x43\x32\x4B\x58\x4C\x20\x41\x4C\x4C\x20\x31\x2E\x30\x30", 16), m_magic, m__io, std::string("/seq/0")); + } + m_defaults = std::unique_ptr(new defaults_t(m__io, this, m__root)); + m_defaults->_read(); + m_sequencer = std::unique_ptr(new sequencer_t(m__io, this, m__root)); + m_sequencer->_read(); + m__unnamed3 = m__io->read_bytes(10); + m_count = std::unique_ptr(new count_t(m__io, this, m__root)); + m_count->_read(); + m_midi_output = std::unique_ptr(new midi_output_t(m__io, this, m__root)); + m_midi_output->_read(); + m_midi_input = std::unique_ptr(new midi_input_t(m__io, this, m__root)); + m_midi_input->_read(); + m_midi_sync = std::unique_ptr(new midi_sync_t(m__io, this, m__root)); + m_midi_sync->_read(); + m_song_global = std::unique_ptr(new song_global_t(m__io, this, m__root)); + m_song_global->_read(); + m__unnamed9 = m__io->read_bytes(5); + m_locations = std::unique_ptr>>(new std::vector>()); + const int l_locations = 9; + for (int i = 0; i < l_locations; i++) { + std::unique_ptr _t_locations = std::unique_ptr(new location_t(m__io, this, m__root)); + try { + _t_locations->_read(); + } catch(...) { + m_locations->push_back(std::move(_t_locations)); + throw; + } + m_locations->push_back(std::move(_t_locations)); + } + m_misc = std::unique_ptr(new misc_t(m__io, this, m__root)); + m_misc->_read(); + m__unnamed12 = m__io->read_bytes(3); + m_step_edit_options = std::unique_ptr(new step_edit_options_t(m__io, this, m__root)); + m_step_edit_options->_read(); + m_prog_change_to_seq = m__io->read_bits_int_le(1); + m__unnamed15 = m__io->read_bytes(78); + m_sequences_metas = std::unique_ptr>>(new std::vector>()); + const int l_sequences_metas = 99; + for (int i = 0; i < l_sequences_metas; i++) { + std::unique_ptr _t_sequences_metas = std::unique_ptr(new sequence_meta_t(m__io, this, m__root)); + try { + _t_sequences_metas->_read(); + } catch(...) { + m_sequences_metas->push_back(std::move(_t_sequences_metas)); + throw; + } + m_sequences_metas->push_back(std::move(_t_sequences_metas)); + } + m_songs = std::unique_ptr>>(new std::vector>()); + const int l_songs = 20; + for (int i = 0; i < l_songs; i++) { + std::unique_ptr _t_songs = std::unique_ptr(new song_t(m__io, this, m__root)); + try { + _t_songs->_read(); + } catch(...) { + m_songs->push_back(std::move(_t_songs)); + throw; + } + m_songs->push_back(std::move(_t_songs)); + } + m_sequences = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + while (!m__io->is_eof()) { + std::unique_ptr _t_sequences = std::unique_ptr(new sequence_t(m__io, this, m__root)); + try { + _t_sequences->_read(); + } catch(...) { + m_sequences->push_back(std::move(_t_sequences)); + throw; + } + m_sequences->push_back(std::move(_t_sequences)); + i++; + } + } + m__dirty = false; +} + +void mpc2000xl_all_t::_fetch_instances() { + m_defaults.get()->_fetch_instances(); + m_sequencer.get()->_fetch_instances(); + m_count.get()->_fetch_instances(); + m_midi_output.get()->_fetch_instances(); + m_midi_input.get()->_fetch_instances(); + m_midi_sync.get()->_fetch_instances(); + m_song_global.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_locations->size(); ++i) { + m_locations->at(i).get()->_fetch_instances(); + } + m_misc.get()->_fetch_instances(); + m_step_edit_options.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_sequences_metas->size(); ++i) { + m_sequences_metas->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_songs->size(); ++i) { + m_songs->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_sequences->size(); ++i) { + m_sequences->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::_write() { + m__io->write_bytes(m_magic); + if (m_defaults.get() == nullptr) { + throw std::runtime_error("/seq/1: nested object is not set"); + } + m_defaults.get()->_set_io(m__io); + m_defaults.get()->_write(); + if (m_sequencer.get() == nullptr) { + throw std::runtime_error("/seq/2: nested object is not set"); + } + m_sequencer.get()->_set_io(m__io); + m_sequencer.get()->_write(); + m__io->write_bytes(m__unnamed3); + if (m_count.get() == nullptr) { + throw std::runtime_error("/seq/4: nested object is not set"); + } + m_count.get()->_set_io(m__io); + m_count.get()->_write(); + if (m_midi_output.get() == nullptr) { + throw std::runtime_error("/seq/5: nested object is not set"); + } + m_midi_output.get()->_set_io(m__io); + m_midi_output.get()->_write(); + if (m_midi_input.get() == nullptr) { + throw std::runtime_error("/seq/6: nested object is not set"); + } + m_midi_input.get()->_set_io(m__io); + m_midi_input.get()->_write(); + if (m_midi_sync.get() == nullptr) { + throw std::runtime_error("/seq/7: nested object is not set"); + } + m_midi_sync.get()->_set_io(m__io); + m_midi_sync.get()->_write(); + if (m_song_global.get() == nullptr) { + throw std::runtime_error("/seq/8: nested object is not set"); + } + m_song_global.get()->_set_io(m__io); + m_song_global.get()->_write(); + m__io->write_bytes(m__unnamed9); + if (m_locations == nullptr) { + throw std::runtime_error("/seq/10: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_locations->begin(); it != m_locations->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/10: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + if (m_misc.get() == nullptr) { + throw std::runtime_error("/seq/11: nested object is not set"); + } + m_misc.get()->_set_io(m__io); + m_misc.get()->_write(); + m__io->write_bytes(m__unnamed12); + if (m_step_edit_options.get() == nullptr) { + throw std::runtime_error("/seq/13: nested object is not set"); + } + m_step_edit_options.get()->_set_io(m__io); + m_step_edit_options.get()->_write(); + m__io->write_bits_int_le(1, ((m_prog_change_to_seq) ? 1 : 0)); + m__io->write_bytes(m__unnamed15); + if (m_sequences_metas == nullptr) { + throw std::runtime_error("/seq/16: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_sequences_metas->begin(); it != m_sequences_metas->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/16: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + if (m_songs == nullptr) { + throw std::runtime_error("/seq/17: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_songs->begin(); it != m_songs->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/17: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + if (m_sequences == nullptr) { + throw std::runtime_error("/seq/18: repeated field is not set"); + } + if (m_sequences == nullptr) { + throw std::runtime_error("/seq/18: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_sequences->begin(); it != m_sequences->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/18: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::_check() { + if (m_magic.size() != static_cast(16)) { + throw std::runtime_error("/seq/0: size mismatch"); + } + if (!(m_magic == std::string("\x4D\x50\x43\x32\x4B\x58\x4C\x20\x41\x4C\x4C\x20\x31\x2E\x30\x30", 16))) { + throw kaitai::validation_not_equal_error(std::string("\x4D\x50\x43\x32\x4B\x58\x4C\x20\x41\x4C\x4C\x20\x31\x2E\x30\x30", 16), m_magic, m__io, std::string("/seq/0")); + } + if (m_defaults.get() == nullptr) { + throw std::runtime_error("/seq/1: nested object is not set"); + } + m_defaults.get()->_set_io(m__io); + m_defaults.get()->_check(); + if (m_sequencer.get() == nullptr) { + throw std::runtime_error("/seq/2: nested object is not set"); + } + m_sequencer.get()->_set_io(m__io); + m_sequencer.get()->_check(); + if (m__unnamed3.size() != static_cast(10)) { + throw std::runtime_error("/seq/3: size mismatch"); + } + if (m_count.get() == nullptr) { + throw std::runtime_error("/seq/4: nested object is not set"); + } + m_count.get()->_set_io(m__io); + m_count.get()->_check(); + if (m_midi_output.get() == nullptr) { + throw std::runtime_error("/seq/5: nested object is not set"); + } + m_midi_output.get()->_set_io(m__io); + m_midi_output.get()->_check(); + if (m_midi_input.get() == nullptr) { + throw std::runtime_error("/seq/6: nested object is not set"); + } + m_midi_input.get()->_set_io(m__io); + m_midi_input.get()->_check(); + if (m_midi_sync.get() == nullptr) { + throw std::runtime_error("/seq/7: nested object is not set"); + } + m_midi_sync.get()->_set_io(m__io); + m_midi_sync.get()->_check(); + if (m_song_global.get() == nullptr) { + throw std::runtime_error("/seq/8: nested object is not set"); + } + m_song_global.get()->_set_io(m__io); + m_song_global.get()->_check(); + if (m__unnamed9.size() != static_cast(5)) { + throw std::runtime_error("/seq/9: size mismatch"); + } + if (m_locations == nullptr) { + throw std::runtime_error("/seq/10: repeated field is not set"); + } + if (m_locations->size() != static_cast(9)) { + throw std::runtime_error("/seq/10: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_locations->begin(); it != m_locations->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/10: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m_misc.get() == nullptr) { + throw std::runtime_error("/seq/11: nested object is not set"); + } + m_misc.get()->_set_io(m__io); + m_misc.get()->_check(); + if (m__unnamed12.size() != static_cast(3)) { + throw std::runtime_error("/seq/12: size mismatch"); + } + if (m_step_edit_options.get() == nullptr) { + throw std::runtime_error("/seq/13: nested object is not set"); + } + m_step_edit_options.get()->_set_io(m__io); + m_step_edit_options.get()->_check(); + if (m__unnamed15.size() != static_cast(78)) { + throw std::runtime_error("/seq/15: size mismatch"); + } + if (m_sequences_metas == nullptr) { + throw std::runtime_error("/seq/16: repeated field is not set"); + } + if (m_sequences_metas->size() != static_cast(99)) { + throw std::runtime_error("/seq/16: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_sequences_metas->begin(); it != m_sequences_metas->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/16: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m_songs == nullptr) { + throw std::runtime_error("/seq/17: repeated field is not set"); + } + if (m_songs->size() != static_cast(20)) { + throw std::runtime_error("/seq/17: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_songs->begin(); it != m_songs->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/17: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m_sequences == nullptr) { + throw std::runtime_error("/seq/18: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_sequences->begin(); it != m_sequences->end(); ++it) { + const std::size_t i = static_cast(it - m_sequences->begin()); + const sequence_t* _ = (*it).get(); + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/18: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + m__dirty = false; +} + +mpc2000xl_all_t::~mpc2000xl_all_t() {} + +mpc2000xl_all_t::bar_t::bar_t(int32_t p_idx, kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_idx = p_idx; + m__dirty = false; + f_denominator = false; + f_first_tick = false; + f_numerator = false; +} + +void mpc2000xl_all_t::bar_t::_read() { + m_ticks_per_beat = m__io->read_u1(); + m_last_tick = m__io->read_bits_int_le(24); + m__dirty = false; +} + +void mpc2000xl_all_t::bar_t::_fetch_instances() { +} + +void mpc2000xl_all_t::bar_t::_write() { + m__io->write_u1(m_ticks_per_beat); + m__io->write_bits_int_le(24, m_last_tick); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::bar_t::_check() { + m__dirty = false; +} + +mpc2000xl_all_t::bar_t::~bar_t() {} + +int32_t mpc2000xl_all_t::bar_t::denominator() { + if (f_denominator) + return m_denominator; + f_denominator = true; + m_denominator = 4 / (ticks_per_beat() / 96); + return m_denominator; +} + +int32_t mpc2000xl_all_t::bar_t::first_tick() { + if (f_first_tick) + return m_first_tick; + f_first_tick = true; + m_first_tick = ((idx() == 0) ? (0) : (_parent()->bars()->at(idx() - 1)->last_tick())); + return m_first_tick; +} + +int32_t mpc2000xl_all_t::bar_t::numerator() { + if (f_numerator) + return m_numerator; + f_numerator = true; + m_numerator = (last_tick() - first_tick()) / ticks_per_beat(); + return m_numerator; +} + +mpc2000xl_all_t::ch_pressure_event_t::ch_pressure_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::ch_pressure_event_t::_read() { + m_pressure = m__io->read_u1(); + if (!(m_pressure >= 0)) { + throw kaitai::validation_less_than_error(0, m_pressure, m__io, std::string("/types/ch_pressure_event/seq/0")); + } + if (!(m_pressure <= 127)) { + throw kaitai::validation_greater_than_error(127, m_pressure, m__io, std::string("/types/ch_pressure_event/seq/0")); + } + m__unnamed1 = m__io->read_bytes(2); + m__dirty = false; +} + +void mpc2000xl_all_t::ch_pressure_event_t::_fetch_instances() { +} + +void mpc2000xl_all_t::ch_pressure_event_t::_write() { + m__io->write_u1(m_pressure); + m__io->write_bytes(m__unnamed1); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::ch_pressure_event_t::_check() { + if (!(m_pressure >= 0)) { + throw kaitai::validation_less_than_error(0, m_pressure, m__io, std::string("/types/ch_pressure_event/seq/0")); + } + if (!(m_pressure <= 127)) { + throw kaitai::validation_greater_than_error(127, m_pressure, m__io, std::string("/types/ch_pressure_event/seq/0")); + } + if (m__unnamed1.size() != static_cast(2)) { + throw std::runtime_error("/types/ch_pressure_event/seq/1: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::ch_pressure_event_t::~ch_pressure_event_t() {} + +mpc2000xl_all_t::control_change_event_t::control_change_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::control_change_event_t::_read() { + m_controller = static_cast(m__io->read_u1()); + m_value = m__io->read_u1(); + if (!(m_value >= 0)) { + throw kaitai::validation_less_than_error(0, m_value, m__io, std::string("/types/control_change_event/seq/1")); + } + if (!(m_value <= 127)) { + throw kaitai::validation_greater_than_error(127, m_value, m__io, std::string("/types/control_change_event/seq/1")); + } + m__unnamed2 = m__io->read_bytes(1); + m__dirty = false; +} + +void mpc2000xl_all_t::control_change_event_t::_fetch_instances() { +} + +void mpc2000xl_all_t::control_change_event_t::_write() { + m__io->write_u1(static_cast(m_controller)); + m__io->write_u1(m_value); + m__io->write_bytes(m__unnamed2); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::control_change_event_t::_check() { + if (!(m_value >= 0)) { + throw kaitai::validation_less_than_error(0, m_value, m__io, std::string("/types/control_change_event/seq/1")); + } + if (!(m_value <= 127)) { + throw kaitai::validation_greater_than_error(127, m_value, m__io, std::string("/types/control_change_event/seq/1")); + } + if (m__unnamed2.size() != static_cast(1)) { + throw std::runtime_error("/types/control_change_event/seq/2: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::control_change_event_t::~control_change_event_t() {} + +mpc2000xl_all_t::count_t::count_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::count_t::_read() { + m_enabled = m__io->read_bits_int_le(1); + m__unnamed1 = m__io->read_bits_int_le(7); + m_count_in_mode = static_cast(m__io->read_u1()); + m_click_volume = m__io->read_u1(); + if (!(m_click_volume >= 0)) { + throw kaitai::validation_less_than_error(0, m_click_volume, m__io, std::string("/types/count/seq/3")); + } + if (!(m_click_volume <= 100)) { + throw kaitai::validation_greater_than_error(100, m_click_volume, m__io, std::string("/types/count/seq/3")); + } + m_rate = static_cast(m__io->read_u1()); + m_enabled_in_play = m__io->read_bits_int_le(1); + m__unnamed6 = m__io->read_bits_int_le(7); + m_enabled_in_rec = m__io->read_bits_int_le(1); + m__unnamed8 = m__io->read_bits_int_le(7); + m_click_output = static_cast(m__io->read_u1()); + m_wait_for_key = m__io->read_bits_int_le(1); + m__unnamed11 = m__io->read_bits_int_le(7); + m_sound_source = static_cast(m__io->read_u1()); + m_accent_pad_index = m__io->read_u1(); + m_normal_pad_index = m__io->read_u1(); + m_accent_velo = m__io->read_u1(); + if (!(m_accent_velo >= 1)) { + throw kaitai::validation_less_than_error(1, m_accent_velo, m__io, std::string("/types/count/seq/15")); + } + if (!(m_accent_velo <= 127)) { + throw kaitai::validation_greater_than_error(127, m_accent_velo, m__io, std::string("/types/count/seq/15")); + } + m_normal_velo = m__io->read_u1(); + if (!(m_normal_velo >= 1)) { + throw kaitai::validation_less_than_error(1, m_normal_velo, m__io, std::string("/types/count/seq/16")); + } + if (!(m_normal_velo <= 127)) { + throw kaitai::validation_greater_than_error(127, m_normal_velo, m__io, std::string("/types/count/seq/16")); + } + m__dirty = false; +} + +void mpc2000xl_all_t::count_t::_fetch_instances() { +} + +void mpc2000xl_all_t::count_t::_write() { + m__io->write_bits_int_le(1, ((m_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed1); + m__io->write_u1(static_cast(m_count_in_mode)); + m__io->write_u1(m_click_volume); + m__io->write_u1(static_cast(m_rate)); + m__io->write_bits_int_le(1, ((m_enabled_in_play) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed6); + m__io->write_bits_int_le(1, ((m_enabled_in_rec) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed8); + m__io->write_u1(static_cast(m_click_output)); + m__io->write_bits_int_le(1, ((m_wait_for_key) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed11); + m__io->write_u1(static_cast(m_sound_source)); + m__io->write_u1(m_accent_pad_index); + m__io->write_u1(m_normal_pad_index); + m__io->write_u1(m_accent_velo); + m__io->write_u1(m_normal_velo); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::count_t::_check() { + if (!(m_click_volume >= 0)) { + throw kaitai::validation_less_than_error(0, m_click_volume, m__io, std::string("/types/count/seq/3")); + } + if (!(m_click_volume <= 100)) { + throw kaitai::validation_greater_than_error(100, m_click_volume, m__io, std::string("/types/count/seq/3")); + } + if (!(m_accent_velo >= 1)) { + throw kaitai::validation_less_than_error(1, m_accent_velo, m__io, std::string("/types/count/seq/15")); + } + if (!(m_accent_velo <= 127)) { + throw kaitai::validation_greater_than_error(127, m_accent_velo, m__io, std::string("/types/count/seq/15")); + } + if (!(m_normal_velo >= 1)) { + throw kaitai::validation_less_than_error(1, m_normal_velo, m__io, std::string("/types/count/seq/16")); + } + if (!(m_normal_velo <= 127)) { + throw kaitai::validation_greater_than_error(127, m_normal_velo, m__io, std::string("/types/count/seq/16")); + } + m__dirty = false; +} + +mpc2000xl_all_t::count_t::~count_t() {} + +mpc2000xl_all_t::defaults_t::defaults_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::defaults_t::_read() { + m_sequence_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(16), "ASCII"); + m__unnamed1 = m__io->read_bytes(6); + m_tempo = m__io->read_u2le(); + m_numerator = m__io->read_u1(); + m_denominator = m__io->read_u1(); + m_bar_count = m__io->read_u2le(); + m_tick_count = m__io->read_u2le(); + m_unknown1 = std::unique_ptr>(new std::vector()); + const int l_unknown1 = 4; + for (int i = 0; i < l_unknown1; i++) { + m_unknown1->push_back(std::move(m__io->read_u4le())); + } + m_unknown2 = m__io->read_bytes(74); + m_device_names = std::unique_ptr>(new std::vector()); + const int l_device_names = 33; + for (int i = 0; i < l_device_names; i++) { + m_device_names->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(8), "ASCII"))); + } + m_track_names = std::unique_ptr>(new std::vector()); + const int l_track_names = 64; + for (int i = 0; i < l_track_names; i++) { + m_track_names->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(16), "ASCII"))); + } + m_devices = std::unique_ptr>(new std::vector()); + const int l_devices = 64; + for (int i = 0; i < l_devices; i++) { + m_devices->push_back(std::move(m__io->read_u1())); + } + m_buses = std::unique_ptr>(new std::vector()); + const int l_buses = 64; + for (int i = 0; i < l_buses; i++) { + m_buses->push_back(std::move(static_cast(m__io->read_u1()))); + } + m_programs = std::unique_ptr>(new std::vector()); + const int l_programs = 64; + for (int i = 0; i < l_programs; i++) { + m_programs->push_back(std::move(m__io->read_u1())); + } + m_track_velocities = std::unique_ptr>(new std::vector()); + const int l_track_velocities = 64; + for (int i = 0; i < l_track_velocities; i++) { + m_track_velocities->push_back(std::move(m__io->read_u1())); + } + m_track_statuses = std::unique_ptr>>(new std::vector>()); + const int l_track_statuses = 64; + for (int i = 0; i < l_track_statuses; i++) { + std::unique_ptr _t_track_statuses = std::unique_ptr(new track_status_t(m__io, this, m__root)); + try { + _t_track_statuses->_read(); + } catch(...) { + m_track_statuses->push_back(std::move(_t_track_statuses)); + throw; + } + m_track_statuses->push_back(std::move(_t_track_statuses)); + } + m__unnamed16 = m__io->read_bytes(64); + m__dirty = false; +} + +void mpc2000xl_all_t::defaults_t::_fetch_instances() { + for (std::size_t i = 0; i < m_unknown1->size(); ++i) { + } + for (std::size_t i = 0; i < m_device_names->size(); ++i) { + } + for (std::size_t i = 0; i < m_track_names->size(); ++i) { + } + for (std::size_t i = 0; i < m_devices->size(); ++i) { + } + for (std::size_t i = 0; i < m_buses->size(); ++i) { + } + for (std::size_t i = 0; i < m_programs->size(); ++i) { + } + for (std::size_t i = 0; i < m_track_velocities->size(); ++i) { + } + for (std::size_t i = 0; i < m_track_statuses->size(); ++i) { + m_track_statuses->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::defaults_t::_write() { + m__io->write_bytes(m_sequence_name); + m__io->write_bytes(m__unnamed1); + m__io->write_u2le(m_tempo); + m__io->write_u1(m_numerator); + m__io->write_u1(m_denominator); + m__io->write_u2le(m_bar_count); + m__io->write_u2le(m_tick_count); + if (m_unknown1 == nullptr) { + throw std::runtime_error("/types/defaults/seq/7: repeated field is not set"); + } + for (std::vector::const_iterator it = m_unknown1->begin(); it != m_unknown1->end(); ++it) { + m__io->write_u4le((*it)); + } + m__io->write_bytes(m_unknown2); + if (m_device_names == nullptr) { + throw std::runtime_error("/types/defaults/seq/9: repeated field is not set"); + } + for (std::vector::const_iterator it = m_device_names->begin(); it != m_device_names->end(); ++it) { + m__io->write_bytes((*it)); + } + if (m_track_names == nullptr) { + throw std::runtime_error("/types/defaults/seq/10: repeated field is not set"); + } + for (std::vector::const_iterator it = m_track_names->begin(); it != m_track_names->end(); ++it) { + m__io->write_bytes((*it)); + } + if (m_devices == nullptr) { + throw std::runtime_error("/types/defaults/seq/11: repeated field is not set"); + } + for (std::vector::const_iterator it = m_devices->begin(); it != m_devices->end(); ++it) { + m__io->write_u1((*it)); + } + if (m_buses == nullptr) { + throw std::runtime_error("/types/defaults/seq/12: repeated field is not set"); + } + for (std::vector::const_iterator it = m_buses->begin(); it != m_buses->end(); ++it) { + m__io->write_u1(static_cast((*it))); + } + if (m_programs == nullptr) { + throw std::runtime_error("/types/defaults/seq/13: repeated field is not set"); + } + for (std::vector::const_iterator it = m_programs->begin(); it != m_programs->end(); ++it) { + m__io->write_u1((*it)); + } + if (m_track_velocities == nullptr) { + throw std::runtime_error("/types/defaults/seq/14: repeated field is not set"); + } + for (std::vector::const_iterator it = m_track_velocities->begin(); it != m_track_velocities->end(); ++it) { + m__io->write_u1((*it)); + } + if (m_track_statuses == nullptr) { + throw std::runtime_error("/types/defaults/seq/15: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_track_statuses->begin(); it != m_track_statuses->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/defaults/seq/15: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed16); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::defaults_t::_check() { + if (m_sequence_name.size() != static_cast(16)) { + throw std::runtime_error("/types/defaults/seq/0: size mismatch"); + } + if (m__unnamed1.size() != static_cast(6)) { + throw std::runtime_error("/types/defaults/seq/1: size mismatch"); + } + if (m_unknown1 == nullptr) { + throw std::runtime_error("/types/defaults/seq/7: repeated field is not set"); + } + if (m_unknown1->size() != static_cast(4)) { + throw std::runtime_error("/types/defaults/seq/7: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_unknown1->begin(); it != m_unknown1->end(); ++it) { + } + if (m_unknown2.size() != static_cast(74)) { + throw std::runtime_error("/types/defaults/seq/8: size mismatch"); + } + if (m_device_names == nullptr) { + throw std::runtime_error("/types/defaults/seq/9: repeated field is not set"); + } + if (m_device_names->size() != static_cast(33)) { + throw std::runtime_error("/types/defaults/seq/9: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_device_names->begin(); it != m_device_names->end(); ++it) { + if ((*it).size() != static_cast(8)) { + throw std::runtime_error("/types/defaults/seq/9: size mismatch"); + } + } + if (m_track_names == nullptr) { + throw std::runtime_error("/types/defaults/seq/10: repeated field is not set"); + } + if (m_track_names->size() != static_cast(64)) { + throw std::runtime_error("/types/defaults/seq/10: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_track_names->begin(); it != m_track_names->end(); ++it) { + if ((*it).size() != static_cast(16)) { + throw std::runtime_error("/types/defaults/seq/10: size mismatch"); + } + } + if (m_devices == nullptr) { + throw std::runtime_error("/types/defaults/seq/11: repeated field is not set"); + } + if (m_devices->size() != static_cast(64)) { + throw std::runtime_error("/types/defaults/seq/11: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_devices->begin(); it != m_devices->end(); ++it) { + } + if (m_buses == nullptr) { + throw std::runtime_error("/types/defaults/seq/12: repeated field is not set"); + } + if (m_buses->size() != static_cast(64)) { + throw std::runtime_error("/types/defaults/seq/12: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_buses->begin(); it != m_buses->end(); ++it) { + } + if (m_programs == nullptr) { + throw std::runtime_error("/types/defaults/seq/13: repeated field is not set"); + } + if (m_programs->size() != static_cast(64)) { + throw std::runtime_error("/types/defaults/seq/13: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_programs->begin(); it != m_programs->end(); ++it) { + } + if (m_track_velocities == nullptr) { + throw std::runtime_error("/types/defaults/seq/14: repeated field is not set"); + } + if (m_track_velocities->size() != static_cast(64)) { + throw std::runtime_error("/types/defaults/seq/14: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_track_velocities->begin(); it != m_track_velocities->end(); ++it) { + } + if (m_track_statuses == nullptr) { + throw std::runtime_error("/types/defaults/seq/15: repeated field is not set"); + } + if (m_track_statuses->size() != static_cast(64)) { + throw std::runtime_error("/types/defaults/seq/15: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_track_statuses->begin(); it != m_track_statuses->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/defaults/seq/15: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed16.size() != static_cast(64)) { + throw std::runtime_error("/types/defaults/seq/16: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::defaults_t::~defaults_t() {} + +mpc2000xl_all_t::event_t::event_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; + n_duration_bits_1 = true; + n_track = true; + n_duration_bits_2 = true; + n_id = true; + n_terminator_pad = true; + n_terminator = true; +} + +void mpc2000xl_all_t::event_t::_read() { + m_tick = m__io->read_bits_int_le(20); + n_duration_bits_1 = true; + if (tick() < 1048575) { + n_duration_bits_1 = false; + m_duration_bits_1 = m__io->read_bits_int_le(4); + } + n_track = true; + if (tick() < 1048575) { + n_track = false; + m_track = m__io->read_bits_int_le(6); + } + n_duration_bits_2 = true; + if (tick() < 1048575) { + n_duration_bits_2 = false; + m_duration_bits_2 = m__io->read_bits_int_le(2); + } + n_id = true; + if (tick() < 1048575) { + n_id = false; + m_id = m__io->read_u1(); + } + n_terminator_pad = true; + if (tick() >= 1048575) { + n_terminator_pad = false; + m_terminator_pad = m__io->read_bits_int_le(4); + } + if ( ((tick() < 1048575) && (id() <= 127)) ) { + m_note_event = std::unique_ptr(new note_event_t(m__io, this, m__root)); + m_note_event->_read(); + } + if ( ((tick() < 1048575) && (id() == 224)) ) { + m_pitch_bend = std::unique_ptr(new pitch_bend_event_t(m__io, this, m__root)); + m_pitch_bend->_read(); + } + if ( ((tick() < 1048575) && (id() == 176)) ) { + m_control_change = std::unique_ptr(new control_change_event_t(m__io, this, m__root)); + m_control_change->_read(); + } + if ( ((tick() < 1048575) && (id() == 192)) ) { + m_program_change = std::unique_ptr(new program_change_event_t(m__io, this, m__root)); + m_program_change->_read(); + } + if ( ((tick() < 1048575) && (id() == 208)) ) { + m_ch_pressure = std::unique_ptr(new ch_pressure_event_t(m__io, this, m__root)); + m_ch_pressure->_read(); + } + if ( ((tick() < 1048575) && (id() == 160)) ) { + m_poly_pressure = std::unique_ptr(new poly_pressure_event_t(m__io, this, m__root)); + m_poly_pressure->_read(); + } + if ( ((tick() < 1048575) && (id() == 240)) ) { + m_exclusive = std::unique_ptr(new exclusive_event_t(m__io, this, m__root)); + m_exclusive->_read(); + } + n_terminator = true; + if (tick() >= 1048575) { + n_terminator = false; + m_terminator = m__io->read_bytes(5); + } + m__dirty = false; +} + +void mpc2000xl_all_t::event_t::_fetch_instances() { + n_duration_bits_1 = true; + if (tick() < 1048575) { + n_duration_bits_1 = false; + } + n_track = true; + if (tick() < 1048575) { + n_track = false; + } + n_duration_bits_2 = true; + if (tick() < 1048575) { + n_duration_bits_2 = false; + } + n_id = true; + if (tick() < 1048575) { + n_id = false; + } + n_terminator_pad = true; + if (tick() >= 1048575) { + n_terminator_pad = false; + } + if ( ((tick() < 1048575) && (id() <= 127)) ) { + m_note_event.get()->_fetch_instances(); + } + if ( ((tick() < 1048575) && (id() == 224)) ) { + m_pitch_bend.get()->_fetch_instances(); + } + if ( ((tick() < 1048575) && (id() == 176)) ) { + m_control_change.get()->_fetch_instances(); + } + if ( ((tick() < 1048575) && (id() == 192)) ) { + m_program_change.get()->_fetch_instances(); + } + if ( ((tick() < 1048575) && (id() == 208)) ) { + m_ch_pressure.get()->_fetch_instances(); + } + if ( ((tick() < 1048575) && (id() == 160)) ) { + m_poly_pressure.get()->_fetch_instances(); + } + if ( ((tick() < 1048575) && (id() == 240)) ) { + m_exclusive.get()->_fetch_instances(); + } + n_terminator = true; + if (tick() >= 1048575) { + n_terminator = false; + } +} + +void mpc2000xl_all_t::event_t::_write() { + m__io->write_bits_int_le(20, m_tick); + if (tick() < 1048575) { + m__io->write_bits_int_le(4, m_duration_bits_1); + } + if (tick() < 1048575) { + m__io->write_bits_int_le(6, m_track); + } + if (tick() < 1048575) { + m__io->write_bits_int_le(2, m_duration_bits_2); + } + if (tick() < 1048575) { + m__io->write_u1(m_id); + } + if (tick() >= 1048575) { + m__io->write_bits_int_le(4, m_terminator_pad); + } + if ( ((tick() < 1048575) && (id() <= 127)) ) { + if (m_note_event.get() == nullptr) { + throw std::runtime_error("/types/event/seq/6: nested object is not set"); + } + m_note_event.get()->_set_io(m__io); + m_note_event.get()->_write(); + } + if ( ((tick() < 1048575) && (id() == 224)) ) { + if (m_pitch_bend.get() == nullptr) { + throw std::runtime_error("/types/event/seq/7: nested object is not set"); + } + m_pitch_bend.get()->_set_io(m__io); + m_pitch_bend.get()->_write(); + } + if ( ((tick() < 1048575) && (id() == 176)) ) { + if (m_control_change.get() == nullptr) { + throw std::runtime_error("/types/event/seq/8: nested object is not set"); + } + m_control_change.get()->_set_io(m__io); + m_control_change.get()->_write(); + } + if ( ((tick() < 1048575) && (id() == 192)) ) { + if (m_program_change.get() == nullptr) { + throw std::runtime_error("/types/event/seq/9: nested object is not set"); + } + m_program_change.get()->_set_io(m__io); + m_program_change.get()->_write(); + } + if ( ((tick() < 1048575) && (id() == 208)) ) { + if (m_ch_pressure.get() == nullptr) { + throw std::runtime_error("/types/event/seq/10: nested object is not set"); + } + m_ch_pressure.get()->_set_io(m__io); + m_ch_pressure.get()->_write(); + } + if ( ((tick() < 1048575) && (id() == 160)) ) { + if (m_poly_pressure.get() == nullptr) { + throw std::runtime_error("/types/event/seq/11: nested object is not set"); + } + m_poly_pressure.get()->_set_io(m__io); + m_poly_pressure.get()->_write(); + } + if ( ((tick() < 1048575) && (id() == 240)) ) { + if (m_exclusive.get() == nullptr) { + throw std::runtime_error("/types/event/seq/12: nested object is not set"); + } + m_exclusive.get()->_set_io(m__io); + m_exclusive.get()->_write(); + } + if (tick() >= 1048575) { + m__io->write_bytes(m_terminator); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::event_t::_check() { + if (tick() < 1048575) { + if (!(!n_duration_bits_1)) { + throw std::runtime_error("/types/event/seq/1: conditional field is not set"); + } + } else { + if (!n_duration_bits_1) { + throw std::runtime_error("/types/event/seq/1: conditional field should be absent"); + } + } + if (tick() < 1048575) { + if (!(!n_track)) { + throw std::runtime_error("/types/event/seq/2: conditional field is not set"); + } + } else { + if (!n_track) { + throw std::runtime_error("/types/event/seq/2: conditional field should be absent"); + } + } + if (tick() < 1048575) { + if (!(!n_duration_bits_2)) { + throw std::runtime_error("/types/event/seq/3: conditional field is not set"); + } + } else { + if (!n_duration_bits_2) { + throw std::runtime_error("/types/event/seq/3: conditional field should be absent"); + } + } + if (tick() < 1048575) { + if (!(!n_id)) { + throw std::runtime_error("/types/event/seq/4: conditional field is not set"); + } + } else { + if (!n_id) { + throw std::runtime_error("/types/event/seq/4: conditional field should be absent"); + } + } + if (tick() >= 1048575) { + if (!(!n_terminator_pad)) { + throw std::runtime_error("/types/event/seq/5: conditional field is not set"); + } + } else { + if (!n_terminator_pad) { + throw std::runtime_error("/types/event/seq/5: conditional field should be absent"); + } + } + if ( ((tick() < 1048575) && (id() <= 127)) ) { + if (!(m_note_event.get() != nullptr)) { + throw std::runtime_error("/types/event/seq/6: conditional field is not set"); + } + if (m_note_event.get() == nullptr) { + throw std::runtime_error("/types/event/seq/6: nested object is not set"); + } + m_note_event.get()->_set_io(m__io); + m_note_event.get()->_check(); + } else { + if (m_note_event.get() != nullptr) { + throw std::runtime_error("/types/event/seq/6: conditional field should be absent"); + } + } + if ( ((tick() < 1048575) && (id() == 224)) ) { + if (!(m_pitch_bend.get() != nullptr)) { + throw std::runtime_error("/types/event/seq/7: conditional field is not set"); + } + if (m_pitch_bend.get() == nullptr) { + throw std::runtime_error("/types/event/seq/7: nested object is not set"); + } + m_pitch_bend.get()->_set_io(m__io); + m_pitch_bend.get()->_check(); + } else { + if (m_pitch_bend.get() != nullptr) { + throw std::runtime_error("/types/event/seq/7: conditional field should be absent"); + } + } + if ( ((tick() < 1048575) && (id() == 176)) ) { + if (!(m_control_change.get() != nullptr)) { + throw std::runtime_error("/types/event/seq/8: conditional field is not set"); + } + if (m_control_change.get() == nullptr) { + throw std::runtime_error("/types/event/seq/8: nested object is not set"); + } + m_control_change.get()->_set_io(m__io); + m_control_change.get()->_check(); + } else { + if (m_control_change.get() != nullptr) { + throw std::runtime_error("/types/event/seq/8: conditional field should be absent"); + } + } + if ( ((tick() < 1048575) && (id() == 192)) ) { + if (!(m_program_change.get() != nullptr)) { + throw std::runtime_error("/types/event/seq/9: conditional field is not set"); + } + if (m_program_change.get() == nullptr) { + throw std::runtime_error("/types/event/seq/9: nested object is not set"); + } + m_program_change.get()->_set_io(m__io); + m_program_change.get()->_check(); + } else { + if (m_program_change.get() != nullptr) { + throw std::runtime_error("/types/event/seq/9: conditional field should be absent"); + } + } + if ( ((tick() < 1048575) && (id() == 208)) ) { + if (!(m_ch_pressure.get() != nullptr)) { + throw std::runtime_error("/types/event/seq/10: conditional field is not set"); + } + if (m_ch_pressure.get() == nullptr) { + throw std::runtime_error("/types/event/seq/10: nested object is not set"); + } + m_ch_pressure.get()->_set_io(m__io); + m_ch_pressure.get()->_check(); + } else { + if (m_ch_pressure.get() != nullptr) { + throw std::runtime_error("/types/event/seq/10: conditional field should be absent"); + } + } + if ( ((tick() < 1048575) && (id() == 160)) ) { + if (!(m_poly_pressure.get() != nullptr)) { + throw std::runtime_error("/types/event/seq/11: conditional field is not set"); + } + if (m_poly_pressure.get() == nullptr) { + throw std::runtime_error("/types/event/seq/11: nested object is not set"); + } + m_poly_pressure.get()->_set_io(m__io); + m_poly_pressure.get()->_check(); + } else { + if (m_poly_pressure.get() != nullptr) { + throw std::runtime_error("/types/event/seq/11: conditional field should be absent"); + } + } + if ( ((tick() < 1048575) && (id() == 240)) ) { + if (!(m_exclusive.get() != nullptr)) { + throw std::runtime_error("/types/event/seq/12: conditional field is not set"); + } + if (m_exclusive.get() == nullptr) { + throw std::runtime_error("/types/event/seq/12: nested object is not set"); + } + m_exclusive.get()->_set_io(m__io); + m_exclusive.get()->_check(); + } else { + if (m_exclusive.get() != nullptr) { + throw std::runtime_error("/types/event/seq/12: conditional field should be absent"); + } + } + if (tick() >= 1048575) { + if (!(!n_terminator)) { + throw std::runtime_error("/types/event/seq/13: conditional field is not set"); + } + if (m_terminator.size() != static_cast(5)) { + throw std::runtime_error("/types/event/seq/13: size mismatch"); + } + } else { + if (!n_terminator) { + throw std::runtime_error("/types/event/seq/13: conditional field should be absent"); + } + } + m__dirty = false; +} + +mpc2000xl_all_t::event_t::~event_t() {} + +mpc2000xl_all_t::exclusive_event_t::exclusive_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::exclusive_event_t::_read() { + m__unnamed0 = m__io->read_bytes(3); + m_bytes = m__io->read_bytes(2); + if (bytes() == std::string("\xF0\x47", 2)) { + m_mixer = std::unique_ptr(new mixer_event_t(m__io, this, m__root)); + m_mixer->_read(); + } + m__unnamed3 = m__io->read_bytes(14); + m__dirty = false; +} + +void mpc2000xl_all_t::exclusive_event_t::_fetch_instances() { + if (bytes() == std::string("\xF0\x47", 2)) { + m_mixer.get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::exclusive_event_t::_write() { + m__io->write_bytes(m__unnamed0); + m__io->write_bytes(m_bytes); + if (bytes() == std::string("\xF0\x47", 2)) { + if (m_mixer.get() == nullptr) { + throw std::runtime_error("/types/exclusive_event/seq/2: nested object is not set"); + } + m_mixer.get()->_set_io(m__io); + m_mixer.get()->_write(); + } + m__io->write_bytes(m__unnamed3); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::exclusive_event_t::_check() { + if (m__unnamed0.size() != static_cast(3)) { + throw std::runtime_error("/types/exclusive_event/seq/0: size mismatch"); + } + if (m_bytes.size() != static_cast(2)) { + throw std::runtime_error("/types/exclusive_event/seq/1: size mismatch"); + } + if (bytes() == std::string("\xF0\x47", 2)) { + if (!(m_mixer.get() != nullptr)) { + throw std::runtime_error("/types/exclusive_event/seq/2: conditional field is not set"); + } + if (m_mixer.get() == nullptr) { + throw std::runtime_error("/types/exclusive_event/seq/2: nested object is not set"); + } + m_mixer.get()->_set_io(m__io); + m_mixer.get()->_check(); + } else { + if (m_mixer.get() != nullptr) { + throw std::runtime_error("/types/exclusive_event/seq/2: conditional field should be absent"); + } + } + if (m__unnamed3.size() != static_cast(14)) { + throw std::runtime_error("/types/exclusive_event/seq/3: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::exclusive_event_t::~exclusive_event_t() {} + +mpc2000xl_all_t::location_t::location_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; + f_display_value = false; +} + +void mpc2000xl_all_t::location_t::_read() { + m_bar = m__io->read_u2le(); + m_beat = m__io->read_u1(); + m_clock = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_all_t::location_t::_fetch_instances() { +} + +void mpc2000xl_all_t::location_t::_write() { + m__io->write_u2le(m_bar); + m__io->write_u1(m_beat); + m__io->write_u1(m_clock); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::location_t::_check() { + m__dirty = false; +} + +mpc2000xl_all_t::location_t::~location_t() {} + +std::string mpc2000xl_all_t::location_t::display_value() { + if (f_display_value) + return m_display_value; + f_display_value = true; + m_display_value = (((((bar() > 98) ? (kaitai::kstream::to_string(bar() + 1)) : (((bar() > 8) ? (std::string("0") + kaitai::kstream::to_string(bar() + 1)) : (std::string("00") + kaitai::kstream::to_string(bar() + 1))))) + std::string(".")) + ((beat() > 8) ? (kaitai::kstream::to_string(beat() + 1)) : (std::string("0") + kaitai::kstream::to_string(beat() + 1)))) + std::string(".")) + ((clock() > 9) ? (kaitai::kstream::to_string(clock())) : (std::string("0") + kaitai::kstream::to_string(clock()))); + return m_display_value; +} + +mpc2000xl_all_t::midi_input_t::midi_input_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::midi_input_t::_read() { + m_receive_channel = static_cast(m__io->read_u1()); + m_sustain_pedal_to_duration = m__io->read_bits_int_le(1); + m__unnamed2 = m__io->read_bits_int_le(7); + m_filter_enabled = m__io->read_bits_int_le(1); + m__unnamed4 = m__io->read_bits_int_le(7); + m_filter_type = static_cast(m__io->read_u1()); + m_multi_rec_enabled = m__io->read_bits_int_le(1); + m__unnamed7 = m__io->read_bits_int_le(7); + m_multi_rec_destination_tracks = std::unique_ptr>(new std::vector()); + const int l_multi_rec_destination_tracks = 34; + for (int i = 0; i < l_multi_rec_destination_tracks; i++) { + m_multi_rec_destination_tracks->push_back(std::move(m__io->read_u1())); + } + m_note_pass_enabled = m__io->read_bits_int_le(1); + m__unnamed10 = m__io->read_bits_int_le(7); + m_pitch_bend_pass_enabled = m__io->read_bits_int_le(1); + m__unnamed12 = m__io->read_bits_int_le(7); + m_pgm_change_pass_enabled = m__io->read_bits_int_le(1); + m__unnamed14 = m__io->read_bits_int_le(7); + m_ch_pressure_pass_enabled = m__io->read_bits_int_le(1); + m__unnamed16 = m__io->read_bits_int_le(7); + m_poly_pressure_pass_enabled = m__io->read_bits_int_le(1); + m__unnamed18 = m__io->read_bits_int_le(7); + m_exclusive_pass_enabled = m__io->read_bits_int_le(1); + m__unnamed20 = m__io->read_bits_int_le(7); + m_cc_pass_enabled = std::unique_ptr>(new std::vector()); + const int l_cc_pass_enabled = 128; + for (int i = 0; i < l_cc_pass_enabled; i++) { + m_cc_pass_enabled->push_back(std::move(m__io->read_bits_int_le(1))); + } + m__dirty = false; +} + +void mpc2000xl_all_t::midi_input_t::_fetch_instances() { + for (std::size_t i = 0; i < m_multi_rec_destination_tracks->size(); ++i) { + } + for (std::size_t i = 0; i < m_cc_pass_enabled->size(); ++i) { + } +} + +void mpc2000xl_all_t::midi_input_t::_write() { + m__io->write_u1(static_cast(m_receive_channel)); + m__io->write_bits_int_le(1, ((m_sustain_pedal_to_duration) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed2); + m__io->write_bits_int_le(1, ((m_filter_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed4); + m__io->write_u1(static_cast(m_filter_type)); + m__io->write_bits_int_le(1, ((m_multi_rec_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed7); + if (m_multi_rec_destination_tracks == nullptr) { + throw std::runtime_error("/types/midi_input/seq/8: repeated field is not set"); + } + for (std::vector::const_iterator it = m_multi_rec_destination_tracks->begin(); it != m_multi_rec_destination_tracks->end(); ++it) { + m__io->write_u1((*it)); + } + m__io->write_bits_int_le(1, ((m_note_pass_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed10); + m__io->write_bits_int_le(1, ((m_pitch_bend_pass_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed12); + m__io->write_bits_int_le(1, ((m_pgm_change_pass_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed14); + m__io->write_bits_int_le(1, ((m_ch_pressure_pass_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed16); + m__io->write_bits_int_le(1, ((m_poly_pressure_pass_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed18); + m__io->write_bits_int_le(1, ((m_exclusive_pass_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed20); + if (m_cc_pass_enabled == nullptr) { + throw std::runtime_error("/types/midi_input/seq/21: repeated field is not set"); + } + for (std::vector::const_iterator it = m_cc_pass_enabled->begin(); it != m_cc_pass_enabled->end(); ++it) { + m__io->write_bits_int_le(1, (((*it)) ? 1 : 0)); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::midi_input_t::_check() { + if (m_multi_rec_destination_tracks == nullptr) { + throw std::runtime_error("/types/midi_input/seq/8: repeated field is not set"); + } + if (m_multi_rec_destination_tracks->size() != static_cast(34)) { + throw std::runtime_error("/types/midi_input/seq/8: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_multi_rec_destination_tracks->begin(); it != m_multi_rec_destination_tracks->end(); ++it) { + } + if (m_cc_pass_enabled == nullptr) { + throw std::runtime_error("/types/midi_input/seq/21: repeated field is not set"); + } + if (m_cc_pass_enabled->size() != static_cast(128)) { + throw std::runtime_error("/types/midi_input/seq/21: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_cc_pass_enabled->begin(); it != m_cc_pass_enabled->end(); ++it) { + } + m__dirty = false; +} + +mpc2000xl_all_t::midi_input_t::~midi_input_t() {} + +mpc2000xl_all_t::midi_output_t::midi_output_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::midi_output_t::_read() { + m_soft_thru_mode = static_cast(m__io->read_u1()); + m__dirty = false; +} + +void mpc2000xl_all_t::midi_output_t::_fetch_instances() { +} + +void mpc2000xl_all_t::midi_output_t::_write() { + m__io->write_u1(static_cast(m_soft_thru_mode)); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::midi_output_t::_check() { + m__dirty = false; +} + +mpc2000xl_all_t::midi_output_t::~midi_output_t() {} + +mpc2000xl_all_t::midi_switch_t::midi_switch_t(kaitai::kstream* p__io, mpc2000xl_all_t::misc_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::midi_switch_t::_read() { + m_controller = m__io->read_u1(); + if (!(m_controller >= 0)) { + throw kaitai::validation_less_than_error(0, m_controller, m__io, std::string("/types/midi_switch/seq/0")); + } + if (!(m_controller <= 127)) { + throw kaitai::validation_greater_than_error(127, m_controller, m__io, std::string("/types/midi_switch/seq/0")); + } + m_function = static_cast(m__io->read_u1()); + m__dirty = false; +} + +void mpc2000xl_all_t::midi_switch_t::_fetch_instances() { +} + +void mpc2000xl_all_t::midi_switch_t::_write() { + m__io->write_u1(m_controller); + m__io->write_u1(static_cast(m_function)); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::midi_switch_t::_check() { + if (!(m_controller >= 0)) { + throw kaitai::validation_less_than_error(0, m_controller, m__io, std::string("/types/midi_switch/seq/0")); + } + if (!(m_controller <= 127)) { + throw kaitai::validation_greater_than_error(127, m_controller, m__io, std::string("/types/midi_switch/seq/0")); + } + m__dirty = false; +} + +mpc2000xl_all_t::midi_switch_t::~midi_switch_t() {} + +mpc2000xl_all_t::midi_sync_t::midi_sync_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::midi_sync_t::_read() { + m_in_mode = static_cast(m__io->read_u1()); + m_out_mode = static_cast(m__io->read_u1()); + m_shift_early = m__io->read_u1(); + if (!(m_shift_early >= 0)) { + throw kaitai::validation_less_than_error(0, m_shift_early, m__io, std::string("/types/midi_sync/seq/2")); + } + if (!(m_shift_early <= 20)) { + throw kaitai::validation_greater_than_error(20, m_shift_early, m__io, std::string("/types/midi_sync/seq/2")); + } + m_send_mmc_enabled = m__io->read_bits_int_le(1); + m__unnamed4 = m__io->read_bits_int_le(7); + m_frame_rate = static_cast(m__io->read_u1()); + m_input = m__io->read_u1(); + m_output = static_cast(m__io->read_u1()); + m__dirty = false; +} + +void mpc2000xl_all_t::midi_sync_t::_fetch_instances() { +} + +void mpc2000xl_all_t::midi_sync_t::_write() { + m__io->write_u1(static_cast(m_in_mode)); + m__io->write_u1(static_cast(m_out_mode)); + m__io->write_u1(m_shift_early); + m__io->write_bits_int_le(1, ((m_send_mmc_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed4); + m__io->write_u1(static_cast(m_frame_rate)); + m__io->write_u1(m_input); + m__io->write_u1(static_cast(m_output)); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::midi_sync_t::_check() { + if (!(m_shift_early >= 0)) { + throw kaitai::validation_less_than_error(0, m_shift_early, m__io, std::string("/types/midi_sync/seq/2")); + } + if (!(m_shift_early <= 20)) { + throw kaitai::validation_greater_than_error(20, m_shift_early, m__io, std::string("/types/midi_sync/seq/2")); + } + m__dirty = false; +} + +mpc2000xl_all_t::midi_sync_t::~midi_sync_t() {} + +mpc2000xl_all_t::misc_t::misc_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::misc_t::_read() { + m_tap_averaging = static_cast(m__io->read_u1()); + m_midi_sync_in_receive_mmc_enabled = m__io->read_bits_int_le(1); + m_midi_switch = std::unique_ptr>>(new std::vector>()); + const int l_midi_switch = 4; + for (int i = 0; i < l_midi_switch; i++) { + std::unique_ptr _t_midi_switch = std::unique_ptr(new midi_switch_t(m__io, this, m__root)); + try { + _t_midi_switch->_read(); + } catch(...) { + m_midi_switch->push_back(std::move(_t_midi_switch)); + throw; + } + m_midi_switch->push_back(std::move(_t_midi_switch)); + } + m__dirty = false; +} + +void mpc2000xl_all_t::misc_t::_fetch_instances() { + for (std::size_t i = 0; i < m_midi_switch->size(); ++i) { + m_midi_switch->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::misc_t::_write() { + m__io->write_u1(static_cast(m_tap_averaging)); + m__io->write_bits_int_le(1, ((m_midi_sync_in_receive_mmc_enabled) ? 1 : 0)); + if (m_midi_switch == nullptr) { + throw std::runtime_error("/types/misc/seq/2: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_midi_switch->begin(); it != m_midi_switch->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/misc/seq/2: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::misc_t::_check() { + if (m_midi_switch == nullptr) { + throw std::runtime_error("/types/misc/seq/2: repeated field is not set"); + } + if (m_midi_switch->size() != static_cast(4)) { + throw std::runtime_error("/types/misc/seq/2: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_midi_switch->begin(); it != m_midi_switch->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/misc/seq/2: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + m__dirty = false; +} + +mpc2000xl_all_t::misc_t::~misc_t() {} + +mpc2000xl_all_t::mixer_event_t::mixer_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::exclusive_event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::mixer_event_t::_read() { + m__unnamed0 = m__io->read_bytes(3); + m_param = static_cast(m__io->read_u1()); + m_pad_index = m__io->read_u1(); + m_value = m__io->read_u1(); + if (!(m_value >= 0)) { + throw kaitai::validation_less_than_error(0, m_value, m__io, std::string("/types/mixer_event/seq/3")); + } + if (!(m_value <= 100)) { + throw kaitai::validation_greater_than_error(100, m_value, m__io, std::string("/types/mixer_event/seq/3")); + } + m__unnamed4 = m__io->read_bytes(2); + m__dirty = false; +} + +void mpc2000xl_all_t::mixer_event_t::_fetch_instances() { +} + +void mpc2000xl_all_t::mixer_event_t::_write() { + m__io->write_bytes(m__unnamed0); + m__io->write_u1(static_cast(m_param)); + m__io->write_u1(m_pad_index); + m__io->write_u1(m_value); + m__io->write_bytes(m__unnamed4); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::mixer_event_t::_check() { + if (m__unnamed0.size() != static_cast(3)) { + throw std::runtime_error("/types/mixer_event/seq/0: size mismatch"); + } + if (!(m_value >= 0)) { + throw kaitai::validation_less_than_error(0, m_value, m__io, std::string("/types/mixer_event/seq/3")); + } + if (!(m_value <= 100)) { + throw kaitai::validation_greater_than_error(100, m_value, m__io, std::string("/types/mixer_event/seq/3")); + } + if (m__unnamed4.size() != static_cast(2)) { + throw std::runtime_error("/types/mixer_event/seq/4: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::mixer_event_t::~mixer_event_t() {} +const std::set mpc2000xl_all_t::note_event_t::_values_note_variation_type_t{ + mpc2000xl_all_t::note_event_t::NOTE_VARIATION_TYPE_TUNE, + mpc2000xl_all_t::note_event_t::NOTE_VARIATION_TYPE_DECAY, + mpc2000xl_all_t::note_event_t::NOTE_VARIATION_TYPE_ATTACK, + mpc2000xl_all_t::note_event_t::NOTE_VARIATION_TYPE_FILTER, +}; +bool mpc2000xl_all_t::note_event_t::_is_defined_note_variation_type_t(mpc2000xl_all_t::note_event_t::note_variation_type_t v) { + return mpc2000xl_all_t::note_event_t::_values_note_variation_type_t.find(v) != mpc2000xl_all_t::note_event_t::_values_note_variation_type_t.end(); +} + +mpc2000xl_all_t::note_event_t::note_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; + f_duration = false; + f_note = false; + f_variation_type = false; +} + +void mpc2000xl_all_t::note_event_t::_read() { + m_duration_bits_3 = m__io->read_u1(); + m_velocity = m__io->read_bits_int_le(7); + m_variation_type_bit_1 = m__io->read_bits_int_le(1); + m_variation_value = m__io->read_bits_int_le(7); + m_variation_type_bit_2 = m__io->read_bits_int_le(1); + m__dirty = false; +} + +void mpc2000xl_all_t::note_event_t::_fetch_instances() { +} + +void mpc2000xl_all_t::note_event_t::_write() { + m__io->write_u1(m_duration_bits_3); + m__io->write_bits_int_le(7, m_velocity); + m__io->write_bits_int_le(1, ((m_variation_type_bit_1) ? 1 : 0)); + m__io->write_bits_int_le(7, m_variation_value); + m__io->write_bits_int_le(1, ((m_variation_type_bit_2) ? 1 : 0)); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::note_event_t::_check() { + m__dirty = false; +} + +mpc2000xl_all_t::note_event_t::~note_event_t() {} + +int32_t mpc2000xl_all_t::note_event_t::duration() { + if (f_duration) + return m_duration; + f_duration = true; + m_duration = ((_parent()->duration_bits_1() << 10) + (_parent()->duration_bits_2() << 8)) + duration_bits_3(); + return m_duration; +} + +uint8_t mpc2000xl_all_t::note_event_t::note() { + if (f_note) + return m_note; + f_note = true; + m_note = _parent()->id(); + return m_note; +} + +mpc2000xl_all_t::note_event_t::note_variation_type_t mpc2000xl_all_t::note_event_t::variation_type() { + if (f_variation_type) + return m_variation_type; + f_variation_type = true; + m_variation_type = static_cast(static_cast(variation_type_bit_1()) << 1 | static_cast(variation_type_bit_2())); + return m_variation_type; +} + +mpc2000xl_all_t::pitch_bend_event_t::pitch_bend_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; + f_corrected_amount = false; +} + +void mpc2000xl_all_t::pitch_bend_event_t::_read() { + m_amount_bits_1 = m__io->read_bits_int_le(8); + m_amount_bits_2 = m__io->read_bits_int_le(8); + m__unnamed2 = m__io->read_bytes(1); + m__dirty = false; +} + +void mpc2000xl_all_t::pitch_bend_event_t::_fetch_instances() { +} + +void mpc2000xl_all_t::pitch_bend_event_t::_write() { + m__io->write_bits_int_le(8, m_amount_bits_1); + m__io->write_bits_int_le(8, m_amount_bits_2); + m__io->write_bytes(m__unnamed2); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::pitch_bend_event_t::_check() { + if (m__unnamed2.size() != static_cast(1)) { + throw std::runtime_error("/types/pitch_bend_event/seq/2: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::pitch_bend_event_t::~pitch_bend_event_t() {} + +int32_t mpc2000xl_all_t::pitch_bend_event_t::corrected_amount() { + if (f_corrected_amount) + return m_corrected_amount; + f_corrected_amount = true; + m_corrected_amount = (amount_bits_1() + (amount_bits_2() << 7)) - 8192; + return m_corrected_amount; +} + +mpc2000xl_all_t::poly_pressure_event_t::poly_pressure_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::poly_pressure_event_t::_read() { + m_note = m__io->read_u1(); + if (!(m_note >= 0)) { + throw kaitai::validation_less_than_error(0, m_note, m__io, std::string("/types/poly_pressure_event/seq/0")); + } + if (!(m_note <= 127)) { + throw kaitai::validation_greater_than_error(127, m_note, m__io, std::string("/types/poly_pressure_event/seq/0")); + } + m_pressure = m__io->read_u1(); + if (!(m_pressure >= 0)) { + throw kaitai::validation_less_than_error(0, m_pressure, m__io, std::string("/types/poly_pressure_event/seq/1")); + } + if (!(m_pressure <= 127)) { + throw kaitai::validation_greater_than_error(127, m_pressure, m__io, std::string("/types/poly_pressure_event/seq/1")); + } + m__unnamed2 = m__io->read_bytes(1); + m__dirty = false; +} + +void mpc2000xl_all_t::poly_pressure_event_t::_fetch_instances() { +} + +void mpc2000xl_all_t::poly_pressure_event_t::_write() { + m__io->write_u1(m_note); + m__io->write_u1(m_pressure); + m__io->write_bytes(m__unnamed2); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::poly_pressure_event_t::_check() { + if (!(m_note >= 0)) { + throw kaitai::validation_less_than_error(0, m_note, m__io, std::string("/types/poly_pressure_event/seq/0")); + } + if (!(m_note <= 127)) { + throw kaitai::validation_greater_than_error(127, m_note, m__io, std::string("/types/poly_pressure_event/seq/0")); + } + if (!(m_pressure >= 0)) { + throw kaitai::validation_less_than_error(0, m_pressure, m__io, std::string("/types/poly_pressure_event/seq/1")); + } + if (!(m_pressure <= 127)) { + throw kaitai::validation_greater_than_error(127, m_pressure, m__io, std::string("/types/poly_pressure_event/seq/1")); + } + if (m__unnamed2.size() != static_cast(1)) { + throw std::runtime_error("/types/poly_pressure_event/seq/2: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::poly_pressure_event_t::~poly_pressure_event_t() {} + +mpc2000xl_all_t::program_change_event_t::program_change_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::program_change_event_t::_read() { + m_program = m__io->read_u1(); + if (!(m_program >= 0)) { + throw kaitai::validation_less_than_error(0, m_program, m__io, std::string("/types/program_change_event/seq/0")); + } + if (!(m_program <= 127)) { + throw kaitai::validation_greater_than_error(127, m_program, m__io, std::string("/types/program_change_event/seq/0")); + } + m__unnamed1 = m__io->read_bytes(2); + m__dirty = false; +} + +void mpc2000xl_all_t::program_change_event_t::_fetch_instances() { +} + +void mpc2000xl_all_t::program_change_event_t::_write() { + m__io->write_u1(m_program); + m__io->write_bytes(m__unnamed1); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::program_change_event_t::_check() { + if (!(m_program >= 0)) { + throw kaitai::validation_less_than_error(0, m_program, m__io, std::string("/types/program_change_event/seq/0")); + } + if (!(m_program <= 127)) { + throw kaitai::validation_greater_than_error(127, m_program, m__io, std::string("/types/program_change_event/seq/0")); + } + if (m__unnamed1.size() != static_cast(2)) { + throw std::runtime_error("/types/program_change_event/seq/1: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::program_change_event_t::~program_change_event_t() {} + +mpc2000xl_all_t::sequence_t::sequence_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; + n_name_part_2 = true; + f_name = false; +} + +void mpc2000xl_all_t::sequence_t::_read() { + m_name_part_1 = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 255), 255, false), "ASCII"); + n_name_part_2 = true; + if (name_part_1() != std::string("")) { + n_name_part_2 = false; + m_name_part_2 = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 255), 255, false), "ASCII"); + } + if (name_part_1() != std::string("")) { + m_body = std::unique_ptr(new sequence_body_t(m__io, this, m__root)); + m_body->_read(); + } + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_t::_fetch_instances() { + n_name_part_2 = true; + if (name_part_1() != std::string("")) { + n_name_part_2 = false; + } + if (name_part_1() != std::string("")) { + m_body.get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::sequence_t::_write() { + std::string _bufm_name_part_1 = m_name_part_1; + if (_bufm_name_part_1.size() < static_cast(8)) { + _bufm_name_part_1 += std::string(1, static_cast(255)); + } + if (_bufm_name_part_1.size() < static_cast(8)) { + _bufm_name_part_1.append(static_cast(8) - _bufm_name_part_1.size(), static_cast(255)); + } + m__io->write_bytes(_bufm_name_part_1); + if (name_part_1() != std::string("")) { + std::string _bufm_name_part_2 = m_name_part_2; + if (_bufm_name_part_2.size() < static_cast(8)) { + _bufm_name_part_2 += std::string(1, static_cast(255)); + } + if (_bufm_name_part_2.size() < static_cast(8)) { + _bufm_name_part_2.append(static_cast(8) - _bufm_name_part_2.size(), static_cast(255)); + } + m__io->write_bytes(_bufm_name_part_2); + } + if (name_part_1() != std::string("")) { + if (m_body.get() == nullptr) { + throw std::runtime_error("/types/sequence/seq/2: nested object is not set"); + } + m_body.get()->_set_io(m__io); + m_body.get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_t::_check() { + if (m_name_part_1.size() > static_cast(8)) { + throw std::runtime_error("/types/sequence/seq/0: size mismatch"); + } + if (m_name_part_1.find(static_cast(255)) != std::string::npos) { + throw std::runtime_error("/types/sequence/seq/0: terminator must not appear in value"); + } + if (name_part_1() != std::string("")) { + if (!(!n_name_part_2)) { + throw std::runtime_error("/types/sequence/seq/1: conditional field is not set"); + } + if (m_name_part_2.size() > static_cast(8)) { + throw std::runtime_error("/types/sequence/seq/1: size mismatch"); + } + if (m_name_part_2.find(static_cast(255)) != std::string::npos) { + throw std::runtime_error("/types/sequence/seq/1: terminator must not appear in value"); + } + } else { + if (!n_name_part_2) { + throw std::runtime_error("/types/sequence/seq/1: conditional field should be absent"); + } + } + if (name_part_1() != std::string("")) { + if (!(m_body.get() != nullptr)) { + throw std::runtime_error("/types/sequence/seq/2: conditional field is not set"); + } + if (m_body.get() == nullptr) { + throw std::runtime_error("/types/sequence/seq/2: nested object is not set"); + } + m_body.get()->_set_io(m__io); + m_body.get()->_check(); + } else { + if (m_body.get() != nullptr) { + throw std::runtime_error("/types/sequence/seq/2: conditional field should be absent"); + } + } + m__dirty = false; +} + +mpc2000xl_all_t::sequence_t::~sequence_t() {} + +std::string mpc2000xl_all_t::sequence_t::name() { + if (f_name) + return m_name; + f_name = true; + n_name = true; + if ( ((name_part_1() != std::string("")) && (name_part_2() != std::string(""))) ) { + n_name = false; + m_name = name_part_1() + name_part_2(); + } + return m_name; +} + +mpc2000xl_all_t::sequence_body_t::sequence_body_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_body_t::_read() { + m_is_used = static_cast(m__io->read_u2le()); + m_index = m__io->read_u1(); + m__unnamed2 = m__io->read_bytes(7); + m_bar_count = m__io->read_u2le(); + m_last_tick = m__io->read_u4le(); + m__unnamed5 = m__io->read_bytes(16); + m_loop_start_bar_index = m__io->read_u2le(); + m_loop_end_bar_index = m__io->read_u2le(); + m_loop_enabled = m__io->read_bits_int_le(1); + m__unnamed9 = m__io->read_bits_int_le(7); + m_start_time = std::unique_ptr(new start_time_t(m__io, this, m__root)); + m_start_time->_read(); + m__unnamed11 = m__io->read_bytes(6); + m_last_tick2 = m__io->read_u4le(); + m__unnamed13 = m__io->read_bytes(52); + m_device_names = std::unique_ptr>(new std::vector()); + const int l_device_names = 33; + for (int i = 0; i < l_device_names; i++) { + m_device_names->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(8), "ASCII"))); + } + m_tracks = std::unique_ptr(new tracks_t(m__io, this, m__root)); + m_tracks->_read(); + m__unnamed16 = m__io->read_bytes(3587); + m_bars = std::unique_ptr>>(new std::vector>()); + const int l_bars = bar_count(); + for (int i = 0; i < l_bars; i++) { + std::unique_ptr _t_bars = std::unique_ptr(new bar_t(i, m__io, this, m__root)); + try { + _t_bars->_read(); + } catch(...) { + m_bars->push_back(std::move(_t_bars)); + throw; + } + m_bars->push_back(std::move(_t_bars)); + } + m__unnamed18 = m__io->read_bytes(4 * (999 - bar_count())); + m__unnamed19 = m__io->read_bytes(865); + m_events = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + event_t* _; + do { + std::unique_ptr _t_events = std::unique_ptr(new event_t(m__io, this, m__root)); + try { + _t_events->_read(); + } catch(...) { + _ = _t_events.get(); + m_events->push_back(std::move(_t_events)); + throw; + } + _ = _t_events.get(); + m_events->push_back(std::move(_t_events)); + i++; + } while (!(_->tick() == 1048575)); + } + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_body_t::_fetch_instances() { + m_start_time.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_device_names->size(); ++i) { + } + m_tracks.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_bars->size(); ++i) { + m_bars->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_events->size(); ++i) { + m_events->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::sequence_body_t::_write() { + m__io->write_u2le(static_cast(m_is_used)); + m__io->write_u1(m_index); + m__io->write_bytes(m__unnamed2); + m__io->write_u2le(m_bar_count); + m__io->write_u4le(m_last_tick); + m__io->write_bytes(m__unnamed5); + m__io->write_u2le(m_loop_start_bar_index); + m__io->write_u2le(m_loop_end_bar_index); + m__io->write_bits_int_le(1, ((m_loop_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed9); + if (m_start_time.get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/10: nested object is not set"); + } + m_start_time.get()->_set_io(m__io); + m_start_time.get()->_write(); + m__io->write_bytes(m__unnamed11); + m__io->write_u4le(m_last_tick2); + m__io->write_bytes(m__unnamed13); + if (m_device_names == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/14: repeated field is not set"); + } + for (std::vector::const_iterator it = m_device_names->begin(); it != m_device_names->end(); ++it) { + m__io->write_bytes((*it)); + } + if (m_tracks.get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/15: nested object is not set"); + } + m_tracks.get()->_set_io(m__io); + m_tracks.get()->_write(); + m__io->write_bytes(m__unnamed16); + if (m_bars == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/17: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_bars->begin(); it != m_bars->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/17: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed18); + m__io->write_bytes(m__unnamed19); + if (m_events == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/20: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_events->begin(); it != m_events->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/20: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_body_t::_check() { + if (m__unnamed2.size() != static_cast(7)) { + throw std::runtime_error("/types/sequence_body/seq/2: size mismatch"); + } + if (m__unnamed5.size() != static_cast(16)) { + throw std::runtime_error("/types/sequence_body/seq/5: size mismatch"); + } + if (m_start_time.get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/10: nested object is not set"); + } + m_start_time.get()->_set_io(m__io); + m_start_time.get()->_check(); + if (m__unnamed11.size() != static_cast(6)) { + throw std::runtime_error("/types/sequence_body/seq/11: size mismatch"); + } + if (m__unnamed13.size() != static_cast(52)) { + throw std::runtime_error("/types/sequence_body/seq/13: size mismatch"); + } + if (m_device_names == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/14: repeated field is not set"); + } + if (m_device_names->size() != static_cast(33)) { + throw std::runtime_error("/types/sequence_body/seq/14: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_device_names->begin(); it != m_device_names->end(); ++it) { + if ((*it).size() != static_cast(8)) { + throw std::runtime_error("/types/sequence_body/seq/14: size mismatch"); + } + } + if (m_tracks.get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/15: nested object is not set"); + } + m_tracks.get()->_set_io(m__io); + m_tracks.get()->_check(); + if (m__unnamed16.size() != static_cast(3587)) { + throw std::runtime_error("/types/sequence_body/seq/16: size mismatch"); + } + if (m_bars == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/17: repeated field is not set"); + } + if (m_bars->size() != static_cast(bar_count())) { + throw std::runtime_error("/types/sequence_body/seq/17: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_bars->begin(); it != m_bars->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/17: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed18.size() != static_cast(4 * (999 - bar_count()))) { + throw std::runtime_error("/types/sequence_body/seq/18: size mismatch"); + } + if (m__unnamed19.size() != static_cast(865)) { + throw std::runtime_error("/types/sequence_body/seq/19: size mismatch"); + } + if (m_events == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/20: repeated field is not set"); + } + if (m_events->empty()) { + throw std::runtime_error("/types/sequence_body/seq/20: repeat-until field must not be empty"); + } + for (std::vector>::const_iterator it = m_events->begin(); it != m_events->end(); ++it) { + const std::size_t i = static_cast(it - m_events->begin()); + const event_t* _ = (*it).get(); + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/sequence_body/seq/20: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + const bool _is_last = (i == m_events->size() - 1); + if ((_->tick() == 1048575) != _is_last) { + throw std::runtime_error("/types/sequence_body/seq/20: repeat-until condition mismatch"); + } + } + m__dirty = false; +} + +mpc2000xl_all_t::sequence_body_t::~sequence_body_t() {} + +mpc2000xl_all_t::sequence_body_t::start_time_t::start_time_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_body_t::start_time_t::_read() { + m_hours = m__io->read_u1(); + m_minutes = m__io->read_u1(); + m_seconds = m__io->read_u1(); + m_frames = m__io->read_u1(); + m_frame_decimals = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_body_t::start_time_t::_fetch_instances() { +} + +void mpc2000xl_all_t::sequence_body_t::start_time_t::_write() { + m__io->write_u1(m_hours); + m__io->write_u1(m_minutes); + m__io->write_u1(m_seconds); + m__io->write_u1(m_frames); + m__io->write_u1(m_frame_decimals); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_body_t::start_time_t::_check() { + m__dirty = false; +} + +mpc2000xl_all_t::sequence_body_t::start_time_t::~start_time_t() {} + +mpc2000xl_all_t::sequence_meta_t::sequence_meta_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_meta_t::_read() { + m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(16), "ASCII"); + m_is_used = static_cast(m__io->read_u2le()); + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_meta_t::_fetch_instances() { +} + +void mpc2000xl_all_t::sequence_meta_t::_write() { + m__io->write_bytes(m_name); + m__io->write_u2le(static_cast(m_is_used)); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::sequence_meta_t::_check() { + if (m_name.size() != static_cast(16)) { + throw std::runtime_error("/types/sequence_meta/seq/0: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::sequence_meta_t::~sequence_meta_t() {} + +mpc2000xl_all_t::sequencer_t::sequencer_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::sequencer_t::_read() { + m_active_sequence = m__io->read_u1(); + m__unnamed1 = m__io->read_bytes(1); + m_active_track = m__io->read_u1(); + m__unnamed3 = m__io->read_bytes(1); + m_master_tempo = m__io->read_u2le(); + m_tempo_source_is_sequence = m__io->read_bits_int_le(1); + m__unnamed6 = m__io->read_bits_int_le(7); + m_timing_correct = static_cast(m__io->read_u1()); + m_time_display_style = static_cast(m__io->read_bits_int_le(1)); + m__unnamed9 = m__io->read_bits_int_le(7); + m_second_sequence_enabled = m__io->read_bits_int_le(1); + m__unnamed11 = m__io->read_bits_int_le(7); + m_sequence_sequence_index = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_all_t::sequencer_t::_fetch_instances() { +} + +void mpc2000xl_all_t::sequencer_t::_write() { + m__io->write_u1(m_active_sequence); + m__io->write_bytes(m__unnamed1); + m__io->write_u1(m_active_track); + m__io->write_bytes(m__unnamed3); + m__io->write_u2le(m_master_tempo); + m__io->write_bits_int_le(1, ((m_tempo_source_is_sequence) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed6); + m__io->write_u1(static_cast(m_timing_correct)); + m__io->write_bits_int_le(1, static_cast(m_time_display_style)); + m__io->write_bits_int_le(7, m__unnamed9); + m__io->write_bits_int_le(1, ((m_second_sequence_enabled) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed11); + m__io->write_u1(m_sequence_sequence_index); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::sequencer_t::_check() { + if (m__unnamed1.size() != static_cast(1)) { + throw std::runtime_error("/types/sequencer/seq/1: size mismatch"); + } + if (m__unnamed3.size() != static_cast(1)) { + throw std::runtime_error("/types/sequencer/seq/3: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::sequencer_t::~sequencer_t() {} + +mpc2000xl_all_t::song_t::song_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::song_t::_read() { + m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(16), "ASCII"); + m_steps = std::unique_ptr>>(new std::vector>()); + const int l_steps = 250; + for (int i = 0; i < l_steps; i++) { + std::unique_ptr _t_steps = std::unique_ptr(new song_step_t(m__io, this, m__root)); + try { + _t_steps->_read(); + } catch(...) { + m_steps->push_back(std::move(_t_steps)); + throw; + } + m_steps->push_back(std::move(_t_steps)); + } + m__unnamed2 = m__io->read_bytes(2); + m_is_used = m__io->read_bits_int_le(1); + m_loop_first_step = m__io->read_u1(); + m_loop_last_step = m__io->read_u1(); + m_is_loop_enabled = m__io->read_bits_int_le(1); + m__unnamed7 = m__io->read_bytes(6); + m__dirty = false; +} + +void mpc2000xl_all_t::song_t::_fetch_instances() { + for (std::size_t i = 0; i < m_steps->size(); ++i) { + m_steps->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::song_t::_write() { + m__io->write_bytes(m_name); + if (m_steps == nullptr) { + throw std::runtime_error("/types/song/seq/1: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_steps->begin(); it != m_steps->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/song/seq/1: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m__unnamed2); + m__io->write_bits_int_le(1, ((m_is_used) ? 1 : 0)); + m__io->write_u1(m_loop_first_step); + m__io->write_u1(m_loop_last_step); + m__io->write_bits_int_le(1, ((m_is_loop_enabled) ? 1 : 0)); + m__io->write_bytes(m__unnamed7); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::song_t::_check() { + if (m_name.size() != static_cast(16)) { + throw std::runtime_error("/types/song/seq/0: size mismatch"); + } + if (m_steps == nullptr) { + throw std::runtime_error("/types/song/seq/1: repeated field is not set"); + } + if (m_steps->size() != static_cast(250)) { + throw std::runtime_error("/types/song/seq/1: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_steps->begin(); it != m_steps->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/song/seq/1: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m__unnamed2.size() != static_cast(2)) { + throw std::runtime_error("/types/song/seq/2: size mismatch"); + } + if (m__unnamed7.size() != static_cast(6)) { + throw std::runtime_error("/types/song/seq/7: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::song_t::~song_t() {} + +mpc2000xl_all_t::song_global_t::song_global_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::song_global_t::_read() { + m_default_song_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(16), "ASCII"); + m_ignore_tempo_change_events_in_sequence = m__io->read_bits_int_le(1); + m__unnamed2 = m__io->read_bits_int_le(7); + m__dirty = false; +} + +void mpc2000xl_all_t::song_global_t::_fetch_instances() { +} + +void mpc2000xl_all_t::song_global_t::_write() { + m__io->write_bytes(m_default_song_name); + m__io->write_bits_int_le(1, ((m_ignore_tempo_change_events_in_sequence) ? 1 : 0)); + m__io->write_bits_int_le(7, m__unnamed2); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::song_global_t::_check() { + if (m_default_song_name.size() != static_cast(16)) { + throw std::runtime_error("/types/song_global/seq/0: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::song_global_t::~song_global_t() {} + +mpc2000xl_all_t::song_step_t::song_step_t(kaitai::kstream* p__io, mpc2000xl_all_t::song_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::song_step_t::_read() { + m_sequence_index = m__io->read_u1(); + m_repeat_count = m__io->read_u1(); + m__dirty = false; +} + +void mpc2000xl_all_t::song_step_t::_fetch_instances() { +} + +void mpc2000xl_all_t::song_step_t::_write() { + m__io->write_u1(m_sequence_index); + m__io->write_u1(m_repeat_count); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::song_step_t::_check() { + m__dirty = false; +} + +mpc2000xl_all_t::song_step_t::~song_step_t() {} + +mpc2000xl_all_t::step_edit_options_t::step_edit_options_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::step_edit_options_t::_read() { + m_auto_step_increment = m__io->read_bits_int_le(1); + m_duration_of_recorded_notes = static_cast(m__io->read_u1()); + m_tc_value_percentage = m__io->read_u1(); + if (!(m_tc_value_percentage >= 0)) { + throw kaitai::validation_less_than_error(0, m_tc_value_percentage, m__io, std::string("/types/step_edit_options/seq/2")); + } + if (!(m_tc_value_percentage <= 100)) { + throw kaitai::validation_greater_than_error(100, m_tc_value_percentage, m__io, std::string("/types/step_edit_options/seq/2")); + } + m__dirty = false; +} + +void mpc2000xl_all_t::step_edit_options_t::_fetch_instances() { +} + +void mpc2000xl_all_t::step_edit_options_t::_write() { + m__io->write_bits_int_le(1, ((m_auto_step_increment) ? 1 : 0)); + m__io->write_u1(static_cast(m_duration_of_recorded_notes)); + m__io->write_u1(m_tc_value_percentage); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::step_edit_options_t::_check() { + if (!(m_tc_value_percentage >= 0)) { + throw kaitai::validation_less_than_error(0, m_tc_value_percentage, m__io, std::string("/types/step_edit_options/seq/2")); + } + if (!(m_tc_value_percentage <= 100)) { + throw kaitai::validation_greater_than_error(100, m_tc_value_percentage, m__io, std::string("/types/step_edit_options/seq/2")); + } + m__dirty = false; +} + +mpc2000xl_all_t::step_edit_options_t::~step_edit_options_t() {} + +mpc2000xl_all_t::track_status_t::track_status_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::track_status_t::_read() { + m_unused_or_used = static_cast(m__io->read_bits_int_le(1)); + m_off_or_on = static_cast(m__io->read_bits_int_le(1)); + m_transmit_program_changes = static_cast(m__io->read_bits_int_le(1)); + m__unnamed3 = m__io->read_bits_int_le(5); + m__dirty = false; +} + +void mpc2000xl_all_t::track_status_t::_fetch_instances() { +} + +void mpc2000xl_all_t::track_status_t::_write() { + m__io->write_bits_int_le(1, static_cast(m_unused_or_used)); + m__io->write_bits_int_le(1, static_cast(m_off_or_on)); + m__io->write_bits_int_le(1, static_cast(m_transmit_program_changes)); + m__io->write_bits_int_le(5, m__unnamed3); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::track_status_t::_check() { + m__dirty = false; +} + +mpc2000xl_all_t::track_status_t::~track_status_t() {} + +mpc2000xl_all_t::tracks_t::tracks_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_all_t::tracks_t::_read() { + m_names = std::unique_ptr>(new std::vector()); + const int l_names = 64; + for (int i = 0; i < l_names; i++) { + m_names->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(16), "ASCII"))); + } + m_device = std::unique_ptr>(new std::vector()); + const int l_device = 64; + for (int i = 0; i < l_device; i++) { + m_device->push_back(std::move(m__io->read_u1())); + } + m_bus = std::unique_ptr>(new std::vector()); + const int l_bus = 64; + for (int i = 0; i < l_bus; i++) { + m_bus->push_back(std::move(static_cast(m__io->read_u1()))); + } + m_program_change = std::unique_ptr>(new std::vector()); + const int l_program_change = 64; + for (int i = 0; i < l_program_change; i++) { + m_program_change->push_back(std::move(m__io->read_u1())); + } + m_velocity_ratio = std::unique_ptr>(new std::vector()); + const int l_velocity_ratio = 64; + for (int i = 0; i < l_velocity_ratio; i++) { + m_velocity_ratio->push_back(std::move(m__io->read_u1())); + } + m_status = std::unique_ptr>>(new std::vector>()); + const int l_status = 64; + for (int i = 0; i < l_status; i++) { + std::unique_ptr _t_status = std::unique_ptr(new track_status_t(m__io, this, m__root)); + try { + _t_status->_read(); + } catch(...) { + m_status->push_back(std::move(_t_status)); + throw; + } + m_status->push_back(std::move(_t_status)); + } + m_unknown = m__io->read_bytes(64); + m__dirty = false; +} + +void mpc2000xl_all_t::tracks_t::_fetch_instances() { + for (std::size_t i = 0; i < m_names->size(); ++i) { + } + for (std::size_t i = 0; i < m_device->size(); ++i) { + } + for (std::size_t i = 0; i < m_bus->size(); ++i) { + } + for (std::size_t i = 0; i < m_program_change->size(); ++i) { + } + for (std::size_t i = 0; i < m_velocity_ratio->size(); ++i) { + } + for (std::size_t i = 0; i < m_status->size(); ++i) { + m_status->at(i).get()->_fetch_instances(); + } +} + +void mpc2000xl_all_t::tracks_t::_write() { + if (m_names == nullptr) { + throw std::runtime_error("/types/tracks/seq/0: repeated field is not set"); + } + for (std::vector::const_iterator it = m_names->begin(); it != m_names->end(); ++it) { + m__io->write_bytes((*it)); + } + if (m_device == nullptr) { + throw std::runtime_error("/types/tracks/seq/1: repeated field is not set"); + } + for (std::vector::const_iterator it = m_device->begin(); it != m_device->end(); ++it) { + m__io->write_u1((*it)); + } + if (m_bus == nullptr) { + throw std::runtime_error("/types/tracks/seq/2: repeated field is not set"); + } + for (std::vector::const_iterator it = m_bus->begin(); it != m_bus->end(); ++it) { + m__io->write_u1(static_cast((*it))); + } + if (m_program_change == nullptr) { + throw std::runtime_error("/types/tracks/seq/3: repeated field is not set"); + } + for (std::vector::const_iterator it = m_program_change->begin(); it != m_program_change->end(); ++it) { + m__io->write_u1((*it)); + } + if (m_velocity_ratio == nullptr) { + throw std::runtime_error("/types/tracks/seq/4: repeated field is not set"); + } + for (std::vector::const_iterator it = m_velocity_ratio->begin(); it != m_velocity_ratio->end(); ++it) { + m__io->write_u1((*it)); + } + if (m_status == nullptr) { + throw std::runtime_error("/types/tracks/seq/5: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_status->begin(); it != m_status->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/tracks/seq/5: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + m__io->write_bytes(m_unknown); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_all_t::tracks_t::_check() { + if (m_names == nullptr) { + throw std::runtime_error("/types/tracks/seq/0: repeated field is not set"); + } + if (m_names->size() != static_cast(64)) { + throw std::runtime_error("/types/tracks/seq/0: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_names->begin(); it != m_names->end(); ++it) { + if ((*it).size() != static_cast(16)) { + throw std::runtime_error("/types/tracks/seq/0: size mismatch"); + } + } + if (m_device == nullptr) { + throw std::runtime_error("/types/tracks/seq/1: repeated field is not set"); + } + if (m_device->size() != static_cast(64)) { + throw std::runtime_error("/types/tracks/seq/1: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_device->begin(); it != m_device->end(); ++it) { + } + if (m_bus == nullptr) { + throw std::runtime_error("/types/tracks/seq/2: repeated field is not set"); + } + if (m_bus->size() != static_cast(64)) { + throw std::runtime_error("/types/tracks/seq/2: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_bus->begin(); it != m_bus->end(); ++it) { + } + if (m_program_change == nullptr) { + throw std::runtime_error("/types/tracks/seq/3: repeated field is not set"); + } + if (m_program_change->size() != static_cast(64)) { + throw std::runtime_error("/types/tracks/seq/3: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_program_change->begin(); it != m_program_change->end(); ++it) { + } + if (m_velocity_ratio == nullptr) { + throw std::runtime_error("/types/tracks/seq/4: repeated field is not set"); + } + if (m_velocity_ratio->size() != static_cast(64)) { + throw std::runtime_error("/types/tracks/seq/4: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_velocity_ratio->begin(); it != m_velocity_ratio->end(); ++it) { + } + if (m_status == nullptr) { + throw std::runtime_error("/types/tracks/seq/5: repeated field is not set"); + } + if (m_status->size() != static_cast(64)) { + throw std::runtime_error("/types/tracks/seq/5: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_status->begin(); it != m_status->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/tracks/seq/5: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m_unknown.size() != static_cast(64)) { + throw std::runtime_error("/types/tracks/seq/6: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_all_t::tracks_t::~tracks_t() {} diff --git a/src/main/file/kaitai/generated/mpc2000xl_all.h b/src/main/file/kaitai/generated/mpc2000xl_all.h new file mode 100644 index 00000000..e9833d05 --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_all.h @@ -0,0 +1,2136 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class mpc2000xl_all_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +class mpc2000xl_all_t : public kaitai::kstruct { + +public: + class bar_t; + class ch_pressure_event_t; + class control_change_event_t; + class count_t; + class defaults_t; + class event_t; + class exclusive_event_t; + class location_t; + class midi_input_t; + class midi_output_t; + class midi_switch_t; + class midi_sync_t; + class misc_t; + class mixer_event_t; + class note_event_t; + class pitch_bend_event_t; + class poly_pressure_event_t; + class program_change_event_t; + class sequence_t; + class sequence_body_t; + class sequence_meta_t; + class sequencer_t; + class song_t; + class song_global_t; + class song_step_t; + class step_edit_options_t; + class track_status_t; + class tracks_t; + + enum bus_t { + BUS_MIDI = 0, + BUS_DRUM1 = 1, + BUS_DRUM2 = 2, + BUS_DRUM3 = 3, + BUS_DRUM4 = 4 + }; + static bool _is_defined_bus_t(bus_t v); + +private: + static const std::set _values_bus_t; + +public: + + enum click_output_t { + CLICK_OUTPUT_STEREO = 0, + CLICK_OUTPUT_INDIV1 = 1, + CLICK_OUTPUT_INDIV2 = 2, + CLICK_OUTPUT_INDIV3 = 3, + CLICK_OUTPUT_INDIV4 = 4, + CLICK_OUTPUT_INDIV5 = 5, + CLICK_OUTPUT_INDIV6 = 6, + CLICK_OUTPUT_INDIV7 = 7, + CLICK_OUTPUT_INDIV8 = 8 + }; + static bool _is_defined_click_output_t(click_output_t v); + +private: + static const std::set _values_click_output_t; + +public: + + enum controller_t { + CONTROLLER_BANK_SEL_MSB = 0, + CONTROLLER_MOD_WHEEL = 1, + CONTROLLER_BREATH_CONT = 2, + CONTROLLER_CC3 = 3, + CONTROLLER_FOOT_CONTROL = 4, + CONTROLLER_PORTA_TIME = 5, + CONTROLLER_DATA_ENTRY = 6, + CONTROLLER_MAIN_VOLUME = 7, + CONTROLLER_BALANCE = 8, + CONTROLLER_CC9 = 9, + CONTROLLER_PAN = 10, + CONTROLLER_EXPRESSION = 11, + CONTROLLER_EFFECT_1 = 12, + CONTROLLER_EFFECT_2 = 13, + CONTROLLER_CC14 = 14, + CONTROLLER_CC15 = 15, + CONTROLLER_GEN_PUR_1 = 16, + CONTROLLER_GEN_PUR_2 = 17, + CONTROLLER_GEN_PUR_3 = 18, + CONTROLLER_GEN_PUR_4 = 19, + CONTROLLER_CC20 = 20, + CONTROLLER_CC21 = 21, + CONTROLLER_CC22 = 22, + CONTROLLER_CC23 = 23, + CONTROLLER_CC24 = 24, + CONTROLLER_CC25 = 25, + CONTROLLER_CC26 = 26, + CONTROLLER_CC27 = 27, + CONTROLLER_CC28 = 28, + CONTROLLER_CC29 = 29, + CONTROLLER_CC30 = 30, + CONTROLLER_CC31 = 31, + CONTROLLER_BANK_SEL_LSB = 32, + CONTROLLER_MOD_WHEL_LSB = 33, + CONTROLLER_BREATH_LSB = 34, + CONTROLLER_CC35 = 35, + CONTROLLER_FOOT_CNT_LSB = 36, + CONTROLLER_PORT_TIME_LS = 37, + CONTROLLER_DATA_ENT_LSB = 38, + CONTROLLER_MAIN_VOL_LSB = 39, + CONTROLLER_BALANCE_LSB = 40, + CONTROLLER_CC41 = 41, + CONTROLLER_PAN_LSB = 42, + CONTROLLER_EXPRESS_LSB = 43, + CONTROLLER_EFFECT_1_LSB = 44, + CONTROLLER_EFFECT_2_MSB = 45, + CONTROLLER_CC46 = 46, + CONTROLLER_CC47 = 47, + CONTROLLER_GEN_PUR_1_LS = 48, + CONTROLLER_GEN_PUR_2_LS = 49, + CONTROLLER_GEN_PUR_3_LS = 50, + CONTROLLER_GEN_PUR_4_LS = 51, + CONTROLLER_CC52 = 52, + CONTROLLER_CC53 = 53, + CONTROLLER_CC54 = 54, + CONTROLLER_CC55 = 55, + CONTROLLER_CC56 = 56, + CONTROLLER_CC57 = 57, + CONTROLLER_CC58 = 58, + CONTROLLER_CC59 = 59, + CONTROLLER_CC60 = 60, + CONTROLLER_CC61 = 61, + CONTROLLER_CC62 = 62, + CONTROLLER_CC63 = 63, + CONTROLLER_SUSTAIN_PDL = 64, + CONTROLLER_PORTA_PEDAL = 65, + CONTROLLER_SOSTENUTO = 66, + CONTROLLER_SOFT_PEDAL = 67, + CONTROLLER_LEGATO_FT_SW = 68, + CONTROLLER_HOLD_2 = 69, + CONTROLLER_SOUND_VARI = 70, + CONTROLLER_TIMBER_HARMO = 71, + CONTROLLER_RELEASE_TIME = 72, + CONTROLLER_ATTACK_TIME = 73, + CONTROLLER_BRIGHTNESS = 74, + CONTROLLER_SOUND_CONT_6 = 75, + CONTROLLER_SOUND_CONT_7 = 76, + CONTROLLER_SOUND_CONT_8 = 77, + CONTROLLER_SOUND_CONT_9 = 78, + CONTROLLER_SOUND_CONT10 = 79, + CONTROLLER_GEN_PUR_5 = 80, + CONTROLLER_GEN_PUR_6 = 81, + CONTROLLER_GEN_PUR_7 = 82, + CONTROLLER_GEN_PUR_8 = 83, + CONTROLLER_PORTA_CNTRL = 84, + CONTROLLER_CC85 = 85, + CONTROLLER_CC86 = 86, + CONTROLLER_CC87 = 87, + CONTROLLER_CC88 = 88, + CONTROLLER_CC89 = 89, + CONTROLLER_CC90 = 90, + CONTROLLER_EXT_EFF_DPTH = 91, + CONTROLLER_TREMOLO_DPTH = 92, + CONTROLLER_CHORUS_DEPTH = 93, + CONTROLLER_DETUNE_DEPTH = 94, + CONTROLLER_PHASER_DEPTH = 95, + CONTROLLER_DATA_INCRE = 96, + CONTROLLER_DATA_DECRE = 97, + CONTROLLER_NRPN_LSB = 98, + CONTROLLER_NRPN_MSB = 99, + CONTROLLER_RPN_LSB = 100, + CONTROLLER_RPN_MSB = 101, + CONTROLLER_CC102 = 102, + CONTROLLER_CC103 = 103, + CONTROLLER_CC104 = 104, + CONTROLLER_CC105 = 105, + CONTROLLER_CC106 = 106, + CONTROLLER_CC107 = 107, + CONTROLLER_CC108 = 108, + CONTROLLER_CC109 = 109, + CONTROLLER_CC110 = 110, + CONTROLLER_CC111 = 111, + CONTROLLER_CC112 = 112, + CONTROLLER_CC113 = 113, + CONTROLLER_CC114 = 114, + CONTROLLER_CC115 = 115, + CONTROLLER_CC116 = 116, + CONTROLLER_CC117 = 117, + CONTROLLER_CC118 = 118, + CONTROLLER_CC119 = 119, + CONTROLLER_ALL_SND_OFF = 120, + CONTROLLER_RESET_CONTRL = 121, + CONTROLLER_LOCAL_ON_OFF = 122, + CONTROLLER_ALL_NOTE_OFF = 123, + CONTROLLER_OMNI_OFF = 124, + CONTROLLER_OMNI_ON = 125, + CONTROLLER_MONO_MODE_ON = 126, + CONTROLLER_POLY_MODE_ON = 127 + }; + static bool _is_defined_controller_t(controller_t v); + +private: + static const std::set _values_controller_t; + +public: + + enum count_in_mode_t { + COUNT_IN_MODE_FALSE = 0, + COUNT_IN_MODE_REC_ONLY = 1, + COUNT_IN_MODE_REC_AND_PLAY = 2 + }; + static bool _is_defined_count_in_mode_t(count_in_mode_t v); + +private: + static const std::set _values_count_in_mode_t; + +public: + + enum duration_of_recorded_notes_t { + DURATION_OF_RECORDED_NOTES_AS_PLAYED = 0, + DURATION_OF_RECORDED_NOTES_TC_VALUE = 1 + }; + static bool _is_defined_duration_of_recorded_notes_t(duration_of_recorded_notes_t v); + +private: + static const std::set _values_duration_of_recorded_notes_t; + +public: + + enum frame_rate_t { + FRAME_RATE_FPS_24 = 0, + FRAME_RATE_FPS_25 = 1, + FRAME_RATE_FPS_30D = 2, + FRAME_RATE_FPS_30 = 3 + }; + static bool _is_defined_frame_rate_t(frame_rate_t v); + +private: + static const std::set _values_frame_rate_t; + +public: + + enum midi_input_filter_type_t { + MIDI_INPUT_FILTER_TYPE_NOTES = 0, + MIDI_INPUT_FILTER_TYPE_PITCH_BEND = 1, + MIDI_INPUT_FILTER_TYPE_PROG_CHANGE = 2, + MIDI_INPUT_FILTER_TYPE_CH_PRESSURE = 3, + MIDI_INPUT_FILTER_TYPE_POLY_PRESS = 4, + MIDI_INPUT_FILTER_TYPE_EXCLUSIVE = 5, + MIDI_INPUT_FILTER_TYPE_CC0_BANK_SEL_MSB = 6, + MIDI_INPUT_FILTER_TYPE_CC1_MOD_WHEEL = 7, + MIDI_INPUT_FILTER_TYPE_CC2_BREATH_CONT = 8, + MIDI_INPUT_FILTER_TYPE_CC3 = 9, + MIDI_INPUT_FILTER_TYPE_CC4_FOOT_CONTROL = 10, + MIDI_INPUT_FILTER_TYPE_CC5_PORTA_TIME = 11, + MIDI_INPUT_FILTER_TYPE_CC6_DATA_ENTRY = 12, + MIDI_INPUT_FILTER_TYPE_CC7_MAIN_VOLUME = 13, + MIDI_INPUT_FILTER_TYPE_CC8_BALANCE = 14, + MIDI_INPUT_FILTER_TYPE_CC9 = 15, + MIDI_INPUT_FILTER_TYPE_CC10_PAN = 16, + MIDI_INPUT_FILTER_TYPE_CC11_EXPRESSION = 17, + MIDI_INPUT_FILTER_TYPE_CC12_EFFECT_1 = 18, + MIDI_INPUT_FILTER_TYPE_CC13_EFFECT_2 = 19, + MIDI_INPUT_FILTER_TYPE_CC14 = 20, + MIDI_INPUT_FILTER_TYPE_CC15 = 21, + MIDI_INPUT_FILTER_TYPE_CC16_GEN_PUR_1 = 22, + MIDI_INPUT_FILTER_TYPE_CC17_GEN_PUR_2 = 23, + MIDI_INPUT_FILTER_TYPE_CC18_GEN_PUR_3 = 24, + MIDI_INPUT_FILTER_TYPE_CC19_GEN_PUR_4 = 25, + MIDI_INPUT_FILTER_TYPE_CC20 = 26, + MIDI_INPUT_FILTER_TYPE_CC21 = 27, + MIDI_INPUT_FILTER_TYPE_CC22 = 28, + MIDI_INPUT_FILTER_TYPE_CC23 = 29, + MIDI_INPUT_FILTER_TYPE_CC24 = 30, + MIDI_INPUT_FILTER_TYPE_CC25 = 31, + MIDI_INPUT_FILTER_TYPE_CC26 = 32, + MIDI_INPUT_FILTER_TYPE_CC27 = 33, + MIDI_INPUT_FILTER_TYPE_CC28 = 34, + MIDI_INPUT_FILTER_TYPE_CC29 = 35, + MIDI_INPUT_FILTER_TYPE_CC30 = 36, + MIDI_INPUT_FILTER_TYPE_CC31 = 37, + MIDI_INPUT_FILTER_TYPE_CC32_BANK_SEL_LSB = 38, + MIDI_INPUT_FILTER_TYPE_CC33_MOD_WHEL_LSB = 39, + MIDI_INPUT_FILTER_TYPE_CC34_BREATH_LSB = 40, + MIDI_INPUT_FILTER_TYPE_CC35 = 41, + MIDI_INPUT_FILTER_TYPE_CC36_FOOT_CNT_LSB = 42, + MIDI_INPUT_FILTER_TYPE_CC37_PORT_TIME_LS = 43, + MIDI_INPUT_FILTER_TYPE_CC38_DATA_ENT_LSB = 44, + MIDI_INPUT_FILTER_TYPE_CC39_MAIN_VOL_LSB = 45, + MIDI_INPUT_FILTER_TYPE_CC40_BALANCE_LSB = 46, + MIDI_INPUT_FILTER_TYPE_CC41 = 47, + MIDI_INPUT_FILTER_TYPE_CC42_PAN_LSB = 48, + MIDI_INPUT_FILTER_TYPE_CC43_EXPRESS_LSB = 49, + MIDI_INPUT_FILTER_TYPE_CC44_EFFECT_1_LSB = 50, + MIDI_INPUT_FILTER_TYPE_CC45_EFFECT_2_MSB = 51, + MIDI_INPUT_FILTER_TYPE_CC46 = 52, + MIDI_INPUT_FILTER_TYPE_CC47 = 53, + MIDI_INPUT_FILTER_TYPE_CC48_GEN_PUR_1_LS = 54, + MIDI_INPUT_FILTER_TYPE_CC49_GEN_PUR_2_LS = 55, + MIDI_INPUT_FILTER_TYPE_CC50_GEN_PUR_3_LS = 56, + MIDI_INPUT_FILTER_TYPE_CC51_GEN_PUR_4_LS = 57, + MIDI_INPUT_FILTER_TYPE_CC52 = 58, + MIDI_INPUT_FILTER_TYPE_CC53 = 59, + MIDI_INPUT_FILTER_TYPE_CC54 = 60, + MIDI_INPUT_FILTER_TYPE_CC55 = 61, + MIDI_INPUT_FILTER_TYPE_CC56 = 62, + MIDI_INPUT_FILTER_TYPE_CC57 = 63, + MIDI_INPUT_FILTER_TYPE_CC58 = 64, + MIDI_INPUT_FILTER_TYPE_CC59 = 65, + MIDI_INPUT_FILTER_TYPE_CC60 = 66, + MIDI_INPUT_FILTER_TYPE_CC61 = 67, + MIDI_INPUT_FILTER_TYPE_CC62 = 68, + MIDI_INPUT_FILTER_TYPE_CC63 = 69, + MIDI_INPUT_FILTER_TYPE_CC64_SUSTAIN_PDL = 70, + MIDI_INPUT_FILTER_TYPE_CC65_PORTA_PEDAL = 71, + MIDI_INPUT_FILTER_TYPE_CC66_SOSTENUTO = 72, + MIDI_INPUT_FILTER_TYPE_CC67_SOFT_PEDAL = 73, + MIDI_INPUT_FILTER_TYPE_CC68_LEGATO_FT_SW = 74, + MIDI_INPUT_FILTER_TYPE_CC69_HOLD_2 = 75, + MIDI_INPUT_FILTER_TYPE_CC70_SOUND_VARI = 76, + MIDI_INPUT_FILTER_TYPE_CC71_TIMBER_HARMO = 77, + MIDI_INPUT_FILTER_TYPE_CC72_RELEASE_TIME = 78, + MIDI_INPUT_FILTER_TYPE_CC73_ATTACK_TIME = 79, + MIDI_INPUT_FILTER_TYPE_CC74_BRIGHTNESS = 80, + MIDI_INPUT_FILTER_TYPE_CC75_SOUND_CONT_6 = 81, + MIDI_INPUT_FILTER_TYPE_CC76_SOUND_CONT_7 = 82, + MIDI_INPUT_FILTER_TYPE_CC77_SOUND_CONT_8 = 83, + MIDI_INPUT_FILTER_TYPE_CC78_SOUND_CONT_9 = 84, + MIDI_INPUT_FILTER_TYPE_CC79_SOUND_CONT10 = 85, + MIDI_INPUT_FILTER_TYPE_CC80_GEN_PUR_5 = 86, + MIDI_INPUT_FILTER_TYPE_CC81_GEN_PUR_6 = 87, + MIDI_INPUT_FILTER_TYPE_CC82_GEN_PUR_7 = 88, + MIDI_INPUT_FILTER_TYPE_CC83_GEN_PUR_8 = 89, + MIDI_INPUT_FILTER_TYPE_CC84_PORTA_CNTRL = 90, + MIDI_INPUT_FILTER_TYPE_CC85 = 91, + MIDI_INPUT_FILTER_TYPE_CC86 = 92, + MIDI_INPUT_FILTER_TYPE_CC87 = 93, + MIDI_INPUT_FILTER_TYPE_CC88 = 94, + MIDI_INPUT_FILTER_TYPE_CC89 = 95, + MIDI_INPUT_FILTER_TYPE_CC90 = 96, + MIDI_INPUT_FILTER_TYPE_CC91_EXT_EFF_DPTH = 97, + MIDI_INPUT_FILTER_TYPE_CC92_TREMOLO_DPTH = 98, + MIDI_INPUT_FILTER_TYPE_CC93_CHORUS_DEPTH = 99, + MIDI_INPUT_FILTER_TYPE_CC94_DETUNE_DEPTH = 100, + MIDI_INPUT_FILTER_TYPE_CC95_PHASER_DEPTH = 101, + MIDI_INPUT_FILTER_TYPE_CC96_DATA_INCRE = 102, + MIDI_INPUT_FILTER_TYPE_CC97_DATA_DECRE = 103, + MIDI_INPUT_FILTER_TYPE_CC98_NRPN_LSB = 104, + MIDI_INPUT_FILTER_TYPE_CC99_NRPN_MSB = 105, + MIDI_INPUT_FILTER_TYPE_CC100_RPN_LSB = 106, + MIDI_INPUT_FILTER_TYPE_CC101_RPN_MSB = 107, + MIDI_INPUT_FILTER_TYPE_CC102 = 108, + MIDI_INPUT_FILTER_TYPE_CC103 = 109, + MIDI_INPUT_FILTER_TYPE_CC104 = 110, + MIDI_INPUT_FILTER_TYPE_CC105 = 111, + MIDI_INPUT_FILTER_TYPE_CC106 = 112, + MIDI_INPUT_FILTER_TYPE_CC107 = 113, + MIDI_INPUT_FILTER_TYPE_CC108 = 114, + MIDI_INPUT_FILTER_TYPE_CC109 = 115, + MIDI_INPUT_FILTER_TYPE_CC110 = 116, + MIDI_INPUT_FILTER_TYPE_CC111 = 117, + MIDI_INPUT_FILTER_TYPE_CC112 = 118, + MIDI_INPUT_FILTER_TYPE_CC113 = 119, + MIDI_INPUT_FILTER_TYPE_CC114 = 120, + MIDI_INPUT_FILTER_TYPE_CC115 = 121, + MIDI_INPUT_FILTER_TYPE_CC116 = 122, + MIDI_INPUT_FILTER_TYPE_CC117 = 123, + MIDI_INPUT_FILTER_TYPE_CC118 = 124, + MIDI_INPUT_FILTER_TYPE_CC119 = 125, + MIDI_INPUT_FILTER_TYPE_CC120_ALL_SND_OFF = 126, + MIDI_INPUT_FILTER_TYPE_CC121_RESET_CONTRL = 127, + MIDI_INPUT_FILTER_TYPE_CC122_LOCAL_ON_OFF = 128, + MIDI_INPUT_FILTER_TYPE_CC123_ALL_NOTE_OFF = 129, + MIDI_INPUT_FILTER_TYPE_CC124_OMNI_OFF = 130, + MIDI_INPUT_FILTER_TYPE_CC125_OMNI_ON = 131, + MIDI_INPUT_FILTER_TYPE_CC126_MONO_MODE_ON = 132, + MIDI_INPUT_FILTER_TYPE_CC127_POLY_MODE_ON = 133 + }; + static bool _is_defined_midi_input_filter_type_t(midi_input_filter_type_t v); + +private: + static const std::set _values_midi_input_filter_type_t; + +public: + + enum midi_input_receive_channel_t { + MIDI_INPUT_RECEIVE_CHANNEL_ALL = 0, + MIDI_INPUT_RECEIVE_CHANNEL_CH1 = 1, + MIDI_INPUT_RECEIVE_CHANNEL_CH2 = 2, + MIDI_INPUT_RECEIVE_CHANNEL_CH3 = 3, + MIDI_INPUT_RECEIVE_CHANNEL_CH4 = 4, + MIDI_INPUT_RECEIVE_CHANNEL_CH5 = 5, + MIDI_INPUT_RECEIVE_CHANNEL_CH6 = 6, + MIDI_INPUT_RECEIVE_CHANNEL_CH7 = 7, + MIDI_INPUT_RECEIVE_CHANNEL_CH8 = 8, + MIDI_INPUT_RECEIVE_CHANNEL_CH9 = 9, + MIDI_INPUT_RECEIVE_CHANNEL_CH10 = 10, + MIDI_INPUT_RECEIVE_CHANNEL_CH11 = 11, + MIDI_INPUT_RECEIVE_CHANNEL_CH12 = 12, + MIDI_INPUT_RECEIVE_CHANNEL_CH13 = 13, + MIDI_INPUT_RECEIVE_CHANNEL_CH14 = 14, + MIDI_INPUT_RECEIVE_CHANNEL_CH15 = 15, + MIDI_INPUT_RECEIVE_CHANNEL_CH16 = 16 + }; + static bool _is_defined_midi_input_receive_channel_t(midi_input_receive_channel_t v); + +private: + static const std::set _values_midi_input_receive_channel_t; + +public: + + enum midi_switch_function_t { + MIDI_SWITCH_FUNCTION_PLAY_STRT = 0, + MIDI_SWITCH_FUNCTION_PLAY = 1, + MIDI_SWITCH_FUNCTION_STOP = 2, + MIDI_SWITCH_FUNCTION_REC_AND_PLAY = 3, + MIDI_SWITCH_FUNCTION_ODUB_AND_PLAY = 4, + MIDI_SWITCH_FUNCTION_REC_PUNCH = 5, + MIDI_SWITCH_FUNCTION_ODUB_PNCH = 6, + MIDI_SWITCH_FUNCTION_TAP = 7, + MIDI_SWITCH_FUNCTION_PAD_BNK_A = 8, + MIDI_SWITCH_FUNCTION_PAD_BNK_B = 9, + MIDI_SWITCH_FUNCTION_PAD_BNK_C = 10, + MIDI_SWITCH_FUNCTION_PAD_BNK_D = 11, + MIDI_SWITCH_FUNCTION_PAD_1 = 12, + MIDI_SWITCH_FUNCTION_PAD_2 = 13, + MIDI_SWITCH_FUNCTION_PAD_3 = 14, + MIDI_SWITCH_FUNCTION_PAD_4 = 15, + MIDI_SWITCH_FUNCTION_PAD_5 = 16, + MIDI_SWITCH_FUNCTION_PAD_6 = 17, + MIDI_SWITCH_FUNCTION_PAD_7 = 18, + MIDI_SWITCH_FUNCTION_PAD_8 = 19, + MIDI_SWITCH_FUNCTION_PAD_9 = 20, + MIDI_SWITCH_FUNCTION_PAD_10 = 21, + MIDI_SWITCH_FUNCTION_PAD_11 = 22, + MIDI_SWITCH_FUNCTION_PAD_12 = 23, + MIDI_SWITCH_FUNCTION_PAD_13 = 24, + MIDI_SWITCH_FUNCTION_PAD_14 = 25, + MIDI_SWITCH_FUNCTION_PAD_15 = 26, + MIDI_SWITCH_FUNCTION_PAD_16 = 27, + MIDI_SWITCH_FUNCTION_F1 = 28, + MIDI_SWITCH_FUNCTION_F2 = 29, + MIDI_SWITCH_FUNCTION_F3 = 30, + MIDI_SWITCH_FUNCTION_F4 = 31, + MIDI_SWITCH_FUNCTION_F5 = 32, + MIDI_SWITCH_FUNCTION_F6 = 33 + }; + static bool _is_defined_midi_switch_function_t(midi_switch_function_t v); + +private: + static const std::set _values_midi_switch_function_t; + +public: + + enum midi_sync_mode_t { + MIDI_SYNC_MODE_FALSE = 0, + MIDI_SYNC_MODE_MIDI_CLOCK = 1, + MIDI_SYNC_MODE_TIME_CODE = 2 + }; + static bool _is_defined_midi_sync_mode_t(midi_sync_mode_t v); + +private: + static const std::set _values_midi_sync_mode_t; + +public: + + enum midi_sync_output_t { + MIDI_SYNC_OUTPUT_A = 0, + MIDI_SYNC_OUTPUT_B = 1, + MIDI_SYNC_OUTPUT_A_AND_B = 2 + }; + static bool _is_defined_midi_sync_output_t(midi_sync_output_t v); + +private: + static const std::set _values_midi_sync_output_t; + +public: + + enum mixer_event_param_t { + MIXER_EVENT_PARAM_STEREO_LEVEL = 1, + MIXER_EVENT_PARAM_STEREO_PAN = 2, + MIXER_EVENT_PARAM_FXSEND_LEVEL = 3, + MIXER_EVENT_PARAM_INDIV_LEVEL = 5 + }; + static bool _is_defined_mixer_event_param_t(mixer_event_param_t v); + +private: + static const std::set _values_mixer_event_param_t; + +public: + + enum off_on_t { + OFF_ON_FALSE = 0, + OFF_ON_TRUE = 1 + }; + static bool _is_defined_off_on_t(off_on_t v); + +private: + static const std::set _values_off_on_t; + +public: + + enum rate_t { + RATE_ONE_4 = 0, + RATE_ONE_4_3 = 1, + RATE_ONE_8 = 2, + RATE_ONE_8_3 = 3, + RATE_ONE_16 = 4, + RATE_ONE_16_3 = 5, + RATE_ONE_32 = 6, + RATE_ONE_32_3 = 7 + }; + static bool _is_defined_rate_t(rate_t v); + +private: + static const std::set _values_rate_t; + +public: + + enum sequence_is_used_t { + SEQUENCE_IS_USED_FALSE = 0, + SEQUENCE_IS_USED_TRUE = 641 + }; + static bool _is_defined_sequence_is_used_t(sequence_is_used_t v); + +private: + static const std::set _values_sequence_is_used_t; + +public: + + enum soft_thru_mode_t { + SOFT_THRU_MODE_FALSE = 0, + SOFT_THRU_MODE_AS_TRACK = 1, + SOFT_THRU_MODE_OMNI_A = 2, + SOFT_THRU_MODE_OMNI_B = 3, + SOFT_THRU_MODE_OMNI_AB = 4 + }; + static bool _is_defined_soft_thru_mode_t(soft_thru_mode_t v); + +private: + static const std::set _values_soft_thru_mode_t; + +public: + + enum sound_source_t { + SOUND_SOURCE_CLICK = 0, + SOUND_SOURCE_DRUM1 = 1, + SOUND_SOURCE_DRUM2 = 2, + SOUND_SOURCE_DRUM3 = 3, + SOUND_SOURCE_DRUM4 = 4 + }; + static bool _is_defined_sound_source_t(sound_source_t v); + +private: + static const std::set _values_sound_source_t; + +public: + + enum tap_averaging_t { + TAP_AVERAGING_TAP_AVG_2 = 0, + TAP_AVERAGING_TAP_AVG_3 = 1, + TAP_AVERAGING_TAP_AVG_4 = 2 + }; + static bool _is_defined_tap_averaging_t(tap_averaging_t v); + +private: + static const std::set _values_tap_averaging_t; + +public: + + enum time_display_style_t { + TIME_DISPLAY_STYLE_BAR_BEAT_CLOCK = 0, + TIME_DISPLAY_STYLE_HOUR_MINUTE_SEC = 1 + }; + static bool _is_defined_time_display_style_t(time_display_style_t v); + +private: + static const std::set _values_time_display_style_t; + +public: + + enum timing_correct_t { + TIMING_CORRECT_FALSE = 0, + TIMING_CORRECT_ONE_8 = 1, + TIMING_CORRECT_ONE_8_3 = 2, + TIMING_CORRECT_ONE_16 = 3, + TIMING_CORRECT_ONE_16_3 = 4, + TIMING_CORRECT_ONE_32 = 5, + TIMING_CORRECT_ONE_32_3 = 6 + }; + static bool _is_defined_timing_correct_t(timing_correct_t v); + +private: + static const std::set _values_timing_correct_t; + +public: + + enum unused_used_t { + UNUSED_USED_UNUSED = 0, + UNUSED_USED_USED = 1 + }; + static bool _is_defined_unused_used_t(unused_used_t v); + +private: + static const std::set _values_unused_used_t; + +public: + +private: + bool m__dirty; + +public: + + mpc2000xl_all_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~mpc2000xl_all_t(); + + class bar_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + bar_t(int32_t p_idx, kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~bar_t(); + int32_t denominator(); + void _invalidate_denominator() { f_denominator = false; } + int32_t first_tick(); + void _invalidate_first_tick() { f_first_tick = false; } + int32_t numerator(); + void _invalidate_numerator() { f_numerator = false; } + uint8_t ticks_per_beat() const { return m_ticks_per_beat; } + void set_ticks_per_beat(uint8_t _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m_ticks_per_beat = std::move(_v); } + uint64_t last_tick() const { return m_last_tick; } + void set_last_tick(uint64_t _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m_last_tick = std::move(_v); } + int32_t idx() const { return m_idx; } + void set_idx(int32_t _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m_idx = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m__root = std::move(_v); } + mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m__parent = std::move(_v); } + + private: + bool f_denominator; + int32_t m_denominator; + bool f_first_tick; + int32_t m_first_tick; + bool f_numerator; + int32_t m_numerator; + uint8_t m_ticks_per_beat; + uint64_t m_last_tick; + int32_t m_idx; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::sequence_body_t* m__parent; + }; + + class ch_pressure_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + ch_pressure_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~ch_pressure_event_t(); + uint8_t pressure() const { return m_pressure; } + void set_pressure(uint8_t _v) { m__dirty = true; m_pressure = std::move(_v); } + std::string _unnamed1() const { return m__unnamed1; } + void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_pressure; + std::string m__unnamed1; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::event_t* m__parent; + }; + + class control_change_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + control_change_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~control_change_event_t(); + controller_t controller() const { return m_controller; } + void set_controller(controller_t _v) { m__dirty = true; m_controller = std::move(_v); } + uint8_t value() const { return m_value; } + void set_value(uint8_t _v) { m__dirty = true; m_value = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + controller_t m_controller; + uint8_t m_value; + std::string m__unnamed2; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::event_t* m__parent; + }; + + class count_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + count_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~count_t(); + bool enabled() const { return m_enabled; } + void set_enabled(bool _v) { m__dirty = true; m_enabled = std::move(_v); } + uint64_t _unnamed1() const { return m__unnamed1; } + void set__unnamed1(uint64_t _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + count_in_mode_t count_in_mode() const { return m_count_in_mode; } + void set_count_in_mode(count_in_mode_t _v) { m__dirty = true; m_count_in_mode = std::move(_v); } + uint8_t click_volume() const { return m_click_volume; } + void set_click_volume(uint8_t _v) { m__dirty = true; m_click_volume = std::move(_v); } + rate_t rate() const { return m_rate; } + void set_rate(rate_t _v) { m__dirty = true; m_rate = std::move(_v); } + bool enabled_in_play() const { return m_enabled_in_play; } + void set_enabled_in_play(bool _v) { m__dirty = true; m_enabled_in_play = std::move(_v); } + uint64_t _unnamed6() const { return m__unnamed6; } + void set__unnamed6(uint64_t _v) { m__dirty = true; m__unnamed6 = std::move(_v); } + bool enabled_in_rec() const { return m_enabled_in_rec; } + void set_enabled_in_rec(bool _v) { m__dirty = true; m_enabled_in_rec = std::move(_v); } + uint64_t _unnamed8() const { return m__unnamed8; } + void set__unnamed8(uint64_t _v) { m__dirty = true; m__unnamed8 = std::move(_v); } + click_output_t click_output() const { return m_click_output; } + void set_click_output(click_output_t _v) { m__dirty = true; m_click_output = std::move(_v); } + bool wait_for_key() const { return m_wait_for_key; } + void set_wait_for_key(bool _v) { m__dirty = true; m_wait_for_key = std::move(_v); } + uint64_t _unnamed11() const { return m__unnamed11; } + void set__unnamed11(uint64_t _v) { m__dirty = true; m__unnamed11 = std::move(_v); } + sound_source_t sound_source() const { return m_sound_source; } + void set_sound_source(sound_source_t _v) { m__dirty = true; m_sound_source = std::move(_v); } + uint8_t accent_pad_index() const { return m_accent_pad_index; } + void set_accent_pad_index(uint8_t _v) { m__dirty = true; m_accent_pad_index = std::move(_v); } + uint8_t normal_pad_index() const { return m_normal_pad_index; } + void set_normal_pad_index(uint8_t _v) { m__dirty = true; m_normal_pad_index = std::move(_v); } + uint8_t accent_velo() const { return m_accent_velo; } + void set_accent_velo(uint8_t _v) { m__dirty = true; m_accent_velo = std::move(_v); } + uint8_t normal_velo() const { return m_normal_velo; } + void set_normal_velo(uint8_t _v) { m__dirty = true; m_normal_velo = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + bool m_enabled; + uint64_t m__unnamed1; + count_in_mode_t m_count_in_mode; + uint8_t m_click_volume; + rate_t m_rate; + bool m_enabled_in_play; + uint64_t m__unnamed6; + bool m_enabled_in_rec; + uint64_t m__unnamed8; + click_output_t m_click_output; + bool m_wait_for_key; + uint64_t m__unnamed11; + sound_source_t m_sound_source; + uint8_t m_accent_pad_index; + uint8_t m_normal_pad_index; + uint8_t m_accent_velo; + uint8_t m_normal_velo; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class defaults_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + defaults_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~defaults_t(); + std::string sequence_name() const { return m_sequence_name; } + void set_sequence_name(std::string _v) { m__dirty = true; m_sequence_name = std::move(_v); } + std::string _unnamed1() const { return m__unnamed1; } + void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + uint16_t tempo() const { return m_tempo; } + void set_tempo(uint16_t _v) { m__dirty = true; m_tempo = std::move(_v); } + uint8_t numerator() const { return m_numerator; } + void set_numerator(uint8_t _v) { m__dirty = true; m_numerator = std::move(_v); } + uint8_t denominator() const { return m_denominator; } + void set_denominator(uint8_t _v) { m__dirty = true; m_denominator = std::move(_v); } + uint16_t bar_count() const { return m_bar_count; } + void set_bar_count(uint16_t _v) { m__dirty = true; m_bar_count = std::move(_v); } + uint16_t tick_count() const { return m_tick_count; } + void set_tick_count(uint16_t _v) { m__dirty = true; m_tick_count = std::move(_v); } + std::vector* unknown1() const { return m_unknown1.get(); } + void set_unknown1(std::unique_ptr> _v) { m__dirty = true; m_unknown1 = std::move(_v); } + std::string unknown2() const { return m_unknown2; } + void set_unknown2(std::string _v) { m__dirty = true; m_unknown2 = std::move(_v); } + std::vector* device_names() const { return m_device_names.get(); } + void set_device_names(std::unique_ptr> _v) { m__dirty = true; m_device_names = std::move(_v); } + std::vector* track_names() const { return m_track_names.get(); } + void set_track_names(std::unique_ptr> _v) { m__dirty = true; m_track_names = std::move(_v); } + std::vector* devices() const { return m_devices.get(); } + void set_devices(std::unique_ptr> _v) { m__dirty = true; m_devices = std::move(_v); } + std::vector* buses() const { return m_buses.get(); } + void set_buses(std::unique_ptr> _v) { m__dirty = true; m_buses = std::move(_v); } + std::vector* programs() const { return m_programs.get(); } + void set_programs(std::unique_ptr> _v) { m__dirty = true; m_programs = std::move(_v); } + std::vector* track_velocities() const { return m_track_velocities.get(); } + void set_track_velocities(std::unique_ptr> _v) { m__dirty = true; m_track_velocities = std::move(_v); } + std::vector>* track_statuses() const { return m_track_statuses.get(); } + void set_track_statuses(std::unique_ptr>> _v) { m__dirty = true; m_track_statuses = std::move(_v); } + std::string _unnamed16() const { return m__unnamed16; } + void set__unnamed16(std::string _v) { m__dirty = true; m__unnamed16 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m_sequence_name; + std::string m__unnamed1; + uint16_t m_tempo; + uint8_t m_numerator; + uint8_t m_denominator; + uint16_t m_bar_count; + uint16_t m_tick_count; + std::unique_ptr> m_unknown1; + std::string m_unknown2; + std::unique_ptr> m_device_names; + std::unique_ptr> m_track_names; + std::unique_ptr> m_devices; + std::unique_ptr> m_buses; + std::unique_ptr> m_programs; + std::unique_ptr> m_track_velocities; + std::unique_ptr>> m_track_statuses; + std::string m__unnamed16; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + event_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~event_t(); + uint64_t tick() const { return m_tick; } + void set_tick(uint64_t _v) { m__dirty = true; m_tick = std::move(_v); } + uint64_t duration_bits_1() const { return m_duration_bits_1; } + void set_duration_bits_1(uint64_t _v) { m__dirty = true; n_duration_bits_1 = false; m_duration_bits_1 = std::move(_v); } + uint64_t track() const { return m_track; } + void set_track(uint64_t _v) { m__dirty = true; n_track = false; m_track = std::move(_v); } + uint64_t duration_bits_2() const { return m_duration_bits_2; } + void set_duration_bits_2(uint64_t _v) { m__dirty = true; n_duration_bits_2 = false; m_duration_bits_2 = std::move(_v); } + uint8_t id() const { return m_id; } + void set_id(uint8_t _v) { m__dirty = true; n_id = false; m_id = std::move(_v); } + uint64_t terminator_pad() const { return m_terminator_pad; } + void set_terminator_pad(uint64_t _v) { m__dirty = true; n_terminator_pad = false; m_terminator_pad = std::move(_v); } + note_event_t* note_event() const { return m_note_event.get(); } + void set_note_event(std::unique_ptr _v) { m__dirty = true; m_note_event = std::move(_v); } + pitch_bend_event_t* pitch_bend() const { return m_pitch_bend.get(); } + void set_pitch_bend(std::unique_ptr _v) { m__dirty = true; m_pitch_bend = std::move(_v); } + control_change_event_t* control_change() const { return m_control_change.get(); } + void set_control_change(std::unique_ptr _v) { m__dirty = true; m_control_change = std::move(_v); } + program_change_event_t* program_change() const { return m_program_change.get(); } + void set_program_change(std::unique_ptr _v) { m__dirty = true; m_program_change = std::move(_v); } + ch_pressure_event_t* ch_pressure() const { return m_ch_pressure.get(); } + void set_ch_pressure(std::unique_ptr _v) { m__dirty = true; m_ch_pressure = std::move(_v); } + poly_pressure_event_t* poly_pressure() const { return m_poly_pressure.get(); } + void set_poly_pressure(std::unique_ptr _v) { m__dirty = true; m_poly_pressure = std::move(_v); } + exclusive_event_t* exclusive() const { return m_exclusive.get(); } + void set_exclusive(std::unique_ptr _v) { m__dirty = true; m_exclusive = std::move(_v); } + std::string terminator() const { return m_terminator; } + void set_terminator(std::string _v) { m__dirty = true; n_terminator = false; m_terminator = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint64_t m_tick; + uint64_t m_duration_bits_1; + bool n_duration_bits_1; + + public: + bool _is_null_duration_bits_1() { duration_bits_1(); return n_duration_bits_1; }; + + private: + uint64_t m_track; + bool n_track; + + public: + bool _is_null_track() { track(); return n_track; }; + + private: + uint64_t m_duration_bits_2; + bool n_duration_bits_2; + + public: + bool _is_null_duration_bits_2() { duration_bits_2(); return n_duration_bits_2; }; + + private: + uint8_t m_id; + bool n_id; + + public: + bool _is_null_id() { id(); return n_id; }; + + private: + uint64_t m_terminator_pad; + bool n_terminator_pad; + + public: + bool _is_null_terminator_pad() { terminator_pad(); return n_terminator_pad; }; + + private: + std::unique_ptr m_note_event; + + public: + bool _is_null_note_event() { return !note_event(); }; + + private: + std::unique_ptr m_pitch_bend; + + public: + bool _is_null_pitch_bend() { return !pitch_bend(); }; + + private: + std::unique_ptr m_control_change; + + public: + bool _is_null_control_change() { return !control_change(); }; + + private: + std::unique_ptr m_program_change; + + public: + bool _is_null_program_change() { return !program_change(); }; + + private: + std::unique_ptr m_ch_pressure; + + public: + bool _is_null_ch_pressure() { return !ch_pressure(); }; + + private: + std::unique_ptr m_poly_pressure; + + public: + bool _is_null_poly_pressure() { return !poly_pressure(); }; + + private: + std::unique_ptr m_exclusive; + + public: + bool _is_null_exclusive() { return !exclusive(); }; + + private: + std::string m_terminator; + bool n_terminator; + + public: + bool _is_null_terminator() { terminator(); return n_terminator; }; + + private: + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::sequence_body_t* m__parent; + }; + + class exclusive_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + exclusive_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~exclusive_event_t(); + std::string _unnamed0() const { return m__unnamed0; } + void set__unnamed0(std::string _v) { m__dirty = true; m__unnamed0 = std::move(_v); } + std::string bytes() const { return m_bytes; } + void set_bytes(std::string _v) { m__dirty = true; m_bytes = std::move(_v); } + mixer_event_t* mixer() const { return m_mixer.get(); } + void set_mixer(std::unique_ptr _v) { m__dirty = true; m_mixer = std::move(_v); } + std::string _unnamed3() const { return m__unnamed3; } + void set__unnamed3(std::string _v) { m__dirty = true; m__unnamed3 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m__unnamed0; + std::string m_bytes; + std::unique_ptr m_mixer; + + public: + bool _is_null_mixer() { return !mixer(); }; + + private: + std::string m__unnamed3; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::event_t* m__parent; + }; + + class location_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + location_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~location_t(); + std::string display_value(); + void _invalidate_display_value() { f_display_value = false; } + uint16_t bar() const { return m_bar; } + void set_bar(uint16_t _v) { m__dirty = true; f_display_value = false; m_bar = std::move(_v); } + uint8_t beat() const { return m_beat; } + void set_beat(uint8_t _v) { m__dirty = true; f_display_value = false; m_beat = std::move(_v); } + uint8_t clock() const { return m_clock; } + void set_clock(uint8_t _v) { m__dirty = true; f_display_value = false; m_clock = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_display_value = false; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; f_display_value = false; m__parent = std::move(_v); } + + private: + bool f_display_value; + std::string m_display_value; + uint16_t m_bar; + uint8_t m_beat; + uint8_t m_clock; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class midi_input_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + midi_input_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~midi_input_t(); + midi_input_receive_channel_t receive_channel() const { return m_receive_channel; } + void set_receive_channel(midi_input_receive_channel_t _v) { m__dirty = true; m_receive_channel = std::move(_v); } + bool sustain_pedal_to_duration() const { return m_sustain_pedal_to_duration; } + void set_sustain_pedal_to_duration(bool _v) { m__dirty = true; m_sustain_pedal_to_duration = std::move(_v); } + uint64_t _unnamed2() const { return m__unnamed2; } + void set__unnamed2(uint64_t _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + bool filter_enabled() const { return m_filter_enabled; } + void set_filter_enabled(bool _v) { m__dirty = true; m_filter_enabled = std::move(_v); } + uint64_t _unnamed4() const { return m__unnamed4; } + void set__unnamed4(uint64_t _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + midi_input_filter_type_t filter_type() const { return m_filter_type; } + void set_filter_type(midi_input_filter_type_t _v) { m__dirty = true; m_filter_type = std::move(_v); } + bool multi_rec_enabled() const { return m_multi_rec_enabled; } + void set_multi_rec_enabled(bool _v) { m__dirty = true; m_multi_rec_enabled = std::move(_v); } + uint64_t _unnamed7() const { return m__unnamed7; } + void set__unnamed7(uint64_t _v) { m__dirty = true; m__unnamed7 = std::move(_v); } + std::vector* multi_rec_destination_tracks() const { return m_multi_rec_destination_tracks.get(); } + void set_multi_rec_destination_tracks(std::unique_ptr> _v) { m__dirty = true; m_multi_rec_destination_tracks = std::move(_v); } + bool note_pass_enabled() const { return m_note_pass_enabled; } + void set_note_pass_enabled(bool _v) { m__dirty = true; m_note_pass_enabled = std::move(_v); } + uint64_t _unnamed10() const { return m__unnamed10; } + void set__unnamed10(uint64_t _v) { m__dirty = true; m__unnamed10 = std::move(_v); } + bool pitch_bend_pass_enabled() const { return m_pitch_bend_pass_enabled; } + void set_pitch_bend_pass_enabled(bool _v) { m__dirty = true; m_pitch_bend_pass_enabled = std::move(_v); } + uint64_t _unnamed12() const { return m__unnamed12; } + void set__unnamed12(uint64_t _v) { m__dirty = true; m__unnamed12 = std::move(_v); } + bool pgm_change_pass_enabled() const { return m_pgm_change_pass_enabled; } + void set_pgm_change_pass_enabled(bool _v) { m__dirty = true; m_pgm_change_pass_enabled = std::move(_v); } + uint64_t _unnamed14() const { return m__unnamed14; } + void set__unnamed14(uint64_t _v) { m__dirty = true; m__unnamed14 = std::move(_v); } + bool ch_pressure_pass_enabled() const { return m_ch_pressure_pass_enabled; } + void set_ch_pressure_pass_enabled(bool _v) { m__dirty = true; m_ch_pressure_pass_enabled = std::move(_v); } + uint64_t _unnamed16() const { return m__unnamed16; } + void set__unnamed16(uint64_t _v) { m__dirty = true; m__unnamed16 = std::move(_v); } + bool poly_pressure_pass_enabled() const { return m_poly_pressure_pass_enabled; } + void set_poly_pressure_pass_enabled(bool _v) { m__dirty = true; m_poly_pressure_pass_enabled = std::move(_v); } + uint64_t _unnamed18() const { return m__unnamed18; } + void set__unnamed18(uint64_t _v) { m__dirty = true; m__unnamed18 = std::move(_v); } + bool exclusive_pass_enabled() const { return m_exclusive_pass_enabled; } + void set_exclusive_pass_enabled(bool _v) { m__dirty = true; m_exclusive_pass_enabled = std::move(_v); } + uint64_t _unnamed20() const { return m__unnamed20; } + void set__unnamed20(uint64_t _v) { m__dirty = true; m__unnamed20 = std::move(_v); } + std::vector* cc_pass_enabled() const { return m_cc_pass_enabled.get(); } + void set_cc_pass_enabled(std::unique_ptr> _v) { m__dirty = true; m_cc_pass_enabled = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + midi_input_receive_channel_t m_receive_channel; + bool m_sustain_pedal_to_duration; + uint64_t m__unnamed2; + bool m_filter_enabled; + uint64_t m__unnamed4; + midi_input_filter_type_t m_filter_type; + bool m_multi_rec_enabled; + uint64_t m__unnamed7; + std::unique_ptr> m_multi_rec_destination_tracks; + bool m_note_pass_enabled; + uint64_t m__unnamed10; + bool m_pitch_bend_pass_enabled; + uint64_t m__unnamed12; + bool m_pgm_change_pass_enabled; + uint64_t m__unnamed14; + bool m_ch_pressure_pass_enabled; + uint64_t m__unnamed16; + bool m_poly_pressure_pass_enabled; + uint64_t m__unnamed18; + bool m_exclusive_pass_enabled; + uint64_t m__unnamed20; + std::unique_ptr> m_cc_pass_enabled; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class midi_output_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + midi_output_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~midi_output_t(); + soft_thru_mode_t soft_thru_mode() const { return m_soft_thru_mode; } + void set_soft_thru_mode(soft_thru_mode_t _v) { m__dirty = true; m_soft_thru_mode = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + soft_thru_mode_t m_soft_thru_mode; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class midi_switch_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + midi_switch_t(kaitai::kstream* p__io, mpc2000xl_all_t::misc_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~midi_switch_t(); + uint8_t controller() const { return m_controller; } + void set_controller(uint8_t _v) { m__dirty = true; m_controller = std::move(_v); } + midi_switch_function_t function() const { return m_function; } + void set_function(midi_switch_function_t _v) { m__dirty = true; m_function = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::misc_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::misc_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_controller; + midi_switch_function_t m_function; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::misc_t* m__parent; + }; + + class midi_sync_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + midi_sync_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~midi_sync_t(); + midi_sync_mode_t in_mode() const { return m_in_mode; } + void set_in_mode(midi_sync_mode_t _v) { m__dirty = true; m_in_mode = std::move(_v); } + midi_sync_mode_t out_mode() const { return m_out_mode; } + void set_out_mode(midi_sync_mode_t _v) { m__dirty = true; m_out_mode = std::move(_v); } + uint8_t shift_early() const { return m_shift_early; } + void set_shift_early(uint8_t _v) { m__dirty = true; m_shift_early = std::move(_v); } + bool send_mmc_enabled() const { return m_send_mmc_enabled; } + void set_send_mmc_enabled(bool _v) { m__dirty = true; m_send_mmc_enabled = std::move(_v); } + uint64_t _unnamed4() const { return m__unnamed4; } + void set__unnamed4(uint64_t _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + frame_rate_t frame_rate() const { return m_frame_rate; } + void set_frame_rate(frame_rate_t _v) { m__dirty = true; m_frame_rate = std::move(_v); } + uint8_t input() const { return m_input; } + void set_input(uint8_t _v) { m__dirty = true; m_input = std::move(_v); } + midi_sync_output_t output() const { return m_output; } + void set_output(midi_sync_output_t _v) { m__dirty = true; m_output = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + midi_sync_mode_t m_in_mode; + midi_sync_mode_t m_out_mode; + uint8_t m_shift_early; + bool m_send_mmc_enabled; + uint64_t m__unnamed4; + frame_rate_t m_frame_rate; + uint8_t m_input; + midi_sync_output_t m_output; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class misc_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + misc_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~misc_t(); + tap_averaging_t tap_averaging() const { return m_tap_averaging; } + void set_tap_averaging(tap_averaging_t _v) { m__dirty = true; m_tap_averaging = std::move(_v); } + bool midi_sync_in_receive_mmc_enabled() const { return m_midi_sync_in_receive_mmc_enabled; } + void set_midi_sync_in_receive_mmc_enabled(bool _v) { m__dirty = true; m_midi_sync_in_receive_mmc_enabled = std::move(_v); } + std::vector>* midi_switch() const { return m_midi_switch.get(); } + void set_midi_switch(std::unique_ptr>> _v) { m__dirty = true; m_midi_switch = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + tap_averaging_t m_tap_averaging; + bool m_midi_sync_in_receive_mmc_enabled; + std::unique_ptr>> m_midi_switch; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class mixer_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + mixer_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::exclusive_event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~mixer_event_t(); + std::string _unnamed0() const { return m__unnamed0; } + void set__unnamed0(std::string _v) { m__dirty = true; m__unnamed0 = std::move(_v); } + mixer_event_param_t param() const { return m_param; } + void set_param(mixer_event_param_t _v) { m__dirty = true; m_param = std::move(_v); } + uint8_t pad_index() const { return m_pad_index; } + void set_pad_index(uint8_t _v) { m__dirty = true; m_pad_index = std::move(_v); } + uint8_t value() const { return m_value; } + void set_value(uint8_t _v) { m__dirty = true; m_value = std::move(_v); } + std::string _unnamed4() const { return m__unnamed4; } + void set__unnamed4(std::string _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::exclusive_event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::exclusive_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m__unnamed0; + mixer_event_param_t m_param; + uint8_t m_pad_index; + uint8_t m_value; + std::string m__unnamed4; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::exclusive_event_t* m__parent; + }; + + class note_event_t : public kaitai::kstruct { + + public: + + enum note_variation_type_t { + NOTE_VARIATION_TYPE_TUNE = 0, + NOTE_VARIATION_TYPE_DECAY = 1, + NOTE_VARIATION_TYPE_ATTACK = 2, + NOTE_VARIATION_TYPE_FILTER = 3 + }; + static bool _is_defined_note_variation_type_t(note_variation_type_t v); + + private: + static const std::set _values_note_variation_type_t; + + public: + + private: + bool m__dirty; + + public: + + note_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~note_event_t(); + int32_t duration(); + void _invalidate_duration() { f_duration = false; } + uint8_t note(); + void _invalidate_note() { f_note = false; } + mpc2000xl_all_t::note_event_t::note_variation_type_t variation_type(); + void _invalidate_variation_type() { f_variation_type = false; } + uint8_t duration_bits_3() const { return m_duration_bits_3; } + void set_duration_bits_3(uint8_t _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m_duration_bits_3 = std::move(_v); } + uint64_t velocity() const { return m_velocity; } + void set_velocity(uint64_t _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m_velocity = std::move(_v); } + bool variation_type_bit_1() const { return m_variation_type_bit_1; } + void set_variation_type_bit_1(bool _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m_variation_type_bit_1 = std::move(_v); } + uint64_t variation_value() const { return m_variation_value; } + void set_variation_value(uint64_t _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m_variation_value = std::move(_v); } + bool variation_type_bit_2() const { return m_variation_type_bit_2; } + void set_variation_type_bit_2(bool _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m_variation_type_bit_2 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m__root = std::move(_v); } + mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m__parent = std::move(_v); } + + private: + bool f_duration; + int32_t m_duration; + bool f_note; + uint8_t m_note; + bool f_variation_type; + mpc2000xl_all_t::note_event_t::note_variation_type_t m_variation_type; + uint8_t m_duration_bits_3; + uint64_t m_velocity; + bool m_variation_type_bit_1; + uint64_t m_variation_value; + bool m_variation_type_bit_2; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::event_t* m__parent; + }; + + class pitch_bend_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + pitch_bend_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~pitch_bend_event_t(); + int32_t corrected_amount(); + void _invalidate_corrected_amount() { f_corrected_amount = false; } + uint64_t amount_bits_1() const { return m_amount_bits_1; } + void set_amount_bits_1(uint64_t _v) { m__dirty = true; f_corrected_amount = false; m_amount_bits_1 = std::move(_v); } + uint64_t amount_bits_2() const { return m_amount_bits_2; } + void set_amount_bits_2(uint64_t _v) { m__dirty = true; f_corrected_amount = false; m_amount_bits_2 = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; f_corrected_amount = false; m__unnamed2 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_corrected_amount = false; m__root = std::move(_v); } + mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; f_corrected_amount = false; m__parent = std::move(_v); } + + private: + bool f_corrected_amount; + int32_t m_corrected_amount; + uint64_t m_amount_bits_1; + uint64_t m_amount_bits_2; + std::string m__unnamed2; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::event_t* m__parent; + }; + + class poly_pressure_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + poly_pressure_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~poly_pressure_event_t(); + uint8_t note() const { return m_note; } + void set_note(uint8_t _v) { m__dirty = true; m_note = std::move(_v); } + uint8_t pressure() const { return m_pressure; } + void set_pressure(uint8_t _v) { m__dirty = true; m_pressure = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_note; + uint8_t m_pressure; + std::string m__unnamed2; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::event_t* m__parent; + }; + + class program_change_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + program_change_event_t(kaitai::kstream* p__io, mpc2000xl_all_t::event_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~program_change_event_t(); + uint8_t program() const { return m_program; } + void set_program(uint8_t _v) { m__dirty = true; m_program = std::move(_v); } + std::string _unnamed1() const { return m__unnamed1; } + void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_program; + std::string m__unnamed1; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::event_t* m__parent; + }; + + class sequence_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + sequence_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sequence_t(); + std::string name(); + void _invalidate_name() { f_name = false; } + std::string name_part_1() const { return m_name_part_1; } + void set_name_part_1(std::string _v) { m__dirty = true; f_name = false; m_name_part_1 = std::move(_v); } + std::string name_part_2() const { return m_name_part_2; } + void set_name_part_2(std::string _v) { m__dirty = true; n_name_part_2 = false; f_name = false; m_name_part_2 = std::move(_v); } + sequence_body_t* body() const { return m_body.get(); } + void set_body(std::unique_ptr _v) { m__dirty = true; f_name = false; m_body = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_name = false; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; f_name = false; m__parent = std::move(_v); } + + private: + bool f_name; + std::string m_name; + bool n_name; + + public: + bool _is_null_name() { name(); return n_name; }; + + private: + std::string m_name_part_1; + std::string m_name_part_2; + bool n_name_part_2; + + public: + bool _is_null_name_part_2() { name_part_2(); return n_name_part_2; }; + + private: + std::unique_ptr m_body; + + public: + bool _is_null_body() { return !body(); }; + + private: + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class sequence_body_t : public kaitai::kstruct { + + public: + class start_time_t; + + private: + bool m__dirty; + + public: + + sequence_body_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sequence_body_t(); + + class start_time_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + start_time_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~start_time_t(); + uint8_t hours() const { return m_hours; } + void set_hours(uint8_t _v) { m__dirty = true; m_hours = std::move(_v); } + uint8_t minutes() const { return m_minutes; } + void set_minutes(uint8_t _v) { m__dirty = true; m_minutes = std::move(_v); } + uint8_t seconds() const { return m_seconds; } + void set_seconds(uint8_t _v) { m__dirty = true; m_seconds = std::move(_v); } + uint8_t frames() const { return m_frames; } + void set_frames(uint8_t _v) { m__dirty = true; m_frames = std::move(_v); } + uint8_t frame_decimals() const { return m_frame_decimals; } + void set_frame_decimals(uint8_t _v) { m__dirty = true; m_frame_decimals = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_hours; + uint8_t m_minutes; + uint8_t m_seconds; + uint8_t m_frames; + uint8_t m_frame_decimals; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::sequence_body_t* m__parent; + }; + + public: + sequence_is_used_t is_used() const { return m_is_used; } + void set_is_used(sequence_is_used_t _v) { m__dirty = true; m_is_used = std::move(_v); } + + /** + * Warning! 1-based. You'll need this to put the sequence in the right slot + */ + uint8_t index() const { return m_index; } + void set_index(uint8_t _v) { m__dirty = true; m_index = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + uint16_t bar_count() const { return m_bar_count; } + void set_bar_count(uint16_t _v) { m__dirty = true; m_bar_count = std::move(_v); } + uint32_t last_tick() const { return m_last_tick; } + void set_last_tick(uint32_t _v) { m__dirty = true; m_last_tick = std::move(_v); } + std::string _unnamed5() const { return m__unnamed5; } + void set__unnamed5(std::string _v) { m__dirty = true; m__unnamed5 = std::move(_v); } + uint16_t loop_start_bar_index() const { return m_loop_start_bar_index; } + void set_loop_start_bar_index(uint16_t _v) { m__dirty = true; m_loop_start_bar_index = std::move(_v); } + uint16_t loop_end_bar_index() const { return m_loop_end_bar_index; } + void set_loop_end_bar_index(uint16_t _v) { m__dirty = true; m_loop_end_bar_index = std::move(_v); } + bool loop_enabled() const { return m_loop_enabled; } + void set_loop_enabled(bool _v) { m__dirty = true; m_loop_enabled = std::move(_v); } + uint64_t _unnamed9() const { return m__unnamed9; } + void set__unnamed9(uint64_t _v) { m__dirty = true; m__unnamed9 = std::move(_v); } + start_time_t* start_time() const { return m_start_time.get(); } + void set_start_time(std::unique_ptr _v) { m__dirty = true; m_start_time = std::move(_v); } + std::string _unnamed11() const { return m__unnamed11; } + void set__unnamed11(std::string _v) { m__dirty = true; m__unnamed11 = std::move(_v); } + uint32_t last_tick2() const { return m_last_tick2; } + void set_last_tick2(uint32_t _v) { m__dirty = true; m_last_tick2 = std::move(_v); } + std::string _unnamed13() const { return m__unnamed13; } + void set__unnamed13(std::string _v) { m__dirty = true; m__unnamed13 = std::move(_v); } + std::vector* device_names() const { return m_device_names.get(); } + void set_device_names(std::unique_ptr> _v) { m__dirty = true; m_device_names = std::move(_v); } + tracks_t* tracks() const { return m_tracks.get(); } + void set_tracks(std::unique_ptr _v) { m__dirty = true; m_tracks = std::move(_v); } + std::string _unnamed16() const { return m__unnamed16; } + void set__unnamed16(std::string _v) { m__dirty = true; m__unnamed16 = std::move(_v); } + std::vector>* bars() const { return m_bars.get(); } + void set_bars(std::unique_ptr>> _v) { m__dirty = true; m_bars = std::move(_v); } + std::string _unnamed18() const { return m__unnamed18; } + void set__unnamed18(std::string _v) { m__dirty = true; m__unnamed18 = std::move(_v); } + std::string _unnamed19() const { return m__unnamed19; } + void set__unnamed19(std::string _v) { m__dirty = true; m__unnamed19 = std::move(_v); } + std::vector>* events() const { return m_events.get(); } + void set_events(std::unique_ptr>> _v) { m__dirty = true; m_events = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::sequence_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::sequence_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + sequence_is_used_t m_is_used; + uint8_t m_index; + std::string m__unnamed2; + uint16_t m_bar_count; + uint32_t m_last_tick; + std::string m__unnamed5; + uint16_t m_loop_start_bar_index; + uint16_t m_loop_end_bar_index; + bool m_loop_enabled; + uint64_t m__unnamed9; + std::unique_ptr m_start_time; + std::string m__unnamed11; + uint32_t m_last_tick2; + std::string m__unnamed13; + std::unique_ptr> m_device_names; + std::unique_ptr m_tracks; + std::string m__unnamed16; + std::unique_ptr>> m_bars; + std::string m__unnamed18; + std::string m__unnamed19; + std::unique_ptr>> m_events; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::sequence_t* m__parent; + }; + + class sequence_meta_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + sequence_meta_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sequence_meta_t(); + std::string name() const { return m_name; } + void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } + sequence_is_used_t is_used() const { return m_is_used; } + void set_is_used(sequence_is_used_t _v) { m__dirty = true; m_is_used = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m_name; + sequence_is_used_t m_is_used; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class sequencer_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + sequencer_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sequencer_t(); + uint8_t active_sequence() const { return m_active_sequence; } + void set_active_sequence(uint8_t _v) { m__dirty = true; m_active_sequence = std::move(_v); } + std::string _unnamed1() const { return m__unnamed1; } + void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + uint8_t active_track() const { return m_active_track; } + void set_active_track(uint8_t _v) { m__dirty = true; m_active_track = std::move(_v); } + std::string _unnamed3() const { return m__unnamed3; } + void set__unnamed3(std::string _v) { m__dirty = true; m__unnamed3 = std::move(_v); } + uint16_t master_tempo() const { return m_master_tempo; } + void set_master_tempo(uint16_t _v) { m__dirty = true; m_master_tempo = std::move(_v); } + bool tempo_source_is_sequence() const { return m_tempo_source_is_sequence; } + void set_tempo_source_is_sequence(bool _v) { m__dirty = true; m_tempo_source_is_sequence = std::move(_v); } + uint64_t _unnamed6() const { return m__unnamed6; } + void set__unnamed6(uint64_t _v) { m__dirty = true; m__unnamed6 = std::move(_v); } + timing_correct_t timing_correct() const { return m_timing_correct; } + void set_timing_correct(timing_correct_t _v) { m__dirty = true; m_timing_correct = std::move(_v); } + time_display_style_t time_display_style() const { return m_time_display_style; } + void set_time_display_style(time_display_style_t _v) { m__dirty = true; m_time_display_style = std::move(_v); } + uint64_t _unnamed9() const { return m__unnamed9; } + void set__unnamed9(uint64_t _v) { m__dirty = true; m__unnamed9 = std::move(_v); } + bool second_sequence_enabled() const { return m_second_sequence_enabled; } + void set_second_sequence_enabled(bool _v) { m__dirty = true; m_second_sequence_enabled = std::move(_v); } + uint64_t _unnamed11() const { return m__unnamed11; } + void set__unnamed11(uint64_t _v) { m__dirty = true; m__unnamed11 = std::move(_v); } + uint8_t sequence_sequence_index() const { return m_sequence_sequence_index; } + void set_sequence_sequence_index(uint8_t _v) { m__dirty = true; m_sequence_sequence_index = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_active_sequence; + std::string m__unnamed1; + uint8_t m_active_track; + std::string m__unnamed3; + uint16_t m_master_tempo; + bool m_tempo_source_is_sequence; + uint64_t m__unnamed6; + timing_correct_t m_timing_correct; + time_display_style_t m_time_display_style; + uint64_t m__unnamed9; + bool m_second_sequence_enabled; + uint64_t m__unnamed11; + uint8_t m_sequence_sequence_index; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class song_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + song_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~song_t(); + std::string name() const { return m_name; } + void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } + std::vector>* steps() const { return m_steps.get(); } + void set_steps(std::unique_ptr>> _v) { m__dirty = true; m_steps = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + bool is_used() const { return m_is_used; } + void set_is_used(bool _v) { m__dirty = true; m_is_used = std::move(_v); } + uint8_t loop_first_step() const { return m_loop_first_step; } + void set_loop_first_step(uint8_t _v) { m__dirty = true; m_loop_first_step = std::move(_v); } + uint8_t loop_last_step() const { return m_loop_last_step; } + void set_loop_last_step(uint8_t _v) { m__dirty = true; m_loop_last_step = std::move(_v); } + bool is_loop_enabled() const { return m_is_loop_enabled; } + void set_is_loop_enabled(bool _v) { m__dirty = true; m_is_loop_enabled = std::move(_v); } + std::string _unnamed7() const { return m__unnamed7; } + void set__unnamed7(std::string _v) { m__dirty = true; m__unnamed7 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m_name; + std::unique_ptr>> m_steps; + std::string m__unnamed2; + bool m_is_used; + uint8_t m_loop_first_step; + uint8_t m_loop_last_step; + bool m_is_loop_enabled; + std::string m__unnamed7; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class song_global_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + song_global_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~song_global_t(); + std::string default_song_name() const { return m_default_song_name; } + void set_default_song_name(std::string _v) { m__dirty = true; m_default_song_name = std::move(_v); } + bool ignore_tempo_change_events_in_sequence() const { return m_ignore_tempo_change_events_in_sequence; } + void set_ignore_tempo_change_events_in_sequence(bool _v) { m__dirty = true; m_ignore_tempo_change_events_in_sequence = std::move(_v); } + uint64_t _unnamed2() const { return m__unnamed2; } + void set__unnamed2(uint64_t _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m_default_song_name; + bool m_ignore_tempo_change_events_in_sequence; + uint64_t m__unnamed2; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class song_step_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + song_step_t(kaitai::kstream* p__io, mpc2000xl_all_t::song_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~song_step_t(); + uint8_t sequence_index() const { return m_sequence_index; } + void set_sequence_index(uint8_t _v) { m__dirty = true; m_sequence_index = std::move(_v); } + uint8_t repeat_count() const { return m_repeat_count; } + void set_repeat_count(uint8_t _v) { m__dirty = true; m_repeat_count = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::song_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::song_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_sequence_index; + uint8_t m_repeat_count; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::song_t* m__parent; + }; + + class step_edit_options_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + step_edit_options_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~step_edit_options_t(); + bool auto_step_increment() const { return m_auto_step_increment; } + void set_auto_step_increment(bool _v) { m__dirty = true; m_auto_step_increment = std::move(_v); } + duration_of_recorded_notes_t duration_of_recorded_notes() const { return m_duration_of_recorded_notes; } + void set_duration_of_recorded_notes(duration_of_recorded_notes_t _v) { m__dirty = true; m_duration_of_recorded_notes = std::move(_v); } + uint8_t tc_value_percentage() const { return m_tc_value_percentage; } + void set_tc_value_percentage(uint8_t _v) { m__dirty = true; m_tc_value_percentage = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + bool m_auto_step_increment; + duration_of_recorded_notes_t m_duration_of_recorded_notes; + uint8_t m_tc_value_percentage; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t* m__parent; + }; + + class track_status_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + track_status_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~track_status_t(); + unused_used_t unused_or_used() const { return m_unused_or_used; } + void set_unused_or_used(unused_used_t _v) { m__dirty = true; m_unused_or_used = std::move(_v); } + off_on_t off_or_on() const { return m_off_or_on; } + void set_off_or_on(off_on_t _v) { m__dirty = true; m_off_or_on = std::move(_v); } + off_on_t transmit_program_changes() const { return m_transmit_program_changes; } + void set_transmit_program_changes(off_on_t _v) { m__dirty = true; m_transmit_program_changes = std::move(_v); } + uint64_t _unnamed3() const { return m__unnamed3; } + void set__unnamed3(uint64_t _v) { m__dirty = true; m__unnamed3 = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + unused_used_t m_unused_or_used; + off_on_t m_off_or_on; + off_on_t m_transmit_program_changes; + uint64_t m__unnamed3; + mpc2000xl_all_t* m__root; + kaitai::kstruct* m__parent; + }; + + class tracks_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + tracks_t(kaitai::kstream* p__io, mpc2000xl_all_t::sequence_body_t* p__parent = nullptr, mpc2000xl_all_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~tracks_t(); + std::vector* names() const { return m_names.get(); } + void set_names(std::unique_ptr> _v) { m__dirty = true; m_names = std::move(_v); } + std::vector* device() const { return m_device.get(); } + void set_device(std::unique_ptr> _v) { m__dirty = true; m_device = std::move(_v); } + std::vector* bus() const { return m_bus.get(); } + void set_bus(std::unique_ptr> _v) { m__dirty = true; m_bus = std::move(_v); } + std::vector* program_change() const { return m_program_change.get(); } + void set_program_change(std::unique_ptr> _v) { m__dirty = true; m_program_change = std::move(_v); } + std::vector* velocity_ratio() const { return m_velocity_ratio.get(); } + void set_velocity_ratio(std::unique_ptr> _v) { m__dirty = true; m_velocity_ratio = std::move(_v); } + std::vector>* status() const { return m_status.get(); } + void set_status(std::unique_ptr>> _v) { m__dirty = true; m_status = std::move(_v); } + std::string unknown() const { return m_unknown; } + void set_unknown(std::string _v) { m__dirty = true; m_unknown = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::unique_ptr> m_names; + std::unique_ptr> m_device; + std::unique_ptr> m_bus; + std::unique_ptr> m_program_change; + std::unique_ptr> m_velocity_ratio; + std::unique_ptr>> m_status; + std::string m_unknown; + mpc2000xl_all_t* m__root; + mpc2000xl_all_t::sequence_body_t* m__parent; + }; + +public: + std::string magic() const { return m_magic; } + void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } + defaults_t* defaults() const { return m_defaults.get(); } + void set_defaults(std::unique_ptr _v) { m__dirty = true; m_defaults = std::move(_v); } + sequencer_t* sequencer() const { return m_sequencer.get(); } + void set_sequencer(std::unique_ptr _v) { m__dirty = true; m_sequencer = std::move(_v); } + std::string _unnamed3() const { return m__unnamed3; } + void set__unnamed3(std::string _v) { m__dirty = true; m__unnamed3 = std::move(_v); } + count_t* count() const { return m_count.get(); } + void set_count(std::unique_ptr _v) { m__dirty = true; m_count = std::move(_v); } + midi_output_t* midi_output() const { return m_midi_output.get(); } + void set_midi_output(std::unique_ptr _v) { m__dirty = true; m_midi_output = std::move(_v); } + midi_input_t* midi_input() const { return m_midi_input.get(); } + void set_midi_input(std::unique_ptr _v) { m__dirty = true; m_midi_input = std::move(_v); } + midi_sync_t* midi_sync() const { return m_midi_sync.get(); } + void set_midi_sync(std::unique_ptr _v) { m__dirty = true; m_midi_sync = std::move(_v); } + song_global_t* song_global() const { return m_song_global.get(); } + void set_song_global(std::unique_ptr _v) { m__dirty = true; m_song_global = std::move(_v); } + std::string _unnamed9() const { return m__unnamed9; } + void set__unnamed9(std::string _v) { m__dirty = true; m__unnamed9 = std::move(_v); } + std::vector>* locations() const { return m_locations.get(); } + void set_locations(std::unique_ptr>> _v) { m__dirty = true; m_locations = std::move(_v); } + misc_t* misc() const { return m_misc.get(); } + void set_misc(std::unique_ptr _v) { m__dirty = true; m_misc = std::move(_v); } + std::string _unnamed12() const { return m__unnamed12; } + void set__unnamed12(std::string _v) { m__dirty = true; m__unnamed12 = std::move(_v); } + step_edit_options_t* step_edit_options() const { return m_step_edit_options.get(); } + void set_step_edit_options(std::unique_ptr _v) { m__dirty = true; m_step_edit_options = std::move(_v); } + bool prog_change_to_seq() const { return m_prog_change_to_seq; } + void set_prog_change_to_seq(bool _v) { m__dirty = true; m_prog_change_to_seq = std::move(_v); } + std::string _unnamed15() const { return m__unnamed15; } + void set__unnamed15(std::string _v) { m__dirty = true; m__unnamed15 = std::move(_v); } + std::vector>* sequences_metas() const { return m_sequences_metas.get(); } + void set_sequences_metas(std::unique_ptr>> _v) { m__dirty = true; m_sequences_metas = std::move(_v); } + std::vector>* songs() const { return m_songs.get(); } + void set_songs(std::unique_ptr>> _v) { m__dirty = true; m_songs = std::move(_v); } + std::vector>* sequences() const { return m_sequences.get(); } + void set_sequences(std::unique_ptr>> _v) { m__dirty = true; m_sequences = std::move(_v); } + mpc2000xl_all_t* _root() const { return m__root; } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; m__parent = std::move(_v); } + +private: + std::string m_magic; + std::unique_ptr m_defaults; + std::unique_ptr m_sequencer; + std::string m__unnamed3; + std::unique_ptr m_count; + std::unique_ptr m_midi_output; + std::unique_ptr m_midi_input; + std::unique_ptr m_midi_sync; + std::unique_ptr m_song_global; + std::string m__unnamed9; + std::unique_ptr>> m_locations; + std::unique_ptr m_misc; + std::string m__unnamed12; + std::unique_ptr m_step_edit_options; + bool m_prog_change_to_seq; + std::string m__unnamed15; + std::unique_ptr>> m_sequences_metas; + std::unique_ptr>> m_songs; + std::unique_ptr>> m_sequences; + mpc2000xl_all_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/test/KaitaiAllTest.cpp b/src/test/KaitaiAllTest.cpp new file mode 100644 index 00000000..05594170 --- /dev/null +++ b/src/test/KaitaiAllTest.cpp @@ -0,0 +1,166 @@ +#include + +#include "TestMpc.hpp" +#include "Mpc.hpp" +#include "disk/AbstractDisk.hpp" +#include "disk/AllLoader.hpp" +#include "disk/MpcFile.hpp" +#include "file/all/AllParser.hpp" +#include "file/kaitai/generated/mpc2000xl_all.h" +#include "sequencer/Sequence.hpp" +#include "sequencer/Sequencer.hpp" +#include "sequencer/SequencerStateManager.hpp" + +#include +#include + +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +namespace { + +void prepareAllResources(mpc::Mpc& mpc) +{ + auto disk = mpc.getDisk(); + auto fs = cmrc::mpctest::get_filesystem(); + + for (auto&& entry : fs.iterate_directory("test/AllLoading")) { + auto file = fs.open("test/AllLoading/" + entry.filename()); + std::vector data(file.begin(), file.end()); + auto newFile = disk->newFile(entry.filename()); + newFile->setFileData(data); + } + + disk->initFiles(); +} + +} + +TEST_CASE("Kaitai MPC2000 ALL parses and rewrites real 2KXL ALL", "[kaitai-all][real-2kxl]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc2000xl/All/ALL.ALL"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.defaults() != nullptr); + REQUIRE(parsed.defaults()->tempo() == 1162); + REQUIRE(parsed.defaults()->numerator() == 4); + REQUIRE(parsed.defaults()->denominator() == 4); + REQUIRE(parsed.defaults()->buses() != nullptr); + REQUIRE(parsed.defaults()->devices() != nullptr); + REQUIRE(parsed.defaults()->buses()->at(0) == mpc2000xl_all_t::BUS_DRUM2); + REQUIRE(parsed.defaults()->devices()->at(0) == 7); + + REQUIRE(parsed.sequences_metas() != nullptr); + REQUIRE(parsed.sequences() != nullptr); + REQUIRE(parsed.sequences_metas()->size() >= 2U); + REQUIRE(parsed.sequences()->size() >= 2U); + REQUIRE(parsed.sequences_metas()->at(0)->is_used() == mpc2000xl_all_t::SEQUENCE_IS_USED_TRUE); + REQUIRE(parsed.sequences_metas()->at(1)->is_used() == mpc2000xl_all_t::SEQUENCE_IS_USED_TRUE); + std::vector usedSequenceBodies; + for (const auto& seq : *parsed.sequences()) { + if (seq->body() != nullptr) { + usedSequenceBodies.push_back(seq->body()); + } + } + REQUIRE(usedSequenceBodies.size() == 2U); + REQUIRE(usedSequenceBodies.at(0)->index() == 1); + REQUIRE(usedSequenceBodies.at(1)->index() == 2); + REQUIRE(usedSequenceBodies.at(0)->tracks() != nullptr); + REQUIRE(usedSequenceBodies.at(1)->tracks() != nullptr); + REQUIRE(usedSequenceBodies.at(0)->tracks()->bus()->at(0) == mpc2000xl_all_t::BUS_DRUM2); + REQUIRE(usedSequenceBodies.at(1)->tracks()->bus()->at(0) == mpc2000xl_all_t::BUS_DRUM2); + REQUIRE(usedSequenceBodies.at(0)->tracks()->device()->at(0) == 7); + REQUIRE(usedSequenceBodies.at(1)->tracks()->device()->at(0) == 7); + + REQUIRE(parsed.songs() != nullptr); + REQUIRE(parsed.songs()->size() >= 2U); + REQUIRE(parsed.songs()->at(0)->is_used()); + REQUIRE(parsed.songs()->at(1)->is_used()); + REQUIRE(parsed.songs()->at(0)->steps() != nullptr); + REQUIRE(parsed.songs()->at(1)->steps() != nullptr); + REQUIRE(parsed.songs()->at(0)->steps()->at(0)->sequence_index() == 0); + REQUIRE(parsed.songs()->at(0)->steps()->at(0)->repeat_count() == 1); + REQUIRE(parsed.songs()->at(0)->steps()->at(1)->sequence_index() == 1); + REQUIRE(parsed.songs()->at(0)->steps()->at(1)->repeat_count() == 1); + REQUIRE(parsed.songs()->at(1)->steps()->at(0)->sequence_index() == 1); + REQUIRE(parsed.songs()->at(1)->steps()->at(0)->repeat_count() == 2); + REQUIRE(parsed.songs()->at(1)->steps()->at(1)->sequence_index() == 0); + REQUIRE(parsed.songs()->at(1)->steps()->at(1)->repeat_count() == 3); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + REQUIRE(rewrittenBytes.size() == originalBytes.size()); + REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); +} + +TEST_CASE("Kaitai MPC2000 ALL matches handwritten ALL bytes", "[kaitai-all]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + prepareAllResources(mpc); + + auto allFile = mpc.getDisk()->getFile("ShouldLoadSeq21.ALL"); + REQUIRE(allFile); + + mpc::file::all::AllParser handwrittenLoader(mpc, allFile->getBytes()); + mpc::disk::AllLoader::loadEverythingFromAllParser(mpc, handwrittenLoader); + mpc.getSequencer()->getStateManager()->drainQueue(); + + REQUIRE(mpc.getSequencer()->getSequence(0)->isUsed()); + REQUIRE(mpc.getSequencer()->getSequence(20)->isUsed()); + + mpc::file::all::AllParser handwrittenWriter(mpc); + const auto handwrittenBytes = handwrittenWriter.getBytes(); + + std::stringstream parseStream( + std::string(handwrittenBytes.begin(), handwrittenBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.sequences_metas() != nullptr); + REQUIRE(parsed.sequences_metas()->at(0)->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE); + REQUIRE(parsed.sequences_metas()->at(20)->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto kaitaiBytes = writeStream.str(); + REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); + + mpc::Mpc reparsedMpc; + mpc::TestMpc::initializeTestMpc(reparsedMpc); + std::vector kaitaiBytesVec(kaitaiBytes.begin(), kaitaiBytes.end()); + mpc::file::all::AllParser reparsed(reparsedMpc, kaitaiBytesVec); + mpc::disk::AllLoader::loadEverythingFromAllParser(reparsedMpc, reparsed); + reparsedMpc.getSequencer()->getStateManager()->drainQueue(); + + REQUIRE(reparsedMpc.getSequencer()->getSequence(0)->isUsed()); + REQUIRE(reparsedMpc.getSequencer()->getSequence(20)->isUsed()); +} diff --git a/test-resources/RealMpc2000xl/All/ALL.ALL b/test-resources/RealMpc2000xl/All/ALL.ALL new file mode 100755 index 0000000000000000000000000000000000000000..cc349e0f17ebae31fa88d87225e6c48a32a27598 GIT binary patch literal 34918 zcmeI5%Wl&^6ox%cXt|X8{niFnWdX{}*lxQ6!Hysy6(p8LNmL=EAV6hHDp>I}JXRk9 zDcH`L1pgA9C`OUU{3FHV$v7wf`R3T;NOR&BFQ1y{Z#u0folZ+XYPWa$9}oJ2Zoef( zMUhg`k7l!(@8xCqeZBIEqS0vFQ+Ch2ao_i>|K(k`-_}wasjbwB)Tz{&)LT+-OT9C$ zbz5q&r^TKYds^&iv8TnJ7JFLkX|ZR-o)LRS>>06V#GVm*M(i1}XT+WndsggOv1iSz zPj9>LAGWpQA#DR~3+)8jDYP?aZ$Wz-+B?;@ZbKXNY0#%Zp9Xyz^l8wiL7xVF8uS^^ zXF#6;eFpRy&}TrO0euGa8PI1yp9Osu^jXknL7xSE7W7%rXF;C@eHQd3pf3S^3Fu2e zUjq6P(3gO|1oS1KF9Cfi=u1Ig3i?vemx8_&^rfIL1$`;#OF>@-`ZCa$fxZm%WfOg? zHA`Hx%zXiu5B6%7m71ll{^IjLo2pUNYsIE0O7-$hx%>68D)&^}Xr5SEJ$dT%nYFX$ z&R@8A>GGAU*RJ2VdF%F_yXzaRd-uo3kD!$1qG(z`7X^fepCFUB-h4P+;ARhrkBh<1XXD11PX=#zSBO?s1p# z-~kj^H{&6&0r$Aec<=xUtef!=*noT7WjuHQ1=h`Y2yDPT?oQ)jk|Q8_FL{oHa#@4J zd>PfRZyV*yWe@(5HMkiK^Q^+@Qmd)a8TQ62Oj|9<`eW9h0Abc(kwwX@L3e(P`HqDINPq-LfCNZ@ z1W14cNPq-LV5tb~<-hs%mdYbKLjoi~0wh2JBtQZrKmsH{0wh2JBtQZrKmtMl7Ya_+ z1ImBssVG)l56GtoRM%f=_?L7(MWD)uPZ6l{;8O&uJoprWzpWeOdO+TqkN^pg011!) z36KB@kN^pg00}IJ0M`R92sFQj1W14cNPq-LfCNZ@1W14cNPq-LfCNZj@dR)^;BP@1 BK@R`` literal 0 HcmV?d00001 From f21e4afa7e1f7081b6d6cdcd7ec8ffd3d7b3fbde Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 13 Jun 2026 20:35:12 +0200 Subject: [PATCH 05/52] Add Kaitai 2KXL MID parser #342 --- .../file/kaitai/generated/mpc2000xl_mid.cpp | 287 +++++ .../file/kaitai/generated/mpc2000xl_mid.h | 142 +++ ...standard_midi_file_with_running_status.cpp | 1059 +++++++++++++++++ .../standard_midi_file_with_running_status.h | 589 +++++++++ .../file/kaitai/generated/vlq_base128_be.cpp | 125 ++ .../file/kaitai/generated/vlq_base128_be.h | 117 ++ src/test/KaitaiMidTest.cpp | 225 ++++ .../Mid/mpc2000xl_seq_variations.MID | Bin 0 -> 270 bytes 8 files changed, 2544 insertions(+) create mode 100644 src/main/file/kaitai/generated/mpc2000xl_mid.cpp create mode 100644 src/main/file/kaitai/generated/mpc2000xl_mid.h create mode 100644 src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp create mode 100644 src/main/file/kaitai/generated/standard_midi_file_with_running_status.h create mode 100644 src/main/file/kaitai/generated/vlq_base128_be.cpp create mode 100644 src/main/file/kaitai/generated/vlq_base128_be.h create mode 100644 src/test/KaitaiMidTest.cpp create mode 100755 test-resources/RealMpc2000xl/Mid/mpc2000xl_seq_variations.MID diff --git a/src/main/file/kaitai/generated/mpc2000xl_mid.cpp b/src/main/file/kaitai/generated/mpc2000xl_mid.cpp new file mode 100644 index 00000000..fc4dbb2b --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_mid.cpp @@ -0,0 +1,287 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "mpc2000xl_mid.h" +#include +#include +#include "kaitai/exceptions.h" + +mpc2000xl_mid_t::mpc2000xl_mid_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mpc2000xl_mid_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; + f_denominator = false; + f_first_meta = false; + f_is_mpc2000xl_mid = false; + f_meta_events = false; + f_numerator = false; + f_sequence_name = false; + f_sequencer = false; + f_smpte_offset = false; + f_tempo_bpm = false; + w_sequencer = false; + e_sequencer = true; +} + +void mpc2000xl_mid_t::_read() { + m_hdr = std::unique_ptr(new standard_midi_file_with_running_status_t::header_t(m__io)); + m_hdr->_read(); + m_tracks = std::unique_ptr>>(new std::vector>()); + const int l_tracks = hdr()->num_tracks(); + for (int i = 0; i < l_tracks; i++) { + std::unique_ptr _t_tracks = std::unique_ptr(new standard_midi_file_with_running_status_t::track_t(m__io)); + try { + _t_tracks->_read(); + } catch(...) { + m_tracks->push_back(std::move(_t_tracks)); + throw; + } + m_tracks->push_back(std::move(_t_tracks)); + } + m__dirty = false; +} + +void mpc2000xl_mid_t::_fetch_instances() { + m_hdr.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_tracks->size(); ++i) { + m_tracks->at(i).get()->_fetch_instances(); + } + sequencer(); + if (f_sequencer) { + m_sequencer.get()->_fetch_instances(); + } +} + +void mpc2000xl_mid_t::_write() { + w_sequencer = e_sequencer; + if (m_hdr.get() == nullptr) { + throw std::runtime_error("/seq/0: nested object is not set"); + } + m_hdr.get()->_set_io(m__io); + m_hdr.get()->_write(); + if (m_tracks == nullptr) { + throw std::runtime_error("/seq/1: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_tracks->begin(); it != m_tracks->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/1: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_mid_t::_check() { + if (m_hdr.get() == nullptr) { + throw std::runtime_error("/seq/0: nested object is not set"); + } + m_hdr.get()->_set_io(m__io); + m_hdr.get()->_check(); + if (m_tracks == nullptr) { + throw std::runtime_error("/seq/1: repeated field is not set"); + } + if (m_tracks->size() != static_cast(hdr()->num_tracks())) { + throw std::runtime_error("/seq/1: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_tracks->begin(); it != m_tracks->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/1: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (e_sequencer) { + kaitai::kstream *io = tracks()->at(0)->events()->_io(); + if (m_sequencer.get() == nullptr) { + throw std::runtime_error("/instances/sequencer: nested object is not set"); + } + m_sequencer.get()->_set_io(io); + m_sequencer.get()->_check(); + } + m__dirty = false; +} + +mpc2000xl_mid_t::~mpc2000xl_mid_t() {} + +mpc2000xl_mid_t::sequencer_t::sequencer_t(kaitai::kstream* p__io, mpc2000xl_mid_t* p__parent, mpc2000xl_mid_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc2000xl_mid_t::sequencer_t::_read() { + m__unnamed0 = m__io->read_bytes(5); + if (!(m__unnamed0 == std::string("\x4C\x4F\x4F\x50\x3D", 5))) { + throw kaitai::validation_not_equal_error(std::string("\x4C\x4F\x4F\x50\x3D", 5), m__unnamed0, m__io, std::string("/types/sequencer/seq/0")); + } + m_loop_enabled = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), "ASCII"); + m__unnamed2 = m__io->read_bytes(6); + if (!(m__unnamed2 == std::string("\x53\x54\x41\x52\x54\x3D", 6))) { + throw kaitai::validation_not_equal_error(std::string("\x53\x54\x41\x52\x54\x3D", 6), m__unnamed2, m__io, std::string("/types/sequencer/seq/2")); + } + m_loop_start = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), "ASCII"); + m__unnamed4 = m__io->read_bytes(4); + if (!(m__unnamed4 == std::string("\x45\x4E\x44\x3D", 4))) { + throw kaitai::validation_not_equal_error(std::string("\x45\x4E\x44\x3D", 4), m__unnamed4, m__io, std::string("/types/sequencer/seq/4")); + } + m_loop_end = kaitai::kstream::bytes_to_str(m__io->read_bytes(4), "ASCII"); + m__unnamed6 = m__io->read_bytes(6); + if (!(m__unnamed6 == std::string("\x54\x45\x4D\x50\x4F\x3D", 6))) { + throw kaitai::validation_not_equal_error(std::string("\x54\x45\x4D\x50\x4F\x3D", 6), m__unnamed6, m__io, std::string("/types/sequencer/seq/6")); + } + m_tempo_source = kaitai::kstream::bytes_to_str(m__io->read_bytes(3), "ASCII"); + m__dirty = false; +} + +void mpc2000xl_mid_t::sequencer_t::_fetch_instances() { +} + +void mpc2000xl_mid_t::sequencer_t::_write() { + m__io->write_bytes(m__unnamed0); + m__io->write_bytes(m_loop_enabled); + m__io->write_bytes(m__unnamed2); + m__io->write_bytes(m_loop_start); + m__io->write_bytes(m__unnamed4); + m__io->write_bytes(m_loop_end); + m__io->write_bytes(m__unnamed6); + m__io->write_bytes(m_tempo_source); + _fetch_instances(); + m__dirty = false; +} + +void mpc2000xl_mid_t::sequencer_t::_check() { + if (m__unnamed0.size() != static_cast(5)) { + throw std::runtime_error("/types/sequencer/seq/0: size mismatch"); + } + if (!(m__unnamed0 == std::string("\x4C\x4F\x4F\x50\x3D", 5))) { + throw kaitai::validation_not_equal_error(std::string("\x4C\x4F\x4F\x50\x3D", 5), m__unnamed0, m__io, std::string("/types/sequencer/seq/0")); + } + if (m_loop_enabled.size() != static_cast(4)) { + throw std::runtime_error("/types/sequencer/seq/1: size mismatch"); + } + if (m__unnamed2.size() != static_cast(6)) { + throw std::runtime_error("/types/sequencer/seq/2: size mismatch"); + } + if (!(m__unnamed2 == std::string("\x53\x54\x41\x52\x54\x3D", 6))) { + throw kaitai::validation_not_equal_error(std::string("\x53\x54\x41\x52\x54\x3D", 6), m__unnamed2, m__io, std::string("/types/sequencer/seq/2")); + } + if (m_loop_start.size() != static_cast(4)) { + throw std::runtime_error("/types/sequencer/seq/3: size mismatch"); + } + if (m__unnamed4.size() != static_cast(4)) { + throw std::runtime_error("/types/sequencer/seq/4: size mismatch"); + } + if (!(m__unnamed4 == std::string("\x45\x4E\x44\x3D", 4))) { + throw kaitai::validation_not_equal_error(std::string("\x45\x4E\x44\x3D", 4), m__unnamed4, m__io, std::string("/types/sequencer/seq/4")); + } + if (m_loop_end.size() != static_cast(4)) { + throw std::runtime_error("/types/sequencer/seq/5: size mismatch"); + } + if (m__unnamed6.size() != static_cast(6)) { + throw std::runtime_error("/types/sequencer/seq/6: size mismatch"); + } + if (!(m__unnamed6 == std::string("\x54\x45\x4D\x50\x4F\x3D", 6))) { + throw kaitai::validation_not_equal_error(std::string("\x54\x45\x4D\x50\x4F\x3D", 6), m__unnamed6, m__io, std::string("/types/sequencer/seq/6")); + } + if (m_tempo_source.size() != static_cast(3)) { + throw std::runtime_error("/types/sequencer/seq/7: size mismatch"); + } + m__dirty = false; +} + +mpc2000xl_mid_t::sequencer_t::~sequencer_t() {} + +int32_t mpc2000xl_mid_t::denominator() { + if (f_denominator) + return m_denominator; + f_denominator = true; + m_denominator = 1 << meta_events()->at(4)->meta_event_body()->body().at(1); + return m_denominator; +} + +standard_midi_file_with_running_status_t::meta_event_body_t* mpc2000xl_mid_t::first_meta() { + if (f_first_meta) + return m_first_meta; + f_first_meta = true; + m_first_meta = meta_events()->at(0)->meta_event_body(); + return m_first_meta; +} + +bool mpc2000xl_mid_t::is_mpc2000xl_mid() { + if (f_is_mpc2000xl_mid) + return m_is_mpc2000xl_mid; + f_is_mpc2000xl_mid = true; + m_is_mpc2000xl_mid = ((tracks()->size() > 0) && (meta_events()->size() > 0) && (meta_events()->at(0)->event_type() == 240) && (first_meta()->len()->value() == 32) && (kaitai::kstream::bytes_to_str(first_meta()->body(), "ASCII").substr(0, 16 - 0) == std::string("MPC2000XL 1.00 "))) ; + return m_is_mpc2000xl_mid; +} + +std::vector>* mpc2000xl_mid_t::meta_events() { + if (f_meta_events) + return m_meta_events; + f_meta_events = true; + m_meta_events = tracks()->at(0)->events()->event(); + return m_meta_events; +} + +uint8_t mpc2000xl_mid_t::numerator() { + if (f_numerator) + return m_numerator; + f_numerator = true; + m_numerator = meta_events()->at(4)->meta_event_body()->body().at(0); + return m_numerator; +} + +std::string mpc2000xl_mid_t::sequence_name() { + if (f_sequence_name) + return m_sequence_name; + f_sequence_name = true; + m_sequence_name = kaitai::kstream::bytes_to_str(first_meta()->body(), "ASCII").substr(16, 32 - 16); + return m_sequence_name; +} + +mpc2000xl_mid_t::sequencer_t* mpc2000xl_mid_t::sequencer() { + if (w_sequencer) + _write_sequencer(); + if (f_sequencer) + return m_sequencer.get(); + if (!e_sequencer) + return nullptr; + f_sequencer = true; + kaitai::kstream *io = tracks()->at(0)->events()->_io(); + std::streampos _pos = io->pos(); + io->seek(40); + m_sequencer = std::unique_ptr(new sequencer_t(io, this, m__root)); + m_sequencer->_read(); + io->seek(_pos); + return m_sequencer.get(); +} + +void mpc2000xl_mid_t::_write_sequencer() { + w_sequencer = false; + kaitai::kstream *io = tracks()->at(0)->events()->_io(); + std::streampos _pos = io->pos(); + io->seek(40); + if (m_sequencer.get() == nullptr) { + throw std::runtime_error("/instances/sequencer: nested object is not set"); + } + m_sequencer.get()->_set_io(io); + m_sequencer.get()->_write(); + io->seek(_pos); +} + +std::string mpc2000xl_mid_t::smpte_offset() { + if (f_smpte_offset) + return m_smpte_offset; + f_smpte_offset = true; + m_smpte_offset = meta_events()->at(3)->meta_event_body()->body(); + return m_smpte_offset; +} + +double mpc2000xl_mid_t::tempo_bpm() { + if (f_tempo_bpm) + return m_tempo_bpm; + f_tempo_bpm = true; + m_tempo_bpm = 60000000.0 / (((meta_events()->at(2)->meta_event_body()->body().at(0) << 16) + (meta_events()->at(2)->meta_event_body()->body().at(1) << 8)) + meta_events()->at(2)->meta_event_body()->body().at(2)); + return m_tempo_bpm; +} diff --git a/src/main/file/kaitai/generated/mpc2000xl_mid.h b/src/main/file/kaitai/generated/mpc2000xl_mid.h new file mode 100644 index 00000000..966f3237 --- /dev/null +++ b/src/main/file/kaitai/generated/mpc2000xl_mid.h @@ -0,0 +1,142 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class mpc2000xl_mid_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include "standard_midi_file_with_running_status.h" +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +class mpc2000xl_mid_t : public kaitai::kstruct { + +public: + class sequencer_t; + +private: + bool m__dirty; + +public: + + mpc2000xl_mid_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mpc2000xl_mid_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~mpc2000xl_mid_t(); + + class sequencer_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + sequencer_t(kaitai::kstream* p__io, mpc2000xl_mid_t* p__parent = nullptr, mpc2000xl_mid_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sequencer_t(); + std::string _unnamed0() const { return m__unnamed0; } + void set__unnamed0(std::string _v) { m__dirty = true; m__unnamed0 = std::move(_v); } + std::string loop_enabled() const { return m_loop_enabled; } + void set_loop_enabled(std::string _v) { m__dirty = true; m_loop_enabled = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + std::string loop_start() const { return m_loop_start; } + void set_loop_start(std::string _v) { m__dirty = true; m_loop_start = std::move(_v); } + std::string _unnamed4() const { return m__unnamed4; } + void set__unnamed4(std::string _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + std::string loop_end() const { return m_loop_end; } + void set_loop_end(std::string _v) { m__dirty = true; m_loop_end = std::move(_v); } + std::string _unnamed6() const { return m__unnamed6; } + void set__unnamed6(std::string _v) { m__dirty = true; m__unnamed6 = std::move(_v); } + std::string tempo_source() const { return m_tempo_source; } + void set_tempo_source(std::string _v) { m__dirty = true; m_tempo_source = std::move(_v); } + mpc2000xl_mid_t* _root() const { return m__root; } + void set__root(mpc2000xl_mid_t* _v) { m__dirty = true; m__root = std::move(_v); } + mpc2000xl_mid_t* _parent() const { return m__parent; } + void set__parent(mpc2000xl_mid_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m__unnamed0; + std::string m_loop_enabled; + std::string m__unnamed2; + std::string m_loop_start; + std::string m__unnamed4; + std::string m_loop_end; + std::string m__unnamed6; + std::string m_tempo_source; + mpc2000xl_mid_t* m__root; + mpc2000xl_mid_t* m__parent; + }; + +public: + int32_t denominator(); + void _invalidate_denominator() { f_denominator = false; } + standard_midi_file_with_running_status_t::meta_event_body_t* first_meta(); + void _invalidate_first_meta() { f_first_meta = false; } + bool is_mpc2000xl_mid(); + void _invalidate_is_mpc2000xl_mid() { f_is_mpc2000xl_mid = false; } + std::vector>* meta_events(); + void _invalidate_meta_events() { f_meta_events = false; } + uint8_t numerator(); + void _invalidate_numerator() { f_numerator = false; } + std::string sequence_name(); + void _invalidate_sequence_name() { f_sequence_name = false; } + mpc2000xl_mid_t::sequencer_t* sequencer(); + void set_sequencer(std::unique_ptr _v) { m__dirty = true; f_denominator = false; f_first_meta = false; f_is_mpc2000xl_mid = false; f_meta_events = false; f_numerator = false; f_sequence_name = false; f_smpte_offset = false; f_tempo_bpm = false; f_sequencer = true; m_sequencer = std::move(_v); } + void set_sequencer_enabled(bool _v) { m__dirty = true; e_sequencer = _v; } + +private: + void _write_sequencer(); + +public: + std::string smpte_offset(); + void _invalidate_smpte_offset() { f_smpte_offset = false; } + double tempo_bpm(); + void _invalidate_tempo_bpm() { f_tempo_bpm = false; } + standard_midi_file_with_running_status_t::header_t* hdr() const { return m_hdr.get(); } + void set_hdr(std::unique_ptr _v) { m__dirty = true; f_denominator = false; f_first_meta = false; f_is_mpc2000xl_mid = false; f_meta_events = false; f_numerator = false; f_sequence_name = false; f_smpte_offset = false; f_tempo_bpm = false; m_hdr = std::move(_v); } + std::vector>* tracks() const { return m_tracks.get(); } + void set_tracks(std::unique_ptr>> _v) { m__dirty = true; f_denominator = false; f_first_meta = false; f_is_mpc2000xl_mid = false; f_meta_events = false; f_numerator = false; f_sequence_name = false; f_smpte_offset = false; f_tempo_bpm = false; m_tracks = std::move(_v); } + mpc2000xl_mid_t* _root() const { return m__root; } + void set__root(mpc2000xl_mid_t* _v) { m__dirty = true; f_denominator = false; f_first_meta = false; f_is_mpc2000xl_mid = false; f_meta_events = false; f_numerator = false; f_sequence_name = false; f_smpte_offset = false; f_tempo_bpm = false; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; f_denominator = false; f_first_meta = false; f_is_mpc2000xl_mid = false; f_meta_events = false; f_numerator = false; f_sequence_name = false; f_smpte_offset = false; f_tempo_bpm = false; m__parent = std::move(_v); } + +private: + bool f_denominator; + int32_t m_denominator; + bool f_first_meta; + standard_midi_file_with_running_status_t::meta_event_body_t* m_first_meta; + bool f_is_mpc2000xl_mid; + bool m_is_mpc2000xl_mid; + bool f_meta_events; + std::vector>* m_meta_events; + bool f_numerator; + uint8_t m_numerator; + bool f_sequence_name; + std::string m_sequence_name; + bool f_sequencer; + std::unique_ptr m_sequencer; + bool w_sequencer; + bool e_sequencer; + bool f_smpte_offset; + std::string m_smpte_offset; + bool f_tempo_bpm; + double m_tempo_bpm; + std::unique_ptr m_hdr; + std::unique_ptr>> m_tracks; + mpc2000xl_mid_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp new file mode 100644 index 00000000..ea94cfaf --- /dev/null +++ b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp @@ -0,0 +1,1059 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "standard_midi_file_with_running_status.h" +#include +#include +#include "kaitai/exceptions.h" + +standard_midi_file_with_running_status_t::standard_midi_file_with_running_status_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::_read() { + m_hdr = std::unique_ptr(new header_t(m__io, this, m__root)); + m_hdr->_read(); + m_tracks = std::unique_ptr>>(new std::vector>()); + const int l_tracks = hdr()->num_tracks(); + for (int i = 0; i < l_tracks; i++) { + std::unique_ptr _t_tracks = std::unique_ptr(new track_t(m__io, this, m__root)); + try { + _t_tracks->_read(); + } catch(...) { + m_tracks->push_back(std::move(_t_tracks)); + throw; + } + m_tracks->push_back(std::move(_t_tracks)); + } + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::_fetch_instances() { + m_hdr.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_tracks->size(); ++i) { + m_tracks->at(i).get()->_fetch_instances(); + } +} + +void standard_midi_file_with_running_status_t::_write() { + if (m_hdr.get() == nullptr) { + throw std::runtime_error("/seq/0: nested object is not set"); + } + m_hdr.get()->_set_io(m__io); + m_hdr.get()->_write(); + if (m_tracks == nullptr) { + throw std::runtime_error("/seq/1: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_tracks->begin(); it != m_tracks->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/1: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::_check() { + if (m_hdr.get() == nullptr) { + throw std::runtime_error("/seq/0: nested object is not set"); + } + m_hdr.get()->_set_io(m__io); + m_hdr.get()->_check(); + if (m_tracks == nullptr) { + throw std::runtime_error("/seq/1: repeated field is not set"); + } + if (m_tracks->size() != static_cast(hdr()->num_tracks())) { + throw std::runtime_error("/seq/1: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_tracks->begin(); it != m_tracks->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/1: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + m__dirty = false; +} + +standard_midi_file_with_running_status_t::~standard_midi_file_with_running_status_t() {} + +standard_midi_file_with_running_status_t::channel_pressure_event_t::channel_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::channel_pressure_event_t::_read() { + m_pressure = m__io->read_u1(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::channel_pressure_event_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::channel_pressure_event_t::_write() { + m__io->write_u1(m_pressure); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::channel_pressure_event_t::_check() { + m__dirty = false; +} + +standard_midi_file_with_running_status_t::channel_pressure_event_t::~channel_pressure_event_t() {} + +standard_midi_file_with_running_status_t::controller_event_t::controller_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::controller_event_t::_read() { + m_controller = m__io->read_u1(); + m_value = m__io->read_u1(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::controller_event_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::controller_event_t::_write() { + m__io->write_u1(m_controller); + m__io->write_u1(m_value); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::controller_event_t::_check() { + m__dirty = false; +} + +standard_midi_file_with_running_status_t::controller_event_t::~controller_event_t() {} + +standard_midi_file_with_running_status_t::header_t::header_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::header_t::_read() { + m_magic = m__io->read_bytes(4); + if (!(m_magic == std::string("\x4D\x54\x68\x64", 4))) { + throw kaitai::validation_not_equal_error(std::string("\x4D\x54\x68\x64", 4), m_magic, m__io, std::string("/types/header/seq/0")); + } + m_len_header = m__io->read_u4be(); + m_format = m__io->read_u2be(); + m_num_tracks = m__io->read_u2be(); + m_division = m__io->read_s2be(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::header_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::header_t::_write() { + m__io->write_bytes(m_magic); + m__io->write_u4be(m_len_header); + m__io->write_u2be(m_format); + m__io->write_u2be(m_num_tracks); + m__io->write_s2be(m_division); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::header_t::_check() { + if (m_magic.size() != static_cast(4)) { + throw std::runtime_error("/types/header/seq/0: size mismatch"); + } + if (!(m_magic == std::string("\x4D\x54\x68\x64", 4))) { + throw kaitai::validation_not_equal_error(std::string("\x4D\x54\x68\x64", 4), m_magic, m__io, std::string("/types/header/seq/0")); + } + m__dirty = false; +} + +standard_midi_file_with_running_status_t::header_t::~header_t() {} +const std::set standard_midi_file_with_running_status_t::meta_event_body_t::_values_meta_type_enum_t{ + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_SEQUENCE_NUMBER, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_TEXT_EVENT, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_COPYRIGHT, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_INSTRUMENT_NAME, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_LYRIC_TEXT, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_MARKER_TEXT, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_CUE_POINT, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_MIDI_CHANNEL_PREFIX_ASSIGNMENT, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_END_OF_TRACK, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_TEMPO, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_SMPTE_OFFSET, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_TIME_SIGNATURE, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_KEY_SIGNATURE, + standard_midi_file_with_running_status_t::meta_event_body_t::META_TYPE_ENUM_SEQUENCER_SPECIFIC_EVENT, +}; +bool standard_midi_file_with_running_status_t::meta_event_body_t::_is_defined_meta_type_enum_t(standard_midi_file_with_running_status_t::meta_event_body_t::meta_type_enum_t v) { + return standard_midi_file_with_running_status_t::meta_event_body_t::_values_meta_type_enum_t.find(v) != standard_midi_file_with_running_status_t::meta_event_body_t::_values_meta_type_enum_t.end(); +} + +standard_midi_file_with_running_status_t::meta_event_body_t::meta_event_body_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::meta_event_body_t::_read() { + m_meta_type = static_cast(m__io->read_u1()); + m_len = std::unique_ptr(new vlq_base128_be_t(m__io)); + m_len->_read(); + m_body = m__io->read_bytes(len()->value()); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::meta_event_body_t::_fetch_instances() { + m_len.get()->_fetch_instances(); +} + +void standard_midi_file_with_running_status_t::meta_event_body_t::_write() { + m__io->write_u1(static_cast(m_meta_type)); + if (m_len.get() == nullptr) { + throw std::runtime_error("/types/meta_event_body/seq/1: nested object is not set"); + } + m_len.get()->_set_io(m__io); + m_len.get()->_write(); + m__io->write_bytes(m_body); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::meta_event_body_t::_check() { + if (m_len.get() == nullptr) { + throw std::runtime_error("/types/meta_event_body/seq/1: nested object is not set"); + } + m_len.get()->_set_io(m__io); + m_len.get()->_check(); + if (m_body.size() != static_cast(len()->value())) { + throw std::runtime_error("/types/meta_event_body/seq/2: size mismatch"); + } + m__dirty = false; +} + +standard_midi_file_with_running_status_t::meta_event_body_t::~meta_event_body_t() {} + +standard_midi_file_with_running_status_t::note_off_event_t::note_off_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::note_off_event_t::_read() { + m_note = m__io->read_u1(); + m_velocity = m__io->read_u1(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::note_off_event_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::note_off_event_t::_write() { + m__io->write_u1(m_note); + m__io->write_u1(m_velocity); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::note_off_event_t::_check() { + m__dirty = false; +} + +standard_midi_file_with_running_status_t::note_off_event_t::~note_off_event_t() {} + +standard_midi_file_with_running_status_t::note_on_event_t::note_on_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::note_on_event_t::_read() { + m_note = m__io->read_u1(); + m_velocity = m__io->read_u1(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::note_on_event_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::note_on_event_t::_write() { + m__io->write_u1(m_note); + m__io->write_u1(m_velocity); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::note_on_event_t::_check() { + m__dirty = false; +} + +standard_midi_file_with_running_status_t::note_on_event_t::~note_on_event_t() {} + +standard_midi_file_with_running_status_t::pitch_bend_event_t::pitch_bend_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; + f_adj_bend_value = false; + f_bend_value = false; +} + +void standard_midi_file_with_running_status_t::pitch_bend_event_t::_read() { + m_b1 = m__io->read_u1(); + m_b2 = m__io->read_u1(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::pitch_bend_event_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::pitch_bend_event_t::_write() { + m__io->write_u1(m_b1); + m__io->write_u1(m_b2); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::pitch_bend_event_t::_check() { + m__dirty = false; +} + +standard_midi_file_with_running_status_t::pitch_bend_event_t::~pitch_bend_event_t() {} + +int32_t standard_midi_file_with_running_status_t::pitch_bend_event_t::adj_bend_value() { + if (f_adj_bend_value) + return m_adj_bend_value; + f_adj_bend_value = true; + m_adj_bend_value = bend_value() - 16384; + return m_adj_bend_value; +} + +int32_t standard_midi_file_with_running_status_t::pitch_bend_event_t::bend_value() { + if (f_bend_value) + return m_bend_value; + f_bend_value = true; + m_bend_value = ((b2() << 7) + b1()) - 16384; + return m_bend_value; +} + +standard_midi_file_with_running_status_t::polyphonic_pressure_event_t::polyphonic_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::polyphonic_pressure_event_t::_read() { + m_note = m__io->read_u1(); + m_pressure = m__io->read_u1(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::polyphonic_pressure_event_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::polyphonic_pressure_event_t::_write() { + m__io->write_u1(m_note); + m__io->write_u1(m_pressure); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::polyphonic_pressure_event_t::_check() { + m__dirty = false; +} + +standard_midi_file_with_running_status_t::polyphonic_pressure_event_t::~polyphonic_pressure_event_t() {} + +standard_midi_file_with_running_status_t::program_change_event_t::program_change_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::program_change_event_t::_read() { + m_program = m__io->read_u1(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::program_change_event_t::_fetch_instances() { +} + +void standard_midi_file_with_running_status_t::program_change_event_t::_write() { + m__io->write_u1(m_program); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::program_change_event_t::_check() { + m__dirty = false; +} + +standard_midi_file_with_running_status_t::program_change_event_t::~program_change_event_t() {} + +standard_midi_file_with_running_status_t::sysex_event_body_t::sysex_event_body_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::sysex_event_body_t::_read() { + m_len = std::unique_ptr(new vlq_base128_be_t(m__io)); + m_len->_read(); + m_data = m__io->read_bytes(len()->value()); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::sysex_event_body_t::_fetch_instances() { + m_len.get()->_fetch_instances(); +} + +void standard_midi_file_with_running_status_t::sysex_event_body_t::_write() { + if (m_len.get() == nullptr) { + throw std::runtime_error("/types/sysex_event_body/seq/0: nested object is not set"); + } + m_len.get()->_set_io(m__io); + m_len.get()->_write(); + m__io->write_bytes(m_data); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::sysex_event_body_t::_check() { + if (m_len.get() == nullptr) { + throw std::runtime_error("/types/sysex_event_body/seq/0: nested object is not set"); + } + m_len.get()->_set_io(m__io); + m_len.get()->_check(); + if (m_data.size() != static_cast(len()->value())) { + throw std::runtime_error("/types/sysex_event_body/seq/1: size mismatch"); + } + m__dirty = false; +} + +standard_midi_file_with_running_status_t::sysex_event_body_t::~sysex_event_body_t() {} + +standard_midi_file_with_running_status_t::track_t::track_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_t::_read() { + m_magic = m__io->read_bytes(4); + if (!(m_magic == std::string("\x4D\x54\x72\x6B", 4))) { + throw kaitai::validation_not_equal_error(std::string("\x4D\x54\x72\x6B", 4), m_magic, m__io, std::string("/types/track/seq/0")); + } + m_len_events = m__io->read_u4be(); + m__raw_events = m__io->read_bytes(len_events()); + m__io__raw_events = std::unique_ptr(new kaitai::kstream(m__raw_events)); + m_events = std::unique_ptr(new track_events_t(m__io__raw_events.get(), this, m__root)); + m_events->_read(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_t::_fetch_instances() { + m_events.get()->_fetch_instances(); +} + +void standard_midi_file_with_running_status_t::track_t::_write() { + m__io->write_bytes(m_magic); + m__io->write_u4be(m_len_events); + if (m_events.get() == nullptr) { + throw std::runtime_error("/types/track/seq/2: nested object is not set"); + } + m__raw_events = std::string(static_cast(len_events()), '\0'); + m__io__raw_events = std::unique_ptr(new kaitai::kstream(m__raw_events)); + m_events.get()->_set_io(m__io__raw_events.get()); + m_events.get()->_write(); + if (m__io__raw_events.get()->pos() != static_cast(len_events())) { + throw std::runtime_error("/types/track/seq/2: serialized size mismatch"); + } + if (m__io__raw_events.get()->to_byte_array().size() != static_cast(len_events())) { + throw std::runtime_error("/types/track/seq/2: raw buffer size mismatch"); + } + m__raw_events = m__io__raw_events.get()->to_byte_array(); + m__io->write_bytes(m__raw_events); + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_t::_check() { + if (m_magic.size() != static_cast(4)) { + throw std::runtime_error("/types/track/seq/0: size mismatch"); + } + if (!(m_magic == std::string("\x4D\x54\x72\x6B", 4))) { + throw kaitai::validation_not_equal_error(std::string("\x4D\x54\x72\x6B", 4), m_magic, m__io, std::string("/types/track/seq/0")); + } + if (m_events.get() == nullptr) { + throw std::runtime_error("/types/track/seq/2: nested object is not set"); + } + m__raw_events = std::string(static_cast(len_events()), '\0'); + m__io__raw_events = std::unique_ptr(new kaitai::kstream(m__raw_events)); + m_events.get()->_set_io(m__io__raw_events.get()); + m_events.get()->_check(); + m__dirty = false; +} + +standard_midi_file_with_running_status_t::track_t::~track_t() {} + +standard_midi_file_with_running_status_t::track_event_t::track_event_t(uint8_t p_previous_event_type, kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_events_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_previous_event_type = p_previous_event_type; + m__dirty = false; + n_event_header = true; + f_channel = false; + f_event_type = false; + f_status_byte_lookahead = false; + f_using_running_status = false; + w_status_byte_lookahead = false; + e_status_byte_lookahead = false; +} + +void standard_midi_file_with_running_status_t::track_event_t::_read() { + m_v_time = std::unique_ptr(new vlq_base128_be_t(m__io)); + m_v_time->_read(); + n_event_header = true; + if (!(using_running_status())) { + n_event_header = false; + m_event_header = m__io->read_u1(); + } + if (event_header() == 255) { + m_meta_event_body = std::unique_ptr(new meta_event_body_t(m__io, this, m__root)); + m_meta_event_body->_read(); + } + if (event_header() == 240) { + m_sysex_body = std::unique_ptr(new sysex_event_body_t(m__io, this, m__root)); + m_sysex_body->_read(); + } + switch (event_type()) { + case 128: { + m_event_body = std::unique_ptr(new note_off_event_t(m__io, this, m__root)); + static_cast(m_event_body.get())->_read(); + break; + } + case 144: { + m_event_body = std::unique_ptr(new note_on_event_t(m__io, this, m__root)); + static_cast(m_event_body.get())->_read(); + break; + } + case 160: { + m_event_body = std::unique_ptr(new polyphonic_pressure_event_t(m__io, this, m__root)); + static_cast(m_event_body.get())->_read(); + break; + } + case 176: { + m_event_body = std::unique_ptr(new controller_event_t(m__io, this, m__root)); + static_cast(m_event_body.get())->_read(); + break; + } + case 192: { + m_event_body = std::unique_ptr(new program_change_event_t(m__io, this, m__root)); + static_cast(m_event_body.get())->_read(); + break; + } + case 208: { + m_event_body = std::unique_ptr(new channel_pressure_event_t(m__io, this, m__root)); + static_cast(m_event_body.get())->_read(); + break; + } + case 224: { + m_event_body = std::unique_ptr(new pitch_bend_event_t(m__io, this, m__root)); + static_cast(m_event_body.get())->_read(); + break; + } + } + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_event_t::_fetch_instances() { + m_v_time.get()->_fetch_instances(); + n_event_header = true; + if (!(using_running_status())) { + n_event_header = false; + } + if (event_header() == 255) { + m_meta_event_body.get()->_fetch_instances(); + } + if (event_header() == 240) { + m_sysex_body.get()->_fetch_instances(); + } + switch (event_type()) { + case 128: { + { + note_off_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("switch object type mismatch in _fetch_instances"); + } + _switch_obj->_fetch_instances(); + } + break; + } + case 144: { + { + note_on_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("switch object type mismatch in _fetch_instances"); + } + _switch_obj->_fetch_instances(); + } + break; + } + case 160: { + { + polyphonic_pressure_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("switch object type mismatch in _fetch_instances"); + } + _switch_obj->_fetch_instances(); + } + break; + } + case 176: { + { + controller_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("switch object type mismatch in _fetch_instances"); + } + _switch_obj->_fetch_instances(); + } + break; + } + case 192: { + { + program_change_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("switch object type mismatch in _fetch_instances"); + } + _switch_obj->_fetch_instances(); + } + break; + } + case 208: { + { + channel_pressure_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("switch object type mismatch in _fetch_instances"); + } + _switch_obj->_fetch_instances(); + } + break; + } + case 224: { + { + pitch_bend_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("switch object type mismatch in _fetch_instances"); + } + _switch_obj->_fetch_instances(); + } + break; + } + } + status_byte_lookahead(); + if (f_status_byte_lookahead) { + } +} + +void standard_midi_file_with_running_status_t::track_event_t::_write() { + w_status_byte_lookahead = e_status_byte_lookahead; + if (m_v_time.get() == nullptr) { + throw std::runtime_error("/types/track_event/seq/0: nested object is not set"); + } + m_v_time.get()->_set_io(m__io); + m_v_time.get()->_write(); + if (!(using_running_status())) { + m__io->write_u1(m_event_header); + } + if (event_header() == 255) { + if (m_meta_event_body.get() == nullptr) { + throw std::runtime_error("/types/track_event/seq/2: nested object is not set"); + } + m_meta_event_body.get()->_set_io(m__io); + m_meta_event_body.get()->_write(); + } + if (event_header() == 240) { + if (m_sysex_body.get() == nullptr) { + throw std::runtime_error("/types/track_event/seq/3: nested object is not set"); + } + m_sysex_body.get()->_set_io(m__io); + m_sysex_body.get()->_write(); + } + switch (event_type()) { + case 128: { + { + note_off_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_write(); + } + break; + } + case 144: { + { + note_on_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_write(); + } + break; + } + case 160: { + { + polyphonic_pressure_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_write(); + } + break; + } + case 176: { + { + controller_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_write(); + } + break; + } + case 192: { + { + program_change_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_write(); + } + break; + } + case 208: { + { + channel_pressure_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_write(); + } + break; + } + case 224: { + { + pitch_bend_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_write(); + } + break; + } + } + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_event_t::_check() { + if (m_v_time.get() == nullptr) { + throw std::runtime_error("/types/track_event/seq/0: nested object is not set"); + } + m_v_time.get()->_set_io(m__io); + m_v_time.get()->_check(); + if (!(using_running_status())) { + if (!(!n_event_header)) { + throw std::runtime_error("/types/track_event/seq/1: conditional field is not set"); + } + } else { + if (!n_event_header) { + throw std::runtime_error("/types/track_event/seq/1: conditional field should be absent"); + } + } + if (event_header() == 255) { + if (!(m_meta_event_body.get() != nullptr)) { + throw std::runtime_error("/types/track_event/seq/2: conditional field is not set"); + } + if (m_meta_event_body.get() == nullptr) { + throw std::runtime_error("/types/track_event/seq/2: nested object is not set"); + } + m_meta_event_body.get()->_set_io(m__io); + m_meta_event_body.get()->_check(); + } else { + if (m_meta_event_body.get() != nullptr) { + throw std::runtime_error("/types/track_event/seq/2: conditional field should be absent"); + } + } + if (event_header() == 240) { + if (!(m_sysex_body.get() != nullptr)) { + throw std::runtime_error("/types/track_event/seq/3: conditional field is not set"); + } + if (m_sysex_body.get() == nullptr) { + throw std::runtime_error("/types/track_event/seq/3: nested object is not set"); + } + m_sysex_body.get()->_set_io(m__io); + m_sysex_body.get()->_check(); + } else { + if (m_sysex_body.get() != nullptr) { + throw std::runtime_error("/types/track_event/seq/3: conditional field should be absent"); + } + } + switch (event_type()) { + case 128: { + { + note_off_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_check(); + } + break; + } + case 144: { + { + note_on_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_check(); + } + break; + } + case 160: { + { + polyphonic_pressure_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_check(); + } + break; + } + case 176: { + { + controller_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_check(); + } + break; + } + case 192: { + { + program_change_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_check(); + } + break; + } + case 208: { + { + channel_pressure_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_check(); + } + break; + } + case 224: { + { + pitch_bend_event_t* _switch_obj = dynamic_cast(m_event_body.get()); + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: switch object type mismatch"); + } + if (_switch_obj == nullptr) { + throw std::runtime_error("/types/track_event/seq/4: nested object is not set"); + } + _switch_obj->_set_io(m__io); + _switch_obj->_check(); + } + break; + } + } + if (e_status_byte_lookahead) { + } + m__dirty = false; +} + +standard_midi_file_with_running_status_t::track_event_t::~track_event_t() {} + +int32_t standard_midi_file_with_running_status_t::track_event_t::channel() { + if (f_channel) + return m_channel; + f_channel = true; + n_channel = true; + if (event_type() != 240) { + n_channel = false; + m_channel = event_header() & 15; + } + return m_channel; +} + +int32_t standard_midi_file_with_running_status_t::track_event_t::event_type() { + if (f_event_type) + return m_event_type; + f_event_type = true; + m_event_type = ((using_running_status()) ? (previous_event_type()) : (event_header() & 240)); + return m_event_type; +} + +uint8_t standard_midi_file_with_running_status_t::track_event_t::status_byte_lookahead() { + if (w_status_byte_lookahead) + _write_status_byte_lookahead(); + if (f_status_byte_lookahead) + return m_status_byte_lookahead; + if (!e_status_byte_lookahead) + return 0; + f_status_byte_lookahead = true; + std::streampos _pos = m__io->pos(); + m__io->seek(_io()->pos()); + m_status_byte_lookahead = m__io->read_u1(); + m__io->seek(_pos); + return m_status_byte_lookahead; +} + +void standard_midi_file_with_running_status_t::track_event_t::_write_status_byte_lookahead() { + w_status_byte_lookahead = false; + std::streampos _pos = m__io->pos(); + m__io->seek(_io()->pos()); + m__io->write_u1(m_status_byte_lookahead); + m__io->seek(_pos); +} + +bool standard_midi_file_with_running_status_t::track_event_t::using_running_status() { + if (f_using_running_status) + return m_using_running_status; + f_using_running_status = true; + m_using_running_status = (status_byte_lookahead() & 128) == 0; + return m_using_running_status; +} + +standard_midi_file_with_running_status_t::track_events_t::track_events_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_t* p__parent, standard_midi_file_with_running_status_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_events_t::_read() { + m_event = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + while (!m__io->is_eof()) { + std::unique_ptr _t_event = std::unique_ptr(new track_event_t(((i != 0) ? (event()->at(i - 1)->event_type()) : (255)), m__io, this, m__root)); + try { + _t_event->_read(); + } catch(...) { + m_event->push_back(std::move(_t_event)); + throw; + } + m_event->push_back(std::move(_t_event)); + i++; + } + } + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_events_t::_fetch_instances() { + for (std::size_t i = 0; i < m_event->size(); ++i) { + m_event->at(i).get()->_fetch_instances(); + } +} + +void standard_midi_file_with_running_status_t::track_events_t::_write() { + if (m_event == nullptr) { + throw std::runtime_error("/types/track_events/seq/0: repeated field is not set"); + } + if (m_event == nullptr) { + throw std::runtime_error("/types/track_events/seq/0: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_event->begin(); it != m_event->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/track_events/seq/0: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void standard_midi_file_with_running_status_t::track_events_t::_check() { + if (m_event == nullptr) { + throw std::runtime_error("/types/track_events/seq/0: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_event->begin(); it != m_event->end(); ++it) { + const std::size_t i = static_cast(it - m_event->begin()); + const track_event_t* _ = (*it).get(); + if ((*it).get() == nullptr) { + throw std::runtime_error("/types/track_events/seq/0: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + m__dirty = false; +} + +standard_midi_file_with_running_status_t::track_events_t::~track_events_t() {} diff --git a/src/main/file/kaitai/generated/standard_midi_file_with_running_status.h b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.h new file mode 100644 index 00000000..78fd8d02 --- /dev/null +++ b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.h @@ -0,0 +1,589 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class standard_midi_file_with_running_status_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include "vlq_base128_be.h" +#include +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +/** + * Standard MIDI file, typically known just as "MID", is a standard way + * to serialize series of MIDI events, which is a protocol used in many + * music synthesizers to transfer music data: notes being played, + * effects being applied, etc. + * + * Internally, file consists of a header and series of tracks, every + * track listing MIDI events with certain header designating time these + * events are happening. + * + * NOTE: Rarely, MIDI files employ certain stateful compression scheme + * to avoid storing certain elements of further elements, instead + * reusing them from events which happened earlier in the + * stream. Kaitai Struct (as of v0.9) is currently unable to parse + * these, but files employing this mechanism are relatively rare. + */ + +class standard_midi_file_with_running_status_t : public kaitai::kstruct { + +public: + class channel_pressure_event_t; + class controller_event_t; + class header_t; + class meta_event_body_t; + class note_off_event_t; + class note_on_event_t; + class pitch_bend_event_t; + class polyphonic_pressure_event_t; + class program_change_event_t; + class sysex_event_body_t; + class track_t; + class track_event_t; + class track_events_t; + +private: + bool m__dirty; + +public: + + standard_midi_file_with_running_status_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~standard_midi_file_with_running_status_t(); + + class channel_pressure_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + channel_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~channel_pressure_event_t(); + uint8_t pressure() const { return m_pressure; } + void set_pressure(uint8_t _v) { m__dirty = true; m_pressure = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_pressure; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class controller_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + controller_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~controller_event_t(); + uint8_t controller() const { return m_controller; } + void set_controller(uint8_t _v) { m__dirty = true; m_controller = std::move(_v); } + uint8_t value() const { return m_value; } + void set_value(uint8_t _v) { m__dirty = true; m_value = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_controller; + uint8_t m_value; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class header_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + header_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~header_t(); + std::string magic() const { return m_magic; } + void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } + uint32_t len_header() const { return m_len_header; } + void set_len_header(uint32_t _v) { m__dirty = true; m_len_header = std::move(_v); } + uint16_t format() const { return m_format; } + void set_format(uint16_t _v) { m__dirty = true; m_format = std::move(_v); } + uint16_t num_tracks() const { return m_num_tracks; } + void set_num_tracks(uint16_t _v) { m__dirty = true; m_num_tracks = std::move(_v); } + int16_t division() const { return m_division; } + void set_division(int16_t _v) { m__dirty = true; m_division = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m_magic; + uint32_t m_len_header; + uint16_t m_format; + uint16_t m_num_tracks; + int16_t m_division; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t* m__parent; + }; + + class meta_event_body_t : public kaitai::kstruct { + + public: + + enum meta_type_enum_t { + META_TYPE_ENUM_SEQUENCE_NUMBER = 0, + META_TYPE_ENUM_TEXT_EVENT = 1, + META_TYPE_ENUM_COPYRIGHT = 2, + META_TYPE_ENUM_SEQUENCE_TRACK_NAME = 3, + META_TYPE_ENUM_INSTRUMENT_NAME = 4, + META_TYPE_ENUM_LYRIC_TEXT = 5, + META_TYPE_ENUM_MARKER_TEXT = 6, + META_TYPE_ENUM_CUE_POINT = 7, + META_TYPE_ENUM_MIDI_CHANNEL_PREFIX_ASSIGNMENT = 32, + META_TYPE_ENUM_END_OF_TRACK = 47, + META_TYPE_ENUM_TEMPO = 81, + META_TYPE_ENUM_SMPTE_OFFSET = 84, + META_TYPE_ENUM_TIME_SIGNATURE = 88, + META_TYPE_ENUM_KEY_SIGNATURE = 89, + META_TYPE_ENUM_SEQUENCER_SPECIFIC_EVENT = 127 + }; + static bool _is_defined_meta_type_enum_t(meta_type_enum_t v); + + private: + static const std::set _values_meta_type_enum_t; + + public: + + private: + bool m__dirty; + + public: + + meta_event_body_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~meta_event_body_t(); + meta_type_enum_t meta_type() const { return m_meta_type; } + void set_meta_type(meta_type_enum_t _v) { m__dirty = true; m_meta_type = std::move(_v); } + vlq_base128_be_t* len() const { return m_len.get(); } + void set_len(std::unique_ptr _v) { m__dirty = true; m_len = std::move(_v); } + std::string body() const { return m_body; } + void set_body(std::string _v) { m__dirty = true; m_body = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + meta_type_enum_t m_meta_type; + std::unique_ptr m_len; + std::string m_body; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class note_off_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + note_off_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~note_off_event_t(); + uint8_t note() const { return m_note; } + void set_note(uint8_t _v) { m__dirty = true; m_note = std::move(_v); } + uint8_t velocity() const { return m_velocity; } + void set_velocity(uint8_t _v) { m__dirty = true; m_velocity = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_note; + uint8_t m_velocity; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class note_on_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + note_on_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~note_on_event_t(); + uint8_t note() const { return m_note; } + void set_note(uint8_t _v) { m__dirty = true; m_note = std::move(_v); } + uint8_t velocity() const { return m_velocity; } + void set_velocity(uint8_t _v) { m__dirty = true; m_velocity = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_note; + uint8_t m_velocity; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class pitch_bend_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + pitch_bend_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~pitch_bend_event_t(); + int32_t adj_bend_value(); + void _invalidate_adj_bend_value() { f_adj_bend_value = false; } + int32_t bend_value(); + void _invalidate_bend_value() { f_bend_value = false; } + uint8_t b1() const { return m_b1; } + void set_b1(uint8_t _v) { m__dirty = true; f_adj_bend_value = false; f_bend_value = false; m_b1 = std::move(_v); } + uint8_t b2() const { return m_b2; } + void set_b2(uint8_t _v) { m__dirty = true; f_adj_bend_value = false; f_bend_value = false; m_b2 = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; f_adj_bend_value = false; f_bend_value = false; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; f_adj_bend_value = false; f_bend_value = false; m__parent = std::move(_v); } + + private: + bool f_adj_bend_value; + int32_t m_adj_bend_value; + bool f_bend_value; + int32_t m_bend_value; + uint8_t m_b1; + uint8_t m_b2; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class polyphonic_pressure_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + polyphonic_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~polyphonic_pressure_event_t(); + uint8_t note() const { return m_note; } + void set_note(uint8_t _v) { m__dirty = true; m_note = std::move(_v); } + uint8_t pressure() const { return m_pressure; } + void set_pressure(uint8_t _v) { m__dirty = true; m_pressure = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_note; + uint8_t m_pressure; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class program_change_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + program_change_event_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~program_change_event_t(); + uint8_t program() const { return m_program; } + void set_program(uint8_t _v) { m__dirty = true; m_program = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + uint8_t m_program; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class sysex_event_body_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + sysex_event_body_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_event_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sysex_event_body_t(); + vlq_base128_be_t* len() const { return m_len.get(); } + void set_len(std::unique_ptr _v) { m__dirty = true; m_len = std::move(_v); } + std::string data() const { return m_data; } + void set_data(std::string _v) { m__dirty = true; m_data = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::unique_ptr m_len; + std::string m_data; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_event_t* m__parent; + }; + + class track_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + track_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~track_t(); + std::string magic() const { return m_magic; } + void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } + uint32_t len_events() const { return m_len_events; } + void set_len_events(uint32_t _v) { m__dirty = true; m_len_events = std::move(_v); } + track_events_t* events() const { return m_events.get(); } + void set_events(std::unique_ptr _v) { m__dirty = true; m_events = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__parent = std::move(_v); } + std::string _raw_events() const { return m__raw_events; } + void set__raw_events(std::string _v) { m__dirty = true; m__raw_events = std::move(_v); } + kaitai::kstream* _io__raw_events() const { return m__io__raw_events.get(); } + void set__io__raw_events(std::unique_ptr _v) { m__io__raw_events = std::move(_v); } + + private: + std::string m_magic; + uint32_t m_len_events; + std::unique_ptr m_events; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t* m__parent; + std::string m__raw_events; + std::unique_ptr m__io__raw_events; + }; + + class track_event_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + track_event_t(uint8_t p_previous_event_type, kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_events_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~track_event_t(); + int32_t channel(); + void _invalidate_channel() { f_channel = false; } + int32_t event_type(); + void _invalidate_event_type() { f_event_type = false; } + uint8_t status_byte_lookahead(); + void set_status_byte_lookahead(uint8_t _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; e_status_byte_lookahead = false; f_status_byte_lookahead = true; m_status_byte_lookahead = std::move(_v); } + void set_status_byte_lookahead_enabled(bool _v) { m__dirty = true; e_status_byte_lookahead = _v; } + + private: + void _write_status_byte_lookahead(); + + public: + bool using_running_status(); + void _invalidate_using_running_status() { f_using_running_status = false; } + vlq_base128_be_t* v_time() const { return m_v_time.get(); } + void set_v_time(std::unique_ptr _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m_v_time = std::move(_v); } + uint8_t event_header() const { return m_event_header; } + void set_event_header(uint8_t _v) { m__dirty = true; n_event_header = false; f_channel = false; f_event_type = false; f_using_running_status = false; m_event_header = std::move(_v); } + meta_event_body_t* meta_event_body() const { return m_meta_event_body.get(); } + void set_meta_event_body(std::unique_ptr _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m_meta_event_body = std::move(_v); } + sysex_event_body_t* sysex_body() const { return m_sysex_body.get(); } + void set_sysex_body(std::unique_ptr _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m_sysex_body = std::move(_v); } + kaitai::kstruct* event_body() const { return m_event_body.get(); } + void set_event_body(std::unique_ptr _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m_event_body = std::move(_v); } + uint8_t previous_event_type() const { return m_previous_event_type; } + void set_previous_event_type(uint8_t _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m_previous_event_type = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_events_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_events_t* _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m__parent = std::move(_v); } + + private: + bool f_channel; + int32_t m_channel; + bool n_channel; + + public: + bool _is_null_channel() { channel(); return n_channel; }; + + private: + bool f_event_type; + int32_t m_event_type; + bool f_status_byte_lookahead; + uint8_t m_status_byte_lookahead; + bool w_status_byte_lookahead; + bool e_status_byte_lookahead; + bool f_using_running_status; + bool m_using_running_status; + std::unique_ptr m_v_time; + uint8_t m_event_header; + bool n_event_header; + + public: + bool _is_null_event_header() { event_header(); return n_event_header; }; + + private: + std::unique_ptr m_meta_event_body; + + public: + bool _is_null_meta_event_body() { return !meta_event_body(); }; + + private: + std::unique_ptr m_sysex_body; + + public: + bool _is_null_sysex_body() { return !sysex_body(); }; + + private: + std::unique_ptr m_event_body; + + public: + bool _is_null_event_body() { return !event_body(); }; + + private: + uint8_t m_previous_event_type; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_events_t* m__parent; + }; + + class track_events_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + track_events_t(kaitai::kstream* p__io, standard_midi_file_with_running_status_t::track_t* p__parent = nullptr, standard_midi_file_with_running_status_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~track_events_t(); + std::vector>* event() const { return m_event.get(); } + void set_event(std::unique_ptr>> _v) { m__dirty = true; m_event = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + standard_midi_file_with_running_status_t::track_t* _parent() const { return m__parent; } + void set__parent(standard_midi_file_with_running_status_t::track_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::unique_ptr>> m_event; + standard_midi_file_with_running_status_t* m__root; + standard_midi_file_with_running_status_t::track_t* m__parent; + }; + +public: + header_t* hdr() const { return m_hdr.get(); } + void set_hdr(std::unique_ptr _v) { m__dirty = true; m_hdr = std::move(_v); } + std::vector>* tracks() const { return m_tracks.get(); } + void set_tracks(std::unique_ptr>> _v) { m__dirty = true; m_tracks = std::move(_v); } + standard_midi_file_with_running_status_t* _root() const { return m__root; } + void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; m__parent = std::move(_v); } + +private: + std::unique_ptr m_hdr; + std::unique_ptr>> m_tracks; + standard_midi_file_with_running_status_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/main/file/kaitai/generated/vlq_base128_be.cpp b/src/main/file/kaitai/generated/vlq_base128_be.cpp new file mode 100644 index 00000000..6ee58ab8 --- /dev/null +++ b/src/main/file/kaitai/generated/vlq_base128_be.cpp @@ -0,0 +1,125 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "vlq_base128_be.h" +#include +#include + +vlq_base128_be_t::vlq_base128_be_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, vlq_base128_be_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; + f_last = false; + f_value = false; +} + +void vlq_base128_be_t::_read() { + m_groups = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + group_t* _; + do { + std::unique_ptr _t_groups = std::unique_ptr(new group_t(m__io, this, m__root)); + try { + _t_groups->_read(); + } catch(...) { + _ = _t_groups.get(); + m_groups->push_back(std::move(_t_groups)); + throw; + } + _ = _t_groups.get(); + m_groups->push_back(std::move(_t_groups)); + i++; + } while (!(!(_->has_next()))); + } + m__dirty = false; +} + +void vlq_base128_be_t::_fetch_instances() { + for (std::size_t i = 0; i < m_groups->size(); ++i) { + m_groups->at(i).get()->_fetch_instances(); + } +} + +void vlq_base128_be_t::_write() { + if (m_groups == nullptr) { + throw std::runtime_error("/seq/0: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_groups->begin(); it != m_groups->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/0: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + _fetch_instances(); + m__dirty = false; +} + +void vlq_base128_be_t::_check() { + if (m_groups == nullptr) { + throw std::runtime_error("/seq/0: repeated field is not set"); + } + if (m_groups->empty()) { + throw std::runtime_error("/seq/0: repeat-until field must not be empty"); + } + for (std::vector>::const_iterator it = m_groups->begin(); it != m_groups->end(); ++it) { + const std::size_t i = static_cast(it - m_groups->begin()); + const group_t* _ = (*it).get(); + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/0: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + const bool _is_last = (i == m_groups->size() - 1); + if ((!(_->has_next())) != _is_last) { + throw std::runtime_error("/seq/0: repeat-until condition mismatch"); + } + } + m__dirty = false; +} + +vlq_base128_be_t::~vlq_base128_be_t() {} + +vlq_base128_be_t::group_t::group_t(kaitai::kstream* p__io, vlq_base128_be_t* p__parent, vlq_base128_be_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void vlq_base128_be_t::group_t::_read() { + m_has_next = m__io->read_bits_int_be(1); + m_value = m__io->read_bits_int_be(7); + m__dirty = false; +} + +void vlq_base128_be_t::group_t::_fetch_instances() { +} + +void vlq_base128_be_t::group_t::_write() { + m__io->write_bits_int_be(1, ((m_has_next) ? 1 : 0)); + m__io->write_bits_int_be(7, m_value); + _fetch_instances(); + m__dirty = false; +} + +void vlq_base128_be_t::group_t::_check() { + m__dirty = false; +} + +vlq_base128_be_t::group_t::~group_t() {} + +int32_t vlq_base128_be_t::last() { + if (f_last) + return m_last; + f_last = true; + m_last = groups()->size() - 1; + return m_last; +} + +uint64_t vlq_base128_be_t::value() { + if (f_value) + return m_value; + f_value = true; + m_value = static_cast(((((((groups()->at(last())->value() + ((last() >= 1) ? (groups()->at(last() - 1)->value() << 7) : (0))) + ((last() >= 2) ? (groups()->at(last() - 2)->value() << 14) : (0))) + ((last() >= 3) ? (groups()->at(last() - 3)->value() << 21) : (0))) + ((last() >= 4) ? (groups()->at(last() - 4)->value() << 28) : (0))) + ((last() >= 5) ? (groups()->at(last() - 5)->value() << 35) : (0))) + ((last() >= 6) ? (groups()->at(last() - 6)->value() << 42) : (0))) + ((last() >= 7) ? (groups()->at(last() - 7)->value() << 49) : (0))); + return m_value; +} diff --git a/src/main/file/kaitai/generated/vlq_base128_be.h b/src/main/file/kaitai/generated/vlq_base128_be.h new file mode 100644 index 00000000..dbdcf320 --- /dev/null +++ b/src/main/file/kaitai/generated/vlq_base128_be.h @@ -0,0 +1,117 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class vlq_base128_be_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +/** + * A variable-length unsigned integer using base128 encoding. 1-byte groups + * consist of 1-bit flag of continuation and 7-bit value chunk, and are ordered + * "most significant group first", i.e. in "big-endian" manner. + * + * This particular encoding is specified and used in: + * + * * Standard MIDI file format + * * ASN.1 BER encoding + * * RAR 5.0 file format + * + * More information on this encoding is available at + * + * + * This particular implementation supports serialized values to up 8 bytes long. + */ + +class vlq_base128_be_t : public kaitai::kstruct { + +public: + class group_t; + +private: + bool m__dirty; + +public: + + vlq_base128_be_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, vlq_base128_be_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~vlq_base128_be_t(); + + /** + * One byte group, clearly divided into 7-bit "value" chunk and 1-bit "continuation" flag. + */ + + class group_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + group_t(kaitai::kstream* p__io, vlq_base128_be_t* p__parent = nullptr, vlq_base128_be_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~group_t(); + + /** + * If true, then we have more bytes to read + */ + bool has_next() const { return m_has_next; } + void set_has_next(bool _v) { m__dirty = true; m_has_next = std::move(_v); } + + /** + * The 7-bit (base128) numeric value chunk of this group + */ + uint64_t value() const { return m_value; } + void set_value(uint64_t _v) { m__dirty = true; m_value = std::move(_v); } + vlq_base128_be_t* _root() const { return m__root; } + void set__root(vlq_base128_be_t* _v) { m__dirty = true; m__root = std::move(_v); } + vlq_base128_be_t* _parent() const { return m__parent; } + void set__parent(vlq_base128_be_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + bool m_has_next; + uint64_t m_value; + vlq_base128_be_t* m__root; + vlq_base128_be_t* m__parent; + }; + +public: + int32_t last(); + void _invalidate_last() { f_last = false; } + + /** + * Resulting value as normal integer + */ + uint64_t value(); + void _invalidate_value() { f_value = false; } + std::vector>* groups() const { return m_groups.get(); } + void set_groups(std::unique_ptr>> _v) { m__dirty = true; f_last = false; f_value = false; m_groups = std::move(_v); } + vlq_base128_be_t* _root() const { return m__root; } + void set__root(vlq_base128_be_t* _v) { m__dirty = true; f_last = false; f_value = false; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; f_last = false; f_value = false; m__parent = std::move(_v); } + +private: + bool f_last; + int32_t m_last; + bool f_value; + uint64_t m_value; + std::unique_ptr>> m_groups; + vlq_base128_be_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/test/KaitaiMidTest.cpp b/src/test/KaitaiMidTest.cpp new file mode 100644 index 00000000..03e8c562 --- /dev/null +++ b/src/test/KaitaiMidTest.cpp @@ -0,0 +1,225 @@ +#include + +#include "TestMpc.hpp" + +#include "file/kaitai/generated/standard_midi_file_with_running_status.h" +#include "file/mid/MidiReader.hpp" +#include "file/mid/MidiWriter.hpp" +#include "sequencer/NoteOnEvent.hpp" +#include "sequencer/Sequence.hpp" +#include "sequencer/Sequencer.hpp" +#include "sequencer/SequencerStateManager.hpp" +#include "sequencer/Track.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +namespace { + +struct ParsedNoteSnapshot { + int note; + int velocity; + int duration; + int variationType; +}; + +std::vector collectParsedNotes(const std::shared_ptr& track) +{ + std::vector result; + for (const auto& event : track->getEvents()) { + const auto note = std::dynamic_pointer_cast(event); + if (!note) { + continue; + } + result.push_back(ParsedNoteSnapshot{ + note->getNote(), + note->getVelocity(), + note->getDuration(), + note->getVariationType() + }); + } + return result; +} + +} + +TEST_CASE("Kaitai standard MIDI parses and rewrites FRUTZLE", "[kaitai-mid]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/FRUTZLE.MID"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + standard_midi_file_with_running_status_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.hdr() != nullptr); + REQUIRE(parsed.hdr()->num_tracks() > 0); + REQUIRE(parsed.tracks() != nullptr); + REQUIRE(parsed.tracks()->size() == parsed.hdr()->num_tracks()); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + REQUIRE(rewrittenBytes.size() == originalBytes.size()); + REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); +} + +TEST_CASE("Kaitai standard MIDI matches handwritten MIDI bytes", "[kaitai-mid]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + + auto sequencer = mpc.getSequencer(); + auto stateManager = sequencer->getStateManager(); + auto sequence = sequencer->getSequence(0); + sequence->init(1); + sequence->setName("KTAIMID"); + stateManager->drainQueue(); + + auto track0 = sequence->getTrack(0); + track0->setUsedIfCurrentlyUnused(); + track0->setDeviceIndex(2); + + mpc::sequencer::EventData eventData; + eventData.type = mpc::sequencer::EventType::NoteOn; + eventData.tick = 0; + eventData.noteNumber = mpc::NoteNumber(37); + eventData.velocity = mpc::MaxVelocity; + eventData.duration = mpc::Duration(10); + track0->acquireAndInsertEvent(eventData); + stateManager->drainQueue(); + + mpc::file::mid::MidiWriter handwrittenWriter(sequence.get()); + auto handwrittenStream = std::make_shared(); + handwrittenWriter.writeToOStream(handwrittenStream); + const auto handwrittenBytes = handwrittenStream->str(); + + std::stringstream parseStream( + handwrittenBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + standard_midi_file_with_running_status_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.hdr() != nullptr); + REQUIRE(parsed.hdr()->num_tracks() >= 2); + REQUIRE(parsed.tracks() != nullptr); + REQUIRE(parsed.tracks()->size() == parsed.hdr()->num_tracks()); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto kaitaiBytes = writeStream.str(); + REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); + + auto reloadSequence = sequencer->getSequence(0); + reloadSequence->init(1); + stateManager->drainQueue(); + + auto input = std::make_shared(kaitaiBytes); + mpc::file::mid::MidiReader reader(input, reloadSequence); + REQUIRE_NOTHROW(reader.parseSequence(mpc)); + stateManager->drainQueue(); + + REQUIRE(reloadSequence->getTrack(0)->getDeviceIndex() == 2); + REQUIRE(reloadSequence->getTrack(0)->getEvents().size() == 1); + auto note = std::dynamic_pointer_cast( + reloadSequence->getTrack(0)->getEvents()[0] + ); + REQUIRE(note); + REQUIRE(note->getNote() == 37); + REQUIRE(note->getVelocity() == 127); + REQUIRE(note->getDuration() == 10); +} + +TEST_CASE("Kaitai standard MIDI parses and rewrites real 2KXL SEQ", "[kaitai-mid][real-2kxl]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc2000xl/Mid/mpc2000xl_seq_variations.MID"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + standard_midi_file_with_running_status_t parsed(&parseIo); + parsed._read(); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + REQUIRE(rewrittenBytes.size() == originalBytes.size()); + REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + auto sequence = mpc.getSequencer()->getSequence(mpc::TempSequenceIndex); + auto stateManager = mpc.getSequencer()->getStateManager(); + sequence->init(1); + stateManager->drainQueue(); + + auto input = std::make_shared(rewrittenBytes); + mpc::file::mid::MidiReader reader(input, sequence); + REQUIRE_NOTHROW(reader.parseSequence(mpc)); + stateManager->drainQueue(); + + REQUIRE(sequence->getBarCount() == 1); + + int totalEvents = 0; + for (int trackIndex = 0; trackIndex < 64; ++trackIndex) { + totalEvents += static_cast(sequence->getTrack(trackIndex)->getEvents().size()); + } + REQUIRE(totalEvents == 7); + + const auto parsedNotes = collectParsedNotes(sequence->getTrack(0)); + REQUIRE(parsedNotes.size() == 7U); + + const std::vector expected{ + {0, 65, 13, mpc::NoteVariationTypeTune}, + {0, 35, 49, mpc::NoteVariationTypeDecay}, + {0, 75, 101, mpc::NoteVariationTypeAttack}, + {0, 30, 35, mpc::NoteVariationTypeFilter}, + {0, 22, 89, mpc::NoteVariationTypeFilter}, + {0, 46, 174, mpc::NoteVariationTypeTune}, + {0, 19, 161, mpc::NoteVariationTypeTune}, + }; + REQUIRE(parsedNotes.size() == expected.size()); + for (std::size_t i = 0; i < expected.size(); ++i) { + CAPTURE(i); + CAPTURE(parsedNotes[i].note); + CHECK(parsedNotes[i].velocity == expected[i].velocity); + CHECK(parsedNotes[i].duration == expected[i].duration); + CHECK(parsedNotes[i].variationType == expected[i].variationType); + } +} diff --git a/test-resources/RealMpc2000xl/Mid/mpc2000xl_seq_variations.MID b/test-resources/RealMpc2000xl/Mid/mpc2000xl_seq_variations.MID new file mode 100755 index 0000000000000000000000000000000000000000..abac485993a73216a597cd520a627c75a3988e33 GIT binary patch literal 270 zcmYjLO-sX25S)C}7D_=7G^es)-_g3Q(tr@~(d5*oFV;QusMLU^c(4cmfDr$Izt4a2 z+@OL3%g!>hJ6p>06M!QG2=P$LVXxB;KBBUkPnmhMq{*0>=)QiX|9}rhOXsT0tyC1d zmQ3wbtny5Yq$n%bYVdba_shdeM^7vKCXU0T_YQxF-@p$IJeI@bc7MT>zYq-|S=;%7 zax3 Date: Sun, 14 Jun 2026 11:56:03 +0200 Subject: [PATCH 06/52] Switch MPC file I/O to Kaitai-backed adapters --- src/main/disk/AbstractDisk.cpp | 45 +++------ src/main/disk/AllLoader.cpp | 34 ++----- src/main/disk/ApsLoader.cpp | 29 +----- src/main/disk/ProgramLoader.cpp | 4 +- src/main/disk/SoundLoader.cpp | 39 +------- src/main/file/kaitai/AllIo.cpp | 61 ++++++++++++ src/main/file/kaitai/AllIo.hpp | 39 ++++++++ src/main/file/kaitai/ApsIo.cpp | 32 ++++++ src/main/file/kaitai/ApsIo.hpp | 26 +++++ src/main/file/kaitai/KaitaiIoUtil.hpp | 31 ++++++ src/main/file/kaitai/MidIo.cpp | 55 +++++++++++ src/main/file/kaitai/MidIo.hpp | 32 ++++++ src/main/file/kaitai/PgmIo.cpp | 52 ++++++++++ src/main/file/kaitai/PgmIo.hpp | 40 ++++++++ src/main/file/kaitai/SndIo.cpp | 98 +++++++++++++++++++ src/main/file/kaitai/SndIo.hpp | 31 ++++++ src/main/file/kaitai/generated/mpc2000snd.cpp | 20 ++-- src/main/file/kaitai/generated/mpc2000snd.h | 6 +- .../screens/window/Mpc2000XlAllFileScreen.cpp | 4 +- src/test/KaitaiSndTest.cpp | 8 +- 20 files changed, 542 insertions(+), 144 deletions(-) create mode 100644 src/main/file/kaitai/AllIo.cpp create mode 100644 src/main/file/kaitai/AllIo.hpp create mode 100644 src/main/file/kaitai/ApsIo.cpp create mode 100644 src/main/file/kaitai/ApsIo.hpp create mode 100644 src/main/file/kaitai/KaitaiIoUtil.hpp create mode 100644 src/main/file/kaitai/MidIo.cpp create mode 100644 src/main/file/kaitai/MidIo.hpp create mode 100644 src/main/file/kaitai/PgmIo.cpp create mode 100644 src/main/file/kaitai/PgmIo.hpp create mode 100644 src/main/file/kaitai/SndIo.cpp create mode 100644 src/main/file/kaitai/SndIo.hpp diff --git a/src/main/disk/AbstractDisk.cpp b/src/main/disk/AbstractDisk.cpp index fde0c71e..035107be 100644 --- a/src/main/disk/AbstractDisk.cpp +++ b/src/main/disk/AbstractDisk.cpp @@ -15,6 +15,11 @@ #include "file/sndreader/SndReader.hpp" #include "file/aps/ApsParser.hpp" #include "file/all/AllParser.hpp" +#include "file/kaitai/SndIo.hpp" +#include "file/kaitai/PgmIo.hpp" +#include "file/kaitai/ApsIo.hpp" +#include "file/kaitai/MidIo.hpp" +#include "file/kaitai/AllIo.hpp" #include "sampler/Sampler.hpp" #include "sampler/Program.hpp" @@ -166,8 +171,7 @@ void AbstractDisk::writeSnd(const std::shared_ptr &s, const auto name = Util::getFileName( fileName == "" ? s->getName() + ".SND" : fileName); auto f = newFile(name); - auto sw = SndWriter(s.get()); - auto &sndArray = sw.getSndFileArray(); + auto sndArray = file::kaitai::SndIo::saveSound(*s); f->setFileData(sndArray); flush(); initFiles(); @@ -237,8 +241,7 @@ void AbstractDisk::writeMid(const std::shared_ptr &s, return tl::make_unexpected( mpc_io_error_msg{"Unable to open MIDI output stream"}); } - const MidiWriter writer(s.get()); - writer.writeToOStream(outputStream); + file::kaitai::MidIo::save(s, outputStream); flush(); initFiles(); mpc.getLayeredScreen()->showPopupAndThenReturnToLayer( @@ -330,8 +333,7 @@ void AbstractDisk::writePgm(const std::shared_ptr &p, const std::function writeFunc = [&]() -> file_or_error { auto f = newFile(fileName); - const PgmWriter writer(p.get(), mpc.getSampler()); - auto bytes = writer.get(); + auto bytes = file::kaitai::PgmIo::saveProgram(*p, mpc.getSampler()); f->setFileData(bytes); const std::string popupMsg = "Saving " + fileName; @@ -394,8 +396,7 @@ void AbstractDisk::writeAps(const std::string &fileName) { auto f = newFile(fileName); const auto apsName = f->getNameWithoutExtension(); - ApsParser apsParser(mpc, apsName); - auto bytes = apsParser.getBytes(); + auto bytes = file::kaitai::ApsIo::save(mpc, apsName); f->setFileData(bytes); auto saveAProgramScreen = @@ -439,8 +440,7 @@ void AbstractDisk::writeAll(const std::string &fileName) const std::function writeFunc = [&]() -> file_or_error { auto f = newFile(fileName); - AllParser allParser(mpc); - auto bytes = allParser.getBytes(); + auto bytes = file::kaitai::AllIo::save(mpc); f->setFileData(bytes); flush(); @@ -588,30 +588,7 @@ sequence_or_error AbstractDisk::readMid2(std::shared_ptr f) { const std::function readFunc = [this, f]() -> sequence_or_error { - if (!f) - { - return tl::make_unexpected(mpc_io_error_msg{"Empty file"}); - } - - const auto fStream = f->getInputStream(); - if (!fStream) - { - return tl::make_unexpected( - mpc_io_error_msg{"Unable to open MIDI input stream"}); - } - auto newSeq = mpc.getSequencer()->getSequence(TempSequenceIndex); - - newSeq->init(0); - - const MidiReader midiReader(fStream, newSeq); - midiReader.parseSequence(mpc); - - if (newSeq->getName().empty()) - { - newSeq->setName(f->getNameWithoutExtension()); - } - - return newSeq; + return file::kaitai::MidIo::load(mpc, f); }; return performRequiredIoOrOpenErrorPopup(readFunc); diff --git a/src/main/disk/AllLoader.cpp b/src/main/disk/AllLoader.cpp index d121b26a..08a95330 100644 --- a/src/main/disk/AllLoader.cpp +++ b/src/main/disk/AllLoader.cpp @@ -7,6 +7,7 @@ #include "controller/ClientMidiEventController.hpp" #include "controller/MidiFootswitchFunctionMap.hpp" #include "file/all/AllParser.hpp" +#include "file/kaitai/AllIo.hpp" #include "file/all/Count.hpp" #include "file/all/Defaults.hpp" #include "file/all/MidiInput.hpp" @@ -51,8 +52,7 @@ using namespace mpc::sequencer; void AllLoader::loadEverythingFromFile(Mpc &mpc, MpcFile *f) { - AllParser allParser(mpc, f->getBytes()); - loadEverythingFromAllParser(mpc, allParser); + file::kaitai::AllIo::loadEverything(mpc, f); } void AllLoader::loadEverythingFromAllParser(Mpc &mpc, AllParser &allParser) @@ -302,18 +302,12 @@ void AllLoader::loadEverythingFromAllParser(Mpc &mpc, AllParser &allParser) std::vector AllLoader::loadSequenceMetaInfosFromFile(Mpc &mpc, MpcFile *f) { - std::vector result; - const AllParser allParser(mpc, f->getBytes()); - - const auto allSeqNames = allParser.getSeqNames()->getNames(); - const auto allSeqUsednesses = allParser.getSeqNames()->getUsednesses(); - - for (int i = 0; i < Mpc2000XlSpecs::SEQUENCE_COUNT; ++i) + auto result = file::kaitai::AllIo::loadSequenceMetaInfos(mpc, f); + if (!result) { - result.push_back({allSeqUsednesses[i], allSeqNames[i]}); + throw std::runtime_error(result.error()); } - - return result; + return *result; } std::shared_ptr @@ -321,18 +315,6 @@ AllLoader::loadOneSequenceFromFile(Mpc &mpc, MpcFile *f, const SequenceIndex sourceIndexInAllFile, const SequenceIndex destIndexInMpcMemory) { - AllParser allParser(mpc, f->getBytes()); - - const auto allSequences = allParser.getAllSequences(); - - const auto allSeqNames = allParser.getSeqNames()->getNames(); - - const auto sequencer = mpc.getSequencer(); - - const auto sequence = sequencer->getSequence(destIndexInMpcMemory); - - allSequences[sourceIndexInAllFile]->applyToInMemorySequence( - sequence, sequencer->getStateManager().get()); - - return sequence; + return file::kaitai::AllIo::loadOneSequence( + mpc, f, sourceIndexInAllFile, destIndexInMpcMemory); } diff --git a/src/main/disk/ApsLoader.cpp b/src/main/disk/ApsLoader.cpp index f10e46b4..7f96a2b7 100644 --- a/src/main/disk/ApsLoader.cpp +++ b/src/main/disk/ApsLoader.cpp @@ -8,6 +8,7 @@ #include "disk/SoundLoader.hpp" #include "file/aps/ApsNoteParameters.hpp" #include "file/aps/ApsParser.hpp" +#include "file/kaitai/ApsIo.hpp" #include "file/aps/ApsSlider.hpp" #include "lcdgui/screens/DrumScreen.hpp" @@ -37,33 +38,7 @@ using namespace mpc::file::aps; void ApsLoader::load(Mpc &mpc, const std::shared_ptr &file, const bool headless) { - if (!file->exists()) - { - throw std::invalid_argument("File does not exist"); - } - - const auto seqScreen = mpc.screens->get(); - - const auto cantFindFileScreen = - mpc.screens->get(); - cantFindFileScreen->skipAll = false; - - ApsParser apsParser(file->getBytes()); - - if (!apsParser.isHeaderValid()) - { - MLOG( - "The APS file you're trying to load does not have a valid ID. The " - "first 2 bytes of an MPC2000XL APS file should be 0A 05. MPC2000 " - "APS files start with 0A 04 and are not supported (yet?)."); - - throw std::runtime_error("Invalid APS header"); - } - - constexpr auto withoutSounds = false; - loadFromParsedAps(apsParser, mpc, withoutSounds, headless); - - mpc.getSampler()->setSoundIndex(0); + file::kaitai::ApsIo::load(mpc, file, headless); } void ApsLoader::loadFromParsedAps(ApsParser &apsParser, Mpc &mpc, diff --git a/src/main/disk/ProgramLoader.cpp b/src/main/disk/ProgramLoader.cpp index aae3719e..e3444317 100644 --- a/src/main/disk/ProgramLoader.cpp +++ b/src/main/disk/ProgramLoader.cpp @@ -4,6 +4,7 @@ #include "disk/AbstractDisk.hpp" #include "disk/MpcFile.hpp" +#include "file/kaitai/PgmIo.hpp" #include "disk/PgmFileToProgramConverter.hpp" #include "disk/SoundLoader.hpp" #include "sampler/Program.hpp" @@ -81,8 +82,7 @@ ProgramLoader::loadProgram(Mpc &mpc, const std::shared_ptr &file, std::vector pgmSoundNames; - return PgmFileToProgramConverter::loadFromFileAndConvert(mpc, file, program, - pgmSoundNames) + return file::kaitai::PgmIo::loadProgram(mpc, file, program, pgmSoundNames) .map( [pgmSoundNames, &mpc, programIndex](std::shared_ptr p) { diff --git a/src/main/disk/SoundLoader.cpp b/src/main/disk/SoundLoader.cpp index 4538d5db..69722cf3 100644 --- a/src/main/disk/SoundLoader.cpp +++ b/src/main/disk/SoundLoader.cpp @@ -4,6 +4,7 @@ #include "disk/MpcFile.hpp" #include "disk/AbstractDisk.hpp" #include "file/wav/WavFile.hpp" +#include "file/kaitai/SndIo.hpp" #include "file/sndreader/SndReader.hpp" #include "sampler/Sampler.hpp" #include "sampler/Sound.hpp" @@ -83,42 +84,8 @@ void SoundLoader::loadSound(std::shared_ptr f, SoundLoaderResult &r, } else if (StrUtil::eqIgnoreCase(extension, ".snd")) { - auto onSndReaderSuccess = - [sampler, sound, nameWithoutExtension, &existingSoundIndex]( - const std::shared_ptr &sndReader) -> sound_or_error - { - if (!sndReader->isHeaderValid()) - { - return tl::make_unexpected( - mpc_io_error_msg{"Invalid SND header"}); - } - - if (StrUtil::eqIgnoreCase(sndReader->getName(), - nameWithoutExtension)) - { - existingSoundIndex = sampler->checkExists(sndReader->getName()); - sound->setName(sndReader->getName()); - } - else - { - existingSoundIndex = sampler->checkExists(nameWithoutExtension); - sound->setName(nameWithoutExtension); - } - - sndReader->readData(sound->getMutableSampleData()); - sound->setMono(sndReader->isMono()); - sound->setStart(sndReader->getStart()); - sound->setEnd(sndReader->getEnd()); - sound->setLoopTo(sndReader->getEnd() - sndReader->getLoopLength()); - sound->setSampleRate(sndReader->getSampleRate()); - sound->setLoopEnabled(sndReader->isLoopEnabled()); - sound->setLevel(sndReader->getLevel()); - sound->setTune(sndReader->getTune()); - sound->setBeatCount(sndReader->getNumberOfBeats()); - return sound; - }; - - soundOrError = mpc.getDisk()->readSnd2(f, onSndReaderSuccess); + existingSoundIndex = sampler->checkExists(nameWithoutExtension); + soundOrError = file::kaitai::SndIo::loadSound(f, sound, nameWithoutExtension); } if (!soundOrError.has_value()) diff --git a/src/main/file/kaitai/AllIo.cpp b/src/main/file/kaitai/AllIo.cpp new file mode 100644 index 00000000..1b32a6d0 --- /dev/null +++ b/src/main/file/kaitai/AllIo.cpp @@ -0,0 +1,61 @@ +#include "file/kaitai/AllIo.hpp" + +#include "Mpc.hpp" +#include "disk/AllLoader.hpp" +#include "disk/MpcFile.hpp" +#include "file/all/AllParser.hpp" +#include "file/all/AllSequence.hpp" +#include "file/all/SequenceNames.hpp" +#include "file/kaitai/KaitaiIoUtil.hpp" +#include "file/kaitai/generated/mpc2000xl_all.h" +#include "sequencer/Sequencer.hpp" + +using namespace mpc::file::kaitai; + +void AllIo::loadEverything(mpc::Mpc &mpc, mpc::disk::MpcFile *file) +{ + const auto canonicalBytes = parseRewrite(file->getBytes()); + mpc::file::all::AllParser parser(mpc, canonicalBytes); + mpc::disk::AllLoader::loadEverythingFromAllParser(mpc, parser); +} + +sequence_meta_infos_or_error AllIo::loadSequenceMetaInfos(mpc::Mpc &mpc, mpc::disk::MpcFile *file) +{ + const auto canonicalBytes = parseRewrite(file->getBytes()); + const mpc::file::all::AllParser parser(mpc, canonicalBytes); + + std::vector result; + const auto allSeqNames = parser.getSeqNames()->getNames(); + const auto allSeqUsednesses = parser.getSeqNames()->getUsednesses(); + + for (int i = 0; i < mpc::Mpc2000XlSpecs::SEQUENCE_COUNT; ++i) + { + result.push_back({allSeqUsednesses[i], allSeqNames[i]}); + } + + return result; +} + +std::shared_ptr AllIo::loadOneSequence( + mpc::Mpc &mpc, + mpc::disk::MpcFile *file, + mpc::SequenceIndex sourceIndexInAllFile, + mpc::SequenceIndex destIndexInMpcMemory) +{ + const auto canonicalBytes = parseRewrite(file->getBytes()); + mpc::file::all::AllParser parser(mpc, canonicalBytes); + + const auto sequence = mpc.getSequencer()->getSequence(destIndexInMpcMemory); + parser.getAllSequences()[sourceIndexInAllFile]->applyToInMemorySequence( + sequence, + mpc.getSequencer()->getStateManager().get() + ); + + return sequence; +} + +std::vector AllIo::save(mpc::Mpc &mpc) +{ + mpc::file::all::AllParser parser(mpc); + return parseRewrite(parser.getBytes()); +} diff --git a/src/main/file/kaitai/AllIo.hpp b/src/main/file/kaitai/AllIo.hpp new file mode 100644 index 00000000..1ffb86c8 --- /dev/null +++ b/src/main/file/kaitai/AllIo.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "IntTypes.hpp" +#include "mpc_types.hpp" + +#include +#include + +namespace mpc +{ + class Mpc; +} + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::sequencer +{ + class Sequence; + struct SequenceMetaInfo; +} + +namespace mpc::file::kaitai +{ + class AllIo + { + public: + static void loadEverything(mpc::Mpc &, mpc::disk::MpcFile *); + static sequence_meta_infos_or_error loadSequenceMetaInfos(mpc::Mpc &, mpc::disk::MpcFile *); + static std::shared_ptr loadOneSequence( + mpc::Mpc &, + mpc::disk::MpcFile *, + mpc::SequenceIndex sourceIndexInAllFile, + mpc::SequenceIndex destIndexInMpcMemory); + static std::vector save(mpc::Mpc &); + }; +} diff --git a/src/main/file/kaitai/ApsIo.cpp b/src/main/file/kaitai/ApsIo.cpp new file mode 100644 index 00000000..0392c4eb --- /dev/null +++ b/src/main/file/kaitai/ApsIo.cpp @@ -0,0 +1,32 @@ +#include "file/kaitai/ApsIo.hpp" + +#include "Mpc.hpp" +#include "disk/ApsLoader.hpp" +#include "disk/MpcFile.hpp" +#include "file/aps/ApsParser.hpp" +#include "file/kaitai/KaitaiIoUtil.hpp" +#include "file/kaitai/generated/mpc2000xl_aps.h" +#include "sampler/Sampler.hpp" + +using namespace mpc::file::kaitai; + +void ApsIo::load(mpc::Mpc &mpc, const std::shared_ptr &file, bool headless) +{ + const auto canonicalBytes = parseRewrite(file->getBytes()); + mpc::file::aps::ApsParser parser(canonicalBytes); + + if (!parser.isHeaderValid()) + { + throw std::runtime_error("Invalid APS header"); + } + + constexpr auto withoutSounds = false; + mpc::disk::ApsLoader::loadFromParsedAps(parser, mpc, withoutSounds, headless); + mpc.getSampler()->setSoundIndex(0); +} + +std::vector ApsIo::save(mpc::Mpc &mpc, const std::string &apsName) +{ + mpc::file::aps::ApsParser parser(mpc, apsName); + return parseRewrite(parser.getBytes()); +} diff --git a/src/main/file/kaitai/ApsIo.hpp b/src/main/file/kaitai/ApsIo.hpp new file mode 100644 index 00000000..c18d0247 --- /dev/null +++ b/src/main/file/kaitai/ApsIo.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include + +namespace mpc +{ + class Mpc; +} + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::file::kaitai +{ + class ApsIo + { + public: + static void load(mpc::Mpc &, const std::shared_ptr &, bool headless); + static std::vector save(mpc::Mpc &, const std::string &apsName); + }; +} diff --git a/src/main/file/kaitai/KaitaiIoUtil.hpp b/src/main/file/kaitai/KaitaiIoUtil.hpp new file mode 100644 index 00000000..7107a008 --- /dev/null +++ b/src/main/file/kaitai/KaitaiIoUtil.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include +#include +#include + +namespace mpc::file::kaitai +{ + template + inline std::vector parseRewrite(const std::vector &bytes) + { + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream parseIo(&parseStream); + T parsed(&parseIo); + parsed._read(); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + ::kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto written = writeStream.str(); + return std::vector(written.begin(), written.end()); + } +} diff --git a/src/main/file/kaitai/MidIo.cpp b/src/main/file/kaitai/MidIo.cpp new file mode 100644 index 00000000..77424915 --- /dev/null +++ b/src/main/file/kaitai/MidIo.cpp @@ -0,0 +1,55 @@ +#include "file/kaitai/MidIo.hpp" + +#include "Mpc.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/KaitaiIoUtil.hpp" +#include "file/kaitai/generated/standard_midi_file_with_running_status.h" +#include "file/mid/MidiReader.hpp" +#include "file/mid/MidiWriter.hpp" +#include "sequencer/Sequence.hpp" +#include "sequencer/Sequencer.hpp" + +#include + +using namespace mpc::file::kaitai; + +sequence_or_error MidIo::load(mpc::Mpc &mpc, const std::shared_ptr &file) +{ + const auto bytes = file->getBytes(); + const auto canonicalBytes = parseRewrite(bytes); + + auto newSeq = mpc.getSequencer()->getSequence(mpc::TempSequenceIndex); + newSeq->init(0); + + auto input = std::make_shared( + std::string(canonicalBytes.begin(), canonicalBytes.end()), + std::ios::in | std::ios::binary + ); + mpc::file::mid::MidiReader reader(input, newSeq); + reader.parseSequence(mpc); + + if (newSeq->getName().empty()) + { + newSeq->setName(file->getNameWithoutExtension()); + } + + return newSeq; +} + +void MidIo::save(const std::shared_ptr &sequence, + const std::shared_ptr &outputStream) +{ + mpc::file::mid::MidiWriter handwrittenWriter(sequence.get()); + auto handwrittenStream = std::make_shared(); + handwrittenWriter.writeToOStream(handwrittenStream); + const auto handwrittenBytesString = handwrittenStream->str(); + const std::vector handwrittenBytes( + handwrittenBytesString.begin(), + handwrittenBytesString.end() + ); + + const auto canonicalBytes = + parseRewrite(handwrittenBytes); + + outputStream->write(canonicalBytes.data(), static_cast(canonicalBytes.size())); +} diff --git a/src/main/file/kaitai/MidIo.hpp b/src/main/file/kaitai/MidIo.hpp new file mode 100644 index 00000000..6da4376b --- /dev/null +++ b/src/main/file/kaitai/MidIo.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "mpc_types.hpp" + +#include +#include +#include + +namespace mpc +{ + class Mpc; +} + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::sequencer +{ + class Sequence; +} + +namespace mpc::file::kaitai +{ + class MidIo + { + public: + static sequence_or_error load(mpc::Mpc &, const std::shared_ptr &); + static void save(const std::shared_ptr &, const std::shared_ptr &); + }; +} diff --git a/src/main/file/kaitai/PgmIo.cpp b/src/main/file/kaitai/PgmIo.cpp new file mode 100644 index 00000000..12a54fec --- /dev/null +++ b/src/main/file/kaitai/PgmIo.cpp @@ -0,0 +1,52 @@ +#include "file/kaitai/PgmIo.hpp" + +#include "Mpc.hpp" +#include "StrUtil.hpp" +#include "disk/MpcFile.hpp" +#include "engine/IndivFxMixer.hpp" +#include "engine/StereoMixer.hpp" +#include "disk/PgmFileToProgramConverter.hpp" +#include "file/kaitai/KaitaiIoUtil.hpp" +#include "file/kaitai/generated/mpc2000xl_pgm.h" +#include "mpc_fs.hpp" +#include "sampler/Program.hpp" +#include "sampler/Sampler.hpp" +#include "file/pgmwriter/PgmWriter.hpp" + +using namespace mpc::file::kaitai; + +program_or_error PgmIo::loadProgram(mpc::Mpc &mpc, + const std::shared_ptr &file, + const std::shared_ptr &program, + std::vector &soundNames) +{ + const auto fileBytes = file->getBytes(); + const auto canonicalBytes = parseRewrite(fileBytes); + + const auto tempDirRes = mpc_fs::temp_directory_path(); + if (!tempDirRes) + { + return tl::make_unexpected(mpc::disk::mpc_io_error_msg{"Unable to resolve temp directory"}); + } + + auto tempPath = *tempDirRes / file->getName(); + auto tempFile = std::make_shared( + std::variant>(tempPath) + ); + + auto mutableBytes = canonicalBytes; + tempFile->setFileData(mutableBytes); + const auto result = + mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( + mpc, tempFile, program, soundNames); + (void)mpc_fs::remove(tempPath); + return result; +} + +std::vector PgmIo::saveProgram(mpc::sampler::Program &program, + const std::weak_ptr &sampler) +{ + const mpc::file::pgmwriter::PgmWriter handwrittenWriter(&program, sampler); + const auto handwrittenBytes = handwrittenWriter.get(); + return parseRewrite(handwrittenBytes); +} diff --git a/src/main/file/kaitai/PgmIo.hpp b/src/main/file/kaitai/PgmIo.hpp new file mode 100644 index 00000000..c74c1aca --- /dev/null +++ b/src/main/file/kaitai/PgmIo.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "mpc_types.hpp" + +#include +#include +#include + +namespace mpc +{ + class Mpc; +} + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::sampler +{ + class Program; + class Sampler; +} + +namespace mpc::file::kaitai +{ + class PgmIo + { + public: + static program_or_error loadProgram( + mpc::Mpc &, + const std::shared_ptr &, + const std::shared_ptr &, + std::vector &soundNames); + + static std::vector saveProgram( + sampler::Program &, + const std::weak_ptr &); + }; +} diff --git a/src/main/file/kaitai/SndIo.cpp b/src/main/file/kaitai/SndIo.cpp new file mode 100644 index 00000000..29391a0a --- /dev/null +++ b/src/main/file/kaitai/SndIo.cpp @@ -0,0 +1,98 @@ +#include "file/kaitai/SndIo.hpp" + +#include "SampleOps.hpp" +#include "StrUtil.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/KaitaiIoUtil.hpp" +#include "file/kaitai/generated/mpc2000snd.h" +#include "sampler/Sound.hpp" + +using namespace mpc::file::kaitai; +using namespace mpc::sampleops; + +sound_or_error SndIo::loadSound(const std::shared_ptr &file, + const std::shared_ptr &sound, + const std::string &nameWithoutExtension) +{ + const auto bytes = file->getBytes(); + + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream parseIo(&parseStream); + mpc2000snd_t parsed(&parseIo); + parsed._read(); + + auto parsedName = parsed.name(); + const auto nulPos = parsedName.find('\0'); + if (nulPos != std::string::npos) + { + parsedName.erase(nulPos); + } + while (!parsedName.empty() && parsedName.back() == ' ') + { + parsedName.pop_back(); + } + + const auto soundName = StrUtil::eqIgnoreCase(parsedName, nameWithoutExtension) + ? parsedName + : nameWithoutExtension; + + sound->setName(soundName); + sound->setMono(!parsed.stereo()); + sound->setSampleRate(parsed.sample_rate()); + sound->setLevel(parsed.level()); + sound->setTune(parsed.tune()); + sound->setBeatCount(parsed.beat_count()); + sound->setLoopEnabled(parsed.loop_enabled()); + + auto sampleData = sound->getMutableSampleData(); + sampleData->clear(); + if (parsed.sample_data() != nullptr) + { + for (const auto frame : *parsed.sample_data()) + { + sampleData->push_back(short_to_float(frame)); + } + } + + sound->setStart(parsed.start()); + sound->setEnd(parsed.end()); + sound->setLoopTo(parsed.end() - parsed.loop_frame_count()); + + return sound; +} + +std::vector SndIo::saveSound(mpc::sampler::Sound &sound) +{ + mpc2000snd_t parsed(nullptr); + parsed.set_magic(std::string("\x01\x04", 2)); + parsed.set_name(StrUtil::padRight(sound.getName(), " ", 16) + '\0'); + parsed.set_level(sound.getSndLevel()); + parsed.set_tune(static_cast(sound.getTune())); + parsed.set_stereo(!sound.isMono()); + parsed.set_start(sound.getStart()); + parsed.set_end(sound.getEnd()); + parsed.set_frame_count(sound.getFrameCount()); + parsed.set_loop_frame_count(sound.getEnd() - sound.getLoopTo()); + parsed.set_loop_enabled(sound.isLoopEnabled()); + parsed.set_beat_count(sound.getBeatCount()); + parsed.set_sample_rate(sound.getSampleRate()); + + auto frames = std::make_unique>(); + for (const auto sample : *sound.getSampleData()) + { + frames->push_back(mean_normalized_float_to_short(sample)); + } + parsed.set_sample_data(std::move(frames)); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + ::kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto written = writeStream.str(); + return std::vector(written.begin(), written.end()); +} diff --git a/src/main/file/kaitai/SndIo.hpp b/src/main/file/kaitai/SndIo.hpp new file mode 100644 index 00000000..ef357403 --- /dev/null +++ b/src/main/file/kaitai/SndIo.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "mpc_types.hpp" + +#include +#include +#include + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::sampler +{ + class Sound; +} + +namespace mpc::file::kaitai +{ + class SndIo + { + public: + static sound_or_error loadSound( + const std::shared_ptr &, + const std::shared_ptr &, + const std::string &nameWithoutExtension); + + static std::vector saveSound(sampler::Sound &); + }; +} diff --git a/src/main/file/kaitai/generated/mpc2000snd.cpp b/src/main/file/kaitai/generated/mpc2000snd.cpp index 09e5e7ad..976356bd 100644 --- a/src/main/file/kaitai/generated/mpc2000snd.cpp +++ b/src/main/file/kaitai/generated/mpc2000snd.cpp @@ -27,16 +27,16 @@ void mpc2000snd_t::_read() { m_loop_enabled = m__io->read_bits_int_le(1); m_beat_count = m__io->read_u1(); m_sample_rate = m__io->read_u2le(); - m_frames = std::unique_ptr>(new std::vector()); - const int l_frames = frame_count(); - for (int i = 0; i < l_frames; i++) { - m_frames->push_back(std::move(m__io->read_s2le())); + m_sample_data = std::unique_ptr>(new std::vector()); + const int l_sample_data = ((stereo()) ? (frame_count() * 2) : (frame_count())); + for (int i = 0; i < l_sample_data; i++) { + m_sample_data->push_back(std::move(m__io->read_s2le())); } m__dirty = false; } void mpc2000snd_t::_fetch_instances() { - for (std::size_t i = 0; i < m_frames->size(); ++i) { + for (std::size_t i = 0; i < m_sample_data->size(); ++i) { } } @@ -53,10 +53,10 @@ void mpc2000snd_t::_write() { m__io->write_bits_int_le(1, ((m_loop_enabled) ? 1 : 0)); m__io->write_u1(m_beat_count); m__io->write_u2le(m_sample_rate); - if (m_frames == nullptr) { + if (m_sample_data == nullptr) { throw std::runtime_error("/seq/12: repeated field is not set"); } - for (std::vector::const_iterator it = m_frames->begin(); it != m_frames->end(); ++it) { + for (std::vector::const_iterator it = m_sample_data->begin(); it != m_sample_data->end(); ++it) { m__io->write_s2le((*it)); } _fetch_instances(); @@ -73,13 +73,13 @@ void mpc2000snd_t::_check() { if (m_name.size() != static_cast(17)) { throw std::runtime_error("/seq/1: size mismatch"); } - if (m_frames == nullptr) { + if (m_sample_data == nullptr) { throw std::runtime_error("/seq/12: repeated field is not set"); } - if (m_frames->size() != static_cast(frame_count())) { + if (m_sample_data->size() != static_cast(((stereo()) ? (frame_count() * 2) : (frame_count())))) { throw std::runtime_error("/seq/12: repeat-expr size mismatch"); } - for (std::vector::const_iterator it = m_frames->begin(); it != m_frames->end(); ++it) { + for (std::vector::const_iterator it = m_sample_data->begin(); it != m_sample_data->end(); ++it) { } m__dirty = false; } diff --git a/src/main/file/kaitai/generated/mpc2000snd.h b/src/main/file/kaitai/generated/mpc2000snd.h index 10b92702..04f1afa6 100644 --- a/src/main/file/kaitai/generated/mpc2000snd.h +++ b/src/main/file/kaitai/generated/mpc2000snd.h @@ -52,8 +52,8 @@ class mpc2000snd_t : public kaitai::kstruct { void set_beat_count(uint8_t _v) { m__dirty = true; m_beat_count = std::move(_v); } uint16_t sample_rate() const { return m_sample_rate; } void set_sample_rate(uint16_t _v) { m__dirty = true; m_sample_rate = std::move(_v); } - std::vector* frames() const { return m_frames.get(); } - void set_frames(std::unique_ptr> _v) { m__dirty = true; m_frames = std::move(_v); } + std::vector* sample_data() const { return m_sample_data.get(); } + void set_sample_data(std::unique_ptr> _v) { m__dirty = true; m_sample_data = std::move(_v); } mpc2000snd_t* _root() const { return m__root; } void set__root(mpc2000snd_t* _v) { m__dirty = true; m__root = std::move(_v); } kaitai::kstruct* _parent() const { return m__parent; } @@ -72,7 +72,7 @@ class mpc2000snd_t : public kaitai::kstruct { bool m_loop_enabled; uint8_t m_beat_count; uint16_t m_sample_rate; - std::unique_ptr> m_frames; + std::unique_ptr> m_sample_data; mpc2000snd_t* m__root; kaitai::kstruct* m__parent; }; diff --git a/src/main/lcdgui/screens/window/Mpc2000XlAllFileScreen.cpp b/src/main/lcdgui/screens/window/Mpc2000XlAllFileScreen.cpp index f801d0ce..73117cc6 100644 --- a/src/main/lcdgui/screens/window/Mpc2000XlAllFileScreen.cpp +++ b/src/main/lcdgui/screens/window/Mpc2000XlAllFileScreen.cpp @@ -45,10 +45,10 @@ void Mpc2000XlAllFileScreen::function(const int i) case 4: { const auto selectedFile = loadScreen->getSelectedFile(); + mpc.screens->get()->setFileName( + selectedFile->getNameWithoutExtension()); auto on_success = [&, selectedFile] { - mpc.screens->get()->setFileName( - selectedFile->getNameWithoutExtension()); openScreenById(ScreenId::LoadScreen); }; mpc.getDisk()->readAll2(selectedFile, on_success); diff --git a/src/test/KaitaiSndTest.cpp b/src/test/KaitaiSndTest.cpp index 95f3e604..105af883 100644 --- a/src/test/KaitaiSndTest.cpp +++ b/src/test/KaitaiSndTest.cpp @@ -62,10 +62,10 @@ TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") REQUIRE(parsed.loop_enabled() == true); REQUIRE(parsed.beat_count() == 4); REQUIRE(parsed.sample_rate() == 44100); - REQUIRE(parsed.frames() != nullptr); - REQUIRE(parsed.frames()->size() == 2U); - REQUIRE(parsed.frames()->at(0) == 1234); - REQUIRE(parsed.frames()->at(1) == -1234); + REQUIRE(parsed.sample_data() != nullptr); + REQUIRE(parsed.sample_data()->size() == 2U); + REQUIRE(parsed.sample_data()->at(0) == 1234); + REQUIRE(parsed.sample_data()->at(1) == -1234); std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); kaitai::kstream writeIo(&writeStream); From 2e7a6d9f4a25aa3f66af8e5f5b0bb2e3d673c8be Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Fri, 19 Jun 2026 18:51:41 +0200 Subject: [PATCH 07/52] Expand SND Kaitai parity coverage --- cmake/MpcResourceBundling.cmake | 4 +- src/main/file/kaitai/SndIo.cpp | 2 +- src/test/KaitaiSndTest.cpp | 525 +++++++++++++++--- .../GeneratedMpc2000xl/Snd/README.txt | 12 + .../Snd/mono_corpus_min.SND | Bin 0 -> 50 bytes .../GeneratedMpc2000xl/Snd/mono_loop_mid.SND | Bin 0 -> 50 bytes .../Snd/name_len_sixteen.SND | Bin 0 -> 58 bytes .../GeneratedMpc2000xl/Snd/stereo_max.SND | Bin 0 -> 62 bytes .../GeneratedMpc2000xl/Snd/stereo_span.SND | Bin 0 -> 62 bytes 9 files changed, 470 insertions(+), 73 deletions(-) create mode 100644 test-resources/GeneratedMpc2000xl/Snd/README.txt create mode 100644 test-resources/GeneratedMpc2000xl/Snd/mono_corpus_min.SND create mode 100644 test-resources/GeneratedMpc2000xl/Snd/mono_loop_mid.SND create mode 100644 test-resources/GeneratedMpc2000xl/Snd/name_len_sixteen.SND create mode 100644 test-resources/GeneratedMpc2000xl/Snd/stereo_max.SND create mode 100644 test-resources/GeneratedMpc2000xl/Snd/stereo_span.SND diff --git a/cmake/MpcResourceBundling.cmake b/cmake/MpcResourceBundling.cmake index 8bebd70d..6e627c40 100644 --- a/cmake/MpcResourceBundling.cmake +++ b/cmake/MpcResourceBundling.cmake @@ -40,7 +40,7 @@ function(_bundle_resources) _generate_mpc_required_resource_manifest() - file(GLOB_RECURSE MPC_RESOURCES "${_mpc_resources_root}/*") + file(GLOB_RECURSE MPC_RESOURCES CONFIGURE_DEPENDS "${_mpc_resources_root}/*") list(FILTER MPC_RESOURCES EXCLUDE REGEX "\\.DS_Store$") if (APPLE) @@ -62,7 +62,7 @@ function(_bundle_resources) target_link_libraries(mpc mpc::rc) endif() - file(GLOB_RECURSE MPC_TEST_RESOURCES "${_mpc_test_resources_root}/*") + file(GLOB_RECURSE MPC_TEST_RESOURCES CONFIGURE_DEPENDS "${_mpc_test_resources_root}/*") list(FILTER MPC_TEST_RESOURCES EXCLUDE REGEX "\\.DS_Store$") cmrc_add_resource_library( diff --git a/src/main/file/kaitai/SndIo.cpp b/src/main/file/kaitai/SndIo.cpp index 29391a0a..136492a9 100644 --- a/src/main/file/kaitai/SndIo.cpp +++ b/src/main/file/kaitai/SndIo.cpp @@ -68,7 +68,7 @@ std::vector SndIo::saveSound(mpc::sampler::Sound &sound) { mpc2000snd_t parsed(nullptr); parsed.set_magic(std::string("\x01\x04", 2)); - parsed.set_name(StrUtil::padRight(sound.getName(), " ", 16) + '\0'); + parsed.set_name(StrUtil::padRight(sound.getName().substr(0, 16), " ", 16) + '\0'); parsed.set_level(sound.getSndLevel()); parsed.set_tune(static_cast(sound.getTune())); parsed.set_stereo(!sound.isMono()); diff --git a/src/test/KaitaiSndTest.cpp b/src/test/KaitaiSndTest.cpp index 105af883..7889a79b 100644 --- a/src/test/KaitaiSndTest.cpp +++ b/src/test/KaitaiSndTest.cpp @@ -1,14 +1,22 @@ #include +#include "Mpc.hpp" #include "SampleOps.hpp" +#include "TestMpc.hpp" +#include "disk/MpcFile.hpp" +#include "disk/SoundLoader.hpp" +#include "file/kaitai/SndIo.hpp" #include "file/kaitai/generated/mpc2000snd.h" #include "file/sndreader/SndReader.hpp" #include "file/sndwriter/SndWriter.hpp" +#include "sampler/Sampler.hpp" #include "sampler/Sound.hpp" #include #include +#include +#include #include #include #include @@ -17,10 +25,133 @@ CMRC_DECLARE(mpctest); +using namespace mpc::disk; +using namespace mpc::file::kaitai; using namespace mpc::file::sndreader; using namespace mpc::file::sndwriter; using namespace mpc::sampleops; +namespace +{ + struct ExpectedSound + { + std::string name; + bool mono; + int sampleRate; + int level; + int tune; + int beatCount; + int start; + int end; + int loopTo; + bool loopEnabled; + std::vector sampleData; + }; + + struct SaveRoundtripCase + { + std::string label; + std::string fileStem; + ExpectedSound expected; + }; + + std::vector resourceBytes(const std::string &resourcePath) + { + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open(resourcePath); + return std::vector(file.begin(), file.end()); + } + + template + void withParsedSndBytes(const std::vector &bytes, Assertions &&assertions) + { + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000snd_t parsed(&parseIo); + parsed._read(); + assertions(parsed); + } + + std::shared_ptr writeTempSndFile(const std::vector &bytes, + const std::string &fileName) + { + const auto tempDir = mpc_fs::temp_directory_path().value_or(mpc_fs::path{}); + const auto path = tempDir / fileName; + auto file = std::make_shared(path); + auto bytesCopy = bytes; + file->setFileData(bytesCopy); + return file; + } + + std::shared_ptr loadWithSoundLoader(mpc::Mpc &mpc, + const std::vector &bytes, + const std::string &fileName) + { + auto file = writeTempSndFile(bytes, fileName); + auto sound = mpc.getSampler()->addSound(); + SoundLoaderResult result; + SoundLoader loader(mpc, false); + loader.loadSound(file, result, sound, false); + REQUIRE(result.success); + return sound; + } + + void requireSoundMatches(const std::shared_ptr &sound, + const ExpectedSound &expected) + { + REQUIRE(sound->getName() == expected.name); + REQUIRE(sound->isMono() == expected.mono); + REQUIRE(sound->getSampleRate() == expected.sampleRate); + REQUIRE(sound->getSndLevel() == expected.level); + REQUIRE(sound->getTune() == expected.tune); + REQUIRE(sound->getBeatCount() == expected.beatCount); + REQUIRE(sound->getStart() == expected.start); + REQUIRE(sound->getEnd() == expected.end); + REQUIRE(sound->getLoopTo() == expected.loopTo); + REQUIRE(sound->isLoopEnabled() == expected.loopEnabled); + REQUIRE(sound->getFrameCount() == static_cast(expected.sampleData.size() / (expected.mono ? 1 : 2))); + REQUIRE(*sound->getSampleData() == expected.sampleData); + } + + std::vector monoSamples(const std::vector &samples) + { + std::vector result; + result.reserve(samples.size()); + for (const auto sample : samples) + { + result.push_back(short_to_float(sample)); + } + return result; + } + + std::vector stereoSamples(const std::vector &left, + const std::vector &right) + { + std::vector result; + result.reserve(left.size() + right.size()); + for (const auto sample : left) + { + result.push_back(short_to_float(sample)); + } + for (const auto sample : right) + { + result.push_back(short_to_float(sample)); + } + return result; + } + + std::string expectedHeaderName(const std::string &name) + { + auto truncated = name.substr(0, 16); + truncated.append(16 - truncated.size(), ' '); + truncated.push_back('\0'); + return truncated; + } +} + TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") { mpc::sampler::Sound sound(44100); @@ -42,38 +173,36 @@ TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") SndWriter handwrittenWriter(&sound); const auto handwrittenBytes = handwrittenWriter.getSndFileArray(); - std::stringstream parseStream( - std::string(handwrittenBytes.begin(), handwrittenBytes.end()), - std::ios::in | std::ios::out | std::ios::binary - ); - kaitai::kstream parseIo(&parseStream); - mpc2000snd_t parsed(&parseIo); - parsed._read(); - - REQUIRE(parsed.magic() == std::string("\x01\x04", 2)); - REQUIRE(parsed.name() == std::string(handwrittenBytes.begin() + 2, handwrittenBytes.begin() + 19)); - REQUIRE(parsed.level() == 100); - REQUIRE(parsed.tune() == -2); - REQUIRE(parsed.stereo() == false); - REQUIRE(parsed.start() == 0U); - REQUIRE(parsed.end() == 2U); - REQUIRE(parsed.frame_count() == 2U); - REQUIRE(parsed.loop_frame_count() == 1U); - REQUIRE(parsed.loop_enabled() == true); - REQUIRE(parsed.beat_count() == 4); - REQUIRE(parsed.sample_rate() == 44100); - REQUIRE(parsed.sample_data() != nullptr); - REQUIRE(parsed.sample_data()->size() == 2U); - REQUIRE(parsed.sample_data()->at(0) == 1234); - REQUIRE(parsed.sample_data()->at(1) == -1234); - - std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); - kaitai::kstream writeIo(&writeStream); - parsed._set_io(&writeIo); - parsed._check(); - parsed._write(); - - const auto kaitaiBytes = writeStream.str(); + std::string kaitaiBytes; + + withParsedSndBytes(handwrittenBytes, [&](mpc2000snd_t &parsed) + { + REQUIRE(parsed.magic() == std::string("\x01\x04", 2)); + REQUIRE(parsed.name() == std::string(handwrittenBytes.begin() + 2, handwrittenBytes.begin() + 19)); + REQUIRE(parsed.level() == 100); + REQUIRE(parsed.tune() == -2); + REQUIRE(parsed.stereo() == false); + REQUIRE(parsed.start() == 0U); + REQUIRE(parsed.end() == 2U); + REQUIRE(parsed.frame_count() == 2U); + REQUIRE(parsed.loop_frame_count() == 1U); + REQUIRE(parsed.loop_enabled() == true); + REQUIRE(parsed.beat_count() == 4); + REQUIRE(parsed.sample_rate() == 44100); + REQUIRE(parsed.sample_data() != nullptr); + REQUIRE(parsed.sample_data()->size() == 2U); + REQUIRE(parsed.sample_data()->at(0) == 1234); + REQUIRE(parsed.sample_data()->at(1) == -1234); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + kaitaiBytes = writeStream.str(); + }); + REQUIRE(kaitaiBytes == std::string(handwrittenBytes.begin(), handwrittenBytes.end())); std::vector kaitaiBytesVec(kaitaiBytes.begin(), kaitaiBytes.end()); @@ -97,46 +226,302 @@ TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") REQUIRE((*outputData)[1] == (*inputData)[1]); } -TEST_CASE("Kaitai MPC2000 SND parses real 2KXL mono and stereo files", "[kaitai-snd][real-2kxl]") +TEST_CASE("Kaitai MPC2000 SND save/load covers prod-used sound properties", "[kaitai-snd]") { - auto parseFile = [](const std::string& resourcePath, auto&& assertions) { - auto fs = cmrc::mpctest::get_filesystem(); - auto file = fs.open(resourcePath); - std::stringstream stream( - std::string( - std::string_view(file.begin(), file.end() - file.begin()) - ), - std::ios::in | std::ios::out | std::ios::binary - ); - kaitai::kstream ks(&stream); - mpc2000snd_t parsed(&ks); - parsed._read(); - assertions(parsed); + const auto cases = std::vector{ + { + "mono minimum bounds", + "mono_min_bounds", + ExpectedSound{ + "mono_min_bounds", + true, + 0, + 0, + -120, + 1, + 0, + 0, + 0, + false, + monoSamples({-32768, -1, 0, 32767}) + } + }, + { + "mono mid values", + "mono_mid_values", + ExpectedSound{ + "mono_mid_values", + true, + 44100, + 100, + 0, + 16, + 1, + 3, + 2, + true, + monoSamples({-12345, -17, 19, 12345}) + } + }, + { + "stereo full span loop off", + "stereo_full_span", + ExpectedSound{ + "stereo_full_span", + false, + 22050, + 100, + 0, + 16, + 0, + 5, + 0, + false, + stereoSamples({1000, 2000, 3000, 4000, 5000}, {-1000, -2000, -3000, -4000, -5000}) + } + }, + { + "stereo maximum bounds", + "stereo_max_bounds", + ExpectedSound{ + "stereo_max_bounds", + false, + 65535, + 200, + 120, + 32, + 5, + 5, + 5, + true, + stereoSamples({32767, 23456, 12345, 1, -1}, {-32768, -23456, -12345, -1, 1}) + } + } }; - parseFile("test/RealMpc2000xl/Snd/mono_loop_off.SND", [](const mpc2000snd_t& mono) { - REQUIRE(mono.magic() == std::string("\x01\x04", 2)); - REQUIRE(mono.level() == 100); - REQUIRE(mono.tune() == 0); - REQUIRE(mono.start() == 0U); - REQUIRE(mono.end() == 8012U); - REQUIRE(mono.frame_count() == 8012U); - REQUIRE(mono.loop_frame_count() == 8012U); - REQUIRE(mono.beat_count() == 4); - REQUIRE(mono.sample_rate() == 44100); - REQUIRE(mono.stereo() == false); - }); + for (const auto &testCase : cases) + { + SECTION(testCase.label) + { + mpc::sampler::Sound source(testCase.expected.sampleRate); + source.setName(testCase.expected.name); + source.setMono(testCase.expected.mono); + source.setLevel(testCase.expected.level); + source.setTune(testCase.expected.tune); + source.setBeatCount(testCase.expected.beatCount); - parseFile("test/RealMpc2000xl/Snd/stereo_loop_off.SND", [](const mpc2000snd_t& stereo) { - REQUIRE(stereo.magic() == std::string("\x01\x04", 2)); - REQUIRE(stereo.level() == 100); - REQUIRE(stereo.tune() == 0); - REQUIRE(stereo.start() == 0U); - REQUIRE(stereo.end() == 8012U); - REQUIRE(stereo.frame_count() == 8012U); - REQUIRE(stereo.loop_frame_count() == 8012U); - REQUIRE(stereo.beat_count() == 4); - REQUIRE(stereo.sample_rate() == 44100); - REQUIRE(stereo.stereo() == true); - }); + auto mutableData = source.getMutableSampleData(); + *mutableData = testCase.expected.sampleData; + + source.setStart(testCase.expected.start); + source.setEnd(testCase.expected.end); + source.setLoopTo(testCase.expected.loopTo); + source.setLoopEnabled(testCase.expected.loopEnabled); + + const auto bytes = SndIo::saveSound(source); + withParsedSndBytes(bytes, [&](mpc2000snd_t &parsed) + { + REQUIRE(parsed.level() == static_cast(testCase.expected.level)); + REQUIRE(parsed.tune() == testCase.expected.tune); + REQUIRE(parsed.stereo() == !testCase.expected.mono); + REQUIRE(parsed.start() == static_cast(testCase.expected.start)); + REQUIRE(parsed.end() == static_cast(testCase.expected.end)); + REQUIRE(parsed.frame_count() == static_cast(testCase.expected.sampleData.size() / (testCase.expected.mono ? 1 : 2))); + REQUIRE(parsed.loop_frame_count() == static_cast(testCase.expected.end - testCase.expected.loopTo)); + REQUIRE(parsed.loop_enabled() == testCase.expected.loopEnabled); + REQUIRE(parsed.beat_count() == static_cast(testCase.expected.beatCount)); + REQUIRE(parsed.sample_rate() == static_cast(testCase.expected.sampleRate)); + REQUIRE(parsed.sample_data() != nullptr); + REQUIRE(parsed.sample_data()->size() == testCase.expected.sampleData.size()); + + for (std::size_t i = 0; i < parsed.sample_data()->size(); i++) + { + REQUIRE(parsed.sample_data()->at(i) == mean_normalized_float_to_short(testCase.expected.sampleData[i])); + } + }); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + const auto loaded = loadWithSoundLoader(mpc, bytes, testCase.fileStem + ".SND"); + requireSoundMatches(loaded, testCase.expected); + } + } +} + +TEST_CASE("Kaitai MPC2000 SND parses real 2KXL mono and stereo files through the production loader", "[kaitai-snd][real-2kxl]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + + const auto monoBytes = resourceBytes("test/RealMpc2000xl/Snd/mono_loop_off.SND"); + const auto mono = loadWithSoundLoader(mpc, monoBytes, "mono_loop_off.SND"); + + REQUIRE(mono->getName() == "mono_loop_off"); + REQUIRE(mono->isMono()); + REQUIRE(mono->getSampleRate() == 44100); + REQUIRE(mono->getSndLevel() == 100); + REQUIRE(mono->getTune() == 0); + REQUIRE(mono->getBeatCount() == 4); + REQUIRE(mono->getStart() == 0); + REQUIRE(mono->getEnd() == 8012); + REQUIRE(mono->getLoopTo() == 0); + REQUIRE(!mono->isLoopEnabled()); + REQUIRE(mono->getFrameCount() == 8012); + REQUIRE(mono->getSampleData()->size() == 8012U); + REQUIRE((*mono->getSampleData())[0] == short_to_float(-3326)); + REQUIRE((*mono->getSampleData())[1] == short_to_float(-2941)); + REQUIRE((*mono->getSampleData())[2] == short_to_float(-3809)); + + const auto stereoBytes = resourceBytes("test/RealMpc2000xl/Snd/stereo_loop_off.SND"); + const auto stereo = loadWithSoundLoader(mpc, stereoBytes, "stereo_loop_off.SND"); + + REQUIRE(stereo->getName() == "stereo_loop_off"); + REQUIRE(!stereo->isMono()); + REQUIRE(stereo->getSampleRate() == 44100); + REQUIRE(stereo->getSndLevel() == 100); + REQUIRE(stereo->getTune() == 0); + REQUIRE(stereo->getBeatCount() == 4); + REQUIRE(stereo->getStart() == 0); + REQUIRE(stereo->getEnd() == 8012); + REQUIRE(stereo->getLoopTo() == 0); + REQUIRE(!stereo->isLoopEnabled()); + REQUIRE(stereo->getFrameCount() == 8012); + REQUIRE(stereo->getSampleData()->size() == 16024U); + REQUIRE((*stereo->getSampleData())[0] == short_to_float(-3326)); + REQUIRE((*stereo->getSampleData())[1] == short_to_float(-2941)); + REQUIRE((*stereo->getSampleData())[2] == short_to_float(-3809)); + REQUIRE((*stereo->getSampleData())[8012] == short_to_float(-2233)); +} + +TEST_CASE("Generated MPC2000XL SND corpus loads through the production loader", "[kaitai-snd][generated-corpus]") +{ + struct CorpusCase + { + std::string resourcePath; + std::string fileName; + ExpectedSound expected; + }; + + const auto cases = std::vector{ + { + "test/GeneratedMpc2000xl/Snd/mono_corpus_min.SND", + "mono_corpus_min.SND", + ExpectedSound{ + "mono_corpus_min", + true, + 8000, + 0, + -120, + 1, + 0, + 0, + 0, + false, + monoSamples({-32768, -1, 0, 32767}) + } + }, + { + "test/GeneratedMpc2000xl/Snd/mono_loop_mid.SND", + "mono_loop_mid.SND", + ExpectedSound{ + "mono_loop_mid", + true, + 44100, + 100, + 0, + 16, + 1, + 3, + 2, + true, + monoSamples({-12345, -17, 19, 12345}) + } + }, + { + "test/GeneratedMpc2000xl/Snd/stereo_span.SND", + "stereo_span.SND", + ExpectedSound{ + "stereo_span", + false, + 22050, + 100, + 0, + 16, + 0, + 5, + 0, + false, + stereoSamples({1000, 2000, 3000, 4000, 5000}, {-1000, -2000, -3000, -4000, -5000}) + } + }, + { + "test/GeneratedMpc2000xl/Snd/stereo_max.SND", + "stereo_max.SND", + ExpectedSound{ + "stereo_max", + false, + 44100, + 200, + 120, + 32, + 5, + 5, + 5, + true, + stereoSamples({32767, 23456, 12345, 1, -1}, {-32768, -23456, -12345, -1, 1}) + } + }, + { + "test/GeneratedMpc2000xl/Snd/name_len_sixteen.SND", + "name_len_sixteen.SND", + ExpectedSound{ + "name_len_sixteen", + false, + 32000, + 150, + -37, + 8, + 2, + 4, + 2, + true, + stereoSamples({3210, -4321, 123, -456}, {999, -999, 456, -123}) + } + } + }; + + for (const auto &testCase : cases) + { + SECTION(testCase.fileName) + { + const auto bytes = resourceBytes(testCase.resourcePath); + + withParsedSndBytes(bytes, [&](mpc2000snd_t &parsed) + { + REQUIRE(parsed.name() == expectedHeaderName(testCase.expected.name)); + REQUIRE(parsed.level() == static_cast(testCase.expected.level)); + REQUIRE(parsed.tune() == testCase.expected.tune); + REQUIRE(parsed.stereo() == !testCase.expected.mono); + REQUIRE(parsed.start() == static_cast(testCase.expected.start)); + REQUIRE(parsed.end() == static_cast(testCase.expected.end)); + REQUIRE(parsed.frame_count() == static_cast(testCase.expected.sampleData.size() / (testCase.expected.mono ? 1 : 2))); + REQUIRE(parsed.loop_frame_count() == static_cast(testCase.expected.end - testCase.expected.loopTo)); + REQUIRE(parsed.loop_enabled() == testCase.expected.loopEnabled); + REQUIRE(parsed.beat_count() == static_cast(testCase.expected.beatCount)); + REQUIRE(parsed.sample_rate() == static_cast(testCase.expected.sampleRate)); + REQUIRE(parsed.sample_data() != nullptr); + REQUIRE(parsed.sample_data()->size() == testCase.expected.sampleData.size()); + + for (std::size_t i = 0; i < parsed.sample_data()->size(); i++) + { + REQUIRE(parsed.sample_data()->at(i) == mean_normalized_float_to_short(testCase.expected.sampleData[i])); + } + }); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + const auto loaded = loadWithSoundLoader(mpc, bytes, testCase.fileName); + requireSoundMatches(loaded, testCase.expected); + } + } } diff --git a/test-resources/GeneratedMpc2000xl/Snd/README.txt b/test-resources/GeneratedMpc2000xl/Snd/README.txt new file mode 100644 index 00000000..a0795d3d --- /dev/null +++ b/test-resources/GeneratedMpc2000xl/Snd/README.txt @@ -0,0 +1,12 @@ +Generated MPC2000XL SND corpus + +These fixtures are synthetic and intentionally small. +They are bundled into mpc-tests to exercise the production SND load path +without relying on the handwritten parser as the oracle. + +Files: +- mono_corpus_min.SND: Mono corpus case with low behavioral values. +- mono_loop_mid.SND: Mono loop-enabled mid-range case. +- stereo_span.SND: Stereo case that makes non-interleaved payload ordering obvious. +- stereo_max.SND: Stereo case with high behavioral values. +- name_len_sixteen.SND: Exact 16-character name boundary case. diff --git a/test-resources/GeneratedMpc2000xl/Snd/mono_corpus_min.SND b/test-resources/GeneratedMpc2000xl/Snd/mono_corpus_min.SND new file mode 100644 index 0000000000000000000000000000000000000000..d47942ba006836e57f9dbddcafcbbf7ce07fcff3 GIT binary patch literal 50 scmZQ%$<5Epk5A4oDkv?E&&|wJU|{HAfB_a5gV8~rq2d3328RFj04^H~WdHyG literal 0 HcmV?d00001 diff --git a/test-resources/GeneratedMpc2000xl/Snd/mono_loop_mid.SND b/test-resources/GeneratedMpc2000xl/Snd/mono_loop_mid.SND new file mode 100644 index 0000000000000000000000000000000000000000..f937c02644868855510826d154815f37497ee71b GIT binary patch literal 50 zcmZQ%$<5EpkI%`^FNn|0Oi@r!U`SzLU}RumUUS;hK7VC$It)& H&&U7(#aj_r literal 0 HcmV?d00001 diff --git a/test-resources/GeneratedMpc2000xl/Snd/stereo_span.SND b/test-resources/GeneratedMpc2000xl/Snd/stereo_span.SND new file mode 100644 index 0000000000000000000000000000000000000000..c0b39e576294acb60543ef4166ec6f18bb6264a4 GIT binary patch literal 62 zcmZQ%DK1GZO3jZiE=bH%00D*+21W)TU`4_V0!m>om@lyJ;9kJrAuRF7;D^VTgbx*O E0GVhIKmY&$ literal 0 HcmV?d00001 From 355db47d8d6a764a04a2a911f5539be2d7e4398c Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:10:08 +0200 Subject: [PATCH 08/52] Fix PGM/APS program change semantics and test startup --- src/main/Mpc.cpp | 13 +- src/main/Mpc.hpp | 8 +- src/main/disk/ApsLoader.cpp | 4 +- src/main/disk/PgmFileToProgramConverter.cpp | 2 +- src/main/file/aps/ApsProgram.cpp | 2 +- src/main/file/aps/ApsSlider.cpp | 6 +- src/main/file/aps/ApsSlider.hpp | 3 +- src/main/file/pgmreader/PRSlider.cpp | 6 +- src/main/file/pgmreader/PRSlider.hpp | 2 +- src/main/file/pgmwriter/PWSlider.cpp | 6 +- src/main/file/pgmwriter/PWSlider.hpp | 2 +- src/test/KaitaiApsTest.cpp | 47 +++++- src/test/KaitaiPgmTest.cpp | 171 ++++++++++++++++++++ src/test/TestMpc.cpp | 19 ++- src/test/TestMpc.hpp | 2 + 15 files changed, 272 insertions(+), 21 deletions(-) diff --git a/src/main/Mpc.cpp b/src/main/Mpc.cpp index f1f296f5..a314f030 100644 --- a/src/main/Mpc.cpp +++ b/src/main/Mpc.cpp @@ -52,7 +52,7 @@ Mpc::Mpc() clock = std::make_shared(); } -void Mpc::init() +void Mpc::init(const MpcInitOptions &options) { const auto logFsError = [](const mpc_fs::fs_error &error) { @@ -315,8 +315,15 @@ void Mpc::init() layeredScreen->openScreenById(ScreenId::SequencerScreen); - startMidiDeviceDetector(); - getEngineHost()->getAudioServer()->start(); + if (options.startMidiDeviceDetector) + { + startMidiDeviceDetector(); + } + + if (options.startAudioServer) + { + getEngineHost()->getAudioServer()->start(); + } autoSave = std::make_unique(); } diff --git a/src/main/Mpc.hpp b/src/main/Mpc.hpp index 8811f0fa..c439ad58 100644 --- a/src/main/Mpc.hpp +++ b/src/main/Mpc.hpp @@ -71,6 +71,12 @@ namespace mpc::sampler namespace mpc { + struct MpcInitOptions + { + bool startMidiDeviceDetector = true; + bool startAudioServer = true; + }; + class Mpc { bool pluginModeEnabled = false; @@ -95,7 +101,7 @@ namespace mpc std::shared_ptr midiDeviceDetector; public: - void init(); + void init(const MpcInitOptions &options = {}); void startMidiDeviceDetector(); void panic() const; void setPluginModeEnabled(bool); diff --git a/src/main/disk/ApsLoader.cpp b/src/main/disk/ApsLoader.cpp index 7f96a2b7..4aee5deb 100644 --- a/src/main/disk/ApsLoader.cpp +++ b/src/main/disk/ApsLoader.cpp @@ -212,8 +212,6 @@ void ApsLoader::loadFromParsedAps(ApsParser &apsParser, Mpc &mpc, apsProgram->getSlider()->getAttackHigh(); perfProgram.slider.attackLowRange = apsProgram->getSlider()->getAttackLow(); - perfProgram.slider.controlChange = - apsProgram->getSlider()->getProgramChange(); perfProgram.slider.decayHighRange = apsProgram->getSlider()->getDecayHigh(); perfProgram.slider.decayLowRange = @@ -227,6 +225,8 @@ void ApsLoader::loadFromParsedAps(ApsParser &apsParser, Mpc &mpc, perfProgram.slider.tuneHighRange = apsProgram->getSlider()->getTuneHigh(); perfProgram.slider.tuneLowRange = apsProgram->getSlider()->getTuneLow(); + perfProgram.midiProgramChange = + apsProgram->getSlider()->getProgramChange() + 1; mpc.getPerformanceManager().lock()->enqueue( performance::PerformanceMessage{std::move(msg)}); diff --git a/src/main/disk/PgmFileToProgramConverter.cpp b/src/main/disk/PgmFileToProgramConverter.cpp index d73905fb..390671e5 100644 --- a/src/main/disk/PgmFileToProgramConverter.cpp +++ b/src/main/disk/PgmFileToProgramConverter.cpp @@ -40,7 +40,6 @@ void PgmFileToProgramConverter::setSlider( pgmSlider->setAssignNote(nn); pgmSlider->setAttackHighRange(slider->getAttackHigh()); pgmSlider->setAttackLowRange(slider->getAttackLow()); - pgmSlider->setControlChange(slider->getControlChange()); pgmSlider->setDecayHighRange(slider->getDecayHigh()); pgmSlider->setDecayLowRange(slider->getDecayLow()); pgmSlider->setFilterHighRange(slider->getFilterHigh()); @@ -184,6 +183,7 @@ program_or_error PgmFileToProgramConverter::loadFromFileAndConvert( setNoteParameters(mpc, reader, program); setMixer(reader, program); setSlider(reader, program); + program->setMidiProgramChange(reader.getSlider()->getProgramChange() + 1); return program; } diff --git a/src/main/file/aps/ApsProgram.cpp b/src/main/file/aps/ApsProgram.cpp index 407f8a0c..cd66eddd 100644 --- a/src/main/file/aps/ApsProgram.cpp +++ b/src/main/file/aps/ApsProgram.cpp @@ -65,7 +65,7 @@ ApsProgram::ApsProgram(sampler::Program *program, int index) byteList.push_back({0}); // Name terminator - ApsSlider apsSlider(program->getSlider()); + ApsSlider apsSlider(program); byteList.push_back(apsSlider.getBytes()); byteList.push_back({35, 64, 0, 26, 0}); diff --git a/src/main/file/aps/ApsSlider.cpp b/src/main/file/aps/ApsSlider.cpp index cc4921e1..c17f8db6 100644 --- a/src/main/file/aps/ApsSlider.cpp +++ b/src/main/file/aps/ApsSlider.cpp @@ -1,6 +1,7 @@ #include "file/aps/ApsSlider.hpp" #include "file/aps/ApsProgram.hpp" +#include "sampler/Program.hpp" #include "sampler/PgmSlider.hpp" using namespace mpc::file::aps; @@ -19,8 +20,9 @@ ApsSlider::ApsSlider(const std::vector &loadBytes) programChange = loadBytes[9]; } -ApsSlider::ApsSlider(sampler::PgmSlider *slider) +ApsSlider::ApsSlider(sampler::Program *program) { + auto slider = program->getSlider(); saveBytes = std::vector(ApsProgram::SLIDER_LENGTH); saveBytes[0] = slider->getNote() == 34 ? 0 : slider->getNote(); saveBytes[1] = slider->getTuneLowRange(); @@ -31,7 +33,7 @@ ApsSlider::ApsSlider(sampler::PgmSlider *slider) saveBytes[6] = slider->getAttackHighRange(); saveBytes[7] = slider->getFilterLowRange(); saveBytes[8] = slider->getFilterHighRange(); - saveBytes[9] = slider->getControlChange(); + saveBytes[9] = program->getMidiProgramChange() - 1; } std::vector ApsSlider::PADDING = std::vector{0, 35, 64, 0, 26, 0}; diff --git a/src/main/file/aps/ApsSlider.hpp b/src/main/file/aps/ApsSlider.hpp index d3e43dd7..6b3de678 100644 --- a/src/main/file/aps/ApsSlider.hpp +++ b/src/main/file/aps/ApsSlider.hpp @@ -5,6 +5,7 @@ namespace mpc::sampler { class PgmSlider; + class Program; } namespace mpc::file::aps @@ -42,6 +43,6 @@ namespace mpc::file::aps std::vector getBytes(); ApsSlider(const std::vector &loadBytes); - ApsSlider(sampler::PgmSlider *slider); + ApsSlider(sampler::Program *program); }; } // namespace mpc::file::aps diff --git a/src/main/file/pgmreader/PRSlider.cpp b/src/main/file/pgmreader/PRSlider.cpp index 48c9ef75..76ffdc44 100644 --- a/src/main/file/pgmreader/PRSlider.cpp +++ b/src/main/file/pgmreader/PRSlider.cpp @@ -92,8 +92,8 @@ int Slider::getFilterHigh() return filterHigh; } -int Slider::getControlChange() +int Slider::getProgramChange() { - auto controlChange = getSliderArray()[9]; - return controlChange; + auto programChange = getSliderArray()[9]; + return programChange; } diff --git a/src/main/file/pgmreader/PRSlider.hpp b/src/main/file/pgmreader/PRSlider.hpp index 70522162..73f0c8f0 100644 --- a/src/main/file/pgmreader/PRSlider.hpp +++ b/src/main/file/pgmreader/PRSlider.hpp @@ -37,7 +37,7 @@ namespace mpc int getAttackHigh(); int getFilterLow(); int getFilterHigh(); - int getControlChange(); + int getProgramChange(); Slider(ProgramFileReader *programFile); }; diff --git a/src/main/file/pgmwriter/PWSlider.cpp b/src/main/file/pgmwriter/PWSlider.cpp index 380f7950..ba56e752 100644 --- a/src/main/file/pgmwriter/PWSlider.cpp +++ b/src/main/file/pgmwriter/PWSlider.cpp @@ -23,7 +23,7 @@ Slider::Slider(sampler::Program *program) setAttackHigh(program->getSlider()->getAttackHighRange()); setFilterLow(program->getSlider()->getFilterLowRange()); setFilterHigh(program->getSlider()->getFilterHighRange()); - setControlChange(program->getSlider()->getControlChange()); + setProgramChange(program->getMidiProgramChange() - 1); sliderArray[10] = 35; sliderArray[11] = 64; sliderArray[12] = 0; @@ -81,7 +81,7 @@ void Slider::setFilterHigh(int filterHigh) sliderArray[8] = filterHigh; } -void Slider::setControlChange(int controlChange) +void Slider::setProgramChange(int programChange) { - sliderArray[9] = controlChange; + sliderArray[9] = programChange; } diff --git a/src/main/file/pgmwriter/PWSlider.hpp b/src/main/file/pgmwriter/PWSlider.hpp index 96209b11..c4255513 100644 --- a/src/main/file/pgmwriter/PWSlider.hpp +++ b/src/main/file/pgmwriter/PWSlider.hpp @@ -33,7 +33,7 @@ namespace mpc void setAttackHigh(int attackHigh); void setFilterLow(int filterLow); void setFilterHigh(int filterHigh); - void setControlChange(int controlChange); + void setProgramChange(int programChange); public: Slider(sampler::Program *program); diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index 1096bd3d..4aded286 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -6,8 +6,10 @@ #include "disk/ApsLoader.hpp" #include "disk/MpcFile.hpp" #include "engine/EngineHost.hpp" +#include "file/kaitai/ApsIo.hpp" #include "file/aps/ApsParser.hpp" #include "file/kaitai/generated/mpc2000xl_aps.h" +#include "performance/PerformanceManager.hpp" #include "sampler/Program.hpp" #include "sampler/Sampler.hpp" @@ -138,7 +140,7 @@ TEST_CASE("Kaitai MPC2000 APS parses and rewrites real 2KXL ALL_PGMS", "[kaitai- TEST_CASE("Kaitai MPC2000 APS matches handwritten APS bytes", "[kaitai-aps]") { mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpc(mpc); + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); loadAllPgmsAps(mpc); REQUIRE(mpc.getSampler()->getProgramCount() == 2); @@ -205,3 +207,46 @@ TEST_CASE("Kaitai MPC2000 APS matches handwritten APS bytes", "[kaitai-aps]") REQUIRE(p2->getNoteParameters(35)->getSoundIndex() == 1); REQUIRE(p2->getNoteParameters(36)->getSoundIndex() == 2); } + +TEST_CASE("Kaitai MPC2000 APS saves MIDI program change separately from slider control change", "[kaitai-aps]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + loadAllPgmsAps(mpc); + + auto p1 = mpc.getSampler()->getProgram(0); + REQUIRE(p1 != nullptr); + + p1->setMidiProgramChange(2); + mpc.getPerformanceManager().lock()->drainQueue(); + REQUIRE(p1->getMidiProgramChange() == 2); + p1->getSlider()->setControlChange(0); + mpc::file::aps::ApsParser handwrittenWriterZero(mpc, "ALL_PGMS"); + const auto handwrittenBytesWithZeroControl = handwrittenWriterZero.getBytes(); + std::stringstream handwrittenParseStreamZero( + std::string(handwrittenBytesWithZeroControl.begin(), handwrittenBytesWithZeroControl.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream handwrittenParseIoZero(&handwrittenParseStreamZero); + mpc2000xl_aps_t handwrittenParsedZero(&handwrittenParseIoZero); + handwrittenParsedZero._read(); + REQUIRE(handwrittenParsedZero.aps_programs()->at(0)->body()->program_change() == 1); + + const auto bytesWithZeroControl = + mpc::file::kaitai::ApsIo::save(mpc, "ALL_PGMS"); + + std::stringstream parseStreamZero( + std::string(bytesWithZeroControl.begin(), bytesWithZeroControl.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIoZero(&parseStreamZero); + mpc2000xl_aps_t parsedZero(&parseIoZero); + parsedZero._read(); + REQUIRE(parsedZero.aps_programs()->at(0)->body()->program_change() == 1); + + p1->getSlider()->setControlChange(17); + const auto bytesWithNonZeroControl = + mpc::file::kaitai::ApsIo::save(mpc, "ALL_PGMS"); + + REQUIRE(bytesWithNonZeroControl == bytesWithZeroControl); +} diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp index 1b72a34e..81c0a438 100644 --- a/src/test/KaitaiPgmTest.cpp +++ b/src/test/KaitaiPgmTest.cpp @@ -2,14 +2,21 @@ #include "TestMpc.hpp" #include "Mpc.hpp" +#include "IntTypes.hpp" #include "disk/AbstractDisk.hpp" #include "disk/MpcFile.hpp" #include "disk/ProgramLoader.hpp" +#include "engine/IndivFxMixer.hpp" #include "engine/EngineHost.hpp" +#include "engine/StereoMixer.hpp" +#include "file/kaitai/PgmIo.hpp" #include "file/kaitai/generated/mpc2000xl_pgm.h" #include "file/pgmwriter/PgmWriter.hpp" +#include "performance/PerformanceManager.hpp" +#include "sampler/PgmSlider.hpp" #include "sampler/Program.hpp" #include "sampler/Sampler.hpp" +#include "sampler/VoiceOverlapMode.hpp" #include #include @@ -66,6 +73,97 @@ std::shared_ptr loadProgram1(mpc::Mpc& mpc) return program; } +std::shared_ptr loadProgram1FromBytes( + mpc::Mpc& mpc, + const std::vector& programBytes) +{ + prepareProgramLoadingResources(mpc); + + auto disk = mpc.getDisk(); + disk->moveForward("program1"); + disk->initFiles(); + auto pgmFile = disk->getFile("PROGRAM1.PGM"); + auto mutableBytes = programBytes; + pgmFile->setFileData(mutableBytes); + + auto sampler = mpc.getSampler(); + sampler->deleteAllPrograms(false); + sampler->deleteAllSamples(); + + auto program = sampler->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + (void)mpc::disk::ProgramLoader::loadProgram(mpc, pgmFile, program, 0); + mpc.getEngineHost()->prepareProcessBlock(512); + return program; +} + +void requireProgram1LoadedState(mpc::Mpc& mpc, + const std::shared_ptr& program) +{ + REQUIRE(program != nullptr); + REQUIRE(program->getName() == "PROGRAM1"); + + auto sampler = mpc.getSampler(); + REQUIRE(sampler->getSoundCount() == 2); + REQUIRE(sampler->getSoundName(0) == "sound1"); + REQUIRE(sampler->getSoundName(1) == "sound2"); + REQUIRE(sampler->getSound(1)->getEnd() == 1000); + + const auto note35 = program->getNoteParameters(35); + const auto note36 = program->getNoteParameters(36); + const auto note37 = program->getNoteParameters(37); + + REQUIRE(note35->getSoundIndex() == 0); + REQUIRE(note36->getSoundIndex() == 1); + REQUIRE(note37->getSoundIndex() == -1); + + REQUIRE(note35->getSoundGenerationMode() == 0); + REQUIRE(note35->getVelocityRangeLower() == 44); + REQUIRE(note35->getVelocityRangeUpper() == 88); + REQUIRE(note35->getTune() == 0); + REQUIRE(note35->getAttack() == 0); + REQUIRE(note35->getDecay() == 5); + REQUIRE(note35->getDecayMode() == 0); + REQUIRE(note35->getFilterFrequency() == 100); + REQUIRE(note35->getFilterResonance() == 0); + REQUIRE(note35->getFilterAttack() == 0); + REQUIRE(note35->getFilterDecay() == 0); + REQUIRE(note35->getFilterEnvelopeAmount() == 0); + REQUIRE(note35->getVeloToLevel() == 100); + REQUIRE(note35->getVelocityToAttack() == 0); + REQUIRE(note35->getVelocityToStart() == 0); + REQUIRE(note35->getVelocityToFilterFrequency() == 0); + REQUIRE(note35->getSliderParameterNumber() == 0); + REQUIRE(note35->getVelocityToPitch() == 0); + REQUIRE(note35->getVoiceOverlapMode() == mpc::sampler::VoiceOverlapMode::POLY); + REQUIRE(note35->getOptionalNoteA() == mpc::NoDrumNoteAssigned); + REQUIRE(note35->getOptionalNoteB() == mpc::NoDrumNoteAssigned); + REQUIRE(note35->getMuteAssignA() == mpc::NoDrumNoteAssigned); + REQUIRE(note35->getMuteAssignB() == mpc::NoDrumNoteAssigned); + + const auto stereoMixer = note35->getStereoMixer(); + const auto indivFxMixer = note35->getIndivFxMixer(); + REQUIRE(stereoMixer->getLevel() == mpc::MaxDrumMixerLevel); + REQUIRE(stereoMixer->getPanning() == mpc::PanningCenter); + REQUIRE(indivFxMixer->getVolumeIndividualOut() == mpc::MaxDrumMixerLevel); + REQUIRE(indivFxMixer->getOutput() == mpc::MinDrumMixerIndividualOut); + REQUIRE(indivFxMixer->getFxPath() == mpc::MinDrumMixerFxPath); + REQUIRE(indivFxMixer->getFxSendLevel() == mpc::MinDrumMixerLevel); + + const auto slider = program->getSlider(); + REQUIRE(slider->getNote() == mpc::NoDrumNoteAssigned); + REQUIRE(slider->getTuneLowRange() == -120); + REQUIRE(slider->getTuneHighRange() == 120); + REQUIRE(slider->getDecayLowRange() == 12); + REQUIRE(slider->getDecayHighRange() == 45); + REQUIRE(slider->getAttackLowRange() == 0); + REQUIRE(slider->getAttackHighRange() == 20); + REQUIRE(slider->getFilterLowRange() == -50); + REQUIRE(slider->getFilterHighRange() == 50); + REQUIRE(slider->getControlChange() == 0); + REQUIRE(slider->getParameter() == mpc::NoteVariationTypeTune); + REQUIRE(program->getMidiProgramChange() == 1); +} + } TEST_CASE("Kaitai MPC2000 PGM parses and rewrites PROGRAM1", "[kaitai-pgm]") @@ -101,6 +199,9 @@ TEST_CASE("Kaitai MPC2000 PGM parses and rewrites PROGRAM1", "[kaitai-pgm]") REQUIRE(parsed.note_parameters()->size() == 64U); REQUIRE(parsed.note_parameters()->at(0)->sound_index() == 0); REQUIRE(parsed.note_parameters()->at(1)->sound_index() == 1); + // Hardware-backed comparison shows this standalone byte stores MIDI + // program change as a zero-based value. + REQUIRE(parsed.program_change() == 0); REQUIRE(parsed.pad_to_note_mapping() != nullptr); REQUIRE(parsed.pad_to_note_mapping()->size() == 64U); @@ -216,3 +317,73 @@ TEST_CASE("Kaitai MPC2000 PGM matches handwritten PGM bytes", "[kaitai-pgm]") REQUIRE(reparsedProgram->getNoteParameters(35)->getSoundIndex() == 0); REQUIRE(reparsedProgram->getNoteParameters(36)->getSoundIndex() == 1); } + +TEST_CASE("Kaitai MPC2000 PGM loads PROGRAM1 through the production seam with explicit semantics", "[kaitai-pgm]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + + const auto program = loadProgram1(mpc); + requireProgram1LoadedState(mpc, program); +} + +TEST_CASE("Kaitai MPC2000 PGM load uses standalone byte as MIDI program change", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + parsed.set_program_change(1); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + std::vector programBytes(writeStream.str().begin(), writeStream.str().end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + const auto program = loadProgram1FromBytes(mpc, programBytes); + + REQUIRE(program->getMidiProgramChange() == 2); + REQUIRE(program->getSlider()->getControlChange() == 0); +} + +TEST_CASE("Kaitai MPC2000 PGM save writes MIDI program change and ignores slider control change", "[kaitai-pgm]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + const auto program = loadProgram1(mpc); + + program->setMidiProgramChange(2); + mpc.getPerformanceManager().lock()->drainQueue(); + program->getSlider()->setControlChange(0); + const auto bytesWithZeroControl = + mpc::file::kaitai::PgmIo::saveProgram(*program, mpc.getSampler()); + + std::stringstream parseStreamZero( + std::string(bytesWithZeroControl.begin(), bytesWithZeroControl.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIoZero(&parseStreamZero); + mpc2000xl_pgm_t parsedZero(&parseIoZero); + parsedZero._read(); + REQUIRE(parsedZero.program_change() == 1); + + program->getSlider()->setControlChange(17); + const auto bytesWithNonZeroControl = + mpc::file::kaitai::PgmIo::saveProgram(*program, mpc.getSampler()); + + REQUIRE(bytesWithNonZeroControl == bytesWithZeroControl); +} diff --git a/src/test/TestMpc.cpp b/src/test/TestMpc.cpp index bcc424aa..e62f8c7c 100644 --- a/src/test/TestMpc.cpp +++ b/src/test/TestMpc.cpp @@ -19,5 +19,22 @@ void mpc::TestMpc::initializeTestMpc(Mpc &mpc) { resetTestDataRoot(mpc); mpc.init(); - mpc.getEngineHost()->getAudioServer()->start(); +} + +void mpc::TestMpc::initializeTestMpcWithoutMidiServices(Mpc &mpc) +{ + resetTestDataRoot(mpc); + MpcInitOptions options; + options.startMidiDeviceDetector = false; + options.startAudioServer = true; + mpc.init(options); +} + +void mpc::TestMpc::initializeTestMpcWithoutIoServices(Mpc &mpc) +{ + resetTestDataRoot(mpc); + MpcInitOptions options; + options.startMidiDeviceDetector = false; + options.startAudioServer = false; + mpc.init(options); } diff --git a/src/test/TestMpc.hpp b/src/test/TestMpc.hpp index 6e368acd..65135ee3 100644 --- a/src/test/TestMpc.hpp +++ b/src/test/TestMpc.hpp @@ -9,5 +9,7 @@ namespace mpc public: static void resetTestDataRoot(Mpc &mpc); static void initializeTestMpc(Mpc &mpc); + static void initializeTestMpcWithoutMidiServices(Mpc &mpc); + static void initializeTestMpcWithoutIoServices(Mpc &mpc); }; } // namespace mpc From 05dde77c2679224572a0fb6b07293655416232b7 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:19:34 +0200 Subject: [PATCH 09/52] Tighten Kaitai ALL and MID production-seam tests --- src/test/KaitaiAllTest.cpp | 78 ++++++++++++++++++++++++++++++++++++++ src/test/KaitaiMidTest.cpp | 71 ++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) diff --git a/src/test/KaitaiAllTest.cpp b/src/test/KaitaiAllTest.cpp index 05594170..a290c8b1 100644 --- a/src/test/KaitaiAllTest.cpp +++ b/src/test/KaitaiAllTest.cpp @@ -1,4 +1,5 @@ #include +#include #include "TestMpc.hpp" #include "Mpc.hpp" @@ -6,10 +7,16 @@ #include "disk/AllLoader.hpp" #include "disk/MpcFile.hpp" #include "file/all/AllParser.hpp" +#include "file/kaitai/AllIo.hpp" #include "file/kaitai/generated/mpc2000xl_all.h" +#include "lcdgui/ScreenId.hpp" +#include "lcdgui/screens/UserScreen.hpp" +#include "sequencer/BusType.hpp" #include "sequencer/Sequence.hpp" #include "sequencer/Sequencer.hpp" #include "sequencer/SequencerStateManager.hpp" +#include "sequencer/Song.hpp" +#include "sequencer/Track.hpp" #include #include @@ -38,6 +45,21 @@ void prepareAllResources(mpc::Mpc& mpc) disk->initFiles(); } +std::shared_ptr installResourceFile( + mpc::Mpc& mpc, + const std::string& resourcePath, + const std::string& fileName) +{ + auto disk = mpc.getDisk(); + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open(resourcePath); + std::vector data(file.begin(), file.end()); + auto newFile = disk->newFile(fileName); + newFile->setFileData(data); + disk->initFiles(); + return newFile; +} + } TEST_CASE("Kaitai MPC2000 ALL parses and rewrites real 2KXL ALL", "[kaitai-all][real-2kxl]") @@ -164,3 +186,59 @@ TEST_CASE("Kaitai MPC2000 ALL matches handwritten ALL bytes", "[kaitai-all]") REQUIRE(reparsedMpc.getSequencer()->getSequence(0)->isUsed()); REQUIRE(reparsedMpc.getSequencer()->getSequence(20)->isUsed()); } + +TEST_CASE("Kaitai MPC2000 ALL loads real 2KXL ALL through production seam", "[kaitai-all][real-2kxl]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto allFile = installResourceFile( + mpc, + "test/RealMpc2000xl/All/ALL.ALL", + "ALL.ALL" + ); + REQUIRE(allFile); + + mpc::disk::AllLoader::loadEverythingFromFile(mpc, allFile.get()); + mpc.getSequencer()->getStateManager()->drainQueue(); + + auto sequencer = mpc.getSequencer(); + auto userScreen = mpc.screens->get(); + REQUIRE(userScreen); + + REQUIRE_THAT(userScreen->getTempo(), Catch::Matchers::WithinAbs(116.2, 0.001)); + REQUIRE(userScreen->getBusType() == mpc::sequencer::BusType::DRUM2); + REQUIRE(userScreen->getDevice() == 7); + REQUIRE(userScreen->getTimeSig().numerator == 4); + REQUIRE(userScreen->getTimeSig().denominator == 4); + + auto sequence0 = sequencer->getSequence(0); + auto sequence1 = sequencer->getSequence(1); + REQUIRE(sequence0->isUsed()); + REQUIRE(sequence1->isUsed()); + REQUIRE_THAT(sequence0->getInitialTempo(), Catch::Matchers::WithinAbs(116.2, 0.001)); + REQUIRE_THAT(sequence1->getInitialTempo(), Catch::Matchers::WithinAbs(116.2, 0.001)); + REQUIRE(sequence0->getTrack(0)->getBusType() == mpc::sequencer::BusType::DRUM2); + REQUIRE(sequence1->getTrack(0)->getBusType() == mpc::sequencer::BusType::DRUM2); + REQUIRE(sequence0->getTrack(0)->getDeviceIndex() == 7); + REQUIRE(sequence1->getTrack(0)->getDeviceIndex() == 7); + REQUIRE(sequence0->getTimeSignatureFromBarIndex(0).numerator == 4); + REQUIRE(sequence0->getTimeSignatureFromBarIndex(0).denominator == 4); + REQUIRE(sequence1->getTimeSignatureFromBarIndex(0).numerator == 4); + REQUIRE(sequence1->getTimeSignatureFromBarIndex(0).denominator == 4); + + auto song0 = sequencer->getSong(0); + auto song1 = sequencer->getSong(1); + REQUIRE(song0->isUsed()); + REQUIRE(song1->isUsed()); + REQUIRE(song0->getStepCount() == 2); + REQUIRE(song1->getStepCount() == 2); + REQUIRE(song0->getStep(mpc::SongStepIndex(0)).sequenceIndex == 0); + REQUIRE(song0->getStep(mpc::SongStepIndex(0)).repetitionCount == 1); + REQUIRE(song0->getStep(mpc::SongStepIndex(1)).sequenceIndex == 1); + REQUIRE(song0->getStep(mpc::SongStepIndex(1)).repetitionCount == 1); + REQUIRE(song1->getStep(mpc::SongStepIndex(0)).sequenceIndex == 1); + REQUIRE(song1->getStep(mpc::SongStepIndex(0)).repetitionCount == 2); + REQUIRE(song1->getStep(mpc::SongStepIndex(1)).sequenceIndex == 0); + REQUIRE(song1->getStep(mpc::SongStepIndex(1)).repetitionCount == 3); +} diff --git a/src/test/KaitaiMidTest.cpp b/src/test/KaitaiMidTest.cpp index 03e8c562..79cc00e2 100644 --- a/src/test/KaitaiMidTest.cpp +++ b/src/test/KaitaiMidTest.cpp @@ -2,6 +2,9 @@ #include "TestMpc.hpp" +#include "disk/AbstractDisk.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/MidIo.hpp" #include "file/kaitai/generated/standard_midi_file_with_running_status.h" #include "file/mid/MidiReader.hpp" #include "file/mid/MidiWriter.hpp" @@ -29,6 +32,14 @@ struct ParsedNoteSnapshot { int velocity; int duration; int variationType; + + bool operator==(const ParsedNoteSnapshot& other) const + { + return note == other.note && + velocity == other.velocity && + duration == other.duration && + variationType == other.variationType; + } }; std::vector collectParsedNotes(const std::shared_ptr& track) @@ -49,6 +60,21 @@ std::vector collectParsedNotes(const std::shared_ptr installMidiResourceFile( + mpc::Mpc& mpc, + const std::string& resourcePath, + const std::string& fileName) +{ + auto disk = mpc.getDisk(); + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open(resourcePath); + std::vector data(file.begin(), file.end()); + auto newFile = disk->newFile(fileName); + newFile->setFileData(data); + disk->initFiles(); + return newFile; +} + } TEST_CASE("Kaitai standard MIDI parses and rewrites FRUTZLE", "[kaitai-mid]") @@ -223,3 +249,48 @@ TEST_CASE("Kaitai standard MIDI parses and rewrites real 2KXL SEQ", "[kaitai-mid CHECK(parsedNotes[i].variationType == expected[i].variationType); } } + +TEST_CASE("Kaitai standard MIDI loads real 2KXL SEQ through production seam", "[kaitai-mid][real-2kxl]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto midiFile = installMidiResourceFile( + mpc, + "test/RealMpc2000xl/Mid/mpc2000xl_seq_variations.MID", + "SEQ.MID" + ); + REQUIRE(midiFile); + + const auto sequenceOrError = mpc::file::kaitai::MidIo::load(mpc, midiFile); + REQUIRE(sequenceOrError.has_value()); + + auto sequence = sequenceOrError.value(); + auto stateManager = mpc.getSequencer()->getStateManager(); + stateManager->drainQueue(); + + REQUIRE(sequence == mpc.getSequencer()->getSequence(mpc::TempSequenceIndex)); + REQUIRE(sequence->getBarCount() == 1); + + const auto track0 = sequence->getTrack(0); + REQUIRE(track0->getBusType() == mpc::sequencer::BusType::DRUM2); + REQUIRE(track0->getDeviceIndex() == 7); + + int totalEvents = 0; + for (int trackIndex = 0; trackIndex < 64; ++trackIndex) { + totalEvents += static_cast(sequence->getTrack(trackIndex)->getEvents().size()); + } + REQUIRE(totalEvents == 7); + + const auto parsedNotes = collectParsedNotes(track0); + const std::vector expected{ + {37, 65, 13, mpc::NoteVariationTypeTune}, + {37, 35, 49, mpc::NoteVariationTypeDecay}, + {37, 75, 101, mpc::NoteVariationTypeAttack}, + {37, 30, 35, mpc::NoteVariationTypeFilter}, + {37, 22, 89, mpc::NoteVariationTypeFilter}, + {37, 46, 174, mpc::NoteVariationTypeTune}, + {37, 19, 161, mpc::NoteVariationTypeTune}, + }; + REQUIRE(parsedNotes == expected); +} From 483b36c09ca119033bb57a5e6a20a408c7ca1e64 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:23:39 +0200 Subject: [PATCH 10/52] Tighten Kaitai APS production-seam coverage --- src/test/KaitaiApsTest.cpp | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index 4aded286..9140e7a3 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -40,6 +40,21 @@ void prepareApsResources(mpc::Mpc& mpc) disk->initFiles(); } +std::shared_ptr installApsResourceFile( + mpc::Mpc& mpc, + const std::string& resourcePath, + const std::string& fileName) +{ + auto disk = mpc.getDisk(); + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open(resourcePath); + std::vector data(file.begin(), file.end()); + auto newFile = disk->newFile(fileName); + newFile->setFileData(data); + disk->initFiles(); + return newFile; +} + void loadAllPgmsAps(mpc::Mpc& mpc) { prepareApsResources(mpc); @@ -250,3 +265,32 @@ TEST_CASE("Kaitai MPC2000 APS saves MIDI program change separately from slider c REQUIRE(bytesWithNonZeroControl == bytesWithZeroControl); } + +TEST_CASE("Kaitai MPC2000 APS loads real 2KXL ALL_PGMS through production seam", "[kaitai-aps][real-2kxl]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto apsFile = installApsResourceFile( + mpc, + "test/RealMpc2000xl/Aps/ALL_PGMS.APS", + "ALL_PGMS.APS" + ); + REQUIRE(apsFile); + + constexpr bool headless = true; + mpc::file::kaitai::ApsIo::load(mpc, apsFile, headless); + mpc.getEngineHost()->prepareProcessBlock(512); + + auto sampler = mpc.getSampler(); + REQUIRE(sampler->getProgramCount() == 1); + REQUIRE(sampler->getSoundCount() == 0); + + auto p1 = sampler->getProgram(0); + REQUIRE(p1 != nullptr); + REQUIRE(p1->getName() == "NewPgm-A"); + REQUIRE(p1->getMidiProgramChange() == 1); + REQUIRE(p1->getSlider()->getControlChange() == 0); + REQUIRE(p1->getNoteParameters(35)->getSoundIndex() == -1); + REQUIRE(p1->getNoteParameters(36)->getSoundIndex() == -1); +} From 7b582ecd4c350388984317827172276806f79050 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:40:07 +0200 Subject: [PATCH 11/52] Fix PGM mixer send-level loading and harden tests --- src/main/disk/PgmFileToProgramConverter.cpp | 2 + src/test/KaitaiPgmTest.cpp | 42 +++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/main/disk/PgmFileToProgramConverter.cpp b/src/main/disk/PgmFileToProgramConverter.cpp index 390671e5..9ad0208c 100644 --- a/src/main/disk/PgmFileToProgramConverter.cpp +++ b/src/main/disk/PgmFileToProgramConverter.cpp @@ -142,6 +142,8 @@ void PgmFileToProgramConverter::setMixer( DrumMixerIndividualOutput(pgmMixer->getOutput(i))); indivFxMixer->setFxPath( DrumMixerIndividualFxPath(pgmMixer->getEffectsOutput(i))); + indivFxMixer->setFxSendLevel( + DrumMixerLevel(pgmMixer->getEffectsSendLevel(i))); } } diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp index 81c0a438..7d4a53cc 100644 --- a/src/test/KaitaiPgmTest.cpp +++ b/src/test/KaitaiPgmTest.cpp @@ -258,7 +258,7 @@ TEST_CASE("Kaitai MPC2000 PGM parses and rewrites real 2KXL NEWPGM-A", "[kaitai- TEST_CASE("Kaitai MPC2000 PGM matches handwritten PGM bytes", "[kaitai-pgm]") { mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpc(mpc); + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); auto program = loadProgram1(mpc); REQUIRE(program != nullptr); @@ -321,7 +321,7 @@ TEST_CASE("Kaitai MPC2000 PGM matches handwritten PGM bytes", "[kaitai-pgm]") TEST_CASE("Kaitai MPC2000 PGM loads PROGRAM1 through the production seam with explicit semantics", "[kaitai-pgm]") { mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpc(mpc); + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); const auto program = loadProgram1(mpc); requireProgram1LoadedState(mpc, program); @@ -350,7 +350,8 @@ TEST_CASE("Kaitai MPC2000 PGM load uses standalone byte as MIDI program change", parsed._check(); parsed._write(); - std::vector programBytes(writeStream.str().begin(), writeStream.str().end()); + const auto rewrittenBytes = writeStream.str(); + std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); @@ -387,3 +388,38 @@ TEST_CASE("Kaitai MPC2000 PGM save writes MIDI program change and ignores slider REQUIRE(bytesWithNonZeroControl == bytesWithZeroControl); } + +TEST_CASE("Kaitai MPC2000 PGM load preserves mixer effects send level", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + + parsed.pad_mixers()->at(1)->set_effects_send_level(50); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + const auto program = loadProgram1FromBytes(mpc, programBytes); + + REQUIRE(program != nullptr); + REQUIRE(program->getNoteParameters(36)->getIndivFxMixer()->getFxSendLevel() == 50); +} From 7b160ab36a50b04bb7752ff0a1758cf37bc204dd Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:27:05 +0200 Subject: [PATCH 12/52] Add focused PGM reader and converter parity tests --- src/test/KaitaiPgmTest.cpp | 134 +++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp index 7d4a53cc..57586874 100644 --- a/src/test/KaitaiPgmTest.cpp +++ b/src/test/KaitaiPgmTest.cpp @@ -5,12 +5,15 @@ #include "IntTypes.hpp" #include "disk/AbstractDisk.hpp" #include "disk/MpcFile.hpp" +#include "disk/PgmFileToProgramConverter.hpp" #include "disk/ProgramLoader.hpp" #include "engine/IndivFxMixer.hpp" #include "engine/EngineHost.hpp" #include "engine/StereoMixer.hpp" #include "file/kaitai/PgmIo.hpp" #include "file/kaitai/generated/mpc2000xl_pgm.h" +#include "file/pgmreader/ProgramFileReader.hpp" +#include "file/pgmreader/PRSlider.hpp" #include "file/pgmwriter/PgmWriter.hpp" #include "performance/PerformanceManager.hpp" #include "sampler/PgmSlider.hpp" @@ -96,6 +99,21 @@ std::shared_ptr loadProgram1FromBytes( return program; } +std::shared_ptr loadProgram1FileFromBytes( + mpc::Mpc& mpc, + const std::vector& programBytes) +{ + prepareProgramLoadingResources(mpc); + + auto disk = mpc.getDisk(); + disk->moveForward("program1"); + disk->initFiles(); + auto pgmFile = disk->getFile("PROGRAM1.PGM"); + auto mutableBytes = programBytes; + pgmFile->setFileData(mutableBytes); + return pgmFile; +} + void requireProgram1LoadedState(mpc::Mpc& mpc, const std::shared_ptr& program) { @@ -423,3 +441,119 @@ TEST_CASE("Kaitai MPC2000 PGM load preserves mixer effects send level", "[kaitai REQUIRE(program != nullptr); REQUIRE(program->getNoteParameters(36)->getIndivFxMixer()->getFxSendLevel() == 50); } + +TEST_CASE("PgmFileToProgramConverter loads upper-bound MIDI program change", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + parsed.set_program_change(127); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); + auto program = mpc.getSampler()->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + std::vector soundNames; + + auto result = mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( + mpc, pgmFile, program, soundNames + ); + REQUIRE(result); + + mpc.getPerformanceManager().lock()->drainQueue(); + REQUIRE(program->getMidiProgramChange() == 128); +} + +TEST_CASE("ProgramFileReader reads upper-bound MIDI program change byte", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + parsed.set_program_change(127); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); + + mpc::file::pgmreader::ProgramFileReader reader(pgmFile); + REQUIRE(reader.getSlider()->getProgramChange() == 127); +} + +TEST_CASE("PgmFileToProgramConverter loads mutated note tune", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + parsed.note_parameters()->at(0)->set_tune(-120); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); + auto program = mpc.getSampler()->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + std::vector soundNames; + + auto result = mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( + mpc, pgmFile, program, soundNames + ); + REQUIRE(result); + + mpc.getPerformanceManager().lock()->drainQueue(); + REQUIRE(program->getNoteParameters(35)->getTune() == -120); +} From deff429cef3025b1da50cc6bf78608ba1cab6aa6 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:35:01 +0200 Subject: [PATCH 13/52] Add ProgramLoader PGM parity coverage --- src/test/KaitaiPgmTest.cpp | 95 +++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp index 57586874..c306c253 100644 --- a/src/test/KaitaiPgmTest.cpp +++ b/src/test/KaitaiPgmTest.cpp @@ -99,6 +99,29 @@ std::shared_ptr loadProgram1FromBytes( return program; } +std::shared_ptr loadProgram1FromBytesWithoutRender( + mpc::Mpc& mpc, + const std::vector& programBytes) +{ + prepareProgramLoadingResources(mpc); + + auto disk = mpc.getDisk(); + disk->moveForward("program1"); + disk->initFiles(); + auto pgmFile = disk->getFile("PROGRAM1.PGM"); + auto mutableBytes = programBytes; + pgmFile->setFileData(mutableBytes); + + auto sampler = mpc.getSampler(); + sampler->deleteAllPrograms(false); + sampler->deleteAllSamples(); + + auto program = sampler->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + (void)mpc::disk::ProgramLoader::loadProgram(mpc, pgmFile, program, 0); + mpc.getPerformanceManager().lock()->drainQueue(); + return program; +} + std::shared_ptr loadProgram1FileFromBytes( mpc::Mpc& mpc, const std::vector& programBytes) @@ -373,7 +396,7 @@ TEST_CASE("Kaitai MPC2000 PGM load uses standalone byte as MIDI program change", mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); - const auto program = loadProgram1FromBytes(mpc, programBytes); + const auto program = loadProgram1FromBytesWithoutRender(mpc, programBytes); REQUIRE(program->getMidiProgramChange() == 2); REQUIRE(program->getSlider()->getControlChange() == 0); @@ -436,7 +459,7 @@ TEST_CASE("Kaitai MPC2000 PGM load preserves mixer effects send level", "[kaitai mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); - const auto program = loadProgram1FromBytes(mpc, programBytes); + const auto program = loadProgram1FromBytesWithoutRender(mpc, programBytes); REQUIRE(program != nullptr); REQUIRE(program->getNoteParameters(36)->getIndivFxMixer()->getFxSendLevel() == 50); @@ -557,3 +580,71 @@ TEST_CASE("PgmFileToProgramConverter loads mutated note tune", "[kaitai-pgm]") mpc.getPerformanceManager().lock()->drainQueue(); REQUIRE(program->getNoteParameters(35)->getTune() == -120); } + +TEST_CASE("ProgramLoader loads upper-bound MIDI program change", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + parsed.set_program_change(127); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + const auto program = loadProgram1FromBytes(mpc, programBytes); + + REQUIRE(program != nullptr); + REQUIRE(program->getMidiProgramChange() == 128); +} + +TEST_CASE("ProgramLoader loads mutated note tune", "[kaitai-pgm]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + parsed.note_parameters()->at(0)->set_tune(-120); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + const auto program = loadProgram1FromBytes(mpc, programBytes); + + REQUIRE(program != nullptr); + REQUIRE(program->getNoteParameters(35)->getTune() == -120); +} From bf1fbfd94af8791bae63fbc144bacad55d687cad Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:41:32 +0200 Subject: [PATCH 14/52] Add focused APS loader parity tests --- src/test/KaitaiApsTest.cpp | 120 +++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index 9140e7a3..e91fe1d7 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -8,6 +8,7 @@ #include "engine/EngineHost.hpp" #include "file/kaitai/ApsIo.hpp" #include "file/aps/ApsParser.hpp" +#include "file/aps/ApsSlider.hpp" #include "file/kaitai/generated/mpc2000xl_aps.h" #include "performance/PerformanceManager.hpp" #include "sampler/Program.hpp" @@ -64,6 +65,26 @@ void loadAllPgmsAps(mpc::Mpc& mpc) mpc.getEngineHost()->prepareProcessBlock(512); } +std::shared_ptr loadAllPgmsApsFileFromBytes( + mpc::Mpc& mpc, + const std::vector& apsBytes) +{ + prepareApsResources(mpc); + auto apsFile = mpc.getDisk()->getFile("ALL_PGMS.APS"); + auto mutableBytes = apsBytes; + apsFile->setFileData(mutableBytes); + mpc.getDisk()->initFiles(); + return apsFile; +} + +void loadAllPgmsApsWithoutRender(mpc::Mpc& mpc, const std::vector& apsBytes) +{ + auto apsFile = loadAllPgmsApsFileFromBytes(mpc, apsBytes); + constexpr bool headless = true; + mpc::disk::ApsLoader::load(mpc, apsFile, headless); + mpc.getPerformanceManager().lock()->drainQueue(); +} + } TEST_CASE("Kaitai MPC2000 APS parses and rewrites ALL_PGMS", "[kaitai-aps]") @@ -294,3 +315,102 @@ TEST_CASE("Kaitai MPC2000 APS loads real 2KXL ALL_PGMS through production seam", REQUIRE(p1->getNoteParameters(35)->getSoundIndex() == -1); REQUIRE(p1->getNoteParameters(36)->getSoundIndex() == -1); } + +TEST_CASE("ApsParser reads upper-bound MIDI program change", "[kaitai-aps]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ApsLoading/ALL_PGMS.APS"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + parsed.aps_programs()->at(0)->body()->set_program_change(127); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector apsBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + mpc::file::aps::ApsParser handwrittenParser(apsBytes); + REQUIRE(handwrittenParser.getPrograms().at(0)->getSlider()->getProgramChange() == 127); +} + +TEST_CASE("ApsLoader loads upper-bound MIDI program change", "[kaitai-aps]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ApsLoading/ALL_PGMS.APS"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + parsed.aps_programs()->at(0)->body()->set_program_change(127); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector apsBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + loadAllPgmsApsWithoutRender(mpc, apsBytes); + + auto p1 = mpc.getSampler()->getProgram(0); + REQUIRE(p1 != nullptr); + REQUIRE(p1->getMidiProgramChange() == 128); +} + +TEST_CASE("ApsLoader loads mutated note tune", "[kaitai-aps]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ApsLoading/ALL_PGMS.APS"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + parsed.aps_programs()->at(0)->body()->note_parameters()->at(0)->set_tune(-120); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + std::vector apsBytes(rewrittenBytes.begin(), rewrittenBytes.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + loadAllPgmsApsWithoutRender(mpc, apsBytes); + + auto p1 = mpc.getSampler()->getProgram(0); + REQUIRE(p1 != nullptr); + REQUIRE(p1->getNoteParameters(35)->getTune() == -120); +} From 5e59d337a04ea1ea3fc7d5350a431dee3fdbaba5 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:44:01 +0200 Subject: [PATCH 15/52] Add focused SND handwritten-path parity tests --- src/test/KaitaiSndTest.cpp | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/test/KaitaiSndTest.cpp b/src/test/KaitaiSndTest.cpp index 7889a79b..d3aaadde 100644 --- a/src/test/KaitaiSndTest.cpp +++ b/src/test/KaitaiSndTest.cpp @@ -525,3 +525,83 @@ TEST_CASE("Generated MPC2000XL SND corpus loads through the production loader", } } } + +TEST_CASE("SndReader reads mutated header semantics from Kaitai-written bytes", "[kaitai-snd]") +{ + auto bytes = resourceBytes("test/GeneratedMpc2000xl/Snd/mono_loop_mid.SND"); + + std::vector rewrittenBytes; + withParsedSndBytes(bytes, [&](mpc2000snd_t &parsed) + { + parsed.set_tune(120); + parsed.set_start(0); + parsed.set_end(3); + parsed.set_loop_frame_count(2); + parsed.set_loop_enabled(false); + parsed.set_beat_count(32); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto written = writeStream.str(); + rewrittenBytes.assign(written.begin(), written.end()); + }); + + SndReader handwrittenReader(rewrittenBytes); + auto outputData = std::make_shared>(); + handwrittenReader.readData(outputData); + + REQUIRE(handwrittenReader.isHeaderValid()); + REQUIRE(handwrittenReader.getName() == "mono_loop_mid"); + REQUIRE(handwrittenReader.isMono()); + REQUIRE(handwrittenReader.getSampleRate() == 44100); + REQUIRE(handwrittenReader.getLevel() == 100); + REQUIRE(handwrittenReader.getTune() == 120); + REQUIRE(handwrittenReader.getStart() == 0); + REQUIRE(handwrittenReader.getEnd() == 3); + REQUIRE(handwrittenReader.getLoopLength() == 2); + REQUIRE(!handwrittenReader.isLoopEnabled()); + REQUIRE(handwrittenReader.getNumberOfBeats() == 32); + REQUIRE(outputData->size() == 4U); +} + +TEST_CASE("SoundLoader loads mutated SND header semantics from Kaitai-written bytes", "[kaitai-snd]") +{ + auto bytes = resourceBytes("test/GeneratedMpc2000xl/Snd/stereo_span.SND"); + + std::vector rewrittenBytes; + withParsedSndBytes(bytes, [&](mpc2000snd_t &parsed) + { + parsed.set_tune(-120); + parsed.set_start(1); + parsed.set_end(4); + parsed.set_loop_frame_count(1); + parsed.set_loop_enabled(true); + parsed.set_beat_count(1); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto written = writeStream.str(); + rewrittenBytes.assign(written.begin(), written.end()); + }); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + const auto loaded = loadWithSoundLoader(mpc, rewrittenBytes, "stereo_span.SND"); + + REQUIRE(loaded->getName() == "stereo_span"); + REQUIRE(!loaded->isMono()); + REQUIRE(loaded->getTune() == -120); + REQUIRE(loaded->getStart() == 1); + REQUIRE(loaded->getEnd() == 4); + REQUIRE(loaded->getLoopTo() == 3); + REQUIRE(loaded->isLoopEnabled()); + REQUIRE(loaded->getBeatCount() == 1); +} From 0c44fd2a6d6e5b5a0f0666a24123bf06ba4adf51 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:47:19 +0200 Subject: [PATCH 16/52] Add focused ALL handwritten-path parity tests --- src/test/KaitaiAllTest.cpp | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/test/KaitaiAllTest.cpp b/src/test/KaitaiAllTest.cpp index a290c8b1..e280742c 100644 --- a/src/test/KaitaiAllTest.cpp +++ b/src/test/KaitaiAllTest.cpp @@ -7,6 +7,8 @@ #include "disk/AllLoader.hpp" #include "disk/MpcFile.hpp" #include "file/all/AllParser.hpp" +#include "file/all/AllSong.hpp" +#include "file/all/Defaults.hpp" #include "file/kaitai/AllIo.hpp" #include "file/kaitai/generated/mpc2000xl_all.h" #include "lcdgui/ScreenId.hpp" @@ -60,6 +62,19 @@ std::shared_ptr installResourceFile( return newFile; } +std::shared_ptr installAllBytes( + mpc::Mpc& mpc, + const std::vector& bytes, + const std::string& fileName) +{ + auto disk = mpc.getDisk(); + auto newFile = disk->newFile(fileName); + auto mutableBytes = bytes; + newFile->setFileData(mutableBytes); + disk->initFiles(); + return newFile; +} + } TEST_CASE("Kaitai MPC2000 ALL parses and rewrites real 2KXL ALL", "[kaitai-all][real-2kxl]") @@ -242,3 +257,80 @@ TEST_CASE("Kaitai MPC2000 ALL loads real 2KXL ALL through production seam", "[ka REQUIRE(song1->getStep(mpc::SongStepIndex(1)).sequenceIndex == 0); REQUIRE(song1->getStep(mpc::SongStepIndex(1)).repetitionCount == 3); } + +TEST_CASE("AllParser reads mutated default tempo and song repeat count", "[kaitai-all]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc2000xl/All/ALL.ALL"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + parsed.defaults()->set_tempo(999); + parsed.songs()->at(1)->steps()->at(1)->set_repeat_count(7); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewritten = writeStream.str(); + std::vector bytes(rewritten.begin(), rewritten.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + mpc::file::all::AllParser handwritten(mpc, bytes); + + REQUIRE(handwritten.getDefaults()->getTempo() == 999); + REQUIRE(handwritten.getSongs().at(1)->getSteps().at(1).second == 7); +} + +TEST_CASE("AllLoader loads mutated default tempo and song repeat count", "[kaitai-all]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc2000xl/All/ALL.ALL"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + parsed.defaults()->set_tempo(999); + parsed.songs()->at(1)->steps()->at(1)->set_repeat_count(7); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewritten = writeStream.str(); + std::vector bytes(rewritten.begin(), rewritten.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + auto allFile = installAllBytes(mpc, bytes, "MUTATED.ALL"); + REQUIRE(allFile); + + mpc::disk::AllLoader::loadEverythingFromFile(mpc, allFile.get()); + mpc.getSequencer()->getStateManager()->drainQueue(); + + auto userScreen = mpc.screens->get(); + auto song1 = mpc.getSequencer()->getSong(1); + REQUIRE(userScreen); + REQUIRE_THAT(userScreen->getTempo(), Catch::Matchers::WithinAbs(99.9, 0.001)); + REQUIRE(song1->getStep(mpc::SongStepIndex(1)).repetitionCount == 7); +} From 59472937e7ba66aa5b87b49f42c739b20fb6696b Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 18:26:32 +0200 Subject: [PATCH 17/52] Broaden PGM handwritten-path parity coverage --- src/test/KaitaiPgmTest.cpp | 173 +++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp index c306c253..08b37802 100644 --- a/src/test/KaitaiPgmTest.cpp +++ b/src/test/KaitaiPgmTest.cpp @@ -16,6 +16,7 @@ #include "file/pgmreader/PRSlider.hpp" #include "file/pgmwriter/PgmWriter.hpp" #include "performance/PerformanceManager.hpp" +#include "sampler/Pad.hpp" #include "sampler/PgmSlider.hpp" #include "sampler/Program.hpp" #include "sampler/Sampler.hpp" @@ -34,6 +35,144 @@ CMRC_DECLARE(mpctest); namespace { +std::vector rewriteProgram1WithMutations( + const std::function& mutate) +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); + + mutate(parsed); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + return std::vector(rewrittenBytes.begin(), rewrittenBytes.end()); +} + +void applyBroadProgramMutation(mpc2000xl_pgm_t& parsed) +{ + auto* note35 = parsed.note_parameters()->at(0).get(); + note35->set_sound_index(255); + note35->set_sound_generation_mode(mpc2000xl_pgm_t::SOUND_GENERATION_MODE_VEL_SW); + note35->set_velocity_range_lower(1); + note35->set_velocity_range_upper(127); + note35->set_also_play_use_note_1(41); + note35->set_also_play_use_note_2(42); + note35->set_voice_overlap_mode(mpc2000xl_pgm_t::VOICE_OVERLAP_MODE_NOTE_OFF); + note35->set_mute_assign_1(43); + note35->set_mute_assign_2(44); + note35->set_tune(-120); + note35->set_attack(99); + note35->set_decay(98); + note35->set_decay_mode(mpc2000xl_pgm_t::DECAY_MODE_START); + note35->set_cutoff(17); + note35->set_resonance(18); + note35->set_velocity_envelope_to_filter_attack(19); + note35->set_velocity_envelope_to_filter_decay(20); + note35->set_velocity_envelope_to_filter_amount(21); + note35->set_velocity_to_level(22); + note35->set_velocity_to_attack(23); + note35->set_velocity_to_start(24); + note35->set_velocity_to_cutoff(25); + note35->set_slider_parameter(mpc2000xl_pgm_t::SLIDER_PARAMETER_FILTER); + note35->set_velocity_to_pitch(26); + + auto* mixer35 = parsed.pad_mixers()->at(0).get(); + mixer35->set_fx_output(mpc2000xl_pgm_t::FX_OUTPUT_R2); + mixer35->set_volume(12); + mixer35->set_pan(13); + mixer35->set_volume_individual(14); + mixer35->set_output(2); + mixer35->set_effects_send_level(15); + + parsed.slider()->set_note(52); + parsed.slider()->set_tune_low(-119); + parsed.slider()->set_tune_high(118); + parsed.slider()->set_decay_low(11); + parsed.slider()->set_decay_high(12); + parsed.slider()->set_attack_low(13); + parsed.slider()->set_attack_high(14); + parsed.slider()->set_filter_low(-15); + parsed.slider()->set_filter_high(16); + + parsed.set_program_change(126); + parsed.pad_to_note_mapping()->at(0) = 50; +} + +void requireBroadMutatedProgramState( + const std::shared_ptr& program, + const std::vector& soundNames) +{ + REQUIRE(program != nullptr); + REQUIRE(soundNames.size() == 2U); + REQUIRE(soundNames[0] == std::string("sound1") + std::string(10, ' ')); + REQUIRE(soundNames[1] == std::string("sound2") + std::string(10, ' ')); + + REQUIRE(program->getPad(0)->getNote() == 50); + REQUIRE(program->getMidiProgramChange() == 127); + + const auto note35 = program->getNoteParameters(35); + REQUIRE(note35->getSoundIndex() == -1); + REQUIRE(note35->getSoundGenerationMode() == 2); + REQUIRE(note35->getVelocityRangeLower() == 1); + REQUIRE(note35->getVelocityRangeUpper() == 127); + REQUIRE(note35->getOptionalNoteA() == 41); + REQUIRE(note35->getOptionalNoteB() == 42); + REQUIRE(note35->getMuteAssignA() == 43); + REQUIRE(note35->getMuteAssignB() == 44); + REQUIRE(note35->getTune() == -120); + REQUIRE(note35->getAttack() == 99); + REQUIRE(note35->getDecay() == 98); + REQUIRE(note35->getDecayMode() == 1); + REQUIRE(note35->getFilterFrequency() == 17); + REQUIRE(note35->getFilterResonance() == 18); + REQUIRE(note35->getFilterAttack() == 19); + REQUIRE(note35->getFilterDecay() == 20); + REQUIRE(note35->getFilterEnvelopeAmount() == 21); + REQUIRE(note35->getVeloToLevel() == 22); + REQUIRE(note35->getVelocityToAttack() == 23); + REQUIRE(note35->getVelocityToStart() == 24); + REQUIRE(note35->getVelocityToFilterFrequency() == 25); + REQUIRE(note35->getSliderParameterNumber() == 3); + REQUIRE(note35->getVelocityToPitch() == 26); + REQUIRE(note35->getVoiceOverlapMode() == mpc::sampler::VoiceOverlapMode::NOTE_OFF); + + const auto stereoMixer = note35->getStereoMixer(); + const auto indivFxMixer = note35->getIndivFxMixer(); + REQUIRE(stereoMixer->getLevel() == 12); + REQUIRE(stereoMixer->getPanning() == 13); + REQUIRE(indivFxMixer->getVolumeIndividualOut() == 14); + REQUIRE(indivFxMixer->getOutput() == 2); + REQUIRE(indivFxMixer->getFxPath() == 4); + REQUIRE(indivFxMixer->getFxSendLevel() == 15); + + const auto slider = program->getSlider(); + REQUIRE(slider->getNote() == 52); + REQUIRE(slider->getTuneLowRange() == -119); + REQUIRE(slider->getTuneHighRange() == 118); + REQUIRE(slider->getDecayLowRange() == 11); + REQUIRE(slider->getDecayHighRange() == 12); + REQUIRE(slider->getAttackLowRange() == 13); + REQUIRE(slider->getAttackHighRange() == 14); + REQUIRE(slider->getFilterLowRange() == -15); + REQUIRE(slider->getFilterHighRange() == 16); +} + void prepareProgramLoadingResources(mpc::Mpc& mpc) { auto disk = mpc.getDisk(); @@ -648,3 +787,37 @@ TEST_CASE("ProgramLoader loads mutated note tune", "[kaitai-pgm]") REQUIRE(program != nullptr); REQUIRE(program->getNoteParameters(35)->getTune() == -120); } + +TEST_CASE("PgmFileToProgramConverter loads broad mutated program semantics", "[kaitai-pgm]") +{ + const auto programBytes = rewriteProgram1WithMutations(applyBroadProgramMutation); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); + auto program = mpc.getSampler()->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + std::vector soundNames; + + auto result = mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( + mpc, pgmFile, program, soundNames + ); + REQUIRE(result); + + mpc.getPerformanceManager().lock()->drainQueue(); + requireBroadMutatedProgramState(program, soundNames); +} + +TEST_CASE("ProgramLoader loads broad mutated program semantics", "[kaitai-pgm]") +{ + const auto programBytes = rewriteProgram1WithMutations(applyBroadProgramMutation); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + const auto program = loadProgram1FromBytesWithoutRender(mpc, programBytes); + const std::vector expectedSoundNames{ + std::string("sound1") + std::string(10, ' '), + std::string("sound2") + std::string(10, ' ') + }; + + requireBroadMutatedProgramState(program, expectedSoundNames); +} From 56b119b0b489f20531b7c099fcca526c7a73838c Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 18:26:41 +0200 Subject: [PATCH 18/52] Fix assign screen slider parameter semantics --- src/main/lcdgui/screens/AssignScreen.cpp | 39 +++++++++++++++++++++- src/main/lcdgui/screens/AssignScreen.hpp | 2 ++ src/test/SamplerTest.cpp | 42 ++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/main/lcdgui/screens/AssignScreen.cpp b/src/main/lcdgui/screens/AssignScreen.cpp index 273df2a5..ae906234 100644 --- a/src/main/lcdgui/screens/AssignScreen.cpp +++ b/src/main/lcdgui/screens/AssignScreen.cpp @@ -15,6 +15,7 @@ AssignScreen::AssignScreen(Mpc &mpc, const int layerIndex) void AssignScreen::open() { + syncSliderParameterToAssignedNote(); displayAssignNote(); displayParameter(); displayHighRange(); @@ -47,7 +48,13 @@ void AssignScreen::turnWheel(int i) } else if (focusedFieldName == "parameter") { - slider->setParameter(slider->getParameter() + i); + const auto nextParameter = getSelectedSliderParameter() + i; + if (slider->getNote() != mpc::NoDrumNoteAssigned) + { + program->getNoteParameters(slider->getNote()) + ->setSliderParameterNumber(nextParameter); + } + slider->setParameter(nextParameter); } else if (focusedFieldName == "highrange") { @@ -202,7 +209,11 @@ void AssignScreen::update(Observable *observable, Message message) if (msg == "assignnote") { + syncSliderParameterToAssignedNote(); displayAssignNote(); + displayParameter(); + displayHighRange(); + displayLowRange(); } else if (msg == "parameter") { @@ -223,3 +234,29 @@ void AssignScreen::update(Observable *observable, Message message) displayAssignNv(); } } + +int AssignScreen::getSelectedSliderParameter() const +{ + const auto program = getProgramOrThrow(); + const auto slider = program->getSlider(); + const auto note = slider->getNote(); + + if (note == mpc::NoDrumNoteAssigned) + { + return slider->getParameter(); + } + + return program->getNoteParameters(note)->getSliderParameterNumber(); +} + +void AssignScreen::syncSliderParameterToAssignedNote() const +{ + const auto program = getProgramOrThrow(); + const auto slider = program->getSlider(); + const auto selectedParameter = getSelectedSliderParameter(); + + if (slider->getParameter() != selectedParameter) + { + slider->setParameter(selectedParameter); + } +} diff --git a/src/main/lcdgui/screens/AssignScreen.hpp b/src/main/lcdgui/screens/AssignScreen.hpp index f21de45e..5eb216ff 100644 --- a/src/main/lcdgui/screens/AssignScreen.hpp +++ b/src/main/lcdgui/screens/AssignScreen.hpp @@ -15,6 +15,8 @@ namespace mpc::lcdgui::screens void update(Observable *o, Message message) override; private: + int getSelectedSliderParameter() const; + void syncSliderParameterToAssignedNote() const; void displayAssignNote() const; void displayParameter() const; void displayHighRange() const; diff --git a/src/test/SamplerTest.cpp b/src/test/SamplerTest.cpp index 33a19e82..ebb5614d 100644 --- a/src/test/SamplerTest.cpp +++ b/src/test/SamplerTest.cpp @@ -13,6 +13,7 @@ #include "engine/control/CompoundControl.hpp" #include "lcdgui/ScreenComponent.hpp" #include "lcdgui/screens/dialog/MetronomeSoundScreen.hpp" +#include "performance/PerformanceManager.hpp" #include "disk/SoundLoader.hpp" #include @@ -393,6 +394,47 @@ TEST_CASE("Sort does not corrupt note parameter sound indices", "[sampler]") } } +TEST_CASE("Assign screen parameter follows assigned note and edits that note", "[sampler]") +{ + Mpc mpc; + TestMpc::initializeTestMpc(mpc); + + auto sampler = mpc.getSampler(); + auto program = sampler->getProgram(0); + REQUIRE(program != nullptr); + + program->getSlider()->setAssignNote(mpc::DrumNoteNumber(42)); + program->getSlider()->setParameter(mpc::NoteVariationTypeTune); + program->getNoteParameters(42)->setSliderParameterNumber(mpc::NoteVariationTypeFilter); + program->getNoteParameters(43)->setSliderParameterNumber(mpc::NoteVariationTypeAttack); + mpc.getPerformanceManager().lock()->drainQueue(); + + mpc.getLayeredScreen()->openScreenById(ScreenId::AssignScreen); + auto controls = mpc.getScreen(); + REQUIRE(controls != nullptr); + + auto parameterField = [&] + { + return controls->findChild("parameter"); + }; + + REQUIRE(parameterField() != nullptr); + REQUIRE(parameterField()->getText() == "FILTER"); + + REQUIRE(mpc.getLayeredScreen()->setFocus("assignnote")); + controls->turnWheel(1); + REQUIRE(parameterField()->getText() == "ATTACK"); + REQUIRE(program->getSlider()->getParameter() == mpc::NoteVariationTypeAttack); + + REQUIRE(mpc.getLayeredScreen()->setFocus("parameter")); + controls->turnWheel(1); + REQUIRE(parameterField()->getText() == "FILTER"); + mpc.getPerformanceManager().lock()->drainQueue(); + REQUIRE(program->getNoteParameters(43)->getSliderParameterNumber() == mpc::NoteVariationTypeFilter); + REQUIRE(program->getSlider()->getParameter() == mpc::NoteVariationTypeFilter); + REQUIRE(program->getNoteParameters(42)->getSliderParameterNumber() == mpc::NoteVariationTypeFilter); +} + TEST_CASE("Delete sound 1", "[sampler]") { Mpc mpc; From 7372fb4e904c5c3632f7f75bbc2aca6d5a4f8c7e Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 22:54:21 +0200 Subject: [PATCH 19/52] Expand APS parity coverage --- src/test/KaitaiApsTest.cpp | 252 +++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index e91fe1d7..395db5e8 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -5,14 +5,25 @@ #include "disk/AbstractDisk.hpp" #include "disk/ApsLoader.hpp" #include "disk/MpcFile.hpp" +#include "engine/IndivFxMixer.hpp" #include "engine/EngineHost.hpp" +#include "engine/StereoMixer.hpp" #include "file/kaitai/ApsIo.hpp" +#include "file/aps/ApsDrumConfiguration.hpp" +#include "file/aps/ApsGlobalParameters.hpp" +#include "file/aps/ApsNoteParameters.hpp" #include "file/aps/ApsParser.hpp" #include "file/aps/ApsSlider.hpp" #include "file/kaitai/generated/mpc2000xl_aps.h" +#include "lcdgui/screens/DrumScreen.hpp" +#include "lcdgui/screens/MixerSetupScreen.hpp" +#include "lcdgui/screens/PgmAssignScreen.hpp" #include "performance/PerformanceManager.hpp" +#include "sampler/Pad.hpp" #include "sampler/Program.hpp" #include "sampler/Sampler.hpp" +#include "sequencer/Bus.hpp" +#include "sequencer/Sequencer.hpp" #include #include @@ -26,6 +37,103 @@ CMRC_DECLARE(mpctest); namespace { +std::vector rewriteAllPgmsApsWithMutations( + const std::function& mutate) +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/ApsLoading/ALL_PGMS.APS"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + + mutate(parsed); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + return std::vector(rewrittenBytes.begin(), rewrittenBytes.end()); +} + +void applyBroadApsMutation(mpc2000xl_aps_t& parsed) +{ + auto* program0 = parsed.aps_programs()->at(0)->body(); + auto* note35 = program0->note_parameters()->at(0).get(); + note35->set_sound_index(255); + note35->set_sound_generation_mode(mpc2000xl_pgm_t::SOUND_GENERATION_MODE_VEL_SW); + note35->set_velocity_range_lower(1); + note35->set_also_play_use_note_1(41); + note35->set_velocity_range_upper(127); + note35->set_also_play_use_note_2(42); + note35->set_voice_overlap_mode(mpc2000xl_pgm_t::VOICE_OVERLAP_MODE_NOTE_OFF); + note35->set_mute_assign_1(43); + note35->set_mute_assign_2(44); + note35->set_tune(-120); + note35->set_attack(99); + note35->set_decay(98); + note35->set_decay_mode(mpc2000xl_pgm_t::DECAY_MODE_START); + note35->set_cutoff(17); + note35->set_resonance(18); + note35->set_velocity_envelope_to_filter_attack(19); + note35->set_velocity_envelope_to_filter_decay(20); + note35->set_velocity_envelope_to_filter_amount(21); + note35->set_velocity_to_level(22); + note35->set_velocity_to_attack(23); + note35->set_velocity_to_start(24); + note35->set_velocity_to_cutoff(25); + note35->set_slider_parameter(mpc2000xl_pgm_t::SLIDER_PARAMETER_FILTER); + note35->set_velocity_to_pitch(26); + + auto* mixer35 = program0->pad_mixers()->at(0).get(); + mixer35->set_fx_output(mpc2000xl_pgm_t::FX_OUTPUT_R2); + mixer35->set_volume(12); + mixer35->set_pan(13); + mixer35->set_volume_individual(14); + mixer35->set_output(2); + mixer35->set_effects_send_level(15); + + program0->slider()->set_note(52); + program0->slider()->set_tune_low(-119); + program0->slider()->set_tune_high(118); + program0->slider()->set_decay_low(11); + program0->slider()->set_decay_high(12); + program0->slider()->set_attack_low(13); + program0->slider()->set_attack_high(14); + program0->slider()->set_filter_low(-15); + program0->slider()->set_filter_high(16); + program0->set_program_change(126); + program0->pad_to_note_mapping()->at(0) = 50; + parsed.master_pad_to_note_mapping()->at(0) = 50; + + auto* drum0 = parsed.drum1(); + drum0->set_receive_program_change(mpc2000xl_aps_t::NO_YES_FALSE); + drum0->set_receive_midi_volume(mpc2000xl_aps_t::NO_YES_FALSE); + drum0->set_program(1); + drum0->set_receive_program_change_duplicate(mpc2000xl_aps_t::NO_YES_FALSE); + drum0->set_receive_midi_volume_duplicate(mpc2000xl_aps_t::NO_YES_FALSE); + + auto* globals = parsed.global_parameters(); + globals->set_pad_to_internal_sound(mpc2000xl_aps_t::NO_YES_TRUE); + globals->set_pad_assign(mpc2000xl_aps_t::PAD_ASSIGN_MASTERS); + globals->set_indiv_fx_source(mpc2000xl_aps_t::MIX_SOURCE_DRUM); + globals->set_stereo_mix_source(mpc2000xl_aps_t::MIX_SOURCE_DRUM); + globals->set_record_mix_changes(mpc2000xl_aps_t::NO_YES_TRUE); + globals->set_copy_pgm_mix_to_drum(mpc2000xl_aps_t::NO_YES_FALSE); + globals->set_fx_drum(3); + globals->set_master_level(6); +} + void prepareApsResources(mpc::Mpc& mpc) { auto disk = mpc.getDisk(); @@ -414,3 +522,147 @@ TEST_CASE("ApsLoader loads mutated note tune", "[kaitai-aps]") REQUIRE(p1 != nullptr); REQUIRE(p1->getNoteParameters(35)->getTune() == -120); } + +TEST_CASE("ApsParser reads broad mutated APS semantics", "[kaitai-aps]") +{ + const auto apsBytes = rewriteAllPgmsApsWithMutations(applyBroadApsMutation); + + mpc::file::aps::ApsParser handwrittenParser(apsBytes); + auto programs = handwrittenParser.getPrograms(); + REQUIRE(programs.size() >= 1U); + + auto* p1 = programs.at(0); + REQUIRE(p1->getName() == "PROGRAM1"); + REQUIRE(p1->getAssignTable()->get().at(0) == 50); + REQUIRE(p1->getSlider()->getNote() == 52); + REQUIRE(p1->getSlider()->getTuneLow() == -119); + REQUIRE(p1->getSlider()->getTuneHigh() == 118); + REQUIRE(p1->getSlider()->getDecayLow() == 11); + REQUIRE(p1->getSlider()->getDecayHigh() == 12); + REQUIRE(p1->getSlider()->getAttackLow() == 13); + REQUIRE(p1->getSlider()->getAttackHigh() == 14); + REQUIRE(p1->getSlider()->getFilterLow() == -15); + REQUIRE(p1->getSlider()->getFilterHigh() == 16); + REQUIRE(p1->getSlider()->getProgramChange() == 126); + + auto* note35 = p1->getNoteParameters(0); + REQUIRE(note35->getSoundIndex() == -1); + REQUIRE(note35->getSoundGenerationMode() == 2); + REQUIRE(note35->getVelocityRangeLower() == 1); + REQUIRE(note35->getAlsoPlay1() == 41); + REQUIRE(note35->getVelocityRangeUpper() == 127); + REQUIRE(note35->getAlsoPlay2() == 42); + REQUIRE(note35->getVoiceOverlapMode() == mpc::sampler::VoiceOverlapMode::NOTE_OFF); + REQUIRE(note35->getMute1() == 43); + REQUIRE(note35->getMute2() == 44); + REQUIRE(note35->getTune() == -120); + REQUIRE(note35->getAttack() == 99); + REQUIRE(note35->getDecay() == 98); + REQUIRE(note35->getDecayMode() == 1); + REQUIRE(note35->getCutoffFrequency() == 17); + REQUIRE(note35->getResonance() == 18); + REQUIRE(note35->getVelocityToFilterAttack() == 19); + REQUIRE(note35->getVelocityToFilterDecay() == 20); + REQUIRE(note35->getVelocityToFilterAmount() == 21); + REQUIRE(note35->getVelocityToLevel() == 22); + REQUIRE(note35->getVelocityToAttack() == 23); + REQUIRE(note35->getVelocityToStart() == 24); + REQUIRE(note35->getVelocityToFilterFrequency() == 25); + REQUIRE(note35->getSliderParameter() == 3); + REQUIRE(note35->getVelocityToPitch() == 26); + + auto* drum0 = handwrittenParser.getDrumConfiguration(0); + REQUIRE(drum0->getProgramIndex() == 1); + REQUIRE(!drum0->isReceivePgmChangeEnabled()); + REQUIRE(!drum0->isReceiveMidiVolumeEnabled()); + + auto* globals = handwrittenParser.getGlobalParameters(); + REQUIRE(globals->isPadToIntSoundEnabled()); + REQUIRE(globals->isPadAssignMaster()); + REQUIRE(globals->isIndivFxSourceDrum()); + REQUIRE(globals->isStereoMixSourceDrum()); + REQUIRE(globals->isRecordMixChangesEnabled()); + REQUIRE(!globals->isCopyPgmMixToDrumEnabled()); + REQUIRE(globals->getFxDrum() == 3); + REQUIRE(globals->getMasterLevel() == 6); +} + +TEST_CASE("ApsLoader loads broad mutated APS semantics", "[kaitai-aps]") +{ + const auto apsBytes = rewriteAllPgmsApsWithMutations(applyBroadApsMutation); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + loadAllPgmsApsWithoutRender(mpc, apsBytes); + + auto sampler = mpc.getSampler(); + auto p1 = sampler->getProgram(0); + REQUIRE(p1 != nullptr); + REQUIRE(p1->getPad(0)->getNote() == 50); + REQUIRE(p1->getMidiProgramChange() == 127); + + auto note35 = p1->getNoteParameters(35); + REQUIRE(note35->getSoundIndex() == -1); + REQUIRE(note35->getSoundGenerationMode() == 2); + REQUIRE(note35->getVelocityRangeLower() == 1); + REQUIRE(note35->getOptionalNoteA() == 41); + REQUIRE(note35->getVelocityRangeUpper() == 127); + REQUIRE(note35->getOptionalNoteB() == 42); + REQUIRE(note35->getVoiceOverlapMode() == mpc::sampler::VoiceOverlapMode::NOTE_OFF); + REQUIRE(note35->getMuteAssignA() == 43); + REQUIRE(note35->getMuteAssignB() == 44); + REQUIRE(note35->getTune() == -120); + REQUIRE(note35->getAttack() == 99); + REQUIRE(note35->getDecay() == 98); + REQUIRE(note35->getDecayMode() == 1); + REQUIRE(note35->getFilterFrequency() == 17); + REQUIRE(note35->getFilterResonance() == 18); + REQUIRE(note35->getFilterAttack() == 19); + REQUIRE(note35->getFilterDecay() == 20); + REQUIRE(note35->getFilterEnvelopeAmount() == 21); + REQUIRE(note35->getVeloToLevel() == 22); + REQUIRE(note35->getVelocityToAttack() == 23); + REQUIRE(note35->getVelocityToStart() == 24); + REQUIRE(note35->getVelocityToFilterFrequency() == 25); + REQUIRE(note35->getSliderParameterNumber() == 3); + REQUIRE(note35->getVelocityToPitch() == 26); + + auto stereoMixer = note35->getStereoMixer(); + auto indivFxMixer = note35->getIndivFxMixer(); + REQUIRE(stereoMixer->getLevel() == 12); + REQUIRE(stereoMixer->getPanning() == 13); + REQUIRE(indivFxMixer->getVolumeIndividualOut() == 14); + REQUIRE(indivFxMixer->getOutput() == 2); + REQUIRE(indivFxMixer->getFxPath() == 4); + REQUIRE(indivFxMixer->getFxSendLevel() == 15); + + auto slider = p1->getSlider(); + REQUIRE(slider->getNote() == 52); + REQUIRE(slider->getTuneLowRange() == -119); + REQUIRE(slider->getTuneHighRange() == 118); + REQUIRE(slider->getDecayLowRange() == 11); + REQUIRE(slider->getDecayHighRange() == 12); + REQUIRE(slider->getAttackLowRange() == 13); + REQUIRE(slider->getAttackHighRange() == 14); + REQUIRE(slider->getFilterLowRange() == -15); + REQUIRE(slider->getFilterHighRange() == 16); + + auto drum0 = mpc.getSequencer()->getDrumBus(mpc::DrumBusIndex(0)); + REQUIRE(drum0->getProgramIndex() == 1); + REQUIRE(!drum0->receivesPgmChange()); + REQUIRE(!drum0->receivesMidiVolume()); + + auto mixerSetup = mpc.screens->get(); + REQUIRE(mixerSetup->isRecordMixChangesEnabled()); + REQUIRE(!mixerSetup->isCopyPgmMixToDrumEnabled()); + REQUIRE(mixerSetup->getFxDrum() == 3); + REQUIRE(mixerSetup->isIndivFxSourceDrum()); + REQUIRE(mixerSetup->isStereoMixSourceDrum()); + REQUIRE(mixerSetup->getMasterLevel() == 6); + + auto drumScreen = mpc.screens->get(); + REQUIRE(drumScreen->isPadToIntSound()); + + auto pgmAssignScreen = mpc.screens->get(); + REQUIRE(pgmAssignScreen->isPadAssignMaster()); +} From 106ca30c4736a56d6cb1d98afb4c298f2822fa82 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sat, 20 Jun 2026 23:49:14 +0200 Subject: [PATCH 20/52] Finish APS Kaitai parity fixes --- src/main/disk/ApsLoader.cpp | 18 +++++++- src/main/file/aps/ApsParser.cpp | 5 ++ src/main/file/aps/ApsParser.hpp | 1 + .../file/kaitai/generated/mpc2000xl_aps.cpp | 44 +++++++++--------- .../file/kaitai/generated/mpc2000xl_aps.h | 36 +++++++-------- src/test/KaitaiApsTest.cpp | 46 +++++++++++++++++-- 6 files changed, 105 insertions(+), 45 deletions(-) diff --git a/src/main/disk/ApsLoader.cpp b/src/main/disk/ApsLoader.cpp index 4aee5deb..58b96532 100644 --- a/src/main/disk/ApsLoader.cpp +++ b/src/main/disk/ApsLoader.cpp @@ -115,6 +115,16 @@ void ApsLoader::loadFromParsedAps(ApsParser &apsParser, Mpc &mpc, for (auto &apsProgram : apsParser.getPrograms()) { sampler->getProgram(apsProgram->index)->setName(apsProgram->getName()); + const auto slider = sampler->getProgram(apsProgram->index)->getSlider(); + slider->setAssignNote(DrumNoteNumber(apsProgram->getSlider()->getNote())); + slider->setTuneLowRange(apsProgram->getSlider()->getTuneLow()); + slider->setTuneHighRange(apsProgram->getSlider()->getTuneHigh()); + slider->setDecayLowRange(apsProgram->getSlider()->getDecayLow()); + slider->setDecayHighRange(apsProgram->getSlider()->getDecayHigh()); + slider->setAttackLowRange(apsProgram->getSlider()->getAttackLow()); + slider->setAttackHighRange(apsProgram->getSlider()->getAttackHigh()); + slider->setFilterLowRange(apsProgram->getSlider()->getFilterLow()); + slider->setFilterHighRange(apsProgram->getSlider()->getFilterHigh()); performance::UpdateProgramBulk msg; auto &perfProgram = msg.program; @@ -275,7 +285,13 @@ void ApsLoader::loadFromParsedAps(ApsParser &apsParser, Mpc &mpc, mixerSetupScreen->setMasterLevel(globals->getMasterLevel()); auto pgmAssignScreen = mpc.screens->get(); - + std::vector masterPadAssign; + masterPadAssign.reserve(64); + for (const auto note : apsParser.getMasterAssignTable()) + { + masterPadAssign.emplace_back(note); + } + mpc.getSampler()->setMasterPadAssign(masterPadAssign); pgmAssignScreen->setPadAssign(globals->isPadAssignMaster()); } diff --git a/src/main/file/aps/ApsParser.cpp b/src/main/file/aps/ApsParser.cpp index c938bd9a..357c9091 100644 --- a/src/main/file/aps/ApsParser.cpp +++ b/src/main/file/aps/ApsParser.cpp @@ -217,6 +217,11 @@ ApsGlobalParameters *ApsParser::getGlobalParameters() const return globalParameters.get(); } +std::vector ApsParser::getMasterAssignTable() const +{ + return maTable->get(); +} + std::vector ApsParser::getBytes() { return saveBytes; diff --git a/src/main/file/aps/ApsParser.hpp b/src/main/file/aps/ApsParser.hpp index 131be96e..67b6fcba 100644 --- a/src/main/file/aps/ApsParser.hpp +++ b/src/main/file/aps/ApsParser.hpp @@ -64,6 +64,7 @@ namespace mpc::file::aps std::vector getDrumMixers() const; ApsDrumConfiguration *getDrumConfiguration(int i) const; ApsGlobalParameters *getGlobalParameters() const; + std::vector getMasterAssignTable() const; std::vector getBytes(); diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp index 4153c90b..2033b9ca 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp @@ -616,17 +616,17 @@ mpc2000xl_aps_t::global_parameters_t::global_parameters_t(kaitai::kstream* p__io } void mpc2000xl_aps_t::global_parameters_t::_read() { - m__unnamed0 = m__io->read_bits_int_be(7); - m_pad_to_internal_sound = static_cast(m__io->read_bits_int_be(1)); - m__unnamed2 = m__io->read_bits_int_be(7); - m_pad_assign = static_cast(m__io->read_bits_int_be(1)); - m__unnamed4 = m__io->read_bits_int_be(6); - m_indiv_fx_source = static_cast(m__io->read_bits_int_be(1)); - m_stereo_mix_source = static_cast(m__io->read_bits_int_be(1)); - m__unnamed7 = m__io->read_bits_int_be(3); - m_record_mix_changes = static_cast(m__io->read_bits_int_be(1)); - m_copy_pgm_mix_to_drum = static_cast(m__io->read_bits_int_be(1)); - m__unnamed10 = m__io->read_bits_int_be(3); + m_pad_to_internal_sound = static_cast(m__io->read_bits_int_le(1)); + m__unnamed1 = m__io->read_bits_int_le(7); + m_pad_assign = static_cast(m__io->read_bits_int_le(1)); + m__unnamed3 = m__io->read_bits_int_le(7); + m_stereo_mix_source = static_cast(m__io->read_bits_int_le(1)); + m_indiv_fx_source = static_cast(m__io->read_bits_int_le(1)); + m__unnamed6 = m__io->read_bits_int_le(6); + m_copy_pgm_mix_to_drum = static_cast(m__io->read_bits_int_le(1)); + m__unnamed8 = m__io->read_bits_int_le(3); + m_record_mix_changes = static_cast(m__io->read_bits_int_le(1)); + m__unnamed10 = m__io->read_bits_int_le(3); m_fx_drum = m__io->read_u1(); m__unnamed12 = m__io->read_bytes(1); m_master_level = m__io->read_u1(); @@ -637,17 +637,17 @@ void mpc2000xl_aps_t::global_parameters_t::_fetch_instances() { } void mpc2000xl_aps_t::global_parameters_t::_write() { - m__io->write_bits_int_be(7, m__unnamed0); - m__io->write_bits_int_be(1, static_cast(m_pad_to_internal_sound)); - m__io->write_bits_int_be(7, m__unnamed2); - m__io->write_bits_int_be(1, static_cast(m_pad_assign)); - m__io->write_bits_int_be(6, m__unnamed4); - m__io->write_bits_int_be(1, static_cast(m_indiv_fx_source)); - m__io->write_bits_int_be(1, static_cast(m_stereo_mix_source)); - m__io->write_bits_int_be(3, m__unnamed7); - m__io->write_bits_int_be(1, static_cast(m_record_mix_changes)); - m__io->write_bits_int_be(1, static_cast(m_copy_pgm_mix_to_drum)); - m__io->write_bits_int_be(3, m__unnamed10); + m__io->write_bits_int_le(1, static_cast(m_pad_to_internal_sound)); + m__io->write_bits_int_le(7, m__unnamed1); + m__io->write_bits_int_le(1, static_cast(m_pad_assign)); + m__io->write_bits_int_le(7, m__unnamed3); + m__io->write_bits_int_le(1, static_cast(m_stereo_mix_source)); + m__io->write_bits_int_le(1, static_cast(m_indiv_fx_source)); + m__io->write_bits_int_le(6, m__unnamed6); + m__io->write_bits_int_le(1, static_cast(m_copy_pgm_mix_to_drum)); + m__io->write_bits_int_le(3, m__unnamed8); + m__io->write_bits_int_le(1, static_cast(m_record_mix_changes)); + m__io->write_bits_int_le(3, m__unnamed10); m__io->write_u1(m_fx_drum); m__io->write_bytes(m__unnamed12); m__io->write_u1(m_master_level); diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.h b/src/main/file/kaitai/generated/mpc2000xl_aps.h index 7d2c2abe..07283fa7 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.h +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.h @@ -235,26 +235,26 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void _write(); void _check(); ~global_parameters_t(); - uint64_t _unnamed0() const { return m__unnamed0; } - void set__unnamed0(uint64_t _v) { m__dirty = true; m__unnamed0 = std::move(_v); } no_yes_t pad_to_internal_sound() const { return m_pad_to_internal_sound; } void set_pad_to_internal_sound(no_yes_t _v) { m__dirty = true; m_pad_to_internal_sound = std::move(_v); } - uint64_t _unnamed2() const { return m__unnamed2; } - void set__unnamed2(uint64_t _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + uint64_t _unnamed1() const { return m__unnamed1; } + void set__unnamed1(uint64_t _v) { m__dirty = true; m__unnamed1 = std::move(_v); } pad_assign_t pad_assign() const { return m_pad_assign; } void set_pad_assign(pad_assign_t _v) { m__dirty = true; m_pad_assign = std::move(_v); } - uint64_t _unnamed4() const { return m__unnamed4; } - void set__unnamed4(uint64_t _v) { m__dirty = true; m__unnamed4 = std::move(_v); } - mix_source_t indiv_fx_source() const { return m_indiv_fx_source; } - void set_indiv_fx_source(mix_source_t _v) { m__dirty = true; m_indiv_fx_source = std::move(_v); } + uint64_t _unnamed3() const { return m__unnamed3; } + void set__unnamed3(uint64_t _v) { m__dirty = true; m__unnamed3 = std::move(_v); } mix_source_t stereo_mix_source() const { return m_stereo_mix_source; } void set_stereo_mix_source(mix_source_t _v) { m__dirty = true; m_stereo_mix_source = std::move(_v); } - uint64_t _unnamed7() const { return m__unnamed7; } - void set__unnamed7(uint64_t _v) { m__dirty = true; m__unnamed7 = std::move(_v); } - no_yes_t record_mix_changes() const { return m_record_mix_changes; } - void set_record_mix_changes(no_yes_t _v) { m__dirty = true; m_record_mix_changes = std::move(_v); } + mix_source_t indiv_fx_source() const { return m_indiv_fx_source; } + void set_indiv_fx_source(mix_source_t _v) { m__dirty = true; m_indiv_fx_source = std::move(_v); } + uint64_t _unnamed6() const { return m__unnamed6; } + void set__unnamed6(uint64_t _v) { m__dirty = true; m__unnamed6 = std::move(_v); } no_yes_t copy_pgm_mix_to_drum() const { return m_copy_pgm_mix_to_drum; } void set_copy_pgm_mix_to_drum(no_yes_t _v) { m__dirty = true; m_copy_pgm_mix_to_drum = std::move(_v); } + uint64_t _unnamed8() const { return m__unnamed8; } + void set__unnamed8(uint64_t _v) { m__dirty = true; m__unnamed8 = std::move(_v); } + no_yes_t record_mix_changes() const { return m_record_mix_changes; } + void set_record_mix_changes(no_yes_t _v) { m__dirty = true; m_record_mix_changes = std::move(_v); } uint64_t _unnamed10() const { return m__unnamed10; } void set__unnamed10(uint64_t _v) { m__dirty = true; m__unnamed10 = std::move(_v); } uint8_t fx_drum() const { return m_fx_drum; } @@ -269,16 +269,16 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void set__parent(mpc2000xl_aps_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: - uint64_t m__unnamed0; no_yes_t m_pad_to_internal_sound; - uint64_t m__unnamed2; + uint64_t m__unnamed1; pad_assign_t m_pad_assign; - uint64_t m__unnamed4; - mix_source_t m_indiv_fx_source; + uint64_t m__unnamed3; mix_source_t m_stereo_mix_source; - uint64_t m__unnamed7; - no_yes_t m_record_mix_changes; + mix_source_t m_indiv_fx_source; + uint64_t m__unnamed6; no_yes_t m_copy_pgm_mix_to_drum; + uint64_t m__unnamed8; + no_yes_t m_record_mix_changes; uint64_t m__unnamed10; uint8_t m_fx_drum; std::string m__unnamed12; diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index 395db5e8..3dd5fbec 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -29,6 +29,8 @@ #include #include +#include +#include #include #include #include @@ -66,6 +68,28 @@ std::vector rewriteAllPgmsApsWithMutations( return std::vector(rewrittenBytes.begin(), rewrittenBytes.end()); } +std::string describeFirstByteDiff( + const std::string& lhs, + const std::string& rhs) +{ + const auto mismatch = std::mismatch(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + if (mismatch.first == lhs.end() && mismatch.second == rhs.end()) + { + return "no diff"; + } + + const auto offset = static_cast(mismatch.first - lhs.begin()); + std::ostringstream oss; + oss << "first diff at offset " << offset + << ": lhs=0x" + << std::hex << std::setw(2) << std::setfill('0') + << (static_cast(static_cast(*mismatch.first))) + << " rhs=0x" + << std::hex << std::setw(2) << std::setfill('0') + << (static_cast(static_cast(*mismatch.second))); + return oss.str(); +} + void applyBroadApsMutation(mpc2000xl_aps_t& parsed) { auto* program0 = parsed.aps_programs()->at(0)->body(); @@ -131,7 +155,7 @@ void applyBroadApsMutation(mpc2000xl_aps_t& parsed) globals->set_record_mix_changes(mpc2000xl_aps_t::NO_YES_TRUE); globals->set_copy_pgm_mix_to_drum(mpc2000xl_aps_t::NO_YES_FALSE); globals->set_fx_drum(3); - globals->set_master_level(6); + globals->set_master_level(2); } void prepareApsResources(mpc::Mpc& mpc) @@ -230,7 +254,6 @@ TEST_CASE("Kaitai MPC2000 APS parses and rewrites ALL_PGMS", "[kaitai-aps]") REQUIRE(parsed.aps_programs()->at(1)->body()->name().substr(0, 8) == "PROGRAM2"); REQUIRE(parsed.aps_programs()->at(1)->body()->note_parameters()->at(0)->sound_index() == 1); REQUIRE(parsed.aps_programs()->at(1)->body()->note_parameters()->at(1)->sound_index() == 2); - std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); kaitai::kstream writeIo(&writeStream); parsed._set_io(&writeIo); @@ -239,6 +262,7 @@ TEST_CASE("Kaitai MPC2000 APS parses and rewrites ALL_PGMS", "[kaitai-aps]") const auto rewrittenBytes = writeStream.str(); REQUIRE(rewrittenBytes.size() == originalBytes.size()); + INFO(describeFirstByteDiff(rewrittenBytes, originalBytes)); REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); } @@ -278,6 +302,7 @@ TEST_CASE("Kaitai MPC2000 APS parses and rewrites real 2KXL ALL_PGMS", "[kaitai- const auto rewrittenBytes = writeStream.str(); REQUIRE(rewrittenBytes.size() == originalBytes.size()); + INFO(describeFirstByteDiff(rewrittenBytes, originalBytes)); REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); } @@ -321,6 +346,7 @@ TEST_CASE("Kaitai MPC2000 APS matches handwritten APS bytes", "[kaitai-aps]") const auto kaitaiBytes = writeStream.str(); REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); + INFO(describeFirstByteDiff(kaitaiBytes, std::string(handwrittenBytes.begin(), handwrittenBytes.end()))); REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); auto sampler = mpc.getSampler(); @@ -526,6 +552,18 @@ TEST_CASE("ApsLoader loads mutated note tune", "[kaitai-aps]") TEST_CASE("ApsParser reads broad mutated APS semantics", "[kaitai-aps]") { const auto apsBytes = rewriteAllPgmsApsWithMutations(applyBroadApsMutation); + INFO("raw pad_assign byte=0x" + << std::hex << std::setw(2) << std::setfill('0') + << static_cast(static_cast(apsBytes.at(75)))); + INFO("raw mix-source byte=0x" + << std::hex << std::setw(2) << std::setfill('0') + << static_cast(static_cast(apsBytes.at(76)))); + INFO("raw record/copy byte=0x" + << std::hex << std::setw(2) << std::setfill('0') + << static_cast(static_cast(apsBytes.at(77)))); + INFO("raw slider note byte=0x" + << std::hex << std::setw(2) << std::setfill('0') + << static_cast(static_cast(apsBytes.at(1757)))); mpc::file::aps::ApsParser handwrittenParser(apsBytes); auto programs = handwrittenParser.getPrograms(); @@ -584,7 +622,7 @@ TEST_CASE("ApsParser reads broad mutated APS semantics", "[kaitai-aps]") REQUIRE(globals->isRecordMixChangesEnabled()); REQUIRE(!globals->isCopyPgmMixToDrumEnabled()); REQUIRE(globals->getFxDrum() == 3); - REQUIRE(globals->getMasterLevel() == 6); + REQUIRE(globals->getMasterLevel() == 2); } TEST_CASE("ApsLoader loads broad mutated APS semantics", "[kaitai-aps]") @@ -658,7 +696,7 @@ TEST_CASE("ApsLoader loads broad mutated APS semantics", "[kaitai-aps]") REQUIRE(mixerSetup->getFxDrum() == 3); REQUIRE(mixerSetup->isIndivFxSourceDrum()); REQUIRE(mixerSetup->isStereoMixSourceDrum()); - REQUIRE(mixerSetup->getMasterLevel() == 6); + REQUIRE(mixerSetup->getMasterLevel() == 2); auto drumScreen = mpc.screens->get(); REQUIRE(drumScreen->isPadToIntSound()); From c6cc1c45899f8b13ba93023459897810a2923a4d Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sun, 21 Jun 2026 08:21:11 +0200 Subject: [PATCH 21/52] Tighten Kaitai parity coverage for PGM ALL and MID --- src/test/KaitaiAllTest.cpp | 158 +++++++++++++++++++++++++++++++++ src/test/KaitaiMidTest.cpp | 174 +++++++++++++++++++++++++++++++++++++ src/test/KaitaiPgmTest.cpp | 78 +++++++++++++++++ 3 files changed, 410 insertions(+) diff --git a/src/test/KaitaiAllTest.cpp b/src/test/KaitaiAllTest.cpp index e280742c..4e08268a 100644 --- a/src/test/KaitaiAllTest.cpp +++ b/src/test/KaitaiAllTest.cpp @@ -8,7 +8,10 @@ #include "disk/MpcFile.hpp" #include "file/all/AllParser.hpp" #include "file/all/AllSong.hpp" +#include "file/all/AllSequence.hpp" +#include "file/all/AllSequencer.hpp" #include "file/all/Defaults.hpp" +#include "file/all/Tracks.hpp" #include "file/kaitai/AllIo.hpp" #include "file/kaitai/generated/mpc2000xl_all.h" #include "lcdgui/ScreenId.hpp" @@ -75,6 +78,82 @@ std::shared_ptr installAllBytes( return newFile; } +std::vector buildBroadMutatedAllBytes() +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc2000xl/All/ALL.ALL"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + + parsed.defaults()->set_tempo(875); + parsed.defaults()->set_numerator(7); + parsed.defaults()->set_denominator(8); + + auto defaultDevices = std::make_unique>(*parsed.defaults()->devices()); + defaultDevices->at(0) = 31; + parsed.defaults()->set_devices(std::move(defaultDevices)); + + auto defaultBuses = std::make_unique>(*parsed.defaults()->buses()); + defaultBuses->at(0) = mpc2000xl_all_t::BUS_DRUM4; + parsed.defaults()->set_buses(std::move(defaultBuses)); + + std::vector usedSequenceBodies; + for (const auto& sequence : *parsed.sequences()) { + if (sequence->body() != nullptr) { + usedSequenceBodies.push_back(sequence->body()); + } + } + + auto sequence0 = usedSequenceBodies.at(0); + auto sequence0Devices = std::make_unique>(*sequence0->tracks()->device()); + sequence0Devices->at(0) = 29; + sequence0->tracks()->set_device(std::move(sequence0Devices)); + + auto sequence0Buses = std::make_unique>(*sequence0->tracks()->bus()); + sequence0Buses->at(0) = mpc2000xl_all_t::BUS_DRUM3; + sequence0->tracks()->set_bus(std::move(sequence0Buses)); + + auto sequence1 = usedSequenceBodies.at(1); + auto sequence1Devices = std::make_unique>(*sequence1->tracks()->device()); + sequence1Devices->at(0) = 5; + sequence1->tracks()->set_device(std::move(sequence1Devices)); + + auto sequence1Buses = std::make_unique>(*sequence1->tracks()->bus()); + sequence1Buses->at(0) = mpc2000xl_all_t::BUS_MIDI; + sequence1->tracks()->set_bus(std::move(sequence1Buses)); + + parsed.sequencer()->set_active_sequence(1); + parsed.sequencer()->set_active_track(3); + parsed.sequencer()->set_master_tempo(875); + + auto song0 = parsed.songs()->at(0).get(); + song0->steps()->at(0)->set_sequence_index(1); + song0->steps()->at(0)->set_repeat_count(4); + song0->steps()->at(1)->set_sequence_index(0); + song0->steps()->at(1)->set_repeat_count(5); + song0->set_loop_first_step(0); + song0->set_loop_last_step(1); + song0->set_is_loop_enabled(true); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewritten = writeStream.str(); + return std::vector(rewritten.begin(), rewritten.end()); +} + } TEST_CASE("Kaitai MPC2000 ALL parses and rewrites real 2KXL ALL", "[kaitai-all][real-2kxl]") @@ -334,3 +413,82 @@ TEST_CASE("AllLoader loads mutated default tempo and song repeat count", "[kaita REQUIRE_THAT(userScreen->getTempo(), Catch::Matchers::WithinAbs(99.9, 0.001)); REQUIRE(song1->getStep(mpc::SongStepIndex(1)).repetitionCount == 7); } + +TEST_CASE("AllParser reads broad mutated defaults, track routing, and song loop semantics", "[kaitai-all]") +{ + const auto bytes = buildBroadMutatedAllBytes(); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + mpc::file::all::AllParser handwritten(mpc, bytes); + + auto defaults = handwritten.getDefaults(); + REQUIRE(defaults->getTempo() == 875); + REQUIRE(defaults->getTimeSigNum() == 7); + REQUIRE(defaults->getTimeSigDen() == 8); + REQUIRE(defaults->getBusses().at(0) == 4); + REQUIRE(defaults->getDevices().at(0) == 31); + + auto sequences = handwritten.getAllSequences(); + REQUIRE(sequences.at(0) != nullptr); + REQUIRE(sequences.at(1) != nullptr); + REQUIRE(sequences.at(0)->tracks->getBus(0) == 3); + REQUIRE(sequences.at(0)->tracks->getDeviceIndex(0) == 29); + REQUIRE(sequences.at(1)->tracks->getBus(0) == 0); + REQUIRE(sequences.at(1)->tracks->getDeviceIndex(0) == 5); + + auto sequencer = handwritten.getSequencer(); + REQUIRE(sequencer->sequence == 1); + REQUIRE(sequencer->track == 3); + REQUIRE_THAT(sequencer->masterTempo, Catch::Matchers::WithinAbs(87.5, 0.001)); + + auto songs = handwritten.getSongs(); + REQUIRE(songs.at(0)->getSteps().at(0).first == 1); + REQUIRE(songs.at(0)->getSteps().at(0).second == 4); + REQUIRE(songs.at(0)->getSteps().at(1).first == 0); + REQUIRE(songs.at(0)->getSteps().at(1).second == 5); + REQUIRE(songs.at(0)->getLoopFirstStepIndex() == 0); + REQUIRE(songs.at(0)->getLoopLastStepIndex() == 1); + REQUIRE(songs.at(0)->isLoopEnabled()); +} + +TEST_CASE("AllLoader loads broad mutated defaults, track routing, and song loop semantics", "[kaitai-all]") +{ + const auto bytes = buildBroadMutatedAllBytes(); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + auto allFile = installAllBytes(mpc, bytes, "BROAD_MUTATED.ALL"); + REQUIRE(allFile); + + mpc::disk::AllLoader::loadEverythingFromFile(mpc, allFile.get()); + mpc.getSequencer()->getStateManager()->drainQueue(); + + auto sequencer = mpc.getSequencer(); + auto userScreen = mpc.screens->get(); + REQUIRE(userScreen); + REQUIRE_THAT(userScreen->getTempo(), Catch::Matchers::WithinAbs(87.5, 0.001)); + REQUIRE(userScreen->getBusType() == mpc::sequencer::BusType::DRUM4); + REQUIRE(userScreen->getDevice() == 31); + REQUIRE(userScreen->getTimeSig().numerator == 7); + REQUIRE(userScreen->getTimeSig().denominator == 8); + + REQUIRE(sequencer->getSelectedSequenceIndex() == 1); + REQUIRE(sequencer->getSelectedTrackIndex() == 3); + + auto sequence0 = sequencer->getSequence(0); + auto sequence1 = sequencer->getSequence(1); + REQUIRE(sequence0->getTrack(0)->getBusType() == mpc::sequencer::BusType::DRUM3); + REQUIRE(sequence0->getTrack(0)->getDeviceIndex() == 29); + REQUIRE(sequence1->getTrack(0)->getBusType() == mpc::sequencer::BusType::MIDI); + REQUIRE(sequence1->getTrack(0)->getDeviceIndex() == 5); + + auto song0 = sequencer->getSong(0); + REQUIRE(song0->getStep(mpc::SongStepIndex(0)).sequenceIndex == 1); + REQUIRE(song0->getStep(mpc::SongStepIndex(0)).repetitionCount == 4); + REQUIRE(song0->getStep(mpc::SongStepIndex(1)).sequenceIndex == 0); + REQUIRE(song0->getStep(mpc::SongStepIndex(1)).repetitionCount == 5); + REQUIRE(song0->getFirstLoopStepIndex() == mpc::SongStepIndex(0)); + REQUIRE(song0->getLastLoopStepIndex() == mpc::SongStepIndex(1)); + REQUIRE(song0->isLoopEnabled()); +} diff --git a/src/test/KaitaiMidTest.cpp b/src/test/KaitaiMidTest.cpp index 79cc00e2..62c8c081 100644 --- a/src/test/KaitaiMidTest.cpp +++ b/src/test/KaitaiMidTest.cpp @@ -75,6 +75,39 @@ std::shared_ptr installMidiResourceFile( return newFile; } +std::shared_ptr installMidiBytes( + mpc::Mpc& mpc, + const std::vector& bytes, + const std::string& fileName) +{ + auto disk = mpc.getDisk(); + auto newFile = disk->newFile(fileName); + auto mutableBytes = bytes; + newFile->setFileData(mutableBytes); + disk->initFiles(); + return newFile; +} + +void insertNote( + const std::shared_ptr& track, + int tick, + int note, + int velocity, + int duration, + int variationType, + int variationValue) +{ + mpc::sequencer::EventData eventData; + eventData.type = mpc::sequencer::EventType::NoteOn; + eventData.tick = tick; + eventData.noteNumber = mpc::NoteNumber(note); + eventData.velocity = mpc::Velocity(velocity); + eventData.duration = mpc::Duration(duration); + eventData.noteVariationType = mpc::NoteVariationType(variationType); + eventData.noteVariationValue = mpc::NoteVariationValue(variationValue); + track->acquireAndInsertEvent(eventData); +} + } TEST_CASE("Kaitai standard MIDI parses and rewrites FRUTZLE", "[kaitai-mid]") @@ -182,6 +215,147 @@ TEST_CASE("Kaitai standard MIDI matches handwritten MIDI bytes", "[kaitai-mid]") REQUIRE(note->getDuration() == 10); } +TEST_CASE("Kaitai standard MIDI roundtrips broad handwritten note semantics", "[kaitai-mid]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto sequencer = mpc.getSequencer(); + auto stateManager = sequencer->getStateManager(); + auto sequence = sequencer->getSequence(0); + sequence->init(1); + sequence->setName("MIDBROAD"); + stateManager->drainQueue(); + + auto track0 = sequence->getTrack(0); + track0->setUsedIfCurrentlyUnused(); + track0->setBusType(mpc::sequencer::BusType::DRUM3); + track0->setDeviceIndex(7); + insertNote(track0, 0, 37, 65, 13, mpc::NoteVariationTypeTune, 80); + insertNote(track0, 120, 37, 35, 49, mpc::NoteVariationTypeDecay, 26); + insertNote(track0, 240, 37, 75, 101, mpc::NoteVariationTypeAttack, 31); + insertNote(track0, 360, 37, 30, 35, mpc::NoteVariationTypeFilter, 61); + + auto track1 = sequence->getTrack(1); + track1->setUsedIfCurrentlyUnused(); + track1->setBusType(mpc::sequencer::BusType::MIDI); + track1->setDeviceIndex(2); + insertNote(track1, 60, 45, 99, 88, mpc::NoteVariationTypeTune, 64); + stateManager->drainQueue(); + + mpc::file::mid::MidiWriter handwrittenWriter(sequence.get()); + auto handwrittenStream = std::make_shared(); + handwrittenWriter.writeToOStream(handwrittenStream); + const auto handwrittenBytes = handwrittenStream->str(); + + std::stringstream parseStream( + handwrittenBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + standard_midi_file_with_running_status_t parsed(&parseIo); + parsed._read(); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto kaitaiBytes = writeStream.str(); + REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); + + auto reloadSequence = sequencer->getSequence(0); + reloadSequence->init(1); + stateManager->drainQueue(); + + auto input = std::make_shared(kaitaiBytes); + mpc::file::mid::MidiReader reader(input, reloadSequence); + REQUIRE_NOTHROW(reader.parseSequence(mpc)); + stateManager->drainQueue(); + + REQUIRE(reloadSequence->getTrack(0)->getBusType() == mpc::sequencer::BusType::DRUM3); + REQUIRE(reloadSequence->getTrack(0)->getDeviceIndex() == 7); + REQUIRE(reloadSequence->getTrack(1)->getBusType() == mpc::sequencer::BusType::MIDI); + REQUIRE(reloadSequence->getTrack(1)->getDeviceIndex() == 2); + + const std::vector expectedTrack0{ + {37, 65, 13, mpc::NoteVariationTypeTune}, + {37, 35, 49, mpc::NoteVariationTypeDecay}, + {37, 75, 101, mpc::NoteVariationTypeAttack}, + {37, 30, 35, mpc::NoteVariationTypeFilter}, + }; + const std::vector expectedTrack1{ + {45, 99, 88, mpc::NoteVariationTypeTune}, + }; + REQUIRE(collectParsedNotes(reloadSequence->getTrack(0)) == expectedTrack0); + REQUIRE(collectParsedNotes(reloadSequence->getTrack(1)) == expectedTrack1); +} + +TEST_CASE("Kaitai standard MIDI production load preserves broad handwritten note semantics", "[kaitai-mid]") +{ + mpc::Mpc sourceMpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(sourceMpc); + + auto sourceSequencer = sourceMpc.getSequencer(); + auto sourceStateManager = sourceSequencer->getStateManager(); + auto sourceSequence = sourceSequencer->getSequence(0); + sourceSequence->init(1); + sourceSequence->setName("MIDBROAD"); + sourceStateManager->drainQueue(); + + auto track0 = sourceSequence->getTrack(0); + track0->setUsedIfCurrentlyUnused(); + track0->setBusType(mpc::sequencer::BusType::DRUM3); + track0->setDeviceIndex(7); + insertNote(track0, 0, 37, 65, 13, mpc::NoteVariationTypeTune, 80); + insertNote(track0, 120, 37, 35, 49, mpc::NoteVariationTypeDecay, 26); + insertNote(track0, 240, 37, 75, 101, mpc::NoteVariationTypeAttack, 31); + insertNote(track0, 360, 37, 30, 35, mpc::NoteVariationTypeFilter, 61); + + auto track1 = sourceSequence->getTrack(1); + track1->setUsedIfCurrentlyUnused(); + track1->setBusType(mpc::sequencer::BusType::MIDI); + track1->setDeviceIndex(2); + insertNote(track1, 60, 45, 99, 88, mpc::NoteVariationTypeTune, 64); + sourceStateManager->drainQueue(); + + auto output = std::make_shared(); + mpc::file::kaitai::MidIo::save(sourceSequence, output); + const auto saved = output->str(); + std::vector bytes(saved.begin(), saved.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + auto midiFile = installMidiBytes(mpc, bytes, "BROAD.MID"); + REQUIRE(midiFile); + + const auto sequenceOrError = mpc::file::kaitai::MidIo::load(mpc, midiFile); + REQUIRE(sequenceOrError.has_value()); + + auto sequence = sequenceOrError.value(); + auto stateManager = mpc.getSequencer()->getStateManager(); + stateManager->drainQueue(); + + REQUIRE(sequence->getTrack(0)->getBusType() == mpc::sequencer::BusType::DRUM3); + REQUIRE(sequence->getTrack(0)->getDeviceIndex() == 7); + REQUIRE(sequence->getTrack(1)->getBusType() == mpc::sequencer::BusType::MIDI); + REQUIRE(sequence->getTrack(1)->getDeviceIndex() == 2); + + const std::vector expectedTrack0{ + {37, 65, 13, mpc::NoteVariationTypeTune}, + {37, 35, 49, mpc::NoteVariationTypeDecay}, + {37, 75, 101, mpc::NoteVariationTypeAttack}, + {37, 30, 35, mpc::NoteVariationTypeFilter}, + }; + const std::vector expectedTrack1{ + {45, 99, 88, mpc::NoteVariationTypeTune}, + }; + REQUIRE(collectParsedNotes(sequence->getTrack(0)) == expectedTrack0); + REQUIRE(collectParsedNotes(sequence->getTrack(1)) == expectedTrack1); +} + TEST_CASE("Kaitai standard MIDI parses and rewrites real 2KXL SEQ", "[kaitai-mid][real-2kxl]") { auto fs = cmrc::mpctest::get_filesystem(); diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp index 08b37802..08dc8a4d 100644 --- a/src/test/KaitaiPgmTest.cpp +++ b/src/test/KaitaiPgmTest.cpp @@ -12,6 +12,12 @@ #include "engine/StereoMixer.hpp" #include "file/kaitai/PgmIo.hpp" #include "file/kaitai/generated/mpc2000xl_pgm.h" +#include "file/pgmreader/PgmHeader.hpp" +#include "file/pgmreader/ProgramName.hpp" +#include "file/pgmreader/SoundNames.hpp" +#include "file/pgmreader/PgmAllNoteParameters.hpp" +#include "file/pgmreader/PRMixer.hpp" +#include "file/pgmreader/PRPads.hpp" #include "file/pgmreader/ProgramFileReader.hpp" #include "file/pgmreader/PRSlider.hpp" #include "file/pgmwriter/PgmWriter.hpp" @@ -173,6 +179,66 @@ void requireBroadMutatedProgramState( REQUIRE(slider->getFilterHighRange() == 16); } +void requireBroadMutatedProgramReaderState( + mpc::file::pgmreader::ProgramFileReader& reader) +{ + REQUIRE(reader.getHeader()->verifyMagic()); + REQUIRE(reader.getHeader()->getSoundCount() == 2); + REQUIRE(reader.getProgramName()->getProgramNameASCII() == "VMPCTESTPROGRAM1"); + REQUIRE(reader.getSampleNames()->getSampleName(0) == + std::string("sound1") + std::string(10, ' ')); + REQUIRE(reader.getSampleNames()->getSampleName(1) == + std::string("sound2") + std::string(10, ' ')); + + REQUIRE(reader.getPads()->getNote(0) == 50); + + auto allNotes = reader.getAllNoteParameters(); + REQUIRE(allNotes->getSampleSelect(0) == -1); + REQUIRE(allNotes->getSoundGenerationMode(0) == 2); + REQUIRE(allNotes->getVelocityRangeLower(0) == 1); + REQUIRE(allNotes->getVelocityRangeUpper(0) == 127); + REQUIRE(allNotes->getAlsoPlayUse1(0) == 41); + REQUIRE(allNotes->getAlsoPlayUse2(0) == 42); + REQUIRE(allNotes->getVoiceOverlapMode(0) == mpc::sampler::VoiceOverlapMode::NOTE_OFF); + REQUIRE(allNotes->getMuteAssign1(0) == 43); + REQUIRE(allNotes->getMuteAssign2(0) == 44); + REQUIRE(allNotes->getTune(0) == -120); + REQUIRE(allNotes->getAttack(0) == 99); + REQUIRE(allNotes->getDecay(0) == 98); + REQUIRE(allNotes->getDecayMode(0) == 1); + REQUIRE(allNotes->getCutoff(0) == 17); + REQUIRE(allNotes->getResonance(0) == 18); + REQUIRE(allNotes->getVelEnvToFiltAtt(0) == 19); + REQUIRE(allNotes->getVelEnvToFiltDec(0) == 20); + REQUIRE(allNotes->getVelEnvToFiltAmt(0) == 21); + REQUIRE(allNotes->getVelocityToLevel(0) == 22); + REQUIRE(allNotes->getVelocityToAttack(0) == 23); + REQUIRE(allNotes->getVelocityToStart(0) == 24); + REQUIRE(allNotes->getVelocityToCutoff(0) == 25); + REQUIRE(allNotes->getSliderParameter(0) == 3); + REQUIRE(allNotes->getVelocityToPitch(0) == 26); + + auto mixer = reader.getMixer(); + REQUIRE(mixer->getEffectsOutput(0) == 4); + REQUIRE(mixer->getVolume(0) == 12); + REQUIRE(mixer->getPan(0) == 13); + REQUIRE(mixer->getVolumeIndividual(0) == 14); + REQUIRE(mixer->getOutput(0) == 2); + REQUIRE(mixer->getEffectsSendLevel(0) == 15); + + auto slider = reader.getSlider(); + REQUIRE(slider->getMidiNoteAssign() == 52); + REQUIRE(slider->getTuneLow() == -119); + REQUIRE(slider->getTuneHigh() == 118); + REQUIRE(slider->getDecayLow() == 11); + REQUIRE(slider->getDecayHigh() == 12); + REQUIRE(slider->getAttackLow() == 13); + REQUIRE(slider->getAttackHigh() == 14); + REQUIRE(slider->getFilterLow() == -15); + REQUIRE(slider->getFilterHigh() == 16); + REQUIRE(slider->getProgramChange() == 126); +} + void prepareProgramLoadingResources(mpc::Mpc& mpc) { auto disk = mpc.getDisk(); @@ -679,6 +745,18 @@ TEST_CASE("ProgramFileReader reads upper-bound MIDI program change byte", "[kait REQUIRE(reader.getSlider()->getProgramChange() == 127); } +TEST_CASE("ProgramFileReader reads broad mutated program semantics", "[kaitai-pgm]") +{ + const auto programBytes = rewriteProgram1WithMutations(applyBroadProgramMutation); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); + auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); + + mpc::file::pgmreader::ProgramFileReader reader(pgmFile); + requireBroadMutatedProgramReaderState(reader); +} + TEST_CASE("PgmFileToProgramConverter loads mutated note tune", "[kaitai-pgm]") { auto fs = cmrc::mpctest::get_filesystem(); From e9bdcffd0224f9d750312bcc124399d215753283 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sun, 21 Jun 2026 10:26:21 +0200 Subject: [PATCH 22/52] Remove handwritten APS implementation --- src/main/AutoSave.cpp | 44 +- src/main/disk/AbstractDisk.cpp | 2 - src/main/disk/ApsLoader.cpp | 362 +--------- src/main/disk/ApsLoader.hpp | 17 - src/main/file/aps/ApsAssignTable.cpp | 31 - src/main/file/aps/ApsAssignTable.hpp | 22 - src/main/file/aps/ApsDrumConfiguration.cpp | 56 -- src/main/file/aps/ApsDrumConfiguration.hpp | 31 - src/main/file/aps/ApsGlobalParameters.cpp | 131 ---- src/main/file/aps/ApsGlobalParameters.hpp | 47 -- src/main/file/aps/ApsHeader.cpp | 46 -- src/main/file/aps/ApsHeader.hpp | 24 - src/main/file/aps/ApsMixer.cpp | 95 --- src/main/file/aps/ApsMixer.hpp | 44 -- src/main/file/aps/ApsName.cpp | 49 -- src/main/file/aps/ApsName.hpp | 25 - src/main/file/aps/ApsNoteParameters.cpp | 197 ------ src/main/file/aps/ApsNoteParameters.hpp | 73 -- src/main/file/aps/ApsParser.cpp | 228 ------- src/main/file/aps/ApsParser.hpp | 74 -- src/main/file/aps/ApsProgram.cpp | 201 ------ src/main/file/aps/ApsProgram.hpp | 75 --- src/main/file/aps/ApsSlider.cpp | 94 --- src/main/file/aps/ApsSlider.hpp | 48 -- src/main/file/aps/ApsSoundNames.cpp | 64 -- src/main/file/aps/ApsSoundNames.hpp | 27 - src/main/file/kaitai/ApsIo.cpp | 636 +++++++++++++++++- src/main/file/kaitai/ApsIo.hpp | 1 + src/main/file/kaitai/PgmIo.cpp | 409 ++++++++++- .../file/kaitai/generated/mpc2000xl_aps.cpp | 15 +- .../file/kaitai/generated/mpc2000xl_aps.h | 9 +- src/test/ApsParserTest.cpp | 68 -- src/test/KaitaiApsTest.cpp | 214 +++--- 33 files changed, 1182 insertions(+), 2277 deletions(-) delete mode 100644 src/main/file/aps/ApsAssignTable.cpp delete mode 100644 src/main/file/aps/ApsAssignTable.hpp delete mode 100644 src/main/file/aps/ApsDrumConfiguration.cpp delete mode 100644 src/main/file/aps/ApsDrumConfiguration.hpp delete mode 100644 src/main/file/aps/ApsGlobalParameters.cpp delete mode 100644 src/main/file/aps/ApsGlobalParameters.hpp delete mode 100644 src/main/file/aps/ApsHeader.cpp delete mode 100644 src/main/file/aps/ApsHeader.hpp delete mode 100644 src/main/file/aps/ApsMixer.cpp delete mode 100644 src/main/file/aps/ApsMixer.hpp delete mode 100644 src/main/file/aps/ApsName.cpp delete mode 100644 src/main/file/aps/ApsName.hpp delete mode 100644 src/main/file/aps/ApsNoteParameters.cpp delete mode 100644 src/main/file/aps/ApsNoteParameters.hpp delete mode 100644 src/main/file/aps/ApsParser.cpp delete mode 100644 src/main/file/aps/ApsParser.hpp delete mode 100644 src/main/file/aps/ApsProgram.cpp delete mode 100644 src/main/file/aps/ApsProgram.hpp delete mode 100644 src/main/file/aps/ApsSlider.cpp delete mode 100644 src/main/file/aps/ApsSlider.hpp delete mode 100644 src/main/file/aps/ApsSoundNames.cpp delete mode 100644 src/main/file/aps/ApsSoundNames.hpp delete mode 100644 src/test/ApsParserTest.cpp diff --git a/src/main/AutoSave.cpp b/src/main/AutoSave.cpp index 351d29a6..9f44971b 100644 --- a/src/main/AutoSave.cpp +++ b/src/main/AutoSave.cpp @@ -10,8 +10,8 @@ #include "disk/AbstractDisk.hpp" #include "disk/ApsLoader.hpp" #include "FileIoPolicy.hpp" -#include "file/aps/ApsParser.hpp" #include "file/ByteUtil.hpp" +#include "file/kaitai/ApsIo.hpp" #include "file/sndreader/SndReader.hpp" #include "file/sndwriter/SndWriter.hpp" #include "lcdgui/screens/VmpcAutoSaveScreen.hpp" @@ -42,7 +42,6 @@ using namespace mpc; using namespace mpc::file_io; using namespace mpc::file; using namespace mpc::file::all; -using namespace mpc::file::aps; using namespace mpc::file::sndwriter; using namespace mpc::file::sndreader; using namespace mpc::lcdgui; @@ -52,6 +51,17 @@ using namespace mpc::lcdgui::screens::dialog2; namespace { +constexpr size_t kApsHeaderLength = 4; +constexpr size_t kApsSoundNameLength = 17; +constexpr size_t kApsPadLength1 = 2; +constexpr size_t kApsNameLength = 17; +constexpr size_t kApsParametersLength = 8; +constexpr size_t kApsMasterTableLength = 64; +constexpr size_t kApsPadLength2 = 7; +constexpr size_t kApsMixerLength = 384; +constexpr size_t kApsDrumConfigLength = 9; +constexpr size_t kApsDrumPadLength = 3; + bool rangeFits(const size_t totalSize, const size_t offset, const size_t length) { return offset <= totalSize && length <= totalSize - offset; @@ -59,7 +69,7 @@ bool rangeFits(const size_t totalSize, const size_t offset, const size_t length) bool isValidAutoSaveApsData(const std::vector &data) { - if (!rangeFits(data.size(), ApsParser::HEADER_OFFSET, ApsParser::HEADER_LENGTH)) + if (!rangeFits(data.size(), 0, kApsHeaderLength)) { return false; } @@ -78,15 +88,15 @@ bool isValidAutoSaveApsData(const std::vector &data) return false; } - const size_t minSize = static_cast(ApsParser::HEADER_LENGTH) + + const size_t minSize = kApsHeaderLength + static_cast(soundCount) * - ApsParser::SOUND_NAME_LENGTH + - ApsParser::PAD_LENGTH1 + ApsParser::APS_NAME_LENGTH + - ApsParser::PARAMETERS_LENGTH + ApsParser::TABLE_LENGTH + - ApsParser::PAD_LENGTH2 + - 4u * (ApsParser::MIXER_LENGTH + - ApsParser::DRUM_CONFIG_LENGTH + - ApsParser::DRUM_PAD_LENGTH); + kApsSoundNameLength + + kApsPadLength1 + kApsNameLength + + kApsParametersLength + kApsMasterTableLength + + kApsPadLength2 + + 4u * (kApsMixerLength + + kApsDrumConfigLength + + kApsDrumPadLength); return data.size() >= minSize; } @@ -284,15 +294,10 @@ void AutoSave::restoreAutoSavedState(Mpc &mpc, { throw std::invalid_argument("invalid APS autosave data"); } - ApsParser apsParser(data); constexpr bool withoutSounds = true; - // Regardless of whether the outer context is headless, - // we want the ApsLoader to always operate in headless - // mode so it doesn't spawn popups. We manage popups - // ourselves here in AutoSave. constexpr bool apsLoadingHeadless = true; - disk::ApsLoader::loadFromParsedAps( - apsParser, mpc, withoutSounds, apsLoadingHeadless); + file::kaitai::ApsIo::loadBytes( + mpc, data, withoutSounds, apsLoadingHeadless); } else if (f == "ALL.ALL") { @@ -607,8 +612,7 @@ void AutoSave::storeAutoSavedState( } { - ApsParser apsParser(mpc, "stateinfo"); - if (!writeRequired("APS.APS", apsParser.getBytes())) + if (!writeRequired("APS.APS", file::kaitai::ApsIo::save(mpc, "stateinfo"))) { layeredScreen->closeCurrentScreen(); return; diff --git a/src/main/disk/AbstractDisk.cpp b/src/main/disk/AbstractDisk.cpp index 035107be..653769fd 100644 --- a/src/main/disk/AbstractDisk.cpp +++ b/src/main/disk/AbstractDisk.cpp @@ -13,7 +13,6 @@ #include "file/pgmwriter/PgmWriter.hpp" #include "file/sndwriter/SndWriter.hpp" #include "file/sndreader/SndReader.hpp" -#include "file/aps/ApsParser.hpp" #include "file/all/AllParser.hpp" #include "file/kaitai/SndIo.hpp" #include "file/kaitai/PgmIo.hpp" @@ -49,7 +48,6 @@ using namespace mpc::file::sndwriter; using namespace mpc::file::sndreader; using namespace mpc::file::mid; using namespace mpc::file::pgmwriter; -using namespace mpc::file::aps; using namespace mpc::file::all; using namespace mpc::lcdgui; diff --git a/src/main/disk/ApsLoader.cpp b/src/main/disk/ApsLoader.cpp index 58b96532..0a742fd9 100644 --- a/src/main/disk/ApsLoader.cpp +++ b/src/main/disk/ApsLoader.cpp @@ -1,366 +1,12 @@ #include "ApsLoader.hpp" -#include "lcdgui/screens/PgmAssignScreen.hpp" -#include "sampler/Pad.hpp" #include "Mpc.hpp" -#include "disk/StdDisk.hpp" #include "disk/MpcFile.hpp" -#include "disk/SoundLoader.hpp" -#include "file/aps/ApsNoteParameters.hpp" -#include "file/aps/ApsParser.hpp" #include "file/kaitai/ApsIo.hpp" -#include "file/aps/ApsSlider.hpp" -#include "lcdgui/screens/DrumScreen.hpp" -#include "lcdgui/screens/MixerSetupScreen.hpp" -#include "lcdgui/screens/window/CantFindFileScreen.hpp" - -#include "StrUtil.hpp" - -#include - -#include "Logger.hpp" -#include "engine/EngineHost.hpp" -#include "engine/IndivFxMixer.hpp" -#include "engine/StereoMixer.hpp" -#include "performance/PerformanceManager.hpp" -#include "sampler/Sampler.hpp" -#include "sequencer/Sequencer.hpp" - -using namespace mpc::lcdgui; -using namespace mpc::lcdgui::screens; -using namespace mpc::lcdgui::screens::window; -using namespace mpc::lcdgui::screens::dialog2; -using namespace mpc::disk; -using namespace mpc::sampler; -using namespace mpc::file::aps; - -void ApsLoader::load(Mpc &mpc, const std::shared_ptr &file, - const bool headless) -{ - file::kaitai::ApsIo::load(mpc, file, headless); -} - -void ApsLoader::loadFromParsedAps(ApsParser &apsParser, Mpc &mpc, - bool withoutSounds, bool headless) -{ - auto sampler = mpc.getSampler(); - auto disk = mpc.getDisk(); - - // These remain empty when loading the APS without sounds. - // It is trusted that the caller of this method validates - // sound indices to make sure they actually exist. This - // allows loading APS and sounds in any order. - std::vector unavailableSoundIndices; - std::map finalSoundIndices; - - if (!withoutSounds) - { - int skipCount = 0; - sampler->deleteAllSamples(); - - for (int i = 0; i < apsParser.getSoundNames().size(); i++) - { - auto ext = "snd"; - std::shared_ptr soundFile; - std::string soundFileName = - StrUtil::replaceAll(apsParser.getSoundNames()[i], ' ', ""); - - for (auto &f : disk->getAllFiles()) - { - if (StrUtil::eqIgnoreCase( - StrUtil::replaceAll(f->getName(), ' ', ""), - soundFileName + ".SND")) - { - soundFile = f; - break; - } - } - - if (!soundFile || !soundFile->exists()) - { - for (auto &f : disk->getAllFiles()) - { - if (StrUtil::eqIgnoreCase( - StrUtil::replaceAll(f->getName(), ' ', ""), - soundFileName + ".WAV")) - { - soundFile = f; - ext = "wav"; - break; - } - } - } - - if (!soundFile || !soundFile->exists()) - { - unavailableSoundIndices.push_back(i); - - skipCount++; - - if (!headless) - { - handleSoundNotFound(mpc, soundFileName); - } - - continue; - } - - finalSoundIndices[i] = i - skipCount; - - loadSound(mpc, soundFileName, ext, soundFile, headless); - } - } - - for (auto &apsProgram : apsParser.getPrograms()) - { - sampler->getProgram(apsProgram->index)->setName(apsProgram->getName()); - const auto slider = sampler->getProgram(apsProgram->index)->getSlider(); - slider->setAssignNote(DrumNoteNumber(apsProgram->getSlider()->getNote())); - slider->setTuneLowRange(apsProgram->getSlider()->getTuneLow()); - slider->setTuneHighRange(apsProgram->getSlider()->getTuneHigh()); - slider->setDecayLowRange(apsProgram->getSlider()->getDecayLow()); - slider->setDecayHighRange(apsProgram->getSlider()->getDecayHigh()); - slider->setAttackLowRange(apsProgram->getSlider()->getAttackLow()); - slider->setAttackHighRange(apsProgram->getSlider()->getAttackHigh()); - slider->setFilterLowRange(apsProgram->getSlider()->getFilterLow()); - slider->setFilterHighRange(apsProgram->getSlider()->getFilterHigh()); - - performance::UpdateProgramBulk msg; - auto &perfProgram = msg.program; - msg.programIndex = ProgramIndex(apsProgram->index); - perfProgram.used = true; - - auto assignTable = apsProgram->getAssignTable()->get(); - - for (int noteIndex = 0; noteIndex < 64; noteIndex++) - { - perfProgram.pads[noteIndex].note = - DrumNoteNumber(assignTable[noteIndex]); - - auto sourceStereoMixerChannel = - apsProgram->getStereoMixerChannel(noteIndex); - auto sourceIndivFxMixerChannel = - apsProgram->getIndivFxMixerChannel(noteIndex); - - auto &destNoteParams = perfProgram.noteParameters[noteIndex]; - destNoteParams.stereoMixer = sourceStereoMixerChannel; - destNoteParams.indivFxMixer = sourceIndivFxMixerChannel; - - auto srcNoteParams = apsProgram->getNoteParameters(noteIndex); - - auto soundIndex = srcNoteParams->getSoundIndex(); - - if (find(begin(unavailableSoundIndices), - end(unavailableSoundIndices), - soundIndex) != end(unavailableSoundIndices)) - { - soundIndex = -1; - } - - if (soundIndex != -1 && - finalSoundIndices.find(soundIndex) != end(finalSoundIndices)) - { - soundIndex = finalSoundIndices[soundIndex]; - } - - destNoteParams.soundIndex = soundIndex; - destNoteParams.tune = srcNoteParams->getTune(); - destNoteParams.voiceOverlapMode = - srcNoteParams->getVoiceOverlapMode(); - - destNoteParams.decayMode = srcNoteParams->getDecayMode(); - destNoteParams.attack = srcNoteParams->getAttack(); - destNoteParams.decay = srcNoteParams->getDecay(); - - destNoteParams.filterAttack = - srcNoteParams->getVelocityToFilterAttack(); - destNoteParams.filterDecay = - srcNoteParams->getVelocityToFilterDecay(); - destNoteParams.filterEnvelopeAmount = - srcNoteParams->getVelocityToFilterAmount(); - - destNoteParams.filterFrequency = - srcNoteParams->getCutoffFrequency(); - destNoteParams.filterResonance = srcNoteParams->getResonance(); - - destNoteParams.muteAssignA = - DrumNoteNumber(srcNoteParams->getMute1()); - destNoteParams.muteAssignB = - DrumNoteNumber(srcNoteParams->getMute2()); - - destNoteParams.optionalNoteA = - DrumNoteNumber(srcNoteParams->getAlsoPlay1()); - destNoteParams.optionalNoteB = - DrumNoteNumber(srcNoteParams->getAlsoPlay2()); - - destNoteParams.sliderParameterNumber = - srcNoteParams->getSliderParameter(); - destNoteParams.soundGenerationMode = - srcNoteParams->getSoundGenerationMode(); - - destNoteParams.velocityToStart = - srcNoteParams->getVelocityToStart(); - destNoteParams.velocityToAttack = - srcNoteParams->getVelocityToAttack(); - destNoteParams.velocityToFilterFrequency = - srcNoteParams->getVelocityToFilterFrequency(); - - destNoteParams.velocityToLevel = - srcNoteParams->getVelocityToLevel(); - - destNoteParams.velocityRangeLower = - srcNoteParams->getVelocityRangeLower(); - destNoteParams.velocityRangeUpper = - srcNoteParams->getVelocityRangeUpper(); - - destNoteParams.velocityToPitch = - srcNoteParams->getVelocityToPitch(); - } - - perfProgram.slider.attackHighRange = - apsProgram->getSlider()->getAttackHigh(); - perfProgram.slider.attackLowRange = - apsProgram->getSlider()->getAttackLow(); - perfProgram.slider.decayHighRange = - apsProgram->getSlider()->getDecayHigh(); - perfProgram.slider.decayLowRange = - apsProgram->getSlider()->getDecayLow(); - perfProgram.slider.filterHighRange = - apsProgram->getSlider()->getFilterHigh(); - perfProgram.slider.filterLowRange = - apsProgram->getSlider()->getFilterLow(); - perfProgram.slider.assignNote = - DrumNoteNumber(apsProgram->getSlider()->getNote()); - perfProgram.slider.tuneHighRange = - apsProgram->getSlider()->getTuneHigh(); - perfProgram.slider.tuneLowRange = apsProgram->getSlider()->getTuneLow(); - perfProgram.midiProgramChange = - apsProgram->getSlider()->getProgramChange() + 1; - - mpc.getPerformanceManager().lock()->enqueue( - performance::PerformanceMessage{std::move(msg)}); - } - - for (int i = 0; i < Mpc2000XlSpecs::DRUM_BUS_COUNT; i++) - { - auto m = apsParser.getDrumMixers()[i]; - - performance::Drum perfDrum; - perfDrum.drumBusIndex = DrumBusIndex(i); - - for (int noteIndex = 0; noteIndex < 64; noteIndex++) - { - perfDrum.stereoMixers[noteIndex] = - m->getStereoMixerChannel(noteIndex); - perfDrum.indivFxMixers[noteIndex] = - m->getIndivFxMixerChannel(noteIndex); - } - - auto pgm = apsParser.getDrumConfiguration(i)->getProgramIndex(); - perfDrum.programIndex = ProgramIndex(pgm); - perfDrum.receivePgmChangeEnabled = - apsParser.getDrumConfiguration(i)->isReceivePgmChangeEnabled(); - perfDrum.receiveMidiVolumeEnabled = - apsParser.getDrumConfiguration(i)->isReceiveMidiVolumeEnabled(); - - mpc.getPerformanceManager().lock()->enqueue( - performance::UpdateDrumBulk{perfDrum}); - } - - auto mixerSetupScreen = mpc.screens->get(); - - auto globals = apsParser.getGlobalParameters(); - - mixerSetupScreen->setRecordMixChangesEnabled( - globals->isRecordMixChangesEnabled()); - mixerSetupScreen->setCopyPgmMixToDrumEnabled( - globals->isCopyPgmMixToDrumEnabled()); - mixerSetupScreen->setFxDrum(globals->getFxDrum()); - mixerSetupScreen->setIndivFxSourceDrum(globals->isIndivFxSourceDrum()); - mixerSetupScreen->setStereoMixSourceDrum(globals->isStereoMixSourceDrum()); - - auto drumScreen = mpc.screens->get(); - drumScreen->setPadToIntSound(globals->isPadToIntSoundEnabled()); - mixerSetupScreen->setMasterLevel(globals->getMasterLevel()); - - auto pgmAssignScreen = mpc.screens->get(); - std::vector masterPadAssign; - masterPadAssign.reserve(64); - for (const auto note : apsParser.getMasterAssignTable()) - { - masterPadAssign.emplace_back(note); - } - mpc.getSampler()->setMasterPadAssign(masterPadAssign); - pgmAssignScreen->setPadAssign(globals->isPadAssignMaster()); -} - -void ApsLoader::loadSound(Mpc &mpc, const std::string &soundFileName, - const std::string &ext, - const std::shared_ptr &soundFile, - const bool headless) +void mpc::disk::ApsLoader::load(mpc::Mpc &mpc, + const std::shared_ptr &file, + const bool headless) { - constexpr auto replace = false; - SoundLoader soundLoader(mpc, replace); - - if (!headless) - { - showPopup(mpc, soundFileName, ext); - } - - SoundLoaderResult result; - constexpr bool shouldBeConverted = false; - const auto sound = mpc.getSampler()->addSound(); - - if (!sound) - { - return; - } - - soundLoader.loadSound(soundFile, result, sound, shouldBeConverted); - - if (!result.success) - { - mpc.getSampler()->deleteSound(sound); - } -} - -void ApsLoader::showPopup(Mpc &mpc, const std::string &name, - const std::string &ext) -{ - const std::string msg = - "Loading " + - StrUtil::toUpper(StrUtil::padRight(name, " ", 16) + "." + ext); - - const auto ls = mpc.getLayeredScreen(); - - ls->postToUiThread(utils::Task( - [ls, msg] - { - ls->showPopup(msg); - })); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); -} - -void ApsLoader::handleSoundNotFound(Mpc &mpc, const std::string &soundFileName) -{ - const auto cantFindFileScreen = - mpc.screens->get(); - - if (const auto skipAll = cantFindFileScreen->skipAll; !skipAll) - { - const auto ls = mpc.getLayeredScreen(); - ls->postToUiThread(utils::Task( - [ls, cantFindFileScreen, soundFileName] - { - cantFindFileScreen->waitingForUser = true; - cantFindFileScreen->fileName = soundFileName; - ls->openScreenById(ScreenId::CantFindFileScreen); - })); - - while (cantFindFileScreen->waitingForUser) - { - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } - } + mpc::file::kaitai::ApsIo::load(mpc, file, headless); } diff --git a/src/main/disk/ApsLoader.hpp b/src/main/disk/ApsLoader.hpp index 772908c7..24ecc222 100644 --- a/src/main/disk/ApsLoader.hpp +++ b/src/main/disk/ApsLoader.hpp @@ -15,11 +15,6 @@ namespace mpc::disk { class MpcFile; } -namespace mpc::file::aps -{ - class ApsParser; -} - namespace mpc::disk { class ApsLoader @@ -27,17 +22,5 @@ namespace mpc::disk public: static void load(Mpc &, const std::shared_ptr &, bool headless); - static void loadFromParsedAps(file::aps::ApsParser &, Mpc &, - bool withoutSounds, bool headless); - - private: - static void handleSoundNotFound(Mpc &, - const std::string &soundFileName); - static void loadSound(Mpc &, const std::string &soundFileName, - const std::string &ext, - const std::shared_ptr &soundFile, - bool headless = false); - static void showPopup(Mpc &, const std::string &name, - const std::string &ext); }; } // namespace mpc::disk diff --git a/src/main/file/aps/ApsAssignTable.cpp b/src/main/file/aps/ApsAssignTable.cpp deleted file mode 100644 index eeb1ec09..00000000 --- a/src/main/file/aps/ApsAssignTable.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "file/aps/ApsAssignTable.hpp" - -using namespace mpc::file::aps; - -ApsAssignTable::ApsAssignTable(const std::vector &loadBytes) -{ - assignTable = std::vector(64); - for (int i = 0; i < 64; i++) - { - assignTable[i] = loadBytes[i]; - } -} - -ApsAssignTable::ApsAssignTable(const std::vector &assignTable) -{ - saveBytes = std::vector(Mpc2000XlSpecs::PROGRAM_PAD_COUNT); - for (int i = 0; i < Mpc2000XlSpecs::PROGRAM_PAD_COUNT; i++) - { - saveBytes[i] = assignTable[i]; - } -} - -std::vector ApsAssignTable::get() -{ - return assignTable; -} - -std::vector ApsAssignTable::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsAssignTable.hpp b/src/main/file/aps/ApsAssignTable.hpp deleted file mode 100644 index 58b9364f..00000000 --- a/src/main/file/aps/ApsAssignTable.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "IntTypes.hpp" - -#include - -namespace mpc::file::aps -{ - class ApsAssignTable - { - - public: - std::vector assignTable; - std::vector saveBytes; - - std::vector get(); - std::vector getBytes(); - - explicit ApsAssignTable(const std::vector &loadBytes); - ApsAssignTable(const std::vector &assignTable); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsDrumConfiguration.cpp b/src/main/file/aps/ApsDrumConfiguration.cpp deleted file mode 100644 index 6f7b5005..00000000 --- a/src/main/file/aps/ApsDrumConfiguration.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "file/aps/ApsDrumConfiguration.hpp" - -#include "file/BitUtil.hpp" - -using namespace mpc::file::aps; - -ApsDrumConfiguration::ApsDrumConfiguration(const std::vector &loadBytes) -{ - programIndex = loadBytes[5]; - receivePgmChangeEnabled = BitUtil::getBits(loadBytes[2])[7] == '1'; - receiveMidiVolumeEnabled = BitUtil::getBits(loadBytes[3])[7] == '1'; -} - -ApsDrumConfiguration::ApsDrumConfiguration(int program, bool recPgmChange, - bool recMidiVolume) -{ - saveBytes = std::vector(12); - for (int i = 0; i < 9; i++) - { - saveBytes[i] = TEMPLATE[i]; - } - - for (int i = 0; i < 3; i++) - { - saveBytes[i + 9] = PADDING[i]; - } - - saveBytes[1] = program; - saveBytes[2] = BitUtil::setBits(1, saveBytes[2], recPgmChange); - saveBytes[3] = BitUtil::setBits(1, saveBytes[3], recMidiVolume); - saveBytes[5] = program; -} - -std::vector ApsDrumConfiguration::TEMPLATE = - std::vector{0, 0, 1, 1, 127, 0, 1, 1, 127}; -std::vector ApsDrumConfiguration::PADDING = std::vector{64, 0, 6}; - -int ApsDrumConfiguration::getProgramIndex() const -{ - return programIndex; -} - -bool ApsDrumConfiguration::isReceivePgmChangeEnabled() const -{ - return receivePgmChangeEnabled; -} - -bool ApsDrumConfiguration::isReceiveMidiVolumeEnabled() const -{ - return receiveMidiVolumeEnabled; -} - -std::vector ApsDrumConfiguration::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsDrumConfiguration.hpp b/src/main/file/aps/ApsDrumConfiguration.hpp deleted file mode 100644 index 5af0b787..00000000 --- a/src/main/file/aps/ApsDrumConfiguration.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -namespace mpc::file::aps -{ - class ApsDrumConfiguration - { - - public: - int programIndex; - bool receivePgmChangeEnabled; - bool receiveMidiVolumeEnabled; - std::vector saveBytes; - - private: - static std::vector TEMPLATE; - static std::vector PADDING; - - public: - int getProgramIndex() const; - bool isReceivePgmChangeEnabled() const; - bool isReceiveMidiVolumeEnabled() const; - - std::vector getBytes(); - - ApsDrumConfiguration(const std::vector &loadBytes); - ApsDrumConfiguration(int program, bool recPgmChange, - bool recMidiVolume); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsGlobalParameters.cpp b/src/main/file/aps/ApsGlobalParameters.cpp deleted file mode 100644 index 787e34d8..00000000 --- a/src/main/file/aps/ApsGlobalParameters.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "ApsGlobalParameters.hpp" - -#include "Mpc.hpp" -#include "file/aps/ApsParser.hpp" - -#include "lcdgui/screens/MixerSetupScreen.hpp" -#include "lcdgui/screens/DrumScreen.hpp" -#include "lcdgui/screens/PgmAssignScreen.hpp" - -#include "file/BitUtil.hpp" -#include "sampler/Sampler.hpp" - -using namespace mpc::lcdgui; -using namespace mpc::lcdgui::screens; -using namespace mpc::file::aps; - -ApsGlobalParameters::ApsGlobalParameters(const std::vector &loadBytes) -{ - padToInternalSound = BitUtil::getBits(loadBytes[0])[7] == '1'; - padAssignMaster = BitUtil::getBits(loadBytes[1])[7] == '1'; - stereoMixSourceDrum = BitUtil::getBits(loadBytes[2])[7] == '1'; - indivFxSourceDrum = BitUtil::getBits(loadBytes[2])[6] == '1'; - copyPgmMixToDrum = BitUtil::getBits(loadBytes[3])[7] == '1'; - recordMixChanges = BitUtil::getBits(loadBytes[3])[3] == '1'; - fxDrum = readFxDrum(loadBytes[4]); - masterLevel = loadBytes[6]; -} - -ApsGlobalParameters::ApsGlobalParameters(Mpc &mpc) -{ - saveBytes = std::vector(ApsParser::PARAMETERS_LENGTH); - - for (int i = 0; i < saveBytes.size(); i++) - { - if (mpc.getSampler()->getSoundCount() == 0) - { - saveBytes[i] = TEMPLATE_NO_SOUNDS[i]; - } - else - { - saveBytes[i] = TEMPLATE_SOUNDS[i]; - } - } - - auto drumScreen = mpc.screens->get(); - - auto const padToInternalSoundVal = drumScreen->isPadToIntSound(); - - auto pgmAssignScreen = mpc.screens->get(); - auto const padAssignMasterVal = pgmAssignScreen->isPadAssignMaster(); - - auto mixerSetupScreen = mpc.screens->get(); - auto const stereoMixSourceDrumVal = - mixerSetupScreen->isStereoMixSourceDrum(); - auto const indivFxSourceDrumVal = mixerSetupScreen->isIndivFxSourceDrum(); - auto const copyPgmMixToDrumVal = - mixerSetupScreen->isCopyPgmMixToDrumEnabled(); - auto const recordMixChangesVal = - mixerSetupScreen->isRecordMixChangesEnabled(); - auto const masterLevelVal = mixerSetupScreen->getMasterLevel(); - auto const fxDrumVal = mixerSetupScreen->getFxDrum(); - - saveBytes[0] = BitUtil::setBits(1, saveBytes[0], padToInternalSoundVal); - saveBytes[1] = BitUtil::setBits(1, saveBytes[1], padAssignMasterVal); - saveBytes[2] = BitUtil::setBits(1, saveBytes[2], stereoMixSourceDrumVal); - saveBytes[2] = BitUtil::setBits(2, saveBytes[2], indivFxSourceDrumVal); - saveBytes[3] = BitUtil::setBits(1, saveBytes[3], copyPgmMixToDrumVal); - saveBytes[3] = BitUtil::setBits(16, saveBytes[3], recordMixChangesVal); - saveBytes[4] = fxDrumVal; - saveBytes[6] = masterLevelVal; -} - -std::vector ApsGlobalParameters::TEMPLATE_NO_SOUNDS = { - 127, (char)(254 & 0xff), 124, (char)(238 & 0xff), 0, 0, 0, 64}; -std::vector ApsGlobalParameters::TEMPLATE_SOUNDS = { - '\x03', '\x38', '\x00', '\xa1', 0, 0, 0, 64}; - -int ApsGlobalParameters::readFxDrum(char b) const -{ - for (int i = 2; i < 8; i++) - { - b &= ~(1 << i); - } - - return b; -} - -int ApsGlobalParameters::getFxDrum() const -{ - return fxDrum; -} - -bool ApsGlobalParameters::isPadToIntSoundEnabled() const -{ - return padToInternalSound; -} - -bool ApsGlobalParameters::isPadAssignMaster() const -{ - return padAssignMaster; -} - -bool ApsGlobalParameters::isStereoMixSourceDrum() const -{ - return stereoMixSourceDrum; -} - -bool ApsGlobalParameters::isIndivFxSourceDrum() const -{ - return indivFxSourceDrum; -} - -bool ApsGlobalParameters::isCopyPgmMixToDrumEnabled() const -{ - return copyPgmMixToDrum; -} - -bool ApsGlobalParameters::isRecordMixChangesEnabled() const -{ - return recordMixChanges; -} - -int ApsGlobalParameters::getMasterLevel() const -{ - return masterLevel; -} - -std::vector ApsGlobalParameters::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsGlobalParameters.hpp b/src/main/file/aps/ApsGlobalParameters.hpp deleted file mode 100644 index 4998076c..00000000 --- a/src/main/file/aps/ApsGlobalParameters.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::file::aps -{ - class ApsGlobalParameters - { - bool padToInternalSound; - bool padAssignMaster; - bool stereoMixSourceDrum; - bool indivFxSourceDrum; - bool copyPgmMixToDrum; - bool recordMixChanges; - int masterLevel; - int fxDrum; - - static std::vector TEMPLATE_NO_SOUNDS; - static std::vector TEMPLATE_SOUNDS; - - public: - std::vector saveBytes{}; - - private: - int readFxDrum(char b) const; - - public: - int getFxDrum() const; - bool isPadToIntSoundEnabled() const; - bool isPadAssignMaster() const; - bool isStereoMixSourceDrum() const; - bool isIndivFxSourceDrum() const; - bool isCopyPgmMixToDrumEnabled() const; - bool isRecordMixChangesEnabled() const; - int getMasterLevel() const; - - std::vector getBytes(); - - ApsGlobalParameters(const std::vector &loadBytes); - ApsGlobalParameters(Mpc &mpc); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsHeader.cpp b/src/main/file/aps/ApsHeader.cpp deleted file mode 100644 index 48f804e0..00000000 --- a/src/main/file/aps/ApsHeader.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "file/aps/ApsHeader.hpp" - -#include "file/ByteUtil.hpp" -#include "MpcSpecs.hpp" - -#include - -using namespace mpc::file::aps; - -ApsHeader::ApsHeader(const std::vector &loadBytes) -{ - valid = loadBytes[0] == APS_HEADER_MAGIC[0] && - loadBytes[1] == APS_HEADER_MAGIC[1]; - - soundCount = ByteUtil::bytes2ushort({loadBytes[2], loadBytes[3]}); - - assert(soundCount <= Mpc2000XlSpecs::MAX_SOUND_COUNT_IN_MEMORY); -} - -ApsHeader::ApsHeader(const uint16_t soundCount) -{ - assert(soundCount <= Mpc2000XlSpecs::MAX_SOUND_COUNT_IN_MEMORY); - - saveBytes = std::vector(4); - - const auto soundCountBytes = ByteUtil::ushort2bytes(soundCount); - saveBytes[0] = 10; - saveBytes[1] = 5; - saveBytes[2] = soundCountBytes[0]; - saveBytes[3] = soundCountBytes[1]; -} - -bool ApsHeader::isValid() const -{ - return valid; -} - -int ApsHeader::getSoundAmount() const -{ - return soundCount; -} - -std::vector ApsHeader::getBytes() const -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsHeader.hpp b/src/main/file/aps/ApsHeader.hpp deleted file mode 100644 index 155f10a1..00000000 --- a/src/main/file/aps/ApsHeader.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::aps -{ - class ApsHeader - { - const std::vector APS_HEADER_MAGIC{0x0A, 0x05}; - - public: - bool valid = false; - uint16_t soundCount = 0; - std::vector saveBytes; - - bool isValid() const; - int getSoundAmount() const; - std::vector getBytes() const; - - explicit ApsHeader(const std::vector &loadBytes); - explicit ApsHeader(uint16_t soundCount); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsMixer.cpp b/src/main/file/aps/ApsMixer.cpp deleted file mode 100644 index 786d3ccd..00000000 --- a/src/main/file/aps/ApsMixer.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "file/aps/ApsMixer.hpp" - -#include "engine/StereoMixer.hpp" -#include "engine/IndivFxMixer.hpp" - -using namespace mpc::file::aps; -using namespace mpc::performance; - -ApsMixer::ApsMixer(const std::vector &loadBytes) -{ - for (int i = 0; i < 64; i++) - { - fxPaths[i] = loadBytes[i * 6 + 0]; - levels[i] = loadBytes[i * 6 + 1]; - pannings[i] = loadBytes[i * 6 + 2]; - iLevels[i] = loadBytes[i * 6 + 3]; - iOutputs[i] = loadBytes[i * 6 + 4]; - sendLevels[i] = loadBytes[i * 6 + 5]; - } -} - -ApsMixer::ApsMixer( - const std::vector> &stereoMixer, - const std::vector> &indivFxMixer) -{ - for (int i = 0; i < 64; i++) - { - const auto mixerChannel = stereoMixer[i]; - const auto indivFxMixerChannel = indivFxMixer[i]; - saveBytes[i * 6 + 0] = - static_cast(indivFxMixerChannel->getFxPath()); - saveBytes[i * 6 + 1] = static_cast(mixerChannel->getLevel()); - saveBytes[i * 6 + 2] = static_cast(mixerChannel->getPanning()); - saveBytes[i * 6 + 3] = - static_cast(indivFxMixerChannel->getVolumeIndividualOut()); - saveBytes[i * 6 + 4] = - static_cast(indivFxMixerChannel->getOutput()); - saveBytes[i * 6 + 5] = - static_cast(indivFxMixerChannel->getFxSendLevel()); - } -} - -StereoMixer ApsMixer::getStereoMixerChannel(const int noteIndex) const -{ - StereoMixer result; - result.level = DrumMixerLevel(getLevel(noteIndex)); - result.panning = DrumMixerPanning(getPanning(noteIndex)); - return result; -} - -IndivFxMixer ApsMixer::getIndivFxMixerChannel(const int noteIndex) const -{ - IndivFxMixer result; - result.individualOutLevel = DrumMixerLevel(getIndividualLevel(noteIndex)); - result.individualOutput = - DrumMixerIndividualOutput(getIndividualOutput(noteIndex)); - result.fxSendLevel = DrumMixerLevel(getSendLevel(noteIndex)); - result.fxPath = DrumMixerIndividualFxPath(getFxPath(noteIndex)); - return result; -} - -int ApsMixer::getFxPath(const int noteIndex) const -{ - return fxPaths[noteIndex]; -} - -int ApsMixer::getLevel(const int noteIndex) const -{ - return levels[noteIndex]; -} - -int ApsMixer::getPanning(const int noteIndex) const -{ - return pannings[noteIndex]; -} - -int ApsMixer::getIndividualLevel(const int noteIndex) const -{ - return iLevels[noteIndex]; -} - -int ApsMixer::getIndividualOutput(const int noteIndex) const -{ - return iOutputs[noteIndex]; -} - -int ApsMixer::getSendLevel(const int noteIndex) const -{ - return sendLevels[noteIndex]; -} - -std::vector ApsMixer::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsMixer.hpp b/src/main/file/aps/ApsMixer.hpp deleted file mode 100644 index 9253c895..00000000 --- a/src/main/file/aps/ApsMixer.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "performance/Drum.hpp" - -#include -#include - -namespace mpc::engine -{ - class StereoMixer; - class IndivFxMixer; -} // namespace mpc::engine - -namespace mpc::file::aps -{ - class ApsMixer - { - - public: - std::vector fxPaths = std::vector(64); - std::vector levels = std::vector(64); - std::vector pannings = std::vector(64); - std::vector iLevels = std::vector(64); - std::vector iOutputs = std::vector(64); - std::vector sendLevels = std::vector(64); - std::vector saveBytes = std::vector(384); - - performance::StereoMixer getStereoMixerChannel(int noteIndex) const; - performance::IndivFxMixer getIndivFxMixerChannel(int noteIndex) const; - int getFxPath(int noteIndex) const; - int getLevel(int noteIndex) const; - int getPanning(int noteIndex) const; - int getIndividualLevel(int noteIndex) const; - int getIndividualOutput(int noteIndex) const; - int getSendLevel(int noteIndex) const; - std::vector getBytes(); - - ApsMixer(const std::vector &loadBytes); - ApsMixer(const std::vector> - &stereoMixer, - const std::vector> - &indivFxMixer); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsName.cpp b/src/main/file/aps/ApsName.cpp deleted file mode 100644 index e1506510..00000000 --- a/src/main/file/aps/ApsName.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "file/aps/ApsName.hpp" - -#include "file/aps/ApsParser.hpp" - -#include "Util.hpp" - -using namespace mpc::file::aps; - -ApsName::ApsName(const std::vector &loadBytes) -{ - auto nameBytes = Util::vecCopyOfRange(loadBytes, 0, NAME_STRING_LENGTH); - name = ""; - for (char c : nameBytes) - { - if (c == 0x00) - { - break; - } - name.push_back(c); - } -} - -ApsName::ApsName(std::string name) -{ - saveBytes = std::vector(ApsParser::APS_NAME_LENGTH); - while (name.length() < NAME_STRING_LENGTH) - { - name.push_back(' '); - } - - for (int i = 0; i < NAME_STRING_LENGTH; i++) - { - saveBytes[i] = name[i]; - } - - saveBytes[NAME_STRING_LENGTH] = ApsParser::NAME_TERMINATOR; -} - -const int ApsName::NAME_STRING_LENGTH; - -std::string ApsName::get() -{ - return name; -} - -std::vector ApsName::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsName.hpp b/src/main/file/aps/ApsName.hpp deleted file mode 100644 index cd3eb6bf..00000000 --- a/src/main/file/aps/ApsName.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::aps -{ - - class ApsName - { - - static const int NAME_STRING_LENGTH{16}; - - public: - std::string name; - std::vector saveBytes; - - std::string get(); - - std::vector getBytes(); - - ApsName(const std::vector &loadBytes); - ApsName(std::string name); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsNoteParameters.cpp b/src/main/file/aps/ApsNoteParameters.cpp deleted file mode 100644 index 04043c3c..00000000 --- a/src/main/file/aps/ApsNoteParameters.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "sampler/VoiceOverlapMode.hpp" -#include "file/aps/ApsNoteParameters.hpp" - -#include "sampler/NoteParameters.hpp" - -#include "file/ByteUtil.hpp" - -#include - -using namespace mpc::file::aps; - -ApsNoteParameters::ApsNoteParameters(const std::vector &loadBytes) -{ - soundIndex = - loadBytes[0] == '\xff' ? -1 : static_cast(loadBytes[0]); - assert(soundIndex >= -1); - soundGenerationMode = loadBytes[2]; - velocityRangeLower = loadBytes[3]; - alsoPlay1 = loadBytes[4] == 0 ? 34 : loadBytes[4]; - velocityRangeUpper = loadBytes[5]; - alsoPlay2 = loadBytes[6] == 0 ? 34 : loadBytes[6]; - voiceOverlapMode = static_cast(loadBytes[7]); - mute1 = loadBytes[8] == 0 ? 34 : loadBytes[8]; - mute2 = loadBytes[9] == 0 ? 34 : loadBytes[9]; - auto buf = std::vector{loadBytes[10], loadBytes[11]}; - tune = ByteUtil::bytes2short(buf); - attack = loadBytes[12]; - decay = loadBytes[13]; - decayMode = loadBytes[14]; - cutoffFrequency = loadBytes[15]; - resonance = loadBytes[16]; - filterAttack = loadBytes[17]; - filterDecay = loadBytes[18]; - filterEnvelopeAmount = loadBytes[19]; - velocityToLevel = loadBytes[20]; - velocityToAttack = loadBytes[21]; - velocityToStart = loadBytes[22]; - velocityToFilterFrequency = loadBytes[23]; - sliderParameter = loadBytes[24]; - velocityToPitch = loadBytes[25]; -} - -ApsNoteParameters::ApsNoteParameters(sampler::NoteParameters *np) -{ - saveBytes[0] = np->getSoundIndex() == -1 ? '\xff' : np->getSoundIndex(); - saveBytes[1] = np->getSoundIndex() == -1 ? '\xff' : '\x00'; - saveBytes[2] = np->getSoundGenerationMode(); - saveBytes[3] = np->getVelocityRangeLower(); - saveBytes[4] = np->getOptionalNoteA() == 34 ? 0 : np->getOptionalNoteA(); - saveBytes[5] = np->getVelocityRangeUpper(); - saveBytes[6] = np->getOptionalNoteB() == 34 ? 0 : np->getOptionalNoteB(); - saveBytes[7] = static_cast(np->getVoiceOverlapMode()); - saveBytes[8] = np->getMuteAssignA() == 34 ? 0 : np->getMuteAssignA(); - saveBytes[9] = np->getMuteAssignB() == 34 ? 0 : np->getMuteAssignB(); - auto buf = ByteUtil::ushort2bytes(np->getTune()); - saveBytes[10] = buf[0]; - saveBytes[11] = buf[1]; - saveBytes[12] = np->getAttack(); - saveBytes[13] = np->getDecay(); - saveBytes[14] = np->getDecayMode(); - saveBytes[15] = np->getFilterFrequency(); - saveBytes[16] = np->getFilterResonance(); - saveBytes[17] = np->getFilterAttack(); - saveBytes[18] = np->getFilterDecay(); - saveBytes[19] = np->getFilterEnvelopeAmount(); - saveBytes[20] = np->getVeloToLevel(); - saveBytes[21] = np->getVelocityToAttack(); - saveBytes[22] = np->getVelocityToStart(); - saveBytes[23] = np->getVelocityToFilterFrequency(); - saveBytes[24] = np->getSliderParameterNumber(); - saveBytes[25] = np->getVelocityToPitch(); -} - -int ApsNoteParameters::getSoundIndex() const -{ - return soundIndex; -} - -mpc::sampler::VoiceOverlapMode ApsNoteParameters::getVoiceOverlapMode() const -{ - return voiceOverlapMode; -} - -int ApsNoteParameters::getTune() const -{ - return tune; -} - -int ApsNoteParameters::getDecayMode() const -{ - return decayMode; -} - -int ApsNoteParameters::getSoundGenerationMode() const -{ - return soundGenerationMode; -} - -int ApsNoteParameters::getVelocityRangeLower() const -{ - return velocityRangeLower; -} - -int ApsNoteParameters::getAlsoPlay1() const -{ - return alsoPlay1; -} - -int ApsNoteParameters::getVelocityRangeUpper() const -{ - return velocityRangeUpper; -} - -int ApsNoteParameters::getAlsoPlay2() const -{ - return alsoPlay2; -} - -int ApsNoteParameters::getMute1() const -{ - return mute1; -} - -int ApsNoteParameters::getMute2() const -{ - return mute2; -} - -int ApsNoteParameters::getAttack() const -{ - return attack; -} - -int ApsNoteParameters::getDecay() const -{ - return decay; -} - -int ApsNoteParameters::getCutoffFrequency() const -{ - return cutoffFrequency; -} - -int ApsNoteParameters::getResonance() const -{ - return resonance; -} - -int ApsNoteParameters::getVelocityToFilterAttack() const -{ - return filterAttack; -} - -int ApsNoteParameters::getVelocityToFilterDecay() const -{ - return filterDecay; -} - -int ApsNoteParameters::getVelocityToFilterAmount() const -{ - return filterEnvelopeAmount; -} - -int ApsNoteParameters::getVelocityToLevel() const -{ - return velocityToLevel; -} - -int ApsNoteParameters::getVelocityToAttack() const -{ - return velocityToAttack; -} - -int ApsNoteParameters::getVelocityToStart() const -{ - return velocityToStart; -} - -int ApsNoteParameters::getVelocityToFilterFrequency() const -{ - return velocityToFilterFrequency; -} - -int ApsNoteParameters::getSliderParameter() const -{ - return sliderParameter; -} - -int ApsNoteParameters::getVelocityToPitch() const -{ - return velocityToPitch; -} - -std::vector ApsNoteParameters::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsNoteParameters.hpp b/src/main/file/aps/ApsNoteParameters.hpp deleted file mode 100644 index 3ab53e86..00000000 --- a/src/main/file/aps/ApsNoteParameters.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include "sampler/VoiceOverlapMode.hpp" - -#include - -namespace mpc::sampler -{ - class NoteParameters; -} - -namespace mpc::file::aps -{ - class ApsNoteParameters - { - - public: - int soundIndex; - int soundGenerationMode; - int velocityRangeLower; - int alsoPlay1; - int velocityRangeUpper; - int alsoPlay2; - sampler::VoiceOverlapMode voiceOverlapMode; - int mute1; - int mute2; - int tune; - int attack; - int decay; - int decayMode; - int cutoffFrequency; - int resonance; - int filterAttack; - int filterDecay; - int filterEnvelopeAmount; - int velocityToLevel; - int velocityToAttack; - int velocityToStart; - int velocityToFilterFrequency; - int sliderParameter; - int velocityToPitch; - std::vector saveBytes = std::vector(26); - - int getSoundIndex() const; - sampler::VoiceOverlapMode getVoiceOverlapMode() const; - int getTune() const; - int getDecayMode() const; - int getSoundGenerationMode() const; - int getVelocityRangeLower() const; - int getAlsoPlay1() const; - int getVelocityRangeUpper() const; - int getAlsoPlay2() const; - int getMute1() const; - int getMute2() const; - int getAttack() const; - int getDecay() const; - int getCutoffFrequency() const; - int getResonance() const; - int getVelocityToFilterAttack() const; - int getVelocityToFilterDecay() const; - int getVelocityToFilterAmount() const; - int getVelocityToLevel() const; - int getVelocityToAttack() const; - int getVelocityToStart() const; - int getVelocityToFilterFrequency() const; - int getSliderParameter() const; - int getVelocityToPitch() const; - std::vector getBytes(); - - ApsNoteParameters(const std::vector &loadBytes); - ApsNoteParameters(sampler::NoteParameters *np); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsParser.cpp b/src/main/file/aps/ApsParser.cpp deleted file mode 100644 index 357c9091..00000000 --- a/src/main/file/aps/ApsParser.cpp +++ /dev/null @@ -1,228 +0,0 @@ -#include "file/aps/ApsParser.hpp" - -#include "Mpc.hpp" - -#include "sampler/Program.hpp" -#include "sampler/Sampler.hpp" -#include "sequencer/Bus.hpp" -#include "sequencer/Sequencer.hpp" - -#include "Util.hpp" - -using namespace mpc::file::aps; -using namespace mpc::disk; -using namespace mpc::sampler; - -ApsParser::ApsParser(const std::vector &loadBytes) -{ - if (loadBytes.empty()) - { - // throw invalid_argument(name + " has no data"); - return; - } - - header = std::make_unique(Util::vecCopyOfRange( - loadBytes, HEADER_OFFSET, HEADER_OFFSET + HEADER_LENGTH)); - - auto const soundNamesEnd = - HEADER_LENGTH + header->getSoundAmount() * SOUND_NAME_LENGTH; - soundNames = std::make_unique(Util::vecCopyOfRange( - loadBytes, HEADER_OFFSET + HEADER_LENGTH, soundNamesEnd)); - programCount = (loadBytes.size() - 1689 - soundNames->get().size() * 17) / - PROGRAM_LENGTH; - auto const nameEnd = soundNamesEnd + PAD_LENGTH1 + APS_NAME_LENGTH; - auto const nameOffset = soundNamesEnd + PAD_LENGTH1; - apsName = std::make_unique( - Util::vecCopyOfRange(loadBytes, nameOffset, nameEnd)); - auto const parametersEnd = nameEnd + PARAMETERS_LENGTH; - globalParameters = std::make_unique( - Util::vecCopyOfRange(loadBytes, nameEnd, parametersEnd)); - auto const maTableEnd = parametersEnd + TABLE_LENGTH; - maTable = std::make_unique( - Util::vecCopyOfRange(loadBytes, parametersEnd, maTableEnd)); - int const drum1MixerOffset = maTableEnd + PAD_LENGTH2; - - for (int i = 0; i < 4; i++) - { - int offset = drum1MixerOffset + - i * (MIXER_LENGTH + DRUM_CONFIG_LENGTH + DRUM_PAD_LENGTH); - drumMixers[i] = std::make_unique( - Util::vecCopyOfRange(loadBytes, offset, offset + MIXER_LENGTH)); - drumConfigurations[i] = std::make_unique( - Util::vecCopyOfRange(loadBytes, offset + MIXER_LENGTH, - offset + MIXER_LENGTH + DRUM_CONFIG_LENGTH)); - } - - int const firstProgramOffset = drum1MixerOffset + - (MIXER_LENGTH + DRUM_CONFIG_LENGTH) * 4 + - PAD_LENGTH3 - 6; - - for (int i = 0; i < programCount; i++) - { - int offset = - firstProgramOffset + i * (PROGRAM_LENGTH + PROGRAM_PAD_LENGTH); - programs.push_back(std::make_unique( - Util::vecCopyOfRange(loadBytes, offset, offset + PROGRAM_LENGTH))); - } -} - -ApsParser::ApsParser(Mpc &mpc, std::string apsNameString) -{ - auto sampler = mpc.getSampler(); - std::vector> chunks; - programCount = sampler->getProgramCount(); - int const soundCount = sampler->getSoundCount(); - - chunks.push_back(ApsHeader(soundCount).getBytes()); - - chunks.push_back(ApsSoundNames(sampler.get()).getBytes()); - - chunks.push_back(std::vector{24, 0}); - - chunks.push_back(ApsName(apsNameString).getBytes()); - - auto parameters = ApsGlobalParameters(mpc); - chunks.push_back(parameters.getBytes()); - - auto masterTable = ApsAssignTable(*sampler->getMasterPadAssign()); - chunks.push_back(masterTable.getBytes()); - chunks.push_back( - std::vector{4, 0, static_cast(136), 1, 64, 0, 6}); - - for (int i = 0; i < Mpc2000XlSpecs::DRUM_BUS_COUNT; i++) - { - auto drumBus = mpc.getSequencer()->getDrumBus(DrumBusIndex(i)); - - ApsMixer mixer(drumBus->getStereoMixerChannels(), - drumBus->getIndivFxMixerChannels()); - - ApsDrumConfiguration drumConfig(drumBus->getProgramIndex(), - drumBus->receivesPgmChange(), - drumBus->receivesMidiVolume()); - - chunks.push_back(mixer.getBytes()); - - if (i < 3) - { - chunks.push_back(drumConfig.getBytes()); - } - else - { - auto ba = drumConfig.getBytes(); - auto ba1 = std::vector(7); - - for (int j = 0; j < 7; j++) - { - ba1[j] = ba[j]; - } - - chunks.push_back(ba1); - } - } - - chunks.push_back({1, 127}); - - for (int i = 0; i < Mpc2000XlSpecs::MAX_PROGRAM_COUNT; i++) - { - auto p = sampler->getProgram(i); - - if (!p->isUsed()) - { - continue; - } - - auto program = ApsProgram(p.get(), i); - chunks.push_back(program.getBytes()); - } - - chunks.push_back(std::vector{(char)255, (char)255}); - auto totalSize = 0; - - for (auto &ba : chunks) - { - totalSize += ba.size(); - } - - saveBytes = std::vector(totalSize); - auto counter = 0; - - for (auto &ba : chunks) - { - for (auto &b : ba) - { - saveBytes[counter++] = b; - } - } -} - -const int ApsParser::HEADER_OFFSET; -const int ApsParser::HEADER_LENGTH; -const int ApsParser::SOUND_NAME_LENGTH; -const int ApsParser::PAD_LENGTH1; -const int ApsParser::APS_NAME_LENGTH; -const int ApsParser::PARAMETERS_LENGTH; -const int ApsParser::TABLE_LENGTH; -const int ApsParser::PAD_LENGTH2; -const int ApsParser::MIXER_LENGTH; -const int ApsParser::DRUM_CONFIG_LENGTH; -const int ApsParser::DRUM_PAD_LENGTH; -const int ApsParser::PAD_LENGTH3; -const int ApsParser::PROGRAM_LENGTH; -const int ApsParser::PROGRAM_PAD_LENGTH; -const int ApsParser::LAST_PROGRAM_PAD_LENGTH; -const char ApsParser::NAME_TERMINATOR; - -std::vector ApsParser::getSoundNames() const -{ - return soundNames->get(); -} - -bool ApsParser::isHeaderValid() const -{ - return header->isValid(); -} - -std::string ApsParser::getApsName() const -{ - return apsName->get(); -} - -std::vector ApsParser::getPrograms() const -{ - std::vector res; - for (auto &ap : programs) - { - res.push_back(ap.get()); - } - return res; -} - -std::vector ApsParser::getDrumMixers() const -{ - std::vector res; - for (auto &am : drumMixers) - { - res.push_back(am.get()); - } - return res; -} - -ApsDrumConfiguration *ApsParser::getDrumConfiguration(int i) const -{ - return drumConfigurations[i].get(); -} - -ApsGlobalParameters *ApsParser::getGlobalParameters() const -{ - return globalParameters.get(); -} - -std::vector ApsParser::getMasterAssignTable() const -{ - return maTable->get(); -} - -std::vector ApsParser::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsParser.hpp b/src/main/file/aps/ApsParser.hpp deleted file mode 100644 index 67b6fcba..00000000 --- a/src/main/file/aps/ApsParser.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::disk -{ - class MpcFile; -} -namespace mpc::file::aps -{ - class ApsParser - { - - public: - static const int HEADER_OFFSET{0}; - static const int HEADER_LENGTH{4}; - static const int SOUND_NAME_LENGTH{17}; - static const int PAD_LENGTH1{2}; - static const int APS_NAME_LENGTH{17}; - static const int PARAMETERS_LENGTH{8}; - static const int TABLE_LENGTH{64}; - static const int PAD_LENGTH2{7}; - static const int MIXER_LENGTH{384}; - static const int DRUM_CONFIG_LENGTH{9}; - static const int DRUM_PAD_LENGTH{3}; - static const int PAD_LENGTH3{15}; - static const int PROGRAM_LENGTH{2350}; - static const int PROGRAM_PAD_LENGTH{4}; - static const int LAST_PROGRAM_PAD_LENGTH{2}; - static const char NAME_TERMINATOR{0}; - int programCount; - std::unique_ptr header; - std::unique_ptr soundNames; - std::unique_ptr apsName; - std::unique_ptr globalParameters; - std::unique_ptr maTable; - std::vector> drumMixers = - std::vector>(4); - std::vector> drumConfigurations = - std::vector>(4); - std::vector> programs; - std::vector saveBytes; - - std::vector getSoundNames() const; - bool isHeaderValid() const; - std::string getApsName() const; - std::vector getPrograms() const; - std::vector getDrumMixers() const; - ApsDrumConfiguration *getDrumConfiguration(int i) const; - ApsGlobalParameters *getGlobalParameters() const; - std::vector getMasterAssignTable() const; - - std::vector getBytes(); - - ApsParser(const std::vector &loadBytes); - ApsParser(Mpc &, std::string apsNameString); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsProgram.cpp b/src/main/file/aps/ApsProgram.cpp deleted file mode 100644 index cd66eddd..00000000 --- a/src/main/file/aps/ApsProgram.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "file/aps/ApsProgram.hpp" - -#include "file/aps/ApsAssignTable.hpp" -#include "file/aps/ApsNoteParameters.hpp" -#include "file/aps/ApsSlider.hpp" -#include "file/pgmwriter/Pads.hpp" -#include "engine/StereoMixer.hpp" -#include "sampler/Program.hpp" - -#include "StrUtil.hpp" -#include "Util.hpp" - -using namespace mpc::file::aps; -using namespace mpc::engine; - -ApsProgram::ApsProgram(const std::vector &loadBytes) -{ - index = loadBytes[INDEX_OFFSET]; - const auto nameBytes = - Util::vecCopyOfRange(loadBytes, NAME_OFFSET, NAME_OFFSET + NAME_LENGTH); - - name = ""; - - for (const char c : nameBytes) - { - if (c == 0x00) - { - break; - } - - name.push_back(c); - } - - name = StrUtil::trim(name); - - slider = new ApsSlider(Util::vecCopyOfRange(loadBytes, SLIDER_OFFSET, - SLIDER_OFFSET + SLIDER_LENGTH)); - - for (int i = 0; i < 64; i++) - { - const int offset = NOTE_PARAMETERS_OFFSET + i * NOTE_PARAMETERS_LENGTH; - noteParameters[i] = new ApsNoteParameters(Util::vecCopyOfRange( - loadBytes, offset, offset + NOTE_PARAMETERS_LENGTH)); - } - - mixer = - new ApsMixer(Util::vecCopyOfRange(loadBytes, MIXER_OFFSET, MIXER_END)); - assignTable = new ApsAssignTable( - Util::vecCopyOfRange(loadBytes, ASSIGN_TABLE_OFFSET, - ASSIGN_TABLE_OFFSET + ASSIGN_TABLE_LENGTH)); -} - -ApsProgram::ApsProgram(sampler::Program *program, int index) -{ - std::vector> byteList; - this->index = index; - byteList.push_back({static_cast(index)}); - byteList.push_back(UNKNOWN); - auto programName = StrUtil::padRight(program->getName(), " ", 16); - - for (char c : programName) - { - byteList.push_back({c}); - } - - byteList.push_back({0}); // Name terminator - - ApsSlider apsSlider(program); - byteList.push_back(apsSlider.getBytes()); - byteList.push_back({35, 64, 0, 26, 0}); - - for (int i = 0; i < 64; i++) - { - ApsNoteParameters np((program->getNoteParameters(i + 35))); - byteList.push_back(np.getBytes()); - } - - byteList.push_back({6}); - - std::vector> stereoMixerChannels(64); - std::vector> indivFxMixerChannels(64); - - for (int i = 0; i < 64; i++) - { - stereoMixerChannels[i] = program->getStereoMixerChannel(i); - indivFxMixerChannels[i] = program->getIndivFxMixerChannel(i); - } - - ApsMixer apsMixer(stereoMixerChannels, indivFxMixerChannels); - byteList.push_back(apsMixer.getBytes()); - byteList.push_back({0, Mpc2000XlSpecs::PROGRAM_PAD_COUNT, 0}); - auto apsAssignTable = - std::vector(Mpc2000XlSpecs::PROGRAM_PAD_COUNT); - - for (int i = 0; i < Mpc2000XlSpecs::PROGRAM_PAD_COUNT; i++) - { - apsAssignTable[i] = program->getNoteFromPad(ProgramPadIndex(i)); - } - - ApsAssignTable table(apsAssignTable); - byteList.push_back(table.getBytes()); - byteList.push_back(pgmwriter::Pads::getFxBoardSettings()); - auto totalSize = 0; - - for (auto &ba : byteList) - { - totalSize += ba.size(); - } - - saveBytes = std::vector(totalSize); - auto counter = 0; - - for (auto &ba : byteList) - { - for (auto b : ba) - { - saveBytes[counter++] = b; - } - } -} - -const int ApsProgram::NAME_OFFSET; -const int ApsProgram::NAME_LENGTH; -const int ApsProgram::NAME_TERMINATOR_LENGTH; -const int ApsProgram::SLIDER_OFFSET; -const int ApsProgram::SLIDER_LENGTH; -const int ApsProgram::PADDING1_LENGTH; -const int ApsProgram::NOTE_PARAMETERS_OFFSET; -const int ApsProgram::NOTE_PARAMETERS_LENGTH; -const int ApsProgram::PADDING2_LENGTH; -const int ApsProgram::MIXER_OFFSET; -const int ApsProgram::MIXER_END; -const int ApsProgram::PADDING3_LENGTH; -const int ApsProgram::ASSIGN_TABLE_OFFSET; -const int ApsProgram::ASSIGN_TABLE_LENGTH; - -ApsNoteParameters *ApsProgram::getNoteParameters(const int noteIndex) const -{ - return noteParameters[noteIndex]; -} - -ApsMixer *ApsProgram::getMixer() const -{ - return mixer; -} - -ApsAssignTable *ApsProgram::getAssignTable() const -{ - return assignTable; -} - -ApsSlider *ApsProgram::getSlider() const -{ - return slider; -} - -std::string ApsProgram::getName() -{ - return name; -} - -std::vector ApsProgram::getBytes() -{ - return saveBytes; -} - -mpc::performance::StereoMixer -ApsProgram::getStereoMixerChannel(const int noteIndex) const -{ - return mixer->getStereoMixerChannel(noteIndex); -} - -mpc::performance::IndivFxMixer -ApsProgram::getIndivFxMixerChannel(const int noteIndex) const -{ - return mixer->getIndivFxMixerChannel(noteIndex); -} - -ApsProgram::~ApsProgram() -{ - if (slider != nullptr) - { - delete slider; - } - if (mixer != nullptr) - { - delete mixer; - } - if (assignTable != nullptr) - { - delete assignTable; - } - - for (const auto &np : noteParameters) - { - if (np != nullptr) - { - delete np; - } - } -} diff --git a/src/main/file/aps/ApsProgram.hpp b/src/main/file/aps/ApsProgram.hpp deleted file mode 100644 index 3d55832a..00000000 --- a/src/main/file/aps/ApsProgram.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace mpc::engine -{ - class StereoMixer; - class IndivFxMixer; -} // namespace mpc::engine - -namespace mpc::sampler -{ - class Program; -} - -namespace mpc::file::aps -{ - class ApsNoteParameters; - class ApsAssignTable; - class ApsSlider; -} // namespace mpc::file::aps - -namespace mpc::file::aps -{ - class ApsProgram - { - - public: - static const int INDEX_OFFSET{0}; - static const int UNKNOWN_OFFSET{1}; - const std::vector UNKNOWN{0, 7, 4, 30, 0}; - static const int NAME_OFFSET{6}; - static const int NAME_LENGTH{16}; - static const int NAME_TERMINATOR_LENGTH{1}; - static const int SLIDER_OFFSET{23}; - static const int SLIDER_LENGTH{10}; - static const int PADDING1_LENGTH{5}; - static const int NOTE_PARAMETERS_OFFSET{38}; - static const int NOTE_PARAMETERS_LENGTH{26}; - static const int PADDING2_LENGTH{7}; - static const int MIXER_OFFSET{1703}; - static const int MIXER_END{2087}; - static const int PADDING3_LENGTH{3}; - static const int ASSIGN_TABLE_OFFSET{2090}; - static const int ASSIGN_TABLE_LENGTH{64}; - - std::string name; - int index; - ApsSlider *slider = nullptr; - std::vector noteParameters = - std::vector(64); - ApsMixer *mixer = nullptr; - ApsAssignTable *assignTable = nullptr; - std::vector saveBytes; - - ApsNoteParameters *getNoteParameters(int noteIndex) const; - ApsMixer *getMixer() const; - ApsAssignTable *getAssignTable() const; - ApsSlider *getSlider() const; - std::string getName(); - - std::vector getBytes(); - - performance::StereoMixer getStereoMixerChannel(int noteIndex) const; - - performance::IndivFxMixer getIndivFxMixerChannel(int noteIndex) const; - - ApsProgram(const std::vector &loadBytes); - ApsProgram(sampler::Program *program, int index); - ~ApsProgram(); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsSlider.cpp b/src/main/file/aps/ApsSlider.cpp deleted file mode 100644 index c17f8db6..00000000 --- a/src/main/file/aps/ApsSlider.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "file/aps/ApsSlider.hpp" - -#include "file/aps/ApsProgram.hpp" -#include "sampler/Program.hpp" -#include "sampler/PgmSlider.hpp" - -using namespace mpc::file::aps; - -ApsSlider::ApsSlider(const std::vector &loadBytes) -{ - note = loadBytes[0] == 0 ? 34 : loadBytes[0]; - tuneLow = loadBytes[1]; - tuneHigh = loadBytes[2]; - decayLow = loadBytes[3]; - decayHigh = loadBytes[4]; - attackLow = loadBytes[5]; - attackHigh = loadBytes[6]; - filterLow = loadBytes[7]; - filterHigh = loadBytes[8]; - programChange = loadBytes[9]; -} - -ApsSlider::ApsSlider(sampler::Program *program) -{ - auto slider = program->getSlider(); - saveBytes = std::vector(ApsProgram::SLIDER_LENGTH); - saveBytes[0] = slider->getNote() == 34 ? 0 : slider->getNote(); - saveBytes[1] = slider->getTuneLowRange(); - saveBytes[2] = slider->getTuneHighRange(); - saveBytes[3] = slider->getDecayLowRange(); - saveBytes[4] = slider->getDecayHighRange(); - saveBytes[5] = slider->getAttackLowRange(); - saveBytes[6] = slider->getAttackHighRange(); - saveBytes[7] = slider->getFilterLowRange(); - saveBytes[8] = slider->getFilterHighRange(); - saveBytes[9] = program->getMidiProgramChange() - 1; -} - -std::vector ApsSlider::PADDING = std::vector{0, 35, 64, 0, 26, 0}; - -int ApsSlider::getNote() const -{ - return note; -} - -int ApsSlider::getTuneLow() const -{ - return tuneLow; -} - -int ApsSlider::getTuneHigh() const -{ - return tuneHigh; -} - -int ApsSlider::getDecayLow() const -{ - return decayLow; -} - -int ApsSlider::getDecayHigh() const -{ - return decayHigh; -} - -int ApsSlider::getAttackLow() const -{ - return attackLow; -} - -int ApsSlider::getAttackHigh() const -{ - return attackHigh; -} - -int ApsSlider::getFilterLow() const -{ - return filterLow; -} - -int ApsSlider::getFilterHigh() const -{ - return filterHigh; -} - -int ApsSlider::getProgramChange() const -{ - return programChange; -} - -std::vector ApsSlider::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsSlider.hpp b/src/main/file/aps/ApsSlider.hpp deleted file mode 100644 index 6b3de678..00000000 --- a/src/main/file/aps/ApsSlider.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -namespace mpc::sampler -{ - class PgmSlider; - class Program; -} - -namespace mpc::file::aps -{ - class ApsSlider - { - - public: - int note; - int tuneLow; - int tuneHigh; - int decayLow; - int decayHigh; - int attackLow; - int attackHigh; - int filterLow; - int filterHigh; - int programChange; - std::vector saveBytes; - - private: - static std::vector PADDING; - - public: - int getNote() const; - int getTuneLow() const; - int getTuneHigh() const; - int getDecayLow() const; - int getDecayHigh() const; - int getAttackLow() const; - int getAttackHigh() const; - int getFilterLow() const; - int getFilterHigh() const; - int getProgramChange() const; - std::vector getBytes(); - - ApsSlider(const std::vector &loadBytes); - ApsSlider(sampler::Program *program); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/aps/ApsSoundNames.cpp b/src/main/file/aps/ApsSoundNames.cpp deleted file mode 100644 index 87cacaba..00000000 --- a/src/main/file/aps/ApsSoundNames.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "file/aps/ApsSoundNames.hpp" - -#include "file/aps/ApsParser.hpp" -#include "sampler/Sampler.hpp" - -#include "StrUtil.hpp" - -#include "Util.hpp" - -using namespace mpc::file::aps; - -ApsSoundNames::ApsSoundNames(const std::vector &loadBytes) -{ - int sound = 0; - - while (sound < loadBytes.size() / ApsParser::SOUND_NAME_LENGTH) - { - auto nameBytes = Util::vecCopyOfRange( - loadBytes, sound * ApsParser::SOUND_NAME_LENGTH, - sound * ApsParser::SOUND_NAME_LENGTH + NAME_STRING_LENGTH); - - std::string nameStr; - for (char c : nameBytes) - { - if (c == 0x00) - { - break; - } - nameStr.push_back(c); - } - - names.push_back(nameStr); - sound++; - } -} - -ApsSoundNames::ApsSoundNames(sampler::Sampler *sampler) -{ - saveBytes = std::vector(sampler->getSoundCount() * - ApsParser::SOUND_NAME_LENGTH); - for (int i = 0; i < sampler->getSoundCount(); i++) - { - int offset = i * ApsParser::SOUND_NAME_LENGTH; - for (int j = 0; j < NAME_STRING_LENGTH; j++) - { - saveBytes[offset + j] = StrUtil::padRight( - sampler->getSound(i)->getName(), " ", NAME_STRING_LENGTH)[j]; - } - - saveBytes[offset + NAME_STRING_LENGTH] = ApsParser::NAME_TERMINATOR; - } -} - -const int ApsSoundNames::NAME_STRING_LENGTH; - -std::vector ApsSoundNames::get() -{ - return names; -} - -std::vector ApsSoundNames::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/aps/ApsSoundNames.hpp b/src/main/file/aps/ApsSoundNames.hpp deleted file mode 100644 index 2a425c29..00000000 --- a/src/main/file/aps/ApsSoundNames.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::sampler -{ - class Sampler; -} - -namespace mpc::file::aps -{ - class ApsSoundNames - { - public: - ApsSoundNames(const std::vector &loadBytes); - ApsSoundNames(sampler::Sampler *sampler); - - static const int NAME_STRING_LENGTH = 16; - - std::vector names; - std::vector saveBytes; - - std::vector get(); - std::vector getBytes(); - }; -} // namespace mpc::file::aps diff --git a/src/main/file/kaitai/ApsIo.cpp b/src/main/file/kaitai/ApsIo.cpp index 0392c4eb..a82180da 100644 --- a/src/main/file/kaitai/ApsIo.cpp +++ b/src/main/file/kaitai/ApsIo.cpp @@ -1,32 +1,646 @@ #include "file/kaitai/ApsIo.hpp" #include "Mpc.hpp" -#include "disk/ApsLoader.hpp" +#include "StrUtil.hpp" +#include "disk/AbstractDisk.hpp" #include "disk/MpcFile.hpp" -#include "file/aps/ApsParser.hpp" +#include "disk/SoundLoader.hpp" +#include "engine/IndivFxMixer.hpp" +#include "engine/StereoMixer.hpp" +#include "file/BitUtil.hpp" +#include "file/ByteUtil.hpp" #include "file/kaitai/KaitaiIoUtil.hpp" #include "file/kaitai/generated/mpc2000xl_aps.h" +#include "lcdgui/screens/DrumScreen.hpp" +#include "lcdgui/screens/MixerSetupScreen.hpp" +#include "lcdgui/screens/PgmAssignScreen.hpp" +#include "lcdgui/screens/window/CantFindFileScreen.hpp" +#include "performance/PerformanceManager.hpp" +#include "sampler/NoteParameters.hpp" +#include "sampler/PgmSlider.hpp" +#include "sampler/Program.hpp" #include "sampler/Sampler.hpp" +#include "sequencer/Bus.hpp" +#include "sequencer/Sequencer.hpp" + +#include +#include +#include +#include +#include +#include + +#include + +namespace { + +constexpr uint8_t kUnassignedSoundIndex = 0xFF; +constexpr int kOffNoteNumber = 34; +constexpr int kVisibleNameLength = 16; +constexpr int kProgramPadCount = 64; +constexpr char kApsProgramUnknownBytes[] = {0, 7, 4, 30, 0}; +constexpr char kApsProgramSliderPadding[] = {35, 64, 0, 26, 0}; +constexpr char kApsProgramNoteTerminator = 6; +constexpr char kApsProgramMixerPadding[] = {0, 64, 0}; +constexpr char kApsTopLevelPadAfterSounds[] = {24, 0}; +constexpr char kApsDrumPadBeforeFirstDrum[] = {4, 0, static_cast(136), 1, 64, 0, 6}; +constexpr char kApsAfterDrums[] = {1, 127}; +constexpr char kApsEndMarker[] = {static_cast(255), static_cast(255)}; +constexpr char kApsGlobalTemplateNoSounds[] = {127, static_cast(254), 124, static_cast(238), 0, 0, 0, 64}; +constexpr char kApsGlobalTemplateWithSounds[] = {3, 56, 0, static_cast(161), 0, 0, 0, 64}; +constexpr char kApsDrumConfigTemplate[] = {0, 0, 1, 1, 127, 0, 1, 1, 127, 64, 0, 6}; +constexpr char kPadTailFxBoardSettingsHex[] = + "02004800D0070000630114081DFC323302323C08050A1414320000020F19000541141E0105" + "0000056300F4FF0C0000000000000002004F014F0100424F0100424F01004232006328003C" + "0000D0070000630114081DFC323302323C08050A1414320000020F19000541141E01050000" + "056300F4FF0C0000000000000002004F014F0100424F0100424F01004232006328003C0000" + "04000C000000320023003E335A3214000000320023003E335A3214000000320023003E335A" + "3214000000320023003E335A321400"; + +std::string stripNullTerminatedField(const std::string& raw) +{ + const auto terminator = raw.find('\0'); + return terminator == std::string::npos ? raw : raw.substr(0, terminator); +} + +std::string trimNullTerminatedField(const std::string& raw) +{ + return mpc::StrUtil::trim(stripNullTerminatedField(raw)); +} + +int normalizeOffNote(const uint8_t raw) +{ + return raw == 0 ? kOffNoteNumber : raw; +} + +void copyMixer(mpc::performance::StereoMixer& stereoDest, + mpc::performance::IndivFxMixer& indivDest, + const mpc2000xl_pgm_t::pad_mixer_t& mixer) +{ + stereoDest.level = mpc::DrumMixerLevel(mixer.volume()); + stereoDest.panning = mpc::DrumMixerPanning(mixer.pan()); + indivDest.individualOutLevel = mpc::DrumMixerLevel(mixer.volume_individual()); + indivDest.individualOutput = mpc::DrumMixerIndividualOutput(mixer.output()); + indivDest.fxSendLevel = mpc::DrumMixerLevel(mixer.effects_send_level()); + indivDest.fxPath = mpc::DrumMixerIndividualFxPath(mixer.fx_output()); +} + +void appendBytes(std::vector& dest, const std::vector& src) +{ + dest.insert(dest.end(), src.begin(), src.end()); +} + +void appendBytes(std::vector& dest, const std::string& src) +{ + dest.insert(dest.end(), src.begin(), src.end()); +} + +void appendBytes(std::vector& dest, const char* src, const std::size_t size) +{ + dest.insert(dest.end(), src, src + size); +} + +std::vector toNullTerminatedAsciiBytes(const std::string& value) +{ + std::vector bytes(kVisibleNameLength + 1, ' '); + const auto trimmed = value.substr(0, kVisibleNameLength); + std::copy(trimmed.begin(), trimmed.end(), bytes.begin()); + bytes.back() = 0; + return bytes; +} + +std::vector buildGlobalParametersBytes(mpc::Mpc& mpc, const int soundCount) +{ + std::vector bytes( + soundCount == 0 + ? std::begin(kApsGlobalTemplateNoSounds) + : std::begin(kApsGlobalTemplateWithSounds), + soundCount == 0 + ? std::end(kApsGlobalTemplateNoSounds) + : std::end(kApsGlobalTemplateWithSounds)); + + auto drumScreen = mpc.screens->get(); + auto pgmAssignScreen = mpc.screens->get(); + auto mixerSetupScreen = mpc.screens->get(); + + bytes[0] = mpc::file::BitUtil::setBits(1, bytes[0], drumScreen->isPadToIntSound()); + bytes[1] = mpc::file::BitUtil::setBits(1, bytes[1], pgmAssignScreen->isPadAssignMaster()); + bytes[2] = mpc::file::BitUtil::setBits(1, bytes[2], mixerSetupScreen->isStereoMixSourceDrum()); + bytes[2] = mpc::file::BitUtil::setBits(2, bytes[2], mixerSetupScreen->isIndivFxSourceDrum()); + bytes[3] = mpc::file::BitUtil::setBits(1, bytes[3], mixerSetupScreen->isCopyPgmMixToDrumEnabled()); + bytes[3] = mpc::file::BitUtil::setBits(16, bytes[3], mixerSetupScreen->isRecordMixChangesEnabled()); + bytes[4] = static_cast(mixerSetupScreen->getFxDrum()); + bytes[6] = static_cast(mixerSetupScreen->getMasterLevel()); + return bytes; +} + +std::vector buildDrumMixerBytes(const std::shared_ptr& drumBus) +{ + std::vector bytes; + bytes.reserve(kProgramPadCount * 6); + + const auto stereoMixers = drumBus->getStereoMixerChannels(); + const auto indivFxMixers = drumBus->getIndivFxMixerChannels(); + + for (int i = 0; i < kProgramPadCount; ++i) + { + const auto& stereo = stereoMixers[i]; + const auto& indiv = indivFxMixers[i]; + bytes.push_back(static_cast(indiv->getFxPath())); + bytes.push_back(static_cast(stereo->getLevel())); + bytes.push_back(static_cast(stereo->getPanning())); + bytes.push_back(static_cast(indiv->getVolumeIndividualOut())); + bytes.push_back(static_cast(indiv->getOutput())); + bytes.push_back(static_cast(indiv->getFxSendLevel())); + } + + return bytes; +} + +std::vector buildDrumConfigBytes(const std::shared_ptr& drumBus, + const bool fullLength) +{ + std::vector bytes(std::begin(kApsDrumConfigTemplate), std::end(kApsDrumConfigTemplate)); + bytes[1] = static_cast(drumBus->getProgramIndex()); + bytes[2] = mpc::file::BitUtil::setBits(1, bytes[2], drumBus->receivesPgmChange()); + bytes[3] = mpc::file::BitUtil::setBits(1, bytes[3], drumBus->receivesMidiVolume()); + bytes[5] = static_cast(drumBus->getProgramIndex()); + + if (!fullLength) + { + bytes.resize(7); + } + + return bytes; +} + +std::vector buildProgramBytes(mpc::sampler::Program& program, const int index) +{ + std::vector bytes; + bytes.reserve(2350); + + bytes.push_back(static_cast(index)); + appendBytes(bytes, kApsProgramUnknownBytes, sizeof(kApsProgramUnknownBytes)); + appendBytes(bytes, toNullTerminatedAsciiBytes(program.getName())); + + const auto* slider = program.getSlider(); + bytes.push_back(static_cast(slider->getNote() == 34 ? 0 : slider->getNote().get())); + bytes.push_back(static_cast(slider->getTuneLowRange())); + bytes.push_back(static_cast(slider->getTuneHighRange())); + bytes.push_back(static_cast(slider->getDecayLowRange())); + bytes.push_back(static_cast(slider->getDecayHighRange())); + bytes.push_back(static_cast(slider->getAttackLowRange())); + bytes.push_back(static_cast(slider->getAttackHighRange())); + bytes.push_back(static_cast(slider->getFilterLowRange())); + bytes.push_back(static_cast(slider->getFilterHighRange())); + bytes.push_back(static_cast(program.getMidiProgramChange() - 1)); + appendBytes(bytes, kApsProgramSliderPadding, sizeof(kApsProgramSliderPadding)); + + for (int i = 0; i < kProgramPadCount; ++i) + { + const auto* note = program.getNoteParameters(i + 35); + bytes.push_back(static_cast(note->getSoundIndex() == -1 ? 0xFF : note->getSoundIndex())); + bytes.push_back(static_cast(note->getSoundIndex() == -1 ? 0xFF : 0x00)); + bytes.push_back(static_cast(note->getSoundGenerationMode())); + bytes.push_back(static_cast(note->getVelocityRangeLower())); + bytes.push_back(static_cast(note->getOptionalNoteA() == 34 ? 0 : note->getOptionalNoteA().get())); + bytes.push_back(static_cast(note->getVelocityRangeUpper())); + bytes.push_back(static_cast(note->getOptionalNoteB() == 34 ? 0 : note->getOptionalNoteB().get())); + bytes.push_back(static_cast(static_cast(note->getVoiceOverlapMode()))); + bytes.push_back(static_cast(note->getMuteAssignA() == 34 ? 0 : note->getMuteAssignA().get())); + bytes.push_back(static_cast(note->getMuteAssignB() == 34 ? 0 : note->getMuteAssignB().get())); + appendBytes(bytes, mpc::file::ByteUtil::ushort2bytes(static_cast(note->getTune()))); + bytes.push_back(static_cast(note->getAttack())); + bytes.push_back(static_cast(note->getDecay())); + bytes.push_back(static_cast(note->getDecayMode())); + bytes.push_back(static_cast(note->getFilterFrequency())); + bytes.push_back(static_cast(note->getFilterResonance())); + bytes.push_back(static_cast(note->getFilterAttack())); + bytes.push_back(static_cast(note->getFilterDecay())); + bytes.push_back(static_cast(note->getFilterEnvelopeAmount())); + bytes.push_back(static_cast(note->getVeloToLevel())); + bytes.push_back(static_cast(note->getVelocityToAttack())); + bytes.push_back(static_cast(note->getVelocityToStart())); + bytes.push_back(static_cast(note->getVelocityToFilterFrequency())); + bytes.push_back(static_cast(note->getSliderParameterNumber())); + bytes.push_back(static_cast(note->getVelocityToPitch())); + } + + bytes.push_back(kApsProgramNoteTerminator); + + for (int i = 0; i < kProgramPadCount; ++i) + { + const auto stereo = program.getStereoMixerChannel(i); + const auto indiv = program.getIndivFxMixerChannel(i); + bytes.push_back(static_cast(indiv->getFxPath())); + bytes.push_back(static_cast(stereo->getLevel())); + bytes.push_back(static_cast(stereo->getPanning())); + bytes.push_back(static_cast(indiv->getVolumeIndividualOut())); + bytes.push_back(static_cast(indiv->getOutput())); + bytes.push_back(static_cast(indiv->getFxSendLevel())); + } + + appendBytes(bytes, kApsProgramMixerPadding, sizeof(kApsProgramMixerPadding)); + + for (int i = 0; i < kProgramPadCount; ++i) + { + bytes.push_back(static_cast(program.getNoteFromPad(mpc::ProgramPadIndex(i)).get())); + } + + appendBytes(bytes, mpc::file::ByteUtil::hexToBytes(kPadTailFxBoardSettingsHex)); + return bytes; +} + +void showPopup(mpc::Mpc& mpc, const std::string& name, const std::string& ext) +{ + const std::string msg = + "Loading " + + mpc::StrUtil::toUpper(mpc::StrUtil::padRight(name, " ", 16) + "." + ext); + + const auto ls = mpc.getLayeredScreen(); + ls->postToUiThread(mpc::utils::Task( + [ls, msg] + { + ls->showPopup(msg); + })); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); +} + +void handleSoundNotFound(mpc::Mpc& mpc, const std::string& soundFileName) +{ + const auto cantFindFileScreen = + mpc.screens->get(); + + if (const auto skipAll = cantFindFileScreen->skipAll; !skipAll) + { + const auto ls = mpc.getLayeredScreen(); + ls->postToUiThread(mpc::utils::Task( + [ls, cantFindFileScreen, soundFileName] + { + cantFindFileScreen->waitingForUser = true; + cantFindFileScreen->fileName = soundFileName; + ls->openScreenById(mpc::lcdgui::ScreenId::CantFindFileScreen); + })); + + while (cantFindFileScreen->waitingForUser) + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } +} + +void loadSound(mpc::Mpc& mpc, + const std::string& soundFileName, + const std::string& ext, + const std::shared_ptr& soundFile, + const bool headless) +{ + constexpr auto replace = false; + mpc::disk::SoundLoader soundLoader(mpc, replace); + + if (!headless) + { + showPopup(mpc, soundFileName, ext); + } + + mpc::disk::SoundLoaderResult result; + constexpr bool shouldBeConverted = false; + const auto sound = mpc.getSampler()->addSound(); + + if (!sound) + { + return; + } + + soundLoader.loadSound(soundFile, result, sound, shouldBeConverted); + + if (!result.success) + { + mpc.getSampler()->deleteSound(sound); + } +} + +void loadReferencedSounds(mpc2000xl_aps_t& parsed, + mpc::Mpc& mpc, + const bool headless, + std::vector& unavailableSoundIndices, + std::map& finalSoundIndices) +{ + auto sampler = mpc.getSampler(); + auto disk = mpc.getDisk(); + + int skipCount = 0; + sampler->deleteAllSamples(); + + for (int i = 0; i < static_cast(parsed.sound_names()->size()); ++i) + { + auto ext = std::string("snd"); + std::shared_ptr soundFile; + const auto soundFileName = + mpc::StrUtil::replaceAll(stripNullTerminatedField(parsed.sound_names()->at(i)), ' ', ""); + + for (auto& f : disk->getAllFiles()) + { + if (mpc::StrUtil::eqIgnoreCase( + mpc::StrUtil::replaceAll(f->getName(), ' ', ""), + soundFileName + ".SND")) + { + soundFile = f; + break; + } + } + + if (!soundFile || !soundFile->exists()) + { + for (auto& f : disk->getAllFiles()) + { + if (mpc::StrUtil::eqIgnoreCase( + mpc::StrUtil::replaceAll(f->getName(), ' ', ""), + soundFileName + ".WAV")) + { + soundFile = f; + ext = "wav"; + break; + } + } + } + + if (!soundFile || !soundFile->exists()) + { + unavailableSoundIndices.push_back(i); + ++skipCount; + + if (!headless) + { + handleSoundNotFound(mpc, soundFileName); + } + + continue; + } + + finalSoundIndices[i] = i - skipCount; + loadSound(mpc, soundFileName, ext, soundFile, headless); + } +} + +void loadPrograms(mpc2000xl_aps_t& parsed, + mpc::Mpc& mpc, + const std::vector& unavailableSoundIndices, + const std::map& finalSoundIndices) +{ + auto sampler = mpc.getSampler(); + + for (const auto& apsProgram : *parsed.aps_programs()) + { + if (!apsProgram || apsProgram->body() == nullptr) + { + continue; + } + + const auto programIndex = apsProgram->index(); + auto program = sampler->getProgram(programIndex); + auto* body = apsProgram->body(); + program->setName(trimNullTerminatedField(body->name())); + + const auto* slider = body->slider(); + const auto pgmSlider = program->getSlider(); + pgmSlider->setAssignNote(mpc::DrumNoteNumber(normalizeOffNote(slider->note()))); + pgmSlider->setTuneLowRange(slider->tune_low()); + pgmSlider->setTuneHighRange(slider->tune_high()); + pgmSlider->setDecayLowRange(slider->decay_low()); + pgmSlider->setDecayHighRange(slider->decay_high()); + pgmSlider->setAttackLowRange(slider->attack_low()); + pgmSlider->setAttackHighRange(slider->attack_high()); + pgmSlider->setFilterLowRange(slider->filter_low()); + pgmSlider->setFilterHighRange(slider->filter_high()); + program->setMidiProgramChange(body->program_change() + 1); + + mpc::performance::UpdateProgramBulk msg; + auto& perfProgram = msg.program; + msg.programIndex = mpc::ProgramIndex(programIndex); + perfProgram.used = true; + + for (int noteIndex = 0; noteIndex < 64; ++noteIndex) + { + perfProgram.pads[noteIndex].note = + mpc::DrumNoteNumber(body->pad_to_note_mapping()->at(noteIndex)); + + auto& destNoteParams = perfProgram.noteParameters[noteIndex]; + const auto* sourceMixer = body->pad_mixers()->at(noteIndex).get(); + copyMixer(destNoteParams.stereoMixer, destNoteParams.indivFxMixer, *sourceMixer); + + const auto* srcNoteParams = body->note_parameters()->at(noteIndex).get(); + auto soundIndex = srcNoteParams->sound_index() == kUnassignedSoundIndex + ? -1 + : static_cast(srcNoteParams->sound_index()); + + if (std::find(begin(unavailableSoundIndices), + end(unavailableSoundIndices), + soundIndex) != end(unavailableSoundIndices)) + { + soundIndex = -1; + } + + if (soundIndex != -1) + { + const auto finalSoundIndex = finalSoundIndices.find(soundIndex); + if (finalSoundIndex != end(finalSoundIndices)) + { + soundIndex = finalSoundIndex->second; + } + } + + destNoteParams.soundIndex = soundIndex; + destNoteParams.tune = srcNoteParams->tune(); + destNoteParams.voiceOverlapMode = + static_cast(srcNoteParams->voice_overlap_mode()); + destNoteParams.decayMode = static_cast(srcNoteParams->decay_mode()); + destNoteParams.attack = srcNoteParams->attack(); + destNoteParams.decay = srcNoteParams->decay(); + destNoteParams.filterAttack = srcNoteParams->velocity_envelope_to_filter_attack(); + destNoteParams.filterDecay = srcNoteParams->velocity_envelope_to_filter_decay(); + destNoteParams.filterEnvelopeAmount = srcNoteParams->velocity_envelope_to_filter_amount(); + destNoteParams.filterFrequency = srcNoteParams->cutoff(); + destNoteParams.filterResonance = srcNoteParams->resonance(); + destNoteParams.muteAssignA = + mpc::DrumNoteNumber(normalizeOffNote(srcNoteParams->mute_assign_1())); + destNoteParams.muteAssignB = + mpc::DrumNoteNumber(normalizeOffNote(srcNoteParams->mute_assign_2())); + destNoteParams.optionalNoteA = + mpc::DrumNoteNumber(normalizeOffNote(srcNoteParams->also_play_use_note_1())); + destNoteParams.optionalNoteB = + mpc::DrumNoteNumber(normalizeOffNote(srcNoteParams->also_play_use_note_2())); + destNoteParams.sliderParameterNumber = + static_cast(srcNoteParams->slider_parameter()); + destNoteParams.soundGenerationMode = + static_cast(srcNoteParams->sound_generation_mode()); + destNoteParams.velocityToStart = srcNoteParams->velocity_to_start(); + destNoteParams.velocityToAttack = srcNoteParams->velocity_to_attack(); + destNoteParams.velocityToFilterFrequency = srcNoteParams->velocity_to_cutoff(); + destNoteParams.velocityToLevel = srcNoteParams->velocity_to_level(); + destNoteParams.velocityRangeLower = srcNoteParams->velocity_range_lower(); + destNoteParams.velocityRangeUpper = srcNoteParams->velocity_range_upper(); + destNoteParams.velocityToPitch = srcNoteParams->velocity_to_pitch(); + } + + perfProgram.slider.attackHighRange = slider->attack_high(); + perfProgram.slider.attackLowRange = slider->attack_low(); + perfProgram.slider.decayHighRange = slider->decay_high(); + perfProgram.slider.decayLowRange = slider->decay_low(); + perfProgram.slider.filterHighRange = slider->filter_high(); + perfProgram.slider.filterLowRange = slider->filter_low(); + perfProgram.slider.assignNote = mpc::DrumNoteNumber(normalizeOffNote(slider->note())); + perfProgram.slider.tuneHighRange = slider->tune_high(); + perfProgram.slider.tuneLowRange = slider->tune_low(); + perfProgram.midiProgramChange = body->program_change() + 1; + + mpc.getPerformanceManager().lock()->enqueue( + mpc::performance::PerformanceMessage{std::move(msg)}); + } +} + +void loadDrums(mpc2000xl_aps_t& parsed, mpc::Mpc& mpc) +{ + for (int i = 0; i < mpc::Mpc2000XlSpecs::DRUM_BUS_COUNT; ++i) + { + auto* drum = i == 0 ? parsed.drum1() : parsed.drum2(); + + mpc::performance::Drum perfDrum; + perfDrum.drumBusIndex = mpc::DrumBusIndex(i); + + for (int noteIndex = 0; noteIndex < 64; ++noteIndex) + { + const auto* mixer = drum->pad_mixers()->at(noteIndex).get(); + copyMixer(perfDrum.stereoMixers[noteIndex], perfDrum.indivFxMixers[noteIndex], *mixer); + } + + perfDrum.programIndex = mpc::ProgramIndex(drum->program()); + perfDrum.receivePgmChangeEnabled = + drum->receive_program_change() == mpc2000xl_aps_t::NO_YES_TRUE; + perfDrum.receiveMidiVolumeEnabled = + drum->receive_midi_volume() == mpc2000xl_aps_t::NO_YES_TRUE; + + mpc.getPerformanceManager().lock()->enqueue( + mpc::performance::UpdateDrumBulk{perfDrum}); + } +} + +void loadGlobals(mpc2000xl_aps_t& parsed, mpc::Mpc& mpc) +{ + auto mixerSetupScreen = mpc.screens->get(); + auto* globals = parsed.global_parameters(); + + mixerSetupScreen->setRecordMixChangesEnabled( + globals->record_mix_changes() == mpc2000xl_aps_t::NO_YES_TRUE); + mixerSetupScreen->setCopyPgmMixToDrumEnabled( + globals->copy_pgm_mix_to_drum() == mpc2000xl_aps_t::NO_YES_TRUE); + mixerSetupScreen->setFxDrum(globals->fx_drum()); + mixerSetupScreen->setIndivFxSourceDrum( + globals->indiv_fx_source() == mpc2000xl_aps_t::MIX_SOURCE_DRUM); + mixerSetupScreen->setStereoMixSourceDrum( + globals->stereo_mix_source() == mpc2000xl_aps_t::MIX_SOURCE_DRUM); + + auto drumScreen = mpc.screens->get(); + drumScreen->setPadToIntSound( + globals->pad_to_internal_sound() == mpc2000xl_aps_t::NO_YES_TRUE); + mixerSetupScreen->setMasterLevel(globals->master_level()); + + auto pgmAssignScreen = mpc.screens->get(); + std::vector masterPadAssign; + masterPadAssign.reserve(64); + for (const auto note : *parsed.master_pad_to_note_mapping()) + { + masterPadAssign.emplace_back(note); + } + mpc.getSampler()->setMasterPadAssign(masterPadAssign); + pgmAssignScreen->setPadAssign( + globals->pad_assign() == mpc2000xl_aps_t::PAD_ASSIGN_MASTERS); +} + +} // namespace using namespace mpc::file::kaitai; -void ApsIo::load(mpc::Mpc &mpc, const std::shared_ptr &file, bool headless) +void ApsIo::loadBytes(mpc::Mpc& mpc, + const std::vector& bytes, + const bool withoutSounds, + bool headless) { - const auto canonicalBytes = parseRewrite(file->getBytes()); - mpc::file::aps::ApsParser parser(canonicalBytes); + const auto canonicalBytes = parseRewrite(bytes); + std::stringstream parseStream( + std::string(canonicalBytes.begin(), canonicalBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); - if (!parser.isHeaderValid()) + if (parsed.magic() != std::string("\x0a\x05", 2)) { throw std::runtime_error("Invalid APS header"); } - constexpr auto withoutSounds = false; - mpc::disk::ApsLoader::loadFromParsedAps(parser, mpc, withoutSounds, headless); + std::vector unavailableSoundIndices; + std::map finalSoundIndices; + if (!withoutSounds) + { + loadReferencedSounds(parsed, mpc, headless, unavailableSoundIndices, finalSoundIndices); + } + loadPrograms(parsed, mpc, unavailableSoundIndices, finalSoundIndices); + loadDrums(parsed, mpc); + loadGlobals(parsed, mpc); mpc.getSampler()->setSoundIndex(0); } -std::vector ApsIo::save(mpc::Mpc &mpc, const std::string &apsName) +void ApsIo::load(mpc::Mpc& mpc, const std::shared_ptr& file, bool headless) +{ + loadBytes(mpc, file->getBytes(), false, headless); +} + +std::vector ApsIo::save(mpc::Mpc& mpc, const std::string& apsName) { - mpc::file::aps::ApsParser parser(mpc, apsName); - return parseRewrite(parser.getBytes()); + auto sampler = mpc.getSampler(); + std::vector bytes; + + appendBytes(bytes, std::string("\x0a\x05", 2)); + appendBytes(bytes, mpc::file::ByteUtil::ushort2bytes(static_cast(sampler->getSoundCount()))); + + for (int i = 0; i < sampler->getSoundCount(); ++i) + { + appendBytes(bytes, toNullTerminatedAsciiBytes(sampler->getSound(i)->getName())); + } + + appendBytes(bytes, kApsTopLevelPadAfterSounds, sizeof(kApsTopLevelPadAfterSounds)); + appendBytes(bytes, toNullTerminatedAsciiBytes(apsName)); + appendBytes(bytes, buildGlobalParametersBytes(mpc, sampler->getSoundCount())); + + for (const auto& note : *sampler->getMasterPadAssign()) + { + bytes.push_back(static_cast(note.get())); + } + + appendBytes(bytes, kApsDrumPadBeforeFirstDrum, sizeof(kApsDrumPadBeforeFirstDrum)); + + for (int i = 0; i < mpc::Mpc2000XlSpecs::DRUM_BUS_COUNT; ++i) + { + auto drumBus = mpc.getSequencer()->getDrumBus(mpc::DrumBusIndex(i)); + appendBytes(bytes, buildDrumMixerBytes(drumBus)); + appendBytes(bytes, buildDrumConfigBytes(drumBus, i < 3)); + } + + appendBytes(bytes, kApsAfterDrums, sizeof(kApsAfterDrums)); + + for (int i = 0; i < mpc::Mpc2000XlSpecs::MAX_PROGRAM_COUNT; ++i) + { + auto program = sampler->getProgram(i); + if (!program->isUsed()) + { + continue; + } + + appendBytes(bytes, buildProgramBytes(*program, i)); + } + + appendBytes(bytes, kApsEndMarker, sizeof(kApsEndMarker)); + return parseRewrite(bytes); } diff --git a/src/main/file/kaitai/ApsIo.hpp b/src/main/file/kaitai/ApsIo.hpp index c18d0247..940e5be7 100644 --- a/src/main/file/kaitai/ApsIo.hpp +++ b/src/main/file/kaitai/ApsIo.hpp @@ -21,6 +21,7 @@ namespace mpc::file::kaitai { public: static void load(mpc::Mpc &, const std::shared_ptr &, bool headless); + static void loadBytes(mpc::Mpc &, const std::vector &, bool withoutSounds, bool headless); static std::vector save(mpc::Mpc &, const std::string &apsName); }; } diff --git a/src/main/file/kaitai/PgmIo.cpp b/src/main/file/kaitai/PgmIo.cpp index 12a54fec..9ba91909 100644 --- a/src/main/file/kaitai/PgmIo.cpp +++ b/src/main/file/kaitai/PgmIo.cpp @@ -5,13 +5,309 @@ #include "disk/MpcFile.hpp" #include "engine/IndivFxMixer.hpp" #include "engine/StereoMixer.hpp" -#include "disk/PgmFileToProgramConverter.hpp" +#include "file/ByteUtil.hpp" #include "file/kaitai/KaitaiIoUtil.hpp" #include "file/kaitai/generated/mpc2000xl_pgm.h" -#include "mpc_fs.hpp" +#include "performance/PerformanceManager.hpp" +#include "sampler/NoteParameters.hpp" +#include "sampler/Pad.hpp" +#include "sampler/PgmSlider.hpp" #include "sampler/Program.hpp" #include "sampler/Sampler.hpp" -#include "file/pgmwriter/PgmWriter.hpp" + +#include +#include +#include + +#include + +namespace { + +constexpr uint8_t kUnassignedSoundIndex = 0xFF; +constexpr uint8_t kRawMuteAssignOff = 0; +constexpr int kNormalizedMuteAssignOff = 34; +constexpr int kProgramNameLength = 16; +constexpr int kSoundNameLength = 16; +constexpr int kProgramPadCount = 64; +constexpr int kDefaultSliderUnknown0 = 35; +constexpr int kDefaultSliderUnknown1 = 64; +constexpr int kDefaultSliderUnknown2 = 0; +constexpr int kDefaultSliderUnknown3 = 25; +constexpr int kDefaultSliderUnknown4 = 0; +constexpr int kDefaultNoteParametersTerminator = 6; +constexpr int kDefaultMixerUnknown0 = 0; +constexpr int kDefaultMixerUnknown1 = 64; +constexpr int kDefaultMixerUnknown2 = 0; +constexpr char kPadTailFxBoardSettingsHex[] = + "02004800D0070000630114081DFC323302323C08050A1414320000020F19000541141E0105" + "0000056300F4FF0C0000000000000002004F014F0100424F0100424F01004232006328003C" + "0000D0070000630114081DFC323302323C08050A1414320000020F19000541141E01050000" + "056300F4FF0C0000000000000002004F014F0100424F0100424F01004232006328003C0000" + "04000C000000320023003E335A3214000000320023003E335A3214000000320023003E335A" + "3214000000320023003E335A321400"; + +int normalizeMuteAssign(const uint8_t rawValue) +{ + return rawValue == kRawMuteAssignOff ? kNormalizedMuteAssignOff : rawValue; +} + +std::string stripNullTerminatedField(const std::string& raw) +{ + const auto terminator = raw.find('\0'); + return terminator == std::string::npos ? raw : raw.substr(0, terminator); +} + +std::string toNullTerminatedAsciiField(const std::string& value, const int visibleLength) +{ + auto field = mpc::StrUtil::padRight(value.substr(0, visibleLength), " ", visibleLength); + field.push_back('\0'); + return field; +} + +void setSlider(const mpc2000xl_pgm_t& parsed, + const std::shared_ptr& program) +{ + const auto* slider = parsed.slider(); + const auto note = slider->note() == 0 + ? mpc::NoDrumNoteAssigned + : mpc::DrumNoteNumber(slider->note()); + const auto pgmSlider = program->getSlider(); + pgmSlider->setAssignNote(note); + pgmSlider->setAttackHighRange(slider->attack_high()); + pgmSlider->setAttackLowRange(slider->attack_low()); + pgmSlider->setDecayHighRange(slider->decay_high()); + pgmSlider->setDecayLowRange(slider->decay_low()); + pgmSlider->setFilterHighRange(slider->filter_high()); + pgmSlider->setFilterLowRange(slider->filter_low()); + pgmSlider->setTuneHighRange(slider->tune_high()); + pgmSlider->setTuneLowRange(slider->tune_low()); +} + +void setNoteParameters(mpc::Mpc& mpc, + const mpc2000xl_pgm_t& parsed, + const std::shared_ptr& program) +{ + std::array + allPerfNoteParams; + + for (int programPadIndex = 0; + programPadIndex < mpc::Mpc2000XlSpecs::PROGRAM_PAD_COUNT; + ++programPadIndex) + { + const auto padNote = parsed.pad_to_note_mapping()->at(programPadIndex); + const auto note = padNote == -1 ? mpc::NoDrumNoteAssigned : padNote; + program->getPad(programPadIndex)->setNote(mpc::DrumNoteNumber(note)); + + const auto* parsedNote = parsed.note_parameters()->at(programPadIndex).get(); + auto& perfNoteParams = allPerfNoteParams[programPadIndex]; + + perfNoteParams.attack = parsedNote->attack(); + perfNoteParams.decay = parsedNote->decay(); + perfNoteParams.decayMode = static_cast(parsedNote->decay_mode()); + perfNoteParams.filterAttack = parsedNote->velocity_envelope_to_filter_attack(); + perfNoteParams.filterDecay = parsedNote->velocity_envelope_to_filter_decay(); + perfNoteParams.filterEnvelopeAmount = parsedNote->velocity_envelope_to_filter_amount(); + perfNoteParams.filterFrequency = parsedNote->cutoff(); + perfNoteParams.filterResonance = parsedNote->resonance(); + perfNoteParams.muteAssignA = mpc::DrumNoteNumber(normalizeMuteAssign(parsedNote->mute_assign_1())); + perfNoteParams.muteAssignB = mpc::DrumNoteNumber(normalizeMuteAssign(parsedNote->mute_assign_2())); + perfNoteParams.optionalNoteA = mpc::DrumNoteNumber(parsedNote->also_play_use_note_1()); + perfNoteParams.optionalNoteB = mpc::DrumNoteNumber(parsedNote->also_play_use_note_2()); + perfNoteParams.soundIndex = parsedNote->sound_index() == kUnassignedSoundIndex + ? -1 + : parsedNote->sound_index(); + perfNoteParams.sliderParameterNumber = static_cast(parsedNote->slider_parameter()); + perfNoteParams.soundGenerationMode = static_cast(parsedNote->sound_generation_mode()); + perfNoteParams.tune = parsedNote->tune(); + perfNoteParams.velocityRangeLower = parsedNote->velocity_range_lower(); + perfNoteParams.velocityRangeUpper = parsedNote->velocity_range_upper(); + perfNoteParams.velocityToAttack = parsedNote->velocity_to_attack(); + perfNoteParams.velocityToFilterFrequency = parsedNote->velocity_to_cutoff(); + perfNoteParams.velocityToLevel = parsedNote->velocity_to_level(); + perfNoteParams.velocityToPitch = parsedNote->velocity_to_pitch(); + perfNoteParams.velocityToStart = parsedNote->velocity_to_start(); + perfNoteParams.voiceOverlapMode = static_cast(parsedNote->voice_overlap_mode()); + } + + mpc::performance::UpdateAllNoteParametersBulk msg{program->getProgramIndex(), + allPerfNoteParams}; + mpc.getPerformanceManager().lock()->enqueue(msg); +} + +void setMixer(const mpc2000xl_pgm_t& parsed, + const std::shared_ptr& program) +{ + for (int i = 0; i < 64; ++i) + { + const auto noteParameters = program->getNoteParameters(i + 35); + const auto stereoMixer = noteParameters->getStereoMixer(); + const auto indivFxMixer = noteParameters->getIndivFxMixer(); + const auto* parsedMixer = parsed.pad_mixers()->at(i).get(); + + stereoMixer->setLevel(mpc::DrumMixerLevel(parsedMixer->volume())); + stereoMixer->setPanning(mpc::DrumMixerPanning(parsedMixer->pan())); + indivFxMixer->setVolumeIndividualOut( + mpc::DrumMixerLevel(parsedMixer->volume_individual())); + indivFxMixer->setOutput( + mpc::DrumMixerIndividualOutput(parsedMixer->output())); + indivFxMixer->setFxPath( + mpc::DrumMixerIndividualFxPath(parsedMixer->fx_output())); + indivFxMixer->setFxSendLevel( + mpc::DrumMixerLevel(parsedMixer->effects_send_level())); + } +} + +std::vector collectSavedSoundNames( + mpc::sampler::Program& program, + const std::shared_ptr& sampler) +{ + std::vector soundIndices; + for (auto* noteParameters : program.getNotesParameters()) + { + if (noteParameters->getSoundIndex() != -1) + { + soundIndices.push_back(noteParameters->getSoundIndex()); + } + } + + std::set uniqueSoundNames; + std::vector finalNames; + for (const auto soundIndex : soundIndices) + { + const auto soundName = sampler->getSoundName(soundIndex); + if (uniqueSoundNames.emplace(soundName).second) + { + finalNames.push_back(soundName); + } + } + return finalNames; +} + +std::vector buildSoundIndexConversionTable( + const std::vector& finalSoundNames, + const std::shared_ptr& sampler) +{ + std::vector conversionTable; + conversionTable.reserve(sampler->getSoundCount()); + + for (int soundIndex = 0; soundIndex < sampler->getSoundCount(); ++soundIndex) + { + const auto soundName = sampler->getSoundName(soundIndex); + int mappedIndex = -1; + for (int i = 0; i < static_cast(finalSoundNames.size()); ++i) + { + if (finalSoundNames[i] == soundName) + { + mappedIndex = i; + break; + } + } + conversionTable.push_back(mappedIndex); + } + + return conversionTable; +} + +void populateSavedSlider(mpc2000xl_pgm_t& parsed) +{ + parsed.set__unnamed7(std::string{ + static_cast(kDefaultSliderUnknown0), + static_cast(kDefaultSliderUnknown1), + static_cast(kDefaultSliderUnknown2), + static_cast(kDefaultSliderUnknown3), + static_cast(kDefaultSliderUnknown4) + }); +} + +void populateSavedNoteParameters( + mpc2000xl_pgm_t& parsed, + mpc::sampler::Program& program, + const std::vector& soundIndexConversionTable) +{ + auto notes = std::make_unique>>(); + notes->reserve(kProgramPadCount); + + for (int i = 0; i < kProgramPadCount; ++i) + { + auto note = std::make_unique(nullptr, &parsed, &parsed); + const auto* src = program.getNoteParameters(i + 35); + + if (src->getSoundIndex() == -1) + { + note->set_sound_index(kUnassignedSoundIndex); + } + else + { + note->set_sound_index(static_cast(soundIndexConversionTable.at(src->getSoundIndex()))); + } + + note->set_sound_generation_mode(static_cast(src->getSoundGenerationMode())); + note->set_velocity_range_lower(src->getVelocityRangeLower()); + note->set_also_play_use_note_1(src->getOptionalNoteA()); + note->set_velocity_range_upper(src->getVelocityRangeUpper()); + note->set_also_play_use_note_2(src->getOptionalNoteB()); + note->set_voice_overlap_mode(static_cast(static_cast(src->getVoiceOverlapMode()))); + note->set_mute_assign_1(src->getMuteAssignA() == 34 ? 0 : src->getMuteAssignA()); + note->set_mute_assign_2(src->getMuteAssignB() == 34 ? 0 : src->getMuteAssignB()); + note->set_tune(static_cast(src->getTune())); + note->set_attack(src->getAttack()); + note->set_decay(src->getDecay()); + note->set_decay_mode(static_cast(src->getDecayMode())); + note->set_cutoff(src->getFilterFrequency()); + note->set_resonance(src->getFilterResonance()); + note->set_velocity_envelope_to_filter_attack(src->getFilterAttack()); + note->set_velocity_envelope_to_filter_decay(src->getFilterDecay()); + note->set_velocity_envelope_to_filter_amount(src->getFilterEnvelopeAmount()); + note->set_velocity_to_level(src->getVeloToLevel()); + note->set_velocity_to_attack(src->getVelocityToAttack()); + note->set_velocity_to_start(src->getVelocityToStart()); + note->set_velocity_to_cutoff(src->getVelocityToFilterFrequency()); + note->set_slider_parameter(static_cast(src->getSliderParameterNumber())); + note->set_velocity_to_pitch(src->getVelocityToPitch()); + + notes->push_back(std::move(note)); + } + + parsed.set_note_parameters(std::move(notes)); + parsed.set__unnamed9(std::string{static_cast(kDefaultNoteParametersTerminator)}); +} + +void populateSavedMixers(mpc2000xl_pgm_t& parsed, mpc::sampler::Program& program) +{ + auto mixers = std::make_unique>>(); + mixers->reserve(kProgramPadCount); + + for (int i = 0; i < kProgramPadCount; ++i) + { + auto mixer = std::make_unique(nullptr, &parsed, &parsed); + const auto* src = program.getNoteParameters(i + 35); + const auto stereo = src->getStereoMixer(); + const auto indiv = src->getIndivFxMixer(); + + mixer->set_fx_output(static_cast(static_cast(indiv->getFxPath()))); + mixer->set_volume(stereo->getLevel()); + mixer->set_pan(stereo->getPanning()); + mixer->set_volume_individual(indiv->getVolumeIndividualOut()); + mixer->set_output(indiv->getOutput()); + mixer->set_effects_send_level(indiv->getFxSendLevel()); + mixers->push_back(std::move(mixer)); + } + + parsed.set_pad_mixers(std::move(mixers)); + parsed.set__unnamed11(std::string{ + static_cast(kDefaultMixerUnknown0), + static_cast(kDefaultMixerUnknown1), + static_cast(kDefaultMixerUnknown2) + }); +} + +std::string fxBoardSettingsBytes() +{ + const auto bytes = mpc::file::ByteUtil::hexToBytes(kPadTailFxBoardSettingsHex); + return std::string(bytes.begin(), bytes.end()); +} + +} // namespace using namespace mpc::file::kaitai; @@ -22,31 +318,104 @@ program_or_error PgmIo::loadProgram(mpc::Mpc &mpc, { const auto fileBytes = file->getBytes(); const auto canonicalBytes = parseRewrite(fileBytes); + std::stringstream parseStream( + std::string(canonicalBytes.begin(), canonicalBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream parseIo(&parseStream); + mpc2000xl_pgm_t parsed(&parseIo); + parsed._read(); - const auto tempDirRes = mpc_fs::temp_directory_path(); - if (!tempDirRes) + if (parsed.magic() != std::string("\x07\x04", 2)) { - return tl::make_unexpected(mpc::disk::mpc_io_error_msg{"Unable to resolve temp directory"}); + return tl::make_unexpected(mpc::disk::mpc_io_error_msg{"PGM first 2 bytes are incorrect"}); } - auto tempPath = *tempDirRes / file->getName(); - auto tempFile = std::make_shared( - std::variant>(tempPath) - ); + soundNames.clear(); + soundNames.reserve(parsed.sound_count()); + for (int i = 0; i < parsed.sound_count(); ++i) + { + soundNames.push_back(stripNullTerminatedField(parsed.sound_names()->at(i))); + } + + const std::string programNameInData = mpc::StrUtil::trim(stripNullTerminatedField(parsed.name())); + if (mpc::StrUtil::eqIgnoreCase(programNameInData, file->getNameWithoutExtension())) + { + program->setName(programNameInData); + } + else + { + program->setName(file->getNameWithoutExtension()); + } + + setNoteParameters(mpc, parsed, program); + setMixer(parsed, program); + setSlider(parsed, program); + program->setMidiProgramChange(parsed.program_change() + 1); - auto mutableBytes = canonicalBytes; - tempFile->setFileData(mutableBytes); - const auto result = - mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( - mpc, tempFile, program, soundNames); - (void)mpc_fs::remove(tempPath); - return result; + return program; } std::vector PgmIo::saveProgram(mpc::sampler::Program &program, const std::weak_ptr &sampler) { - const mpc::file::pgmwriter::PgmWriter handwrittenWriter(&program, sampler); - const auto handwrittenBytes = handwrittenWriter.get(); - return parseRewrite(handwrittenBytes); + const auto lockedSampler = sampler.lock(); + if (!lockedSampler) + { + return {}; + } + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + ::kaitai::kstream writeIo(&writeStream); + mpc2000xl_pgm_t parsed(&writeIo); + + const auto finalSoundNames = collectSavedSoundNames(program, lockedSampler); + const auto soundIndexConversionTable = + buildSoundIndexConversionTable(finalSoundNames, lockedSampler); + + auto soundNames = std::make_unique>(); + soundNames->reserve(finalSoundNames.size()); + for (const auto& soundName : finalSoundNames) + { + soundNames->push_back(toNullTerminatedAsciiField(soundName, kSoundNameLength)); + } + + auto slider = std::make_unique(nullptr, &parsed, &parsed); + const auto* srcSlider = program.getSlider(); + slider->set_note(srcSlider->getNote() == 34 ? 0 : srcSlider->getNote()); + slider->set_tune_low(srcSlider->getTuneLowRange()); + slider->set_tune_high(srcSlider->getTuneHighRange()); + slider->set_decay_low(srcSlider->getDecayLowRange()); + slider->set_decay_high(srcSlider->getDecayHighRange()); + slider->set_attack_low(srcSlider->getAttackLowRange()); + slider->set_attack_high(srcSlider->getAttackHighRange()); + slider->set_filter_low(srcSlider->getFilterLowRange()); + slider->set_filter_high(srcSlider->getFilterHighRange()); + + parsed.set_magic(std::string("\x07\x04", 2)); + parsed.set_sound_count(static_cast(finalSoundNames.size())); + parsed.set_sound_names(std::move(soundNames)); + parsed.set__unnamed3(std::string{30, 0}); + parsed.set_name(toNullTerminatedAsciiField(program.getName(), kProgramNameLength)); + parsed.set_slider(std::move(slider)); + parsed.set_program_change(static_cast(program.getMidiProgramChange() - 1)); + populateSavedSlider(parsed); + populateSavedNoteParameters(parsed, program, soundIndexConversionTable); + populateSavedMixers(parsed, program); + + auto padMapping = std::make_unique>(); + padMapping->reserve(kProgramPadCount); + for (int i = 0; i < kProgramPadCount; ++i) + { + const auto note = program.getPad(i)->getNote(); + padMapping->push_back(static_cast(note == 34 ? 0 : note.get())); + } + parsed.set_pad_to_note_mapping(std::move(padMapping)); + parsed.set__unnamed13(fxBoardSettingsBytes()); + + parsed._check(); + parsed._write(); + + const auto bytes = writeStream.str(); + return std::vector(bytes.begin(), bytes.end()); } diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp index 2033b9ca..f0048298 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp @@ -37,8 +37,7 @@ void mpc2000xl_aps_t::_read() { if (!(m_magic == std::string("\x0A\x05", 2))) { throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); } - m_sound_count = m__io->read_u1(); - m__unnamed2 = m__io->read_bytes(1); + m_sound_count = m__io->read_u2le(); m_sound_names = std::unique_ptr>(new std::vector()); const int l_sound_names = sound_count(); for (int i = 0; i < l_sound_names; i++) { @@ -102,8 +101,7 @@ void mpc2000xl_aps_t::_fetch_instances() { void mpc2000xl_aps_t::_write() { m__io->write_bytes(m_magic); - m__io->write_u1(m_sound_count); - m__io->write_bytes(m__unnamed2); + m__io->write_u2le(m_sound_count); if (m_sound_names == nullptr) { throw std::runtime_error("/seq/3: repeated field is not set"); } @@ -173,18 +171,15 @@ void mpc2000xl_aps_t::_check() { if (!(m_magic == std::string("\x0A\x05", 2))) { throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); } - if (m__unnamed2.size() != static_cast(1)) { - throw std::runtime_error("/seq/2: size mismatch"); - } if (m_sound_names == nullptr) { - throw std::runtime_error("/seq/3: repeated field is not set"); + throw std::runtime_error("/seq/2: repeated field is not set"); } if (m_sound_names->size() != static_cast(sound_count())) { - throw std::runtime_error("/seq/3: repeat-expr size mismatch"); + throw std::runtime_error("/seq/2: repeat-expr size mismatch"); } for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { if ((*it).size() != static_cast(17)) { - throw std::runtime_error("/seq/3: size mismatch"); + throw std::runtime_error("/seq/2: size mismatch"); } } if (m__unnamed4.size() != static_cast(2)) { diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.h b/src/main/file/kaitai/generated/mpc2000xl_aps.h index 07283fa7..5ad8face 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.h +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.h @@ -390,10 +390,8 @@ class mpc2000xl_aps_t : public kaitai::kstruct { public: std::string magic() const { return m_magic; } void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } - uint8_t sound_count() const { return m_sound_count; } - void set_sound_count(uint8_t _v) { m__dirty = true; m_sound_count = std::move(_v); } - std::string _unnamed2() const { return m__unnamed2; } - void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + uint16_t sound_count() const { return m_sound_count; } + void set_sound_count(uint16_t _v) { m__dirty = true; m_sound_count = std::move(_v); } std::vector* sound_names() const { return m_sound_names.get(); } void set_sound_names(std::unique_ptr> _v) { m__dirty = true; m_sound_names = std::move(_v); } std::string _unnamed4() const { return m__unnamed4; } @@ -433,8 +431,7 @@ class mpc2000xl_aps_t : public kaitai::kstruct { private: std::string m_magic; - uint8_t m_sound_count; - std::string m__unnamed2; + uint16_t m_sound_count; std::unique_ptr> m_sound_names; std::string m__unnamed4; std::string m_name; diff --git a/src/test/ApsParserTest.cpp b/src/test/ApsParserTest.cpp deleted file mode 100644 index 892d4b78..00000000 --- a/src/test/ApsParserTest.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include - -#include "TestMpc.hpp" -#include "sampler/Sampler.hpp" -#include "file/aps/ApsParser.hpp" - -#include "performance/PerformanceManager.hpp" -#include "sampler/Pad.hpp" - -TEST_CASE("APS with maximum number of sounds", "[apsparser]") -{ - const uint16_t MAX_SOUND_COUNT = 256; - - mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpc(mpc); - - for (uint16_t i = 0; i < MAX_SOUND_COUNT; i++) - { - auto sound = mpc.getSampler()->addSound(); - assert(sound != nullptr); - } - - assert(mpc.getSampler()->getSoundCount() == MAX_SOUND_COUNT); - - mpc::file::aps::ApsParser apsParserSave(mpc, "FOO"); - - mpc.getSampler()->purge(); - - assert(mpc.getSampler()->getSoundCount() == 0); - - mpc::file::aps::ApsParser apsParserLoad(apsParserSave.saveBytes); - - REQUIRE(apsParserLoad.getSoundNames().size() == MAX_SOUND_COUNT); -} - -TEST_CASE("APS with program with unassigned pad", "[apsparser]") -{ - mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpc(mpc); - - const auto manager = mpc.getPerformanceManager().lock(); - - mpc.getSampler() - ->getProgram(mpc::MinProgramIndex) - ->getPad(mpc::MinProgramPadIndex) - ->setNote(mpc::NoDrumNoteAssigned); - - manager->drainQueue(); - - mpc::file::aps::ApsParser apsParserSave(mpc, "FOO"); - - mpc.getSampler()->deleteAllPrograms(true); - - manager->drainQueue(); - manager->drainQueue(); - - assert(mpc.getSampler() - ->getProgram(mpc::MinProgramIndex) - ->getPad(mpc::MinProgramPadIndex) - ->getNote() != mpc::NoDrumNoteAssigned); - - mpc::file::aps::ApsParser apsParserLoad(apsParserSave.saveBytes); - - manager->drainQueue(); - - REQUIRE(apsParserLoad.getPrograms()[0]->assignTable->get()[0] == - mpc::NoDrumNoteAssigned); -} diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index 3dd5fbec..1d10e95b 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -9,11 +9,6 @@ #include "engine/EngineHost.hpp" #include "engine/StereoMixer.hpp" #include "file/kaitai/ApsIo.hpp" -#include "file/aps/ApsDrumConfiguration.hpp" -#include "file/aps/ApsGlobalParameters.hpp" -#include "file/aps/ApsNoteParameters.hpp" -#include "file/aps/ApsParser.hpp" -#include "file/aps/ApsSlider.hpp" #include "file/kaitai/generated/mpc2000xl_aps.h" #include "lcdgui/screens/DrumScreen.hpp" #include "lcdgui/screens/MixerSetupScreen.hpp" @@ -306,7 +301,7 @@ TEST_CASE("Kaitai MPC2000 APS parses and rewrites real 2KXL ALL_PGMS", "[kaitai- REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); } -TEST_CASE("Kaitai MPC2000 APS matches handwritten APS bytes", "[kaitai-aps]") +TEST_CASE("Kaitai MPC2000 APS saves and reloads ALL_PGMS through production seam", "[kaitai-aps]") { mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); @@ -315,11 +310,10 @@ TEST_CASE("Kaitai MPC2000 APS matches handwritten APS bytes", "[kaitai-aps]") REQUIRE(mpc.getSampler()->getProgramCount() == 2); REQUIRE(mpc.getSampler()->getSoundCount() == 3); - mpc::file::aps::ApsParser handwrittenWriter(mpc, "ALL_PGMS"); - const auto handwrittenBytes = handwrittenWriter.getBytes(); + const auto directKaitaiBytes = mpc::file::kaitai::ApsIo::save(mpc, "ALL_PGMS"); std::stringstream parseStream( - std::string(handwrittenBytes.begin(), handwrittenBytes.end()), + std::string(directKaitaiBytes.begin(), directKaitaiBytes.end()), std::ios::in | std::ios::out | std::ios::binary ); kaitai::kstream parseIo(&parseStream); @@ -345,9 +339,11 @@ TEST_CASE("Kaitai MPC2000 APS matches handwritten APS bytes", "[kaitai-aps]") parsed._write(); const auto kaitaiBytes = writeStream.str(); - REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); - INFO(describeFirstByteDiff(kaitaiBytes, std::string(handwrittenBytes.begin(), handwrittenBytes.end()))); - REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); + REQUIRE(kaitaiBytes.size() == directKaitaiBytes.size()); + INFO(describeFirstByteDiff( + kaitaiBytes, + std::string(directKaitaiBytes.begin(), directKaitaiBytes.end()))); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), directKaitaiBytes.begin())); auto sampler = mpc.getSampler(); sampler->deleteAllPrograms(false); @@ -391,16 +387,6 @@ TEST_CASE("Kaitai MPC2000 APS saves MIDI program change separately from slider c mpc.getPerformanceManager().lock()->drainQueue(); REQUIRE(p1->getMidiProgramChange() == 2); p1->getSlider()->setControlChange(0); - mpc::file::aps::ApsParser handwrittenWriterZero(mpc, "ALL_PGMS"); - const auto handwrittenBytesWithZeroControl = handwrittenWriterZero.getBytes(); - std::stringstream handwrittenParseStreamZero( - std::string(handwrittenBytesWithZeroControl.begin(), handwrittenBytesWithZeroControl.end()), - std::ios::in | std::ios::out | std::ios::binary - ); - kaitai::kstream handwrittenParseIoZero(&handwrittenParseStreamZero); - mpc2000xl_aps_t handwrittenParsedZero(&handwrittenParseIoZero); - handwrittenParsedZero._read(); - REQUIRE(handwrittenParsedZero.aps_programs()->at(0)->body()->program_change() == 1); const auto bytesWithZeroControl = mpc::file::kaitai::ApsIo::save(mpc, "ALL_PGMS"); @@ -450,7 +436,7 @@ TEST_CASE("Kaitai MPC2000 APS loads real 2KXL ALL_PGMS through production seam", REQUIRE(p1->getNoteParameters(36)->getSoundIndex() == -1); } -TEST_CASE("ApsParser reads upper-bound MIDI program change", "[kaitai-aps]") +TEST_CASE("Kaitai APS rewrite preserves upper-bound MIDI program change", "[kaitai-aps]") { auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/ApsLoading/ALL_PGMS.APS"); @@ -474,9 +460,14 @@ TEST_CASE("ApsParser reads upper-bound MIDI program change", "[kaitai-aps]") parsed._write(); const auto rewrittenBytes = writeStream.str(); - std::vector apsBytes(rewrittenBytes.begin(), rewrittenBytes.end()); - mpc::file::aps::ApsParser handwrittenParser(apsBytes); - REQUIRE(handwrittenParser.getPrograms().at(0)->getSlider()->getProgramChange() == 127); + std::stringstream reparsedStream( + rewrittenBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream reparsedIo(&reparsedStream); + mpc2000xl_aps_t reparsed(&reparsedIo); + reparsed._read(); + REQUIRE(reparsed.aps_programs()->at(0)->body()->program_change() == 127); } TEST_CASE("ApsLoader loads upper-bound MIDI program change", "[kaitai-aps]") @@ -549,7 +540,7 @@ TEST_CASE("ApsLoader loads mutated note tune", "[kaitai-aps]") REQUIRE(p1->getNoteParameters(35)->getTune() == -120); } -TEST_CASE("ApsParser reads broad mutated APS semantics", "[kaitai-aps]") +TEST_CASE("Kaitai APS parses broad mutated APS semantics", "[kaitai-aps]") { const auto apsBytes = rewriteAllPgmsApsWithMutations(applyBroadApsMutation); INFO("raw pad_assign byte=0x" @@ -565,64 +556,121 @@ TEST_CASE("ApsParser reads broad mutated APS semantics", "[kaitai-aps]") << std::hex << std::setw(2) << std::setfill('0') << static_cast(static_cast(apsBytes.at(1757)))); - mpc::file::aps::ApsParser handwrittenParser(apsBytes); - auto programs = handwrittenParser.getPrograms(); - REQUIRE(programs.size() >= 1U); + std::stringstream parseStream( + std::string(apsBytes.begin(), apsBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); - auto* p1 = programs.at(0); - REQUIRE(p1->getName() == "PROGRAM1"); - REQUIRE(p1->getAssignTable()->get().at(0) == 50); - REQUIRE(p1->getSlider()->getNote() == 52); - REQUIRE(p1->getSlider()->getTuneLow() == -119); - REQUIRE(p1->getSlider()->getTuneHigh() == 118); - REQUIRE(p1->getSlider()->getDecayLow() == 11); - REQUIRE(p1->getSlider()->getDecayHigh() == 12); - REQUIRE(p1->getSlider()->getAttackLow() == 13); - REQUIRE(p1->getSlider()->getAttackHigh() == 14); - REQUIRE(p1->getSlider()->getFilterLow() == -15); - REQUIRE(p1->getSlider()->getFilterHigh() == 16); - REQUIRE(p1->getSlider()->getProgramChange() == 126); - - auto* note35 = p1->getNoteParameters(0); - REQUIRE(note35->getSoundIndex() == -1); - REQUIRE(note35->getSoundGenerationMode() == 2); - REQUIRE(note35->getVelocityRangeLower() == 1); - REQUIRE(note35->getAlsoPlay1() == 41); - REQUIRE(note35->getVelocityRangeUpper() == 127); - REQUIRE(note35->getAlsoPlay2() == 42); - REQUIRE(note35->getVoiceOverlapMode() == mpc::sampler::VoiceOverlapMode::NOTE_OFF); - REQUIRE(note35->getMute1() == 43); - REQUIRE(note35->getMute2() == 44); - REQUIRE(note35->getTune() == -120); - REQUIRE(note35->getAttack() == 99); - REQUIRE(note35->getDecay() == 98); - REQUIRE(note35->getDecayMode() == 1); - REQUIRE(note35->getCutoffFrequency() == 17); - REQUIRE(note35->getResonance() == 18); - REQUIRE(note35->getVelocityToFilterAttack() == 19); - REQUIRE(note35->getVelocityToFilterDecay() == 20); - REQUIRE(note35->getVelocityToFilterAmount() == 21); - REQUIRE(note35->getVelocityToLevel() == 22); - REQUIRE(note35->getVelocityToAttack() == 23); - REQUIRE(note35->getVelocityToStart() == 24); - REQUIRE(note35->getVelocityToFilterFrequency() == 25); - REQUIRE(note35->getSliderParameter() == 3); - REQUIRE(note35->getVelocityToPitch() == 26); + REQUIRE(parsed.aps_programs()->size() >= 1U); - auto* drum0 = handwrittenParser.getDrumConfiguration(0); - REQUIRE(drum0->getProgramIndex() == 1); - REQUIRE(!drum0->isReceivePgmChangeEnabled()); - REQUIRE(!drum0->isReceiveMidiVolumeEnabled()); - - auto* globals = handwrittenParser.getGlobalParameters(); - REQUIRE(globals->isPadToIntSoundEnabled()); - REQUIRE(globals->isPadAssignMaster()); - REQUIRE(globals->isIndivFxSourceDrum()); - REQUIRE(globals->isStereoMixSourceDrum()); - REQUIRE(globals->isRecordMixChangesEnabled()); - REQUIRE(!globals->isCopyPgmMixToDrumEnabled()); - REQUIRE(globals->getFxDrum() == 3); - REQUIRE(globals->getMasterLevel() == 2); + auto* p1 = parsed.aps_programs()->at(0)->body(); + REQUIRE(p1->name().substr(0, 8) == "PROGRAM1"); + REQUIRE(p1->pad_to_note_mapping()->at(0) == 50); + REQUIRE(p1->slider()->note() == 52); + REQUIRE(p1->slider()->tune_low() == -119); + REQUIRE(p1->slider()->tune_high() == 118); + REQUIRE(p1->slider()->decay_low() == 11); + REQUIRE(p1->slider()->decay_high() == 12); + REQUIRE(p1->slider()->attack_low() == 13); + REQUIRE(p1->slider()->attack_high() == 14); + REQUIRE(p1->slider()->filter_low() == -15); + REQUIRE(p1->slider()->filter_high() == 16); + REQUIRE(p1->program_change() == 126); + + auto* note35 = p1->note_parameters()->at(0).get(); + REQUIRE(note35->sound_index() == 255); + REQUIRE(note35->sound_generation_mode() == mpc2000xl_pgm_t::SOUND_GENERATION_MODE_VEL_SW); + REQUIRE(note35->velocity_range_lower() == 1); + REQUIRE(note35->also_play_use_note_1() == 41); + REQUIRE(note35->velocity_range_upper() == 127); + REQUIRE(note35->also_play_use_note_2() == 42); + REQUIRE(note35->voice_overlap_mode() == mpc2000xl_pgm_t::VOICE_OVERLAP_MODE_NOTE_OFF); + REQUIRE(note35->mute_assign_1() == 43); + REQUIRE(note35->mute_assign_2() == 44); + REQUIRE(note35->tune() == -120); + REQUIRE(note35->attack() == 99); + REQUIRE(note35->decay() == 98); + REQUIRE(note35->decay_mode() == mpc2000xl_pgm_t::DECAY_MODE_START); + REQUIRE(note35->cutoff() == 17); + REQUIRE(note35->resonance() == 18); + REQUIRE(note35->velocity_envelope_to_filter_attack() == 19); + REQUIRE(note35->velocity_envelope_to_filter_decay() == 20); + REQUIRE(note35->velocity_envelope_to_filter_amount() == 21); + REQUIRE(note35->velocity_to_level() == 22); + REQUIRE(note35->velocity_to_attack() == 23); + REQUIRE(note35->velocity_to_start() == 24); + REQUIRE(note35->velocity_to_cutoff() == 25); + REQUIRE(note35->slider_parameter() == mpc2000xl_pgm_t::SLIDER_PARAMETER_FILTER); + REQUIRE(note35->velocity_to_pitch() == 26); + + auto* drum0 = parsed.drum1(); + REQUIRE(drum0->program() == 1); + REQUIRE(drum0->receive_program_change() == mpc2000xl_aps_t::NO_YES_FALSE); + REQUIRE(drum0->receive_midi_volume() == mpc2000xl_aps_t::NO_YES_FALSE); + + auto* globals = parsed.global_parameters(); + REQUIRE(globals->pad_to_internal_sound() == mpc2000xl_aps_t::NO_YES_TRUE); + REQUIRE(globals->pad_assign() == mpc2000xl_aps_t::PAD_ASSIGN_MASTERS); + REQUIRE(globals->indiv_fx_source() == mpc2000xl_aps_t::MIX_SOURCE_DRUM); + REQUIRE(globals->stereo_mix_source() == mpc2000xl_aps_t::MIX_SOURCE_DRUM); + REQUIRE(globals->record_mix_changes() == mpc2000xl_aps_t::NO_YES_TRUE); + REQUIRE(globals->copy_pgm_mix_to_drum() == mpc2000xl_aps_t::NO_YES_FALSE); + REQUIRE(globals->fx_drum() == 3); + REQUIRE(globals->master_level() == 2); +} + +TEST_CASE("Kaitai APS saves maximum sound count in 16-bit header", "[kaitai-aps]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + for (uint16_t i = 0; i < 256; ++i) + { + auto sound = mpc.getSampler()->addSound(); + REQUIRE(sound != nullptr); + sound->setName("S" + std::to_string(i)); + } + + const auto apsBytes = mpc::file::kaitai::ApsIo::save(mpc, "MAXSOUNDS"); + + std::stringstream parseStream( + std::string(apsBytes.begin(), apsBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.sound_count() == 256); + REQUIRE(parsed.sound_names()->size() == 256U); +} + +TEST_CASE("Kaitai APS saves unassigned pad mapping", "[kaitai-aps]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + const auto manager = mpc.getPerformanceManager().lock(); + mpc.getSampler() + ->getProgram(mpc::MinProgramIndex) + ->getPad(mpc::MinProgramPadIndex) + ->setNote(mpc::NoDrumNoteAssigned); + manager->drainQueue(); + + const auto apsBytes = mpc::file::kaitai::ApsIo::save(mpc, "UNASSIGN"); + + std::stringstream parseStream( + std::string(apsBytes.begin(), apsBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_aps_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.aps_programs()->at(0)->body()->pad_to_note_mapping()->at(0) == 34); } TEST_CASE("ApsLoader loads broad mutated APS semantics", "[kaitai-aps]") From c452d78a652c46be6b0e4802773ee38e381ff145 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sun, 21 Jun 2026 14:04:34 +0200 Subject: [PATCH 23/52] Remove handwritten PGM and SND implementations --- src/main/AutoSave.cpp | 43 ++-- src/main/disk/AbstractDisk.cpp | 17 -- src/main/disk/AbstractDisk.hpp | 9 - src/main/disk/PgmFileToProgramConverter.cpp | 191 ------------------ src/main/disk/PgmFileToProgramConverter.hpp | 49 ----- src/main/disk/ProgramLoader.cpp | 1 - src/main/disk/SoundLoader.cpp | 2 - src/main/file/kaitai/SndIo.cpp | 11 +- src/main/file/kaitai/SndIo.hpp | 5 + src/main/file/pgmreader/PRMixer.cpp | 78 ------- src/main/file/pgmreader/PRMixer.hpp | 41 ---- src/main/file/pgmreader/PRPads.cpp | 46 ----- src/main/file/pgmreader/PRPads.hpp | 38 ---- src/main/file/pgmreader/PRSlider.cpp | 99 --------- src/main/file/pgmreader/PRSlider.hpp | 47 ----- .../file/pgmreader/PgmAllNoteParameters.cpp | 191 ------------------ .../file/pgmreader/PgmAllNoteParameters.hpp | 54 ----- src/main/file/pgmreader/PgmHeader.cpp | 39 ---- src/main/file/pgmreader/PgmHeader.hpp | 26 --- src/main/file/pgmreader/ProgramFileReader.cpp | 76 ------- src/main/file/pgmreader/ProgramFileReader.hpp | 51 ----- src/main/file/pgmreader/ProgramName.cpp | 58 ------ src/main/file/pgmreader/ProgramName.hpp | 39 ---- src/main/file/pgmreader/SoundNames.cpp | 53 ----- src/main/file/pgmreader/SoundNames.hpp | 35 ---- src/main/file/pgmwriter/MidiNotes.cpp | 183 ----------------- src/main/file/pgmwriter/MidiNotes.hpp | 56 ----- src/main/file/pgmwriter/Mixer.cpp | 66 ------ src/main/file/pgmwriter/Mixer.hpp | 40 ---- src/main/file/pgmwriter/PWHeader.cpp | 35 ---- src/main/file/pgmwriter/PWHeader.hpp | 22 -- src/main/file/pgmwriter/PWSlider.cpp | 87 -------- src/main/file/pgmwriter/PWSlider.hpp | 44 ---- src/main/file/pgmwriter/Pads.cpp | 53 ----- src/main/file/pgmwriter/Pads.hpp | 33 --- src/main/file/pgmwriter/PgmName.cpp | 29 --- src/main/file/pgmwriter/PgmName.hpp | 33 --- src/main/file/pgmwriter/PgmWriter.cpp | 66 ------ src/main/file/pgmwriter/PgmWriter.hpp | 32 --- src/main/file/pgmwriter/SampleNames.cpp | 89 -------- src/main/file/pgmwriter/SampleNames.hpp | 44 ---- src/main/file/sndreader/SndHeaderReader.cpp | 106 ---------- src/main/file/sndreader/SndHeaderReader.hpp | 34 ---- src/main/file/sndreader/SndReader.cpp | 118 ----------- src/main/file/sndreader/SndReader.hpp | 47 ----- src/main/file/sndwriter/SndHeaderWriter.cpp | 101 --------- src/main/file/sndwriter/SndHeaderWriter.hpp | 38 ---- src/main/file/sndwriter/SndWriter.cpp | 119 ----------- src/main/file/sndwriter/SndWriter.hpp | 46 ----- src/test/KaitaiPgmTest.cpp | 174 +++++----------- src/test/KaitaiSndTest.cpp | 94 ++++----- src/test/SndPersistenceTest.cpp | 19 +- 52 files changed, 131 insertions(+), 2976 deletions(-) delete mode 100644 src/main/disk/PgmFileToProgramConverter.cpp delete mode 100644 src/main/disk/PgmFileToProgramConverter.hpp delete mode 100644 src/main/file/pgmreader/PRMixer.cpp delete mode 100644 src/main/file/pgmreader/PRMixer.hpp delete mode 100644 src/main/file/pgmreader/PRPads.cpp delete mode 100644 src/main/file/pgmreader/PRPads.hpp delete mode 100644 src/main/file/pgmreader/PRSlider.cpp delete mode 100644 src/main/file/pgmreader/PRSlider.hpp delete mode 100644 src/main/file/pgmreader/PgmAllNoteParameters.cpp delete mode 100644 src/main/file/pgmreader/PgmAllNoteParameters.hpp delete mode 100644 src/main/file/pgmreader/PgmHeader.cpp delete mode 100644 src/main/file/pgmreader/PgmHeader.hpp delete mode 100644 src/main/file/pgmreader/ProgramFileReader.cpp delete mode 100644 src/main/file/pgmreader/ProgramFileReader.hpp delete mode 100644 src/main/file/pgmreader/ProgramName.cpp delete mode 100644 src/main/file/pgmreader/ProgramName.hpp delete mode 100644 src/main/file/pgmreader/SoundNames.cpp delete mode 100644 src/main/file/pgmreader/SoundNames.hpp delete mode 100644 src/main/file/pgmwriter/MidiNotes.cpp delete mode 100644 src/main/file/pgmwriter/MidiNotes.hpp delete mode 100644 src/main/file/pgmwriter/Mixer.cpp delete mode 100644 src/main/file/pgmwriter/Mixer.hpp delete mode 100644 src/main/file/pgmwriter/PWHeader.cpp delete mode 100644 src/main/file/pgmwriter/PWHeader.hpp delete mode 100644 src/main/file/pgmwriter/PWSlider.cpp delete mode 100644 src/main/file/pgmwriter/PWSlider.hpp delete mode 100644 src/main/file/pgmwriter/Pads.cpp delete mode 100644 src/main/file/pgmwriter/Pads.hpp delete mode 100644 src/main/file/pgmwriter/PgmName.cpp delete mode 100644 src/main/file/pgmwriter/PgmName.hpp delete mode 100644 src/main/file/pgmwriter/PgmWriter.cpp delete mode 100644 src/main/file/pgmwriter/PgmWriter.hpp delete mode 100644 src/main/file/pgmwriter/SampleNames.cpp delete mode 100644 src/main/file/pgmwriter/SampleNames.hpp delete mode 100644 src/main/file/sndreader/SndHeaderReader.cpp delete mode 100644 src/main/file/sndreader/SndHeaderReader.hpp delete mode 100644 src/main/file/sndreader/SndReader.cpp delete mode 100644 src/main/file/sndreader/SndReader.hpp delete mode 100644 src/main/file/sndwriter/SndHeaderWriter.cpp delete mode 100644 src/main/file/sndwriter/SndHeaderWriter.hpp delete mode 100644 src/main/file/sndwriter/SndWriter.cpp delete mode 100644 src/main/file/sndwriter/SndWriter.hpp diff --git a/src/main/AutoSave.cpp b/src/main/AutoSave.cpp index 9f44971b..78907755 100644 --- a/src/main/AutoSave.cpp +++ b/src/main/AutoSave.cpp @@ -12,8 +12,7 @@ #include "FileIoPolicy.hpp" #include "file/ByteUtil.hpp" #include "file/kaitai/ApsIo.hpp" -#include "file/sndreader/SndReader.hpp" -#include "file/sndwriter/SndWriter.hpp" +#include "file/kaitai/SndIo.hpp" #include "lcdgui/screens/VmpcAutoSaveScreen.hpp" #include "lcdgui/screens/window/VmpcContinuePreviousSessionScreen.hpp" #include "lcdgui/screens/window/SaveAllFileScreen.hpp" @@ -42,8 +41,6 @@ using namespace mpc; using namespace mpc::file_io; using namespace mpc::file; using namespace mpc::file::all; -using namespace mpc::file::sndwriter; -using namespace mpc::file::sndreader; using namespace mpc::lcdgui; using namespace mpc::lcdgui::screens; using namespace mpc::lcdgui::screens::window; @@ -142,6 +139,12 @@ bool isValidAutoSaveSndData(const std::vector &data) static_cast(frameCount) * channelCount * sizeof(int16_t); return rangeFits(data.size(), sndHeaderSize, sampleDataBytes); } + +std::string stripExtension(const std::string &fileName) +{ + const auto dotPos = fileName.find_last_of('.'); + return dotPos == std::string::npos ? fileName : fileName.substr(0, dotPos); +} } // namespace void AutoSave::restoreAutoSavedState(Mpc &mpc, @@ -337,25 +340,21 @@ void AutoSave::restoreAutoSavedState(Mpc &mpc, soundName + "'"); continue; } - SndReader sndReader(soundData); - auto sound = mpc.getSampler()->addSound( - sndReader.getSampleRate()); + auto sound = mpc.getSampler()->addSound(); if (!sound) { break; } - - sound->setMono(sndReader.isMono()); - sndReader.readData(sound->getMutableSampleData()); - sound->setName(sndReader.getName()); - sound->setTune(sndReader.getTune()); - sound->setLevel(sndReader.getLevel()); - sound->setStart(sndReader.getStart()); - sound->setEnd(sndReader.getEnd()); - sound->setLoopTo(sound->getEnd() - - sndReader.getLoopLength()); - sound->setBeatCount(sndReader.getNumberOfBeats()); - sound->setLoopEnabled(sndReader.isLoopEnabled()); + const auto loadResult = file::kaitai::SndIo::loadBytes( + soundData, + sound, + stripExtension(soundName)); + if (!loadResult) + { + mpc.getSampler()->deleteSoundWithoutRepairingPrograms(sound); + MLOG("AutoSave restore skipped corrupt file '" + + soundName + "'"); + } } } else @@ -623,10 +622,8 @@ void AutoSave::storeAutoSavedState( for (auto &sound : mpc.getSampler()->getSounds()) { const auto sndPath = sound->getName() + ".SND"; - SndWriter sndWriter(sound.get()); - if (!writeRequired(sndPath, - {sndWriter.getSndFileArray().begin(), - sndWriter.getSndFileArray().end()})) + const auto soundBytes = file::kaitai::SndIo::saveSound(*sound); + if (!writeRequired(sndPath, soundBytes)) { layeredScreen->closeCurrentScreen(); return; diff --git a/src/main/disk/AbstractDisk.cpp b/src/main/disk/AbstractDisk.cpp index 653769fd..af5825c8 100644 --- a/src/main/disk/AbstractDisk.cpp +++ b/src/main/disk/AbstractDisk.cpp @@ -10,9 +10,6 @@ #include "file/wav/WavFile.hpp" #include "file/mid/MidiWriter.hpp" #include "file/mid/MidiReader.hpp" -#include "file/pgmwriter/PgmWriter.hpp" -#include "file/sndwriter/SndWriter.hpp" -#include "file/sndreader/SndReader.hpp" #include "file/all/AllParser.hpp" #include "file/kaitai/SndIo.hpp" #include "file/kaitai/PgmIo.hpp" @@ -44,10 +41,7 @@ using namespace mpc::input::midi; using namespace mpc::file; using namespace mpc::file::wav; -using namespace mpc::file::sndwriter; -using namespace mpc::file::sndreader; using namespace mpc::file::mid; -using namespace mpc::file::pgmwriter; using namespace mpc::file::all; using namespace mpc::lcdgui; @@ -571,17 +565,6 @@ sound_or_error AbstractDisk::readWav2( return performRequiredIoOrOpenErrorPopup(readFunc); } -sound_or_error AbstractDisk::readSnd2( - std::shared_ptr f, - std::function)> onSuccess) -{ - const std::function readFunc = [f, onSuccess] - { - return onSuccess(std::make_shared(f.get())); - }; - return performRequiredIoOrOpenErrorPopup(readFunc); -} - sequence_or_error AbstractDisk::readMid2(std::shared_ptr f) { const std::function readFunc = [this, f]() -> sequence_or_error diff --git a/src/main/disk/AbstractDisk.hpp b/src/main/disk/AbstractDisk.hpp index a23c4168..7a7a1b9b 100644 --- a/src/main/disk/AbstractDisk.hpp +++ b/src/main/disk/AbstractDisk.hpp @@ -44,11 +44,6 @@ namespace mpc::file::wav class WavFile; } -namespace mpc::file::sndreader -{ - class SndReader; -} - namespace mpc::disk { @@ -173,10 +168,6 @@ namespace mpc::disk std::shared_ptr, std::function)> onSuccess); - sound_or_error - readSnd2(std::shared_ptr, - std::function)>); sequence_or_error readMid2(std::shared_ptr); void readAps2(std::shared_ptr, std::function onSuccess, diff --git a/src/main/disk/PgmFileToProgramConverter.cpp b/src/main/disk/PgmFileToProgramConverter.cpp deleted file mode 100644 index 9ad0208c..00000000 --- a/src/main/disk/PgmFileToProgramConverter.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "disk/PgmFileToProgramConverter.hpp" - -#include "Mpc.hpp" -#include "file/pgmreader/PRMixer.hpp" -#include "file/pgmreader/PRPads.hpp" -#include "file/pgmreader/PgmAllNoteParameters.hpp" -#include "file/pgmreader/PgmHeader.hpp" -#include "file/pgmreader/ProgramFileReader.hpp" -#include "file/pgmreader/ProgramName.hpp" -#include "file/pgmreader/PRSlider.hpp" -#include "file/pgmreader/SoundNames.hpp" -#include "sampler/Pad.hpp" -#include "sampler/Program.hpp" -#include "sampler/PgmSlider.hpp" -#include "sampler/NoteParameters.hpp" - -#include "disk/MpcFile.hpp" - -#include "StrUtil.hpp" - -#include -#include - -#include "engine/IndivFxMixer.hpp" -#include "engine/StereoMixer.hpp" -#include "performance/PerformanceManager.hpp" - -using namespace mpc::disk; -using namespace mpc::sampler; -using namespace mpc::file::pgmreader; - -void PgmFileToProgramConverter::setSlider( - const ProgramFileReader &reader, const std::shared_ptr &program) -{ - const auto slider = reader.getSlider(); - const auto nn = slider->getMidiNoteAssign() == 0 - ? NoDrumNoteAssigned - : DrumNoteNumber(slider->getMidiNoteAssign()); - const auto pgmSlider = program->getSlider(); - pgmSlider->setAssignNote(nn); - pgmSlider->setAttackHighRange(slider->getAttackHigh()); - pgmSlider->setAttackLowRange(slider->getAttackLow()); - pgmSlider->setDecayHighRange(slider->getDecayHigh()); - pgmSlider->setDecayLowRange(slider->getDecayLow()); - pgmSlider->setFilterHighRange(slider->getFilterHigh()); - pgmSlider->setFilterLowRange(slider->getFilterLow()); - pgmSlider->setTuneHighRange(slider->getTuneHigh()); - pgmSlider->setTuneLowRange(slider->getTuneLow()); -} - -void PgmFileToProgramConverter::setNoteParameters( - mpc::Mpc &mpc, const ProgramFileReader &reader, - const std::shared_ptr &program) -{ - const auto pgmNoteParameters = reader.getAllNoteParameters(); - const auto pgmPads = reader.getPads(); - - std::array - allPerfNoteParams; - - for (int programPadIndex = 0; - programPadIndex < Mpc2000XlSpecs::PROGRAM_PAD_COUNT; ++programPadIndex) - { - const auto padNote = pgmPads->getNote(programPadIndex); - const auto note = padNote == -1 ? NoDrumNoteAssigned : padNote; - program->getPad(programPadIndex)->setNote(DrumNoteNumber(note)); - - auto &perfNoteParams = allPerfNoteParams[programPadIndex]; - - perfNoteParams.attack = pgmNoteParameters->getAttack(programPadIndex); - perfNoteParams.decay = pgmNoteParameters->getDecay(programPadIndex); - perfNoteParams.decayMode = - pgmNoteParameters->getDecayMode(programPadIndex); - perfNoteParams.filterAttack = - pgmNoteParameters->getVelEnvToFiltAtt(programPadIndex); - perfNoteParams.filterDecay = - pgmNoteParameters->getVelEnvToFiltDec(programPadIndex); - perfNoteParams.filterEnvelopeAmount = - pgmNoteParameters->getVelEnvToFiltAmt(programPadIndex); - perfNoteParams.filterFrequency = - pgmNoteParameters->getCutoff(programPadIndex); - perfNoteParams.filterResonance = - pgmNoteParameters->getResonance(programPadIndex); - perfNoteParams.muteAssignA = - DrumNoteNumber(pgmNoteParameters->getMuteAssign1(programPadIndex)); - perfNoteParams.muteAssignB = - DrumNoteNumber(pgmNoteParameters->getMuteAssign2(programPadIndex)); - perfNoteParams.optionalNoteA = - DrumNoteNumber(pgmNoteParameters->getAlsoPlayUse1(programPadIndex)); - perfNoteParams.optionalNoteB = - DrumNoteNumber(pgmNoteParameters->getAlsoPlayUse2(programPadIndex)); - - const auto sampleSelect = - pgmNoteParameters->getSampleSelect(programPadIndex); - - perfNoteParams.soundIndex = sampleSelect == 255 ? -1 : sampleSelect; - - perfNoteParams.sliderParameterNumber = - pgmNoteParameters->getSliderParameter(programPadIndex); - perfNoteParams.soundGenerationMode = - pgmNoteParameters->getSoundGenerationMode(programPadIndex); - perfNoteParams.tune = pgmNoteParameters->getTune(programPadIndex); - perfNoteParams.velocityRangeLower = - pgmNoteParameters->getVelocityRangeLower(programPadIndex); - perfNoteParams.velocityRangeUpper = - pgmNoteParameters->getVelocityRangeUpper(programPadIndex); - perfNoteParams.velocityToAttack = - pgmNoteParameters->getVelocityToAttack(programPadIndex); - perfNoteParams.velocityToFilterFrequency = - pgmNoteParameters->getVelocityToCutoff(programPadIndex); - perfNoteParams.velocityToLevel = - pgmNoteParameters->getVelocityToLevel(programPadIndex); - perfNoteParams.velocityToPitch = - pgmNoteParameters->getVelocityToPitch(programPadIndex); - perfNoteParams.velocityToStart = - pgmNoteParameters->getVelocityToStart(programPadIndex); - perfNoteParams.voiceOverlapMode = - pgmNoteParameters->getVoiceOverlapMode(programPadIndex); - } - - performance::UpdateAllNoteParametersBulk msg{program->getProgramIndex(), - allPerfNoteParams}; - mpc.getPerformanceManager().lock()->enqueue(msg); -} - -void PgmFileToProgramConverter::setMixer( - const ProgramFileReader &reader, const std::shared_ptr &program) -{ - const auto pgmMixer = reader.getMixer(); - - for (int i = 0; i < 64; i++) - { - const auto noteParameters = program->getNoteParameters(i + 35); - const auto stereoMixer = noteParameters->getStereoMixer(); - const auto indivFxMixer = noteParameters->getIndivFxMixer(); - - stereoMixer->setLevel(DrumMixerLevel(pgmMixer->getVolume(i))); - stereoMixer->setPanning(DrumMixerPanning(pgmMixer->getPan(i))); - indivFxMixer->setVolumeIndividualOut( - DrumMixerLevel(pgmMixer->getVolumeIndividual(i))); - indivFxMixer->setOutput( - DrumMixerIndividualOutput(pgmMixer->getOutput(i))); - indivFxMixer->setFxPath( - DrumMixerIndividualFxPath(pgmMixer->getEffectsOutput(i))); - indivFxMixer->setFxSendLevel( - DrumMixerLevel(pgmMixer->getEffectsSendLevel(i))); - } -} - -program_or_error PgmFileToProgramConverter::loadFromFileAndConvert( - mpc::Mpc &mpc, const std::shared_ptr &f, - std::shared_ptr program, std::vector &soundNames) -{ - if (!f->exists()) - { - throw std::invalid_argument("File does not exist"); - } - - const ProgramFileReader reader(f); - - if (!reader.getHeader()->verifyMagic()) - { - throw std::invalid_argument("PGM first 2 bytes are incorrect"); - } - - const auto pgmSoundNames = reader.getSampleNames(); - - for (int i = 0; i < reader.getHeader()->getSoundCount(); i++) - { - soundNames.push_back(pgmSoundNames->getSampleName(i)); - } - - const std::string programNameInData = - StrUtil::trim(reader.getProgramName()->getProgramNameASCII()); - - if (StrUtil::eqIgnoreCase(programNameInData, f->getNameWithoutExtension())) - { - program->setName(programNameInData); - } - else - { - program->setName(f->getNameWithoutExtension()); - } - - setNoteParameters(mpc, reader, program); - setMixer(reader, program); - setSlider(reader, program); - program->setMidiProgramChange(reader.getSlider()->getProgramChange() + 1); - - return program; -} diff --git a/src/main/disk/PgmFileToProgramConverter.hpp b/src/main/disk/PgmFileToProgramConverter.hpp deleted file mode 100644 index 53988648..00000000 --- a/src/main/disk/PgmFileToProgramConverter.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include -#include -#include -#include "mpc_types.hpp" - -namespace mpc -{ - class Mpc; -} - -namespace mpc::sampler -{ - class Sampler; - class Program; -} // namespace mpc::sampler - -namespace mpc::file::pgmreader -{ - class ProgramFileReader; -} - -namespace mpc::disk -{ - class MpcFile; -} - -namespace mpc::disk -{ - class PgmFileToProgramConverter - { - public: - static program_or_error - loadFromFileAndConvert(mpc::Mpc &, const std::shared_ptr &, - std::shared_ptr, - std::vector &soundNames); - - private: - static void setSlider(const file::pgmreader::ProgramFileReader &, - const std::shared_ptr &); - static void - setNoteParameters(mpc::Mpc &, - const file::pgmreader::ProgramFileReader &, - const std::shared_ptr &); - static void setMixer(const file::pgmreader::ProgramFileReader &, - const std::shared_ptr &); - }; -} // namespace mpc::disk diff --git a/src/main/disk/ProgramLoader.cpp b/src/main/disk/ProgramLoader.cpp index e3444317..4d1bb99d 100644 --- a/src/main/disk/ProgramLoader.cpp +++ b/src/main/disk/ProgramLoader.cpp @@ -5,7 +5,6 @@ #include "disk/AbstractDisk.hpp" #include "disk/MpcFile.hpp" #include "file/kaitai/PgmIo.hpp" -#include "disk/PgmFileToProgramConverter.hpp" #include "disk/SoundLoader.hpp" #include "sampler/Program.hpp" diff --git a/src/main/disk/SoundLoader.cpp b/src/main/disk/SoundLoader.cpp index 69722cf3..e0cd7f73 100644 --- a/src/main/disk/SoundLoader.cpp +++ b/src/main/disk/SoundLoader.cpp @@ -5,7 +5,6 @@ #include "disk/AbstractDisk.hpp" #include "file/wav/WavFile.hpp" #include "file/kaitai/SndIo.hpp" -#include "file/sndreader/SndReader.hpp" #include "sampler/Sampler.hpp" #include "sampler/Sound.hpp" #include "lcdgui/screens/VmpcSettingsScreen.hpp" @@ -15,7 +14,6 @@ using namespace mpc::sampler; using namespace mpc::disk; using namespace mpc::file::wav; -using namespace mpc::file::sndreader; using namespace mpc::lcdgui; using namespace mpc::lcdgui::screens; diff --git a/src/main/file/kaitai/SndIo.cpp b/src/main/file/kaitai/SndIo.cpp index 136492a9..5b2027e4 100644 --- a/src/main/file/kaitai/SndIo.cpp +++ b/src/main/file/kaitai/SndIo.cpp @@ -10,12 +10,10 @@ using namespace mpc::file::kaitai; using namespace mpc::sampleops; -sound_or_error SndIo::loadSound(const std::shared_ptr &file, +sound_or_error SndIo::loadBytes(const std::vector &bytes, const std::shared_ptr &sound, const std::string &nameWithoutExtension) { - const auto bytes = file->getBytes(); - std::stringstream parseStream( std::string(bytes.begin(), bytes.end()), std::ios::in | std::ios::out | std::ios::binary @@ -64,6 +62,13 @@ sound_or_error SndIo::loadSound(const std::shared_ptr &file, return sound; } +sound_or_error SndIo::loadSound(const std::shared_ptr &file, + const std::shared_ptr &sound, + const std::string &nameWithoutExtension) +{ + return loadBytes(file->getBytes(), sound, nameWithoutExtension); +} + std::vector SndIo::saveSound(mpc::sampler::Sound &sound) { mpc2000snd_t parsed(nullptr); diff --git a/src/main/file/kaitai/SndIo.hpp b/src/main/file/kaitai/SndIo.hpp index ef357403..84aeee66 100644 --- a/src/main/file/kaitai/SndIo.hpp +++ b/src/main/file/kaitai/SndIo.hpp @@ -21,6 +21,11 @@ namespace mpc::file::kaitai class SndIo { public: + static sound_or_error loadBytes( + const std::vector &, + const std::shared_ptr &, + const std::string &nameWithoutExtension); + static sound_or_error loadSound( const std::shared_ptr &, const std::shared_ptr &, diff --git a/src/main/file/pgmreader/PRMixer.cpp b/src/main/file/pgmreader/PRMixer.cpp deleted file mode 100644 index e35ca4da..00000000 --- a/src/main/file/pgmreader/PRMixer.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "file/pgmreader/PRMixer.hpp" - -#include "file/pgmreader/ProgramFileReader.hpp" -#include "file/pgmreader/SoundNames.hpp" - -#include "Util.hpp" - -using namespace mpc::file::pgmreader; - -Mixer::Mixer(ProgramFileReader *programFile) -{ - this->programFile = programFile; -} - -int Mixer::getSampleNamesSize() const -{ - auto sampleNamesSize = programFile->getSampleNames()->getSampleNamesSize(); - return sampleNamesSize; -} - -int Mixer::getMixerStart() -{ - auto mixerStart = 4 + getSampleNamesSize() + 2 + 17 + 9 + 6 + 1601; - return mixerStart; -} - -int Mixer::getMixerEnd() -{ - auto mixerEnd = 4 + getSampleNamesSize() + 2 + 17 + 9 + 6 + 1601 + 387; - return mixerEnd; -} - -std::vector Mixer::getMixerArray() -{ - auto pgmFileArray = programFile->readProgramFileArray(); - if (mixerArray.size() == 0) - { - mixerArray = - Util::vecCopyOfRange(pgmFileArray, getMixerStart(), getMixerEnd()); - } - return mixerArray; -} - -int Mixer::getEffectsOutput(int noteIndex) -{ - auto effectsOutput = getMixerArray()[noteIndex * 6 + 0]; - return effectsOutput; -} - -int Mixer::getVolume(int noteIndex) -{ - auto volume = getMixerArray()[noteIndex * 6 + 1]; - return volume; -} - -int Mixer::getPan(int noteIndex) -{ - auto pan = getMixerArray()[noteIndex * 6 + 2]; - return pan; -} - -int Mixer::getVolumeIndividual(int noteIndex) -{ - auto volumeIndividual = getMixerArray()[noteIndex * 6 + 3]; - return volumeIndividual; -} - -int Mixer::getOutput(int noteIndex) -{ - auto output = getMixerArray()[noteIndex * 6 + 4]; - return output; -} - -int Mixer::getEffectsSendLevel(int noteIndex) -{ - auto effectsSendLevel = getMixerArray()[noteIndex * 6 + 5]; - return effectsSendLevel; -} diff --git a/src/main/file/pgmreader/PRMixer.hpp b/src/main/file/pgmreader/PRMixer.hpp deleted file mode 100644 index a2bd08be..00000000 --- a/src/main/file/pgmreader/PRMixer.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - namespace file - { - namespace pgmreader - { - - class ProgramFileReader; - - class Mixer - { - - public: - std::vector mixerArray{}; - - private: - ProgramFileReader *programFile{}; - - public: - int getSampleNamesSize() const; - int getMixerStart(); - int getMixerEnd(); - std::vector getMixerArray(); - - int getEffectsOutput(int note); - int getVolume(int note); - int getPan(int note); - int getVolumeIndividual(int note); - int getOutput(int note); - int getEffectsSendLevel(int note); - - Mixer(ProgramFileReader *programFile); - }; - - } // namespace pgmreader - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmreader/PRPads.cpp b/src/main/file/pgmreader/PRPads.cpp deleted file mode 100644 index c4da745f..00000000 --- a/src/main/file/pgmreader/PRPads.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "file/pgmreader/PRPads.hpp" - -#include "file/pgmreader/PgmAllNoteParameters.hpp" -#include "file/pgmreader/ProgramFileReader.hpp" -#include "file/pgmreader/SoundNames.hpp" - -#include "Util.hpp" - -using namespace mpc::file::pgmreader; - -Pads::Pads(ProgramFileReader *programFile) -{ - this->programFile = programFile; -} - -int Pads::getSampleNamesSize() -{ - sampleNamesSize = programFile->getSampleNames()->getSampleNamesSize(); - return sampleNamesSize; -} - -int Pads::getPadsStart() -{ - auto padsStart = 4 + getSampleNamesSize() + 2 + 17 + 9 + 6 + 1601 + 387; - return padsStart; -} - -int Pads::getPadsEnd() -{ - auto padsEnd = 4 + getSampleNamesSize() + 2 + 17 + 9 + 6 + 1601 + 387 + 264; - return padsEnd; -} - -std::vector Pads::getPadsArray() -{ - auto pgmFileArray = programFile->readProgramFileArray(); - padsArray = - Util::vecCopyOfRange(pgmFileArray, getPadsStart(), getPadsEnd()); - return padsArray; -} - -int Pads::getNote(int pad) -{ - int padMidiNote = getPadsArray()[pad]; - return padMidiNote; -} diff --git a/src/main/file/pgmreader/PRPads.hpp b/src/main/file/pgmreader/PRPads.hpp deleted file mode 100644 index 1e2c09fb..00000000 --- a/src/main/file/pgmreader/PRPads.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - namespace file - { - namespace pgmreader - { - - class ProgramFileReader; - - class Pads - { - - public: - int sampleNamesSize{0}; - - std::vector padsArray{}; - - private: - ProgramFileReader *programFile{}; - - public: - int getSampleNamesSize(); - int getPadsStart(); - int getPadsEnd(); - std::vector getPadsArray(); - - int getNote(int pad); - - Pads(ProgramFileReader *programFile); - }; - - } // namespace pgmreader - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmreader/PRSlider.cpp b/src/main/file/pgmreader/PRSlider.cpp deleted file mode 100644 index 76ffdc44..00000000 --- a/src/main/file/pgmreader/PRSlider.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "file/pgmreader/PRSlider.hpp" - -#include "file/pgmreader/ProgramFileReader.hpp" -#include "file/pgmreader/SoundNames.hpp" - -#include "Util.hpp" - -using namespace mpc::file::pgmreader; - -Slider::Slider(ProgramFileReader *programFile) -{ - this->programFile = programFile; -} - -int Slider::getSampleNamesSize() -{ - sampleNamesSize = programFile->getSampleNames()->getSampleNamesSize(); - return sampleNamesSize; -} - -int Slider::getSliderStart() -{ - int sliderStart = 4 + getSampleNamesSize() + 2 + 17; - return sliderStart; -} - -int Slider::getSliderEnd() -{ - auto sliderEnd = 4 + getSampleNamesSize() + 2 + 17 + 10 + 5; - return sliderEnd; -} - -std::vector Slider::getSliderArray() -{ - auto pgmFileArray = programFile->readProgramFileArray(); - sliderArray = - Util::vecCopyOfRange(pgmFileArray, getSliderStart(), getSliderEnd()); - return sliderArray; -} - -int Slider::getMidiNoteAssign() -{ - const auto midiNoteAssign = getSliderArray()[0]; - return midiNoteAssign; -} - -int Slider::getTuneLow() -{ - auto tuneLow = getSliderArray()[1]; - return tuneLow; -} - -int Slider::getTuneHigh() -{ - auto tuneHigh = getSliderArray()[2]; - return tuneHigh; -} - -int Slider::getDecayLow() -{ - auto decayLow = getSliderArray()[3]; - return decayLow; -} - -int Slider::getDecayHigh() -{ - auto decayHigh = getSliderArray()[4]; - return decayHigh; -} - -int Slider::getAttackLow() -{ - auto attackLow = getSliderArray()[5]; - return attackLow; -} - -int Slider::getAttackHigh() -{ - auto attackHigh = getSliderArray()[6]; - return attackHigh; -} - -int Slider::getFilterLow() -{ - auto filterLow = getSliderArray()[7]; - return filterLow; -} - -int Slider::getFilterHigh() -{ - auto filterHigh = getSliderArray()[8]; - return filterHigh; -} - -int Slider::getProgramChange() -{ - auto programChange = getSliderArray()[9]; - return programChange; -} diff --git a/src/main/file/pgmreader/PRSlider.hpp b/src/main/file/pgmreader/PRSlider.hpp deleted file mode 100644 index 73f0c8f0..00000000 --- a/src/main/file/pgmreader/PRSlider.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - namespace file - { - namespace pgmreader - { - - class ProgramFileReader; - - class Slider - { - - public: - int sampleNamesSize{0}; - - std::vector sliderArray{}; - - private: - ProgramFileReader *programFile{}; - - public: - int getSampleNamesSize(); - int getSliderStart(); - int getSliderEnd(); - std::vector getSliderArray(); - - int getMidiNoteAssign(); - int getTuneLow(); - int getTuneHigh(); - int getDecayLow(); - int getDecayHigh(); - int getAttackLow(); - int getAttackHigh(); - int getFilterLow(); - int getFilterHigh(); - int getProgramChange(); - - Slider(ProgramFileReader *programFile); - }; - - } // namespace pgmreader - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmreader/PgmAllNoteParameters.cpp b/src/main/file/pgmreader/PgmAllNoteParameters.cpp deleted file mode 100644 index 96bf89e1..00000000 --- a/src/main/file/pgmreader/PgmAllNoteParameters.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "sampler/VoiceOverlapMode.hpp" -#include "file/pgmreader/PgmAllNoteParameters.hpp" - -#include "file/pgmreader/PRPads.hpp" -#include "file/pgmreader/ProgramFileReader.hpp" -#include "file/pgmreader/SoundNames.hpp" - -#include "file/ByteUtil.hpp" - -#include "Util.hpp" - -using namespace mpc::file::pgmreader; - -PgmAllNoteParameters::PgmAllNoteParameters(ProgramFileReader *programFile) -{ - this->programFile = programFile; -} - -int PgmAllNoteParameters::getSampleNamesSize() -{ - sampleNamesSize = programFile->getSampleNames()->getSampleNamesSize(); - return sampleNamesSize; -} - -int PgmAllNoteParameters::getMidiNotesStart() -{ - auto midiNotesStart = 4 + getSampleNamesSize() + 2 + 17 + 9 + 6; - return midiNotesStart; -} - -int PgmAllNoteParameters::getMidiNotesEnd() -{ - auto midiNotesEnd = 4 + getSampleNamesSize() + 2 + 17 + 9 + 6 + 1601; - return midiNotesEnd; -} - -std::vector PgmAllNoteParameters::getMidiNotesArray() -{ - auto pgmFileArray = programFile->readProgramFileArray(); - midiNotesArray = Util::vecCopyOfRange(pgmFileArray, getMidiNotesStart(), - getMidiNotesEnd()); - return midiNotesArray; -} - -int PgmAllNoteParameters::getSampleSelect(int midiNote) -{ - int sampleSelect = getMidiNotesArray()[midiNote * 25 + 0]; - return sampleSelect; -} - -int PgmAllNoteParameters::getSoundGenerationMode(int midiNote) -{ - auto soundGenerationMode = getMidiNotesArray()[midiNote * 25 + 1]; - return soundGenerationMode; -} - -int PgmAllNoteParameters::getVelocityRangeLower(int midiNote) -{ - auto velocityRangeLower = getMidiNotesArray()[midiNote * 25 + 2]; - return velocityRangeLower; -} - -int PgmAllNoteParameters::getAlsoPlayUse1(int midiNote) -{ - auto alsoPlayUse1 = getMidiNotesArray()[midiNote * 25 + 3]; - return alsoPlayUse1; -} - -int PgmAllNoteParameters::getVelocityRangeUpper(int midiNote) -{ - auto velocityRangeUpper = getMidiNotesArray()[midiNote * 25 + 4]; - return velocityRangeUpper; -} - -int PgmAllNoteParameters::getAlsoPlayUse2(int midiNote) -{ - auto alsoPlayUse2 = getMidiNotesArray()[midiNote * 25 + 5]; - return alsoPlayUse2; -} - -mpc::sampler::VoiceOverlapMode -PgmAllNoteParameters::getVoiceOverlapMode(int midiNote) -{ - auto voiceOverlapMode = getMidiNotesArray()[midiNote * 25 + 6]; - return static_cast(voiceOverlapMode); -} - -int PgmAllNoteParameters::getMuteAssign1(int midiNote) -{ - auto muteAssign1 = getMidiNotesArray()[midiNote * 25 + 7]; - return muteAssign1 == 0 ? 34 : muteAssign1; -} - -int PgmAllNoteParameters::getMuteAssign2(int midiNote) -{ - auto muteAssign2 = getMidiNotesArray()[midiNote * 25 + 8]; - return muteAssign2 == 0 ? 34 : muteAssign2; -} - -int PgmAllNoteParameters::getTune(int midiNote) -{ - auto startPos = midiNote * 25 + 9; - auto endPos = midiNote * 25 + 11; - auto tuneBytes = - Util::vecCopyOfRange(getMidiNotesArray(), startPos, endPos); - return ByteUtil::bytes2short(tuneBytes); -} - -int PgmAllNoteParameters::getAttack(int midiNote) -{ - auto attack = getMidiNotesArray()[midiNote * 25 + 11]; - return attack; -} - -int PgmAllNoteParameters::getDecay(int midiNote) -{ - auto decay = getMidiNotesArray()[midiNote * 25 + 12]; - return decay; -} - -int PgmAllNoteParameters::getDecayMode(int midiNote) -{ - auto decayMode = getMidiNotesArray()[midiNote * 25 + 13]; - return decayMode; -} - -int PgmAllNoteParameters::getCutoff(int midiNote) -{ - auto cutoff = getMidiNotesArray()[midiNote * 25 + 14]; - return cutoff; -} - -int PgmAllNoteParameters::getResonance(int midiNote) -{ - auto resonance = getMidiNotesArray()[midiNote * 25 + 15]; - return resonance; -} - -int PgmAllNoteParameters::getVelEnvToFiltAtt(int midiNote) -{ - auto velEnvToFiltAtt = getMidiNotesArray()[midiNote * 25 + 16]; - return velEnvToFiltAtt; -} - -int PgmAllNoteParameters::getVelEnvToFiltDec(int midiNote) -{ - auto velEnvToFiltDec = getMidiNotesArray()[midiNote * 25 + 17]; - return velEnvToFiltDec; -} - -int PgmAllNoteParameters::getVelEnvToFiltAmt(int midiNote) -{ - auto velEnvToFiltAmt = getMidiNotesArray()[midiNote * 25 + 18]; - return velEnvToFiltAmt; -} - -int PgmAllNoteParameters::getVelocityToLevel(int midiNote) -{ - auto velocityToLevel = getMidiNotesArray()[midiNote * 25 + 19]; - return velocityToLevel; -} - -int PgmAllNoteParameters::getVelocityToAttack(int midiNote) -{ - auto velocityToAttack = getMidiNotesArray()[midiNote * 25 + 20]; - return velocityToAttack; -} - -int PgmAllNoteParameters::getVelocityToStart(int midiNote) -{ - auto velocityToStart = getMidiNotesArray()[midiNote * 25 + 21]; - return velocityToStart; -} - -int PgmAllNoteParameters::getVelocityToCutoff(int midiNote) -{ - auto velocityToCutoff = getMidiNotesArray()[midiNote * 25 + 22]; - return velocityToCutoff; -} - -int PgmAllNoteParameters::getSliderParameter(int midiNote) -{ - auto sliderParameter = getMidiNotesArray()[midiNote * 25 + 23]; - return sliderParameter; -} - -int PgmAllNoteParameters::getVelocityToPitch(int midiNote) -{ - auto velocityToPitch = getMidiNotesArray()[midiNote * 25 + 24]; - return velocityToPitch; -} diff --git a/src/main/file/pgmreader/PgmAllNoteParameters.hpp b/src/main/file/pgmreader/PgmAllNoteParameters.hpp deleted file mode 100644 index 8fe0c535..00000000 --- a/src/main/file/pgmreader/PgmAllNoteParameters.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "sampler/VoiceOverlapMode.hpp" -#include - -namespace mpc::file::pgmreader -{ - class ProgramFileReader; - - class PgmAllNoteParameters - { - - public: - int sampleNamesSize = 0; - - private: - std::vector midiNotesArray; - - ProgramFileReader *programFile; - - public: - int getSampleNamesSize(); - int getMidiNotesStart(); - int getMidiNotesEnd(); - std::vector getMidiNotesArray(); - - int getSampleSelect(int midiNote); - int getSoundGenerationMode(int midiNote); - int getVelocityRangeLower(int midiNote); - int getAlsoPlayUse1(int midiNote); - int getVelocityRangeUpper(int midiNote); - int getAlsoPlayUse2(int midiNote); - sampler::VoiceOverlapMode getVoiceOverlapMode(int midiNote); - int getMuteAssign1(int midiNote); - int getMuteAssign2(int midiNote); - int getTune(int midiNote); - int getAttack(int midiNote); - int getDecay(int midiNote); - int getDecayMode(int midiNote); - int getCutoff(int midiNote); - int getResonance(int midiNote); - int getVelEnvToFiltAtt(int midiNote); - int getVelEnvToFiltDec(int midiNote); - int getVelEnvToFiltAmt(int midiNote); - int getVelocityToLevel(int midiNote); - int getVelocityToAttack(int midiNote); - int getVelocityToStart(int midiNote); - int getVelocityToCutoff(int midiNote); - int getSliderParameter(int midiNote); - int getVelocityToPitch(int midiNote); - - PgmAllNoteParameters(ProgramFileReader *programFile); - }; -} // namespace mpc::file::pgmreader diff --git a/src/main/file/pgmreader/PgmHeader.cpp b/src/main/file/pgmreader/PgmHeader.cpp deleted file mode 100644 index f78ebd48..00000000 --- a/src/main/file/pgmreader/PgmHeader.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "PgmHeader.hpp" - -#include "MpcSpecs.hpp" - -#include "file/pgmreader/ProgramFileReader.hpp" - -#include "file/ByteUtil.hpp" -#include "Util.hpp" - -#include - -using namespace mpc::file::pgmreader; - -PgmHeader::PgmHeader(ProgramFileReader *programFile) -{ - auto pgmFileArray = programFile->readProgramFileArray(); - headerArray = Util::vecCopyOfRange(pgmFileArray, 0, 4); -} - -std::vector PgmHeader::getHeaderArray() -{ - return headerArray; -} - -bool PgmHeader::verifyMagic() const -{ - return headerArray[0] == PGM_HEADER_MAGIC[0] && - headerArray[1] == PGM_HEADER_MAGIC[1]; -} - -const uint16_t PgmHeader::getSoundCount() -{ - const auto result = - ByteUtil::bytes2ushort({headerArray[2], headerArray[3]}); - - assert(result <= Mpc2000XlSpecs::MAX_SOUND_COUNT_IN_MEMORY); - - return result; -} diff --git a/src/main/file/pgmreader/PgmHeader.hpp b/src/main/file/pgmreader/PgmHeader.hpp deleted file mode 100644 index 5bb442af..00000000 --- a/src/main/file/pgmreader/PgmHeader.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::pgmreader -{ - - class ProgramFileReader; - - class PgmHeader - { - - const std::vector PGM_HEADER_MAGIC{0x07, 0x04}; - std::vector headerArray; - - public: - std::vector getHeaderArray(); - - bool verifyMagic() const; - - const uint16_t getSoundCount(); - - PgmHeader(ProgramFileReader *programFile); - }; -} // namespace mpc::file::pgmreader diff --git a/src/main/file/pgmreader/ProgramFileReader.cpp b/src/main/file/pgmreader/ProgramFileReader.cpp deleted file mode 100644 index 5b9df1f5..00000000 --- a/src/main/file/pgmreader/ProgramFileReader.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "file/pgmreader/ProgramFileReader.hpp" - -#include "disk/MpcFile.hpp" -#include "file/pgmreader/PRMixer.hpp" -#include "file/pgmreader/PRPads.hpp" -#include "file/pgmreader/PgmAllNoteParameters.hpp" -#include "file/pgmreader/PgmHeader.hpp" -#include "file/pgmreader/ProgramName.hpp" -#include "file/pgmreader/PRSlider.hpp" -#include "file/pgmreader/SoundNames.hpp" - -using namespace mpc::file::pgmreader; - -ProgramFileReader::ProgramFileReader( - const std::weak_ptr &_programFile) - : programFile(_programFile) -{ - pgmHeader = new PgmHeader(this); - programName = new ProgramName(this); - sampleNames = new SoundNames(this); - midiNotes = new PgmAllNoteParameters(this); - mixer = new Mixer(this); - slider = new Slider(this); - pads = new Pads(this); -} - -ProgramFileReader::~ProgramFileReader() -{ - delete pgmHeader; - delete programName; - delete sampleNames; - delete midiNotes; - delete mixer; - delete slider; - delete pads; -} - -std::vector ProgramFileReader::readProgramFileArray() const -{ - return programFile.lock()->getBytes(); -} - -PgmHeader *ProgramFileReader::getHeader() const -{ - return pgmHeader; -} - -SoundNames *ProgramFileReader::getSampleNames() const -{ - return sampleNames; -} - -PgmAllNoteParameters *ProgramFileReader::getAllNoteParameters() const -{ - return midiNotes; -} - -Mixer *ProgramFileReader::getMixer() const -{ - return mixer; -} - -Pads *ProgramFileReader::getPads() const -{ - return pads; -} - -ProgramName *ProgramFileReader::getProgramName() const -{ - return programName; -} - -Slider *ProgramFileReader::getSlider() const -{ - return slider; -} diff --git a/src/main/file/pgmreader/ProgramFileReader.hpp b/src/main/file/pgmreader/ProgramFileReader.hpp deleted file mode 100644 index 9c00edc3..00000000 --- a/src/main/file/pgmreader/ProgramFileReader.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::disk -{ - class MpcFile; -} - -namespace mpc::file::pgmreader -{ - class PgmHeader; - class SoundNames; - class ProgramName; - class PgmAllNoteParameters; - class Mixer; - class Slider; - class Pads; -} // namespace mpc::file::pgmreader - -namespace mpc::file::pgmreader -{ - - class ProgramFileReader - { - - PgmHeader *pgmHeader; - SoundNames *sampleNames; - ProgramName *programName; - PgmAllNoteParameters *midiNotes; - Mixer *mixer; - Slider *slider; - Pads *pads; - std::weak_ptr programFile; - - public: - std::vector readProgramFileArray() const; - - PgmHeader *getHeader() const; - SoundNames *getSampleNames() const; - PgmAllNoteParameters *getAllNoteParameters() const; - Mixer *getMixer() const; - Pads *getPads() const; - ProgramName *getProgramName() const; - Slider *getSlider() const; - - ProgramFileReader(const std::weak_ptr &); - ~ProgramFileReader(); - }; -} // namespace mpc::file::pgmreader diff --git a/src/main/file/pgmreader/ProgramName.cpp b/src/main/file/pgmreader/ProgramName.cpp deleted file mode 100644 index 364128fb..00000000 --- a/src/main/file/pgmreader/ProgramName.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "file/pgmreader/ProgramName.hpp" - -#include "file/pgmreader/ProgramFileReader.hpp" -#include "file/pgmreader/SoundNames.hpp" - -#include "Util.hpp" - -using namespace mpc::file::pgmreader; - -ProgramName::ProgramName(ProgramFileReader *programFile) -{ - this->programFile = programFile; -} - -int ProgramName::getSampleNamesSize() -{ - sampleNamesSize = programFile->getSampleNames()->getSampleNamesSize(); - return sampleNamesSize; -} - -int ProgramName::getProgramNameStart() -{ - auto programNameStart = 4 + getSampleNamesSize() + 2; - return programNameStart; -} - -int ProgramName::getProgramNameEnd() -{ - auto programNameEnd = 4 + getSampleNamesSize() + 2 + 17; - return programNameEnd; -} - -std::vector ProgramName::getProgramNameArray() -{ - auto pgmFileArray = programFile->readProgramFileArray(); - programNameArray = Util::vecCopyOfRange(pgmFileArray, getProgramNameStart(), - getProgramNameEnd()); - return programNameArray; -} - -std::string ProgramName::getProgramNameASCII() -{ - std::string programNameASCII; - auto bytes = getProgramNameArray(); - for (char c : bytes) - { - if (c == 0x00) - { - break; - } - programNameASCII.push_back(c); - } - if (programNameASCII.length() > 16) - { - programNameASCII = programNameASCII.substr(0, 16); - } - return programNameASCII; -} diff --git a/src/main/file/pgmreader/ProgramName.hpp b/src/main/file/pgmreader/ProgramName.hpp deleted file mode 100644 index e43f3884..00000000 --- a/src/main/file/pgmreader/ProgramName.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc -{ - namespace file - { - namespace pgmreader - { - - class ProgramFileReader; - - class ProgramName - { - - public: - int sampleNamesSize{0}; - - std::vector programNameArray{}; - - private: - ProgramFileReader *programFile{}; - - public: - int getSampleNamesSize(); - int getProgramNameStart(); - int getProgramNameEnd(); - std::vector getProgramNameArray(); - - std::string getProgramNameASCII(); - - ProgramName(ProgramFileReader *programFile); - }; - - } // namespace pgmreader - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmreader/SoundNames.cpp b/src/main/file/pgmreader/SoundNames.cpp deleted file mode 100644 index e6bb6706..00000000 --- a/src/main/file/pgmreader/SoundNames.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "file/pgmreader/SoundNames.hpp" - -#include "file/pgmreader/PgmHeader.hpp" -#include "file/pgmreader/ProgramFileReader.hpp" - -#include "Util.hpp" - -using namespace mpc::file::pgmreader; - -SoundNames::SoundNames(ProgramFileReader *programFile) -{ - this->programFile = programFile; -} - -int SoundNames::getSampleNamesSize() const -{ - int sampleNamesSize = programFile->getHeader()->getSoundCount() * 17; - return sampleNamesSize; -} - -std::vector SoundNames::getSampleNamesArray() -{ - auto sampleNamesSize = getSampleNamesSize(); - auto pgmFileArray = programFile->readProgramFileArray(); - sampleNamesArray = - Util::vecCopyOfRange(pgmFileArray, 4, 4 + sampleNamesSize + 2); - return sampleNamesArray; -} - -std::string SoundNames::getSampleName(int sampleNumber) -{ - std::string sampleNameString; - auto h = programFile->getHeader(); - if (sampleNumber < h->getSoundCount()) - { - sampleNamesArray = getSampleNamesArray(); - auto sampleName = Util::vecCopyOfRange( - sampleNamesArray, sampleNumber * 17, sampleNumber * 17 + 16); - for (char c : sampleName) - { - if (c == 0x00) - { - break; - } - sampleNameString.push_back(c); - } - } - else - { - sampleNameString = "OFF"; - } - return sampleNameString; -} diff --git a/src/main/file/pgmreader/SoundNames.hpp b/src/main/file/pgmreader/SoundNames.hpp deleted file mode 100644 index 0a31f3ae..00000000 --- a/src/main/file/pgmreader/SoundNames.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc -{ - namespace file - { - namespace pgmreader - { - - class ProgramFileReader; - - class SoundNames - { - - public: - std::vector sampleNamesArray{}; - - private: - ProgramFileReader *programFile{}; - - public: - int getSampleNamesSize() const; - std::vector getSampleNamesArray(); - - std::string getSampleName(int sampleNumber); - - SoundNames(ProgramFileReader *programFile); - }; - - } // namespace pgmreader - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmwriter/MidiNotes.cpp b/src/main/file/pgmwriter/MidiNotes.cpp deleted file mode 100644 index 47afd601..00000000 --- a/src/main/file/pgmwriter/MidiNotes.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "file/pgmwriter/MidiNotes.hpp" - -#include "sampler/NoteParameters.hpp" -#include "sampler/Program.hpp" - -using namespace mpc::file::pgmwriter; - -MidiNotes::MidiNotes(sampler::Program *program, - const std::vector &snConvTable) -{ - midiNotesArray = std::vector(1601); - - for (int i = 0; i < 64; i++) - { - auto nn = program->getNoteParameters(i + 35); - - if (nn->getSoundIndex() == -1) - { - setSampleSelect(i, 255); - } - else - { - setSampleSelect(i, snConvTable[nn->getSoundIndex()]); - } - - setSoundGenerationMode(i, nn->getSoundGenerationMode()); - setVelocityRangeLower(i, nn->getVelocityRangeLower()); - setAlsoPlayUse1(i, nn->getOptionalNoteA()); - setVelocityRangeUpper(i, nn->getVelocityRangeUpper()); - setAlsoPlayUse2(i, nn->getOptionalNoteB()); - setVoiceOverlapMode(i, nn->getVoiceOverlapMode()); - setMuteAssign1(i, - nn->getMuteAssignA() == 34 ? 0 : nn->getMuteAssignA()); - setMuteAssign2(i, - nn->getMuteAssignB() == 34 ? 0 : nn->getMuteAssignB()); - setTune(i, static_cast(nn->getTune())); - setAttack(i, nn->getAttack()); - setDecay(i, nn->getDecay()); - setDecayMode(i, nn->getDecayMode()); - setCutoff(i, nn->getFilterFrequency()); - setResonance(i, nn->getFilterResonance()); - setVelEnvToFiltAtt(i, nn->getFilterAttack()); - setVelEnvToFiltDec(i, nn->getFilterDecay()); - setVelEnvToFiltAmt(i, nn->getFilterEnvelopeAmount()); - setVelocityToLevel(i, nn->getVeloToLevel()); - setVelocityToAttack(i, nn->getVelocityToAttack()); - setVelocityToStart(i, nn->getVelocityToStart()); - setVelocityToCutoff(i, nn->getVelocityToFilterFrequency()); - setSliderParameter(i, nn->getSliderParameterNumber()); - setVelocityToPitch(i, nn->getVelocityToPitch()); - } - - midiNotesArray[1600] = 6; -} - -void MidiNotes::setSampleSelect(int midiNote, int sampleNumber) -{ - char sampleSelect = sampleNumber; - midiNotesArray[midiNote * 25 + 0] = sampleSelect; -} - -void MidiNotes::setSoundGenerationMode(int midiNote, int soundGenerationMode) -{ - midiNotesArray[midiNote * 25 + 1] = soundGenerationMode; -} - -void MidiNotes::setVelocityRangeLower(int midiNote, int velocityRangeLower) -{ - midiNotesArray[midiNote * 25 + 2] = velocityRangeLower; -} - -void MidiNotes::setAlsoPlayUse1(int midiNote, int alsoPlayUse1) -{ - midiNotesArray[midiNote * 25 + 3] = alsoPlayUse1; -} - -void MidiNotes::setVelocityRangeUpper(int midiNote, int velocityRangeUpper) -{ - midiNotesArray[midiNote * 25 + 4] = velocityRangeUpper; -} - -void MidiNotes::setAlsoPlayUse2(int midiNote, int alsoPlayUse2) -{ - midiNotesArray[midiNote * 25 + 5] = alsoPlayUse2; -} - -void MidiNotes::setVoiceOverlapMode( - int midiNote, const sampler::VoiceOverlapMode voiceOverlapMode) -{ - midiNotesArray[midiNote * 25 + 6] = static_cast(voiceOverlapMode); -} - -void MidiNotes::setMuteAssign1(int midiNote, int muteAssign1) -{ - midiNotesArray[midiNote * 25 + 7] = muteAssign1; -} - -void MidiNotes::setMuteAssign2(int midiNote, int muteAssign2) -{ - midiNotesArray[midiNote * 25 + 8] = muteAssign2; -} - -void MidiNotes::setTune(int midiNote, int16_t tune) -{ - auto startPos = midiNote * 25 + 9; - setShort(midiNotesArray, startPos, tune); -} - -void MidiNotes::setAttack(int midiNote, int attack) -{ - midiNotesArray[midiNote * 25 + 11] = attack; -} - -void MidiNotes::setDecay(int midiNote, int decay) -{ - midiNotesArray[midiNote * 25 + 12] = decay; -} - -void MidiNotes::setDecayMode(int midiNote, int decayMode) -{ - midiNotesArray[midiNote * 25 + 13] = decayMode; -} - -void MidiNotes::setCutoff(int midiNote, int cutoff) -{ - midiNotesArray[midiNote * 25 + 14] = cutoff; -} - -void MidiNotes::setResonance(int midiNote, int resonance) -{ - midiNotesArray[midiNote * 25 + 15] = resonance; -} - -void MidiNotes::setVelEnvToFiltAtt(int midiNote, int velEnvToFiltAtt) -{ - midiNotesArray[midiNote * 25 + 16] = velEnvToFiltAtt; -} - -void MidiNotes::setVelEnvToFiltDec(int midiNote, int velEnvToFiltDec) -{ - midiNotesArray[midiNote * 25 + 17] = velEnvToFiltDec; -} - -void MidiNotes::setVelEnvToFiltAmt(int midiNote, int velEnvToFiltAmt) -{ - midiNotesArray[midiNote * 25 + 18] = velEnvToFiltAmt; -} - -void MidiNotes::setVelocityToLevel(int midiNote, int velocityToLevel) -{ - midiNotesArray[midiNote * 25 + 19] = velocityToLevel; -} - -void MidiNotes::setVelocityToAttack(int midiNote, int velocityToAttack) -{ - midiNotesArray[midiNote * 25 + 20] = velocityToAttack; -} - -void MidiNotes::setVelocityToStart(int midiNote, int velocityToStart) -{ - midiNotesArray[midiNote * 25 + 21] = velocityToStart; -} - -void MidiNotes::setVelocityToCutoff(int midiNote, int velocityToCutoff) -{ - midiNotesArray[midiNote * 25 + 22] = velocityToCutoff; -} - -void MidiNotes::setSliderParameter(int midiNote, int sliderParameter) -{ - midiNotesArray[midiNote * 25 + 23] = sliderParameter; -} - -void MidiNotes::setVelocityToPitch(int midiNote, int velocityToPitch) -{ - midiNotesArray[midiNote * 25 + 24] = velocityToPitch; -} - -void MidiNotes::setShort(std::vector &ca, int offset, int16_t s) const -{ - ca[offset] = s; - ca[offset + 1] = s >> 8; -} diff --git a/src/main/file/pgmwriter/MidiNotes.hpp b/src/main/file/pgmwriter/MidiNotes.hpp deleted file mode 100644 index 8278dfe1..00000000 --- a/src/main/file/pgmwriter/MidiNotes.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include - -#ifdef __linux__ -#include -#endif // __linux__ - -#include "sampler/VoiceOverlapMode.hpp" - -namespace mpc::sampler -{ - class Program; -} - -namespace mpc::file::pgmwriter -{ - - class MidiNotes - { - - public: - std::vector midiNotesArray; - - private: - void setSampleSelect(int midiNote, int sampleNumber); - void setSoundGenerationMode(int midiNote, int soundGenerationMode); - void setVelocityRangeLower(int midiNote, int velocityRangeLower); - void setAlsoPlayUse1(int midiNote, int alsoPlayUse1); - void setVelocityRangeUpper(int midiNote, int velocityRangeUpper); - void setAlsoPlayUse2(int midiNote, int alsoPlayUse2); - void setVoiceOverlapMode(int midiNote, const sampler::VoiceOverlapMode); - void setMuteAssign1(int midiNote, int muteAssign1); - void setMuteAssign2(int midiNote, int muteAssign2); - void setTune(int midiNote, int16_t tune); - void setAttack(int midiNote, int attack); - void setDecay(int midiNote, int decay); - void setDecayMode(int midiNote, int decayMode); - void setCutoff(int midiNote, int cutoff); - void setResonance(int midiNote, int resonance); - void setVelEnvToFiltAtt(int midiNote, int velEnvToFiltAtt); - void setVelEnvToFiltDec(int midiNote, int velEnvToFiltDec); - void setVelEnvToFiltAmt(int midiNote, int velEnvToFiltAmt); - void setVelocityToLevel(int midiNote, int velocityToLevel); - void setVelocityToAttack(int midiNote, int velocityToAttack); - void setVelocityToStart(int midiNote, int velocityToStart); - void setVelocityToCutoff(int midiNote, int velocityToCutoff); - void setSliderParameter(int midiNote, int sliderParameter); - void setVelocityToPitch(int midiNote, int velocityToPitch); - void setShort(std::vector &ca, int offset, int16_t s) const; - - public: - MidiNotes(sampler::Program *program, - const std::vector &snConvTable); - }; -} // namespace mpc::file::pgmwriter diff --git a/src/main/file/pgmwriter/Mixer.cpp b/src/main/file/pgmwriter/Mixer.cpp deleted file mode 100644 index ad375f62..00000000 --- a/src/main/file/pgmwriter/Mixer.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "file/pgmwriter/Mixer.hpp" - -#include "engine/IndivFxMixer.hpp" -#include "engine/StereoMixer.hpp" -#include "sampler/Pad.hpp" -#include "sampler/Program.hpp" - -using namespace mpc::file::pgmwriter; -using namespace mpc::sampler; - -Mixer::Mixer(Program *program) -{ - mixerArray = std::vector(384 + 3); - - for (int i = 0; i < 64; i++) - { - auto noteParameters = program->getNoteParameters(i + 35); - auto smc = noteParameters->getStereoMixer(); - auto ifmc = noteParameters->getIndivFxMixer(); - setVolume(i, smc->getLevel()); - setPan(i, smc->getPanning()); - setVolumeIndividual(i, ifmc->getVolumeIndividualOut()); - setOutput(i, ifmc->getOutput()); - setEffectsSendLevel(i, ifmc->getFxSendLevel()); - setEffectsOutput(i, ifmc->getFxPath()); - } - - mixerArray[384] = 0; - mixerArray[385] = 64; - mixerArray[386] = 0; -} - -std::vector Mixer::getMixerArray() -{ - return mixerArray; -} - -void Mixer::setEffectsOutput(int pad, int effectsOutputNumber) -{ - mixerArray[pad * 6 + 0] = (char)effectsOutputNumber; -} - -void Mixer::setVolume(int pad, int volume) -{ - mixerArray[pad * 6 + 1] = (char)volume; -} - -void Mixer::setPan(int pad, int pan) -{ - mixerArray[pad * 6 + 2] = (char)pan; -} - -void Mixer::setVolumeIndividual(int pad, int volumeIndividual) -{ - mixerArray[pad * 6 + 3] = (char)volumeIndividual; -} - -void Mixer::setOutput(int pad, int output) -{ - mixerArray[pad * 6 + 4] = (char)output; -} - -void Mixer::setEffectsSendLevel(int pad, int effectsSendLevel) -{ - mixerArray[pad * 6 + 5] = (char)effectsSendLevel; -} diff --git a/src/main/file/pgmwriter/Mixer.hpp b/src/main/file/pgmwriter/Mixer.hpp deleted file mode 100644 index e28cdefc..00000000 --- a/src/main/file/pgmwriter/Mixer.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - - namespace sampler - { - class Program; - } - - namespace file - { - namespace pgmwriter - { - - class Mixer - { - - public: - std::vector mixerArray{}; - - std::vector getMixerArray(); - - private: - void setEffectsOutput(int pad, int effectsOutputNumber); - void setVolume(int pad, int volume); - void setPan(int pad, int pan); - void setVolumeIndividual(int pad, int volumeIndividual); - void setOutput(int pad, int output); - void setEffectsSendLevel(int pad, int effectsSendLevel); - - public: - Mixer(sampler::Program *program); - }; - - } // namespace pgmwriter - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmwriter/PWHeader.cpp b/src/main/file/pgmwriter/PWHeader.cpp deleted file mode 100644 index 60feefb6..00000000 --- a/src/main/file/pgmwriter/PWHeader.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "PWHeader.hpp" - -#include "MpcSpecs.hpp" -#include "file/ByteUtil.hpp" - -#include - -using namespace mpc::file::pgmwriter; - -PWHeader::PWHeader(int numberOfSamples) -{ - headerArray = std::vector(4); - writeMagic(); - setSoundCount(numberOfSamples); - headerArray[3] = 0; -} - -void PWHeader::writeMagic() -{ - headerArray[0] = PGM_HEADER_MAGIC[0]; - headerArray[1] = PGM_HEADER_MAGIC[1]; -} - -void PWHeader::setSoundCount(const uint16_t soundCount) -{ - assert(soundCount <= Mpc2000XlSpecs::MAX_SOUND_COUNT_IN_MEMORY); - const auto soundCountBytes = ByteUtil::ushort2bytes(soundCount); - headerArray[2] = soundCountBytes[0]; - headerArray[3] = soundCountBytes[1]; -} - -std::vector PWHeader::getHeaderArray() -{ - return headerArray; -} diff --git a/src/main/file/pgmwriter/PWHeader.hpp b/src/main/file/pgmwriter/PWHeader.hpp deleted file mode 100644 index 176c2cf5..00000000 --- a/src/main/file/pgmwriter/PWHeader.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::pgmwriter -{ - class PWHeader - { - const std::vector PGM_HEADER_MAGIC{0x07, 0x04}; - std::vector headerArray; - - void writeMagic(); - - void setSoundCount(uint16_t soundCount); - - public: - std::vector getHeaderArray(); - - PWHeader(int numberOfSamples); - }; -} // namespace mpc::file::pgmwriter diff --git a/src/main/file/pgmwriter/PWSlider.cpp b/src/main/file/pgmwriter/PWSlider.cpp deleted file mode 100644 index ba56e752..00000000 --- a/src/main/file/pgmwriter/PWSlider.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "file/pgmwriter/PWSlider.hpp" - -#include "sampler/Program.hpp" - -using namespace mpc::file::pgmwriter; - -Slider::Slider(sampler::Program *program) -{ - sliderArray = std::vector(15); - if (program->getSlider()->getNote() == 34) - { - setMidiNoteAssign(0); - } - else - { - setMidiNoteAssign(program->getSlider()->getNote()); - } - setTuneLow(program->getSlider()->getTuneLowRange()); - setTuneHigh(program->getSlider()->getTuneHighRange()); - setDecayLow(program->getSlider()->getDecayLowRange()); - setDecayHigh(program->getSlider()->getDecayHighRange()); - setAttackLow(program->getSlider()->getAttackLowRange()); - setAttackHigh(program->getSlider()->getAttackHighRange()); - setFilterLow(program->getSlider()->getFilterLowRange()); - setFilterHigh(program->getSlider()->getFilterHighRange()); - setProgramChange(program->getMidiProgramChange() - 1); - sliderArray[10] = 35; - sliderArray[11] = 64; - sliderArray[12] = 0; - sliderArray[13] = 25; - sliderArray[14] = 0; -} - -std::vector Slider::getSliderArray() -{ - return sliderArray; -} - -void Slider::setMidiNoteAssign(int midiNoteAssign) -{ - sliderArray[0] = midiNoteAssign; -} - -void Slider::setTuneLow(int tuneLow) -{ - sliderArray[1] = tuneLow; -} - -void Slider::setTuneHigh(int tuneHigh) -{ - sliderArray[2] = tuneHigh; -} - -void Slider::setDecayLow(int decayLow) -{ - sliderArray[3] = decayLow; -} - -void Slider::setDecayHigh(int decayHigh) -{ - sliderArray[4] = decayHigh; -} - -void Slider::setAttackLow(int attackLow) -{ - sliderArray[5] = attackLow; -} - -void Slider::setAttackHigh(int attackHigh) -{ - sliderArray[6] = attackHigh; -} - -void Slider::setFilterLow(int filterLow) -{ - sliderArray[7] = filterLow; -} - -void Slider::setFilterHigh(int filterHigh) -{ - sliderArray[8] = filterHigh; -} - -void Slider::setProgramChange(int programChange) -{ - sliderArray[9] = programChange; -} diff --git a/src/main/file/pgmwriter/PWSlider.hpp b/src/main/file/pgmwriter/PWSlider.hpp deleted file mode 100644 index c4255513..00000000 --- a/src/main/file/pgmwriter/PWSlider.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - - namespace sampler - { - class Program; - } - - namespace file - { - namespace pgmwriter - { - - class Slider - { - - public: - std::vector sliderArray{}; - - std::vector getSliderArray(); - - private: - void setMidiNoteAssign(int midiNoteAssign); - void setTuneLow(int tuneLow); - void setTuneHigh(int tuneHigh); - void setDecayLow(int decayLow); - void setDecayHigh(int decayHigh); - void setAttackLow(int attackLow); - void setAttackHigh(int attackHigh); - void setFilterLow(int filterLow); - void setFilterHigh(int filterHigh); - void setProgramChange(int programChange); - - public: - Slider(sampler::Program *program); - }; - - } // namespace pgmwriter - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmwriter/Pads.cpp b/src/main/file/pgmwriter/Pads.cpp deleted file mode 100644 index 244ca940..00000000 --- a/src/main/file/pgmwriter/Pads.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "file/pgmwriter/Pads.hpp" - -#include "sampler/Pad.hpp" -#include "sampler/Program.hpp" - -#include "file/ByteUtil.hpp" - -using namespace mpc::file::pgmwriter; - -Pads::Pads(sampler::Program *program) -{ - - padsArray = std::vector(264); - for (int i = 0; i < 64; i++) - { - auto nn = program->getPad(i)->getNote(); - if (nn == 34) - { - setPadMidiNote(i, 0); - } - else - { - setPadMidiNote(i, nn); - } - } - auto paddingBytes = getFxBoardSettings(); - for (int i = 0; i < 200; i++) - { - padsArray[i + 64] = paddingBytes[i]; - } -} -std::string Pads::fxBoardSettings = - "02004800D0070000630114081DFC323302323C08050A1414320000020F19000541141E0105" - "0000056300F4FF0C0000000000000002004F014F0100424F0100424F01004232006328003C" - "0000D0070000630114081DFC323302323C08050A1414320000020F19000541141E01050000" - "056300F4FF0C0000000000000002004F014F0100424F0100424F01004232006328003C0000" - "04000C000000320023003E335A3214000000320023003E335A3214000000320023003E335A" - "3214000000320023003E335A321400"; - -std::vector Pads::getPadsArray() -{ - return padsArray; -} - -void Pads::setPadMidiNote(int pad, int padMidiNote) -{ - padsArray[pad] = padMidiNote; -} - -std::vector Pads::getFxBoardSettings() -{ - return ByteUtil::hexToBytes(fxBoardSettings); -} diff --git a/src/main/file/pgmwriter/Pads.hpp b/src/main/file/pgmwriter/Pads.hpp deleted file mode 100644 index a5525ec2..00000000 --- a/src/main/file/pgmwriter/Pads.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::sampler -{ - class Program; -} - -namespace mpc::file::pgmwriter -{ - class Pads - { - - std::vector padsArray; - static std::string - fxBoardSettings; // dummy -- not implemented in any way -- just to - // fool anybody who's trying to read the product of - // this parser - - public: - std::vector getPadsArray(); - - private: - void setPadMidiNote(int pad, int padMidiNote); - - public: - static std::vector getFxBoardSettings(); - - Pads(sampler::Program *program); - }; -} // namespace mpc::file::pgmwriter diff --git a/src/main/file/pgmwriter/PgmName.cpp b/src/main/file/pgmwriter/PgmName.cpp deleted file mode 100644 index f0c5c0c2..00000000 --- a/src/main/file/pgmwriter/PgmName.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "file/pgmwriter/PgmName.hpp" - -#include "sampler/Program.hpp" - -using namespace mpc::file::pgmwriter; - -PgmName::PgmName(sampler::Program *program) -{ - auto ca = program->getName(); - std::vector temp(17); - for (int i = 0; i < ca.length(); i++) - { - temp[i] = ca[i]; - } - - for (int i = ca.length(); i < 16; i++) - { - temp[i] = 32; - } - - temp[16] = 0; - programNameArray = temp; - sampleNamesSize = program->getNumberOfSamples() * 17; -} - -std::vector PgmName::getPgmNameArray() -{ - return programNameArray; -} diff --git a/src/main/file/pgmwriter/PgmName.hpp b/src/main/file/pgmwriter/PgmName.hpp deleted file mode 100644 index 7d88e27c..00000000 --- a/src/main/file/pgmwriter/PgmName.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - - namespace sampler - { - class Program; - } - - namespace file - { - namespace pgmwriter - { - - class PgmName - { - - public: - int sampleNamesSize{0}; - - std::vector programNameArray{}; - - std::vector getPgmNameArray(); - - PgmName(sampler::Program *program); - }; - - } // namespace pgmwriter - } // namespace file -} // namespace mpc diff --git a/src/main/file/pgmwriter/PgmWriter.cpp b/src/main/file/pgmwriter/PgmWriter.cpp deleted file mode 100644 index f5b7491c..00000000 --- a/src/main/file/pgmwriter/PgmWriter.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "file/pgmwriter/PgmWriter.hpp" - -#include "file/pgmwriter/PWHeader.hpp" -#include "file/pgmwriter/MidiNotes.hpp" -#include "file/pgmwriter/Mixer.hpp" -#include "file/pgmwriter/Pads.hpp" -#include "file/pgmwriter/PgmName.hpp" -#include "file/pgmwriter/SampleNames.hpp" -#include "file/pgmwriter/PWSlider.hpp" - -using namespace mpc::file::pgmwriter; - -PgmWriter::PgmWriter(sampler::Program *program, - const std::weak_ptr &sampler) -{ - SampleNames pwSampleNames(program, sampler); - sampleNames = pwSampleNames.getSampleNamesArray(); - - PWHeader pwHeader(pwSampleNames.getNumberOfSamples()); - header = pwHeader.getHeaderArray(); - - PgmName pwPgmName(program); - pgmName = pwPgmName.getPgmNameArray(); - - Slider pwSlider(program); - slider = pwSlider.getSliderArray(); - - MidiNotes pwMidiNotes(program, pwSampleNames.getSnConvTable()); - midiNotes = pwMidiNotes.midiNotesArray; - - Mixer pwMixer(program); - mixer = pwMixer.getMixerArray(); - - Pads pwPads(program); - pads = pwPads.getPadsArray(); -} - -std::vector PgmWriter::get() const -{ - std::vector> charArrayChunks(7); - charArrayChunks[0] = header; - charArrayChunks[1] = sampleNames; - charArrayChunks[2] = pgmName; - charArrayChunks[3] = slider; - charArrayChunks[4] = midiNotes; - charArrayChunks[5] = mixer; - charArrayChunks[6] = pads; - auto programFileSize = 0; - - for (auto ca : charArrayChunks) - { - programFileSize += ca.size(); - } - - std::vector result(programFileSize); - int counter = 0; - - for (auto ca : charArrayChunks) - { - for (auto c : ca) - { - result[counter++] = c; - } - } - return result; -} diff --git a/src/main/file/pgmwriter/PgmWriter.hpp b/src/main/file/pgmwriter/PgmWriter.hpp deleted file mode 100644 index caa77343..00000000 --- a/src/main/file/pgmwriter/PgmWriter.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::sampler -{ - class Sampler; - class Program; -} // namespace mpc::sampler - -namespace mpc::file::pgmwriter -{ - - class PgmWriter - { - - std::vector header; - std::vector pgmName; - std::vector sampleNames; - std::vector slider; - std::vector midiNotes; - std::vector mixer; - std::vector pads; - - public: - std::vector get() const; - - PgmWriter(sampler::Program *program, - const std::weak_ptr &sampler); - }; -} // namespace mpc::file::pgmwriter diff --git a/src/main/file/pgmwriter/SampleNames.cpp b/src/main/file/pgmwriter/SampleNames.cpp deleted file mode 100644 index c87bd874..00000000 --- a/src/main/file/pgmwriter/SampleNames.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "file/pgmwriter/SampleNames.hpp" - -#include "sampler/Program.hpp" -#include "sampler/Sampler.hpp" - -#include - -using namespace mpc::file::pgmwriter; - -SampleNames::SampleNames(sampler::Program *program, - const std::weak_ptr &sampler) -{ - std::vector list; - - for (auto &nn : program->getNotesParameters()) - { - if (nn->getSoundIndex() != -1) - { - list.push_back(nn->getSoundIndex()); - } - } - - std::set sampleNamesSet; - std::vector finalNames; - - auto lSampler = sampler.lock(); - - for (int i = 0; i < list.size(); i++) - { - if (sampleNamesSet.emplace(lSampler->getSoundName(list[i])).second) - { - finalNames.push_back(lSampler->getSoundName(list[i])); - } - } - - for (int i = 0; i < lSampler->getSoundCount(); i++) - { - int j = -1; - for (int k = 0; k < finalNames.size(); k++) - { - if (finalNames[k] == lSampler->getSoundName(i)) - { - j = k; - break; - } - } - - snConvTable.push_back(j); - } - numberOfSamples = finalNames.size(); - sampleNamesArray = std::vector(numberOfSamples * 17 + 2); - int counter = 0; - for (auto &s : finalNames) - { - setSampleName(counter++, s); - } - sampleNamesArray[(int)sampleNamesArray.size() - 2] = 30; - sampleNamesArray[(int)sampleNamesArray.size() - 1] = 0; -} - -std::vector SampleNames::getSampleNamesArray() -{ - return sampleNamesArray; -} - -void SampleNames::setSampleName(int sampleNumber, const std::string &name) -{ - for (int i = 0; i < name.length(); i++) - { - sampleNamesArray[i + sampleNumber * 17] = name[i]; - } - - for (int i = name.length(); i < 16; i++) - { - sampleNamesArray[i + sampleNumber * 17] = 32; - } - - sampleNamesArray[16 + sampleNumber * 17] = 0; -} - -int SampleNames::getNumberOfSamples() const -{ - return numberOfSamples; -} - -std::vector SampleNames::getSnConvTable() -{ - return snConvTable; -} diff --git a/src/main/file/pgmwriter/SampleNames.hpp b/src/main/file/pgmwriter/SampleNames.hpp deleted file mode 100644 index 3b3236e3..00000000 --- a/src/main/file/pgmwriter/SampleNames.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace mpc -{ - - namespace sampler - { - class Sampler; - class Program; - } // namespace sampler - - namespace file - { - namespace pgmwriter - { - - class SampleNames - { - - std::vector sampleNamesArray{}; - int numberOfSamples{}; - std::vector snConvTable{}; - - public: - std::vector getSampleNamesArray(); - - private: - void setSampleName(int sampleNumber, const std::string &name); - - public: - int getNumberOfSamples() const; - std::vector getSnConvTable(); - - SampleNames(sampler::Program *program, - const std::weak_ptr &sampler); - }; - - } // namespace pgmwriter - } // namespace file -} // namespace mpc diff --git a/src/main/file/sndreader/SndHeaderReader.cpp b/src/main/file/sndreader/SndHeaderReader.cpp deleted file mode 100644 index e9f60a2c..00000000 --- a/src/main/file/sndreader/SndHeaderReader.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "SndHeaderReader.hpp" - -#include "file/sndreader/SndReader.hpp" - -#include "Util.hpp" -#include "file/ByteUtil.hpp" -#include "StrUtil.hpp" - -using namespace mpc::file::sndreader; - -SndHeaderReader::SndHeaderReader(SndReader *sndReader) -{ - auto sndFileArray = sndReader->getSndFileArray(); - headerArray = Util::vecCopyOfRange(sndFileArray, 0, 42); -} - -std::vector &SndHeaderReader::getHeaderArray() -{ - return headerArray; -} - -bool SndHeaderReader::hasValidId() const -{ - int i = headerArray[0]; - int j = headerArray[1]; - - return i == 1 && j < 5; -} - -std::string SndHeaderReader::getName() const -{ - std::string name; - - for (int i = 2; i < 18; i++) - { - if (headerArray[i] == 0x00) - { - break; - } - name.push_back(headerArray[i]); - } - - return StrUtil::trim(name); -} - -int SndHeaderReader::getLevel() const -{ - return headerArray[19]; -} - -int SndHeaderReader::getTune() const -{ - return headerArray[20]; -} - -bool SndHeaderReader::isMono() const -{ - auto channels = headerArray[21]; - return channels == 0; -} - -int SndHeaderReader::getStart() const -{ - auto startArray = Util::vecCopyOfRange(headerArray, 22, 26); - auto start = ByteUtil::bytes2uint(startArray); - return start; -} - -int SndHeaderReader::getEnd() const -{ - auto endArray = Util::vecCopyOfRange(headerArray, 26, 30); - auto end = ByteUtil::bytes2uint(endArray); - return end; -} - -int SndHeaderReader::getNumberOfFrames() const -{ - auto numberOfFramesArray = Util::vecCopyOfRange(headerArray, 30, 34); - int numberOfFrames = ByteUtil::bytes2uint(numberOfFramesArray); - return numberOfFrames; -} - -int SndHeaderReader::getLoopLength() const -{ - auto loopLengthArray = Util::vecCopyOfRange(headerArray, 34, 38); - auto loopLength = ByteUtil::bytes2uint(loopLengthArray); - return loopLength; -} - -bool SndHeaderReader::isLoopEnabled() const -{ - int loop = headerArray[38]; - return loop == 1; -} - -int SndHeaderReader::getNumberOfBeats() const -{ - return headerArray[39]; -} - -int SndHeaderReader::getSampleRate() const -{ - auto rateArray = Util::vecCopyOfRange(headerArray, 40, 42); - auto rate = ByteUtil::bytes2ushort(rateArray); - return rate; -} diff --git a/src/main/file/sndreader/SndHeaderReader.hpp b/src/main/file/sndreader/SndHeaderReader.hpp deleted file mode 100644 index adbebb15..00000000 --- a/src/main/file/sndreader/SndHeaderReader.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::sndreader -{ - class SndReader; -} - -namespace mpc::file::sndreader -{ - class SndHeaderReader - { - std::vector headerArray = std::vector(42); - - public: - std::vector &getHeaderArray(); - bool hasValidId() const; - std::string getName() const; - int getLevel() const; - int getTune() const; - bool isMono() const; - int getStart() const; - int getEnd() const; - int getNumberOfFrames() const; - int getLoopLength() const; - bool isLoopEnabled() const; - int getNumberOfBeats() const; - int getSampleRate() const; - - SndHeaderReader(SndReader *sndReader); - }; -} // namespace mpc::file::sndreader diff --git a/src/main/file/sndreader/SndReader.cpp b/src/main/file/sndreader/SndReader.cpp deleted file mode 100644 index d5067a47..00000000 --- a/src/main/file/sndreader/SndReader.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "file/sndreader/SndReader.hpp" - -#include "disk/MpcFile.hpp" -#include "file/sndreader/SndHeaderReader.hpp" - -#include - -#include "file/ByteUtil.hpp" - -using namespace mpc::file::sndreader; -using namespace mpc::sampleops; - -SndReader::SndReader(disk::MpcFile *soundFile) - : SndReader(soundFile->getBytes()) -{ -} - -SndReader::SndReader(const std::vector &loadBytes) -{ - sndFileArray = loadBytes; - sndHeaderReader = std::make_shared(this); -} - -bool SndReader::isHeaderValid() const -{ - return sndHeaderReader->hasValidId(); -} - -std::string SndReader::getName() const -{ - return sndHeaderReader->getName(); -} - -bool SndReader::isMono() const -{ - return sndHeaderReader->isMono(); -} - -int SndReader::getSampleRate() const -{ - return sndHeaderReader->getSampleRate(); -} - -int SndReader::getLevel() const -{ - return sndHeaderReader->getLevel(); -} - -int SndReader::getStart() const -{ - return sndHeaderReader->getStart(); -} - -int SndReader::getEnd() const -{ - return sndHeaderReader->getEnd(); -} - -int SndReader::getLoopLength() const -{ - return sndHeaderReader->getLoopLength(); -} - -bool SndReader::isLoopEnabled() const -{ - return sndHeaderReader->isLoopEnabled(); -} - -int SndReader::getTune() const -{ - return sndHeaderReader->getTune(); -} - -int SndReader::getNumberOfBeats() const -{ - return sndHeaderReader->getNumberOfBeats(); -} - -void SndReader::readData(const std::shared_ptr> &dest) -{ - int length = sndHeaderReader->getNumberOfFrames(); - - bool mono = sndHeaderReader->isMono(); - - if (!mono) - { - length *= 2; - } - - dest->clear(); - dest->resize(length); - - auto shorts = ByteUtil::bytesToShorts( - std::vector(sndFileArray.begin() + 42, sndFileArray.end())); - - for (int i = 0; i < length; ++i) - { - short value = shorts[i]; - auto f = short_to_float(value); - - if (f < -1) - { - f = -1.0f; - } - - if (f > 1) - { - f = 1.0f; - } - - (*dest)[i] = f; - } -} - -std::vector &SndReader::getSndFileArray() -{ - return sndFileArray; -} diff --git a/src/main/file/sndreader/SndReader.hpp b/src/main/file/sndreader/SndReader.hpp deleted file mode 100644 index 533a0250..00000000 --- a/src/main/file/sndreader/SndReader.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "Util.hpp" - -#include -#include -#include - -namespace mpc::disk -{ - class MpcFile; -} - -namespace mpc::file::sndreader -{ - class SndHeaderReader; -} - -namespace mpc::file::sndreader -{ - class SndReader - { - - std::vector sndFileArray; - std::shared_ptr sndHeaderReader; - - public: - std::string getName() const; - bool isHeaderValid() const; - bool isMono() const; - - int getSampleRate() const; - int getLevel() const; - int getStart() const; - int getEnd() const; - int getLoopLength() const; - bool isLoopEnabled() const; - int getTune() const; - int getNumberOfBeats() const; - void readData(const std::shared_ptr> &); - - std::vector &getSndFileArray(); - - SndReader(disk::MpcFile *); - - SndReader(const std::vector &loadBytes); - }; -} // namespace mpc::file::sndreader diff --git a/src/main/file/sndwriter/SndHeaderWriter.cpp b/src/main/file/sndwriter/SndHeaderWriter.cpp deleted file mode 100644 index 21986848..00000000 --- a/src/main/file/sndwriter/SndHeaderWriter.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "file/sndwriter/SndHeaderWriter.hpp" -#include "file/ByteUtil.hpp" - -using namespace mpc::file::sndwriter; - -SndHeaderWriter::SndHeaderWriter() -{ - setFirstTwoBytes(); -} - -std::vector &SndHeaderWriter::getHeaderArray() -{ - return headerArray; -} - -void SndHeaderWriter::setFirstTwoBytes() -{ - headerArray[0] = 1; - headerArray[1] = 4; -} - -void SndHeaderWriter::setName(const std::string &name) -{ - std::vector nameArray(16); - - for (int i = 0; i < name.length(); i++) - { - nameArray[i] = name[i]; - } - - for (int i = name.length(); i < nameArray.size(); i++) - { - nameArray[i] = 32; - } - - for (int i = 0; i < nameArray.size(); i++) - { - headerArray[i + 2] = nameArray[i]; - } -} - -void SndHeaderWriter::setLevel(int i) -{ - headerArray[19] = static_cast(i); -} - -void SndHeaderWriter::setTune(int i) -{ - headerArray[20] = static_cast(i); -} - -void SndHeaderWriter::setMono(bool b) -{ - headerArray[21] = static_cast(b ? 0 : 1); -} - -void SndHeaderWriter::setStart(int i) -{ - putLE(22, i); -} - -void SndHeaderWriter::setEnd(int i) -{ - putLE(26, i); -} - -void SndHeaderWriter::setFrameCount(int i) -{ - putLE(30, i); -} - -void SndHeaderWriter::setLoopLength(int i) -{ - putLE(34, i); -} - -void SndHeaderWriter::setLoopEnabled(bool b) -{ - headerArray[38] = b ? 1 : 0; -} - -void SndHeaderWriter::setBeatCount(int i) -{ - headerArray[39] = i; -} - -void SndHeaderWriter::setSampleRate(int i) -{ - auto shortBytes = ByteUtil::short2bytes(i - 65536); - headerArray[40] = shortBytes[0]; - headerArray[41] = shortBytes[1]; -} - -void SndHeaderWriter::putLE(int offset, int value) -{ - auto ba = ByteUtil::uint2bytes(value); - for (auto j = 0; j < ba.size(); j++) - { - headerArray[j + offset] = ba[j]; - } -} diff --git a/src/main/file/sndwriter/SndHeaderWriter.hpp b/src/main/file/sndwriter/SndHeaderWriter.hpp deleted file mode 100644 index c6a55b48..00000000 --- a/src/main/file/sndwriter/SndHeaderWriter.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::sndwriter -{ - class SndWriter; -} - -namespace mpc::file::sndwriter -{ - class SndHeaderWriter - { - std::vector headerArray = std::vector(42); - - public: - std::vector &getHeaderArray(); - void setFirstTwoBytes(); - void setName(const std::string &name); - void setLevel(int i); - void setTune(int i); - void setMono(bool b); - void setStart(int i); - void setEnd(int i); - void setFrameCount(int i); - void setLoopLength(int i); - void setLoopEnabled(bool b); - void setBeatCount(int i); - void setSampleRate(int i); - - private: - void putLE(int offset, int value); - - public: - SndHeaderWriter(); - }; -} // namespace mpc::file::sndwriter diff --git a/src/main/file/sndwriter/SndWriter.cpp b/src/main/file/sndwriter/SndWriter.cpp deleted file mode 100644 index 515324a2..00000000 --- a/src/main/file/sndwriter/SndWriter.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "file/sndwriter/SndWriter.hpp" - -#include "file/sndwriter/SndHeaderWriter.hpp" -#include "sampler/Sound.hpp" - -#include "file/ByteUtil.hpp" - -#include - -using namespace mpc::file::sndwriter; - -SndWriter::SndWriter(sampler::Sound *sound) -{ - this->sound = sound; - sndHeaderWriter = std::make_shared(); - setValues(); -} -const int SndWriter::HEADER_SIZE; - -void SndWriter::setValues() -{ - setName(sound->getName()); - setMono(sound->isMono()); - setFramesCount(sound->getFrameCount()); - setSampleRate(sound->getSampleRate()); - setLevel(sound->getSndLevel()); - setStart(sound->getStart()); - setEnd(sound->getEnd()); - setLoopLength(sound->getEnd() - sound->getLoopTo()); - setLoopEnabled(sound->isLoopEnabled()); - setTune(sound->getTune()); - setBeatCount(sound->getBeatCount()); - setSampleData(*sound->getSampleData(), sound->isMono()); -} - -void SndWriter::setName(const std::string &s) const -{ - sndHeaderWriter->setName(s); -} - -void SndWriter::setMono(bool b) const -{ - sndHeaderWriter->setMono(b); -} - -void SndWriter::setFramesCount(int i) const -{ - sndHeaderWriter->setFrameCount(i); -} - -void SndWriter::setSampleRate(int i) const -{ - sndHeaderWriter->setSampleRate(i); -} - -void SndWriter::setLevel(int i) const -{ - sndHeaderWriter->setLevel(i); -} - -void SndWriter::setStart(int i) const -{ - sndHeaderWriter->setStart(i); -} - -void SndWriter::setEnd(int i) const -{ - sndHeaderWriter->setEnd(i); -} - -void SndWriter::setLoopLength(int i) const -{ - sndHeaderWriter->setLoopLength(i); -} - -void SndWriter::setLoopEnabled(bool b) const -{ - sndHeaderWriter->setLoopEnabled(b); -} - -void SndWriter::setTune(int i) const -{ - sndHeaderWriter->setTune(i); -} - -void SndWriter::setBeatCount(int i) const -{ - sndHeaderWriter->setBeatCount(i); -} - -void SndWriter::setSampleData(const std::vector &fa, bool mono) -{ - sndFileArray = std::vector(HEADER_SIZE + fa.size() * 2); - auto frames = mono ? fa.size() : fa.size() * 0.5; - sndHeaderWriter->setFrameCount(frames); - - std::vector buffer(2); - auto sPos = 0; - - auto bytePos = HEADER_SIZE; - for (int i = 0; i < fa.size(); i++) - { - auto shortres = sampleops::mean_normalized_float_to_short(fa[sPos++]); - buffer = ByteUtil::short2bytes(shortres); - sndFileArray[bytePos++] = buffer[0]; - sndFileArray[bytePos++] = buffer[1]; - } -} - -std::vector &SndWriter::getSndFileArray() -{ - auto header = sndHeaderWriter->getHeaderArray(); - for (int i = 0; i < header.size(); i++) - { - sndFileArray[i] = header[i]; - } - - return sndFileArray; -} diff --git a/src/main/file/sndwriter/SndWriter.hpp b/src/main/file/sndwriter/SndWriter.hpp deleted file mode 100644 index 5085e528..00000000 --- a/src/main/file/sndwriter/SndWriter.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace mpc::sampler -{ - class Sound; -} - -namespace mpc::file::sndwriter -{ - class SndHeaderWriter; -} - -namespace mpc::file::sndwriter -{ - class SndWriter - { - - static const int HEADER_SIZE = 42; - std::shared_ptr sndHeaderWriter; - sampler::Sound *sound; - std::vector sndFileArray; - - void setValues(); - void setName(const std::string &s) const; - void setMono(bool b) const; - void setFramesCount(int i) const; - void setSampleRate(int i) const; - void setLevel(int i) const; - void setStart(int i) const; - void setEnd(int i) const; - void setLoopLength(int i) const; - void setLoopEnabled(bool b) const; - void setTune(int i) const; - void setBeatCount(int i) const; - void setSampleData(const std::vector &fa, bool b); - - public: - std::vector &getSndFileArray(); - - SndWriter(sampler::Sound *sound); - }; -} // namespace mpc::file::sndwriter diff --git a/src/test/KaitaiPgmTest.cpp b/src/test/KaitaiPgmTest.cpp index 08dc8a4d..22084e24 100644 --- a/src/test/KaitaiPgmTest.cpp +++ b/src/test/KaitaiPgmTest.cpp @@ -5,22 +5,12 @@ #include "IntTypes.hpp" #include "disk/AbstractDisk.hpp" #include "disk/MpcFile.hpp" -#include "disk/PgmFileToProgramConverter.hpp" #include "disk/ProgramLoader.hpp" #include "engine/IndivFxMixer.hpp" #include "engine/EngineHost.hpp" #include "engine/StereoMixer.hpp" #include "file/kaitai/PgmIo.hpp" #include "file/kaitai/generated/mpc2000xl_pgm.h" -#include "file/pgmreader/PgmHeader.hpp" -#include "file/pgmreader/ProgramName.hpp" -#include "file/pgmreader/SoundNames.hpp" -#include "file/pgmreader/PgmAllNoteParameters.hpp" -#include "file/pgmreader/PRMixer.hpp" -#include "file/pgmreader/PRPads.hpp" -#include "file/pgmreader/ProgramFileReader.hpp" -#include "file/pgmreader/PRSlider.hpp" -#include "file/pgmwriter/PgmWriter.hpp" #include "performance/PerformanceManager.hpp" #include "sampler/Pad.hpp" #include "sampler/PgmSlider.hpp" @@ -179,66 +169,6 @@ void requireBroadMutatedProgramState( REQUIRE(slider->getFilterHighRange() == 16); } -void requireBroadMutatedProgramReaderState( - mpc::file::pgmreader::ProgramFileReader& reader) -{ - REQUIRE(reader.getHeader()->verifyMagic()); - REQUIRE(reader.getHeader()->getSoundCount() == 2); - REQUIRE(reader.getProgramName()->getProgramNameASCII() == "VMPCTESTPROGRAM1"); - REQUIRE(reader.getSampleNames()->getSampleName(0) == - std::string("sound1") + std::string(10, ' ')); - REQUIRE(reader.getSampleNames()->getSampleName(1) == - std::string("sound2") + std::string(10, ' ')); - - REQUIRE(reader.getPads()->getNote(0) == 50); - - auto allNotes = reader.getAllNoteParameters(); - REQUIRE(allNotes->getSampleSelect(0) == -1); - REQUIRE(allNotes->getSoundGenerationMode(0) == 2); - REQUIRE(allNotes->getVelocityRangeLower(0) == 1); - REQUIRE(allNotes->getVelocityRangeUpper(0) == 127); - REQUIRE(allNotes->getAlsoPlayUse1(0) == 41); - REQUIRE(allNotes->getAlsoPlayUse2(0) == 42); - REQUIRE(allNotes->getVoiceOverlapMode(0) == mpc::sampler::VoiceOverlapMode::NOTE_OFF); - REQUIRE(allNotes->getMuteAssign1(0) == 43); - REQUIRE(allNotes->getMuteAssign2(0) == 44); - REQUIRE(allNotes->getTune(0) == -120); - REQUIRE(allNotes->getAttack(0) == 99); - REQUIRE(allNotes->getDecay(0) == 98); - REQUIRE(allNotes->getDecayMode(0) == 1); - REQUIRE(allNotes->getCutoff(0) == 17); - REQUIRE(allNotes->getResonance(0) == 18); - REQUIRE(allNotes->getVelEnvToFiltAtt(0) == 19); - REQUIRE(allNotes->getVelEnvToFiltDec(0) == 20); - REQUIRE(allNotes->getVelEnvToFiltAmt(0) == 21); - REQUIRE(allNotes->getVelocityToLevel(0) == 22); - REQUIRE(allNotes->getVelocityToAttack(0) == 23); - REQUIRE(allNotes->getVelocityToStart(0) == 24); - REQUIRE(allNotes->getVelocityToCutoff(0) == 25); - REQUIRE(allNotes->getSliderParameter(0) == 3); - REQUIRE(allNotes->getVelocityToPitch(0) == 26); - - auto mixer = reader.getMixer(); - REQUIRE(mixer->getEffectsOutput(0) == 4); - REQUIRE(mixer->getVolume(0) == 12); - REQUIRE(mixer->getPan(0) == 13); - REQUIRE(mixer->getVolumeIndividual(0) == 14); - REQUIRE(mixer->getOutput(0) == 2); - REQUIRE(mixer->getEffectsSendLevel(0) == 15); - - auto slider = reader.getSlider(); - REQUIRE(slider->getMidiNoteAssign() == 52); - REQUIRE(slider->getTuneLow() == -119); - REQUIRE(slider->getTuneHigh() == 118); - REQUIRE(slider->getDecayLow() == 11); - REQUIRE(slider->getDecayHigh() == 12); - REQUIRE(slider->getAttackLow() == 13); - REQUIRE(slider->getAttackHigh() == 14); - REQUIRE(slider->getFilterLow() == -15); - REQUIRE(slider->getFilterHigh() == 16); - REQUIRE(slider->getProgramChange() == 126); -} - void prepareProgramLoadingResources(mpc::Mpc& mpc) { auto disk = mpc.getDisk(); @@ -342,6 +272,24 @@ std::shared_ptr loadProgram1FileFromBytes( return pgmFile; } +std::shared_ptr loadProgram1ViaPgmIoFromBytes( + mpc::Mpc& mpc, + const std::vector& programBytes, + std::vector& soundNames) +{ + auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); + + auto sampler = mpc.getSampler(); + sampler->deleteAllPrograms(false); + sampler->deleteAllSamples(); + + auto program = sampler->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + auto result = mpc::file::kaitai::PgmIo::loadProgram(mpc, pgmFile, program, soundNames); + REQUIRE(result); + mpc.getPerformanceManager().lock()->drainQueue(); + return program; +} + void requireProgram1LoadedState(mpc::Mpc& mpc, const std::shared_ptr& program) { @@ -501,7 +449,7 @@ TEST_CASE("Kaitai MPC2000 PGM parses and rewrites real 2KXL NEWPGM-A", "[kaitai- REQUIRE(writeStream.str() == originalBytes); } -TEST_CASE("Kaitai MPC2000 PGM matches handwritten PGM bytes", "[kaitai-pgm]") +TEST_CASE("Kaitai MPC2000 PGM saves and reloads PROGRAM1 without handwritten code", "[kaitai-pgm]") { mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); @@ -510,11 +458,10 @@ TEST_CASE("Kaitai MPC2000 PGM matches handwritten PGM bytes", "[kaitai-pgm]") REQUIRE(program != nullptr); REQUIRE(program->getName() == "PROGRAM1"); - mpc::file::pgmwriter::PgmWriter handwrittenWriter(program.get(), mpc.getSampler()); - const auto handwrittenBytes = handwrittenWriter.get(); + const auto kaitaiBytes = mpc::file::kaitai::PgmIo::saveProgram(*program, mpc.getSampler()); std::stringstream parseStream( - std::string(handwrittenBytes.begin(), handwrittenBytes.end()), + std::string(kaitaiBytes.begin(), kaitaiBytes.end()), std::ios::in | std::ios::out | std::ios::binary ); kaitai::kstream parseIo(&parseStream); @@ -538,8 +485,7 @@ TEST_CASE("Kaitai MPC2000 PGM matches handwritten PGM bytes", "[kaitai-pgm]") parsed._check(); parsed._write(); - const auto kaitaiBytes = writeStream.str(); - REQUIRE(kaitaiBytes == std::string(handwrittenBytes.begin(), handwrittenBytes.end())); + REQUIRE(writeStream.str() == std::string(kaitaiBytes.begin(), kaitaiBytes.end())); auto disk = mpc.getDisk(); auto kaitaiFile = disk->newFile("KPGM.PGM"); @@ -670,7 +616,7 @@ TEST_CASE("Kaitai MPC2000 PGM load preserves mixer effects send level", "[kaitai REQUIRE(program->getNoteParameters(36)->getIndivFxMixer()->getFxSendLevel() == 50); } -TEST_CASE("PgmFileToProgramConverter loads upper-bound MIDI program change", "[kaitai-pgm]") +TEST_CASE("Kaitai MPC2000 PGM direct load handles upper-bound MIDI program change", "[kaitai-pgm]") { auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); @@ -698,20 +644,13 @@ TEST_CASE("PgmFileToProgramConverter loads upper-bound MIDI program change", "[k mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); - auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); - auto program = mpc.getSampler()->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); std::vector soundNames; - - auto result = mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( - mpc, pgmFile, program, soundNames - ); - REQUIRE(result); - - mpc.getPerformanceManager().lock()->drainQueue(); + const auto program = loadProgram1ViaPgmIoFromBytes(mpc, programBytes, soundNames); REQUIRE(program->getMidiProgramChange() == 128); + REQUIRE(soundNames.size() == 2U); } -TEST_CASE("ProgramFileReader reads upper-bound MIDI program change byte", "[kaitai-pgm]") +TEST_CASE("Kaitai MPC2000 PGM direct parse reads upper-bound MIDI program change byte", "[kaitai-pgm]") { auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); @@ -735,29 +674,28 @@ TEST_CASE("ProgramFileReader reads upper-bound MIDI program change byte", "[kait parsed._write(); const auto rewrittenBytes = writeStream.str(); - std::vector programBytes(rewrittenBytes.begin(), rewrittenBytes.end()); - - mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); - auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); - - mpc::file::pgmreader::ProgramFileReader reader(pgmFile); - REQUIRE(reader.getSlider()->getProgramChange() == 127); + std::stringstream reparsedStream( + rewrittenBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream reparsedIo(&reparsedStream); + mpc2000xl_pgm_t reparsed(&reparsedIo); + reparsed._read(); + REQUIRE(reparsed.program_change() == 127); } -TEST_CASE("ProgramFileReader reads broad mutated program semantics", "[kaitai-pgm]") +TEST_CASE("Kaitai MPC2000 PGM direct load preserves broad mutated program semantics", "[kaitai-pgm]") { const auto programBytes = rewriteProgram1WithMutations(applyBroadProgramMutation); mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); - auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); - - mpc::file::pgmreader::ProgramFileReader reader(pgmFile); - requireBroadMutatedProgramReaderState(reader); + std::vector soundNames; + const auto program = loadProgram1ViaPgmIoFromBytes(mpc, programBytes, soundNames); + requireBroadMutatedProgramState(program, soundNames); } -TEST_CASE("PgmFileToProgramConverter loads mutated note tune", "[kaitai-pgm]") +TEST_CASE("Kaitai MPC2000 PGM direct load preserves mutated note tune", "[kaitai-pgm]") { auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/ProgramLoading/program1/PROGRAM1.PGM"); @@ -785,16 +723,8 @@ TEST_CASE("PgmFileToProgramConverter loads mutated note tune", "[kaitai-pgm]") mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); - auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); - auto program = mpc.getSampler()->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); std::vector soundNames; - - auto result = mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( - mpc, pgmFile, program, soundNames - ); - REQUIRE(result); - - mpc.getPerformanceManager().lock()->drainQueue(); + const auto program = loadProgram1ViaPgmIoFromBytes(mpc, programBytes, soundNames); REQUIRE(program->getNoteParameters(35)->getTune() == -120); } @@ -866,23 +796,21 @@ TEST_CASE("ProgramLoader loads mutated note tune", "[kaitai-pgm]") REQUIRE(program->getNoteParameters(35)->getTune() == -120); } -TEST_CASE("PgmFileToProgramConverter loads broad mutated program semantics", "[kaitai-pgm]") +TEST_CASE("Kaitai MPC2000 PGM save and production load preserve broad mutated program semantics", "[kaitai-pgm]") { - const auto programBytes = rewriteProgram1WithMutations(applyBroadProgramMutation); - mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutIoServices(mpc); - auto pgmFile = loadProgram1FileFromBytes(mpc, programBytes); - auto program = mpc.getSampler()->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); - std::vector soundNames; - - auto result = mpc::disk::PgmFileToProgramConverter::loadFromFileAndConvert( - mpc, pgmFile, program, soundNames - ); - REQUIRE(result); + const auto mutatedBytes = rewriteProgram1WithMutations(applyBroadProgramMutation); + const auto mutatedProgram = loadProgram1FromBytesWithoutRender(mpc, mutatedBytes); + const std::vector expectedSoundNames{ + std::string("sound1") + std::string(10, ' '), + std::string("sound2") + std::string(10, ' ') + }; + requireBroadMutatedProgramState(mutatedProgram, expectedSoundNames); - mpc.getPerformanceManager().lock()->drainQueue(); - requireBroadMutatedProgramState(program, soundNames); + const auto savedBytes = mpc::file::kaitai::PgmIo::saveProgram(*mutatedProgram, mpc.getSampler()); + const auto reparsedProgram = loadProgram1FromBytesWithoutRender(mpc, savedBytes); + requireBroadMutatedProgramState(reparsedProgram, expectedSoundNames); } TEST_CASE("ProgramLoader loads broad mutated program semantics", "[kaitai-pgm]") diff --git a/src/test/KaitaiSndTest.cpp b/src/test/KaitaiSndTest.cpp index d3aaadde..ec9e99c1 100644 --- a/src/test/KaitaiSndTest.cpp +++ b/src/test/KaitaiSndTest.cpp @@ -7,8 +7,6 @@ #include "disk/SoundLoader.hpp" #include "file/kaitai/SndIo.hpp" #include "file/kaitai/generated/mpc2000snd.h" -#include "file/sndreader/SndReader.hpp" -#include "file/sndwriter/SndWriter.hpp" #include "sampler/Sampler.hpp" #include "sampler/Sound.hpp" @@ -27,8 +25,6 @@ CMRC_DECLARE(mpctest); using namespace mpc::disk; using namespace mpc::file::kaitai; -using namespace mpc::file::sndreader; -using namespace mpc::file::sndwriter; using namespace mpc::sampleops; namespace @@ -152,7 +148,7 @@ namespace } } -TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") +TEST_CASE("Kaitai MPC2000 SND saves and loads explicit semantics", "[kaitai-snd]") { mpc::sampler::Sound sound(44100); sound.setName("KICK_01"); @@ -170,15 +166,12 @@ TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") sound.setLoopEnabled(true); sound.setBeatCount(4); - SndWriter handwrittenWriter(&sound); - const auto handwrittenBytes = handwrittenWriter.getSndFileArray(); + const auto kaitaiBytes = SndIo::saveSound(sound); - std::string kaitaiBytes; - - withParsedSndBytes(handwrittenBytes, [&](mpc2000snd_t &parsed) + withParsedSndBytes(kaitaiBytes, [&](mpc2000snd_t &parsed) { REQUIRE(parsed.magic() == std::string("\x01\x04", 2)); - REQUIRE(parsed.name() == std::string(handwrittenBytes.begin() + 2, handwrittenBytes.begin() + 19)); + REQUIRE(parsed.name() == expectedHeaderName("KICK_01")); REQUIRE(parsed.level() == 100); REQUIRE(parsed.tune() == -2); REQUIRE(parsed.stereo() == false); @@ -193,37 +186,26 @@ TEST_CASE("Kaitai MPC2000 SND matches handwritten SND bytes", "[kaitai-snd]") REQUIRE(parsed.sample_data()->size() == 2U); REQUIRE(parsed.sample_data()->at(0) == 1234); REQUIRE(parsed.sample_data()->at(1) == -1234); - - std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); - kaitai::kstream writeIo(&writeStream); - parsed._set_io(&writeIo); - parsed._check(); - parsed._write(); - - kaitaiBytes = writeStream.str(); }); - REQUIRE(kaitaiBytes == std::string(handwrittenBytes.begin(), handwrittenBytes.end())); - - std::vector kaitaiBytesVec(kaitaiBytes.begin(), kaitaiBytes.end()); - SndReader handwrittenReader(kaitaiBytesVec); - auto outputData = std::make_shared>(); - handwrittenReader.readData(outputData); - - REQUIRE(handwrittenReader.isHeaderValid()); - REQUIRE(handwrittenReader.getName() == "KICK_01"); - REQUIRE(handwrittenReader.isMono()); - REQUIRE(handwrittenReader.getLevel() == 100); - REQUIRE(handwrittenReader.getTune() == -2); - REQUIRE(handwrittenReader.getStart() == 0); - REQUIRE(handwrittenReader.getEnd() == 2); - REQUIRE(handwrittenReader.getLoopLength() == 1); - REQUIRE(handwrittenReader.isLoopEnabled()); - REQUIRE(handwrittenReader.getNumberOfBeats() == 4); - REQUIRE(handwrittenReader.getSampleRate() == 44100); - REQUIRE(outputData->size() == inputData->size()); - REQUIRE((*outputData)[0] == (*inputData)[0]); - REQUIRE((*outputData)[1] == (*inputData)[1]); + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + const auto loaded = loadWithSoundLoader(mpc, kaitaiBytes, "KICK_01.SND"); + requireSoundMatches( + loaded, + ExpectedSound{ + "KICK_01", + true, + 44100, + 100, + -2, + 4, + 0, + 2, + 1, + true, + *inputData + }); } TEST_CASE("Kaitai MPC2000 SND save/load covers prod-used sound properties", "[kaitai-snd]") @@ -526,7 +508,7 @@ TEST_CASE("Generated MPC2000XL SND corpus loads through the production loader", } } -TEST_CASE("SndReader reads mutated header semantics from Kaitai-written bytes", "[kaitai-snd]") +TEST_CASE("SndIo reads mutated header semantics from Kaitai-written bytes", "[kaitai-snd]") { auto bytes = resourceBytes("test/GeneratedMpc2000xl/Snd/mono_loop_mid.SND"); @@ -550,22 +532,20 @@ TEST_CASE("SndReader reads mutated header semantics from Kaitai-written bytes", rewrittenBytes.assign(written.begin(), written.end()); }); - SndReader handwrittenReader(rewrittenBytes); - auto outputData = std::make_shared>(); - handwrittenReader.readData(outputData); - - REQUIRE(handwrittenReader.isHeaderValid()); - REQUIRE(handwrittenReader.getName() == "mono_loop_mid"); - REQUIRE(handwrittenReader.isMono()); - REQUIRE(handwrittenReader.getSampleRate() == 44100); - REQUIRE(handwrittenReader.getLevel() == 100); - REQUIRE(handwrittenReader.getTune() == 120); - REQUIRE(handwrittenReader.getStart() == 0); - REQUIRE(handwrittenReader.getEnd() == 3); - REQUIRE(handwrittenReader.getLoopLength() == 2); - REQUIRE(!handwrittenReader.isLoopEnabled()); - REQUIRE(handwrittenReader.getNumberOfBeats() == 32); - REQUIRE(outputData->size() == 4U); + auto sound = std::make_shared(44100); + auto result = SndIo::loadBytes(rewrittenBytes, sound, "mono_loop_mid"); + REQUIRE(result); + REQUIRE(sound->getName() == "mono_loop_mid"); + REQUIRE(sound->isMono()); + REQUIRE(sound->getSampleRate() == 44100); + REQUIRE(sound->getSndLevel() == 100); + REQUIRE(sound->getTune() == 120); + REQUIRE(sound->getStart() == 0); + REQUIRE(sound->getEnd() == 3); + REQUIRE(sound->getLoopTo() == 1); + REQUIRE(!sound->isLoopEnabled()); + REQUIRE(sound->getBeatCount() == 32); + REQUIRE(sound->getSampleData()->size() == 4U); } TEST_CASE("SoundLoader loads mutated SND header semantics from Kaitai-written bytes", "[kaitai-snd]") diff --git a/src/test/SndPersistenceTest.cpp b/src/test/SndPersistenceTest.cpp index 6d54c730..929ff150 100644 --- a/src/test/SndPersistenceTest.cpp +++ b/src/test/SndPersistenceTest.cpp @@ -1,13 +1,11 @@ #include #include "sampler/Sound.hpp" -#include "file/sndwriter/SndWriter.hpp" -#include "file/sndreader/SndReader.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/SndIo.hpp" #include "SampleOps.hpp" -using namespace mpc::file::sndwriter; -using namespace mpc::file::sndreader; using namespace mpc::sampleops; TEST_CASE("Sample ops", "[sample-ops]") @@ -24,6 +22,7 @@ TEST_CASE("Sample ops", "[sample-ops]") TEST_CASE("Write and read non-destructively", "[snd-persistence]") { mpc::sampler::Sound snd1(44100); + snd1.setName("snd_persist"); snd1.setMono(true); auto inputData = snd1.getMutableSampleData(); @@ -33,11 +32,13 @@ TEST_CASE("Write and read non-destructively", "[snd-persistence]") inputData->emplace_back(short_to_float(static_cast(i))); } - SndWriter sndWriter(&snd1); - auto &writtenData = sndWriter.getSndFileArray(); - SndReader reader(writtenData); - auto outputData = std::make_shared>(); - reader.readData(outputData); + const auto writtenData = mpc::file::kaitai::SndIo::saveSound(snd1); + auto sound = std::make_shared(44100); + auto result = mpc::file::kaitai::SndIo::loadBytes( + writtenData, sound, "snd_persist"); + REQUIRE(result); + + const auto outputData = sound->getSampleData(); REQUIRE(outputData->size() == snd1.getSampleData()->size()); From cca8569906fa5633306b07003064024bff630e17 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Mon, 22 Jun 2026 21:50:40 +0200 Subject: [PATCH 24/52] Add direct Kaitai MIDI save path --- src/main/disk/AbstractDisk.cpp | 3 - src/main/file/kaitai/MidIo.cpp | 1134 +++++++++++++++++++++++++++++++- src/main/file/kaitai/MidIo.hpp | 5 + src/test/KaitaiMidTest.cpp | 216 ++++-- 4 files changed, 1300 insertions(+), 58 deletions(-) diff --git a/src/main/disk/AbstractDisk.cpp b/src/main/disk/AbstractDisk.cpp index af5825c8..9c4f480a 100644 --- a/src/main/disk/AbstractDisk.cpp +++ b/src/main/disk/AbstractDisk.cpp @@ -8,8 +8,6 @@ #include "disk/ProgramLoader.hpp" #include "file/wav/WavFile.hpp" -#include "file/mid/MidiWriter.hpp" -#include "file/mid/MidiReader.hpp" #include "file/all/AllParser.hpp" #include "file/kaitai/SndIo.hpp" #include "file/kaitai/PgmIo.hpp" @@ -41,7 +39,6 @@ using namespace mpc::input::midi; using namespace mpc::file; using namespace mpc::file::wav; -using namespace mpc::file::mid; using namespace mpc::file::all; using namespace mpc::lcdgui; diff --git a/src/main/file/kaitai/MidIo.cpp b/src/main/file/kaitai/MidIo.cpp index 77424915..613e3f50 100644 --- a/src/main/file/kaitai/MidIo.cpp +++ b/src/main/file/kaitai/MidIo.cpp @@ -5,22 +5,1122 @@ #include "file/kaitai/KaitaiIoUtil.hpp" #include "file/kaitai/generated/standard_midi_file_with_running_status.h" #include "file/mid/MidiReader.hpp" -#include "file/mid/MidiWriter.hpp" +#include "sequencer/BusType.hpp" +#include "sequencer/EventData.hpp" #include "sequencer/Sequence.hpp" #include "sequencer/Sequencer.hpp" +#include "sequencer/TempoChangeEvent.hpp" +#include "sequencer/Track.hpp" +#include "sequencer/Transport.hpp" +#include +#include +#include +#include #include using namespace mpc::file::kaitai; -sequence_or_error MidIo::load(mpc::Mpc &mpc, const std::shared_ptr &file) +namespace { + +using midi_t = standard_midi_file_with_running_status_t; +using meta_type_t = midi_t::meta_event_body_t::meta_type_enum_t; + +std::string asciiBody(const std::string& body) +{ + return kaitai::kstream::bytes_to_str(body, "ASCII"); +} + +bool isInteger(const std::string& s) +{ + for (const auto c : s) + { + if (!std::isdigit(static_cast(c))) + { + return false; + } + } + return true; +} + +bool isMpc2000xlTrackName(const std::string& value) +{ + return value.rfind("MPC2000XL 1.00 ", 0) == 0; +} + +bool isMpc2000xlMetaTrack(const midi_t& parsed) +{ + if (parsed.tracks() == nullptr || parsed.tracks()->empty()) + { + return false; + } + + for (const auto& eventPtr : *parsed.tracks()->at(0)->events()->event()) + { + const auto* meta = eventPtr->meta_event_body(); + if (meta == nullptr || + meta->meta_type() != meta_type_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME) + { + continue; + } + + if (isMpc2000xlTrackName(asciiBody(meta->body()))) + { + return true; + } + } + + return false; +} + +double bpmFromTempoBody(const std::string& body) +{ + if (body.size() < 3) + { + return 120.0; + } + + const auto mpqn = + (static_cast(body[0]) << 16) | + (static_cast(body[1]) << 8) | + static_cast(body[2]); + return mpqn == 0 ? 120.0 : 60000000.0 / static_cast(mpqn); +} + +int denominatorFromTimeSignatureBody(const std::string& body) +{ + return body.size() < 2 ? mpc::DefaultTimeSigDenominator + : 1 << static_cast(body[1]); +} + +struct TimedMidiEvent +{ + int tick; + int order; + std::vector bytes; +}; + +void appendU2Be(std::vector& out, const uint16_t value) +{ + out.push_back(static_cast((value >> 8) & 0xFF)); + out.push_back(static_cast(value & 0xFF)); +} + +void appendU4Be(std::vector& out, const uint32_t value) +{ + out.push_back(static_cast((value >> 24) & 0xFF)); + out.push_back(static_cast((value >> 16) & 0xFF)); + out.push_back(static_cast((value >> 8) & 0xFF)); + out.push_back(static_cast(value & 0xFF)); +} + +void appendVlq(std::vector& out, uint32_t value) +{ + std::array reversed{}; + auto count = 0; + reversed[count++] = static_cast(value & 0x7F); + value >>= 7; + + while (value > 0) + { + reversed[count++] = static_cast((value & 0x7F) | 0x80); + value >>= 7; + } + + for (auto i = count - 1; i >= 0; --i) + { + out.push_back(reversed[i]); + } +} + +std::vector metaEventBytes(const uint8_t type, const std::vector& payload) +{ + std::vector result{ + static_cast(0xFF), + static_cast(type) + }; + appendVlq(result, static_cast(payload.size())); + result.insert(result.end(), payload.begin(), payload.end()); + return result; +} + +std::vector channelEventBytes(const uint8_t status, const uint8_t dataA) +{ + return std::vector{ + static_cast(status), + static_cast(dataA) + }; +} + +std::vector channelEventBytes(const uint8_t status, const uint8_t dataA, const uint8_t dataB) +{ + return std::vector{ + static_cast(status), + static_cast(dataA), + static_cast(dataB) + }; +} + +std::vector sysexEventBytes(const std::vector& payload) +{ + std::vector result{ + static_cast(0xF0) + }; + appendVlq(result, static_cast(payload.size())); + result.insert(result.end(), payload.begin(), payload.end()); + return result; +} + +std::string zeroPad3(const int value) +{ + std::ostringstream ss; + ss << std::setw(3) << std::setfill('0') << std::clamp(value, 0, 999); + return ss.str(); +} + +std::string padRightTruncate(const std::string& value, const size_t width) +{ + if (value.size() >= width) + { + return value.substr(0, width); + } + return value + std::string(width - value.size(), ' '); +} + +std::string hexByte(const int value) +{ + std::ostringstream ss; + ss << std::uppercase << std::hex + << std::setw(2) << std::setfill('0') + << (value & 0xFF); + return ss.str(); +} + +bool isDefaultNoteVariation(const mpc::sequencer::EventData& event) +{ + if (event.noteVariationType == mpc::NoteVariationTypeTune) + { + return event.noteVariationValue == mpc::DefaultNoteVariationValue; + } + if (event.noteVariationType == mpc::NoteVariationTypeDecay || + event.noteVariationType == mpc::NoteVariationTypeAttack) + { + return event.noteVariationValue == 0; + } + if (event.noteVariationType == mpc::NoteVariationTypeFilter) + { + return event.noteVariationValue == 50; + } + return false; +} + +std::string sequenceParamsText(const mpc::sequencer::Sequence& sequence) +{ + const auto loopStart = zeroPad3(sequence.getFirstLoopBarIndex()); + const auto loopEnd = + sequence.getLastLoopBarIndex() == mpc::EndOfSequence + ? std::string("END") + : zeroPad3(sequence.getLastLoopBarIndex()); + + return std::string("LOOP=") + + (sequence.isLoopEnabled() ? "ON " : "OFF") + + " START=" + loopStart + + " END=" + loopEnd + + " TEMPO=" + (sequence.isTempoChangeOn() ? "ON " : "OFF") + " "; +} + +std::vector stringPayload(const std::string& value) +{ + return std::vector(value.begin(), value.end()); +} + +int tempoToMpqn(const double bpm) +{ + const auto clamped = std::clamp(bpm, 30.0, 300.0); + return static_cast(60000000.0 / clamped); +} + +int timeSignatureDenominatorPow(const int denominator) +{ + auto value = denominator; + auto power = 0; + while (value > 1) + { + value >>= 1; + power++; + } + return power; +} + +std::vector serializeTrack(const std::vector& inputEvents, const int lastTick) +{ + auto events = inputEvents; + std::stable_sort( + events.begin(), + events.end(), + [](const auto& a, const auto& b) + { + if (a.tick != b.tick) + { + return a.tick < b.tick; + } + return a.order < b.order; + }); + + std::vector trackBody; + auto previousTick = 0; + for (const auto& event : events) + { + appendVlq(trackBody, static_cast(std::max(0, event.tick - previousTick))); + trackBody.insert(trackBody.end(), event.bytes.begin(), event.bytes.end()); + previousTick = event.tick; + } + + appendVlq(trackBody, static_cast(std::max(0, lastTick - previousTick))); + trackBody.push_back(static_cast(0xFF)); + trackBody.push_back(static_cast(0x2F)); + trackBody.push_back(static_cast(0x00)); + + std::vector result{'M', 'T', 'r', 'k'}; + appendU4Be(result, static_cast(trackBody.size())); + result.insert(result.end(), trackBody.begin(), trackBody.end()); + return result; +} + +std::vector buildMetaTrack(const mpc::sequencer::Sequence& sequence) +{ + std::vector events; + events.push_back(TimedMidiEvent{ + 0, + 0, + metaEventBytes(0x01, stringPayload(sequenceParamsText(sequence))) + }); + events.push_back(TimedMidiEvent{ + 0, + 1, + metaEventBytes( + 0x03, + stringPayload("MPC2000XL 1.00 " + padRightTruncate(sequence.getName(), 16))) + }); + + const auto initialMpqn = tempoToMpqn(sequence.getInitialTempo()); + events.push_back(TimedMidiEvent{ + 0, + 2, + metaEventBytes( + 0x51, + std::vector{ + static_cast((initialMpqn >> 16) & 0xFF), + static_cast((initialMpqn >> 8) & 0xFF), + static_cast(initialMpqn & 0xFF)}) + }); + + for (const auto& tempoChange : sequence.getTempoChangeEvents()) + { + if (tempoChange->getTick() <= 0 || tempoChange->getTick() >= sequence.getLastTick()) + { + continue; + } + + const auto mpqn = tempoToMpqn(tempoChange->getTempo()); + events.push_back(TimedMidiEvent{ + tempoChange->getTick(), + 2, + metaEventBytes( + 0x51, + std::vector{ + static_cast((mpqn >> 16) & 0xFF), + static_cast((mpqn >> 8) & 0xFF), + static_cast(mpqn & 0xFF)}) + }); + } + + events.push_back(TimedMidiEvent{ + 0, + 3, + metaEventBytes(0x54, std::vector{0, 0, 0, 0, 0}) + }); + + auto barStartTick = 0; + auto previousNumerator = sequence.getNumerator(0); + auto previousDenominator = sequence.getDenominator(0); + events.push_back(TimedMidiEvent{ + 0, + 4, + metaEventBytes( + 0x58, + std::vector{ + static_cast(previousNumerator), + static_cast(timeSignatureDenominatorPow(previousDenominator)), + static_cast(24), + static_cast(8)}) + }); + + for (auto barIndex = 1; barIndex <= sequence.getLastBarIndex(); ++barIndex) + { + barStartTick += sequence.getBarLength(barIndex - 1); + const auto numerator = sequence.getNumerator(barIndex); + const auto denominator = sequence.getDenominator(barIndex); + if (numerator == previousNumerator && denominator == previousDenominator) + { + continue; + } + + previousNumerator = numerator; + previousDenominator = denominator; + events.push_back(TimedMidiEvent{ + barStartTick, + 4, + metaEventBytes( + 0x58, + std::vector{ + static_cast(numerator), + static_cast(timeSignatureDenominatorPow(denominator)), + static_cast(24), + static_cast(8)}) + }); + } + + return serializeTrack(events, sequence.getLastTick()); +} + +std::vector buildSequenceTrack(const std::shared_ptr& sequence, + const std::shared_ptr& track) +{ + std::vector events; + events.push_back(TimedMidiEvent{ + 0, + 0, + metaEventBytes(0x04, stringPayload(std::string(8, ' '))) + }); + + const auto deviceIndex = track->getDeviceIndex(); + const auto trackNumber = zeroPad3(track->getIndex()).substr(1, 2); + const auto trackDevice = + deviceIndex == 0 ? std::string("C0") : hexByte(0xE0 + deviceIndex - 1); + const auto deviceNumber = hexByte(deviceIndex); + const auto busIndex = hexByte(static_cast(mpc::sequencer::busTypeToIndex(track->getBusType()))); + events.push_back(TimedMidiEvent{ + 0, + 1, + metaEventBytes( + 0x01, + stringPayload( + "TRACK DATA:" + + trackNumber + + trackDevice + + "006403 " + + deviceNumber + + busIndex + + deviceNumber + + " ")) + }); + events.push_back(TimedMidiEvent{ + 0, + 2, + metaEventBytes(0x03, stringPayload(padRightTruncate(track->getName(), 16))) + }); + + std::vector noteOffEvents; + std::vector noteVariationEvents; + std::vector noteOnEvents; + std::vector miscEvents; + + for (const auto& event : track->getEventStates()) + { + if (event.tick >= sequence->getLastTick()) + { + continue; + } + + switch (event.type) + { + case mpc::sequencer::EventType::NoteOn: + { + const auto noteOffTick = static_cast(event.tick + event.duration); + for (auto& noteOffEvent : noteOffEvents) + { + if (noteOffEvent.tick > event.tick && + noteOffEvent.bytes.size() >= 3 && + static_cast(noteOffEvent.bytes[1]) == + static_cast(event.noteNumber)) + { + noteOffEvent.tick = event.tick; + } + } + + if (!isDefaultNoteVariation(event)) + { + noteVariationEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 1, + channelEventBytes( + 0x80, + static_cast(event.noteVariationType.get()), + static_cast(event.noteVariationValue.get())) + }); + } + + noteOnEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 2, + channelEventBytes( + 0x90, + static_cast(event.noteNumber.get()), + static_cast(event.velocity.get())) + }); + + if (noteOffTick < sequence->getLastTick()) + { + noteOffEvents.push_back(TimedMidiEvent{ + noteOffTick, + 0, + channelEventBytes( + 0x90, + static_cast(event.noteNumber.get()), + 0) + }); + } + break; + } + case mpc::sequencer::EventType::PolyPressure: + miscEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 3, + channelEventBytes( + 0xA0, + static_cast(event.noteNumber.get()), + static_cast(event.amount & 0x7F)) + }); + break; + case mpc::sequencer::EventType::ControlChange: + miscEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 3, + channelEventBytes( + 0xB0, + static_cast(event.controllerNumber & 0x7F), + static_cast(event.controllerValue & 0x7F)) + }); + break; + case mpc::sequencer::EventType::ProgramChange: + miscEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 3, + channelEventBytes( + 0xC0, + static_cast(event.programChangeProgramIndex.get())) + }); + break; + case mpc::sequencer::EventType::ChannelPressure: + miscEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 3, + channelEventBytes( + 0xD0, + static_cast(event.amount & 0x7F)) + }); + break; + case mpc::sequencer::EventType::PitchBend: + { + const auto bendValue = std::clamp(event.amount + 8192, 0, 16383); + miscEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 3, + channelEventBytes( + 0xE0, + static_cast(bendValue & 0x7F), + static_cast((bendValue >> 7) & 0x7F)) + }); + break; + } + case mpc::sequencer::EventType::Mixer: + miscEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 3, + sysexEventBytes(std::vector{ + 71, + 0, + 68, + 69, + static_cast(event.mixerParameter + 1), + static_cast(event.mixerPad), + static_cast(event.mixerValue), + static_cast(0xF7)}) + }); + break; + case mpc::sequencer::EventType::SystemExclusive: + miscEvents.push_back(TimedMidiEvent{ + static_cast(event.tick), + 3, + sysexEventBytes(std::vector{ + static_cast(event.sysExByteA), + static_cast(event.sysExByteB)}) + }); + break; + default: + break; + } + } + + events.insert(events.end(), noteOffEvents.begin(), noteOffEvents.end()); + events.insert(events.end(), noteVariationEvents.begin(), noteVariationEvents.end()); + events.insert(events.end(), noteOnEvents.begin(), noteOnEvents.end()); + events.insert(events.end(), miscEvents.begin(), miscEvents.end()); + return serializeTrack(events, sequence->getLastTick()); +} + +std::vector buildMpc2000xlMidiBytes(const std::shared_ptr& sequence) +{ + auto firstUsedTrackIndex = -1; + auto lastUsedTrackIndex = -1; + for (auto i = 0; i < 64; ++i) + { + if (!sequence->getTrack(i)->isUsed()) + { + continue; + } + if (firstUsedTrackIndex == -1) + { + firstUsedTrackIndex = i; + } + lastUsedTrackIndex = i; + } + + std::vector> tracks; + tracks.push_back(buildMetaTrack(*sequence)); + + for (auto trackIndex = firstUsedTrackIndex; + trackIndex >= 0 && trackIndex <= lastUsedTrackIndex; + ++trackIndex) + { + tracks.push_back(buildSequenceTrack(sequence, sequence->getTrack(trackIndex))); + } + + std::vector result{'M', 'T', 'h', 'd'}; + appendU4Be(result, 6); + appendU2Be(result, tracks.size() > 1 ? 1 : 0); + appendU2Be(result, static_cast(tracks.size())); + appendU2Be(result, 96); + + for (const auto& track : tracks) + { + result.insert(result.end(), track.begin(), track.end()); + } + return result; +} + +bool tryLoadMpc2000xl(mpc::Mpc& mpc, + const midi_t& parsed, + const std::shared_ptr& sequence) +{ + if (!isMpc2000xlMetaTrack(parsed)) + { + return false; + } + + auto sequencer = mpc.getSequencer(); + auto transport = sequencer->getTransport(); + + sequence->setUsed(true); + + struct TimedMetaEvent + { + int tick; + const midi_t::track_event_t* event; + const midi_t::meta_event_body_t* meta; + }; + + std::vector metaTrackEvents; + int tick = 0; + for (const auto& eventPtr : *parsed.tracks()->at(0)->events()->event()) + { + tick += eventPtr->v_time()->value(); + if (const auto* meta = eventPtr->meta_event_body(); meta != nullptr) + { + metaTrackEvents.push_back(TimedMetaEvent{tick, eventPtr.get(), meta}); + } + } + + std::vector> tempoChanges; + struct TimeSigChange { int tick; int numerator; int denominator; }; + std::vector timeSignatures; + int firstLoopBar = -1; + int lastLoopBar = -1; + + for (const auto& entry : metaTrackEvents) + { + const auto metaType = entry.meta->meta_type(); + const auto body = asciiBody(entry.meta->body()); + + if (metaType == meta_type_t::META_TYPE_ENUM_TEXT_EVENT) + { + if (body.find("LOOP=ON") != std::string::npos) + { + sequence->setLoopEnabled(true); + } + else if (body.find("LOOP=OFF") != std::string::npos) + { + sequence->setLoopEnabled(false); + } + + if (body.find("TEMPO=ON") != std::string::npos) + { + transport->setTempoSourceIsSequence(true); + } + else if (body.find("TEMPO=OFF") != std::string::npos) + { + transport->setTempoSourceIsSequence(false); + } + + if (body.size() >= 18) + { + firstLoopBar = std::stoi(body.substr(15, 18)); + } + lastLoopBar = -1; + if (body.size() >= 26) + { + const auto loopEnd = body.substr(23, 26); + if (isInteger(loopEnd)) + { + lastLoopBar = std::stoi(loopEnd); + } + } + } + else if (metaType == meta_type_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME && + isMpc2000xlTrackName(body)) + { + sequence->setName(body.substr(16)); + } + else if (metaType == meta_type_t::META_TYPE_ENUM_TEMPO) + { + tempoChanges.push_back({entry.tick, bpmFromTempoBody(entry.meta->body())}); + } + else if (metaType == meta_type_t::META_TYPE_ENUM_TIME_SIGNATURE) + { + timeSignatures.push_back( + TimeSigChange{ + entry.tick, + entry.meta->body().empty() + ? mpc::DefaultTimeSigNumerator + : static_cast(entry.meta->body()[0]), + denominatorFromTimeSignatureBody(entry.meta->body())}); + } + } + + const auto initialTempo = tempoChanges.empty() ? 120.0 : tempoChanges[0].second; + sequence->setInitialTempo(initialTempo); + if (!transport->isTempoSourceSequence()) + { + transport->setTempo(initialTempo); + } + + for (size_t i = 1; i < tempoChanges.size(); ++i) + { + const auto ratio = tempoChanges[i].second / initialTempo; + sequence->addTempoChangeEvent(tempoChanges[i].first, + static_cast(ratio * 1000.0)); + } + + const bool hadExplicitTimeSignatures = !timeSignatures.empty(); + if (!hadExplicitTimeSignatures) + { + timeSignatures.push_back( + TimeSigChange{0, mpc::DefaultTimeSigNumerator, mpc::DefaultTimeSigDenominator}); + } + + int lengthInTicks = 1; + for (const auto& trackPtr : *parsed.tracks()) + { + int trackTick = 0; + for (const auto& eventPtr : *trackPtr->events()->event()) + { + trackTick += eventPtr->v_time()->value(); + } + lengthInTicks = std::max(lengthInTicks, trackTick); + } + + int accumLength = 0; + int barCounter = 0; + for (size_t i = 0; i < timeSignatures.size(); ++i) + { + const auto current = timeSignatures[i]; + const auto hasNext = i + 1 < timeSignatures.size(); + const auto nextTick = hasNext ? timeSignatures[i + 1].tick : lengthInTicks; + + while (accumLength < nextTick) + { + sequence->setTimeSignature(barCounter, current.numerator, current.denominator); + const auto newDenTicks = 96 * (4.0 / current.denominator); + const auto barLength = static_cast(newDenTicks * current.numerator); + accumLength += barLength; + barCounter++; + } + } + + sequence->setLastBarIndex(barCounter - 1); + sequence->setFirstLoopBarIndex(mpc::BarIndex(firstLoopBar)); + if (lastLoopBar == -1) + { + sequence->setLastLoopBarIndex(mpc::EndOfSequence); + } + else + { + sequence->setLastLoopBarIndex(mpc::BarIndex(lastLoopBar)); + } + + for (size_t trackContainerIndex = 1; trackContainerIndex < parsed.tracks()->size(); ++trackContainerIndex) + { + const auto& midiTrack = parsed.tracks()->at(trackContainerIndex); + auto trackIndex = static_cast(trackContainerIndex - 1); + auto deviceIndex = 0; + auto busType = mpc::sequencer::BusType::DRUM1; + auto track = sequence->getTrack(trackIndex); + + struct OpenNote + { + mpc::sequencer::EventData event; + bool isClosed = false; + }; + + auto noteVariationType = mpc::NoteVariationTypeTune; + auto noteVariationValue = mpc::DefaultNoteVariationValue; + std::vector openNotes; + bool hasImportedEvents = false; + int absoluteTick = 0; + + for (const auto& eventPtr : *midiTrack->events()->event()) + { + absoluteTick += eventPtr->v_time()->value(); + + if (const auto* meta = eventPtr->meta_event_body(); meta != nullptr) + { + const auto body = asciiBody(meta->body()); + if (meta->meta_type() == meta_type_t::META_TYPE_ENUM_TEXT_EVENT && + body.find("TRACK DATA:") != std::string::npos) + { + const auto payload = body.substr(std::string("TRACK DATA:").length()); + trackIndex = std::stoi(payload.substr(0, 2)); + if (payload.substr(2, 2) != "C0") + { + deviceIndex = + std::stoi(payload.substr(2, 2), nullptr, 16) - + std::stoi(std::string("E0"), nullptr, 16) + 1; + } + if (payload.size() >= 16) + { + busType = mpc::sequencer::busIndexToBusType( + std::stoi(payload.substr(14, 2), nullptr, 16)); + } + track = sequence->getTrack(trackIndex); + track->setBusType(busType, false); + track->setDeviceIndex(deviceIndex, false); + } + else if (meta->meta_type() == + meta_type_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME && + !body.empty()) + { + track->setName( + body.substr(0, mpc::Mpc2000XlSpecs::MAX_TRACK_NAME_LENGTH)); + } + continue; + } + + switch (eventPtr->event_type()) + { + case 0x80: + { + const auto* noteOff = + dynamic_cast(eventPtr->event_body()); + if (noteOff == nullptr) + { + break; + } + noteVariationType = + mpc::NoteVariationType(noteOff->note()); + noteVariationValue = + mpc::NoteVariationValue(noteOff->velocity()); + break; + } + case 0x90: + { + const auto* noteOn = + dynamic_cast(eventPtr->event_body()); + if (noteOn == nullptr) + { + break; + } + + if (noteOn->velocity() == 0) + { + auto bestIt = openNotes.end(); + const auto isDefaultVariation = + [](const mpc::sequencer::EventData& event) + { + if (event.noteVariationType == mpc::NoteVariationTypeTune) + { + return event.noteVariationValue == + mpc::DefaultNoteVariationValue; + } + if (event.noteVariationType == mpc::NoteVariationTypeDecay || + event.noteVariationType == mpc::NoteVariationTypeAttack) + { + return event.noteVariationValue == 0; + } + if (event.noteVariationType == mpc::NoteVariationTypeFilter) + { + return event.noteVariationValue == 50; + } + return false; + }; + const auto isEligible = + [&](const OpenNote& openNote) + { + return !openNote.isClosed && + openNote.event.noteNumber == + mpc::NoteNumber(noteOn->note()) && + openNote.event.tick <= absoluteTick; + }; + + auto latestNonDefaultIt = openNotes.end(); + for (auto it = openNotes.rbegin(); it != openNotes.rend(); ++it) + { + if (!isEligible(*it) || isDefaultVariation(it->event)) + { + continue; + } + latestNonDefaultIt = std::prev(it.base()); + break; + } + + if (latestNonDefaultIt != openNotes.end()) + { + auto sameVariationCount = 0; + for (auto it = openNotes.begin(); it != openNotes.end(); ++it) + { + if (!isEligible(*it)) + { + continue; + } + if (it->event.noteVariationType == + latestNonDefaultIt->event.noteVariationType && + it->event.noteVariationValue == + latestNonDefaultIt->event.noteVariationValue) + { + sameVariationCount++; + if (bestIt == openNotes.end()) + { + bestIt = it; + } + } + } + + if (sameVariationCount < 2) + { + bestIt = openNotes.end(); + } + } + + if (bestIt == openNotes.end()) + { + for (auto it = openNotes.begin(); it != openNotes.end(); ++it) + { + if (!isEligible(*it)) + { + continue; + } + bestIt = it; + break; + } + } + + if (bestIt != openNotes.end()) + { + bestIt->event.duration = + mpc::Duration(absoluteTick - bestIt->event.tick); + bestIt->isClosed = true; + } + } + else + { + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::NoteOn; + e.noteNumber = mpc::NoteNumber(noteOn->note()); + e.tick = absoluteTick; + e.velocity = mpc::Velocity(noteOn->velocity()); + e.noteVariationType = noteVariationType; + e.noteVariationValue = noteVariationValue; + e.duration = mpc::Duration(24); + openNotes.push_back(OpenNote{e}); + noteVariationType = mpc::NoteVariationTypeTune; + noteVariationValue = mpc::DefaultNoteVariationValue; + } + break; + } + case 0xA0: + { + const auto* noteAftertouch = + dynamic_cast(eventPtr->event_body()); + if (noteAftertouch == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::PolyPressure; + e.tick = absoluteTick; + e.noteNumber = mpc::NoteNumber(noteAftertouch->note()); + e.amount = noteAftertouch->pressure(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xB0: + { + const auto* controller = + dynamic_cast(eventPtr->event_body()); + if (controller == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ControlChange; + e.tick = absoluteTick; + e.controllerNumber = controller->controller(); + e.controllerValue = controller->value(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xC0: + { + const auto* programChange = + dynamic_cast(eventPtr->event_body()); + if (programChange == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ProgramChange; + e.tick = absoluteTick; + e.programChangeProgramIndex = + mpc::ProgramIndex(programChange->program()); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xD0: + { + const auto* channelPressure = + dynamic_cast(eventPtr->event_body()); + if (channelPressure == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ChannelPressure; + e.tick = absoluteTick; + e.amount = channelPressure->pressure(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xE0: + { + auto* pitchBend = + dynamic_cast(eventPtr->event_body()); + if (pitchBend == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::PitchBend; + e.tick = absoluteTick; + e.amount = pitchBend->bend_value(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xF0: + { + const auto* sysEx = eventPtr->sysex_body(); + if (sysEx == nullptr) + { + break; + } + const auto& data = sysEx->data(); + if (data.size() == 8 && + static_cast(data[0]) == 71 && + static_cast(data[1]) == 0 && + static_cast(data[2]) == 68 && + static_cast(data[3]) == 69 && + static_cast(data[7]) == 247) + { + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::Mixer; + e.tick = absoluteTick; + e.mixerParameter = static_cast(data[4]) - 1; + e.mixerPad = static_cast(data[5]); + e.mixerValue = static_cast(data[6]); + track->acquireAndInsertEvent(e); + } + else if (data.size() >= 2) + { + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::SystemExclusive; + e.tick = absoluteTick; + e.sysExByteA = static_cast(data[0]); + e.sysExByteB = static_cast(data[1]); + track->acquireAndInsertEvent(e); + } + hasImportedEvents = true; + break; + } + } + } + + for (const auto& openNote : openNotes) + { + track->acquireAndInsertEvent(openNote.event); + hasImportedEvents = true; + } + + if (hasImportedEvents) + { + track->setUsedIfCurrentlyUnused(); + } + } + + return true; +} + +} // namespace + +sequence_or_error MidIo::loadBytes(mpc::Mpc &mpc, + const std::vector &bytes, + const std::string &fileNameWithoutExtension) { - const auto bytes = file->getBytes(); const auto canonicalBytes = parseRewrite(bytes); auto newSeq = mpc.getSequencer()->getSequence(mpc::TempSequenceIndex); newSeq->init(0); + std::stringstream kaitaiStream( + std::string(canonicalBytes.begin(), canonicalBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream kaitaiIo(&kaitaiStream); + midi_t parsed(&kaitaiIo); + parsed._read(); + + if (tryLoadMpc2000xl(mpc, parsed, newSeq)) + { + if (newSeq->getName().empty()) + { + newSeq->setName(fileNameWithoutExtension); + } + return newSeq; + } + auto input = std::make_shared( std::string(canonicalBytes.begin(), canonicalBytes.end()), std::ios::in | std::ios::binary @@ -30,26 +1130,26 @@ sequence_or_error MidIo::load(mpc::Mpc &mpc, const std::shared_ptrgetName().empty()) { - newSeq->setName(file->getNameWithoutExtension()); + newSeq->setName(fileNameWithoutExtension); } return newSeq; } -void MidIo::save(const std::shared_ptr &sequence, - const std::shared_ptr &outputStream) +sequence_or_error MidIo::load(mpc::Mpc &mpc, const std::shared_ptr &file) { - mpc::file::mid::MidiWriter handwrittenWriter(sequence.get()); - auto handwrittenStream = std::make_shared(); - handwrittenWriter.writeToOStream(handwrittenStream); - const auto handwrittenBytesString = handwrittenStream->str(); - const std::vector handwrittenBytes( - handwrittenBytesString.begin(), - handwrittenBytesString.end() - ); + return loadBytes(mpc, file->getBytes(), file->getNameWithoutExtension()); +} - const auto canonicalBytes = - parseRewrite(handwrittenBytes); +std::vector MidIo::saveBytes(const std::shared_ptr &sequence) +{ + return parseRewrite( + buildMpc2000xlMidiBytes(sequence)); +} - outputStream->write(canonicalBytes.data(), static_cast(canonicalBytes.size())); +void MidIo::save(const std::shared_ptr &sequence, + const std::shared_ptr &outputStream) +{ + const auto bytes = saveBytes(sequence); + outputStream->write(bytes.data(), static_cast(bytes.size())); } diff --git a/src/main/file/kaitai/MidIo.hpp b/src/main/file/kaitai/MidIo.hpp index 6da4376b..d2cb8b42 100644 --- a/src/main/file/kaitai/MidIo.hpp +++ b/src/main/file/kaitai/MidIo.hpp @@ -26,7 +26,12 @@ namespace mpc::file::kaitai class MidIo { public: + static sequence_or_error loadBytes( + mpc::Mpc &, + const std::vector &, + const std::string &fileNameWithoutExtension); static sequence_or_error load(mpc::Mpc &, const std::shared_ptr &); + static std::vector saveBytes(const std::shared_ptr &); static void save(const std::shared_ptr &, const std::shared_ptr &); }; } diff --git a/src/test/KaitaiMidTest.cpp b/src/test/KaitaiMidTest.cpp index 62c8c081..3f590928 100644 --- a/src/test/KaitaiMidTest.cpp +++ b/src/test/KaitaiMidTest.cpp @@ -6,18 +6,23 @@ #include "disk/MpcFile.hpp" #include "file/kaitai/MidIo.hpp" #include "file/kaitai/generated/standard_midi_file_with_running_status.h" -#include "file/mid/MidiReader.hpp" -#include "file/mid/MidiWriter.hpp" +#include "sequencer/ChannelPressureEvent.hpp" +#include "sequencer/ControlChangeEvent.hpp" +#include "sequencer/MixerEvent.hpp" #include "sequencer/NoteOnEvent.hpp" +#include "sequencer/PolyPressureEvent.hpp" +#include "sequencer/ProgramChangeEvent.hpp" #include "sequencer/Sequence.hpp" #include "sequencer/Sequencer.hpp" #include "sequencer/SequencerStateManager.hpp" #include "sequencer/Track.hpp" +#include "sequencer/Transport.hpp" #include #include #include +#include #include #include #include @@ -60,6 +65,17 @@ std::vector collectParsedNotes(const std::shared_ptr +std::shared_ptr findEventOfType(const std::shared_ptr& track) +{ + for (const auto& event : track->getEvents()) { + if (const auto cast = std::dynamic_pointer_cast(event)) { + return cast; + } + } + return {}; +} + std::shared_ptr installMidiResourceFile( mpc::Mpc& mpc, const std::string& resourcePath, @@ -88,6 +104,25 @@ std::shared_ptr installMidiBytes( return newFile; } +std::vector saveSequenceWithMidIo( + const std::shared_ptr& sequence) +{ + return mpc::file::kaitai::MidIo::saveBytes(sequence); +} + +std::shared_ptr loadSequenceWithMidIo( + mpc::Mpc& mpc, + const std::vector& bytes, + const std::string& fileName) +{ + const auto stem = fileName.substr(0, fileName.find_last_of('.')); + const auto sequenceOrError = mpc::file::kaitai::MidIo::loadBytes(mpc, bytes, stem); + REQUIRE(sequenceOrError.has_value()); + auto stateManager = mpc.getSequencer()->getStateManager(); + stateManager->drainQueue(); + return sequenceOrError.value(); +} + void insertNote( const std::shared_ptr& track, int tick, @@ -142,7 +177,7 @@ TEST_CASE("Kaitai standard MIDI parses and rewrites FRUTZLE", "[kaitai-mid]") REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); } -TEST_CASE("Kaitai standard MIDI matches handwritten MIDI bytes", "[kaitai-mid]") +TEST_CASE("Kaitai standard MIDI saves and loads explicit sequence semantics", "[kaitai-mid]") { mpc::Mpc mpc; mpc::TestMpc::initializeTestMpc(mpc); @@ -167,13 +202,10 @@ TEST_CASE("Kaitai standard MIDI matches handwritten MIDI bytes", "[kaitai-mid]") track0->acquireAndInsertEvent(eventData); stateManager->drainQueue(); - mpc::file::mid::MidiWriter handwrittenWriter(sequence.get()); - auto handwrittenStream = std::make_shared(); - handwrittenWriter.writeToOStream(handwrittenStream); - const auto handwrittenBytes = handwrittenStream->str(); + const auto savedBytes = saveSequenceWithMidIo(sequence); std::stringstream parseStream( - handwrittenBytes, + std::string(savedBytes.begin(), savedBytes.end()), std::ios::in | std::ios::out | std::ios::binary ); kaitai::kstream parseIo(&parseStream); @@ -192,17 +224,13 @@ TEST_CASE("Kaitai standard MIDI matches handwritten MIDI bytes", "[kaitai-mid]") parsed._write(); const auto kaitaiBytes = writeStream.str(); - REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); - REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); - - auto reloadSequence = sequencer->getSequence(0); - reloadSequence->init(1); - stateManager->drainQueue(); + REQUIRE(kaitaiBytes.size() == savedBytes.size()); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), savedBytes.begin())); - auto input = std::make_shared(kaitaiBytes); - mpc::file::mid::MidiReader reader(input, reloadSequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); + auto reloadSequence = loadSequenceWithMidIo( + mpc, + std::vector(kaitaiBytes.begin(), kaitaiBytes.end()), + "KTAIMID.MID"); REQUIRE(reloadSequence->getTrack(0)->getDeviceIndex() == 2); REQUIRE(reloadSequence->getTrack(0)->getEvents().size() == 1); @@ -215,7 +243,7 @@ TEST_CASE("Kaitai standard MIDI matches handwritten MIDI bytes", "[kaitai-mid]") REQUIRE(note->getDuration() == 10); } -TEST_CASE("Kaitai standard MIDI roundtrips broad handwritten note semantics", "[kaitai-mid]") +TEST_CASE("Kaitai standard MIDI roundtrips broad sequence semantics", "[kaitai-mid]") { mpc::Mpc mpc; mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); @@ -243,13 +271,10 @@ TEST_CASE("Kaitai standard MIDI roundtrips broad handwritten note semantics", "[ insertNote(track1, 60, 45, 99, 88, mpc::NoteVariationTypeTune, 64); stateManager->drainQueue(); - mpc::file::mid::MidiWriter handwrittenWriter(sequence.get()); - auto handwrittenStream = std::make_shared(); - handwrittenWriter.writeToOStream(handwrittenStream); - const auto handwrittenBytes = handwrittenStream->str(); + const auto savedBytes = saveSequenceWithMidIo(sequence); std::stringstream parseStream( - handwrittenBytes, + std::string(savedBytes.begin(), savedBytes.end()), std::ios::in | std::ios::out | std::ios::binary ); kaitai::kstream parseIo(&parseStream); @@ -263,17 +288,13 @@ TEST_CASE("Kaitai standard MIDI roundtrips broad handwritten note semantics", "[ parsed._write(); const auto kaitaiBytes = writeStream.str(); - REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); - REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); + REQUIRE(kaitaiBytes.size() == savedBytes.size()); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), savedBytes.begin())); - auto reloadSequence = sequencer->getSequence(0); - reloadSequence->init(1); - stateManager->drainQueue(); - - auto input = std::make_shared(kaitaiBytes); - mpc::file::mid::MidiReader reader(input, reloadSequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); + auto reloadSequence = loadSequenceWithMidIo( + mpc, + std::vector(kaitaiBytes.begin(), kaitaiBytes.end()), + "MIDBROAD.MID"); REQUIRE(reloadSequence->getTrack(0)->getBusType() == mpc::sequencer::BusType::DRUM3); REQUIRE(reloadSequence->getTrack(0)->getDeviceIndex() == 7); @@ -293,7 +314,7 @@ TEST_CASE("Kaitai standard MIDI roundtrips broad handwritten note semantics", "[ REQUIRE(collectParsedNotes(reloadSequence->getTrack(1)) == expectedTrack1); } -TEST_CASE("Kaitai standard MIDI production load preserves broad handwritten note semantics", "[kaitai-mid]") +TEST_CASE("Kaitai standard MIDI production load preserves broad sequence semantics", "[kaitai-mid]") { mpc::Mpc sourceMpc; mpc::TestMpc::initializeTestMpcWithoutMidiServices(sourceMpc); @@ -356,6 +377,120 @@ TEST_CASE("Kaitai standard MIDI production load preserves broad handwritten note REQUIRE(collectParsedNotes(sequence->getTrack(1)) == expectedTrack1); } +TEST_CASE("Kaitai standard MIDI roundtrips MPC2000XL meta and channel events", "[kaitai-mid]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto sequencer = mpc.getSequencer(); + auto stateManager = sequencer->getStateManager(); + auto sequence = sequencer->getSequence(0); + sequence->init(1); + sequence->setName("MIDMETA"); + sequence->setLoopEnabled(false); + sequence->setLastLoopBarIndex(mpc::BarIndex(1)); + sequence->setInitialTempo(98.7); + sequence->setTempoChangeOn(true); + sequence->addTempoChangeEvent(96, 1250); + sequence->setTimeSignature(1, 3, 4); + + auto track = sequence->getTrack(0); + track->setUsedIfCurrentlyUnused(); + track->setName("CTRLMETA"); + track->setBusType(mpc::sequencer::BusType::MIDI); + track->setDeviceIndex(5); + + insertNote(track, 0, 57, 101, 24, mpc::NoteVariationTypeTune, 64); + + mpc::sequencer::EventData polyPressure; + polyPressure.type = mpc::sequencer::EventType::PolyPressure; + polyPressure.tick = 12; + polyPressure.noteNumber = mpc::NoteNumber(57); + polyPressure.amount = 54; + track->acquireAndInsertEvent(polyPressure); + + mpc::sequencer::EventData controlChange; + controlChange.type = mpc::sequencer::EventType::ControlChange; + controlChange.tick = 24; + controlChange.controllerNumber = 7; + controlChange.controllerValue = 99; + track->acquireAndInsertEvent(controlChange); + + mpc::sequencer::EventData programChange; + programChange.type = mpc::sequencer::EventType::ProgramChange; + programChange.tick = 36; + programChange.programChangeProgramIndex = mpc::ProgramIndex(12); + track->acquireAndInsertEvent(programChange); + + mpc::sequencer::EventData channelPressure; + channelPressure.type = mpc::sequencer::EventType::ChannelPressure; + channelPressure.tick = 48; + channelPressure.amount = 60; + track->acquireAndInsertEvent(channelPressure); + + mpc::sequencer::EventData mixer; + mixer.type = mpc::sequencer::EventType::Mixer; + mixer.tick = 60; + mixer.mixerParameter = 3; + mixer.mixerPad = 12; + mixer.mixerValue = 87; + track->acquireAndInsertEvent(mixer); + + stateManager->drainQueue(); + + auto reloaded = loadSequenceWithMidIo(mpc, saveSequenceWithMidIo(sequence), "MIDMETA.MID"); + auto reloadedTrack = reloaded->getTrack(0); + + REQUIRE(reloaded->getName() == "MIDMETA "); + REQUIRE(reloaded->isLoopEnabled() == false); + REQUIRE(reloaded->getFirstLoopBarIndex() == mpc::BarIndex(0)); + REQUIRE(reloaded->getLastLoopBarIndex() == mpc::EndOfSequence); + REQUIRE(mpc.getSequencer()->getTransport()->isTempoSourceSequence()); + REQUIRE(std::abs(reloaded->getInitialTempo() - 98.7) < 0.2); + REQUIRE(reloaded->getNumerator(0) == 4); + REQUIRE(reloaded->getDenominator(0) == 4); + REQUIRE(reloaded->getNumerator(1) == 3); + REQUIRE(reloaded->getDenominator(1) == 4); + REQUIRE(reloadedTrack->getName() == "CTRLMETA "); + REQUIRE(reloadedTrack->getBusType() == mpc::sequencer::BusType::MIDI); + REQUIRE(reloadedTrack->getDeviceIndex() == 5); + + const auto notes = collectParsedNotes(reloadedTrack); + REQUIRE(notes == std::vector{ + {57, 101, 24, mpc::NoteVariationTypeTune} + }); + + const auto reloadedPolyPressure = + findEventOfType(reloadedTrack); + REQUIRE(reloadedPolyPressure); + REQUIRE(reloadedPolyPressure->getNote() == 57); + REQUIRE(reloadedPolyPressure->getAmount() == 54); + + const auto reloadedControlChange = + findEventOfType(reloadedTrack); + REQUIRE(reloadedControlChange); + REQUIRE(reloadedControlChange->getController() == 7); + REQUIRE(reloadedControlChange->getAmount() == 99); + + const auto reloadedProgramChange = + findEventOfType(reloadedTrack); + REQUIRE(reloadedProgramChange); + REQUIRE(reloadedProgramChange->getProgram() == 12); + + const auto reloadedChannelPressure = + findEventOfType(reloadedTrack); + REQUIRE(reloadedChannelPressure); + REQUIRE(reloadedChannelPressure->getAmount() == 60); + + const auto reloadedMixer = + findEventOfType(reloadedTrack); + REQUIRE(reloadedMixer); + REQUIRE(reloadedMixer->getParameter() == 3); + REQUIRE(reloadedMixer->getPad() == 12); + REQUIRE(reloadedMixer->getValue() == 87); + +} + TEST_CASE("Kaitai standard MIDI parses and rewrites real 2KXL SEQ", "[kaitai-mid][real-2kxl]") { auto fs = cmrc::mpctest::get_filesystem(); @@ -389,9 +524,14 @@ TEST_CASE("Kaitai standard MIDI parses and rewrites real 2KXL SEQ", "[kaitai-mid sequence->init(1); stateManager->drainQueue(); - auto input = std::make_shared(rewrittenBytes); - mpc::file::mid::MidiReader reader(input, sequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); + auto midiFile = installMidiBytes( + mpc, + std::vector(rewrittenBytes.begin(), rewrittenBytes.end()), + "SEQ.MID"); + REQUIRE(midiFile); + const auto sequenceOrError = mpc::file::kaitai::MidIo::load(mpc, midiFile); + REQUIRE(sequenceOrError.has_value()); + sequence = sequenceOrError.value(); stateManager->drainQueue(); REQUIRE(sequence->getBarCount() == 1); From dfb3c6f7bebc07ebc024c8a678405fa8a88553d0 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:28:39 +0200 Subject: [PATCH 25/52] Retire handwritten MIDI and ALL parsers --- src/main/AutoSave.cpp | 12 +- src/main/disk/AbstractDisk.cpp | 3 - src/main/disk/AllLoader.cpp | 507 +++++++-- src/main/disk/AllLoader.hpp | 9 +- src/main/file/all/AllChannelPressureEvent.cpp | 29 - src/main/file/all/AllChannelPressureEvent.hpp | 17 - src/main/file/all/AllControlChangeEvent.cpp | 31 - src/main/file/all/AllControlChangeEvent.hpp | 18 - src/main/file/all/AllEvent.cpp | 106 -- src/main/file/all/AllEvent.hpp | 39 - src/main/file/all/AllNoteEvent.cpp | 182 ---- src/main/file/all/AllNoteEvent.hpp | 47 - src/main/file/all/AllParser.cpp | 293 ------ src/main/file/all/AllParser.hpp | 92 -- src/main/file/all/AllPitchBendEvent.cpp | 51 - src/main/file/all/AllPitchBendEvent.hpp | 17 - src/main/file/all/AllPolyPressureEvent.cpp | 31 - src/main/file/all/AllPolyPressureEvent.hpp | 18 - src/main/file/all/AllProgramChangeEvent.cpp | 29 - src/main/file/all/AllProgramChangeEvent.hpp | 17 - src/main/file/all/AllSequence.cpp | 556 ---------- src/main/file/all/AllSequence.hpp | 131 --- src/main/file/all/AllSequencer.cpp | 82 -- src/main/file/all/AllSequencer.hpp | 45 - src/main/file/all/AllSong.cpp | 138 --- src/main/file/all/AllSong.hpp | 65 -- src/main/file/all/AllSysExEvent.cpp | 115 -- src/main/file/all/AllSysExEvent.hpp | 31 - src/main/file/all/Bar.cpp | 66 -- src/main/file/all/Bar.hpp | 28 - src/main/file/all/BarList.cpp | 77 -- src/main/file/all/BarList.hpp | 29 - src/main/file/all/Count.cpp | 141 --- src/main/file/all/Count.hpp | 64 -- src/main/file/all/Defaults.cpp | 25 +- src/main/file/all/Defaults.hpp | 3 + src/main/file/all/Header.cpp | 50 - src/main/file/all/Header.hpp | 21 - src/main/file/all/MidiInput.cpp | 180 ---- src/main/file/all/MidiInput.hpp | 70 -- src/main/file/all/MidiSyncMisc.cpp | 113 -- src/main/file/all/MidiSyncMisc.hpp | 59 -- src/main/file/all/Misc.cpp | 183 ---- src/main/file/all/Misc.hpp | 56 - src/main/file/all/SequenceNames.cpp | 130 --- src/main/file/all/SequenceNames.hpp | 38 - src/main/file/all/Tracks.cpp | 157 --- src/main/file/all/Tracks.hpp | 55 - src/main/file/kaitai/AllIo.cpp | 995 +++++++++++++++++- src/main/file/kaitai/MidIo.cpp | 400 ++++++- .../file/kaitai/generated/mpc2000xl_all.cpp | 22 +- .../file/kaitai/generated/mpc2000xl_all.h | 60 +- .../file/kaitai/generated/mpc2000xl_aps.cpp | 15 +- .../file/kaitai/generated/mpc2000xl_aps.h | 19 +- .../file/kaitai/generated/mpc2000xl_mid.h | 2 +- .../file/kaitai/generated/mpc2000xl_pgm.h | 6 +- ...standard_midi_file_with_running_status.cpp | 4 +- .../standard_midi_file_with_running_status.h | 26 +- .../file/kaitai/generated/vlq_base128_be.h | 2 +- src/main/file/mid/MidiFile.cpp | 133 --- src/main/file/mid/MidiFile.hpp | 48 - src/main/file/mid/MidiReader.cpp | 664 ------------ src/main/file/mid/MidiReader.hpp | 54 - src/main/file/mid/MidiTrack.cpp | 301 ------ src/main/file/mid/MidiTrack.hpp | 56 - src/main/file/mid/MidiWriter.cpp | 389 ------- src/main/file/mid/MidiWriter.hpp | 34 - src/main/file/mid/event/ChannelAftertouch.cpp | 26 - src/main/file/mid/event/ChannelAftertouch.hpp | 15 - src/main/file/mid/event/ChannelEvent.cpp | 145 --- src/main/file/mid/event/ChannelEvent.hpp | 43 - src/main/file/mid/event/Controller.cpp | 36 - src/main/file/mid/event/Controller.hpp | 19 - src/main/file/mid/event/MidiEvent.cpp | 140 --- src/main/file/mid/event/MidiEvent.hpp | 44 - src/main/file/mid/event/NoteAftertouch.cpp | 36 - src/main/file/mid/event/NoteAftertouch.hpp | 19 - src/main/file/mid/event/NoteOff.cpp | 35 - src/main/file/mid/event/NoteOff.hpp | 17 - src/main/file/mid/event/NoteOn.cpp | 35 - src/main/file/mid/event/NoteOn.hpp | 20 - src/main/file/mid/event/PitchBend.cpp | 49 - src/main/file/mid/event/PitchBend.hpp | 20 - src/main/file/mid/event/ProgramChange.cpp | 25 - src/main/file/mid/event/ProgramChange.hpp | 15 - src/main/file/mid/event/SystemExclusive.cpp | 100 -- src/main/file/mid/event/SystemExclusive.hpp | 29 - .../file/mid/event/meta/CopyrightNotice.cpp | 20 - .../file/mid/event/meta/CopyrightNotice.hpp | 17 - src/main/file/mid/event/meta/CuePoint.cpp | 20 - src/main/file/mid/event/meta/CuePoint.hpp | 15 - src/main/file/mid/event/meta/EndOfTrack.cpp | 46 - src/main/file/mid/event/meta/EndOfTrack.hpp | 20 - src/main/file/mid/event/meta/FrameRate.cpp | 69 -- src/main/file/mid/event/meta/FrameRate.hpp | 30 - .../file/mid/event/meta/GenericMetaEvent.cpp | 45 - .../file/mid/event/meta/GenericMetaEvent.hpp | 23 - .../file/mid/event/meta/InstrumentName.cpp | 20 - .../file/mid/event/meta/InstrumentName.hpp | 15 - src/main/file/mid/event/meta/KeySignature.cpp | 110 -- src/main/file/mid/event/meta/KeySignature.hpp | 35 - src/main/file/mid/event/meta/Marker.cpp | 20 - src/main/file/mid/event/meta/Marker.hpp | 17 - src/main/file/mid/event/meta/MetaEvent.cpp | 137 --- src/main/file/mid/event/meta/MetaEvent.hpp | 43 - .../file/mid/event/meta/MetaEventData.cpp | 17 - .../file/mid/event/meta/MetaEventData.hpp | 20 - .../file/mid/event/meta/MidiChannelPrefix.cpp | 55 - .../file/mid/event/meta/MidiChannelPrefix.hpp | 29 - .../file/mid/event/meta/SequenceNumber.cpp | 84 -- .../file/mid/event/meta/SequenceNumber.hpp | 30 - .../mid/event/meta/SequencerSpecificEvent.cpp | 68 -- .../mid/event/meta/SequencerSpecificEvent.hpp | 25 - src/main/file/mid/event/meta/SmpteOffset.cpp | 145 --- src/main/file/mid/event/meta/SmpteOffset.hpp | 53 - src/main/file/mid/event/meta/Tempo.cpp | 88 -- src/main/file/mid/event/meta/Tempo.hpp | 38 - src/main/file/mid/event/meta/Text.cpp | 10 - src/main/file/mid/event/meta/Text.hpp | 12 - .../file/mid/event/meta/TextualMetaEvent.cpp | 66 -- .../file/mid/event/meta/TextualMetaEvent.hpp | 27 - .../mid/event/meta/TimeSignatureEvent.cpp | 150 --- .../mid/event/meta/TimeSignatureEvent.hpp | 54 - src/main/file/mid/event/meta/TrackName.cpp | 20 - src/main/file/mid/event/meta/TrackName.hpp | 17 - src/main/file/mid/util/MidiUtil.cpp | 73 -- src/main/file/mid/util/MidiUtil.hpp | 23 - src/main/file/mid/util/VariableLengthInt.cpp | 112 -- src/main/file/mid/util/VariableLengthInt.hpp | 33 - src/main/lcdgui/screens/SecondSeqScreen.hpp | 6 - src/main/lcdgui/screens/SyncScreen.cpp | 25 + src/main/lcdgui/screens/SyncScreen.hpp | 13 +- src/main/lcdgui/screens/UserScreen.hpp | 3 +- src/main/nvram/DefaultsParser.cpp | 3 +- src/main/nvram/NvRam.cpp | 3 +- src/test/AllFileTest.cpp | 36 +- src/test/AllLoadingTest.cpp | 67 -- src/test/KaitaiAllTest.cpp | 364 ++++++- src/test/KaitaiMidTest.cpp | 809 ++++++++++++++ src/test/MidiFileTest.cpp | 259 +---- 140 files changed, 3075 insertions(+), 8818 deletions(-) delete mode 100644 src/main/file/all/AllChannelPressureEvent.cpp delete mode 100644 src/main/file/all/AllChannelPressureEvent.hpp delete mode 100644 src/main/file/all/AllControlChangeEvent.cpp delete mode 100644 src/main/file/all/AllControlChangeEvent.hpp delete mode 100644 src/main/file/all/AllEvent.cpp delete mode 100644 src/main/file/all/AllEvent.hpp delete mode 100644 src/main/file/all/AllNoteEvent.cpp delete mode 100644 src/main/file/all/AllNoteEvent.hpp delete mode 100644 src/main/file/all/AllParser.cpp delete mode 100644 src/main/file/all/AllParser.hpp delete mode 100644 src/main/file/all/AllPitchBendEvent.cpp delete mode 100644 src/main/file/all/AllPitchBendEvent.hpp delete mode 100644 src/main/file/all/AllPolyPressureEvent.cpp delete mode 100644 src/main/file/all/AllPolyPressureEvent.hpp delete mode 100644 src/main/file/all/AllProgramChangeEvent.cpp delete mode 100644 src/main/file/all/AllProgramChangeEvent.hpp delete mode 100644 src/main/file/all/AllSequence.cpp delete mode 100644 src/main/file/all/AllSequence.hpp delete mode 100644 src/main/file/all/AllSequencer.cpp delete mode 100644 src/main/file/all/AllSequencer.hpp delete mode 100644 src/main/file/all/AllSong.cpp delete mode 100644 src/main/file/all/AllSong.hpp delete mode 100644 src/main/file/all/AllSysExEvent.cpp delete mode 100644 src/main/file/all/AllSysExEvent.hpp delete mode 100644 src/main/file/all/Bar.cpp delete mode 100644 src/main/file/all/Bar.hpp delete mode 100644 src/main/file/all/BarList.cpp delete mode 100644 src/main/file/all/BarList.hpp delete mode 100644 src/main/file/all/Count.cpp delete mode 100644 src/main/file/all/Count.hpp delete mode 100644 src/main/file/all/Header.cpp delete mode 100644 src/main/file/all/Header.hpp delete mode 100644 src/main/file/all/MidiInput.cpp delete mode 100644 src/main/file/all/MidiInput.hpp delete mode 100644 src/main/file/all/MidiSyncMisc.cpp delete mode 100644 src/main/file/all/MidiSyncMisc.hpp delete mode 100644 src/main/file/all/Misc.cpp delete mode 100644 src/main/file/all/Misc.hpp delete mode 100644 src/main/file/all/SequenceNames.cpp delete mode 100644 src/main/file/all/SequenceNames.hpp delete mode 100644 src/main/file/all/Tracks.cpp delete mode 100644 src/main/file/all/Tracks.hpp delete mode 100644 src/main/file/mid/MidiFile.cpp delete mode 100644 src/main/file/mid/MidiFile.hpp delete mode 100644 src/main/file/mid/MidiReader.cpp delete mode 100644 src/main/file/mid/MidiReader.hpp delete mode 100644 src/main/file/mid/MidiTrack.cpp delete mode 100644 src/main/file/mid/MidiTrack.hpp delete mode 100644 src/main/file/mid/MidiWriter.cpp delete mode 100644 src/main/file/mid/MidiWriter.hpp delete mode 100644 src/main/file/mid/event/ChannelAftertouch.cpp delete mode 100644 src/main/file/mid/event/ChannelAftertouch.hpp delete mode 100644 src/main/file/mid/event/ChannelEvent.cpp delete mode 100644 src/main/file/mid/event/ChannelEvent.hpp delete mode 100644 src/main/file/mid/event/Controller.cpp delete mode 100644 src/main/file/mid/event/Controller.hpp delete mode 100644 src/main/file/mid/event/MidiEvent.cpp delete mode 100644 src/main/file/mid/event/MidiEvent.hpp delete mode 100644 src/main/file/mid/event/NoteAftertouch.cpp delete mode 100644 src/main/file/mid/event/NoteAftertouch.hpp delete mode 100644 src/main/file/mid/event/NoteOff.cpp delete mode 100644 src/main/file/mid/event/NoteOff.hpp delete mode 100644 src/main/file/mid/event/NoteOn.cpp delete mode 100644 src/main/file/mid/event/NoteOn.hpp delete mode 100644 src/main/file/mid/event/PitchBend.cpp delete mode 100644 src/main/file/mid/event/PitchBend.hpp delete mode 100644 src/main/file/mid/event/ProgramChange.cpp delete mode 100644 src/main/file/mid/event/ProgramChange.hpp delete mode 100644 src/main/file/mid/event/SystemExclusive.cpp delete mode 100644 src/main/file/mid/event/SystemExclusive.hpp delete mode 100644 src/main/file/mid/event/meta/CopyrightNotice.cpp delete mode 100644 src/main/file/mid/event/meta/CopyrightNotice.hpp delete mode 100644 src/main/file/mid/event/meta/CuePoint.cpp delete mode 100644 src/main/file/mid/event/meta/CuePoint.hpp delete mode 100644 src/main/file/mid/event/meta/EndOfTrack.cpp delete mode 100644 src/main/file/mid/event/meta/EndOfTrack.hpp delete mode 100644 src/main/file/mid/event/meta/FrameRate.cpp delete mode 100644 src/main/file/mid/event/meta/FrameRate.hpp delete mode 100644 src/main/file/mid/event/meta/GenericMetaEvent.cpp delete mode 100644 src/main/file/mid/event/meta/GenericMetaEvent.hpp delete mode 100644 src/main/file/mid/event/meta/InstrumentName.cpp delete mode 100644 src/main/file/mid/event/meta/InstrumentName.hpp delete mode 100644 src/main/file/mid/event/meta/KeySignature.cpp delete mode 100644 src/main/file/mid/event/meta/KeySignature.hpp delete mode 100644 src/main/file/mid/event/meta/Marker.cpp delete mode 100644 src/main/file/mid/event/meta/Marker.hpp delete mode 100644 src/main/file/mid/event/meta/MetaEvent.cpp delete mode 100644 src/main/file/mid/event/meta/MetaEvent.hpp delete mode 100644 src/main/file/mid/event/meta/MetaEventData.cpp delete mode 100644 src/main/file/mid/event/meta/MetaEventData.hpp delete mode 100644 src/main/file/mid/event/meta/MidiChannelPrefix.cpp delete mode 100644 src/main/file/mid/event/meta/MidiChannelPrefix.hpp delete mode 100644 src/main/file/mid/event/meta/SequenceNumber.cpp delete mode 100644 src/main/file/mid/event/meta/SequenceNumber.hpp delete mode 100644 src/main/file/mid/event/meta/SequencerSpecificEvent.cpp delete mode 100644 src/main/file/mid/event/meta/SequencerSpecificEvent.hpp delete mode 100644 src/main/file/mid/event/meta/SmpteOffset.cpp delete mode 100644 src/main/file/mid/event/meta/SmpteOffset.hpp delete mode 100644 src/main/file/mid/event/meta/Tempo.cpp delete mode 100644 src/main/file/mid/event/meta/Tempo.hpp delete mode 100644 src/main/file/mid/event/meta/Text.cpp delete mode 100644 src/main/file/mid/event/meta/Text.hpp delete mode 100644 src/main/file/mid/event/meta/TextualMetaEvent.cpp delete mode 100644 src/main/file/mid/event/meta/TextualMetaEvent.hpp delete mode 100644 src/main/file/mid/event/meta/TimeSignatureEvent.cpp delete mode 100644 src/main/file/mid/event/meta/TimeSignatureEvent.hpp delete mode 100644 src/main/file/mid/event/meta/TrackName.cpp delete mode 100644 src/main/file/mid/event/meta/TrackName.hpp delete mode 100644 src/main/file/mid/util/MidiUtil.cpp delete mode 100644 src/main/file/mid/util/MidiUtil.hpp delete mode 100644 src/main/file/mid/util/VariableLengthInt.cpp delete mode 100644 src/main/file/mid/util/VariableLengthInt.hpp diff --git a/src/main/AutoSave.cpp b/src/main/AutoSave.cpp index 78907755..097c254a 100644 --- a/src/main/AutoSave.cpp +++ b/src/main/AutoSave.cpp @@ -12,6 +12,7 @@ #include "FileIoPolicy.hpp" #include "file/ByteUtil.hpp" #include "file/kaitai/ApsIo.hpp" +#include "file/kaitai/AllIo.hpp" #include "file/kaitai/SndIo.hpp" #include "lcdgui/screens/VmpcAutoSaveScreen.hpp" #include "lcdgui/screens/window/VmpcContinuePreviousSessionScreen.hpp" @@ -20,7 +21,6 @@ #include "lcdgui/Screens.hpp" #include "disk/AllLoader.hpp" -#include "file/all/AllParser.hpp" #include "sampler/Sampler.hpp" #include "sequencer/Bus.hpp" #include "sequencer/Sequencer.hpp" @@ -40,7 +40,6 @@ using namespace mpc; using namespace mpc::file_io; using namespace mpc::file; -using namespace mpc::file::all; using namespace mpc::lcdgui; using namespace mpc::lcdgui::screens; using namespace mpc::lcdgui::screens::window; @@ -58,6 +57,7 @@ constexpr size_t kApsPadLength2 = 7; constexpr size_t kApsMixerLength = 384; constexpr size_t kApsDrumConfigLength = 9; constexpr size_t kApsDrumPadLength = 3; +constexpr size_t kAllSequencesOffset = 14406; bool rangeFits(const size_t totalSize, const size_t offset, const size_t length) { @@ -100,7 +100,7 @@ bool isValidAutoSaveApsData(const std::vector &data) bool isValidAutoSaveAllData(const std::vector &data) { - if (data.size() < static_cast(AllParser::SEQUENCES_OFFSET)) + if (data.size() < kAllSequencesOffset) { return false; } @@ -308,8 +308,7 @@ void AutoSave::restoreAutoSavedState(Mpc &mpc, { throw std::invalid_argument("invalid ALL autosave data"); } - AllParser allParser(mpc, data); - disk::AllLoader::loadEverythingFromAllParser(mpc, allParser); + disk::AllLoader::loadEverythingFromBytes(mpc, data); } else if (f == "sounds.txt") { @@ -632,8 +631,7 @@ void AutoSave::storeAutoSavedState( } { - AllParser allParser(mpc); - if (!writeRequired("ALL.ALL", allParser.getBytes())) + if (!writeRequired("ALL.ALL", file::kaitai::AllIo::save(mpc))) { layeredScreen->closeCurrentScreen(); return; diff --git a/src/main/disk/AbstractDisk.cpp b/src/main/disk/AbstractDisk.cpp index 9c4f480a..aaa194c8 100644 --- a/src/main/disk/AbstractDisk.cpp +++ b/src/main/disk/AbstractDisk.cpp @@ -8,7 +8,6 @@ #include "disk/ProgramLoader.hpp" #include "file/wav/WavFile.hpp" -#include "file/all/AllParser.hpp" #include "file/kaitai/SndIo.hpp" #include "file/kaitai/PgmIo.hpp" #include "file/kaitai/ApsIo.hpp" @@ -39,8 +38,6 @@ using namespace mpc::input::midi; using namespace mpc::file; using namespace mpc::file::wav; -using namespace mpc::file::all; - using namespace mpc::lcdgui; using namespace mpc::lcdgui::screens; using namespace mpc::lcdgui::screens::window; diff --git a/src/main/disk/AllLoader.cpp b/src/main/disk/AllLoader.cpp index 08a95330..62be90aa 100644 --- a/src/main/disk/AllLoader.cpp +++ b/src/main/disk/AllLoader.cpp @@ -3,24 +3,18 @@ #include "Mpc.hpp" #include "StrUtil.hpp" +#include "file/ByteUtil.hpp" #include "controller/ClientEventController.hpp" #include "controller/ClientMidiEventController.hpp" #include "controller/MidiFootswitchFunctionMap.hpp" -#include "file/all/AllParser.hpp" #include "file/kaitai/AllIo.hpp" -#include "file/all/Count.hpp" -#include "file/all/Defaults.hpp" -#include "file/all/MidiInput.hpp" -#include "file/all/MidiSyncMisc.hpp" -#include "file/all/Misc.hpp" -#include "file/all/AllSequence.hpp" -#include "file/all/SequenceNames.hpp" -#include "file/all/AllSequencer.hpp" -#include "file/all/AllSong.hpp" +#include "file/kaitai/KaitaiIoUtil.hpp" +#include "file/kaitai/generated/mpc2000xl_all.h" #include "disk/MpcFile.hpp" #include "sequencer/Sequencer.hpp" +#include "sequencer/Sequence.hpp" #include "sequencer/Transport.hpp" #include "sequencer/Song.hpp" @@ -42,6 +36,218 @@ #include "lcdgui/screens/dialog/MetronomeSoundScreen.hpp" #include "sequencer/SequencerStateManager.hpp" +#include +#include + +namespace { + +std::string bytesUntilNull(const std::string& value) +{ + const auto pos = value.find('\0'); + return pos == std::string::npos ? value : value.substr(0, pos); +} + +mpc::sequencer::EventData +parsedEventToEventData(const mpc2000xl_all_t::event_t& parsedEvent) +{ + mpc::sequencer::EventData e; + e.tick = parsedEvent.tick(); + e.trackIndex = mpc::TrackIndex(parsedEvent.track()); + + if (parsedEvent.note_event() != nullptr) + { + e.type = mpc::sequencer::EventType::NoteOn; + e.noteNumber = mpc::NoteNumber(parsedEvent.note_event()->note()); + e.duration = mpc::Duration(parsedEvent.note_event()->duration()); + e.velocity = mpc::Velocity(parsedEvent.note_event()->velocity()); + e.noteVariationType = + mpc::NoteVariationType(parsedEvent.note_event()->variation_type()); + e.noteVariationValue = + mpc::NoteVariationValue(parsedEvent.note_event()->variation_value()); + return e; + } + + if (parsedEvent.pitch_bend() != nullptr) + { + e.type = mpc::sequencer::EventType::PitchBend; + auto candidate = static_cast( + parsedEvent.pitch_bend()->amount_bits_1() + + (parsedEvent.pitch_bend()->amount_bits_2() << 8) + ) - 16384; + if (candidate < -8192) + { + candidate += 8192; + } + e.amount = candidate; + return e; + } + + if (parsedEvent.control_change() != nullptr) + { + e.type = mpc::sequencer::EventType::ControlChange; + e.controllerNumber = parsedEvent.control_change()->controller(); + e.controllerValue = parsedEvent.control_change()->value(); + return e; + } + + if (parsedEvent.program_change() != nullptr) + { + e.type = mpc::sequencer::EventType::ProgramChange; + e.programChangeProgramIndex = + mpc::ProgramIndex(parsedEvent.program_change()->program()); + return e; + } + + if (parsedEvent.ch_pressure() != nullptr) + { + e.type = mpc::sequencer::EventType::ChannelPressure; + e.amount = parsedEvent.ch_pressure()->pressure(); + return e; + } + + if (parsedEvent.poly_pressure() != nullptr) + { + e.type = mpc::sequencer::EventType::PolyPressure; + e.noteNumber = mpc::NoteNumber(parsedEvent.poly_pressure()->note()); + e.amount = parsedEvent.poly_pressure()->pressure(); + return e; + } + + if (parsedEvent.exclusive() != nullptr) + { + if (parsedEvent.exclusive()->mixer() != nullptr) + { + e.type = mpc::sequencer::EventType::Mixer; + auto mixerParameter = + static_cast(parsedEvent.exclusive()->mixer()->param()) - 1; + if (mixerParameter == 4) + { + mixerParameter = 3; + } + e.mixerParameter = mixerParameter; + e.mixerPad = parsedEvent.exclusive()->mixer()->pad_index(); + e.mixerValue = parsedEvent.exclusive()->mixer()->value(); + } + else + { + e.type = mpc::sequencer::EventType::SystemExclusive; + const auto& bytes = parsedEvent.exclusive()->bytes(); + e.sysExByteA = bytes.size() > 0 + ? static_cast(bytes[0]) + : 0; + e.sysExByteB = bytes.size() > 1 + ? static_cast(bytes[1]) + : 0; + } + } + + return e; +} + +void applyParsedSequenceToInMemorySequence( + mpc2000xl_all_t& parsed, + const size_t sourceIndex, + const std::shared_ptr& inMemorySequence, + mpc::sequencer::SequencerStateManager* const manager) +{ + auto& parsedSequence = *parsed.sequences()->at(sourceIndex); + auto* body = parsedSequence.body(); + if (body == nullptr) + { + return; + } + + const auto tempoBytes = body->_unnamed2(); + const auto tempo = static_cast(mpc::file::ByteUtil::bytes2ushort({tempoBytes[3], tempoBytes[4]})) / 10.0; + + inMemorySequence->init(body->bar_count() - 1); + + for (size_t i = 0; i < body->bars()->size(); ++i) + { + inMemorySequence->setTimeSignature( + static_cast(i), + body->bars()->at(i)->numerator(), + body->bars()->at(i)->denominator() + ); + } + + const auto slotIndex = static_cast(body->index() - 1); + const auto* sequenceMeta = parsed.sequences_metas()->at(slotIndex).get(); + inMemorySequence->setName(mpc::StrUtil::trim(bytesUntilNull(sequenceMeta->name()))); + inMemorySequence->setInitialTempo(tempo); + + const auto sequenceIndex = inMemorySequence->getSequenceIndex(); + + mpc::sequencer::UpdateSequenceTracks updateSequenceTracks{sequenceIndex}; + manager->trackStatesSnapshots[sequenceIndex] = mpc::sequencer::SequenceTrackStatesSnapshot(); + updateSequenceTracks.trackStates = &manager->trackStatesSnapshots[sequenceIndex]; + + auto& trackStates = *updateSequenceTracks.trackStates; + const auto* parsedTracks = body->tracks(); + + for (int i = 0; i < mpc::Mpc2000XlSpecs::TRACK_COUNT; ++i) + { + const auto* status = parsedTracks->status()->at(i).get(); + trackStates[i].name = bytesUntilNull(parsedTracks->names()->at(i)); + trackStates[i].deviceIndex = parsedTracks->device()->at(i); + trackStates[i].busType = mpc::sequencer::busIndexToBusType(static_cast(parsedTracks->bus()->at(i))); + trackStates[i].programChange = parsedTracks->program_change()->at(i); + trackStates[i].on = status->off_or_on() == mpc2000xl_all_t::OFF_ON_TRUE; + trackStates[i].velocityRatio = parsedTracks->velocity_ratio()->at(i); + trackStates[i].transmitProgramChangesEnabled = + status->transmit_program_changes() == mpc2000xl_all_t::OFF_ON_TRUE; + trackStates[i].used = status->unused_or_used() == mpc2000xl_all_t::UNUSED_USED_USED; + } + + manager->enqueue(updateSequenceTracks); + + mpc::sequencer::UpdateSequenceEvents updateSequenceEvents{sequenceIndex}; + updateSequenceEvents.trackSnapshots = &manager->trackEventsSnapshots[sequenceIndex]; + updateSequenceEvents.trackSnapshots->clear(); + + for (const auto& parsedEvent : *body->events()) + { + if (parsedEvent->tick() >= 0xFFFFF) + { + continue; + } + + auto e = parsedEventToEventData(*parsedEvent); + if (e.type == mpc::sequencer::EventType::Unknown) + { + continue; + } + + (*updateSequenceEvents.trackSnapshots)[e.trackIndex].push_back(e); + } + + manager->enqueue(updateSequenceEvents); + + for (int i = 0; i < 32; i++) + { + inMemorySequence->setDeviceName(i, bytesUntilNull(body->device_names()->at(i + 1))); + } + + inMemorySequence->setFirstLoopBarIndex(mpc::BarIndex(body->loop_start_bar_index())); + if (body->loop_end_bar_index() > 998) + { + inMemorySequence->setLastLoopBarIndex(mpc::EndOfSequence); + } + else + { + inMemorySequence->setLastLoopBarIndex(mpc::BarIndex(body->loop_end_bar_index())); + } + + inMemorySequence->setLoopEnabled(body->loop_enabled()); + inMemorySequence->getStartTime().hours = body->start_time()->hours(); + inMemorySequence->getStartTime().minutes = body->start_time()->minutes(); + inMemorySequence->getStartTime().seconds = body->start_time()->seconds(); + inMemorySequence->getStartTime().frames = body->start_time()->frames(); + inMemorySequence->getStartTime().frameDecimals = body->start_time()->frame_decimals(); +} + +} + using namespace mpc::lcdgui; using namespace mpc::lcdgui::screens; using namespace mpc::lcdgui::screens::window; @@ -55,141 +261,164 @@ void AllLoader::loadEverythingFromFile(Mpc &mpc, MpcFile *f) file::kaitai::AllIo::loadEverything(mpc, f); } -void AllLoader::loadEverythingFromAllParser(Mpc &mpc, AllParser &allParser) +void AllLoader::loadEverythingFromBytes(Mpc &mpc, const std::vector &bytes) +{ + const auto canonicalBytes = file::kaitai::parseRewrite(bytes); + loadEverythingFromCanonicalBytes(mpc, canonicalBytes); +} + +void AllLoader::loadEverythingFromCanonicalBytes( + Mpc &mpc, + const std::vector &canonicalBytes) { + std::stringstream parseStream( + std::string(canonicalBytes.begin(), canonicalBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + auto mpcSequencer = mpc.getSequencer(); - auto allSequences = allParser.getAllSequences(); - auto allSeqNames = allParser.getSeqNames()->getNames(); - auto defaults = allParser.getDefaults(); - auto userScreen = mpc.screens->get(); + auto* defaults = parsed.defaults(); + auto* parsedSequencer = parsed.sequencer(); + auto* songGlobal = parsed.song_global(); - userScreen->setLastBar(defaults->getBarCount() - 1); - userScreen->setLoop(defaults->isLoopEnabled()); - userScreen->setBus(busIndexToBusType(defaults->getBusses()[0])); + auto userScreen = mpc.screens->get(); - mpcSequencer->setDefaultSequenceName(defaults->getDefaultSeqName()); - auto defTrackNames = defaults->getDefaultTrackNames(); + userScreen->setLastBar(static_cast(defaults->bar_count()) - 1); + userScreen->setLoop(defaults->unknown2()[4] == 0x01); + userScreen->setBus(mpc::sequencer::busIndexToBusType(static_cast(defaults->buses()->at(0)))); - for (int i = 0; i < Mpc2000XlSpecs::TRACK_COUNT; ++i) + mpcSequencer->setDefaultSequenceName(bytesUntilNull(defaults->sequence_name())); + for (int i = 0; i < mpc::Mpc2000XlSpecs::TRACK_COUNT; ++i) { - mpcSequencer->setDefaultTrackName(i, defTrackNames[i]); + mpcSequencer->setDefaultTrackName(i, bytesUntilNull(defaults->track_names()->at(i))); } - userScreen->setDeviceNumber(defaults->getDevices()[0]); - userScreen->setTimeSig(defaults->getTimeSigNum(), - defaults->getTimeSigDen()); - userScreen->setPgm(defaults->getPgms()[0]); - userScreen->setTempo(defaults->getTempo() * 0.1); - userScreen->setVelo(defaults->getTrVelos()[0]); - - int index = 0; + userScreen->setDeviceNumber(defaults->devices()->at(0)); + userScreen->setTimeSig(defaults->numerator(), defaults->denominator()); + userScreen->setPgm(defaults->programs()->at(0)); + userScreen->setTempo(defaults->tempo() * 0.1); + userScreen->setVelo(defaults->track_velocities()->at(0)); mpcSequencer->deleteAllSequences(); - for (auto &as : allSequences) + for (size_t sourceIndex = 0; sourceIndex < parsed.sequences()->size(); ++sourceIndex) { - if (as == nullptr) + if (parsed.sequences()->at(sourceIndex)->body() == nullptr) { - index++; continue; } - auto mpcSeq = mpcSequencer->getSequence(index++); - as->applyToInMemorySequence(mpcSeq, - mpcSequencer->getStateManager().get()); + const auto targetIndex = static_cast(parsed.sequences()->at(sourceIndex)->body()->index()) - 1; + auto mpcSeq = mpcSequencer->getSequence(targetIndex); + applyParsedSequenceToInMemorySequence( + parsed, + sourceIndex, + mpcSeq, + mpcSequencer->getStateManager().get() + ); } - auto allParserSequencer = allParser.getSequencer(); mpcSequencer->setSelectedSequenceIndex( - SequenceIndex(allParserSequencer->sequence), false); + SequenceIndex(parsedSequencer->active_sequence()), false); mpcSequencer->getTransport()->setPosition(0); - mpcSequencer->setSelectedTrackIndex(allParserSequencer->track); + mpcSequencer->setSelectedTrackIndex(parsedSequencer->active_track()); mpcSequencer->getTransport()->setMasterTempo( - allParserSequencer->masterTempo); + parsedSequencer->master_tempo() * 0.1); mpcSequencer->getTransport()->setTempoSourceIsSequence( - allParserSequencer->tempoSourceIsSequence); + parsedSequencer->tempo_source_is_sequence()); auto timingCorrectScreen = mpc.screens->get(); - timingCorrectScreen->setNoteValue(allParserSequencer->tc); + timingCorrectScreen->setNoteValue(static_cast(parsedSequencer->timing_correct())); auto timeDisplayScreen = mpc.screens->get(); - timeDisplayScreen->setDisplayStyle(allParserSequencer->timeDisplayStyle); + timeDisplayScreen->setDisplayStyle( + static_cast(parsedSequencer->time_display_style())); - auto count = allParser.getCount(); + auto* count = parsed.count(); + auto* midiOutput = parsed.midi_output(); + auto* midiInput = parsed.midi_input(); + auto* midiSync = parsed.midi_sync(); + auto* misc = parsed.misc(); + auto* stepEditOptions = parsed.step_edit_options(); auto countMetronomeScreen = mpc.screens->get(); auto metronomeSoundScreen = mpc.screens->get(); - countMetronomeScreen->setCountIn(count->getCountInMode()); - metronomeSoundScreen->accentPad = count->getAccentPad(); - metronomeSoundScreen->normalPad = count->getNormalPad(); - metronomeSoundScreen->setAccentVelo(count->getAccentVelo()); - metronomeSoundScreen->setNormalVelo(count->getNormalVelo()); - metronomeSoundScreen->setOutput(count->getClickOutput()); - metronomeSoundScreen->setVolume(count->getClickVolume()); - countMetronomeScreen->setRate(count->getRate()); - metronomeSoundScreen->setSound(count->getSound()); - countMetronomeScreen->setInPlay(count->isEnabledInPlay()); - countMetronomeScreen->setInRec(count->isEnabledInRec()); - countMetronomeScreen->setWaitForKey(count->isWaitForKeyEnabled()); - mpcSequencer->getTransport()->setCountEnabled(count->isEnabled()); - - auto midiInput = allParser.getMidiInput(); + countMetronomeScreen->setCountIn(static_cast(count->count_in_mode())); + metronomeSoundScreen->accentPad = count->accent_pad_index(); + metronomeSoundScreen->normalPad = count->normal_pad_index(); + metronomeSoundScreen->setAccentVelo(count->accent_velo()); + metronomeSoundScreen->setNormalVelo(count->normal_velo()); + metronomeSoundScreen->setOutput(static_cast(count->click_output())); + metronomeSoundScreen->setVolume(count->click_volume()); + countMetronomeScreen->setRate(static_cast(count->rate())); + metronomeSoundScreen->setSound(static_cast(count->sound_source())); + countMetronomeScreen->setInPlay(count->enabled_in_play()); + countMetronomeScreen->setInRec(count->enabled_in_rec()); + countMetronomeScreen->setWaitForKey(count->wait_for_key()); + mpcSequencer->getTransport()->setCountEnabled(count->enabled()); mpc.screens->get()->setSoftThru( - midiInput->getSoftThruMode()); + static_cast(midiOutput->soft_thru_mode())); auto midiInputScreen = mpc.screens->get(); - midiInputScreen->setReceiveCh(midiInput->getReceiveCh() - 1); - midiInputScreen->setType(midiInput->getFilterType()); - midiInputScreen->setMidiFilterEnabled(midiInput->isFilterEnabled()); + midiInputScreen->setReceiveCh( + static_cast(midiInput->receive_channel()) - 1); + midiInputScreen->setType(static_cast(midiInput->filter_type())); + midiInputScreen->setMidiFilterEnabled(midiInput->filter_enabled()); midiInputScreen->setSustainPedalToDuration( - midiInput->isSustainPedalToDurationEnabled()); - - auto trackDests = midiInput->getMultiRecTrackDests(); + midiInput->sustain_pedal_to_duration()); auto multiRecordingSetupScreen = mpc.screens->get(); - for (int i = 0; i < trackDests.size(); i++) + for (int i = 0; i < midiInput->multi_rec_destination_tracks()->size(); i++) { - multiRecordingSetupScreen->getMrsLines()[i]->setTrack(trackDests[i]); + multiRecordingSetupScreen->getMrsLines()[i]->setTrack( + midiInput->multi_rec_destination_tracks()->at(i) - 1); } midiInputScreen->setChPressurePassEnabled( - midiInput->isChPressurePassEnabled()); + midiInput->ch_pressure_pass_enabled()); midiInputScreen->setExclusivePassEnabled( - midiInput->isExclusivePassEnabled()); - mpcSequencer->setRecordingModeMulti(midiInput->isMultiRecEnabled()); - midiInputScreen->setNotePassEnabled(midiInput->isNotePassEnabled()); + midiInput->exclusive_pass_enabled()); + mpcSequencer->setRecordingModeMulti(midiInput->multi_rec_enabled()); + midiInputScreen->setNotePassEnabled(midiInput->note_pass_enabled()); midiInputScreen->setPgmChangePassEnabled( - midiInput->isPgmChangePassEnabled()); + midiInput->pgm_change_pass_enabled()); midiInputScreen->setPitchBendPassEnabled( - midiInput->isPitchBendPassEnabled()); + midiInput->pitch_bend_pass_enabled()); midiInputScreen->setPolyPressurePassEnabled( - midiInput->isPolyPressurePassEnabled()); - midiInputScreen->getCcPassEnabled() = midiInput->getCcPassEnabled(); - - auto midiSyncMisc = allParser.getMidiSync(); + midiInput->poly_pressure_pass_enabled()); + midiInputScreen->getCcPassEnabled() = *midiInput->cc_pass_enabled(); - auto misc = allParser.getMisc(); auto stepEditOptionsScreen = mpc.screens->get(); stepEditOptionsScreen->setAutoStepIncrementEnabled( - misc->isAutoStepIncEnabled()); + stepEditOptions->auto_step_increment()); stepEditOptionsScreen->setDurationOfRecordedNotesTcValue( - misc->isDurationOfRecNotesTc()); + stepEditOptions->duration_of_recorded_notes() == + mpc2000xl_all_t::DURATION_OF_RECORDED_NOTES_TC_VALUE); stepEditOptionsScreen->setTcValueRecordedNotes( - misc->getDurationTcPercentage()); - midiInputScreen->setProgChangeSeq(misc->isPgmChToSeqEnabled()); + stepEditOptions->tc_value_percentage()); + midiInputScreen->setProgChangeSeq(parsed.prog_change_to_seq()); auto locateScreen = mpc.screens->get(); - locateScreen->setLocations(misc->getLocations()); + std::vector locations; + locations.reserve(parsed.locations()->size()); + for (const auto& location : *parsed.locations()) + { + locations.emplace_back(location->bar(), location->beat(), location->clock()); + } + locateScreen->setLocations(locations); auto footswitchController = mpc.clientEventController->getClientMidiEventController() @@ -198,8 +427,10 @@ void AllLoader::loadEverythingFromAllParser(Mpc &mpc, AllParser &allParser) using MT = input::midi::MidiBindingBase::MessageType; int bindingCounter = 0; - for (auto [cc, functionIndex] : misc->getSwitches()) + for (const auto& midiSwitch : *misc->midi_switch()) { + const int cc = midiSwitch->controller() == 0xFF ? -1 : midiSwitch->controller(); + const auto functionIndex = static_cast(midiSwitch->function()); auto fn = static_cast(functionIndex); @@ -230,68 +461,74 @@ void AllLoader::loadEverythingFromAllParser(Mpc &mpc, AllParser &allParser) auto othersScreen = mpc.screens->get(); - othersScreen->setTapAveraging(misc->getTapAvg() + 2); + othersScreen->setTapAveraging(static_cast(misc->tap_averaging()) + 2); auto syncScreen = mpc.screens->get(); - syncScreen->receiveMMCEnabled = misc->isInReceiveMMCEnabled(); - syncScreen->sendMMCEnabled = midiSyncMisc->isSendMMCEnabled(); - syncScreen->in = midiSyncMisc->getInput(); - syncScreen->out = midiSyncMisc->getOutput(); + syncScreen->receiveMMCEnabled = misc->midi_sync_in_receive_mmc_enabled(); + syncScreen->sendMMCEnabled = midiSync->send_mmc_enabled(); + syncScreen->in = midiSync->input(); + syncScreen->out = static_cast(midiSync->output()); if (!mpc.isPluginModeEnabled()) { - syncScreen->setModeIn(midiSyncMisc->getInMode()); - syncScreen->setModeOut(midiSyncMisc->getOutMode()); + syncScreen->setModeIn(static_cast(midiSync->in_mode())); + syncScreen->setModeOut(static_cast(midiSync->out_mode())); } - syncScreen->shiftEarly = midiSyncMisc->getShiftEarly(); - syncScreen->frameRate = midiSyncMisc->getFrameRate(); + syncScreen->shiftEarly = midiSync->shift_early(); + syncScreen->frameRate = static_cast(midiSync->frame_rate()); mpcSequencer->setSecondSequenceEnabled( - allParserSequencer->secondSeqEnabled); + parsedSequencer->second_sequence_enabled()); auto secondSequenceScreen = mpc.screens->get(); - secondSequenceScreen->sq = allParserSequencer->secondSeqIndex; + secondSequenceScreen->sq = parsedSequencer->sequence_sequence_index(); auto songScreen = mpc.screens->get(); - songScreen->setDefaultSongName(midiSyncMisc->getDefSongName()); + songScreen->setDefaultSongName(songGlobal->default_song_name()); auto ignoreTempoChangeScreen = mpc.screens->get(); ignoreTempoChangeScreen->setIgnore( - midiSyncMisc->getSongModeIgnoreTempoChangeEvents()); + songGlobal->ignore_tempo_change_events_in_sequence()); - auto songs = allParser.getSongs(); + const auto* songs = parsed.songs(); for (int i = 0; i < 20; i++) { - auto allSong = songs[i]; + const auto& parsedSong = songs->at(i); auto mpcSong = mpcSequencer->getSong(i); mpcSong->setUsed(false); - if (allSong->getIsUsed()) + const auto trimmedName = mpc::StrUtil::trim(bytesUntilNull(parsedSong->name())); + const bool isUsed = parsedSong->is_used() || trimmedName != "(Unused)"; + if (isUsed) { mpcSong->setUsed(true); - mpcSong->setName(StrUtil::trim(allSong->name)); - - auto steps = allSong->getSteps(); + mpcSong->setName(trimmedName); - for (int stepIndex = 0; stepIndex < steps.size(); ++stepIndex) + int stepIndex = 0; + for (const auto& step : *parsedSong->steps()) { - const auto idx = SongStepIndex(stepIndex); + if (step->sequence_index() == 0xFF || step->repeat_count() == 0xFF) + { + continue; + } + + const auto idx = SongStepIndex(stepIndex++); mpcSong->insertStep(idx); mpcSong->setStepSequenceIndex( - idx, SequenceIndex(steps[stepIndex].first)); - mpcSong->setStepRepetitionCount(idx, steps[stepIndex].second); + idx, SequenceIndex(step->sequence_index())); + mpcSong->setStepRepetitionCount(idx, step->repeat_count()); } mpcSong->setFirstLoopStepIndex( - SongStepIndex(allSong->getLoopFirstStepIndex())); + SongStepIndex(parsedSong->loop_first_step())); mpcSong->setLastLoopStepIndex( - SongStepIndex(allSong->getLoopLastStepIndex())); + SongStepIndex(parsedSong->loop_last_step())); - mpcSong->setLoopEnabled(allSong->isLoopEnabled()); + mpcSong->setLoopEnabled(parsedSong->is_loop_enabled()); } } @@ -310,6 +547,54 @@ AllLoader::loadSequenceMetaInfosFromFile(Mpc &mpc, MpcFile *f) return *result; } +std::shared_ptr +AllLoader::loadOneSequenceFromCanonicalBytes( + Mpc &mpc, + const std::vector &canonicalBytes, + const SequenceIndex sourceIndexInAllFile, + const SequenceIndex destIndexInMpcMemory) +{ + std::stringstream parseStream( + std::string(canonicalBytes.begin(), canonicalBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + + size_t sourceOrdinal = parsed.sequences()->size(); + const auto sourceSlot = static_cast(sourceIndexInAllFile); + for (size_t i = 0; i < parsed.sequences()->size(); ++i) + { + auto* body = parsed.sequences()->at(i)->body(); + if (body == nullptr) + { + continue; + } + + if (static_cast(body->index()) - 1 == sourceSlot) + { + sourceOrdinal = i; + break; + } + } + + const auto sequence = mpc.getSequencer()->getSequence(destIndexInMpcMemory); + if (sourceOrdinal == parsed.sequences()->size()) + { + return sequence; + } + + applyParsedSequenceToInMemorySequence( + parsed, + sourceOrdinal, + sequence, + mpc.getSequencer()->getStateManager().get() + ); + + return sequence; +} + std::shared_ptr AllLoader::loadOneSequenceFromFile(Mpc &mpc, MpcFile *f, const SequenceIndex sourceIndexInAllFile, diff --git a/src/main/disk/AllLoader.hpp b/src/main/disk/AllLoader.hpp index 816cd36e..95197b0e 100644 --- a/src/main/disk/AllLoader.hpp +++ b/src/main/disk/AllLoader.hpp @@ -19,8 +19,6 @@ namespace mpc::disk namespace mpc::file::all { - class AllParser; - class AllSequence; } // namespace mpc::file::all namespace mpc::sequencer @@ -34,7 +32,12 @@ namespace mpc::disk { public: static void loadEverythingFromFile(Mpc &, MpcFile *); - static void loadEverythingFromAllParser(Mpc &, file::all::AllParser &); + static void loadEverythingFromBytes(Mpc &, const std::vector &); + static void loadEverythingFromCanonicalBytes(Mpc &, const std::vector &); + static std::shared_ptr + loadOneSequenceFromCanonicalBytes(Mpc &, const std::vector &, + SequenceIndex sourceIndexInAllFile, + SequenceIndex destIndexInMpcMemory); static std::vector loadSequenceMetaInfosFromFile(Mpc &, MpcFile *f); static std::shared_ptr diff --git a/src/main/file/all/AllChannelPressureEvent.cpp b/src/main/file/all/AllChannelPressureEvent.cpp deleted file mode 100644 index 3ecffe20..00000000 --- a/src/main/file/all/AllChannelPressureEvent.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "file/all/AllChannelPressureEvent.hpp" - -#include "file/all/AllEvent.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -EventData -AllChannelPressureEvent::bytesToMpcEvent(const std::vector &bytes) -{ - EventData e; - e.type = EventType::ChannelPressure; - e.tick = AllEvent::readTick(bytes); - e.trackIndex = TrackIndex(bytes[AllEvent::TRACK_OFFSET]); - e.amount = bytes[AMOUNT_OFFSET]; - return e; -} - -std::vector AllChannelPressureEvent::mpcEventToBytes(const EventData &e) -{ - std::vector bytes(8); - - bytes[AllEvent::EVENT_ID_OFFSET] = AllEvent::CH_PRESSURE_ID; - AllEvent::writeTick(bytes, e.tick); - bytes[AllEvent::TRACK_OFFSET] = e.trackIndex; - bytes[AMOUNT_OFFSET] = e.amount; - - return bytes; -} diff --git a/src/main/file/all/AllChannelPressureEvent.hpp b/src/main/file/all/AllChannelPressureEvent.hpp deleted file mode 100644 index c8cb7795..00000000 --- a/src/main/file/all/AllChannelPressureEvent.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include - -namespace mpc::file::all -{ - class AllChannelPressureEvent - { - static constexpr int AMOUNT_OFFSET = 5; - - public: - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllControlChangeEvent.cpp b/src/main/file/all/AllControlChangeEvent.cpp deleted file mode 100644 index b785f989..00000000 --- a/src/main/file/all/AllControlChangeEvent.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "file/all/AllControlChangeEvent.hpp" - -#include "file/all/AllEvent.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -EventData AllControlChangeEvent::bytesToMpcEvent(const std::vector &bytes) -{ - EventData e; - e.type = EventType::ControlChange; - e.tick = AllEvent::readTick(bytes); - e.trackIndex = TrackIndex(bytes[AllEvent::TRACK_OFFSET]); - e.controllerNumber = bytes[CONTROLLER_OFFSET]; - e.controllerValue = bytes[AMOUNT_OFFSET]; - - return e; -} - -std::vector AllControlChangeEvent::mpcEventToBytes(const EventData &e) -{ - std::vector bytes(8); - - bytes[AllEvent::EVENT_ID_OFFSET] = AllEvent::CONTROL_CHANGE_ID; - AllEvent::writeTick(bytes, e.tick); - bytes[AllEvent::TRACK_OFFSET] = e.trackIndex; - bytes[CONTROLLER_OFFSET] = e.controllerNumber; - bytes[AMOUNT_OFFSET] = e.controllerValue; - - return bytes; -} diff --git a/src/main/file/all/AllControlChangeEvent.hpp b/src/main/file/all/AllControlChangeEvent.hpp deleted file mode 100644 index a41e2bb8..00000000 --- a/src/main/file/all/AllControlChangeEvent.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include - -namespace mpc::file::all -{ - class AllControlChangeEvent - { - static constexpr int CONTROLLER_OFFSET = 5; - static constexpr int AMOUNT_OFFSET = 6; - - public: - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllEvent.cpp b/src/main/file/all/AllEvent.cpp deleted file mode 100644 index 011777cc..00000000 --- a/src/main/file/all/AllEvent.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "AllEvent.hpp" - -#include "AllChannelPressureEvent.hpp" -#include "AllControlChangeEvent.hpp" -#include "AllNoteEvent.hpp" -#include "AllPitchBendEvent.hpp" -#include "AllPolyPressureEvent.hpp" -#include "AllProgramChangeEvent.hpp" -#include "AllSysExEvent.hpp" - -#include - -#include "file/BitUtil.hpp" -#include "file/ByteUtil.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -std::vector AllEvent::TICK_BYTE3_BIT_RANGE{0, 3}; - -EventData AllEvent::bytesToMpcEvent(const std::vector &bytes) -{ - if (const auto eventID = bytes[EVENT_ID_OFFSET]; eventID < 0) - { - switch (bytes[EVENT_ID_OFFSET]) - { - case POLY_PRESSURE_ID: - return AllPolyPressureEvent::bytesToMpcEvent(bytes); - case CONTROL_CHANGE_ID: - return AllControlChangeEvent::bytesToMpcEvent(bytes); - case PGM_CHANGE_ID: - return AllProgramChangeEvent::bytesToMpcEvent(bytes); - case CH_PRESSURE_ID: - return AllChannelPressureEvent::bytesToMpcEvent(bytes); - case PITCH_BEND_ID: - return AllPitchBendEvent::bytesToMpcEvent(bytes); - case SYS_EX_ID: - return AllSysExEvent::bytesToMpcEvent(bytes); - default:; - } - } - - return AllNoteOnEvent::bytesToMpcEvent(bytes); -} - -std::vector AllEvent::mpcEventToBytes(const EventData &e) -{ - assert(e.type != sequencer::EventType::NoteOff); - - if (e.type == EventType::NoteOn) - { - return AllNoteOnEvent::mpcEventToBytes(e); - } - if (e.type == EventType::PolyPressure) - { - return AllPolyPressureEvent::mpcEventToBytes(e); - } - if (e.type == EventType::ControlChange) - { - return AllControlChangeEvent::mpcEventToBytes(e); - } - if (e.type == EventType::ProgramChange) - { - return AllProgramChangeEvent::mpcEventToBytes(e); - } - if (e.type == EventType::ChannelPressure) - { - return AllChannelPressureEvent::mpcEventToBytes(e); - } - if (e.type == EventType::PitchBend) - { - return AllPitchBendEvent::mpcEventToBytes(e); - } - if (e.type == EventType::SystemExclusive || e.type == EventType::Mixer) - { - return AllSysExEvent::mpcEventToBytes(e); - } - - return {}; -} - -int AllEvent::readTick(const std::vector &bytes) -{ - unsigned short s3 = BitUtil::removeUnusedBits(bytes[TICK_BYTE3_OFFSET], - TICK_BYTE3_BIT_RANGE); - - int result = ByteUtil::bytes2ushort(std::vector{bytes[TICK_BYTE1_OFFSET], - bytes[TICK_BYTE2_OFFSET]}) + - s3 * 65536; - - return result; -} - -void AllEvent::writeTick(std::vector &event, int tick) -{ - auto remainder = tick % 65536; - auto ba = ByteUtil::ushort2bytes(remainder); - event[TICK_BYTE1_OFFSET] = ba[0]; - event[TICK_BYTE2_OFFSET] = ba[1]; - auto s3 = static_cast(floor(tick / 65536.0)); - - event[TICK_BYTE3_OFFSET] = BitUtil::stitchBytes( - static_cast(event[TICK_BYTE3_OFFSET]), - AllNoteOnEvent::DURATION_BYTE1_BIT_RANGE, - static_cast(s3), TICK_BYTE3_BIT_RANGE); -} diff --git a/src/main/file/all/AllEvent.hpp b/src/main/file/all/AllEvent.hpp deleted file mode 100644 index b4d22289..00000000 --- a/src/main/file/all/AllEvent.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include -#include - -namespace mpc::sequencer -{ - class EventRef; -} - -namespace mpc::file::all -{ - class AllEvent - { - public: - static constexpr int TICK_BYTE1_OFFSET = 0; - static constexpr int TICK_BYTE2_OFFSET = 1; - static constexpr int TICK_BYTE3_OFFSET = 2; - static std::vector TICK_BYTE3_BIT_RANGE; - - static constexpr int TRACK_OFFSET = 3; - static constexpr int EVENT_ID_OFFSET = 4; - - static constexpr char POLY_PRESSURE_ID = 0xA0; - static constexpr char CONTROL_CHANGE_ID = 0xB0; - static constexpr char PGM_CHANGE_ID = 0xC0; - static constexpr char CH_PRESSURE_ID = 0xD0; - static constexpr char PITCH_BEND_ID = 0xE0; - static constexpr char SYS_EX_ID = 0xF0; - - static int readTick(const std::vector &); - static void writeTick(std::vector &, int); - - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllNoteEvent.cpp b/src/main/file/all/AllNoteEvent.cpp deleted file mode 100644 index 6dc687f3..00000000 --- a/src/main/file/all/AllNoteEvent.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "AllNoteEvent.hpp" - -#include "AllEvent.hpp" -#include "AllSequence.hpp" - -#include "file/BitUtil.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -EventData AllNoteOnEvent::bytesToMpcEvent(const std::vector &bytes) -{ - EventData e; - e.type = EventType::NoteOn; - e.noteNumber = NoteNumber(bytes[NOTE_NUMBER_OFFSET]); - e.tick = AllEvent::readTick(bytes); - const auto track = readTrackIndex(bytes); - e.trackIndex = TrackIndex(track); - e.duration = Duration(readDuration(bytes) - track * 4); - e.velocity = Velocity(readVelocity(bytes)); - e.noteVariationType = readVariationType(bytes); - e.noteVariationValue = NoteVariationValue(readVariationValue(bytes)); - - return e; -} - -std::vector AllNoteOnEvent::mpcEventToBytes(const EventData &e) -{ - std::vector bytes(AllSequence::EVENT_SEG_LENGTH); - - bytes[NOTE_NUMBER_OFFSET] = static_cast(e.noteNumber); - - writeTrackIndex(bytes, e.trackIndex); - writeVariationType(bytes, e.noteVariationType); - writeVariationValue(bytes, e.noteVariationValue); - AllEvent::writeTick(bytes, e.tick); - writeDuration(bytes, e.duration); - writeVelocity(bytes, e.velocity); - - return bytes; -} - -std::vector AllNoteOnEvent::DURATION_BYTE1_BIT_RANGE = std::vector{4, 7}; -std::vector AllNoteOnEvent::DURATION_BYTE2_BIT_RANGE = std::vector{6, 7}; -std::vector AllNoteOnEvent::TRACK_NUMBER_BIT_RANGE = std::vector{0, 5}; -std::vector AllNoteOnEvent::VELOCITY_BIT_RANGE = std::vector{0, 6}; -std::vector AllNoteOnEvent::VAR_VALUE_BIT_RANGE = std::vector{0, 6}; - -int AllNoteOnEvent::readDuration(const std::vector &bytes) -{ - auto b1 = bytes[DURATION_BYTE1_OFFSET]; - auto b2 = bytes[DURATION_BYTE2_OFFSET]; - const auto b3 = bytes[DURATION_BYTE3_OFFSET]; - - if (static_cast(b1) == 255 && - static_cast(b2) == 255 && - static_cast(b3) == 255) - { - return -1; - } - - b1 = BitUtil::removeUnusedBits(b1, DURATION_BYTE1_BIT_RANGE); - b2 = BitUtil::removeUnusedBits(b2, DURATION_BYTE2_BIT_RANGE); - - const auto i1 = b1 & 255; - const auto i2 = b2 & 255; - const auto i3 = b3 & 255; - - return (i1 << 6) + (i2 << 2) + i3; -} - -int AllNoteOnEvent::readTrackIndex(const std::vector &bytes) -{ - const auto raw = static_cast(bytes[TRACK_NUMBER_OFFSET]); - return raw & 0x3F; -} - -int AllNoteOnEvent::readVelocity(const std::vector &bytes) -{ - auto b = static_cast(bytes[VELOCITY_OFFSET]); - for (int i = 0; i < 8; i++) - { - if (i < VELOCITY_BIT_RANGE[0] || i > VELOCITY_BIT_RANGE[1]) - { - b = BitUtil::setBit(b, i, false); - } - } - return b; -} - -int AllNoteOnEvent::readVariationValue(const std::vector &bytes) -{ - auto b = static_cast(bytes[VAR_VALUE_OFFSET]); - for (int i = 0; i < 8; i++) - { - if (i < VAR_VALUE_BIT_RANGE[0] || i > VAR_VALUE_BIT_RANGE[1]) - { - b = BitUtil::setBit(b, i, false); - } - } - return b; -} - -mpc::NoteVariationType -AllNoteOnEvent::readVariationType(const std::vector &bytes) -{ - const auto byte1 = bytes[VAR_TYPE_BYTE1_OFFSET]; - const auto byte2 = bytes[VAR_TYPE_BYTE2_OFFSET]; - - const auto b1 = BitUtil::isBitOn(byte1, VAR_TYPE_BYTE1_BIT); - const auto b2 = BitUtil::isBitOn(byte2, VAR_TYPE_BYTE2_BIT); - - if (b1 && b2) - { - return NoteVariationTypeFilter; - } - if (b1 && !b2) - { - return NoteVariationTypeAttack; - } - if (!b1 && b2) - { - return NoteVariationTypeDecay; - } - return NoteVariationTypeTune; -} - -void AllNoteOnEvent::writeVelocity(std::vector &event, const int v) -{ - const auto value = static_cast(v); - event[VELOCITY_OFFSET] = BitUtil::stitchBytes( - event[VELOCITY_OFFSET], - std::vector{VAR_TYPE_BYTE1_BIT, VAR_TYPE_BYTE1_BIT}, value, - VELOCITY_BIT_RANGE); -} - -void AllNoteOnEvent::writeTrackIndex(std::vector &event, const int t) -{ - const auto value = static_cast(t); - event[TRACK_NUMBER_OFFSET] = BitUtil::stitchBytes( - event[TRACK_NUMBER_OFFSET], DURATION_BYTE2_BIT_RANGE, value, - TRACK_NUMBER_BIT_RANGE); -} - -void AllNoteOnEvent::writeVariationValue(std::vector &event, const int v) -{ - const auto value = static_cast(v); - event[VAR_VALUE_OFFSET] = BitUtil::stitchBytes( - event[VAR_VALUE_OFFSET], - std::vector{VAR_TYPE_BYTE2_BIT, VAR_TYPE_BYTE2_BIT}, value, - VAR_VALUE_BIT_RANGE); -} - -void AllNoteOnEvent::writeDuration(std::vector &event, const int duration) -{ - const auto s1 = static_cast(duration >> 6); - const auto s2 = static_cast(duration >> 2); - const auto s3 = static_cast(duration & 255); - - event[DURATION_BYTE1_OFFSET] = BitUtil::stitchBytes( - event[DURATION_BYTE1_OFFSET], AllEvent::TICK_BYTE3_BIT_RANGE, - static_cast(s1), DURATION_BYTE1_BIT_RANGE); - - event[DURATION_BYTE2_OFFSET] = BitUtil::stitchBytes( - event[DURATION_BYTE2_OFFSET], TRACK_NUMBER_BIT_RANGE, - static_cast(s2), DURATION_BYTE2_BIT_RANGE); - - event[DURATION_BYTE3_OFFSET] = static_cast(s3); -} - -void AllNoteOnEvent::writeVariationType(std::vector &event, - const int type) -{ - auto byte1 = event[VAR_TYPE_BYTE1_OFFSET]; - auto byte2 = event[VAR_TYPE_BYTE2_OFFSET]; - byte1 = static_cast( - BitUtil::setBit(byte1, VAR_TYPE_BYTE1_BIT, type == 2 || type == 3)); - byte2 = static_cast( - BitUtil::setBit(byte2, VAR_TYPE_BYTE2_BIT, type == 1 || type == 3)); - event[VAR_TYPE_BYTE1_OFFSET] = byte1; - event[VAR_TYPE_BYTE2_OFFSET] = byte2; -} diff --git a/src/main/file/all/AllNoteEvent.hpp b/src/main/file/all/AllNoteEvent.hpp deleted file mode 100644 index f6521a8d..00000000 --- a/src/main/file/all/AllNoteEvent.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include - -namespace mpc::file::all -{ - class AllEvent; - class AllNoteOnEvent - { - static constexpr int DURATION_BYTE1_OFFSET = 2; - static std::vector DURATION_BYTE1_BIT_RANGE; - static constexpr int DURATION_BYTE2_OFFSET = 3; - static std::vector DURATION_BYTE2_BIT_RANGE; - static constexpr int TRACK_NUMBER_OFFSET = 3; - static std::vector TRACK_NUMBER_BIT_RANGE; - static constexpr int NOTE_NUMBER_OFFSET = 4; - static constexpr int DURATION_BYTE3_OFFSET = 5; - static constexpr int VELOCITY_OFFSET = 6; - static std::vector VELOCITY_BIT_RANGE; - static constexpr int VAR_TYPE_BYTE1_OFFSET = 6; - static constexpr int VAR_TYPE_BYTE1_BIT = 7; - static constexpr int VAR_TYPE_BYTE2_OFFSET = 7; - static constexpr int VAR_TYPE_BYTE2_BIT = 7; - static constexpr int VAR_VALUE_OFFSET = 7; - static std::vector VAR_VALUE_BIT_RANGE; - - static int readDuration(const std::vector &); - static int readTrackIndex(const std::vector &); - static int readVelocity(const std::vector &); - static int readVariationValue(const std::vector &); - static NoteVariationType readVariationType(const std::vector &); - - static void writeVelocity(std::vector &event, int); - static void writeTrackIndex(std::vector &event, int); - static void writeVariationValue(std::vector &event, int); - static void writeDuration(std::vector &event, int); - static void writeVariationType(std::vector &event, int); - - friend class AllEvent; - - public: - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllParser.cpp b/src/main/file/all/AllParser.cpp deleted file mode 100644 index a9d9c425..00000000 --- a/src/main/file/all/AllParser.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include "AllParser.hpp" - -#include - -#include "Mpc.hpp" - -#include "file/all/Count.hpp" -#include "file/all/Defaults.hpp" -#include "file/all/Header.hpp" -#include "file/all/MidiInput.hpp" -#include "file/all/MidiSyncMisc.hpp" -#include "file/all/Misc.hpp" -#include "file/all/AllSequence.hpp" -#include "file/all/SequenceNames.hpp" -#include "file/all/AllSequencer.hpp" -#include "file/all/AllSong.hpp" - -#include "sequencer/Sequencer.hpp" - -#include "file/ByteUtil.hpp" - -#include "Util.hpp" - -using namespace mpc::file::all; - -AllParser::AllParser(Mpc &_mpc, const std::vector &loadBytes) : mpc(_mpc) -{ - if (loadBytes.size() >= HEADER_OFFSET + HEADER_LENGTH) - { - header = new Header(Util::vecCopyOfRange( - loadBytes, HEADER_OFFSET, HEADER_OFFSET + HEADER_LENGTH)); - } - - if (header == nullptr || !header->verifyFileID()) - { - throw std::invalid_argument("Invalid ALL file header ID"); - } - - defaults = new Defaults( - mpc, Util::vecCopyOfRange(loadBytes, DEFAULTS_OFFSET, - DEFAULTS_OFFSET + DEFAULTS_LENGTH)); - sequencer = new AllSequencer(Util::vecCopyOfRange( - loadBytes, SEQUENCER_OFFSET, SEQUENCER_OFFSET + AllSequencer::LENGTH)); - count = new Count(Util::vecCopyOfRange(loadBytes, COUNT_OFFSET, - COUNT_OFFSET + COUNT_LENGTH)); - midiInput = new MidiInput(Util::vecCopyOfRange( - loadBytes, MIDI_INPUT_OFFSET, MIDI_INPUT_OFFSET + MidiInput::LENGTH)); - midiSyncMisc = new MidiSyncMisc(Util::vecCopyOfRange( - loadBytes, MIDI_SYNC_OFFSET, MIDI_SYNC_OFFSET + MidiSyncMisc::LENGTH)); - misc = new Misc(Util::vecCopyOfRange(loadBytes, MISC_OFFSET, - MISC_OFFSET + Misc::LENGTH)); - seqNames = new SequenceNames( - Util::vecCopyOfRange(loadBytes, SEQUENCE_NAMES_OFFSET, - SEQUENCE_NAMES_OFFSET + SequenceNames::LENGTH)); - - for (int i = 0; i < 20; i++) - { - int offset = SONGS_OFFSET + i * Song::LENGTH; - songs[i] = new Song( - Util::vecCopyOfRange(loadBytes, offset, offset + Song::LENGTH)); - } - - sequences = readSequences( - Util::vecCopyOfRange(loadBytes, SEQUENCES_OFFSET, loadBytes.size())); -} - -AllParser::AllParser(Mpc &_mpc) : mpc(_mpc) -{ - std::vector> chunks; - chunks.push_back(Header().getBytes()); - - Defaults saveDefaults(mpc); - - chunks.push_back(saveDefaults.getBytes()); - chunks.push_back(UNKNOWN_CHUNK); - sequencer = new AllSequencer(mpc); - chunks.push_back(sequencer->getBytes()); - - chunks.push_back({0, 12, 0, 0, 0, 0, 0, 0, 0, 0}); - - count = new Count(mpc); - chunks.push_back(count->getBytes()); - midiInput = new MidiInput(mpc); - chunks.push_back(midiInput->getBytes()); - - midiSyncMisc = new MidiSyncMisc(mpc); - chunks.push_back(midiSyncMisc->getBytes()); - - chunks.push_back({0, 0, 0, 0, 0}); - - misc = new Misc(mpc); - chunks.push_back(misc->getBytes()); - seqNames = new SequenceNames(mpc); - chunks.push_back(seqNames->getBytes()); - - auto mpcSequencer = mpc.getSequencer(); - - for (int i = 0; i < 20; i++) - { - songs[i] = new Song(mpcSequencer->getSong(i).get()); - chunks.push_back(songs[i]->getBytes()); - } - - auto usedSeqs = mpcSequencer->getUsedSequences(); - - for (int i = 0; i < usedSeqs.size(); i++) - { - auto seq = usedSeqs[i]; - AllSequence allSeq(seq.get(), - mpcSequencer->getUsedSequenceIndexes()[i] + 1); - chunks.push_back(allSeq.getBytes()); - } - - saveBytes = ByteUtil::stitchByteArrays(chunks); -} - -AllParser::~AllParser() -{ - if (header != nullptr) - { - delete header; - } - if (defaults != nullptr) - { - delete defaults; - } - if (sequencer != nullptr) - { - delete sequencer; - } - if (count != nullptr) - { - delete count; - } - if (midiInput != nullptr) - { - delete midiInput; - } - if (midiSyncMisc != nullptr) - { - delete midiSyncMisc; - } - if (misc != nullptr) - { - delete misc; - } - if (seqNames != nullptr) - { - delete seqNames; - } - - for (auto &s : sequences) - { - if (s != nullptr) - { - delete s; - } - } - - for (auto &s : songs) - { - if (s != nullptr) - { - delete s; - } - } -} - -std::vector AllParser::getAllSequences() -{ - return sequences; -} - -Defaults *AllParser::getDefaults() const -{ - return defaults; -} - -AllSequencer *AllParser::getSequencer() const -{ - return sequencer; -} - -Count *AllParser::getCount() const -{ - return count; -} - -MidiInput *AllParser::getMidiInput() const -{ - return midiInput; -} - -MidiSyncMisc *AllParser::getMidiSync() const -{ - return midiSyncMisc; -} - -Misc *AllParser::getMisc() const -{ - return misc; -} - -SequenceNames *AllParser::getSeqNames() const -{ - return seqNames; -} - -std::vector AllParser::getSongs() -{ - return songs; -} - -std::vector -AllParser::readSequences(const std::vector &trimmedSeqsArray) const -{ - const int totalSeqChunkLength = trimmedSeqsArray.size(); - - if (totalSeqChunkLength == 0) - { - return {}; - } - - std::vector seqs; - int read = 0; - - auto usednesses = seqNames->getUsednesses(); - - size_t pos = 0; - - for (const auto &u : usednesses) - { - if (!u) - { - seqs.push_back(nullptr); - continue; - } - - std::vector view; - if (pos < trimmedSeqsArray.size()) - { - view = Util::vecCopyOfRange(trimmedSeqsArray, pos, - trimmedSeqsArray.size()); - } - else - { - seqs.push_back(nullptr); - continue; - } - - int eventSegments = - AllSequence::getNumberOfEventSegmentsForThisSeq(view); - - int currentSeqLen = EMPTY_SEQ_LENGTH + eventSegments * EVENT_LENGTH; - - if ((size_t)currentSeqLen > view.size()) - { - currentSeqLen = (int)view.size(); - } - - auto currentSeqArray = - Util::vecCopyOfRange(trimmedSeqsArray, pos, pos + currentSeqLen); - - auto as = new AllSequence(currentSeqArray); - seqs.push_back(as); - - read += currentSeqLen; - pos += currentSeqLen; - - if ((eventSegments & 1) != 0) - { - if (pos >= EVENT_LENGTH) - { - pos -= EVENT_LENGTH; - read -= EVENT_LENGTH; - } - else - { - pos = 0; - read = 0; - } - } - } - - return seqs; -} - -std::vector &AllParser::getBytes() -{ - return saveBytes; -} - -std::vector AllParser::UNKNOWN_CHUNK = std::vector(64); diff --git a/src/main/file/all/AllParser.hpp b/src/main/file/all/AllParser.hpp deleted file mode 100644 index 46b991fb..00000000 --- a/src/main/file/all/AllParser.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include "mpc_types.hpp" - -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::disk -{ - class MpcFile; -} - -namespace mpc::file::all -{ - class Header; - class Defaults; - class AllSequencer; - class Count; - class MidiInput; - class MidiSyncMisc; - class Misc; - class SequenceNames; - class AllSequence; - class Song; -} // namespace mpc::file::all - -namespace mpc::file::all -{ - class AllParser - { - - public: - static const int NAME_LENGTH{16}; - static const int DEV_NAME_LENGTH{8}; - static const int EMPTY_SEQ_LENGTH{10256}; - static const int EVENT_LENGTH{8}; - static const int HEADER_OFFSET{0}; - static const int HEADER_LENGTH{16}; - static const int DEFAULTS_OFFSET{16}; - static std::vector UNKNOWN_CHUNK; - - static const int DEFAULTS_LENGTH{1728}; - - static const int SEQUENCER_OFFSET{1808}; - static const int COUNT_OFFSET{1829}; - static const int COUNT_LENGTH{13}; - static const int MIDI_INPUT_OFFSET{1842}; - static const int MIDI_SYNC_OFFSET{1904}; - static const int MISC_OFFSET{1933}; - static const int SEQUENCE_NAMES_OFFSET{2064}; - static const int SONGS_OFFSET{3846}; - static const int SEQUENCES_OFFSET{14406}; - Header *header = nullptr; - Defaults *defaults = nullptr; - AllSequencer *sequencer = nullptr; - Count *count = nullptr; - MidiInput *midiInput = nullptr; - MidiSyncMisc *midiSyncMisc = nullptr; - Misc *misc = nullptr; - SequenceNames *seqNames = nullptr; - std::vector sequences; - std::vector songs = std::vector(20); - std::vector saveBytes; - - std::vector getAllSequences(); - Defaults *getDefaults() const; - AllSequencer *getSequencer() const; - Count *getCount() const; - MidiInput *getMidiInput() const; - MidiSyncMisc *getMidiSync() const; - Misc *getMisc() const; - SequenceNames *getSeqNames() const; - std::vector getSongs(); - - private: - Mpc &mpc; - - std::vector - readSequences(const std::vector &trimmedSeqsArray) const; - - public: - std::vector &getBytes(); - - AllParser(Mpc &, const std::vector &loadBytes); - AllParser(Mpc &); - ~AllParser(); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllPitchBendEvent.cpp b/src/main/file/all/AllPitchBendEvent.cpp deleted file mode 100644 index cca78767..00000000 --- a/src/main/file/all/AllPitchBendEvent.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "file/all/AllPitchBendEvent.hpp" - -#include "file/all/AllEvent.hpp" - -#include "file/ByteUtil.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -EventData AllPitchBendEvent::bytesToMpcEvent(const std::vector &bytes) -{ - EventData e; - e.type = EventType::PitchBend; - e.tick = AllEvent::readTick(bytes); - e.trackIndex = TrackIndex(bytes[AllEvent::TRACK_OFFSET]); - - auto candidate = ByteUtil::bytes2ushort(std::vector{ - bytes[AMOUNT_OFFSET], bytes[AMOUNT_OFFSET + 1]}) - - 16384; - - if (candidate < -8192) - { - candidate += 8192; - } - - e.amount = candidate; - - return e; -} - -std::vector AllPitchBendEvent::mpcEventToBytes(const EventData &e) -{ - std::vector bytes(8); - bytes[AllEvent::EVENT_ID_OFFSET] = AllEvent::PITCH_BEND_ID; - AllEvent::writeTick(bytes, e.tick); - bytes[AllEvent::TRACK_OFFSET] = e.trackIndex; - - auto candidate = e.amount + 16384; - - if (e.amount < 0) - { - candidate = e.amount + 8192; - } - - const auto amountBytes = ByteUtil::ushort2bytes(candidate); - - bytes[AMOUNT_OFFSET] = amountBytes[0]; - bytes[AMOUNT_OFFSET + 1] = amountBytes[1]; - - return bytes; -} diff --git a/src/main/file/all/AllPitchBendEvent.hpp b/src/main/file/all/AllPitchBendEvent.hpp deleted file mode 100644 index d3ee098f..00000000 --- a/src/main/file/all/AllPitchBendEvent.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include - -namespace mpc::file::all -{ - class AllPitchBendEvent - { - static constexpr int AMOUNT_OFFSET = 5; - - public: - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllPolyPressureEvent.cpp b/src/main/file/all/AllPolyPressureEvent.cpp deleted file mode 100644 index e3170a1c..00000000 --- a/src/main/file/all/AllPolyPressureEvent.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "AllPolyPressureEvent.hpp" - -#include "file/all/AllEvent.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -EventData AllPolyPressureEvent::bytesToMpcEvent(const std::vector &bytes) -{ - EventData e; - e.type = EventType::PolyPressure; - e.tick = AllEvent::readTick(bytes); - e.trackIndex = TrackIndex(bytes[AllEvent::TRACK_OFFSET]); - e.noteNumber = NoteNumber(bytes[NOTE_OFFSET]); - e.amount = bytes[AMOUNT_OFFSET]; - - return e; -} - -std::vector AllPolyPressureEvent::mpcEventToBytes(const EventData &e) -{ - std::vector bytes(8); - - bytes[AllEvent::EVENT_ID_OFFSET] = AllEvent::POLY_PRESSURE_ID; - AllEvent::writeTick(bytes, e.tick); - bytes[AllEvent::TRACK_OFFSET] = e.trackIndex; - bytes[NOTE_OFFSET] = e.noteNumber; - bytes[AMOUNT_OFFSET] = e.amount; - - return bytes; -} diff --git a/src/main/file/all/AllPolyPressureEvent.hpp b/src/main/file/all/AllPolyPressureEvent.hpp deleted file mode 100644 index 879e8d7e..00000000 --- a/src/main/file/all/AllPolyPressureEvent.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include - -namespace mpc::file::all -{ - class AllPolyPressureEvent - { - static constexpr int NOTE_OFFSET = 5; - static constexpr int AMOUNT_OFFSET = 6; - - public: - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllProgramChangeEvent.cpp b/src/main/file/all/AllProgramChangeEvent.cpp deleted file mode 100644 index 51dc79ff..00000000 --- a/src/main/file/all/AllProgramChangeEvent.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "AllProgramChangeEvent.hpp" - -#include "file/all/AllEvent.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -EventData AllProgramChangeEvent::bytesToMpcEvent(const std::vector &bytes) -{ - EventData e; - e.type = EventType::ProgramChange; - e.tick = AllEvent::readTick(bytes); - e.trackIndex = TrackIndex(bytes[AllEvent::TRACK_OFFSET]); - e.programChangeProgramIndex = ProgramIndex(bytes[PROGRAM_OFFSET]); - - return e; -} - -std::vector AllProgramChangeEvent::mpcEventToBytes(const EventData &e) -{ - std::vector bytes(8); - - bytes[AllEvent::EVENT_ID_OFFSET] = AllEvent::PGM_CHANGE_ID; - AllEvent::writeTick(bytes, e.tick); - bytes[AllEvent::TRACK_OFFSET] = e.trackIndex; - bytes[PROGRAM_OFFSET] = e.programChangeProgramIndex; - - return bytes; -} diff --git a/src/main/file/all/AllProgramChangeEvent.hpp b/src/main/file/all/AllProgramChangeEvent.hpp deleted file mode 100644 index a54b177a..00000000 --- a/src/main/file/all/AllProgramChangeEvent.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include - -namespace mpc::file::all -{ - class AllProgramChangeEvent - { - static constexpr int PROGRAM_OFFSET = 5; - - public: - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllSequence.cpp b/src/main/file/all/AllSequence.cpp deleted file mode 100644 index f09a6495..00000000 --- a/src/main/file/all/AllSequence.cpp +++ /dev/null @@ -1,556 +0,0 @@ -#include "AllSequence.hpp" - -#include "Bar.hpp" -#include "AllEvent.hpp" -#include "AllParser.hpp" -#include "BarList.hpp" -#include "SequenceNames.hpp" -#include "Tracks.hpp" - -#include "sequencer/EventRef.hpp" -#include "sequencer/MixerEvent.hpp" -#include "sequencer/Sequence.hpp" -#include "sequencer/Track.hpp" -#include "sequencer/SystemExclusiveEvent.hpp" - -#include "file/ByteUtil.hpp" -#include "StrUtil.hpp" -#include "Util.hpp" -#include "sequencer/SequencerStateManager.hpp" - -#ifdef __linux__ -#include -#endif - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -AllSequence::AllSequence(const std::vector &bytes) -{ - barList = new BarList(Util::vecCopyOfRange( - bytes, BAR_LIST_OFFSET, BAR_LIST_OFFSET + BAR_LIST_LENGTH)); - const auto nameBytes = Util::vecCopyOfRange( - bytes, NAME_OFFSET, NAME_OFFSET + AllParser::NAME_LENGTH); - name = ""; - - for (const char c : nameBytes) - { - if (c == 0x00) - { - break; - } - - name.push_back(c); - } - - name = StrUtil::trim(name); - - tempo = getTempoDouble( - std::vector{bytes[TEMPO_BYTE1_OFFSET], bytes[TEMPO_BYTE2_OFFSET]}); - const auto barCountBytes = std::vector{bytes[BAR_COUNT_BYTE1_OFFSET], - bytes[BAR_COUNT_BYTE2_OFFSET]}; - barCount = ByteUtil::bytes2ushort(barCountBytes); - loopFirst = ByteUtil::bytes2ushort( - std::vector{bytes[LOOP_FIRST_OFFSET], bytes[LOOP_FIRST_OFFSET + 1]}); - loopLast = ByteUtil::bytes2ushort( - std::vector{bytes[LOOP_LAST_OFFSET], bytes[LOOP_LAST_OFFSET + 1]}); - - if (loopLast > 998) - { - loopLast = barCount; - loopLastEnd = true; - } - - loop = bytes[LOOP_ENABLED_OFFSET] > 0; - - startTime.hours = bytes[START_TIME_OFFSET]; - startTime.minutes = bytes[START_TIME_OFFSET + 1]; - startTime.seconds = bytes[START_TIME_OFFSET + 2]; - startTime.frames = bytes[START_TIME_OFFSET + 3]; - startTime.frameDecimals = bytes[START_TIME_OFFSET + 4]; - - for (int i = 0; i < 33; i++) - { - const auto offset = - DEVICE_NAMES_OFFSET + i * AllParser::DEV_NAME_LENGTH; - std::string stringBuffer; - auto stringBytes = Util::vecCopyOfRange( - bytes, offset, offset + AllParser::DEV_NAME_LENGTH); - - for (const char c : stringBytes) - { - if (c == 0x00) - { - break; - } - - stringBuffer.push_back(c); - } - - devNames[i] = stringBuffer; - } - - tracks = - new Tracks(Util::vecCopyOfRange(bytes, TRACKS_OFFSET, TRACKS_LENGTH)); - allEvents = readEvents(bytes); -} - -AllSequence::~AllSequence() -{ - if (tracks != nullptr) - { - delete tracks; - } - - if (barList != nullptr) - { - delete barList; - } -} - -void AllSequence::applyToInMemorySequence( - const std::shared_ptr &inMemorySequence, - SequencerStateManager *const manager) const -{ - inMemorySequence->init(barCount - 1); - - for (int i = 0; i < barCount; i++) - { - const auto num = barList->getBars()[i]->getNumerator(); - const auto den = barList->getBars()[i]->getDenominator(); - inMemorySequence->setTimeSignature(i, num, den); - } - - inMemorySequence->setName(name); - inMemorySequence->setInitialTempo(tempo); - - const auto sequenceIndex = inMemorySequence->getSequenceIndex(); - - UpdateSequenceTracks updateSequenceTracks{sequenceIndex}; - manager->trackStatesSnapshots[sequenceIndex] = - SequenceTrackStatesSnapshot(); - updateSequenceTracks.trackStates = - &manager->trackStatesSnapshots[sequenceIndex]; - - auto &trackStates = *updateSequenceTracks.trackStates; - - for (int i = 0; i < Mpc2000XlSpecs::TRACK_COUNT; ++i) - { - const auto inMemoryTrack = inMemorySequence->getTrack(i); - - trackStates[i].name = tracks->getName(i); - trackStates[i].deviceIndex = tracks->getDeviceIndex(i); - trackStates[i].busType = busIndexToBusType(tracks->getBus(i)); - trackStates[i].programChange = tracks->getPgm(i); - trackStates[i].on = tracks->isOn(i); - trackStates[i].velocityRatio = tracks->getVelo(i); - trackStates[i].transmitProgramChangesEnabled = - tracks->isTransmitProgramChangesEnabled(i); - trackStates[i].used = tracks->isUsed(i); - } - - manager->enqueue(updateSequenceTracks); - - UpdateSequenceEvents updateSequenceEvents{ - inMemorySequence->getSequenceIndex()}; - - updateSequenceEvents.trackSnapshots = - &manager->trackEventsSnapshots[sequenceIndex]; - - updateSequenceEvents.trackSnapshots->clear(); - - for (int j = 0; j < getEventAmount(); j++) - { - auto e = allEvents[j]; - - if (e.type == EventType::Unknown) - { - continue; - } - - (*updateSequenceEvents.trackSnapshots)[e.trackIndex].push_back(e); - } - - manager->enqueue(updateSequenceEvents); - - for (int i = 0; i < 32; i++) - { - inMemorySequence->setDeviceName(i, devNames[i + 1]); - } - - inMemorySequence->setFirstLoopBarIndex(BarIndex(loopFirst)); - inMemorySequence->setLastLoopBarIndex(BarIndex(loopLast)); - inMemorySequence->setLastLoopBarIndex(BarIndex(loopLast)); - - if (loopLastEnd) - { - inMemorySequence->setLastLoopBarIndex(EndOfSequence); - } - - inMemorySequence->setLoopEnabled(loop); - inMemorySequence->getStartTime().hours = startTime.hours; - inMemorySequence->getStartTime().minutes = startTime.minutes; - inMemorySequence->getStartTime().seconds = startTime.seconds; - inMemorySequence->getStartTime().frames = startTime.frames; - inMemorySequence->getStartTime().frameDecimals = startTime.frameDecimals; -} - -AllSequence::AllSequence(Sequence *seq, int number) -{ - auto segmentCountLastEventIndex = SequenceNames::getSegmentCount(seq); - auto segmentCount = getSegmentCount(seq); - auto terminatorCount = (segmentCount & 1) == 0 ? 2 : 1; - saveBytes = std::vector(10240 + segmentCount * EVENT_SEG_LENGTH + - terminatorCount * EVENT_SEG_LENGTH); - - for (int i = 0; i < AllParser::NAME_LENGTH; i++) - { - saveBytes[i] = - StrUtil::padRight(seq->getName(), " ", AllParser::NAME_LENGTH)[i]; - } - - if ((segmentCountLastEventIndex & 1) != 0) - { - segmentCountLastEventIndex--; - } - - segmentCountLastEventIndex /= 2; - auto lastEventIndexBytes = ByteUtil::ushort2bytes( - 1 + (segmentCountLastEventIndex < 0 ? 0 : segmentCountLastEventIndex)); - - saveBytes[LAST_EVENT_INDEX_OFFSET] = lastEventIndexBytes[0]; - saveBytes[LAST_EVENT_INDEX_OFFSET + 1] = lastEventIndexBytes[1]; - - for (int i = PADDING1_OFFSET; i < PADDING1_OFFSET + PADDING1.size(); i++) - { - saveBytes[i] = PADDING1[i - PADDING1_OFFSET]; - } - - setTempoDouble(seq->getInitialTempo()); - - for (int i = PADDING2_OFFSET; i < PADDING2_OFFSET + PADDING2.size(); i++) - { - saveBytes[i] = PADDING2[i - PADDING2_OFFSET]; - } - - setBarCount(seq->getLastBarIndex() + 1); - setLastTick(seq); - saveBytes[SEQUENCE_INDEX_OFFSET] = number; - setUnknown32BitInt(seq); - auto loopStartBytes = ByteUtil::ushort2bytes(seq->getFirstLoopBarIndex()); - auto loopEndBytes = ByteUtil::ushort2bytes(seq->getLastLoopBarIndex()); - - if (seq->getLastLoopBarIndex() == EndOfSequence) - { - loopEndBytes = - std::vector{static_cast(255), static_cast(255)}; - } - - saveBytes[LOOP_FIRST_OFFSET] = loopStartBytes[0]; - saveBytes[LOOP_FIRST_OFFSET + 1] = loopStartBytes[1]; - saveBytes[LOOP_LAST_OFFSET] = loopEndBytes[0]; - saveBytes[LOOP_LAST_OFFSET + 1] = loopEndBytes[1]; - saveBytes[LOOP_ENABLED_OFFSET] = seq->isLoopEnabled() ? 1 : 0; - - saveBytes[START_TIME_OFFSET] = seq->getStartTime().hours; - saveBytes[START_TIME_OFFSET + 1] = seq->getStartTime().minutes; - saveBytes[START_TIME_OFFSET + 2] = seq->getStartTime().seconds; - saveBytes[START_TIME_OFFSET + 3] = seq->getStartTime().frames; - saveBytes[START_TIME_OFFSET + 4] = seq->getStartTime().frameDecimals; - - for (int i = 0; i < PADDING4.size(); i++) - { - saveBytes[PADDING4_OFFSET + i] = PADDING4[i]; - } - - for (int i = 0; i < 33; i++) - { - const auto deviceNameOffset = - DEVICE_NAMES_OFFSET + i * AllParser::DEV_NAME_LENGTH; - - const auto deviceName = - i == 0 ? " " - : StrUtil::padRight(seq->getDeviceName(i - 1), " ", - AllParser::DEV_NAME_LENGTH); - - for (int charOffset = 0; charOffset < AllParser::DEV_NAME_LENGTH; - charOffset++) - { - saveBytes[deviceNameOffset + charOffset] = deviceName[charOffset]; - } - } - Tracks allFileSeqTracks(seq); - - for (int i = 0; i < TRACKS_LENGTH; i++) - { - saveBytes[i + TRACKS_OFFSET] = allFileSeqTracks.getBytes()[i]; - } - - BarList allFileBarList(seq); - - for (int i = BAR_LIST_OFFSET; i < BAR_LIST_OFFSET + BAR_LIST_LENGTH; i++) - { - saveBytes[i] = allFileBarList.getBytes()[i - BAR_LIST_OFFSET]; - } - - auto eventArraysChunk = createEventSegmentsChunk(seq); - - for (int i = EVENTS_OFFSET; i < EVENTS_OFFSET + eventArraysChunk.size(); - i++) - { - saveBytes[i] = eventArraysChunk[i - EVENTS_OFFSET]; - } - - for (int i = static_cast(saveBytes.size()) - 8; i < saveBytes.size(); - i++) - { - saveBytes[i] = static_cast(255); - } -} - -const int AllSequence::MAX_SYSEX_SIZE; -const int AllSequence::EVENT_ID_OFFSET; -const char AllSequence::POLY_PRESSURE_ID; -const char AllSequence::CONTROL_CHANGE_ID; -const char AllSequence::PGM_CHANGE_ID; -const char AllSequence::CH_PRESSURE_ID; -const char AllSequence::PITCH_BEND_ID; -const char AllSequence::SYS_EX_ID; -const char AllSequence::SYS_EX_TERMINATOR_ID; -std::vector AllSequence::TERMINATOR = std::vector{ - static_cast(0xFF), static_cast(0xFF), static_cast(0xFF), - static_cast(0xFF), static_cast(0xFF), static_cast(0xFF), - static_cast(0xFF), static_cast(0xFF)}; -const int AllSequence::MAX_EVENT_SEG_COUNT; -const int AllSequence::EVENT_SEG_LENGTH; -const int AllSequence::NAME_OFFSET; -const int AllSequence::LAST_EVENT_INDEX_OFFSET; -const int AllSequence::SEQUENCE_INDEX_OFFSET; -const int AllSequence::PADDING1_OFFSET; -std::vector AllSequence::PADDING1 = std::vector{1, 1, 0}; -const int AllSequence::TEMPO_BYTE1_OFFSET; -const int AllSequence::TEMPO_BYTE2_OFFSET; -const int AllSequence::PADDING2_OFFSET; -std::vector AllSequence::PADDING2 = std::vector{4, 4}; -const int AllSequence::BAR_COUNT_BYTE1_OFFSET; -const int AllSequence::BAR_COUNT_BYTE2_OFFSET; -const int AllSequence::LAST_TICK_BYTE1_OFFSET; -const int AllSequence::LAST_TICK_BYTE2_OFFSET; -const int AllSequence::UNKNOWN32_BIT_INT_OFFSET; -const int AllSequence::LOOP_FIRST_OFFSET; -const int AllSequence::LOOP_LAST_OFFSET; -const int AllSequence::LOOP_ENABLED_OFFSET; -const int AllSequence::PADDING4_OFFSET; -std::vector AllSequence::PADDING4 = - std::vector{40, 0, static_cast(128), 0, 0}; -const int AllSequence::LAST_TICK_BYTE3_OFFSET; -const int AllSequence::LAST_TICK_BYTE4_OFFSET; -const int AllSequence::DEVICE_NAMES_OFFSET; -const int AllSequence::TRACKS_OFFSET; -const int AllSequence::TRACKS_LENGTH; -const int AllSequence::BAR_LIST_OFFSET; -const int AllSequence::BAR_LIST_LENGTH; -const int AllSequence::EVENTS_OFFSET; - -std::vector -AllSequence::readEvents(const std::vector &seqBytes) -{ - std::vector events; - - for (auto &eventBytes : readEventSegments(seqBytes)) - { - events.emplace_back(AllEvent::bytesToMpcEvent(eventBytes)); - } - - return events; -} - -std::vector> -AllSequence::readEventSegments(const std::vector &seqBytes) -{ - std::vector> eventArrays; - int candidateOffset = EVENTS_OFFSET; - - for (int i = 0; i < MAX_EVENT_SEG_COUNT; i++) - { - auto ea = Util::vecCopyOfRange(seqBytes, candidateOffset, - candidateOffset + EVENT_SEG_LENGTH); - - if (Util::vecEquals(ea, TERMINATOR)) - { - break; - } - - if (ea[EVENT_ID_OFFSET] == SYS_EX_ID) - { - int sysexSegs; - for (sysexSegs = 0; sysexSegs < MAX_SYSEX_SIZE; sysexSegs++) - { - auto potentialTerminator = Util::vecCopyOfRange( - seqBytes, candidateOffset + sysexSegs * EVENT_SEG_LENGTH, - candidateOffset + sysexSegs * EVENT_SEG_LENGTH + - EVENT_SEG_LENGTH); - - if (potentialTerminator[EVENT_ID_OFFSET] == - SYS_EX_TERMINATOR_ID) - { - break; - } - } - - sysexSegs++; - ea = Util::vecCopyOfRange(seqBytes, candidateOffset, - candidateOffset + - sysexSegs * EVENT_SEG_LENGTH); - } - eventArrays.push_back(ea); - candidateOffset += static_cast(ea.size()); - } - return eventArrays; -} - -double AllSequence::getTempoDouble(const std::vector &bytePair) -{ - const auto s = ByteUtil::bytes2ushort(bytePair); - return static_cast(s) / 10.0; -} - -int AllSequence::getNumberOfEventSegmentsForThisSeq( - const std::vector &seqBytes) -{ - auto accum = 0; - - for (auto &ba : readEventSegments(seqBytes)) - { - accum += static_cast(ba.size()) / 8; - } - - return accum; -} - -int AllSequence::getEventAmount() const -{ - return static_cast(allEvents.size()); -} - -int AllSequence::getSegmentCount(Sequence *seq) -{ - int segmentCount = 0; - - for (const auto &track : seq->getTracks()) - { - if (track->getIndex() > 63) - { - break; - } - - for (auto &e : track->getEvents()) - { - if (const auto sysExEvent = - std::dynamic_pointer_cast(e); - sysExEvent) - { - constexpr int dataSegments = 1; - segmentCount += dataSegments + 2; - } - else if (const auto mixerEvent = - std::dynamic_pointer_cast(e); - mixerEvent) - { - segmentCount += 4; - } - else - { - segmentCount++; - } - } - } - return segmentCount; -} - -void AllSequence::setUnknown32BitInt(const Sequence *seq) -{ - const auto unknownNumberBytes1 = ByteUtil::uint2bytes(10000000); - const auto unknownNumberBytes2 = - ByteUtil::uint2bytes(seq->getLastTick() * 5208.333333333333); - - for (int i = 0; i < 2; i++) - { - for (int j = 0; j < 4; j++) - { - saveBytes[UNKNOWN32_BIT_INT_OFFSET + j + i * 4] = - unknownNumberBytes1[j]; - } - } - - for (int i = 2; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - saveBytes[UNKNOWN32_BIT_INT_OFFSET + j + i * 4] = - unknownNumberBytes2[j]; - } - } -} - -void AllSequence::setBarCount(const int i) -{ - const auto ba = ByteUtil::ushort2bytes(i); - saveBytes[BAR_COUNT_BYTE1_OFFSET] = ba[0]; - saveBytes[BAR_COUNT_BYTE2_OFFSET] = ba[1]; -} - -std::vector AllSequence::createEventSegmentsChunk(Sequence *seq) -{ - std::vector> ea; - - for (int i = 0; i < seq->getLastTick(); i++) - { - for (const auto &track : seq->getTracks()) - { - if (track->getIndex() > 63) - { - break; - } - - for (const auto &event : track->getEvents()) - { - if (event->getTick() == i) - { - event->setTrack(track->getIndex()); - ea.push_back(AllEvent::mpcEventToBytes(*event->handle)); - } - } - } - } - - ea.push_back(TERMINATOR); - return ByteUtil::stitchByteArrays(ea); -} - -void AllSequence::setTempoDouble(const double tempoForSaveBytes) -{ - const auto ba = ByteUtil::ushort2bytes( - static_cast(tempoForSaveBytes * 10.0)); - saveBytes[TEMPO_BYTE1_OFFSET] = ba[0]; - saveBytes[TEMPO_BYTE2_OFFSET] = ba[1]; -} - -void AllSequence::setLastTick(const Sequence *seq) -{ - const auto lastTick = seq->getLastTick(); - const auto remainder = lastTick % 65536; - const auto b = ByteUtil::ushort2bytes(remainder); - const auto large = static_cast(floor(lastTick / 65536.0)); - saveBytes[LAST_TICK_BYTE1_OFFSET] = b[0]; - saveBytes[LAST_TICK_BYTE2_OFFSET] = b[1]; - saveBytes[LAST_TICK_BYTE2_OFFSET + 1] = large; - saveBytes[LAST_TICK_BYTE3_OFFSET] = b[0]; - saveBytes[LAST_TICK_BYTE4_OFFSET] = b[1]; - saveBytes[LAST_TICK_BYTE4_OFFSET + 1] = large; -} - -std::vector &AllSequence::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/AllSequence.hpp b/src/main/file/all/AllSequence.hpp deleted file mode 100644 index 92bd03da..00000000 --- a/src/main/file/all/AllSequence.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "sequencer/Sequence.hpp" -#include "sequencer/EventData.hpp" - -namespace mpc::sequencer -{ - class Sequence; - class EventRef; -} // namespace mpc::sequencer - -namespace mpc::file::all -{ - class BarList; - class Tracks; -} // namespace mpc::file::all - -namespace mpc::file::all -{ - class AllSequence final - { - public: - static constexpr int MAX_SYSEX_SIZE{256}; - static constexpr int EVENT_ID_OFFSET{4}; - static constexpr char POLY_PRESSURE_ID = 0xA0; - static constexpr char CONTROL_CHANGE_ID = 0xB0; - static constexpr char PGM_CHANGE_ID = 0xC0; - static constexpr char CH_PRESSURE_ID = 0xD0; - static constexpr char PITCH_BEND_ID = 0xE0; - static constexpr char SYS_EX_ID = 0xF0; - static constexpr char SYS_EX_TERMINATOR_ID = 0xF8; - - private: - static std::vector TERMINATOR; - - public: - static constexpr int MAX_EVENT_SEG_COUNT{50000}; - static constexpr int EVENT_SEG_LENGTH{8}; - static constexpr int NAME_OFFSET{0}; - static constexpr int LAST_EVENT_INDEX_OFFSET{16}; - static constexpr int SEQUENCE_INDEX_OFFSET{18}; - static constexpr int PADDING1_OFFSET{19}; - - private: - static std::vector PADDING1; - - public: - static constexpr int TEMPO_BYTE1_OFFSET{22}; - static constexpr int TEMPO_BYTE2_OFFSET{23}; - static constexpr int PADDING2_OFFSET{24}; - - private: - static std::vector PADDING2; - - public: - static constexpr int BAR_COUNT_BYTE1_OFFSET{26}; - static constexpr int BAR_COUNT_BYTE2_OFFSET{27}; - static constexpr int LAST_TICK_BYTE1_OFFSET{28}; - static constexpr int LAST_TICK_BYTE2_OFFSET{29}; - static constexpr int UNKNOWN32_BIT_INT_OFFSET{32}; - static constexpr int LOOP_FIRST_OFFSET{48}; - static constexpr int LOOP_LAST_OFFSET{50}; - static constexpr int LOOP_ENABLED_OFFSET{52}; - static constexpr int START_TIME_OFFSET{53}; - static constexpr int PADDING4_OFFSET{59}; - - private: - static std::vector PADDING4; - - public: - static constexpr int LAST_TICK_BYTE3_OFFSET{64}; - static constexpr int LAST_TICK_BYTE4_OFFSET{65}; - static constexpr int DEVICE_NAMES_OFFSET{120}; - static constexpr int TRACKS_OFFSET{384}; - static constexpr int TRACKS_LENGTH{1764}; - static constexpr int BAR_LIST_OFFSET{5379}; - static constexpr int BAR_LIST_LENGTH{3996}; - static constexpr int EVENTS_OFFSET{10240}; - std::string name; - int barCount; - int loopFirst; - int loopLast; - bool loopLastEnd; - bool loop; - sequencer::Sequence::StartTime startTime{0, 0, 0, 0, 0}; - - double tempo; - std::vector devNames = std::vector(33); - Tracks *tracks = nullptr; - BarList *barList = nullptr; - std::vector allEvents; - - private: - std::vector saveBytes; - - static std::vector - readEvents(const std::vector &seqBytes); - static std::vector> - readEventSegments(const std::vector &seqBytes); - static double getTempoDouble(const std::vector &bytePair); - - public: - static int - getNumberOfEventSegmentsForThisSeq(const std::vector &seqBytes); - int getEventAmount() const; - - private: - static int getSegmentCount(sequencer::Sequence *seq); - void setUnknown32BitInt(const sequencer::Sequence *seq); - void setBarCount(int i); - static std::vector - createEventSegmentsChunk(sequencer::Sequence *seq); - void setTempoDouble(double tempoForSaveBytes); - void setLastTick(const sequencer::Sequence *seq); - - public: - std::vector &getBytes(); - - void applyToInMemorySequence( - const std::shared_ptr &inMemorySequence, - sequencer::SequencerStateManager *) const; - - explicit AllSequence(const std::vector &bytes); - AllSequence(sequencer::Sequence *seq, int number); - ~AllSequence(); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllSequencer.cpp b/src/main/file/all/AllSequencer.cpp deleted file mode 100644 index 10540504..00000000 --- a/src/main/file/all/AllSequencer.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "AllSequencer.hpp" -#include "sequencer/Transport.hpp" -#include "file/ByteUtil.hpp" -#include "lcdgui/screens/window/TimeDisplayScreen.hpp" - -#include "Mpc.hpp" - -#include "lcdgui/screens/SecondSeqScreen.hpp" -#include "lcdgui/screens/window/TimingCorrectScreen.hpp" -#include "sequencer/Sequencer.hpp" - -using namespace mpc::file::all; -using namespace mpc::lcdgui; -using namespace mpc::lcdgui::screens; -using namespace mpc::lcdgui::screens::window; - -AllSequencer::AllSequencer(const std::vector &loadBytes) -{ - sequence = loadBytes[SEQ_OFFSET]; - track = loadBytes[TR_OFFSET]; - const auto masterTempoBytes = {loadBytes[MASTER_TEMPO_OFFSET], - loadBytes[MASTER_TEMPO_OFFSET + 1]}; - masterTempo = ByteUtil::bytes2ushort(masterTempoBytes) / 10.0; - tempoSourceIsSequence = loadBytes[TEMPO_SOURCE_IS_SEQUENCE_OFFSET] == 0x01; - tc = loadBytes[TC_OFFSET]; - timeDisplayStyle = loadBytes[TIME_DISPLAY_STYLE_OFFSET]; - secondSeqEnabled = loadBytes[SECOND_SEQ_ENABLED_OFFSET] > 0; - secondSeqIndex = loadBytes[SECOND_SEQ_INDEX_OFFSET]; -} - -AllSequencer::AllSequencer(Mpc &mpc) -{ - saveBytes = std::vector(LENGTH); - - for (int i = 0; i < LENGTH; i++) - { - saveBytes[i] = TEMPLATE[i]; - } - - const auto mpcSequencer = mpc.getSequencer(); - - saveBytes[SEQ_OFFSET] = mpcSequencer->getSelectedSequenceIndex(); - saveBytes[TR_OFFSET] = mpcSequencer->getSelectedTrackIndex(); - - const bool tempoSourceIsSequence = - mpcSequencer->getTransport()->isTempoSourceSequence(); - - mpcSequencer->getTransport()->setTempoSourceIsSequence(false); - - const auto masterTempoBytes = ByteUtil::ushort2bytes( - mpcSequencer->getTransport()->getMasterTempo() * 10.0); - - mpcSequencer->getTransport()->setTempoSourceIsSequence( - tempoSourceIsSequence); - - saveBytes[MASTER_TEMPO_OFFSET] = masterTempoBytes[0]; - saveBytes[MASTER_TEMPO_OFFSET + 1] = masterTempoBytes[1]; - - saveBytes[TEMPO_SOURCE_IS_SEQUENCE_OFFSET] = - mpcSequencer->getTransport()->isTempoSourceSequence() ? 0x01 : 0x00; - - const auto timingCorrectScreen = - mpc.screens->get(); - const auto noteValue = timingCorrectScreen->getNoteValue(); - - saveBytes[TC_OFFSET] = noteValue; - saveBytes[TIME_DISPLAY_STYLE_OFFSET] = - mpc.screens->get()->getDisplayStyle(); - saveBytes[SECOND_SEQ_ENABLED_OFFSET] = - mpcSequencer->isSecondSequenceEnabled() ? 1 : 0; - - auto secondSequenceScreen = mpc.screens->get(); - saveBytes[SECOND_SEQ_INDEX_OFFSET] = secondSequenceScreen->sq; -} - -std::vector AllSequencer::TEMPLATE = {0, 0, 0, 0, (char)176, 4, - 1, 3, 0, 0, 0}; - -std::vector &AllSequencer::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/AllSequencer.hpp b/src/main/file/all/AllSequencer.hpp deleted file mode 100644 index dbf2c5f1..00000000 --- a/src/main/file/all/AllSequencer.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::file::all -{ - class AllSequencer - { - public: - static const int LENGTH = 11; - - private: - static std::vector TEMPLATE; - - public: - static const int SEQ_OFFSET = 0; - static const int TR_OFFSET = 2; - static const int MASTER_TEMPO_OFFSET = 4; - static const int TEMPO_SOURCE_IS_SEQUENCE_OFFSET = 6; - static const int TC_OFFSET = 7; - static const int TIME_DISPLAY_STYLE_OFFSET = 8; - static const int SECOND_SEQ_ENABLED_OFFSET = 9; - static const int SECOND_SEQ_INDEX_OFFSET = 10; - - int sequence; - int track; - double masterTempo; - bool tempoSourceIsSequence; - int tc; - int timeDisplayStyle; - bool secondSeqEnabled; - int secondSeqIndex; - std::vector saveBytes; - - std::vector &getBytes(); - - AllSequencer(const std::vector &loadBytes); - AllSequencer(Mpc &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllSong.cpp b/src/main/file/all/AllSong.cpp deleted file mode 100644 index 6be25464..00000000 --- a/src/main/file/all/AllSong.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "file/all/AllSong.hpp" - -#include "sequencer/Song.hpp" - -#include "Util.hpp" - -using namespace mpc::file::all; - -Song::Song(const std::vector &loadBytes) -{ - const auto nameBytes = Util::vecCopyOfRange( - loadBytes, NAME_OFFSET, NAME_OFFSET + AllParser::NAME_LENGTH); - - for (const char &c : nameBytes) - { - if (c == 0x00) - { - break; - } - name.push_back(c); - } - - const size_t end = name.find_last_not_of(' '); - name = end == std::string::npos ? "" : name.substr(0, end + 1); - - const auto stepsBytes = Util::vecCopyOfRange( - loadBytes, FIRST_STEP_OFFSET, FIRST_STEP_OFFSET + STEPS_LENGTH); - - for (int i = 0; i < STEPS_LENGTH; i += STEP_LENGTH) - { - uint8_t seqIndex = stepsBytes[i]; - uint8_t repeatCount = stepsBytes[i + 1]; - - if (seqIndex == 0xFF || repeatCount == 0xFF) - { - continue; - } - - steps.emplace_back(seqIndex, repeatCount); - } - - loopFirstStepIndex = loadBytes[LOOP_FIRST_STEP_INDEX_OFFSET]; - loopLastStepIndex = loadBytes[LOOP_LAST_STEP_INDEX_OFFSET]; - loopEnabled = loadBytes[LOOP_ENABLED_OFFSET] == 1; - - // This is what it's supposed to do, but there may be users out there - // with badly persisted files due to older versions of VMPC2000XL: - - // isUsed = loadBytes[IS_USED_OFFSET]; - - // So for now we rely on the following heuristic, as this will - // correctly parse real MPC2000XL ALL songs, as well as the ones written - // with older versions of VMPC2000XL, unless someone decides to name - // their song "(Unused)": - isUsed = name != "(Unused)"; -} - -Song::Song(sequencer::Song *mpcSong) -{ - const auto songName = mpcSong->getName(); - - for (int i = 0; i < AllParser::NAME_LENGTH; i++) - { - if (i >= songName.length()) - { - saveBytes[NAME_OFFSET + i] = ' '; - continue; - } - - saveBytes[NAME_OFFSET + i] = songName[i]; - } - - for (int i = 0; i < STEP_COUNT; i++) - { - if (i >= mpcSong->getStepCount()) - { - saveBytes[FIRST_STEP_OFFSET + i * 2] = static_cast(0xFF); - saveBytes[FIRST_STEP_OFFSET + i * 2 + 1] = static_cast(0xFF); - continue; - } - - const auto step = mpcSong->getStep(SongStepIndex(i)); - - saveBytes[FIRST_STEP_OFFSET + i * 2] = - static_cast(step.sequenceIndex); - - saveBytes[FIRST_STEP_OFFSET + i * 2 + 1] = - static_cast(step.repetitionCount); - } - - saveBytes[STEPS_TERMINATOR_OFFSET] = static_cast(0xFF); - saveBytes[STEPS_TERMINATOR_OFFSET + 1] = static_cast(0xFF); - - saveBytes[IS_USED_OFFSET] = mpcSong->isUsed() ? 1 : 0; - saveBytes[LOOP_FIRST_STEP_INDEX_OFFSET] = mpcSong->getFirstLoopStepIndex(); - saveBytes[LOOP_LAST_STEP_INDEX_OFFSET] = mpcSong->getLastLoopStepIndex(); - saveBytes[LOOP_ENABLED_OFFSET] = mpcSong->isLoopEnabled() ? 1 : 0; - - for (int i = LOOP_ENABLED_OFFSET + 1; i < LENGTH; i++) - { - saveBytes[i] = 0; - } -} - -std::string Song::getName() -{ - return name; -} - -std::vector> Song::getSteps() -{ - return steps; -} - -bool Song::getIsUsed() const -{ - return isUsed; -} - -int Song::getLoopFirstStepIndex() const -{ - return loopFirstStepIndex; -} - -int Song::getLoopLastStepIndex() const -{ - return loopLastStepIndex; -} - -bool Song::isLoopEnabled() const -{ - return loopEnabled; -} - -std::vector &Song::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/AllSong.hpp b/src/main/file/all/AllSong.hpp deleted file mode 100644 index 0ebb45c7..00000000 --- a/src/main/file/all/AllSong.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace mpc::sequencer -{ - class Song; -} - -namespace mpc::file::all -{ - class Song - { - - public: - static const int LENGTH = 528; - - private: - static const int NAME_OFFSET = 0; - - /** - * Each step in a song is 2 bytes. The first byte is the sequence index - * (0 - 99), the second byte is the number of repeats. - */ - static const int FIRST_STEP_OFFSET = - NAME_OFFSET + AllParser::NAME_LENGTH; - static const int STEPS_LENGTH = 500; - static const int STEP_LENGTH = 2; - static const int STEP_COUNT = 250; - static const int STEPS_TERMINATOR_OFFSET = - FIRST_STEP_OFFSET + STEP_COUNT * STEP_LENGTH; - static const int IS_USED_OFFSET = STEPS_TERMINATOR_OFFSET + 2; - static const int LOOP_FIRST_STEP_INDEX_OFFSET = IS_USED_OFFSET + 1; - static const int LOOP_LAST_STEP_INDEX_OFFSET = - LOOP_FIRST_STEP_INDEX_OFFSET + 1; - static const int LOOP_ENABLED_OFFSET = LOOP_LAST_STEP_INDEX_OFFSET + 1; - - int loopFirstStepIndex = 0; - int loopLastStepIndex = 0; - bool loopEnabled = false; - - public: - std::string name; - std::vector> steps; - bool isUsed = false; - - std::vector saveBytes = std::vector(LENGTH); - - std::string getName(); - - std::vector &getBytes(); - - Song(const std::vector &loadBytes); - Song(sequencer::Song *mpcSong); - std::vector> getSteps(); - bool getIsUsed() const; - int getLoopFirstStepIndex() const; - int getLoopLastStepIndex() const; - bool isLoopEnabled() const; - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/AllSysExEvent.cpp b/src/main/file/all/AllSysExEvent.cpp deleted file mode 100644 index 0d9814df..00000000 --- a/src/main/file/all/AllSysExEvent.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "AllSysExEvent.hpp" - -#include "AllEvent.hpp" -#include "AllSequence.hpp" -#include "Util.hpp" - -using namespace mpc::file::all; -using namespace mpc::sequencer; - -std::vector AllSysExEvent::MIXER_SIGNATURE = {static_cast(240), 71, - 0, 68, 69}; - -EventData AllSysExEvent::bytesToMpcEvent(const std::vector &bytes) -{ - const int byteCount = bytes[BYTE_COUNT_OFFSET]; - - std::vector sysexLoadData(byteCount); - - EventData e; - - for (int i = 0; i < byteCount; i++) - { - sysexLoadData[i] = bytes[DATA_OFFSET + i]; - } - - if (Util::vecEquals(Util::vecCopyOfRange( - sysexLoadData, MIXER_SIGNATURE_OFFSET, - MIXER_SIGNATURE_OFFSET + MIXER_SIGNATURE.size()), - MIXER_SIGNATURE)) - { - e.type = EventType::Mixer; - - auto paramCandidate = sysexLoadData[MIXER_PARAMETER_OFFSET] - 1; - - if (paramCandidate == 4) - { - paramCandidate = 3; - } - - e.mixerParameter = paramCandidate; - e.mixerPad = sysexLoadData[MIXER_PAD_OFFSET]; - e.mixerValue = sysexLoadData[MIXER_VALUE_OFFSET]; - e.tick = AllEvent::readTick(bytes); - } - else - { - e.type = EventType::SystemExclusive; - e.sysExByteA = sysexLoadData.size() > 0 - ? static_cast(sysexLoadData[0]) - : 0; - e.sysExByteB = sysexLoadData.size() > 1 - ? static_cast(sysexLoadData[1]) - : 0; - e.tick = AllEvent::readTick(bytes); - } - - e.trackIndex = TrackIndex(bytes[AllEvent::TRACK_OFFSET]); - - return e; -} - -std::vector AllSysExEvent::mpcEventToBytes(const EventData &e) -{ - std::vector bytes; - - if (e.type == EventType::Mixer) - { - bytes = std::vector(32); - - AllEvent::writeTick(bytes, e.tick); - bytes[AllEvent::TRACK_OFFSET] = e.trackIndex; - bytes[CHUNK_HEADER_ID_OFFSET] = HEADER_ID; - bytes[BYTE_COUNT_OFFSET] = 9; - bytes[DATA_HEADER_ID_OFFSET] = HEADER_ID; - for (int i = 0; i < MIXER_SIGNATURE.size(); i++) - { - bytes[DATA_OFFSET + i] = MIXER_SIGNATURE[i]; - } - - bytes[DATA_OFFSET + MIXER_PAD_OFFSET] = e.mixerPad; - auto paramCandidate = e.mixerParameter; - - if (paramCandidate == 3) - { - paramCandidate = 4; - } - - paramCandidate++; - bytes[DATA_OFFSET + MIXER_PARAMETER_OFFSET] = paramCandidate; - bytes[DATA_OFFSET + MIXER_VALUE_OFFSET] = e.mixerValue; - bytes[DATA_OFFSET + MIXER_VALUE_OFFSET + 1] = DATA_TERMINATOR_ID; - bytes[MIX_TERMINATOR_ID_OFFSET] = CHUNK_TERMINATOR_ID; - } - else if (e.type == EventType::SystemExclusive) - { - constexpr int dataSize = 2; - constexpr int dataSegments = (dataSize + 7) / 8; - bytes = std::vector((dataSegments + 2) * - AllSequence::EVENT_SEG_LENGTH); - AllEvent::writeTick(bytes, e.tick); - bytes[AllEvent::TRACK_OFFSET] = e.trackIndex; - bytes[AllEvent::TRACK_OFFSET + - (dataSegments + 1) * AllSequence::EVENT_SEG_LENGTH] = - e.trackIndex; - bytes[CHUNK_HEADER_ID_OFFSET] = HEADER_ID; - bytes[BYTE_COUNT_OFFSET] = static_cast(dataSize); - - bytes[DATA_OFFSET] = static_cast(e.sysExByteA); - bytes[DATA_OFFSET + 1] = static_cast(e.sysExByteB); - - bytes[static_cast(bytes.size()) - 4] = CHUNK_TERMINATOR_ID; - } - - return bytes; -} diff --git a/src/main/file/all/AllSysExEvent.hpp b/src/main/file/all/AllSysExEvent.hpp deleted file mode 100644 index 88a1630d..00000000 --- a/src/main/file/all/AllSysExEvent.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "sequencer/EventData.hpp" - -#include -#include - -namespace mpc::file::all -{ - class AllSysExEvent - { - static constexpr int CHUNK_HEADER_ID_OFFSET = 4; - static constexpr int BYTE_COUNT_OFFSET = 5; - static constexpr int DATA_OFFSET = 8; - static constexpr int MIX_TERMINATOR_ID_OFFSET = 28; - static constexpr int DATA_HEADER_ID_OFFSET = 8; - static constexpr uint8_t HEADER_ID = 240; - static constexpr uint8_t DATA_TERMINATOR_ID = 247; - static constexpr uint8_t CHUNK_TERMINATOR_ID = 248; - static constexpr int MIXER_SIGNATURE_OFFSET = 0; - static constexpr int MIXER_PARAMETER_OFFSET = 5; - static constexpr int MIXER_PAD_OFFSET = 6; - static constexpr int MIXER_VALUE_OFFSET = 7; - - static std::vector MIXER_SIGNATURE; - - public: - static sequencer::EventData bytesToMpcEvent(const std::vector &); - static std::vector mpcEventToBytes(const sequencer::EventData &); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/Bar.cpp b/src/main/file/all/Bar.cpp deleted file mode 100644 index d9aad996..00000000 --- a/src/main/file/all/Bar.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "file/all/Bar.hpp" - -#include "file/ByteUtil.hpp" - -using namespace mpc::file::all; - -Bar::Bar(const std::vector &bytes, Bar *previousBar) -{ - ticksPerBeat = bytes[0] & 255; - auto intVal = ByteUtil::bytes2ushort({bytes[1], bytes[2]}); - lastTick = (bytes[3] & 255) * 65536 + intVal; - barLength = lastTick - (previousBar == nullptr ? 0 : previousBar->lastTick); -} - -Bar::Bar(int ticksPerBeat, int lastTick) -{ - saveBytes = std::vector(4); - saveBytes[0] = static_cast(ticksPerBeat); - auto intVal = lastTick % 65536; - auto bytePair = ByteUtil::ushort2bytes(intVal); - saveBytes[1] = bytePair[0]; - saveBytes[2] = bytePair[1]; - saveBytes[3] = static_cast((lastTick - intVal) / 65536); -} - -int Bar::getTicksPerBeat() const -{ - return ticksPerBeat; -} - -int Bar::getDenominator() const -{ - auto result = 0; - switch (ticksPerBeat) - { - case 96: - result = 4; - break; - case 48: - result = 8; - break; - case 24: - result = 16; - break; - case 12: - result = 32; - break; - } - - return result; -} - -int Bar::getNumerator() const -{ - return barLength / ticksPerBeat; -} - -int Bar::getLastTick() const -{ - return lastTick; -} - -std::vector &Bar::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/Bar.hpp b/src/main/file/all/Bar.hpp deleted file mode 100644 index ead2103e..00000000 --- a/src/main/file/all/Bar.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -namespace mpc::file::all -{ - class Bar; - - class Bar - { - - public: - int ticksPerBeat; - int lastTick; - int barLength; - std::vector saveBytes; - - int getTicksPerBeat() const; - int getDenominator() const; - int getNumerator() const; - int getLastTick() const; - - std::vector &getBytes(); - - Bar(const std::vector &bytes, Bar *previousBar); - Bar(int ticksPerBeat, int lastTick); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/BarList.cpp b/src/main/file/all/BarList.cpp deleted file mode 100644 index 3d37638d..00000000 --- a/src/main/file/all/BarList.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "file/all/BarList.hpp" - -#include "file/all/Bar.hpp" -#include "sequencer/Sequence.hpp" - -#include "Util.hpp" - -using namespace mpc::file::all; - -BarList::BarList(const std::vector &loadBytes) -{ - Bar *previousBar = nullptr; - - for (int i = 0; i < 999; i++) - { - auto bar = new Bar(Util::vecCopyOfRange(loadBytes, i * 4, i * 4 + 4), - previousBar); - - if (bar->lastTick == 0) - { - delete bar; - break; - } - - bars.push_back(bar); - previousBar = bar; - } -} - -BarList::~BarList() -{ - for (auto &b : bars) - { - if (b != nullptr) - { - delete b; - } - } -} - -BarList::BarList(sequencer::Sequence *seq) -{ - saveBytes = std::vector(3996); - auto ticksPerBeat = 0; - auto lastTick = 0; - - for (int i = 0; i < seq->getLastBarIndex() + 1; i++) - { - const auto barLength = seq->getBarLength(i); - lastTick += barLength; - ticksPerBeat = barLength / seq->getNumerator(i); - - Bar bar(ticksPerBeat, lastTick); - - for (auto j = 0; j < 4; j++) - { - saveBytes[i * 4 + j] = bar.getBytes()[j]; - } - } - - Bar bar(ticksPerBeat, 0); - - for (int i = 0; i < 4; i++) - { - saveBytes[(seq->getLastBarIndex() + 1) * 4 + i] = bar.getBytes()[i]; - } -} - -std::vector BarList::getBars() -{ - return bars; -} - -std::vector &BarList::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/BarList.hpp b/src/main/file/all/BarList.hpp deleted file mode 100644 index 877f3c34..00000000 --- a/src/main/file/all/BarList.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -namespace mpc::sequencer -{ - class Sequence; -} - -namespace mpc::file::all -{ - class Bar; - - class BarList - { - - public: - std::vector bars; - std::vector saveBytes; - - std::vector getBars(); - - std::vector &getBytes(); - BarList(const std::vector &loadBytes); - - BarList(sequencer::Sequence *seq); - ~BarList(); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/Count.cpp b/src/main/file/all/Count.cpp deleted file mode 100644 index 7ebe0f5c..00000000 --- a/src/main/file/all/Count.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "file/all/Count.hpp" -#include "sequencer/Transport.hpp" - -#include "Mpc.hpp" - -#include "file/all/AllParser.hpp" - -#include "lcdgui/screens/window/CountMetronomeScreen.hpp" -#include "lcdgui/screens/dialog/MetronomeSoundScreen.hpp" -#include "sequencer/Sequencer.hpp" -#include "sequencer/Transport.hpp" - -using namespace mpc::lcdgui; -using namespace mpc::lcdgui::screens::window; -using namespace mpc::lcdgui::screens::dialog; -using namespace mpc::file::all; - -Count::Count(const std::vector &b) -{ - enabled = b[ENABLED_OFFSET] > 0; - countInMode = b[COUNT_IN_MODE_OFFSET]; - clickVolume = b[CLICK_VOLUME_OFFSET]; - rate = b[RATE_OFFSET]; - enabledInPlay = b[ENABLED_IN_PLAY_OFFSET] > 0; - enabledInRec = b[ENABLED_IN_REC_OFFSET] > 0; - clickOutput = b[CLICK_OUTPUT_OFFSET]; - waitForKeyEnabled = b[WAIT_FOR_KEY_ENABLED_OFFSET] > 0; - sound = b[SOUND_OFFSET]; - accentPad = b[ACCENT_PAD_OFFSET]; - normalPad = b[NORMAL_PAD_OFFSET]; - accentVelo = b[ACCENT_VELO_OFFSET]; - normalVelo = b[NORMAL_VELO_OFFSET]; -} - -Count::Count(Mpc &mpc) -{ - auto countMetronomeScreen = - mpc.screens->get(); - auto metronomeSoundScreen = - mpc.screens->get(); - - auto lSequencer = mpc.getSequencer(); - - saveBytes = std::vector(AllParser::COUNT_LENGTH); - saveBytes[ENABLED_OFFSET] = static_cast( - lSequencer->getTransport()->isCountEnabled() ? 1 : 0); - saveBytes[COUNT_IN_MODE_OFFSET] = - static_cast(countMetronomeScreen->getCountInMode()); - saveBytes[CLICK_VOLUME_OFFSET] = - static_cast(metronomeSoundScreen->getVolume()); - saveBytes[RATE_OFFSET] = - static_cast(countMetronomeScreen->getRate()); - saveBytes[ENABLED_IN_PLAY_OFFSET] = - static_cast(countMetronomeScreen->getInPlay() ? 1 : 0); - saveBytes[ENABLED_IN_REC_OFFSET] = - static_cast(countMetronomeScreen->getInRec() ? 1 : 0); - saveBytes[CLICK_OUTPUT_OFFSET] = - static_cast(metronomeSoundScreen->getOutput()); - saveBytes[WAIT_FOR_KEY_ENABLED_OFFSET] = static_cast( - countMetronomeScreen->isWaitForKeyEnabled() ? 1 : 0); - saveBytes[SOUND_OFFSET] = - static_cast(metronomeSoundScreen->getSound()); - saveBytes[ACCENT_PAD_OFFSET] = - static_cast(metronomeSoundScreen->getAccentPad()); - saveBytes[NORMAL_PAD_OFFSET] = - static_cast(metronomeSoundScreen->getNormalPad()); - saveBytes[ACCENT_VELO_OFFSET] = - static_cast(metronomeSoundScreen->getAccentVelo()); - saveBytes[NORMAL_VELO_OFFSET] = - static_cast(metronomeSoundScreen->getNormalVelo()); -} - -bool Count::isEnabled() const -{ - return enabled; -} - -int Count::getCountInMode() const -{ - return countInMode; -} - -int Count::getClickVolume() const -{ - return clickVolume; -} - -int Count::getRate() const -{ - return rate; -} - -bool Count::isEnabledInPlay() const -{ - return enabledInPlay; -} - -bool Count::isEnabledInRec() const -{ - return enabledInRec; -} - -int Count::getClickOutput() const -{ - return clickOutput; -} - -bool Count::isWaitForKeyEnabled() const -{ - return waitForKeyEnabled; -} - -int Count::getSound() const -{ - return sound; -} - -int Count::getAccentPad() const -{ - return accentPad; -} - -int Count::getNormalPad() const -{ - return normalPad; -} - -int Count::getAccentVelo() const -{ - return accentVelo; -} - -int Count::getNormalVelo() const -{ - return normalVelo; -} - -std::vector &Count::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/Count.hpp b/src/main/file/all/Count.hpp deleted file mode 100644 index 8b402ba8..00000000 --- a/src/main/file/all/Count.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::file::all -{ - - class Count - { - - public: - static const int ENABLED_OFFSET = 0; - static const int COUNT_IN_MODE_OFFSET = 1; - static const int CLICK_VOLUME_OFFSET = 2; - static const int RATE_OFFSET = 3; - static const int ENABLED_IN_PLAY_OFFSET = 4; - static const int ENABLED_IN_REC_OFFSET = 5; - static const int CLICK_OUTPUT_OFFSET = 6; - static const int WAIT_FOR_KEY_ENABLED_OFFSET = 7; - static const int SOUND_OFFSET = 8; - static const int ACCENT_PAD_OFFSET = 9; - static const int NORMAL_PAD_OFFSET = 10; - static const int ACCENT_VELO_OFFSET = 11; - static const int NORMAL_VELO_OFFSET = 12; - bool enabled; - int countInMode; - int clickVolume; - int rate; - bool enabledInPlay; - bool enabledInRec; - int clickOutput; - bool waitForKeyEnabled; - int sound; - int accentPad; - int normalPad; - int accentVelo; - int normalVelo; - std::vector saveBytes; - - bool isEnabled() const; - int getCountInMode() const; - int getClickVolume() const; - int getRate() const; - bool isEnabledInPlay() const; - bool isEnabledInRec() const; - int getClickOutput() const; - bool isWaitForKeyEnabled() const; - int getSound() const; - int getAccentPad() const; - int getNormalPad() const; - int getAccentVelo() const; - int getNormalVelo() const; - - std::vector &getBytes(); - - Count(const std::vector &b); - Count(Mpc &mpc); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/Defaults.cpp b/src/main/file/all/Defaults.cpp index 716ac47c..ed37306f 100644 --- a/src/main/file/all/Defaults.cpp +++ b/src/main/file/all/Defaults.cpp @@ -2,7 +2,6 @@ #include "Util.hpp" #include "Mpc.hpp" -#include "file/all/AllParser.hpp" #include "lcdgui/screens/UserScreen.hpp" @@ -124,7 +123,7 @@ Defaults::Defaults(Mpc &mpc, const std::vector &loadBytes) : mpc(mpc) Defaults::Defaults(Mpc &mpc) : mpc(mpc) { - saveBytes = std::vector(AllParser::DEFAULTS_LENGTH); + saveBytes = std::vector(TOTAL_LENGTH); setNames(); @@ -174,7 +173,7 @@ void Defaults::parseNames(const std::vector &loadBytes) { std::vector stringBuffer = Util::vecCopyOfRange(loadBytes, DEF_SEQ_NAME_OFFSET, - DEF_SEQ_NAME_OFFSET + AllParser::NAME_LENGTH); + DEF_SEQ_NAME_OFFSET + NAME_LENGTH); defaultSeqName = ""; @@ -192,9 +191,9 @@ void Defaults::parseNames(const std::vector &loadBytes) for (int i = 0; i < 33; i++) { - offset = DEV_NAMES_OFFSET + i * AllParser::DEV_NAME_LENGTH; + offset = DEV_NAMES_OFFSET + i * DEV_NAME_LENGTH; stringBuffer = Util::vecCopyOfRange( - loadBytes, offset, offset + AllParser::DEV_NAME_LENGTH); + loadBytes, offset, offset + DEV_NAME_LENGTH); std::string s; for (const char c : stringBuffer) @@ -212,9 +211,9 @@ void Defaults::parseNames(const std::vector &loadBytes) for (int i = 0; i < 64; i++) { - offset = TR_NAMES_OFFSET + i * AllParser::NAME_LENGTH; + offset = TR_NAMES_OFFSET + i * NAME_LENGTH; stringBuffer = Util::vecCopyOfRange(loadBytes, offset, - offset + AllParser::NAME_LENGTH); + offset + NAME_LENGTH); std::string s; for (const char c : stringBuffer) @@ -329,7 +328,7 @@ void Defaults::setNames() { auto const defSeqName = StrUtil::padRight(mpc.getSequencer()->getDefaultSequenceName(), " ", - AllParser::NAME_LENGTH); + NAME_LENGTH); for (int i = 0; i < 16; i++) { @@ -342,9 +341,9 @@ void Defaults::setNames() i == 0 ? " " : "Device" + StrUtil::padLeft(std::to_string(i), "0", 2); - const auto offset = DEV_NAMES_OFFSET + i * AllParser::DEV_NAME_LENGTH; + const auto offset = DEV_NAMES_OFFSET + i * DEV_NAME_LENGTH; - for (int j = offset; j < offset + AllParser::DEV_NAME_LENGTH; j++) + for (int j = offset; j < offset + DEV_NAME_LENGTH; j++) { saveBytes[j] = deviceName[j - offset]; } @@ -354,11 +353,11 @@ void Defaults::setNames() { const auto trackName = StrUtil::padRight(mpc.getSequencer()->getDefaultTrackName(i), " ", - AllParser::NAME_LENGTH); + NAME_LENGTH); - const auto offset = TR_NAMES_OFFSET + i * AllParser::NAME_LENGTH; + const auto offset = TR_NAMES_OFFSET + i * NAME_LENGTH; - for (int j = offset; j < offset + AllParser::NAME_LENGTH; j++) + for (int j = offset; j < offset + NAME_LENGTH; j++) { saveBytes[j] = trackName[j - offset]; } diff --git a/src/main/file/all/Defaults.hpp b/src/main/file/all/Defaults.hpp index 1d7f1060..207cdb1f 100644 --- a/src/main/file/all/Defaults.hpp +++ b/src/main/file/all/Defaults.hpp @@ -47,6 +47,9 @@ namespace mpc::file::all static const int TR_VELOS_LENGTH{64}; static const int TR_STATUS_OFFSET{1664}; static const int TR_STATUS_LENGTH{64}; + static const int TOTAL_LENGTH{1728}; + static const int NAME_LENGTH{16}; + static const int DEV_NAME_LENGTH{8}; std::string defaultSeqName; int tempo; diff --git a/src/main/file/all/Header.cpp b/src/main/file/all/Header.cpp deleted file mode 100644 index 3927e204..00000000 --- a/src/main/file/all/Header.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "file/all/Header.hpp" - -#include "Util.hpp" - -#include - -using namespace mpc::file::all; - -Header::Header(const std::vector &_loadBytes) : loadBytes(_loadBytes) {} - -Header::Header() -{ - const std::string s = "MPC2KXL ALL 1.00"; - saveBytes = std::vector(16); - for (int i = 0; i < 16; i++) - { - saveBytes[i] = s[i]; - } -} - -std::vector &Header::getHeaderArray() -{ - return loadBytes; -} - -bool Header::verifyFileID() const -{ - auto verifyFileID = false; - auto checkFileID = Util::vecCopyOfRange(loadBytes, 0, 16); - std::string fileIDString; - for (char c : checkFileID) - { - if (c == 0x00) - { - break; - } - fileIDString.push_back(c); - } - std::string shouldBe = "MPC2KXL ALL 1.00"; - if (fileIDString == shouldBe) - { - verifyFileID = true; - } - return verifyFileID; -} - -std::vector &Header::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/Header.hpp b/src/main/file/all/Header.hpp deleted file mode 100644 index 68845fb3..00000000 --- a/src/main/file/all/Header.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -namespace mpc::file::all -{ - class Header - { - public: - std::vector loadBytes; - std::vector saveBytes; - - std::vector &getHeaderArray(); - bool verifyFileID() const; - - std::vector &getBytes(); - - Header(const std::vector &loadBytes); - Header(); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/MidiInput.cpp b/src/main/file/all/MidiInput.cpp deleted file mode 100644 index f55448e6..00000000 --- a/src/main/file/all/MidiInput.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include "MidiInput.hpp" - -#include "Mpc.hpp" - -#include "file/BitUtil.hpp" - -#include "lcdgui/screens/window/MultiRecordingSetupScreen.hpp" -#include "lcdgui/screens/window/MidiInputScreen.hpp" -#include "lcdgui/screens/window/MidiOutputScreen.hpp" -#include "sequencer/Sequencer.hpp" - -using namespace mpc::lcdgui; -using namespace mpc::lcdgui::screens::window; -using namespace mpc::file::all; - -MidiInput::MidiInput(const std::vector &b) -{ - softThruMode = b[SOFT_THRU_MODE_OFFSET]; - receiveCh = b[RECEIVE_CH_OFFSET]; - sustainPedalToDuration = b[SUSTAIN_PEDAL_TO_DURATION_OFFSET] > 0; - filterEnabled = b[FILTER_ENABLED_OFFSET] > 0; - filterType = b[FILTER_TYPE_OFFSET]; - multiRecEnabled = b[MULTI_REC_ENABLED_OFFSET] > 0; - - for (int i = 0; i < MULTI_REC_TRACK_DESTS_LENGTH; i++) - { - multiRecTrackDests[i] = b[MULTI_REC_TRACK_DESTS_OFFSET + i] - 1; - } - - notePassEnabled = b[NOTE_PASS_ENABLED_OFFSET] > 0; - pitchBendPassEnabled = b[PITCH_BEND_PASS_ENABLED_OFFSET] > 0; - pgmChangePassEnabled = b[PGM_CHANGE_PASS_ENABLED_OFFSET] > 0; - chPressurePassEnabled = b[CH_PRESSURE_PASS_ENABLED_OFFSET] > 0; - polyPressurePassEnabled = b[POLY_PRESSURE_PASS_ENABLED_OFFSET] > 0; - exclusivePassEnabled = b[EXCLUSIVE_PASS_ENABLED_OFFSET] > 0; - - int ccPassEnabledCounter = 0; - - for (int i = 0; i < 16; i++) - { - const auto currentCcPassEnabled = b[CC_PASS_ENABLED_OFFSET + i]; - for (int j = 0; j < 8; j++) - { - ccPassEnabled[ccPassEnabledCounter++] = - BitUtil::isBitOn(currentCcPassEnabled, j); - } - } -} - -MidiInput::MidiInput(Mpc &mpc) -{ - saveBytes = std::vector(LENGTH); - - auto midiInputScreen = mpc.screens->get(); - - saveBytes[SOFT_THRU_MODE_OFFSET] = - mpc.screens->get()->getSoftThru(); - saveBytes[RECEIVE_CH_OFFSET] = - static_cast(midiInputScreen->getReceiveCh() + 1); - saveBytes[SUSTAIN_PEDAL_TO_DURATION_OFFSET] = static_cast( - midiInputScreen->isSustainPedalToDurationEnabled() ? 1 : 0); - saveBytes[FILTER_ENABLED_OFFSET] = - static_cast(midiInputScreen->isMidiFilterEnabled() ? 1 : 0); - saveBytes[FILTER_TYPE_OFFSET] = - static_cast(midiInputScreen->getType()); - saveBytes[MULTI_REC_ENABLED_OFFSET] = - static_cast(mpc.getSequencer()->isRecordingModeMulti() ? 1 : 0); - - auto screen = mpc.screens->get(); - - for (int i = 0; i < MULTI_REC_TRACK_DESTS_LENGTH; i++) - { - saveBytes[MULTI_REC_TRACK_DESTS_OFFSET + i] = - static_cast(screen->getMrsLines()[i]->getTrack() + 1); - } - - saveBytes[NOTE_PASS_ENABLED_OFFSET] = - static_cast(midiInputScreen->isNotePassEnabled() ? 1 : 0); - saveBytes[PITCH_BEND_PASS_ENABLED_OFFSET] = - static_cast(midiInputScreen->isPitchBendPassEnabled() ? 1 : 0); - saveBytes[PGM_CHANGE_PASS_ENABLED_OFFSET] = - static_cast(midiInputScreen->isPgmChangePassEnabled() ? 1 : 0); - saveBytes[CH_PRESSURE_PASS_ENABLED_OFFSET] = - static_cast(midiInputScreen->isChPressurePassEnabled() ? 1 : 0); - saveBytes[POLY_PRESSURE_PASS_ENABLED_OFFSET] = static_cast( - midiInputScreen->isPolyPressurePassEnabled() ? 1 : 0); - saveBytes[EXCLUSIVE_PASS_ENABLED_OFFSET] = - static_cast(midiInputScreen->isExclusivePassEnabled() ? 1 : 0); - - for (int i = 0; i < 16; i++) - { - char currentCcPassByte = 0x00; - - for (int j = 0; j < 8; j++) - { - const bool currentCcPassEnabled = - midiInputScreen->getCcPassEnabled()[i * 8 + j]; - - currentCcPassByte = - BitUtil::setBit(currentCcPassByte, j, currentCcPassEnabled); - } - - saveBytes[CC_PASS_ENABLED_OFFSET + i] = currentCcPassByte; - } -} - -int MidiInput::getSoftThruMode() const -{ - return softThruMode; -} - -int MidiInput::getReceiveCh() const -{ - return receiveCh; -} - -bool MidiInput::isSustainPedalToDurationEnabled() const -{ - return sustainPedalToDuration; -} - -bool MidiInput::isFilterEnabled() const -{ - return filterEnabled; -} - -int MidiInput::getFilterType() const -{ - return filterType; -} - -bool MidiInput::isMultiRecEnabled() const -{ - return multiRecEnabled; -} - -std::vector MidiInput::getMultiRecTrackDests() -{ - return multiRecTrackDests; -} - -bool MidiInput::isNotePassEnabled() const -{ - return notePassEnabled; -} - -bool MidiInput::isPitchBendPassEnabled() const -{ - return pitchBendPassEnabled; -} - -bool MidiInput::isPgmChangePassEnabled() const -{ - return pgmChangePassEnabled; -} - -bool MidiInput::isChPressurePassEnabled() const -{ - return chPressurePassEnabled; -} - -bool MidiInput::isPolyPressurePassEnabled() const -{ - return polyPressurePassEnabled; -} - -bool MidiInput::isExclusivePassEnabled() const -{ - return exclusivePassEnabled; -} - -std::vector MidiInput::getCcPassEnabled() -{ - return ccPassEnabled; -} - -std::vector &MidiInput::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/MidiInput.hpp b/src/main/file/all/MidiInput.hpp deleted file mode 100644 index bd198464..00000000 --- a/src/main/file/all/MidiInput.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::file::all -{ - - class MidiInput - { - - public: - static const int LENGTH{62}; - static const int SOFT_THRU_MODE_OFFSET = 0; - static const int RECEIVE_CH_OFFSET{1}; - static const int SUSTAIN_PEDAL_TO_DURATION_OFFSET{2}; - static const int FILTER_ENABLED_OFFSET{3}; - static const int FILTER_TYPE_OFFSET{4}; - static const int MULTI_REC_ENABLED_OFFSET{5}; - static const int MULTI_REC_TRACK_DESTS_OFFSET{6}; - static const int MULTI_REC_TRACK_DESTS_LENGTH{32}; - static const int NOTE_PASS_ENABLED_OFFSET{40}; - static const int PITCH_BEND_PASS_ENABLED_OFFSET{41}; - static const int PGM_CHANGE_PASS_ENABLED_OFFSET{42}; - static const int CH_PRESSURE_PASS_ENABLED_OFFSET{43}; - static const int POLY_PRESSURE_PASS_ENABLED_OFFSET{44}; - static const int EXCLUSIVE_PASS_ENABLED_OFFSET{45}; - static const int CC_PASS_ENABLED_OFFSET{46}; - - int softThruMode; - int receiveCh; - bool sustainPedalToDuration; - bool filterEnabled; - int filterType; - bool multiRecEnabled; - std::vector multiRecTrackDests = std::vector(34); - bool notePassEnabled; - bool pitchBendPassEnabled; - bool pgmChangePassEnabled; - bool chPressurePassEnabled; - bool polyPressurePassEnabled; - bool exclusivePassEnabled; - std::vector ccPassEnabled = std::vector(128); - std::vector saveBytes; - - int getSoftThruMode() const; - int getReceiveCh() const; - bool isSustainPedalToDurationEnabled() const; - bool isFilterEnabled() const; - int getFilterType() const; - bool isMultiRecEnabled() const; - std::vector getMultiRecTrackDests(); - bool isNotePassEnabled() const; - bool isPitchBendPassEnabled() const; - bool isPgmChangePassEnabled() const; - bool isChPressurePassEnabled() const; - bool isPolyPressurePassEnabled() const; - bool isExclusivePassEnabled() const; - std::vector getCcPassEnabled(); - - std::vector &getBytes(); - - MidiInput(const std::vector &b); - MidiInput(Mpc &mpc); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/MidiSyncMisc.cpp b/src/main/file/all/MidiSyncMisc.cpp deleted file mode 100644 index b34ffa8c..00000000 --- a/src/main/file/all/MidiSyncMisc.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "file/all/MidiSyncMisc.hpp" - -#include "Mpc.hpp" -#include "file/all/AllParser.hpp" - -#include "StrUtil.hpp" -#include "Util.hpp" - -#include "lcdgui/screens/SongScreen.hpp" -#include "lcdgui/screens/SyncScreen.hpp" -#include "lcdgui/screens/window/IgnoreTempoChangeScreen.hpp" - -using namespace mpc::lcdgui::screens; -using namespace mpc::lcdgui::screens::window; -using namespace mpc::lcdgui; -using namespace mpc::file::all; - -MidiSyncMisc::MidiSyncMisc(const std::vector &b) -{ - inMode = b[IN_MODE_OFFSET]; - outMode = b[OUT_MODE_OFFSET]; - shiftEarly = b[SHIFT_EARLY_OFFSET]; - sendMMCEnabled = b[SEND_MMC_OFFSET] > 0; - frameRate = b[FRAME_RATE_OFFSET]; - input = b[INPUT_OFFSET]; - output = b[OUTPUT_OFFSET]; - - auto stringBuffer = Util::vecCopyOfRange( - b, DEF_SONG_NAME_OFFSET, DEF_SONG_NAME_OFFSET + AllParser::NAME_LENGTH); - defSongName = std::string(stringBuffer.begin(), stringBuffer.end()); - - songModeIgnoreTempoChangeEventsInSequence = - b[SONG_MODE_IGNORE_TEMPO_CHANGE_EVENTS_IN_SEQUENCE_OFFSET] == 0x01; -} - -MidiSyncMisc::MidiSyncMisc(Mpc &mpc) -{ - saveBytes = std::vector(LENGTH); - - auto syncScreen = mpc.screens->get(); - - saveBytes[IN_MODE_OFFSET] = static_cast(syncScreen->getModeIn()); - saveBytes[OUT_MODE_OFFSET] = static_cast(syncScreen->getModeOut()); - saveBytes[SHIFT_EARLY_OFFSET] = static_cast(syncScreen->shiftEarly); - saveBytes[SEND_MMC_OFFSET] = - static_cast(syncScreen->sendMMCEnabled ? 1 : 0); - saveBytes[FRAME_RATE_OFFSET] = static_cast(syncScreen->frameRate); - saveBytes[INPUT_OFFSET] = static_cast(syncScreen->in); - saveBytes[OUTPUT_OFFSET] = static_cast(syncScreen->out); - - auto songScreen = mpc.screens->get(); - - for (int i = 0; i < AllParser::NAME_LENGTH; i++) - { - saveBytes[DEF_SONG_NAME_OFFSET + i] = - StrUtil::padRight(songScreen->getDefaultSongName(), " ", 16)[i]; - } - - saveBytes[DEF_SONG_NAME_OFFSET + 16] = 1; - - saveBytes[SONG_MODE_IGNORE_TEMPO_CHANGE_EVENTS_IN_SEQUENCE_OFFSET] = - mpc.screens->get()->getIgnore(); -} - -int MidiSyncMisc::getInMode() const -{ - return inMode; -} - -int MidiSyncMisc::getOutMode() const -{ - return outMode; -} - -int MidiSyncMisc::getShiftEarly() const -{ - return shiftEarly; -} - -bool MidiSyncMisc::isSendMMCEnabled() const -{ - return sendMMCEnabled; -} - -int MidiSyncMisc::getFrameRate() const -{ - return frameRate; -} - -int MidiSyncMisc::getInput() const -{ - return input; -} - -int MidiSyncMisc::getOutput() const -{ - return output; -} - -std::string MidiSyncMisc::getDefSongName() -{ - return defSongName; -} - -bool MidiSyncMisc::getSongModeIgnoreTempoChangeEvents() const -{ - return songModeIgnoreTempoChangeEventsInSequence; -} - -std::vector &MidiSyncMisc::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/MidiSyncMisc.hpp b/src/main/file/all/MidiSyncMisc.hpp deleted file mode 100644 index ad5a5a9e..00000000 --- a/src/main/file/all/MidiSyncMisc.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::file::all -{ - class MidiSyncMisc - { - - public: - static const int LENGTH = 24; - - private: - static const int IN_MODE_OFFSET = 0; - static const int OUT_MODE_OFFSET = 1; - static const int SHIFT_EARLY_OFFSET = 2; - static const int SEND_MMC_OFFSET = 3; - static const int FRAME_RATE_OFFSET = 4; - static const int INPUT_OFFSET = 5; - static const int OUTPUT_OFFSET = 6; - static const int DEF_SONG_NAME_OFFSET = 7; - static const int - SONG_MODE_IGNORE_TEMPO_CHANGE_EVENTS_IN_SEQUENCE_OFFSET = 23; - - public: - int inMode; - int outMode; - int shiftEarly; - bool sendMMCEnabled; - int frameRate; - int input; - int output; - std::string defSongName{""}; - bool songModeIgnoreTempoChangeEventsInSequence; - - std::vector saveBytes; - - int getInMode() const; - int getOutMode() const; - int getShiftEarly() const; - bool isSendMMCEnabled() const; - int getFrameRate() const; - int getInput() const; - int getOutput() const; - std::string getDefSongName(); - bool getSongModeIgnoreTempoChangeEvents() const; - - std::vector &getBytes(); - - MidiSyncMisc(const std::vector &b); - MidiSyncMisc(Mpc &mpc); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/Misc.cpp b/src/main/file/all/Misc.cpp deleted file mode 100644 index ebf75239..00000000 --- a/src/main/file/all/Misc.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "file/all/Misc.hpp" - -#include "Mpc.hpp" - -#include "controller/ClientEventController.hpp" -#include "controller/ClientMidiEventController.hpp" -#include "controller/MidiFootswitchFunctionMap.hpp" -#include "lcdgui/screens/window/StepEditOptionsScreen.hpp" -#include "lcdgui/screens/window/MidiInputScreen.hpp" -#include "lcdgui/screens/OthersScreen.hpp" -#include "lcdgui/screens/SyncScreen.hpp" -#include "lcdgui/screens/MidiSwScreen.hpp" - -#include "file/ByteUtil.hpp" - -using namespace mpc::lcdgui::screens; -using namespace mpc::lcdgui::screens::window; -using namespace mpc::lcdgui; -using namespace mpc::file::all; - -Misc::Misc(const std::vector &b) -{ - for (int i = 0; i < 9; i++) - { - const auto locationOffset = LOCATIONS_OFFSET + i * 4; - const uint16_t locationBarIndex = - ByteUtil::bytes2ushort({b[locationOffset], b[locationOffset + 1]}); - const uint8_t locationBeatIndex = b[locationOffset + 2]; - const uint8_t locationClock = b[locationOffset + 3]; - locations[i] = {locationBarIndex, locationBeatIndex, locationClock}; - } - - tapAvg = b[TAP_AVG_OFFSET]; - inReceiveMMCEnabled = b[MIDI_SYNC_IN_RECEIVE_MMC_OFFSET] > 0; - - for (int i = 0; i < 4; i++) - { - auto ctrl = static_cast(b[MIDI_SWITCH_OFFSET + i * 2]); - auto func = b[MIDI_SWITCH_OFFSET + i * 2 + 1]; - switches[i] = std::pair(ctrl == 0xFF ? -1 : ctrl, func); - } - - autoStepInc = b[AUTO_STEP_INCREMENT_OFFSET] > 0; - durationOfRecNotesTcEnabled = b[DURATION_OF_REC_NOTES_OFFSET] > 0; - durationTcPercentage = b[DURATION_TC_PERCENTAGE_OFFSET]; - pgmChToSeqEnabled = b[MIDI_PGM_CHANGE_TO_SEQ_OFFSET] > 0; -} - -Misc::Misc(Mpc &mpc) -{ - saveBytes = std::vector(LENGTH); - - auto &locationsToPersist = - mpc.screens->get()->getLocations(); - - assert(locationsToPersist.size() == 9); - - for (int i = 0; i < 9; i++) - { - const auto locationBarBytes = - ByteUtil::ushort2bytes(std::get<0>(locationsToPersist[i])); - const auto locationBeatByte = std::get<1>(locationsToPersist[i]); - const auto locationClockByte = std::get<2>(locationsToPersist[i]); - const auto locationOffset = LOCATIONS_OFFSET + i * 4; - saveBytes[locationOffset] = locationBarBytes[0]; - saveBytes[locationOffset + 1] = locationBarBytes[1]; - saveBytes[locationOffset + 2] = locationBeatByte; - saveBytes[locationOffset + 3] = locationClockByte; - } - - auto stepEditOptionsScreen = - mpc.screens->get(); - auto othersScreen = mpc.screens->get(); - - saveBytes[TAP_AVG_OFFSET] = (char)(othersScreen->getTapAveraging() - 2); - - auto syncScreen = mpc.screens->get(); - - saveBytes[MIDI_SYNC_IN_RECEIVE_MMC_OFFSET] = - (char)(syncScreen->receiveMMCEnabled ? 1 : 0); - - auto midiSwScreen = mpc.screens->get(); - - auto &footswitchBindings = - mpc.clientEventController->getClientMidiEventController() - ->getFootswitchAssignmentController() - ->bindings; - - for (int i = 0; - i < controller::ClientMidiFootswitchAssignmentController::SWITCH_COUNT; - i++) - { - int cc = -1; - int funcIndex = 0; - - std::visit( - [&](auto &b) - { - cc = b.number; - - if constexpr (std::is_same_v, - input::midi::HardwareBinding>) - { - if (auto fn = controller::componentIdToFootswitch( - b.target.componentId)) - { - funcIndex = static_cast(*fn); - } - } - else if constexpr (std::is_same_v< - std::decay_t, - input::midi::SequencerBinding>) - { - if (auto fn = controller::sequencerCmdToFootswitch( - b.target.command)) - { - funcIndex = static_cast(*fn); - } - } - }, - footswitchBindings[i]); - - saveBytes[MIDI_SWITCH_OFFSET + i * 2] = - cc == -1 ? (char)0xFF : (char)cc; - saveBytes[MIDI_SWITCH_OFFSET + i * 2 + 1] = (char)funcIndex; - } - - saveBytes[AUTO_STEP_INCREMENT_OFFSET] = - (char)(stepEditOptionsScreen->isAutoStepIncrementEnabled() ? 1 : 0); - saveBytes[DURATION_OF_REC_NOTES_OFFSET] = - (char)(stepEditOptionsScreen->isDurationOfRecordedNotesTcValue() ? 1 - : 0); - saveBytes[DURATION_TC_PERCENTAGE_OFFSET] = - (char)stepEditOptionsScreen->getTcValuePercentage(); - const auto midiInputScreen = mpc.screens->get(); - saveBytes[MIDI_PGM_CHANGE_TO_SEQ_OFFSET] = - midiInputScreen->getProgChangeSeq() ? 0x01 : 0x00; -} - -int Misc::getTapAvg() const -{ - return tapAvg; -} - -bool Misc::isInReceiveMMCEnabled() const -{ - return inReceiveMMCEnabled; -} - -bool Misc::isAutoStepIncEnabled() const -{ - return autoStepInc; -} - -bool Misc::isDurationOfRecNotesTc() const -{ - return durationOfRecNotesTcEnabled; -} - -int Misc::getDurationTcPercentage() const -{ - return durationTcPercentage; -} - -bool Misc::isPgmChToSeqEnabled() const -{ - return pgmChToSeqEnabled; -} - -std::vector> Misc::getSwitches() -{ - return switches; -} - -std::vector &Misc::getLocations() -{ - return locations; -} - -std::vector &Misc::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/Misc.hpp b/src/main/file/all/Misc.hpp deleted file mode 100644 index 088b2687..00000000 --- a/src/main/file/all/Misc.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include - -#include "lcdgui/screens/window/LocateScreen.hpp" - -namespace mpc -{ - class Mpc; -} - -namespace mpc::file::all -{ - class Misc - { - public: - static const int LENGTH = 131; - - std::vector> getSwitches(); - int getTapAvg() const; - bool isInReceiveMMCEnabled() const; - bool isAutoStepIncEnabled() const; - bool isDurationOfRecNotesTc() const; - int getDurationTcPercentage() const; - bool isPgmChToSeqEnabled() const; - std::vector &getLocations(); - - std::vector &getBytes(); - - Misc(const std::vector &b); - Misc(Mpc &); - - private: - static const int LOCATIONS_OFFSET = 0; - static const int TAP_AVG_OFFSET = 36; - static const int MIDI_SYNC_IN_RECEIVE_MMC_OFFSET = 37; - static const int MIDI_SWITCH_OFFSET = 38; - static const int AUTO_STEP_INCREMENT_OFFSET = 49; - static const int DURATION_OF_REC_NOTES_OFFSET = 50; - static const int DURATION_TC_PERCENTAGE_OFFSET = 51; - static const int MIDI_PGM_CHANGE_TO_SEQ_OFFSET = 52; - - int tapAvg; - bool inReceiveMMCEnabled; - bool autoStepInc; - bool durationOfRecNotesTcEnabled; - int durationTcPercentage; - bool pgmChToSeqEnabled; - std::vector saveBytes; - std::vector> switches = - std::vector>(4); - std::vector locations = - std::vector(9, {0, 0, 0}); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/SequenceNames.cpp b/src/main/file/all/SequenceNames.cpp deleted file mode 100644 index 0ae363da..00000000 --- a/src/main/file/all/SequenceNames.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "file/all/SequenceNames.hpp" - -#include "Mpc.hpp" -#include "file/all/AllParser.hpp" -#include "sequencer/MixerEvent.hpp" -#include "sequencer/Sequence.hpp" -#include "sequencer/Track.hpp" -#include "sequencer/Sequencer.hpp" -#include "sequencer/SystemExclusiveEvent.hpp" - -#include "file/ByteUtil.hpp" -#include "StrUtil.hpp" -#include "Util.hpp" - -using namespace mpc::file::all; - -SequenceNames::SequenceNames(const std::vector &b) -{ - for (int i = 0; i < names.size(); i++) - { - int offset = i * ENTRY_LENGTH; - std::string stringBuffer = ""; - auto nameBytes = - Util::vecCopyOfRange(b, offset, offset + AllParser::NAME_LENGTH); - - for (char c : nameBytes) - { - if (c == 0x00) - { - break; - } - stringBuffer.push_back(c); - } - names[i] = stringBuffer; - - auto usednessBytes = - Util::vecCopyOfRange(b, offset + AllParser::NAME_LENGTH, - offset + AllParser::NAME_LENGTH + 2); - usednesses[i] = usednessBytes[0] != 0 || usednessBytes[1] != 0; - } -} - -SequenceNames::SequenceNames(Mpc &mpc) -{ - saveBytes = std::vector(LENGTH); - auto sequencer = mpc.getSequencer(); - - for (int i = 0; i < 99; i++) - { - auto seq = sequencer->getSequence(i); - auto name = seq->getName(); - auto offset = i * ENTRY_LENGTH; - - for (auto j = 0; j < AllParser::NAME_LENGTH; j++) - { - saveBytes[offset + j] = StrUtil::padRight(name, " ", 16)[j]; - } - - if (name.find("(Unused)") == std::string::npos) - { - auto eventSegmentCount = getSegmentCount(seq.get()); - - if ((eventSegmentCount & 1) != 0) - { - eventSegmentCount--; - } - - auto lastEventIndex = 641 + eventSegmentCount / 2; - - if (lastEventIndex < 641) - { - lastEventIndex = 641; - } - - auto eventCountBytes = ByteUtil::ushort2bytes(lastEventIndex); - saveBytes[offset + LAST_EVENT_INDEX_OFFSET] = eventCountBytes[0]; - saveBytes[offset + LAST_EVENT_INDEX_OFFSET + 1] = - eventCountBytes[1]; - } - } -} - -std::vector &SequenceNames::getNames() -{ - return names; -} - -std::vector &SequenceNames::getUsednesses() -{ - return usednesses; -} - -std::vector &SequenceNames::getBytes() -{ - return saveBytes; -} - -int SequenceNames::getSegmentCount(sequencer::Sequence *seq) -{ - auto segmentCount = 0; - for (auto &track : seq->getTracks()) - { - if (track->getIndex() > 63) - { - break; - } - - for (auto &e : track->getEvents()) - { - auto sysEx = - std::dynamic_pointer_cast(e); - - if (sysEx) - { - constexpr int dataSegments = 1; - segmentCount += dataSegments + 1; - } - else if (std::dynamic_pointer_cast(e)) - { - segmentCount += 2; - } - else - { - segmentCount++; - } - } - } - - return segmentCount; -} diff --git a/src/main/file/all/SequenceNames.hpp b/src/main/file/all/SequenceNames.hpp deleted file mode 100644 index be274f11..00000000 --- a/src/main/file/all/SequenceNames.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::sequencer -{ - class Sequence; -} - -namespace mpc::file::all -{ - class SequenceNames - { - - public: - static const int LENGTH = 1782; - static const int ENTRY_LENGTH = 18; - static const int LAST_EVENT_INDEX_OFFSET = 16; - std::vector names = std::vector(99); - std::vector usednesses = std::vector(99); - std::vector saveBytes; - - std::vector &getNames(); - std::vector &getUsednesses(); - - std::vector &getBytes(); - static int getSegmentCount(sequencer::Sequence *seq); - - SequenceNames(const std::vector &b); - SequenceNames(Mpc &mpc); - }; -} // namespace mpc::file::all diff --git a/src/main/file/all/Tracks.cpp b/src/main/file/all/Tracks.cpp deleted file mode 100644 index f46faf10..00000000 --- a/src/main/file/all/Tracks.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "file/all/Tracks.hpp" - -#include "file/all/AllParser.hpp" -#include "file/all/AllSequence.hpp" -#include "sequencer/Sequence.hpp" -#include "sequencer/Track.hpp" - -#include "file/ByteUtil.hpp" -#include "StrUtil.hpp" -#include "Util.hpp" - -using namespace mpc::file::all; - -Tracks::Tracks(const std::vector &loadBytes) -{ - for (int i = 0; i < 64; i++) - { - devices[i] = loadBytes[DEVICES_OFFSET + i]; - busses[i] = loadBytes[BUSSES_OFFSET + i]; - pgms[i] = loadBytes[PGMS_OFFSET + i]; - veloRatios[i] = loadBytes[VELO_RATIOS_OFFSET + i]; - const auto offset = TRACK_NAMES_OFFSET + i * AllParser::NAME_LENGTH; - std::string name; - - for (const char c : Util::vecCopyOfRange( - loadBytes, offset, offset + AllParser::NAME_LENGTH)) - { - if (c == 0x00) - { - break; - } - name.push_back(c); - } - - names[i] = name; - - const auto statusByte = loadBytes[STATUS_OFFSET + i]; - - usednesses[i] = (statusByte >> 0) & 1; - ons[i] = (statusByte >> 1) & 1; - transmitProgramChangesEnableds[i] = (statusByte >> 2) & 1; - } -} - -Tracks::Tracks(sequencer::Sequence *seq) -{ - saveBytes = std::vector(AllSequence::TRACKS_LENGTH); - for (int i = 0; i < 64; i++) - { - const auto t = seq->getTrack(i); - - for (auto j = 0; j < AllParser::NAME_LENGTH; j++) - { - const auto offset = TRACK_NAMES_OFFSET + i * AllParser::NAME_LENGTH; - auto name = - StrUtil::padRight(t->getName(), " ", AllParser::NAME_LENGTH); - saveBytes[offset + j] = name[j]; - } - - saveBytes[DEVICES_OFFSET + i] = t->getDeviceIndex(); - saveBytes[BUSSES_OFFSET + i] = busTypeToIndex(t->getBusType()); - saveBytes[PGMS_OFFSET + i] = t->getProgramChange(); - saveBytes[VELO_RATIOS_OFFSET + i] = t->getVelocityRatio(); - - uint8_t b = 0; - if (t->isUsed()) - { - b |= 1u << 0; - } - if (t->isOn()) - { - b |= 1u << 1; - } - if (t->isTransmitProgramChangesEnabled()) - { - b |= 1u << 2; - } - saveBytes[STATUS_OFFSET + i] = b; - } - - for (int i = 0; i < PADDING1.size(); i++) - { - saveBytes[PADDING1_OFFSET + i] = PADDING1[i]; - } - - const auto lastTick = seq->getLastTick(); - const auto remainder = lastTick % 65535; - const auto large = static_cast(floor(lastTick / 65536.0)); - const auto lastTickBytes = ByteUtil::ushort2bytes(remainder); - saveBytes[LAST_TICK_BYTE1_OFFSET] = lastTickBytes[0]; - saveBytes[LAST_TICK_BYTE2_OFFSET] = lastTickBytes[1]; - saveBytes[LAST_TICK_BYTE3_OFFSET] = large; - - const auto unknown32BitIntBytes1 = ByteUtil::uint2bytes(10000000); - const auto unknown32BitIntBytes2 = ByteUtil::uint2bytes( - static_cast(seq->getLastTick() * 5208.333333333333)); - - for (int j = 0; j < 4; j++) - { - const int offset = UNKNOWN32_BIT_INT_OFFSET + j; - saveBytes[offset] = unknown32BitIntBytes1[j]; - } - - for (int j = 0; j < 4; j++) - { - saveBytes[UNKNOWN32_BIT_INT_OFFSET + j + 4] = unknown32BitIntBytes2[j]; - } -} - -std::vector Tracks::PADDING1 = std::vector{ - static_cast(232), 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - static_cast(232), 3}; - -int Tracks::getDeviceIndex(const int i) const -{ - return devices[i]; -} - -int Tracks::getBus(const int i) const -{ - return busses[i]; -} - -int Tracks::getVelo(const int i) const -{ - return veloRatios[i]; -} - -int Tracks::getPgm(const int i) const -{ - return pgms[i]; -} - -std::string Tracks::getName(const int i) -{ - return names[i]; -} - -bool Tracks::isUsed(const int i) const -{ - return usednesses[i]; -} - -bool Tracks::isOn(const int i) const -{ - return ons[i]; -} - -bool Tracks::isTransmitProgramChangesEnabled(const int i) -{ - return transmitProgramChangesEnableds[i]; -} - -std::vector &Tracks::getBytes() -{ - return saveBytes; -} diff --git a/src/main/file/all/Tracks.hpp b/src/main/file/all/Tracks.hpp deleted file mode 100644 index 38cf51f5..00000000 --- a/src/main/file/all/Tracks.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::sequencer -{ - class Sequence; -} - -namespace mpc::file::all -{ - class Tracks - { - - static const int TRACK_NAMES_OFFSET{0}; - static const int DEVICES_OFFSET{1024}; - static const int BUSSES_OFFSET{1088}; - static const int PGMS_OFFSET{1152}; - static const int VELO_RATIOS_OFFSET{1216}; - static const int STATUS_OFFSET{1280}; - static const int PADDING1_OFFSET{1408}; - static std::vector PADDING1; - static const int LAST_TICK_BYTE1_OFFSET{1424}; - static const int LAST_TICK_BYTE2_OFFSET{1425}; - static const int LAST_TICK_BYTE3_OFFSET{1426}; - static const int UNKNOWN32_BIT_INT_OFFSET{1428}; - std::vector busses = std::vector(64); - std::vector devices = std::vector(64); - std::vector veloRatios = std::vector(64); - std::vector pgms = std::vector(64); - std::vector names = std::vector(64); - std::vector usednesses = std::vector(64); - std::vector ons = std::vector(64); - std::vector transmitProgramChangesEnableds = - std::vector(64); - - public: - std::vector saveBytes{}; - - int getDeviceIndex(int i) const; - int getBus(int i) const; - int getVelo(int i) const; - int getPgm(int i) const; - std::string getName(int i); - bool isUsed(int i) const; - bool isOn(int i) const; - bool isTransmitProgramChangesEnabled(int i); - - std::vector &getBytes(); - - explicit Tracks(const std::vector &loadBytes); - explicit Tracks(sequencer::Sequence *seq); - }; -} // namespace mpc::file::all diff --git a/src/main/file/kaitai/AllIo.cpp b/src/main/file/kaitai/AllIo.cpp index 1b32a6d0..946ef626 100644 --- a/src/main/file/kaitai/AllIo.cpp +++ b/src/main/file/kaitai/AllIo.cpp @@ -1,36 +1,972 @@ #include "file/kaitai/AllIo.hpp" #include "Mpc.hpp" +#include "controller/ClientEventController.hpp" +#include "controller/ClientMidiEventController.hpp" +#include "controller/ClientMidiFootswitchAssignmentController.hpp" +#include "controller/MidiFootswitchFunctionMap.hpp" #include "disk/AllLoader.hpp" #include "disk/MpcFile.hpp" -#include "file/all/AllParser.hpp" -#include "file/all/AllSequence.hpp" -#include "file/all/SequenceNames.hpp" #include "file/kaitai/KaitaiIoUtil.hpp" #include "file/kaitai/generated/mpc2000xl_all.h" +#include "input/midi/MidiControlTargetBinding.hpp" +#include "lcdgui/screens/OthersScreen.hpp" +#include "lcdgui/screens/SecondSeqScreen.hpp" +#include "lcdgui/screens/SongScreen.hpp" +#include "lcdgui/screens/SyncScreen.hpp" +#include "lcdgui/screens/UserScreen.hpp" +#include "lcdgui/screens/dialog/MetronomeSoundScreen.hpp" +#include "lcdgui/screens/window/CountMetronomeScreen.hpp" +#include "lcdgui/screens/window/IgnoreTempoChangeScreen.hpp" +#include "lcdgui/screens/window/LocateScreen.hpp" +#include "lcdgui/screens/window/MidiInputScreen.hpp" +#include "lcdgui/screens/window/MidiOutputScreen.hpp" +#include "lcdgui/screens/window/MultiRecordingSetupScreen.hpp" +#include "lcdgui/screens/window/StepEditOptionsScreen.hpp" +#include "lcdgui/screens/window/TimeDisplayScreen.hpp" +#include "lcdgui/screens/window/TimingCorrectScreen.hpp" +#include "sequencer/EventRef.hpp" +#include "sequencer/EventType.hpp" +#include "sequencer/Sequence.hpp" #include "sequencer/Sequencer.hpp" +#include "sequencer/Song.hpp" +#include "sequencer/Track.hpp" +#include "sequencer/Transport.hpp" + +#include + +#include +#include +#include +#include +#include using namespace mpc::file::kaitai; +namespace { + +using all_t = mpc2000xl_all_t; +constexpr size_t kVisibleNameLength = 16; +constexpr size_t kSongStepCount = 250; +constexpr size_t kMultiRecTrackCount = 34; +constexpr size_t kSequenceCount = 99; +constexpr size_t kSongCount = 20; +constexpr char kAllUnknown10[] = {0, 12, 0, 0, 0, 0, 0, 0, 0, 0}; +constexpr size_t kSequenceHeaderLength = 10240; +constexpr size_t kSequenceTrackChunkLength = 1764; +constexpr size_t kSequenceBarChunkOffset = 5379; +constexpr size_t kSequenceBarChunkLength = 3996; +constexpr size_t kSequenceEventsOffset = 10240; +constexpr size_t kSequenceEventSegmentLength = 8; +constexpr char kSequencePadding1[] = {1, 1, 0}; +constexpr char kSequencePadding2[] = {4, 4}; +constexpr char kSequenceTrackPadding[] = { + static_cast(232), 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static_cast(232), 3 +}; +constexpr char kSequencePadding4[] = {40, 0, static_cast(128), 0, 0}; +constexpr char kSequenceTerminator[] = { + static_cast(0xFF), static_cast(0xFF), static_cast(0xFF), static_cast(0xFF), + static_cast(0xFF), static_cast(0xFF), static_cast(0xFF), static_cast(0xFF) +}; +constexpr char kDefaultsUnknown1[] = {1, 0, 0, 1, 1, 0}; +constexpr char kDefaultsUnknown2[] = { + 0, 0, static_cast(0xFF), static_cast(0xFF), 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32, 32 +}; + +std::vector slice(const std::vector& bytes, const size_t offset, const size_t length) +{ + return std::vector(bytes.begin() + static_cast(offset), + bytes.begin() + static_cast(offset + length)); +} + +template +std::unique_ptr parseSection(const std::vector& bytes, all_t& root) +{ + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream parseIo(&parseStream); + auto parsed = std::make_unique(&parseIo, &root, &root); + parsed->_read(); + return parsed; +} + +template +std::vector writeStruct(T& value) +{ + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + ::kaitai::kstream writeIo(&writeStream); + value._set_io(&writeIo); + value._check(); + value._write(); + + const auto written = writeStream.str(); + return std::vector(written.begin(), written.end()); +} + +std::string padRight(const std::string& value, const size_t width, const char fill = ' ') +{ + if (value.size() >= width) + { + return value.substr(0, width); + } + return value + std::string(width - value.size(), fill); +} + +std::unique_ptr makeDefaults(mpc::Mpc& mpc, all_t& root) +{ + constexpr size_t kDefaultsLength = 1792; + constexpr size_t kDefaultSeqNameOffset = 0; + constexpr size_t kDefaultsUnknown1Offset = 16; + constexpr size_t kTempoOffset = 22; + constexpr size_t kNumeratorOffset = 24; + constexpr size_t kDenominatorOffset = 25; + constexpr size_t kBarCountOffset = 26; + constexpr size_t kTickCountOffset = 28; + constexpr size_t kUnknownNumberOffset = 32; + constexpr size_t kDefaultsUnknown2Offset = 48; + constexpr size_t kLoopEnabledOffset = 52; + constexpr size_t kDeviceNamesOffset = 120; + constexpr size_t kTrackNamesOffset = 384; + constexpr size_t kDevicesOffset = 1408; + constexpr size_t kBusesOffset = 1472; + constexpr size_t kProgramsOffset = 1536; + constexpr size_t kTrackVelocitiesOffset = 1600; + constexpr size_t kTrackStatusesOffset = 1664; + constexpr size_t kDefaultDeviceNameLength = 8; + + auto bytes = std::vector(kDefaultsLength, char{0}); + const auto sequencer = mpc.getSequencer(); + const auto userScreen = mpc.screens->get(); + + const auto sequenceName = padRight(sequencer->getDefaultSequenceName(), kVisibleNameLength); + std::copy(sequenceName.begin(), sequenceName.end(), bytes.begin() + static_cast(kDefaultSeqNameOffset)); + + std::copy(std::begin(kDefaultsUnknown1), std::end(kDefaultsUnknown1), bytes.begin() + static_cast(kDefaultsUnknown1Offset)); + + const auto tempo = static_cast(userScreen->getTempo() * 10.0); + bytes[kTempoOffset] = static_cast(tempo & 0xFF); + bytes[kTempoOffset + 1] = static_cast((tempo >> 8) & 0xFF); + bytes[kNumeratorOffset] = static_cast(userScreen->getTimeSig().numerator); + bytes[kDenominatorOffset] = static_cast(userScreen->getTimeSig().denominator); + + const auto barCount = static_cast(userScreen->getLastBar() + 1); + bytes[kBarCountOffset] = static_cast(barCount & 0xFF); + bytes[kBarCountOffset + 1] = static_cast((barCount >> 8) & 0xFF); + + auto lastBar = userScreen->getLastBar(); + uint16_t tickCount = static_cast((lastBar + 1) * 384); + if (lastBar == 1) + { + tickCount = 0; + lastBar = 0; + } + bytes[kTickCountOffset] = static_cast(tickCount & 0xFF); + bytes[kTickCountOffset + 1] = static_cast((tickCount >> 8) & 0xFF); + + const auto unknownNumber = static_cast((lastBar + 1) * 2000000); + for (int i = 0; i < 4; ++i) + { + bytes[kUnknownNumberOffset + i * 4] = static_cast(unknownNumber & 0xFF); + bytes[kUnknownNumberOffset + i * 4 + 1] = static_cast((unknownNumber >> 8) & 0xFF); + bytes[kUnknownNumberOffset + i * 4 + 2] = static_cast((unknownNumber >> 16) & 0xFF); + bytes[kUnknownNumberOffset + i * 4 + 3] = static_cast((unknownNumber >> 24) & 0xFF); + } + + std::copy(std::begin(kDefaultsUnknown2), std::end(kDefaultsUnknown2), bytes.begin() + static_cast(kDefaultsUnknown2Offset)); + bytes[kLoopEnabledOffset] = static_cast(userScreen->isLoopEnabled() ? 0x01 : 0x00); + + for (int i = 0; i < 33; ++i) + { + const auto deviceName = i == 0 + ? std::string(kDefaultDeviceNameLength, ' ') + : std::string("Device") + (i < 10 ? std::string("0") : std::string()) + std::to_string(i); + std::copy( + deviceName.begin(), + deviceName.end(), + bytes.begin() + static_cast(kDeviceNamesOffset + i * kDefaultDeviceNameLength) + ); + } + + for (int i = 0; i < 64; ++i) + { + const auto trackName = padRight(sequencer->getDefaultTrackName(i), kVisibleNameLength); + std::copy( + trackName.begin(), + trackName.end(), + bytes.begin() + static_cast(kTrackNamesOffset + i * kVisibleNameLength) + ); + bytes[kDevicesOffset + i] = static_cast(userScreen->getDevice()); + bytes[kBusesOffset + i] = static_cast(mpc::sequencer::busTypeToIndex(userScreen->getBusType())); + bytes[kProgramsOffset + i] = static_cast(userScreen->getPgm()); + bytes[kTrackVelocitiesOffset + i] = static_cast(userScreen->getVelo()); + bytes[kTrackStatusesOffset + i] = static_cast(userScreen->getTrackStatus()); + } + + return parseSection(bytes, root); +} + +std::unique_ptr makeSequencer(mpc::Mpc& mpc, all_t& root) +{ + auto sequencer = std::make_unique(nullptr, &root, &root); + const auto mpcSequencer = mpc.getSequencer(); + const auto transport = mpcSequencer->getTransport(); + auto timingCorrectScreen = mpc.screens->get(); + auto timeDisplayScreen = mpc.screens->get(); + auto secondSeqScreen = mpc.screens->get(); + + sequencer->set_active_sequence(mpcSequencer->getSelectedSequenceIndex()); + sequencer->set__unnamed1(std::string(1, char{0})); + sequencer->set_active_track(mpcSequencer->getSelectedTrackIndex()); + sequencer->set__unnamed3(std::string(1, char{0})); + sequencer->set_master_tempo(static_cast(transport->getMasterTempo() * 10.0)); + sequencer->set_tempo_source_is_sequence(transport->isTempoSourceSequence()); + sequencer->set__unnamed6(0); + sequencer->set_timing_correct(static_cast(timingCorrectScreen->getNoteValue())); + sequencer->set_time_display_style(static_cast(timeDisplayScreen->getDisplayStyle())); + sequencer->set__unnamed9(0); + sequencer->set_second_sequence_enabled(mpcSequencer->isSecondSequenceEnabled()); + sequencer->set__unnamed11(0); + sequencer->set_sequence_sequence_index(secondSeqScreen->getSq()); + return sequencer; +} + +std::unique_ptr makeCount(mpc::Mpc& mpc, all_t& root) +{ + auto count = std::make_unique(nullptr, &root, &root); + const auto transport = mpc.getSequencer()->getTransport(); + auto countMetronomeScreen = mpc.screens->get(); + auto metronomeSoundScreen = mpc.screens->get(); + + count->set_enabled(transport->isCountEnabled()); + count->set__unnamed1(0); + count->set_count_in_mode(static_cast(countMetronomeScreen->getCountInMode())); + count->set_click_volume(static_cast(metronomeSoundScreen->getVolume())); + count->set_rate(static_cast(countMetronomeScreen->getRate())); + count->set_enabled_in_play(countMetronomeScreen->getInPlay()); + count->set__unnamed6(0); + count->set_enabled_in_rec(countMetronomeScreen->getInRec()); + count->set__unnamed8(0); + count->set_click_output(static_cast(metronomeSoundScreen->getOutput())); + count->set_wait_for_key(countMetronomeScreen->isWaitForKeyEnabled()); + count->set__unnamed11(0); + count->set_sound_source(static_cast(metronomeSoundScreen->getSound())); + count->set_accent_pad_index(static_cast(metronomeSoundScreen->getAccentPad())); + count->set_normal_pad_index(static_cast(metronomeSoundScreen->getNormalPad())); + count->set_accent_velo(static_cast(metronomeSoundScreen->getAccentVelo())); + count->set_normal_velo(static_cast(metronomeSoundScreen->getNormalVelo())); + return count; +} + +std::unique_ptr makeMidiOutput(mpc::Mpc& mpc, all_t& root) +{ + auto midiOutput = std::make_unique(nullptr, &root, &root); + auto midiOutputScreen = mpc.screens->get(); + midiOutput->set_soft_thru_mode(static_cast(midiOutputScreen->getSoftThru())); + return midiOutput; +} + +std::unique_ptr makeMidiInput(mpc::Mpc& mpc, all_t& root) +{ + auto midiInput = std::make_unique(nullptr, &root, &root); + auto midiInputScreen = mpc.screens->get(); + auto multiRecordingSetupScreen = mpc.screens->get(); + + midiInput->set_receive_channel(static_cast(midiInputScreen->getReceiveCh() + 1)); + midiInput->set_sustain_pedal_to_duration(midiInputScreen->isSustainPedalToDurationEnabled()); + midiInput->set__unnamed2(0); + midiInput->set_filter_enabled(midiInputScreen->isMidiFilterEnabled()); + midiInput->set__unnamed4(0); + midiInput->set_filter_type(static_cast(midiInputScreen->getType())); + midiInput->set_multi_rec_enabled(mpc.getSequencer()->isRecordingModeMulti()); + midiInput->set__unnamed7(0); + + auto multiRecTracks = std::make_unique>(); + multiRecTracks->reserve(kMultiRecTrackCount); + for (auto* line : multiRecordingSetupScreen->getMrsLines()) + { + multiRecTracks->push_back(static_cast(line->getTrack() + 1)); + } + midiInput->set_multi_rec_destination_tracks(std::move(multiRecTracks)); + + midiInput->set_note_pass_enabled(midiInputScreen->isNotePassEnabled()); + midiInput->set__unnamed10(0); + midiInput->set_pitch_bend_pass_enabled(midiInputScreen->isPitchBendPassEnabled()); + midiInput->set__unnamed12(0); + midiInput->set_pgm_change_pass_enabled(midiInputScreen->isPgmChangePassEnabled()); + midiInput->set__unnamed14(0); + midiInput->set_ch_pressure_pass_enabled(midiInputScreen->isChPressurePassEnabled()); + midiInput->set__unnamed16(0); + midiInput->set_poly_pressure_pass_enabled(midiInputScreen->isPolyPressurePassEnabled()); + midiInput->set__unnamed18(0); + midiInput->set_exclusive_pass_enabled(midiInputScreen->isExclusivePassEnabled()); + midiInput->set__unnamed20(0); + + auto ccPass = std::make_unique>(midiInputScreen->getCcPassEnabled()); + midiInput->set_cc_pass_enabled(std::move(ccPass)); + return midiInput; +} + +std::unique_ptr makeMidiSync(mpc::Mpc& mpc, all_t& root) +{ + auto midiSync = std::make_unique(nullptr, &root, &root); + auto syncScreen = mpc.screens->get(); + midiSync->set_in_mode(static_cast(syncScreen->getModeIn())); + midiSync->set_out_mode(static_cast(syncScreen->getModeOut())); + midiSync->set_shift_early(static_cast(syncScreen->getShiftEarly())); + midiSync->set_send_mmc_enabled(syncScreen->isSendMMCEnabled()); + midiSync->set__unnamed4(0); + midiSync->set_frame_rate(static_cast(syncScreen->getFrameRate())); + midiSync->set_input(static_cast(syncScreen->getInput())); + midiSync->set_output(static_cast(syncScreen->getOut())); + return midiSync; +} + +std::unique_ptr makeSongGlobal(mpc::Mpc& mpc, all_t& root) +{ + auto songGlobal = std::make_unique(nullptr, &root, &root); + auto songScreen = mpc.screens->get(); + auto ignoreTempoChangeScreen = mpc.screens->get(); + songGlobal->set_default_song_name(padRight(songScreen->getDefaultSongName(), 16)); + songGlobal->set_ignore_tempo_change_events_in_sequence(ignoreTempoChangeScreen->getIgnore()); + songGlobal->set__unnamed2(0); + return songGlobal; +} + +std::unique_ptr>> makeLocations(mpc::Mpc& mpc, all_t& root) +{ + auto locateScreen = mpc.screens->get(); + auto result = std::make_unique>>(); + result->reserve(locateScreen->getLocations().size()); + + for (const auto& location : locateScreen->getLocations()) + { + auto parsedLocation = std::make_unique(nullptr, &root, &root); + parsedLocation->set_bar(std::get<0>(location)); + parsedLocation->set_beat(std::get<1>(location)); + parsedLocation->set_clock(std::get<2>(location)); + result->push_back(std::move(parsedLocation)); + } + + return result; +} + +std::unique_ptr makeMisc(mpc::Mpc& mpc, all_t& root) +{ + auto misc = std::make_unique(nullptr, &root, &root); + auto othersScreen = mpc.screens->get(); + auto syncScreen = mpc.screens->get(); + auto footswitchController = + mpc.clientEventController->getClientMidiEventController() + ->getFootswitchAssignmentController(); + + misc->set_tap_averaging(static_cast(othersScreen->getTapAveraging() - 2)); + misc->set_midi_sync_in_receive_mmc_enabled(syncScreen->isReceiveMMCEnabled()); + + auto midiSwitches = std::make_unique>>(); + midiSwitches->reserve(footswitchController->bindings.size()); + for (const auto& bindingVariant : footswitchController->bindings) + { + auto midiSwitch = std::make_unique(nullptr, misc.get(), &root); + std::visit( + [&](const auto& binding) + { + midiSwitch->set_controller(static_cast(binding.number < 0 ? 0xFF : binding.number)); + if constexpr (std::is_same_v, mpc::input::midi::HardwareBinding>) + { + const auto fn = mpc::controller::componentIdToFootswitch(binding.target.componentId).value(); + midiSwitch->set_function(static_cast(fn)); + } + else + { + const auto fn = mpc::controller::sequencerCmdToFootswitch(binding.target.command).value(); + midiSwitch->set_function(static_cast(fn)); + } + }, + bindingVariant + ); + midiSwitches->push_back(std::move(midiSwitch)); + } + misc->set_midi_switch(std::move(midiSwitches)); + return misc; +} + +std::unique_ptr makeStepEditOptions(mpc::Mpc& mpc, all_t& root) +{ + auto stepEditOptions = std::make_unique(nullptr, &root, &root); + auto screen = mpc.screens->get(); + stepEditOptions->set_auto_step_increment(screen->isAutoStepIncrementEnabled()); + stepEditOptions->set_duration_of_recorded_notes( + screen->isDurationOfRecordedNotesTcValue() + ? all_t::DURATION_OF_RECORDED_NOTES_TC_VALUE + : all_t::DURATION_OF_RECORDED_NOTES_AS_PLAYED + ); + stepEditOptions->set_tc_value_percentage(static_cast(screen->getTcValuePercentage())); + return stepEditOptions; +} + +std::unique_ptr>> makeSequenceMetas(mpc::Mpc& mpc, all_t& root) +{ + auto result = std::make_unique>>(); + const auto sequencer = mpc.getSequencer(); + result->reserve(kSequenceCount); + + for (size_t i = 0; i < kSequenceCount; ++i) + { + auto meta = std::make_unique(nullptr, &root, &root); + const auto seq = sequencer->getSequence(static_cast(i)); + meta->set_name(padRight(seq->getName(), kVisibleNameLength)); + meta->set_is_used(seq->isUsed() ? all_t::SEQUENCE_IS_USED_TRUE : all_t::SEQUENCE_IS_USED_FALSE); + result->push_back(std::move(meta)); + } + + return result; +} + +std::unique_ptr makeSongStep(uint8_t sequenceIndex, uint8_t repeatCount, all_t::song_t* parent, all_t& root) +{ + auto step = std::make_unique(nullptr, parent, &root); + step->set_sequence_index(sequenceIndex); + step->set_repeat_count(repeatCount); + return step; +} + +std::unique_ptr>> makeSongs(mpc::Mpc& mpc, all_t& root) +{ + auto result = std::make_unique>>(); + auto sequencer = mpc.getSequencer(); + result->reserve(kSongCount); + + for (size_t i = 0; i < kSongCount; ++i) + { + auto song = std::make_unique(nullptr, &root, &root); + const auto mpcSong = sequencer->getSong(static_cast(i)); + song->set_name(padRight(mpcSong->getName(), kVisibleNameLength)); + + auto steps = std::make_unique>>(); + steps->reserve(kSongStepCount); + for (size_t stepIndex = 0; stepIndex < kSongStepCount; ++stepIndex) + { + if (stepIndex < mpcSong->getStepCount()) + { + const auto stepState = mpcSong->getStep(mpc::SongStepIndex(static_cast(stepIndex))); + steps->push_back(makeSongStep(stepState.sequenceIndex, stepState.repetitionCount, song.get(), root)); + } + else + { + steps->push_back(makeSongStep(0xFF, 0xFF, song.get(), root)); + } + } + song->set_steps(std::move(steps)); + song->set__unnamed2(std::string(2, static_cast(0xFF))); + song->set_is_used(mpcSong->isUsed()); + song->set_loop_first_step(static_cast(mpcSong->getFirstLoopStepIndex())); + song->set_loop_last_step(static_cast(mpcSong->getLastLoopStepIndex())); + song->set_is_loop_enabled(mpcSong->isLoopEnabled()); + song->set__unnamed7(std::string(6, char{0})); + result->push_back(std::move(song)); + } + + return result; +} + +int countSequenceEventSegments(mpc::sequencer::Sequence& seq) +{ + int segmentCount = 0; + for (const auto& track : seq.getTracks()) + { + if (track->getIndex() > 63) + { + break; + } + + for (const auto& event : track->getEvents()) + { + switch (event->handle->type) + { + case mpc::sequencer::EventType::SystemExclusive: + segmentCount += 3; + break; + case mpc::sequencer::EventType::Mixer: + segmentCount += 4; + break; + default: + segmentCount += 1; + break; + } + } + } + return segmentCount; +} + +std::vector makeTrackChunk(mpc::sequencer::Sequence& seq) +{ + std::vector bytes(kSequenceTrackChunkLength, char{0}); + for (int i = 0; i < 64; ++i) + { + const auto track = seq.getTrack(i); + const auto trackName = padRight(track->getName(), kVisibleNameLength); + std::copy(trackName.begin(), trackName.end(), bytes.begin() + i * kVisibleNameLength); + bytes[1024 + i] = static_cast(track->getDeviceIndex()); + bytes[1088 + i] = static_cast(mpc::sequencer::busTypeToIndex(track->getBusType())); + bytes[1152 + i] = static_cast(track->getProgramChange()); + bytes[1216 + i] = static_cast(track->getVelocityRatio()); + + uint8_t status = 0; + if (track->isUsed()) + { + status |= 1u << 0; + } + if (track->isOn()) + { + status |= 1u << 1; + } + if (track->isTransmitProgramChangesEnabled()) + { + status |= 1u << 2; + } + bytes[1280 + i] = static_cast(status); + } + + std::copy(std::begin(kSequenceTrackPadding), std::end(kSequenceTrackPadding), bytes.begin() + 1408); + + const auto lastTick = static_cast(seq.getLastTick()); + const auto remainder = static_cast(lastTick % 65535); + const auto large = static_cast(std::floor(lastTick / 65536.0)); + bytes[1424] = static_cast(remainder & 0xFF); + bytes[1425] = static_cast((remainder >> 8) & 0xFF); + bytes[1426] = static_cast(large); + + const auto unknown1 = static_cast(10000000); + const auto unknown2 = static_cast(seq.getLastTick() * 5208.333333333333); + bytes[1428] = static_cast(unknown1 & 0xFF); + bytes[1429] = static_cast((unknown1 >> 8) & 0xFF); + bytes[1430] = static_cast((unknown1 >> 16) & 0xFF); + bytes[1431] = static_cast((unknown1 >> 24) & 0xFF); + bytes[1432] = static_cast(unknown2 & 0xFF); + bytes[1433] = static_cast((unknown2 >> 8) & 0xFF); + bytes[1434] = static_cast((unknown2 >> 16) & 0xFF); + bytes[1435] = static_cast((unknown2 >> 24) & 0xFF); + return bytes; +} + +std::vector makeBarChunk(mpc::sequencer::Sequence& seq) +{ + std::vector bytes(kSequenceBarChunkLength, char{0}); + int ticksPerBeat = 0; + int lastTick = 0; + + for (int i = 0; i < seq.getLastBarIndex() + 1; ++i) + { + const auto barLength = seq.getBarLength(i); + lastTick += barLength; + ticksPerBeat = barLength / seq.getNumerator(i); + bytes[i * 4] = static_cast(ticksPerBeat); + bytes[i * 4 + 1] = static_cast(lastTick & 0xFF); + bytes[i * 4 + 2] = static_cast((lastTick >> 8) & 0xFF); + bytes[i * 4 + 3] = static_cast((lastTick >> 16) & 0xFF); + } + + const auto terminatorOffset = static_cast((seq.getLastBarIndex() + 1) * 4); + bytes[terminatorOffset] = static_cast(ticksPerBeat); + return bytes; +} + + +std::unique_ptr makeTerminatorEvent() +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + event->set_tick(0xFFFFF); + event->set_terminator_pad(0xF); + event->set_terminator(std::string(5, static_cast(0xFF))); + return event; +} + +std::unique_ptr makeNoteEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + const auto duration = static_cast(state.duration); + event->set_tick(state.tick); + event->set_duration_bits_1((duration >> 10) & 0x0F); + event->set_track(trackIndex); + event->set_duration_bits_2((duration >> 8) & 0x03); + event->set_id(state.noteNumber); + + auto note = std::make_unique(nullptr, event.get(), nullptr); + note->set_duration_bits_3(duration & 0xFF); + note->set_velocity(state.velocity); + note->set_variation_type_bit_1( + state.noteVariationType == mpc::NoteVariationTypeAttack || state.noteVariationType == mpc::NoteVariationTypeFilter + ); + note->set_variation_value(state.noteVariationValue); + note->set_variation_type_bit_2( + state.noteVariationType == mpc::NoteVariationTypeDecay || state.noteVariationType == mpc::NoteVariationTypeFilter + ); + event->set_note_event(std::move(note)); + return event; +} + +std::unique_ptr makePitchBendEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + event->set_tick(state.tick); + event->set_duration_bits_1(0); + event->set_track(trackIndex); + event->set_duration_bits_2(0); + event->set_id(0xE0); + + auto pitchBend = std::make_unique(nullptr, event.get(), nullptr); + uint16_t candidate = static_cast(state.amount + 16384); + if (state.amount < 0) + { + candidate = static_cast(state.amount + 8192); + } + pitchBend->set_amount_bits_1(candidate & 0xFF); + pitchBend->set_amount_bits_2((candidate >> 8) & 0xFF); + pitchBend->set__unnamed2(std::string(1, char{0})); + event->set_pitch_bend(std::move(pitchBend)); + return event; +} + +std::unique_ptr makeControlChangeEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + event->set_tick(state.tick); + event->set_duration_bits_1(0); + event->set_track(trackIndex); + event->set_duration_bits_2(0); + event->set_id(0xB0); + + auto controlChange = std::make_unique(nullptr, event.get(), nullptr); + controlChange->set_controller(static_cast(state.controllerNumber)); + controlChange->set_value(state.controllerValue); + controlChange->set__unnamed2(std::string(1, char{0})); + event->set_control_change(std::move(controlChange)); + return event; +} + +std::unique_ptr makeProgramChangeEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + event->set_tick(state.tick); + event->set_duration_bits_1(0); + event->set_track(trackIndex); + event->set_duration_bits_2(0); + event->set_id(0xC0); + + auto programChange = std::make_unique(nullptr, event.get(), nullptr); + programChange->set_program(state.programChangeProgramIndex); + programChange->set__unnamed1(std::string(2, char{0})); + event->set_program_change(std::move(programChange)); + return event; +} + +std::unique_ptr makeChannelPressureEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + event->set_tick(state.tick); + event->set_duration_bits_1(0); + event->set_track(trackIndex); + event->set_duration_bits_2(0); + event->set_id(0xD0); + + auto chPressure = std::make_unique(nullptr, event.get(), nullptr); + chPressure->set_pressure(state.amount); + chPressure->set__unnamed1(std::string(2, char{0})); + event->set_ch_pressure(std::move(chPressure)); + return event; +} + +std::unique_ptr makePolyPressureEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + event->set_tick(state.tick); + event->set_duration_bits_1(0); + event->set_track(trackIndex); + event->set_duration_bits_2(0); + event->set_id(0xA0); + + auto polyPressure = std::make_unique(nullptr, event.get(), nullptr); + polyPressure->set_note(state.noteNumber); + polyPressure->set_pressure(state.amount); + polyPressure->set__unnamed2(std::string(1, char{0})); + event->set_poly_pressure(std::move(polyPressure)); + return event; +} + +std::unique_ptr makeExclusiveEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + auto event = std::make_unique(nullptr, nullptr, nullptr); + event->set_tick(state.tick); + event->set_duration_bits_1(0); + event->set_track(trackIndex); + event->set_duration_bits_2(0); + event->set_id(0xF0); + + auto exclusive = std::make_unique(nullptr, event.get(), nullptr); + if (state.type == mpc::sequencer::EventType::Mixer) + { + exclusive->set__unnamed0(std::string({9, 0, 0})); + exclusive->set_bytes(std::string({static_cast(0xF0), 0x47})); + + auto mixer = std::make_unique(nullptr, exclusive.get(), nullptr); + mixer->set__unnamed0(std::string({0, 68, 69})); + auto param = state.mixerParameter; + if (param == 3) + { + param = 4; + } + mixer->set_param(static_cast(param + 1)); + mixer->set_pad_index(state.mixerPad); + mixer->set_value(state.mixerValue); + mixer->set__unnamed4(std::string({static_cast(0xF7), 0})); + exclusive->set_mixer(std::move(mixer)); + + auto tail = std::string(14, char{0}); + tail[10] = static_cast(0xF8); + exclusive->set__unnamed3(std::move(tail)); + } + else + { + exclusive->set__unnamed0(std::string({2, 0, 0})); + exclusive->set_bytes(std::string({static_cast(state.sysExByteA), static_cast(state.sysExByteB)})); + + auto tail = std::string(14, char{0}); + tail[10] = static_cast(0xF8); + exclusive->set__unnamed3(std::move(tail)); + } + + event->set_exclusive(std::move(exclusive)); + return event; +} + +std::unique_ptr makeSequenceEvent(const mpc::sequencer::EventData& state, const uint8_t trackIndex) +{ + switch (state.type) + { + case mpc::sequencer::EventType::NoteOn: + return makeNoteEvent(state, trackIndex); + case mpc::sequencer::EventType::PitchBend: + return makePitchBendEvent(state, trackIndex); + case mpc::sequencer::EventType::ControlChange: + return makeControlChangeEvent(state, trackIndex); + case mpc::sequencer::EventType::ProgramChange: + return makeProgramChangeEvent(state, trackIndex); + case mpc::sequencer::EventType::ChannelPressure: + return makeChannelPressureEvent(state, trackIndex); + case mpc::sequencer::EventType::PolyPressure: + return makePolyPressureEvent(state, trackIndex); + case mpc::sequencer::EventType::Mixer: + case mpc::sequencer::EventType::SystemExclusive: + return makeExclusiveEvent(state, trackIndex); + default: + throw std::runtime_error("Unsupported ALL event type in Kaitai writer"); + } +} + +std::vector makeSequenceEventChunk(mpc::sequencer::Sequence& seq) +{ + std::vector chunk; + for (int tick = 0; tick < seq.getLastTick(); ++tick) + { + for (const auto& track : seq.getTracks()) + { + if (track->getIndex() > 63) + { + break; + } + + for (const auto& event : track->getEvents()) + { + if (event->getTick() != tick) + { + continue; + } + + auto kaitaiEvent = makeSequenceEvent(*event->handle, static_cast(track->getIndex())); + auto eventBytes = writeStruct(*kaitaiEvent); + chunk.insert(chunk.end(), eventBytes.begin(), eventBytes.end()); + } + } + } + + auto terminator = makeTerminatorEvent(); + auto terminatorBytes = writeStruct(*terminator); + chunk.insert(chunk.end(), terminatorBytes.begin(), terminatorBytes.end()); + return chunk; +} + +std::vector makeSequenceBytes(mpc::sequencer::Sequence& seq, int number) +{ + const auto segmentCountLastEventIndex = countSequenceEventSegments(seq); + auto segmentCount = segmentCountLastEventIndex; + const auto terminatorCount = (segmentCount & 1) == 0 ? 2 : 1; + auto bytes = std::vector( + kSequenceHeaderLength + segmentCount * kSequenceEventSegmentLength + terminatorCount * kSequenceEventSegmentLength, + char{0} + ); + + const auto sequenceName = padRight(seq.getName(), kVisibleNameLength); + std::copy(sequenceName.begin(), sequenceName.end(), bytes.begin()); + + auto lastEventSegmentIndex = segmentCountLastEventIndex; + if ((lastEventSegmentIndex & 1) != 0) + { + lastEventSegmentIndex--; + } + lastEventSegmentIndex /= 2; + const auto lastEventIndex = static_cast(1 + (lastEventSegmentIndex < 0 ? 0 : lastEventSegmentIndex)); + bytes[16] = static_cast(lastEventIndex & 0xFF); + bytes[17] = static_cast((lastEventIndex >> 8) & 0xFF); + + std::copy(std::begin(kSequencePadding1), std::end(kSequencePadding1), bytes.begin() + 19); + + const auto tempo = static_cast(seq.getInitialTempo() * 10.0); + bytes[22] = static_cast(tempo & 0xFF); + bytes[23] = static_cast((tempo >> 8) & 0xFF); + std::copy(std::begin(kSequencePadding2), std::end(kSequencePadding2), bytes.begin() + 24); + + const auto barCount = static_cast(seq.getLastBarIndex() + 1); + bytes[26] = static_cast(barCount & 0xFF); + bytes[27] = static_cast((barCount >> 8) & 0xFF); + + const auto lastTick = static_cast(seq.getLastTick()); + const auto lastTickRemainder = static_cast(lastTick % 65536); + const auto lastTickHigh = static_cast(lastTick / 65536); + bytes[28] = static_cast(lastTickRemainder & 0xFF); + bytes[29] = static_cast((lastTickRemainder >> 8) & 0xFF); + bytes[30] = static_cast(lastTickHigh); + bytes[64] = static_cast(lastTickRemainder & 0xFF); + bytes[65] = static_cast((lastTickRemainder >> 8) & 0xFF); + bytes[66] = static_cast(lastTickHigh); + + bytes[18] = static_cast(number); + + const auto unknown1 = static_cast(10000000); + const auto unknown2 = static_cast(seq.getLastTick() * 5208.333333333333); + for (int i = 0; i < 2; ++i) + { + bytes[32 + i * 4] = static_cast(unknown1 & 0xFF); + bytes[33 + i * 4] = static_cast((unknown1 >> 8) & 0xFF); + bytes[34 + i * 4] = static_cast((unknown1 >> 16) & 0xFF); + bytes[35 + i * 4] = static_cast((unknown1 >> 24) & 0xFF); + } + for (int i = 2; i < 4; ++i) + { + bytes[32 + i * 4] = static_cast(unknown2 & 0xFF); + bytes[33 + i * 4] = static_cast((unknown2 >> 8) & 0xFF); + bytes[34 + i * 4] = static_cast((unknown2 >> 16) & 0xFF); + bytes[35 + i * 4] = static_cast((unknown2 >> 24) & 0xFF); + } + + const auto loopFirst = static_cast(seq.getFirstLoopBarIndex()); + auto loopLast = static_cast(seq.getLastLoopBarIndex()); + bytes[48] = static_cast(loopFirst & 0xFF); + bytes[49] = static_cast((loopFirst >> 8) & 0xFF); + if (seq.getLastLoopBarIndex() == mpc::EndOfSequence) + { + loopLast = 0xFFFF; + } + bytes[50] = static_cast(loopLast & 0xFF); + bytes[51] = static_cast((loopLast >> 8) & 0xFF); + bytes[52] = static_cast(seq.isLoopEnabled() ? 1 : 0); + + const auto& startTime = seq.getStartTime(); + bytes[53] = static_cast(startTime.hours); + bytes[54] = static_cast(startTime.minutes); + bytes[55] = static_cast(startTime.seconds); + bytes[56] = static_cast(startTime.frames); + bytes[57] = static_cast(startTime.frameDecimals); + + std::copy(std::begin(kSequencePadding4), std::end(kSequencePadding4), bytes.begin() + 59); + + for (int i = 0; i < 33; ++i) + { + const auto deviceName = i == 0 + ? std::string(8, ' ') + : padRight(seq.getDeviceName(i - 1), 8); + std::copy(deviceName.begin(), deviceName.end(), bytes.begin() + 120 + i * 8); + } + + const auto trackBytes = makeTrackChunk(seq); + std::copy(trackBytes.begin(), trackBytes.end(), bytes.begin() + 384); + + const auto barBytes = makeBarChunk(seq); + std::copy(barBytes.begin(), barBytes.end(), bytes.begin() + static_cast(kSequenceBarChunkOffset)); + + const auto eventChunk = makeSequenceEventChunk(seq); + std::copy(eventChunk.begin(), eventChunk.end(), bytes.begin() + static_cast(kSequenceEventsOffset)); + + for (size_t i = bytes.size() - 8; i < bytes.size(); ++i) + { + bytes[i] = static_cast(0xFF); + } + + return bytes; +} + +std::unique_ptr>> makeSequences(mpc::Mpc& mpc, all_t& root) +{ + auto result = std::make_unique>>(); + + auto sequencer = mpc.getSequencer(); + const auto usedSequences = sequencer->getUsedSequences(); + const auto usedSequenceIndexes = sequencer->getUsedSequenceIndexes(); + + result->reserve(usedSequences.size()); + + for (size_t i = 0; i < usedSequences.size(); ++i) + { + auto sequenceBytes = makeSequenceBytes(*usedSequences[i], usedSequenceIndexes[i] + 1); + result->push_back(parseSection(sequenceBytes, root)); + } + + return result; +} + + +std::vector writeAll(all_t& root) +{ + return writeStruct(root); +} + +} // namespace + void AllIo::loadEverything(mpc::Mpc &mpc, mpc::disk::MpcFile *file) { const auto canonicalBytes = parseRewrite(file->getBytes()); - mpc::file::all::AllParser parser(mpc, canonicalBytes); - mpc::disk::AllLoader::loadEverythingFromAllParser(mpc, parser); + mpc::disk::AllLoader::loadEverythingFromCanonicalBytes(mpc, canonicalBytes); } sequence_meta_infos_or_error AllIo::loadSequenceMetaInfos(mpc::Mpc &mpc, mpc::disk::MpcFile *file) { const auto canonicalBytes = parseRewrite(file->getBytes()); - const mpc::file::all::AllParser parser(mpc, canonicalBytes); + std::stringstream parseStream( + std::string(canonicalBytes.begin(), canonicalBytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); std::vector result; - const auto allSeqNames = parser.getSeqNames()->getNames(); - const auto allSeqUsednesses = parser.getSeqNames()->getUsednesses(); + const auto* sequenceMetas = parsed.sequences_metas(); + if (sequenceMetas == nullptr) + { + return result; + } - for (int i = 0; i < mpc::Mpc2000XlSpecs::SEQUENCE_COUNT; ++i) + for (const auto& sequenceMeta : *sequenceMetas) { - result.push_back({allSeqUsednesses[i], allSeqNames[i]}); + result.push_back( + { + sequenceMeta->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE, + sequenceMeta->name() + } + ); } return result; @@ -43,19 +979,38 @@ std::shared_ptr AllIo::loadOneSequence( mpc::SequenceIndex destIndexInMpcMemory) { const auto canonicalBytes = parseRewrite(file->getBytes()); - mpc::file::all::AllParser parser(mpc, canonicalBytes); - - const auto sequence = mpc.getSequencer()->getSequence(destIndexInMpcMemory); - parser.getAllSequences()[sourceIndexInAllFile]->applyToInMemorySequence( - sequence, - mpc.getSequencer()->getStateManager().get() + return mpc::disk::AllLoader::loadOneSequenceFromCanonicalBytes( + mpc, + canonicalBytes, + sourceIndexInAllFile, + destIndexInMpcMemory ); - - return sequence; } std::vector AllIo::save(mpc::Mpc &mpc) { - mpc::file::all::AllParser parser(mpc); - return parseRewrite(parser.getBytes()); + all_t root(nullptr); + root.set_magic("MPC2KXL ALL 1.00"); + + root.set_defaults(makeDefaults(mpc, root)); + + root.set_sequencer(makeSequencer(mpc, root)); + root.set__unnamed3(std::string(std::begin(kAllUnknown10), std::end(kAllUnknown10))); + root.set_count(makeCount(mpc, root)); + root.set_midi_output(makeMidiOutput(mpc, root)); + root.set_midi_input(makeMidiInput(mpc, root)); + root.set_midi_sync(makeMidiSync(mpc, root)); + root.set_song_global(makeSongGlobal(mpc, root)); + root.set__unnamed9(std::string(5, char{0})); + root.set_locations(makeLocations(mpc, root)); + root.set_misc(makeMisc(mpc, root)); + root.set__unnamed12(std::string(3, char{0})); + root.set_step_edit_options(makeStepEditOptions(mpc, root)); + root.set_prog_change_to_seq(mpc.screens->get()->getProgChangeSeq()); + root.set__unnamed15(std::string(78, char{0})); + root.set_sequences_metas(makeSequenceMetas(mpc, root)); + root.set_songs(makeSongs(mpc, root)); + root.set_sequences(makeSequences(mpc, root)); + + return writeAll(root); } diff --git a/src/main/file/kaitai/MidIo.cpp b/src/main/file/kaitai/MidIo.cpp index 613e3f50..aafe8ab7 100644 --- a/src/main/file/kaitai/MidIo.cpp +++ b/src/main/file/kaitai/MidIo.cpp @@ -4,11 +4,11 @@ #include "disk/MpcFile.hpp" #include "file/kaitai/KaitaiIoUtil.hpp" #include "file/kaitai/generated/standard_midi_file_with_running_status.h" -#include "file/mid/MidiReader.hpp" #include "sequencer/BusType.hpp" #include "sequencer/EventData.hpp" #include "sequencer/Sequence.hpp" #include "sequencer/Sequencer.hpp" +#include "sequencer/SequencerStateManager.hpp" #include "sequencer/TempoChangeEvent.hpp" #include "sequencer/Track.hpp" #include "sequencer/Transport.hpp" @@ -28,7 +28,7 @@ using meta_type_t = midi_t::meta_event_body_t::meta_type_enum_t; std::string asciiBody(const std::string& body) { - return kaitai::kstream::bytes_to_str(body, "ASCII"); + return body; } bool isInteger(const std::string& s) @@ -610,6 +610,373 @@ std::vector buildMpc2000xlMidiBytes(const std::shared_ptr& sequence) +{ + auto sequencer = mpc.getSequencer(); + auto transport = sequencer->getTransport(); + auto stateManager = sequencer->getStateManager(); + + sequence->setUsed(true); + + std::vector> tempoChanges; + struct TimeSigChange { int tick; int numerator; int denominator; }; + std::vector timeSignatures; + + int lengthInTicks = 0; + for (const auto& midiTrack : *parsed.tracks()) + { + int trackTick = 0; + for (const auto& eventPtr : *midiTrack->events()->event()) + { + trackTick += eventPtr->v_time()->value(); + } + lengthInTicks = std::max(lengthInTicks, trackTick); + } + + int tick = 0; + for (const auto& eventPtr : *parsed.tracks()->at(0)->events()->event()) + { + tick += eventPtr->v_time()->value(); + const auto* meta = eventPtr->meta_event_body(); + if (meta == nullptr) + { + continue; + } + + if (meta->meta_type() == meta_type_t::META_TYPE_ENUM_TEMPO) + { + tempoChanges.push_back({tick, bpmFromTempoBody(meta->body())}); + } + else if (meta->meta_type() == meta_type_t::META_TYPE_ENUM_TIME_SIGNATURE) + { + timeSignatures.push_back( + TimeSigChange{ + tick, + meta->body().empty() + ? mpc::DefaultTimeSigNumerator + : static_cast(meta->body()[0]), + denominatorFromTimeSignatureBody(meta->body()) + } + ); + } + } + + const auto initialTempo = tempoChanges.empty() ? 120.0 : tempoChanges[0].second; + sequence->setInitialTempo(initialTempo); + if (!transport->isTempoSourceSequence()) + { + transport->setTempo(initialTempo); + } + + for (size_t i = 1; i < tempoChanges.size(); ++i) + { + const auto ratio = tempoChanges[i].second / initialTempo; + sequence->addTempoChangeEvent( + tempoChanges[i].first, + static_cast(ratio * 1000.0) + ); + } + + if (timeSignatures.empty()) + { + timeSignatures.push_back( + TimeSigChange{0, mpc::DefaultTimeSigNumerator, mpc::DefaultTimeSigDenominator} + ); + } + + lengthInTicks = std::max(lengthInTicks, 1); + int accumLength = 0; + int barCounter = 0; + for (size_t i = 0; i < timeSignatures.size(); ++i) + { + const auto current = timeSignatures[i]; + const auto nextTick = + i + 1 < timeSignatures.size() ? timeSignatures[i + 1].tick : lengthInTicks; + + while (accumLength < nextTick) + { + sequence->setTimeSignature(barCounter, current.numerator, current.denominator); + const auto newDenTicks = 96 * (4.0 / current.denominator); + const auto barLength = static_cast(newDenTicks * current.numerator); + accumLength += barLength; + barCounter++; + } + } + + sequence->setLastBarIndex(barCounter - 1); + sequence->setFirstLoopBarIndex(mpc::BarIndex(-1)); + sequence->setLastLoopBarIndex(mpc::EndOfSequence); + + const auto sequenceIndex = sequence->getSequenceIndex(); + mpc::sequencer::UpdateSequenceEvents updateSequenceEvents{sequenceIndex}; + updateSequenceEvents.trackSnapshots = &stateManager->trackEventsSnapshots[sequenceIndex]; + updateSequenceEvents.trackSnapshots->clear(); + + mpc::sequencer::UpdateSequenceTracks updateSequenceTracks{sequenceIndex}; + updateSequenceTracks.trackStates = &stateManager->trackStatesSnapshots[sequenceIndex]; + *updateSequenceTracks.trackStates = mpc::sequencer::SequenceTrackStatesSnapshot(); + + const std::string trackDataPrefix = "TRACK DATA:"; + + for (size_t i = 0; i < parsed.tracks()->size() && i < 64; ++i) + { + auto resolvedTrackIndex = static_cast(i); + auto deviceIndex = 0; + auto busType = mpc::sequencer::BusType::DRUM1; + + for (const auto& eventPtr : *parsed.tracks()->at(i)->events()->event()) + { + const auto* meta = eventPtr->meta_event_body(); + if (meta == nullptr || meta->meta_type() != meta_type_t::META_TYPE_ENUM_TEXT_EVENT) + { + continue; + } + + const auto body = asciiBody(meta->body()); + if (body.rfind(trackDataPrefix, 0) != 0) + { + continue; + } + + const auto payload = body.substr(trackDataPrefix.size()); + resolvedTrackIndex = std::stoi(payload.substr(0, 2)); + + const auto deviceIndexStr = payload.substr(2, 2); + if (deviceIndexStr != "C0") + { + deviceIndex = std::stoi(deviceIndexStr, nullptr, 16) - std::stoi(std::string("E0"), nullptr, 16) + 1; + } + + if (payload.size() >= 16) + { + busType = mpc::sequencer::busIndexToBusType(std::stoi(payload.substr(14, 2), nullptr, 16)); + } + break; + } + + if (resolvedTrackIndex < 0 || resolvedTrackIndex > mpc::Mpc2000XlSpecs::LAST_TRACK_INDEX) + { + continue; + } + + auto& trackState = (*updateSequenceTracks.trackStates)[resolvedTrackIndex]; + trackState.busType = busType; + trackState.deviceIndex = deviceIndex; + std::string pendingTrackName; + bool hasPendingTrackName = false; + bool hasImportedEvents = false; + + struct OpenNote + { + mpc::sequencer::EventData event; + }; + + std::vector openNotes; + std::vector> noteOffs; + + int absoluteTick = 0; + for (const auto& eventPtr : *parsed.tracks()->at(i)->events()->event()) + { + absoluteTick += eventPtr->v_time()->value(); + + if (const auto* meta = eventPtr->meta_event_body(); meta != nullptr) + { + if (meta->meta_type() == meta_type_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME) + { + const auto body = asciiBody(meta->body()); + if (!body.empty()) + { + pendingTrackName = body.substr(0, mpc::Mpc2000XlSpecs::MAX_TRACK_NAME_LENGTH); + hasPendingTrackName = true; + } + } + continue; + } + + switch (eventPtr->event_type()) + { + case 0x80: + { + const auto* noteOff = + dynamic_cast(eventPtr->event_body()); + if (noteOff != nullptr) + { + noteOffs.push_back({noteOff->note(), absoluteTick}); + } + break; + } + case 0x90: + { + const auto* noteOn = + dynamic_cast(eventPtr->event_body()); + if (noteOn == nullptr) + { + break; + } + mpc::sequencer::EventData ne; + ne.type = mpc::sequencer::EventType::NoteOn; + ne.noteNumber = mpc::NoteNumber(noteOn->note()); + ne.tick = absoluteTick; + ne.velocity = mpc::Velocity(noteOn->velocity()); + ne.noteVariationType = mpc::NoteVariationTypeTune; + ne.noteVariationValue = mpc::DefaultNoteVariationValue; + ne.duration = mpc::Duration(24); + openNotes.push_back(OpenNote{ne}); + break; + } + case 0xA0: + { + const auto* noteAftertouch = + dynamic_cast(eventPtr->event_body()); + if (noteAftertouch == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::PolyPressure; + e.tick = absoluteTick; + e.noteNumber = mpc::NoteNumber(noteAftertouch->note()); + e.amount = noteAftertouch->pressure(); + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(e); + hasImportedEvents = true; + break; + } + case 0xB0: + { + const auto* controller = + dynamic_cast(eventPtr->event_body()); + if (controller == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ControlChange; + e.tick = absoluteTick; + e.controllerNumber = controller->controller(); + e.controllerValue = controller->value(); + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(e); + hasImportedEvents = true; + break; + } + case 0xC0: + { + const auto* programChange = + dynamic_cast(eventPtr->event_body()); + if (programChange == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ProgramChange; + e.tick = absoluteTick; + e.programChangeProgramIndex = mpc::ProgramIndex(programChange->program()); + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(e); + hasImportedEvents = true; + break; + } + case 0xD0: + { + const auto* channelPressure = + dynamic_cast(eventPtr->event_body()); + if (channelPressure == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ChannelPressure; + e.tick = absoluteTick; + e.amount = channelPressure->pressure(); + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(e); + hasImportedEvents = true; + break; + } + case 0xE0: + { + auto* pitchBend = + dynamic_cast(eventPtr->event_body()); + if (pitchBend == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::PitchBend; + e.tick = absoluteTick; + e.amount = pitchBend->bend_value(); + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(e); + hasImportedEvents = true; + break; + } + case 0xF0: + { + const auto* sysEx = eventPtr->sysex_body(); + if (sysEx == nullptr) + { + break; + } + const auto& data = sysEx->data(); + if (data.size() == 8 && + static_cast(data[0]) == 71 && + static_cast(data[1]) == 0 && + static_cast(data[2]) == 68 && + static_cast(data[3]) == 69 && + static_cast(data[7]) == 247) + { + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::Mixer; + e.tick = absoluteTick; + e.mixerParameter = static_cast(data[4]) - 1; + e.mixerPad = static_cast(data[5]); + e.mixerValue = static_cast(data[6]); + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(e); + } + else + { + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::SystemExclusive; + e.tick = absoluteTick; + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(e); + } + hasImportedEvents = true; + break; + } + default: + break; + } + } + + for (auto& on : openNotes) + { + for (auto it = noteOffs.begin(); it != noteOffs.end(); ++it) + { + if (it->first == on.event.noteNumber && it->second >= on.event.tick) + { + on.event.duration = mpc::Duration(it->second - on.event.tick); + noteOffs.erase(it); + break; + } + } + + (*updateSequenceEvents.trackSnapshots)[resolvedTrackIndex].push_back(on.event); + hasImportedEvents = true; + } + + if (hasPendingTrackName) + { + trackState.name = pendingTrackName; + } + + trackState.used = hasImportedEvents; + } + + stateManager->enqueue(updateSequenceTracks); + stateManager->enqueue(updateSequenceEvents); + stateManager->drainQueue(); + + return true; +} + bool tryLoadMpc2000xl(mpc::Mpc& mpc, const midi_t& parsed, const std::shared_ptr& sequence) @@ -786,6 +1153,8 @@ bool tryLoadMpc2000xl(mpc::Mpc& mpc, auto noteVariationType = mpc::NoteVariationTypeTune; auto noteVariationValue = mpc::DefaultNoteVariationValue; std::vector openNotes; + std::string pendingTrackName; + bool hasPendingTrackName = false; bool hasImportedEvents = false; int absoluteTick = 0; @@ -820,8 +1189,9 @@ bool tryLoadMpc2000xl(mpc::Mpc& mpc, meta_type_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME && !body.empty()) { - track->setName( - body.substr(0, mpc::Mpc2000XlSpecs::MAX_TRACK_NAME_LENGTH)); + pendingTrackName = + body.substr(0, mpc::Mpc2000XlSpecs::MAX_TRACK_NAME_LENGTH); + hasPendingTrackName = true; } continue; } @@ -1088,11 +1458,15 @@ bool tryLoadMpc2000xl(mpc::Mpc& mpc, { track->setUsedIfCurrentlyUnused(); } + + if (hasPendingTrackName) + { + track->setName(pendingTrackName); + } } return true; } - } // namespace sequence_or_error MidIo::loadBytes(mpc::Mpc &mpc, @@ -1103,6 +1477,7 @@ sequence_or_error MidIo::loadBytes(mpc::Mpc &mpc, auto newSeq = mpc.getSequencer()->getSequence(mpc::TempSequenceIndex); newSeq->init(0); + mpc.getSequencer()->getStateManager()->drainQueue(); std::stringstream kaitaiStream( std::string(canonicalBytes.begin(), canonicalBytes.end()), @@ -1112,22 +1487,11 @@ sequence_or_error MidIo::loadBytes(mpc::Mpc &mpc, midi_t parsed(&kaitaiIo); parsed._read(); - if (tryLoadMpc2000xl(mpc, parsed, newSeq)) + if (!tryLoadMpc2000xl(mpc, parsed, newSeq)) { - if (newSeq->getName().empty()) - { - newSeq->setName(fileNameWithoutExtension); - } - return newSeq; + loadGenericStandardMidi(mpc, parsed, newSeq); } - auto input = std::make_shared( - std::string(canonicalBytes.begin(), canonicalBytes.end()), - std::ios::in | std::ios::binary - ); - mpc::file::mid::MidiReader reader(input, newSeq); - reader.parseSequence(mpc); - if (newSeq->getName().empty()) { newSeq->setName(fileNameWithoutExtension); diff --git a/src/main/file/kaitai/generated/mpc2000xl_all.cpp b/src/main/file/kaitai/generated/mpc2000xl_all.cpp index a17f0d65..10cd635a 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_all.cpp +++ b/src/main/file/kaitai/generated/mpc2000xl_all.cpp @@ -867,7 +867,7 @@ int32_t mpc2000xl_all_t::bar_t::first_tick() { if (f_first_tick) return m_first_tick; f_first_tick = true; - m_first_tick = ((idx() == 0) ? (0) : (_parent()->bars()->at(idx() - 1)->last_tick())); + m_first_tick = ((idx() == 0) ? (0) : (static_cast(_parent())->bars()->at(idx() - 1)->last_tick())); return m_first_tick; } @@ -1909,12 +1909,6 @@ mpc2000xl_all_t::midi_switch_t::midi_switch_t(kaitai::kstream* p__io, mpc2000xl_ void mpc2000xl_all_t::midi_switch_t::_read() { m_controller = m__io->read_u1(); - if (!(m_controller >= 0)) { - throw kaitai::validation_less_than_error(0, m_controller, m__io, std::string("/types/midi_switch/seq/0")); - } - if (!(m_controller <= 127)) { - throw kaitai::validation_greater_than_error(127, m_controller, m__io, std::string("/types/midi_switch/seq/0")); - } m_function = static_cast(m__io->read_u1()); m__dirty = false; } @@ -1930,12 +1924,6 @@ void mpc2000xl_all_t::midi_switch_t::_write() { } void mpc2000xl_all_t::midi_switch_t::_check() { - if (!(m_controller >= 0)) { - throw kaitai::validation_less_than_error(0, m_controller, m__io, std::string("/types/midi_switch/seq/0")); - } - if (!(m_controller <= 127)) { - throw kaitai::validation_greater_than_error(127, m_controller, m__io, std::string("/types/midi_switch/seq/0")); - } m__dirty = false; } @@ -2161,7 +2149,7 @@ int32_t mpc2000xl_all_t::note_event_t::duration() { if (f_duration) return m_duration; f_duration = true; - m_duration = ((_parent()->duration_bits_1() << 10) + (_parent()->duration_bits_2() << 8)) + duration_bits_3(); + m_duration = ((static_cast(_parent())->duration_bits_1() << 10) + (static_cast(_parent())->duration_bits_2() << 8)) + duration_bits_3(); return m_duration; } @@ -2169,7 +2157,7 @@ uint8_t mpc2000xl_all_t::note_event_t::note() { if (f_note) return m_note; f_note = true; - m_note = _parent()->id(); + m_note = static_cast(_parent())->id(); return m_note; } @@ -2332,11 +2320,11 @@ mpc2000xl_all_t::sequence_t::sequence_t(kaitai::kstream* p__io, mpc2000xl_all_t* } void mpc2000xl_all_t::sequence_t::_read() { - m_name_part_1 = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 255), 255, false), "ASCII"); + m_name_part_1 = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), static_cast(255)), static_cast(255), false), "ASCII"); n_name_part_2 = true; if (name_part_1() != std::string("")) { n_name_part_2 = false; - m_name_part_2 = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 255), 255, false), "ASCII"); + m_name_part_2 = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), static_cast(255)), static_cast(255), false), "ASCII"); } if (name_part_1() != std::string("")) { m_body = std::unique_ptr(new sequence_body_t(m__io, this, m__root)); diff --git a/src/main/file/kaitai/generated/mpc2000xl_all.h b/src/main/file/kaitai/generated/mpc2000xl_all.h index e9833d05..50f2dd1e 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_all.h +++ b/src/main/file/kaitai/generated/mpc2000xl_all.h @@ -658,7 +658,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_idx(int32_t _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m_idx = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m__root = std::move(_v); } - mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; f_denominator = false; f_first_tick = false; f_numerator = false; m__parent = std::move(_v); } private: @@ -696,7 +696,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -729,7 +729,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -791,7 +791,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_normal_velo(uint8_t _v) { m__dirty = true; m_normal_velo = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -867,7 +867,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed16(std::string _v) { m__dirty = true; m__unnamed16 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -937,7 +937,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_terminator(std::string _v) { m__dirty = true; n_terminator = false; m_terminator = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1055,7 +1055,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed3(std::string _v) { m__dirty = true; m__unnamed3 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1097,7 +1097,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_clock(uint8_t _v) { m__dirty = true; f_display_value = false; m_clock = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_display_value = false; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; f_display_value = false; m__parent = std::move(_v); } private: @@ -1171,7 +1171,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_cc_pass_enabled(std::unique_ptr> _v) { m__dirty = true; m_cc_pass_enabled = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1220,7 +1220,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_soft_thru_mode(soft_thru_mode_t _v) { m__dirty = true; m_soft_thru_mode = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1244,13 +1244,17 @@ class mpc2000xl_all_t : public kaitai::kstruct { void _write(); void _check(); ~midi_switch_t(); + + /** + * 0xFF is used for an unassigned footswitch controller. + */ uint8_t controller() const { return m_controller; } void set_controller(uint8_t _v) { m__dirty = true; m_controller = std::move(_v); } midi_switch_function_t function() const { return m_function; } void set_function(midi_switch_function_t _v) { m__dirty = true; m_function = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::misc_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::misc_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1293,7 +1297,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_output(midi_sync_output_t _v) { m__dirty = true; m_output = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1332,7 +1336,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_midi_switch(std::unique_ptr>> _v) { m__dirty = true; m_midi_switch = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1370,7 +1374,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed4(std::string _v) { m__dirty = true; m__unnamed4 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::exclusive_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::exclusive_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1429,7 +1433,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_variation_type_bit_2(bool _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m_variation_type_bit_2 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m__root = std::move(_v); } - mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; f_duration = false; f_note = false; f_variation_type = false; m__parent = std::move(_v); } private: @@ -1473,7 +1477,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed2(std::string _v) { m__dirty = true; f_corrected_amount = false; m__unnamed2 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_corrected_amount = false; m__root = std::move(_v); } - mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; f_corrected_amount = false; m__parent = std::move(_v); } private: @@ -1509,7 +1513,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1541,7 +1545,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1576,7 +1580,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_body(std::unique_ptr _v) { m__dirty = true; f_name = false; m_body = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_name = false; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; f_name = false; m__parent = std::move(_v); } private: @@ -1650,7 +1654,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_frame_decimals(uint8_t _v) { m__dirty = true; m_frame_decimals = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1712,7 +1716,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_events(std::unique_ptr>> _v) { m__dirty = true; m_events = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::sequence_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::sequence_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1762,7 +1766,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_is_used(sequence_is_used_t _v) { m__dirty = true; m_is_used = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1815,7 +1819,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_sequence_sequence_index(uint8_t _v) { m__dirty = true; m_sequence_sequence_index = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1869,7 +1873,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed7(std::string _v) { m__dirty = true; m__unnamed7 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1908,7 +1912,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set__unnamed2(uint64_t _v) { m__dirty = true; m__unnamed2 = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1940,7 +1944,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_repeat_count(uint8_t _v) { m__dirty = true; m_repeat_count = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::song_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::song_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -1973,7 +1977,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_tc_value_percentage(uint8_t _v) { m__dirty = true; m_tc_value_percentage = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -2052,7 +2056,7 @@ class mpc2000xl_all_t : public kaitai::kstruct { void set_unknown(std::string _v) { m__dirty = true; m_unknown = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_all_t::sequence_body_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_all_t::sequence_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp index f0048298..2033b9ca 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp @@ -37,7 +37,8 @@ void mpc2000xl_aps_t::_read() { if (!(m_magic == std::string("\x0A\x05", 2))) { throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); } - m_sound_count = m__io->read_u2le(); + m_sound_count = m__io->read_u1(); + m__unnamed2 = m__io->read_bytes(1); m_sound_names = std::unique_ptr>(new std::vector()); const int l_sound_names = sound_count(); for (int i = 0; i < l_sound_names; i++) { @@ -101,7 +102,8 @@ void mpc2000xl_aps_t::_fetch_instances() { void mpc2000xl_aps_t::_write() { m__io->write_bytes(m_magic); - m__io->write_u2le(m_sound_count); + m__io->write_u1(m_sound_count); + m__io->write_bytes(m__unnamed2); if (m_sound_names == nullptr) { throw std::runtime_error("/seq/3: repeated field is not set"); } @@ -171,15 +173,18 @@ void mpc2000xl_aps_t::_check() { if (!(m_magic == std::string("\x0A\x05", 2))) { throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); } + if (m__unnamed2.size() != static_cast(1)) { + throw std::runtime_error("/seq/2: size mismatch"); + } if (m_sound_names == nullptr) { - throw std::runtime_error("/seq/2: repeated field is not set"); + throw std::runtime_error("/seq/3: repeated field is not set"); } if (m_sound_names->size() != static_cast(sound_count())) { - throw std::runtime_error("/seq/2: repeat-expr size mismatch"); + throw std::runtime_error("/seq/3: repeat-expr size mismatch"); } for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { if ((*it).size() != static_cast(17)) { - throw std::runtime_error("/seq/2: size mismatch"); + throw std::runtime_error("/seq/3: size mismatch"); } } if (m__unnamed4.size() != static_cast(2)) { diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.h b/src/main/file/kaitai/generated/mpc2000xl_aps.h index 5ad8face..23c75a16 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.h +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.h @@ -108,7 +108,7 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void set__unnamed10(std::string _v) { m__dirty = true; m__unnamed10 = std::move(_v); } mpc2000xl_aps_t* _root() const { return m__root; } void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_aps_t::aps_program_meta_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_aps_t::aps_program_meta_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -150,7 +150,7 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void set__unnamed2(std::unique_ptr> _v) { m__dirty = true; m__unnamed2 = std::move(_v); } mpc2000xl_aps_t* _root() const { return m__root; } void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_aps_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_aps_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -204,7 +204,7 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void set_receive_midi_volume_duplicate(no_yes_t _v) { m__dirty = true; m_receive_midi_volume_duplicate = std::move(_v); } mpc2000xl_aps_t* _root() const { return m__root; } void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_aps_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_aps_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -265,7 +265,7 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void set_master_level(uint8_t _v) { m__dirty = true; m_master_level = std::move(_v); } mpc2000xl_aps_t* _root() const { return m__root; } void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_aps_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_aps_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -354,7 +354,7 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void set_velocity_to_pitch(uint8_t _v) { m__dirty = true; m_velocity_to_pitch = std::move(_v); } mpc2000xl_aps_t* _root() const { return m__root; } void set__root(mpc2000xl_aps_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_aps_t::aps_program_body_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_aps_t::aps_program_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -390,8 +390,10 @@ class mpc2000xl_aps_t : public kaitai::kstruct { public: std::string magic() const { return m_magic; } void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } - uint16_t sound_count() const { return m_sound_count; } - void set_sound_count(uint16_t _v) { m__dirty = true; m_sound_count = std::move(_v); } + uint8_t sound_count() const { return m_sound_count; } + void set_sound_count(uint8_t _v) { m__dirty = true; m_sound_count = std::move(_v); } + std::string _unnamed2() const { return m__unnamed2; } + void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } std::vector* sound_names() const { return m_sound_names.get(); } void set_sound_names(std::unique_ptr> _v) { m__dirty = true; m_sound_names = std::move(_v); } std::string _unnamed4() const { return m__unnamed4; } @@ -431,7 +433,8 @@ class mpc2000xl_aps_t : public kaitai::kstruct { private: std::string m_magic; - uint16_t m_sound_count; + uint8_t m_sound_count; + std::string m__unnamed2; std::unique_ptr> m_sound_names; std::string m__unnamed4; std::string m_name; diff --git a/src/main/file/kaitai/generated/mpc2000xl_mid.h b/src/main/file/kaitai/generated/mpc2000xl_mid.h index 966f3237..ac0d4770 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_mid.h +++ b/src/main/file/kaitai/generated/mpc2000xl_mid.h @@ -64,7 +64,7 @@ class mpc2000xl_mid_t : public kaitai::kstruct { void set_tempo_source(std::string _v) { m__dirty = true; m_tempo_source = std::move(_v); } mpc2000xl_mid_t* _root() const { return m__root; } void set__root(mpc2000xl_mid_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_mid_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_mid_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: diff --git a/src/main/file/kaitai/generated/mpc2000xl_pgm.h b/src/main/file/kaitai/generated/mpc2000xl_pgm.h index 8725d2ca..d34b6d8d 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_pgm.h +++ b/src/main/file/kaitai/generated/mpc2000xl_pgm.h @@ -160,7 +160,7 @@ class mpc2000xl_pgm_t : public kaitai::kstruct { void set_velocity_to_pitch(uint8_t _v) { m__dirty = true; m_velocity_to_pitch = std::move(_v); } mpc2000xl_pgm_t* _root() const { return m__root; } void set__root(mpc2000xl_pgm_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_pgm_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_pgm_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -221,7 +221,7 @@ class mpc2000xl_pgm_t : public kaitai::kstruct { void set_effects_send_level(uint8_t _v) { m__dirty = true; m_effects_send_level = std::move(_v); } mpc2000xl_pgm_t* _root() const { return m__root; } void set__root(mpc2000xl_pgm_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_pgm_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_pgm_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -270,7 +270,7 @@ class mpc2000xl_pgm_t : public kaitai::kstruct { void set_filter_high(int8_t _v) { m__dirty = true; m_filter_high = std::move(_v); } mpc2000xl_pgm_t* _root() const { return m__root; } void set__root(mpc2000xl_pgm_t* _v) { m__dirty = true; m__root = std::move(_v); } - mpc2000xl_pgm_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(mpc2000xl_pgm_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: diff --git a/src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp index ea94cfaf..8bd5f888 100644 --- a/src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp +++ b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.cpp @@ -514,7 +514,7 @@ standard_midi_file_with_running_status_t::track_event_t::track_event_t(uint8_t p f_status_byte_lookahead = false; f_using_running_status = false; w_status_byte_lookahead = false; - e_status_byte_lookahead = false; + e_status_byte_lookahead = m__io != nullptr; } void standard_midi_file_with_running_status_t::track_event_t::_read() { @@ -663,7 +663,7 @@ void standard_midi_file_with_running_status_t::track_event_t::_fetch_instances() } void standard_midi_file_with_running_status_t::track_event_t::_write() { - w_status_byte_lookahead = e_status_byte_lookahead; + w_status_byte_lookahead = false; if (m_v_time.get() == nullptr) { throw std::runtime_error("/types/track_event/seq/0: nested object is not set"); } diff --git a/src/main/file/kaitai/generated/standard_midi_file_with_running_status.h b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.h index 78fd8d02..5316cece 100644 --- a/src/main/file/kaitai/generated/standard_midi_file_with_running_status.h +++ b/src/main/file/kaitai/generated/standard_midi_file_with_running_status.h @@ -80,7 +80,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_pressure(uint8_t _v) { m__dirty = true; m_pressure = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -110,7 +110,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_value(uint8_t _v) { m__dirty = true; m_value = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -147,7 +147,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_division(int16_t _v) { m__dirty = true; m_division = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -207,7 +207,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_body(std::string _v) { m__dirty = true; m_body = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -239,7 +239,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_velocity(uint8_t _v) { m__dirty = true; m_velocity = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -270,7 +270,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_velocity(uint8_t _v) { m__dirty = true; m_velocity = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -305,7 +305,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_b2(uint8_t _v) { m__dirty = true; f_adj_bend_value = false; f_bend_value = false; m_b2 = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; f_adj_bend_value = false; f_bend_value = false; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; f_adj_bend_value = false; f_bend_value = false; m__parent = std::move(_v); } private: @@ -340,7 +340,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_pressure(uint8_t _v) { m__dirty = true; m_pressure = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -369,7 +369,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_program(uint8_t _v) { m__dirty = true; m_program = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -399,7 +399,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_data(std::string _v) { m__dirty = true; m_data = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_event_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_event_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: @@ -432,7 +432,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_events(std::unique_ptr _v) { m__dirty = true; m_events = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__parent = std::move(_v); } std::string _raw_events() const { return m__raw_events; } void set__raw_events(std::string _v) { m__dirty = true; m__raw_events = std::move(_v); } @@ -492,7 +492,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_previous_event_type(uint8_t _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m_previous_event_type = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_events_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_events_t* _v) { m__dirty = true; f_channel = false; f_event_type = false; f_using_running_status = false; m__parent = std::move(_v); } private: @@ -562,7 +562,7 @@ class standard_midi_file_with_running_status_t : public kaitai::kstruct { void set_event(std::unique_ptr>> _v) { m__dirty = true; m_event = std::move(_v); } standard_midi_file_with_running_status_t* _root() const { return m__root; } void set__root(standard_midi_file_with_running_status_t* _v) { m__dirty = true; m__root = std::move(_v); } - standard_midi_file_with_running_status_t::track_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(standard_midi_file_with_running_status_t::track_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: diff --git a/src/main/file/kaitai/generated/vlq_base128_be.h b/src/main/file/kaitai/generated/vlq_base128_be.h index dbdcf320..a693af5a 100644 --- a/src/main/file/kaitai/generated/vlq_base128_be.h +++ b/src/main/file/kaitai/generated/vlq_base128_be.h @@ -80,7 +80,7 @@ class vlq_base128_be_t : public kaitai::kstruct { void set_value(uint64_t _v) { m__dirty = true; m_value = std::move(_v); } vlq_base128_be_t* _root() const { return m__root; } void set__root(vlq_base128_be_t* _v) { m__dirty = true; m__root = std::move(_v); } - vlq_base128_be_t* _parent() const { return m__parent; } + kaitai::kstruct* _parent() const { return m__parent; } void set__parent(vlq_base128_be_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: diff --git a/src/main/file/mid/MidiFile.cpp b/src/main/file/mid/MidiFile.cpp deleted file mode 100644 index 721f88d0..00000000 --- a/src/main/file/mid/MidiFile.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "file/mid/MidiFile.hpp" -#include "file/mid/MidiTrack.hpp" -#include "file/mid/util/MidiUtil.hpp" - -#include - -using namespace mpc::file::mid; -using namespace mpc::file::mid::util; - -MidiFile::MidiFile(std::shared_ptr stream) -{ - std::vector buffer(HEADER_SIZE); - stream->read(&buffer[0], buffer.size()); - initFromBuffer(buffer); - mTracks.clear(); - - for (int i = 0; i < mTrackCount; i++) - { - mTracks.emplace_back(std::make_shared(stream)); - } -} - -std::vector MidiFile::IDENTIFIER = {'M', 'T', 'h', 'd'}; - -void MidiFile::setType(int type) -{ - if (type < 0) - { - type = 0; - } - else if (type > 2) - { - type = 1; - } - else if (type == 0 && mTrackCount > 1) - { - type = 1; - } - mType = type; -} - -int MidiFile::getType() const -{ - return mType; -} - -int MidiFile::getLengthInTicks() const -{ - int length = 0; - for (auto &T : mTracks) - { - int l = T->getLengthInTicks(); - if (l > length) - { - length = l; - } - } - return length; -} - -std::vector> MidiFile::getTracks() const -{ - auto res = std::vector>(); - for (auto &t : mTracks) - { - res.push_back(t); - } - return res; -} - -void MidiFile::addTrack(const std::shared_ptr &track) -{ - addTrack(track, mTracks.size()); -} - -void MidiFile::addTrack(std::shared_ptr track, int pos) -{ - if (pos > mTracks.size()) - { - pos = mTracks.size(); - } - else if (pos < 0) - { - pos = 0; - } - mTracks.insert(mTracks.begin() + pos, std::move(track)); - mTrackCount = mTracks.size(); - mType = mTrackCount > 1 ? 1 : 0; -} - -void MidiFile::writeToOutputStream( - const std::shared_ptr &stream) const -{ - stream->write(&IDENTIFIER[0], IDENTIFIER.size()); - - auto val1 = MidiUtil::intToBytes(6, 4); - stream->write(&val1[0], val1.size()); - - auto type = MidiUtil::intToBytes(mType, 2); - stream->write(&type[0], type.size()); - - auto trackCount = MidiUtil::intToBytes(mTrackCount, 2); - stream->write(&trackCount[0], trackCount.size()); - - auto resolution = MidiUtil::intToBytes(mResolution, 2); - stream->write(&resolution[0], resolution.size()); - - for (auto &track : mTracks) - { - track->writeToOutputStream(stream); - } -} - -void MidiFile::initFromBuffer(std::vector &buffer) -{ - if (!MidiUtil::bytesEqual(buffer, IDENTIFIER, 0, 4)) - { - mType = 0; - mTrackCount = 0; - MLOG("File header does not indicate this is a MIDI file"); - return; - } - mType = MidiUtil::bytesToInt(buffer, 8, 2); - mTrackCount = MidiUtil::bytesToInt(buffer, 10, 2); - mResolution = MidiUtil::bytesToInt(buffer, 12, 2); - - if (mResolution != 96) - { - MLOG( - "Developer warning: non-96ppq MIDI file was loaded. Most likely " - "the event positions are incorrect."); - } -} diff --git a/src/main/file/mid/MidiFile.hpp b/src/main/file/mid/MidiFile.hpp deleted file mode 100644 index 6fb64e4b..00000000 --- a/src/main/file/mid/MidiFile.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace mpc::file::mid -{ - class MidiTrack; -} - -namespace mpc::file::mid -{ - - class MidiFile - { - - public: - static const int HEADER_SIZE{14}; - - private: - static std::vector IDENTIFIER; - - int mType = 0; - int mTrackCount = 0; - int mResolution = 96; - std::vector> mTracks; - - public: - void setType(int type); - int getType() const; - - int getLengthInTicks() const; - std::vector> getTracks() const; - void addTrack(const std::shared_ptr &T); - void addTrack(std::shared_ptr T, int pos); - - void writeToOutputStream(const std::shared_ptr &) const; - - private: - void initFromBuffer(std::vector &buffer); - - public: - MidiFile() = default; - explicit MidiFile(std::shared_ptr); - }; -} // namespace mpc::file::mid diff --git a/src/main/file/mid/MidiReader.cpp b/src/main/file/mid/MidiReader.cpp deleted file mode 100644 index 11321208..00000000 --- a/src/main/file/mid/MidiReader.cpp +++ /dev/null @@ -1,664 +0,0 @@ -#include "file/mid/MidiReader.hpp" -#include "sequencer/Transport.hpp" - -#include "Mpc.hpp" - -#include "file/mid/MidiFile.hpp" -#include "file/mid/MidiTrack.hpp" -#include "file/mid/event/ChannelAftertouch.hpp" -#include "file/mid/event/Controller.hpp" -#include "file/mid/event/NoteAftertouch.hpp" -#include "file/mid/event/NoteOff.hpp" -#include "file/mid/event/NoteOn.hpp" -#include "file/mid/event/PitchBend.hpp" -#include "file/mid/event/ProgramChange.hpp" -#include "file/mid/event/SystemExclusive.hpp" -#include "file/mid/event/meta/Tempo.hpp" -#include "file/mid/event/meta/Text.hpp" -#include "file/mid/event/meta/TimeSignatureEvent.hpp" -#include "file/mid/event/meta/TrackName.hpp" - -#include "sequencer/Sequence.hpp" -#include "sequencer/Track.hpp" -#include "sequencer/Sequencer.hpp" -#include "sequencer/SequencerStateManager.hpp" - -#include - -using namespace mpc::file::mid; -using namespace mpc::file::mid::event; -using namespace mpc::sequencer; - -MidiReader::MidiReader(std::shared_ptr istream, - const std::weak_ptr &dest) - : dest(dest) -{ - midiFile = std::make_unique(istream); -} - -void MidiReader::parseSequence(Mpc &mpc) const -{ - auto lSequencer = mpc.getSequencer(); - auto midiTracks = midiFile->getTracks(); - int lengthInTicks = 0; - for (const auto &mtWeak : midiTracks) - { - if (const auto mt = mtWeak.lock()) - { - lengthInTicks = std::max(lengthInTicks, mt->getLengthInTicks() + - mt->getEndOfTrackDelta()); - } - } - - std::vector> timeSignatures; - std::vector> tempoChanges; - - auto firstLoopBar = -1; - auto lastLoopBar = -1; - - auto sequence = dest.lock(); - sequence->setUsed(true); - - const auto sequenceIndex = sequence->getSequenceIndex(); - - UpdateSequenceEvents updateSequenceEvents{sequenceIndex}; - updateSequenceEvents.trackSnapshots = - &lSequencer->getStateManager()->trackEventsSnapshots[sequenceIndex]; - updateSequenceEvents.trackSnapshots->clear(); - - UpdateSequenceTracks updateSequenceTracks{sequence->getSequenceIndex()}; - updateSequenceTracks.trackStates = - &lSequencer->getStateManager()->trackStatesSnapshots[sequenceIndex]; - *updateSequenceTracks.trackStates = SequenceTrackStatesSnapshot(); - - bool isMpc2000XlMidiFile = false; - - for (auto &event : midiTracks[0].lock()->getEvents()) - { - if (const auto textEvent = - std::dynamic_pointer_cast(event.lock()); - textEvent) - { - auto text = textEvent->getText(); - - if (text.find("LOOP=ON") != std::string::npos) - { - sequence->setLoopEnabled(true); - } - else if (text.find("LOOP=OFF") != std::string::npos) - { - sequence->setLoopEnabled(false); - } - - if (text.find("TEMPO=ON") != std::string::npos) - { - lSequencer->getTransport()->setTempoSourceIsSequence(true); - } - else if (text.find("TEMPO=OFF") != std::string::npos) - { - lSequencer->getTransport()->setTempoSourceIsSequence(false); - } - - firstLoopBar = stoi(text.substr(15, 18)); - lastLoopBar = -1; - - if (isInteger(text.substr(23, 26))) - { - lastLoopBar = stoi(text.substr(23, 26)); - } - } - else if (const auto trackNameEvent = - std::dynamic_pointer_cast(event.lock()); - trackNameEvent && trackNameEvent->getTrackName().find( - "MPC2000XL 1.00 ") != std::string::npos) - { - isMpc2000XlMidiFile = true; - auto sequenceName = trackNameEvent->getTrackName().substr(16); - sequence->setName(sequenceName); - } - else if (const auto tempoEvent = - std::dynamic_pointer_cast(event.lock()); - tempoEvent) - { - tempoChanges.push_back(tempoEvent); - } - else if (const auto timeSigEvent = - std::dynamic_pointer_cast( - event.lock()); - timeSigEvent) - { - timeSignatures.push_back(timeSigEvent); - } - } - - const auto initialTempo = - tempoChanges.empty() ? 120 : tempoChanges[0].lock()->getBpm(); - - sequence->setInitialTempo(initialTempo); - - if (!lSequencer->getTransport()->isTempoSourceSequence()) - { - lSequencer->getTransport()->setTempo(initialTempo); - } - - for (int i = 1; i < tempoChanges.size(); i++) - { - auto lTcMidi = tempoChanges[i].lock(); - auto ratio = lTcMidi->getBpm() / initialTempo; - auto amount = static_cast(ratio * 1000.0); - sequence->addTempoChangeEvent(lTcMidi->getTick(), amount); - } - - const bool hadExplicitTimeSignatures = !timeSignatures.empty(); - - if (!hadExplicitTimeSignatures) - { - timeSignatures.push_back(std::make_shared( - 0, 0, DefaultTimeSigNumerator, DefaultTimeSigDenominator, 24, 8)); - } - - lengthInTicks = std::max(lengthInTicks, 1); - - int accumLength = 0; - int barCounter = 0; - - for (int i = 0; i < timeSignatures.size(); i++) - { - auto current = timeSignatures[i].lock(); - std::shared_ptr next; - - if (timeSignatures.size() > i + 1) - { - next = timeSignatures[i + 1].lock(); - } - - if (next) - { - while (accumLength < next->getTick()) - { - sequence->setTimeSignature(barCounter, current->getNumerator(), - current->getRealDenominator()); - const auto newDenTicks = - 96 * (4.0 / current->getRealDenominator()); - const auto barLength = - static_cast(newDenTicks * current->getNumerator()); - accumLength += barLength; - barCounter++; - } - } - else - { - while (accumLength < lengthInTicks) - { - sequence->setTimeSignature(barCounter, current->getNumerator(), - current->getRealDenominator()); - const auto newDenTicks = - 96 * (4.0 / current->getRealDenominator()); - const auto barLength = - static_cast(newDenTicks * current->getNumerator()); - accumLength += barLength; - barCounter++; - } - } - } - - sequence->setLastBarIndex(barCounter - 1); - sequence->setFirstLoopBarIndex(BarIndex(firstLoopBar)); - - if (lastLoopBar == -1) - { - sequence->setLastLoopBarIndex(EndOfSequence); - } - else - { - sequence->setLastLoopBarIndex(BarIndex(lastLoopBar)); - } - - std::pair noteVariationData{NoteVariationTypeTune, - DefaultNoteVariationValue}; - - const std::string trackDataPrefix = "TRACK DATA:"; - - const int midiTrackStartIndexForCollectingNoteEvents = - isMpc2000XlMidiFile ? 1 : 0; - - for (int i = midiTrackStartIndexForCollectingNoteEvents; - i < midiTracks.size(); i++) - { - auto mt = midiTracks[i].lock(); - auto trackIndex = isMpc2000XlMidiFile ? i - 1 : i; - auto deviceIndex = 0; - auto busType = BusType::DRUM1; - - for (auto &e : mt->getEvents()) - { - if (auto textEvent = - std::dynamic_pointer_cast(e.lock())) - { - if (auto text = textEvent->getText(); - text.find(trackDataPrefix) != std::string::npos) - { - auto payload = text.substr(trackDataPrefix.length()); - trackIndex = stoi(payload.substr(0, 2)); - - if (auto deviceIndexStr = payload.substr(2, 2); - deviceIndexStr != "C0") - { - deviceIndex = - stoi(deviceIndexStr, nullptr, 16) - - stoi(std::string("E0"), nullptr, 16) + 1; - } - - if (payload.size() >= 16) - { - busType = busIndexToBusType( - stoi(payload.substr(14, 2), nullptr, 16)); - } - break; - } - } - } - - if (trackIndex < 0 || trackIndex > Mpc2000XlSpecs::LAST_TRACK_INDEX) - { - continue; - } - - auto &track = (*updateSequenceTracks.trackStates)[trackIndex]; - track.deviceIndex = deviceIndex; - track.busType = busType; - bool hasImportedEvents = false; - - struct OpenNote - { - EventData event; - bool isClosed = false; - }; - - std::vector openNotes; - std::vector> noteOffs; - std::vector noteOns; - - if (isMpc2000XlMidiFile) - { - for (auto &me : mt->getEvents()) - { - auto noteOff = std::dynamic_pointer_cast(me.lock()); - auto noteOn = std::dynamic_pointer_cast(me.lock()); - - if (noteOff) - { - noteVariationData = { - NoteVariationType(noteOff->getNoteValue()), - NoteVariationValue(noteOff->getVelocity())}; - } - else if (noteOn) - { - if (noteOn->getVelocity() == 0) - { - const auto isDefaultVariation = [](const EventData &event) - { - if (event.noteVariationType == NoteVariationTypeTune) - { - return event.noteVariationValue == - DefaultNoteVariationValue; - } - - if (event.noteVariationType == - NoteVariationTypeDecay || - event.noteVariationType == - NoteVariationTypeAttack) - { - return event.noteVariationValue == 0; - } - - if (event.noteVariationType == - NoteVariationTypeFilter) - { - return event.noteVariationValue == 50; - } - - return false; - }; - - auto bestIt = openNotes.end(); - - auto isEligible = [&](const OpenNote &openNote) - { - return !openNote.isClosed && - openNote.event.noteNumber == - NoteNumber(noteOn->getNoteValue()) && - openNote.event.tick <= noteOn->getTick(); - }; - - auto latestNonDefaultIt = openNotes.end(); - for (auto it = openNotes.rbegin(); it != openNotes.rend(); - ++it) - { - if (!isEligible(*it) || - isDefaultVariation(it->event)) - { - continue; - } - - latestNonDefaultIt = std::prev(it.base()); - break; - } - - if (latestNonDefaultIt != openNotes.end()) - { - auto sameVariationCount = 0; - for (auto it = openNotes.begin(); it != openNotes.end(); - ++it) - { - if (!isEligible(*it)) - { - continue; - } - - if (it->event.noteVariationType == - latestNonDefaultIt->event.noteVariationType && - it->event.noteVariationValue == - latestNonDefaultIt->event.noteVariationValue) - { - sameVariationCount++; - if (bestIt == openNotes.end()) - { - bestIt = it; - } - } - } - - if (sameVariationCount < 2) - { - bestIt = openNotes.end(); - } - } - - if (bestIt == openNotes.end()) - { - for (auto it = openNotes.begin(); it != openNotes.end(); - ++it) - { - if (!isEligible(*it)) - { - continue; - } - - bestIt = it; - break; - } - } - - if (bestIt != openNotes.end()) - { - bestIt->event.duration = - Duration(noteOn->getTick() - bestIt->event.tick); - bestIt->isClosed = true; - } - } - else - { - EventData ne; - ne.type = EventType::NoteOn; - ne.noteNumber = NoteNumber(noteOn->getNoteValue()); - ne.tick = noteOn->getTick(); - ne.velocity = Velocity(noteOn->getVelocity()); - ne.noteVariationType = noteVariationData.first; - ne.noteVariationValue = noteVariationData.second; - ne.duration = Duration(24); - openNotes.push_back(OpenNote{ne}); - noteVariationData = {NoteVariationTypeTune, - DefaultNoteVariationValue}; - } - } - } - } - else - { - for (auto &me : mt->getEvents()) - { - auto noteOff = std::dynamic_pointer_cast(me.lock()); - auto noteOn = std::dynamic_pointer_cast(me.lock()); - - if (noteOff) - { - noteOffs.push_back(noteOff); - } - else if (noteOn) - { - EventData ne; - ne.type = EventType::NoteOn; - ne.noteNumber = NoteNumber(noteOn->getNoteValue()); - ne.tick = noteOn->getTick(); - ne.velocity = Velocity(noteOn->getVelocity()); - ne.noteVariationType = noteVariationData.first; - ne.noteVariationValue = noteVariationData.second; - ne.duration = Duration(24); - openNotes.push_back(OpenNote{ne}); - } - } - } - - // - // Resolve durations and build EventData - // - for (auto &on : openNotes) - { - if (isMpc2000XlMidiFile) - { - noteOns.emplace_back(on.event); - continue; - } - - int bestIdx = -1; - int endTick = -1; - - for (int k = 0; k < noteOffs.size(); k++) - { - int offVal; - int offTick; - - if (auto nOn = std::dynamic_pointer_cast(noteOffs[k])) - { - offVal = nOn->getNoteValue(); - offTick = nOn->getTick(); - } - else - { - auto nOff = std::dynamic_pointer_cast(noteOffs[k]); - offVal = nOff->getNoteValue(); - offTick = nOff->getTick(); - } - - if (offVal == on.event.noteNumber && offTick >= on.event.tick) - { - endTick = offTick; - bestIdx = k; - break; - } - } - - EventData ne = on.event; - - if (bestIdx != -1) - { - ne.duration = Duration(endTick - on.event.tick); - noteOffs.erase(noteOffs.begin() + bestIdx); - } - - noteOns.emplace_back(ne); - } - - // - // Add final resolved notes into updateSequenceEvents - // - for (auto &n : noteOns) - { - (*updateSequenceEvents.trackSnapshots)[trackIndex].push_back(n); - hasImportedEvents = true; - } - - // - // Non-note events - // - for (auto &me : mt->getEvents()) - { - if (const auto sysEx = - std::dynamic_pointer_cast(me.lock()); - sysEx) - { - - if (auto sysExEventBytes = sysEx->getData(); - sysExEventBytes.size() == 8 && sysExEventBytes[0] == 71 && - sysExEventBytes[1] == 0 && sysExEventBytes[2] == 68 && - sysExEventBytes[3] == 69 && - sysExEventBytes[7] == static_cast(247)) - { - EventData e; - e.type = EventType::Mixer; - e.tick = sysEx->getTick(); - e.mixerParameter = sysExEventBytes[4] - 1; - e.mixerPad = sysExEventBytes[5]; - e.mixerValue = sysExEventBytes[6]; - (*updateSequenceEvents.trackSnapshots)[trackIndex] - .push_back(e); - hasImportedEvents = true; - } - else - { - std::vector bytes(sysEx->getData().size() + 1); - bytes[0] = 0xF0; - for (int j = 0; j < sysEx->getData().size(); j++) - { - bytes[j + 1] = sysEx->getData()[j]; - } - - EventData e; - e.type = EventType::SystemExclusive; - e.tick = sysEx->getTick(); - - (*updateSequenceEvents.trackSnapshots)[trackIndex] - .push_back(e); - hasImportedEvents = true; - } - } - else if (const auto noteAfterTouch = - std::dynamic_pointer_cast(me.lock()); - noteAfterTouch) - { - EventData e; - e.type = EventType::PolyPressure; - e.tick = noteAfterTouch->getTick(); - e.noteNumber = NoteNumber(noteAfterTouch->getNoteValue()); - e.amount = noteAfterTouch->getAmount(); - (*updateSequenceEvents.trackSnapshots)[trackIndex].push_back(e); - hasImportedEvents = true; - } - else if (const auto channelAfterTouch = - std::dynamic_pointer_cast( - me.lock()); - channelAfterTouch) - { - EventData e; - e.type = EventType::ChannelPressure; - e.amount = channelAfterTouch->getAmount(); - (*updateSequenceEvents.trackSnapshots)[trackIndex].push_back(e); - hasImportedEvents = true; - } - else if (const auto programChange = - std::dynamic_pointer_cast(me.lock()); - programChange) - { - EventData e; - e.type = EventType::ProgramChange; - e.programChangeProgramIndex = - ProgramIndex(programChange->getProgramNumber()); - (*updateSequenceEvents.trackSnapshots)[trackIndex].push_back(e); - hasImportedEvents = true; - } - else if (const auto trackName = - std::dynamic_pointer_cast(me.lock()); - trackName && !trackName->getTrackName().empty()) - { - track.name = trackName->getTrackName().substr( - 0, Mpc2000XlSpecs::MAX_TRACK_NAME_LENGTH); - } - else if (const auto controller = - std::dynamic_pointer_cast(me.lock()); - controller) - { - EventData e; - e.type = EventType::ControlChange; - e.controllerNumber = controller->getControllerType(); - e.controllerValue = controller->getValue(); - (*updateSequenceEvents.trackSnapshots)[trackIndex].push_back(e); - hasImportedEvents = true; - } - else if (const auto pitchBend = - std::dynamic_pointer_cast(me.lock()); - pitchBend) - { - EventData e; - e.type = EventType::PitchBend; - e.amount = pitchBend->getBendAmount(); - (*updateSequenceEvents.trackSnapshots)[trackIndex].push_back(e); - hasImportedEvents = true; - } - } - - track.used = hasImportedEvents; - } - - mpc.getSequencer()->getStateManager()->enqueue(updateSequenceTracks); - mpc.getSequencer()->getStateManager()->enqueue(updateSequenceEvents); -} - -bool MidiReader::isInteger(const std::string &s) -{ - for (auto &c : s) - { - if (!std::isdigit(c)) - { - return false; - } - } - - return true; -} - -int MidiReader::getNumberOfNoteOns( - const int noteValue, - const std::vector> &allNotes) -{ - int counter = 0; - - for (auto &no : allNotes) - { - if (const auto noteOn = std::dynamic_pointer_cast(no)) - { - if (noteOn->getNoteValue() == noteValue) - { - counter++; - } - } - } - - return counter; -} - -int MidiReader::getNumberOfNotes(const int noteValue, - const std::vector &allNotes) -{ - int counter = 0; - - for (auto &ne : allNotes) - { - if (ne.noteNumber == noteValue) - { - counter++; - } - } - - return counter; -} diff --git a/src/main/file/mid/MidiReader.hpp b/src/main/file/mid/MidiReader.hpp deleted file mode 100644 index bbef9165..00000000 --- a/src/main/file/mid/MidiReader.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "file/mid/MidiFile.hpp" - -#include "sequencer/EventData.hpp" - -#include -#include -#include - -namespace mpc -{ - class Mpc; -} - -namespace mpc::file::mid::event -{ - class ChannelEvent; -} - -namespace mpc::sequencer -{ - class Sequence; - class NoteOnEvent; -} // namespace mpc::sequencer - -namespace mpc::disk -{ - class MpcFile; -} - -namespace mpc::file::mid -{ - class MidiReader - { - public: - MidiReader(std::shared_ptr, - const std::weak_ptr &dest); - void parseSequence(Mpc &) const; - - private: - static bool isInteger(const std::string &); - - std::unique_ptr midiFile; - std::weak_ptr dest; - - static int getNumberOfNoteOns( - int noteValue, - const std::vector> &allNotes); - static int - getNumberOfNotes(int noteValue, - const std::vector &allNotes); - }; -} // namespace mpc::file::mid diff --git a/src/main/file/mid/MidiTrack.cpp b/src/main/file/mid/MidiTrack.cpp deleted file mode 100644 index 94725741..00000000 --- a/src/main/file/mid/MidiTrack.cpp +++ /dev/null @@ -1,301 +0,0 @@ -#include "file/mid/MidiTrack.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/NoteOn.hpp" -#include "file/mid/event/meta/EndOfTrack.hpp" -#include "file/mid/event/meta/Tempo.hpp" -#include "file/mid/event/meta/TimeSignatureEvent.hpp" -#include "file/mid/util/MidiUtil.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -#include -#include - -#include - -using namespace mpc::file::mid; -using namespace mpc::file::mid::util; -using namespace mpc::file::mid::event; - -MidiTrack::MidiTrack() -{ - mSize = 0; - mSizeNeedsRecalculating = false; - mClosed = false; - mEndOfTrackDelta = 0; -} - -MidiTrack::MidiTrack(const std::shared_ptr &stream) -{ - mSize = 0; - mSizeNeedsRecalculating = false; - mClosed = false; - mEndOfTrackDelta = 0; - std::vector buffer(4); - - stream->read(&buffer[0], buffer.size()); - - if (!MidiUtil::bytesEqual(buffer, IDENTIFIER, 0, 4)) - { - std::string error = "Track identifier did not match MTrk!"; - throw std::invalid_argument(error); - } - - stream->read(&buffer[0], buffer.size()); - - mSize = MidiUtil::bytesToInt(buffer, 0, 4); - buffer.clear(); - buffer.resize(mSize); - stream->read(&buffer[0], mSize); - - readTrackData(buffer); -} - -const bool MidiTrack::VERBOSE; - -std::vector MidiTrack::IDENTIFIER{'M', 'T', 'r', 'k'}; - -MidiTrack *MidiTrack::createTempoTrack() -{ - auto track = new MidiTrack(); - track->insertEvent(std::make_shared()); - track->insertEvent(std::make_shared()); - return track; -} - -void MidiTrack::readTrackData(std::vector &data) -{ - std::stringstream in(std::string(data.begin(), data.end())); - in.unsetf(std::ios_base::skipws); - - int totalTicks = 0; - - auto available = (int)in.rdbuf()->in_avail(); - - while ((available = (int)in.rdbuf()->in_avail() > 0)) - { - auto delta = VariableLengthInt(in); - int value = delta.getValue(); - totalTicks += value; - - auto event = MidiEvent::parseEvent(totalTicks, value, in); - - if (!event) - { - MLOG("MidiTrack readTrackData skipped an event!"); - continue; - } - - if (std::dynamic_pointer_cast(event)) - { - mEndOfTrackDelta = event->getDelta(); - break; - } - - mEvents.emplace_back(event); - } -} - -std::vector> MidiTrack::getEvents() const -{ - std::vector> res; - for (auto &e : mEvents) - { - res.push_back(e); - } - return res; -} - -int MidiTrack::getEventCount() const -{ - return mEvents.size(); -} - -int MidiTrack::getSize() -{ - if (mSizeNeedsRecalculating) - { - recalculateSize(); - } - return mSize; -} - -int MidiTrack::getLengthInTicks() -{ - if (mEvents.size() == 0) - { - return 0; - } - auto E = *std::next(mEvents.begin(), (int)mEvents.size() - 1); - return E->getTick(); -} - -int MidiTrack::getEndOfTrackDelta() const -{ - return mEndOfTrackDelta; -} - -void MidiTrack::setEndOfTrackDelta(int delta) -{ - mEndOfTrackDelta = delta; -} - -void MidiTrack::insertNote(int channel, int pitch, int velocity, int tick, - int duration) -{ - insertEvent(std::make_shared(tick, channel, pitch, velocity)); - insertEvent(std::make_shared(tick + duration, channel, pitch, 0)); -} - -void MidiTrack::insertEvent(const std::weak_ptr &newE) -{ - auto newEvent = newE.lock(); - if (!newEvent) - { - return; - } - if (mClosed) - { - // npc(::java::lang::System::err())->println(u"Error: Cannot add an - // event to a closed track."_j); - return; - } - std::shared_ptr prev; - std::shared_ptr next; - if (mEvents.size() > 0) - { - prev = mEvents.back(); - } - - /* - for (auto& n : mEvents) { - next = n; - if (next->getTick() > newEvent->getTick()) { - break; - } - prev = next; - next.reset(); - } - */ - - mEvents.push_back(newEvent); - mSizeNeedsRecalculating = true; - - if (prev) - { - newEvent->setDelta(newEvent->getTick() - prev->getTick()); - } - else - { - newEvent->setDelta(newEvent->getTick()); - } - if (next) - { - next->setDelta(next->getTick() - newEvent->getTick()); - } - - mSize += newEvent->getSize(); - - if (std::dynamic_pointer_cast(newEvent)) - { - if (next) - { - throw std::invalid_argument( - "Attempting to insert EndOfTrack before an existing event. Use " - "closeTrack() when finished with MidiTrack."); - } - mClosed = true; - } -} - -bool MidiTrack::removeEvent(MidiEvent *e) const -{ - std::shared_ptr prev; - std::shared_ptr curr; - std::shared_ptr next; - - for (auto &n : mEvents) - { - next = n; - if (e == curr.get()) - { - break; - } - prev = curr; - curr = next; - next = nullptr; - } - if (!next) - { - // return mEvents.erase(curr); - return false; - } - // if (!mEvents.erase(curr)) { - // return false; - //} - if (prev != nullptr) - { - next->setDelta(next->getTick() - prev->getTick()); - } - else - { - next->setDelta(next->getTick()); - } - return true; -} - -void MidiTrack::closeTrack() -{ - int lastTick = 0; - if (mEvents.size() > 0) - { - auto last = std::dynamic_pointer_cast( - *std::next(mEvents.begin(), (int)mEvents.size() - 1)); - lastTick = last->getTick(); - } - insertEvent( - std::make_shared(lastTick + mEndOfTrackDelta, 0)); -} - -void MidiTrack::recalculateSize() -{ - mSize = 0; - std::shared_ptr last; - for (auto &e : mEvents) - { - mSize += e->getSize(); - if (last && !e->requiresStatusByte(last.get())) - { - mSize--; - } - last = e; - } - mSizeNeedsRecalculating = false; -} - -void MidiTrack::writeToOutputStream(const std::shared_ptr &stream) -{ - if (!mClosed) - { - closeTrack(); - } - - if (mSizeNeedsRecalculating) - { - recalculateSize(); - } - - stream->write(&IDENTIFIER[0], IDENTIFIER.size()); - - auto trackSizeBuffer = MidiUtil::intToBytes(mSize, 4); - stream->write(&trackSizeBuffer[0], trackSizeBuffer.size()); - - std::shared_ptr lastEvent; - - for (auto &event : mEvents) - { - event->writeToOutputStream(*stream.get(), - event->requiresStatusByte(lastEvent.get())); - lastEvent = event; - } -} diff --git a/src/main/file/mid/MidiTrack.hpp b/src/main/file/mid/MidiTrack.hpp deleted file mode 100644 index 4c5ca0d5..00000000 --- a/src/main/file/mid/MidiTrack.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace mpc::file::mid::event -{ - class MidiEvent; -} - -namespace mpc::file::mid -{ - class MidiTrack - { - - static const bool VERBOSE = false; - static std::vector IDENTIFIER; - - int mSize; - bool mSizeNeedsRecalculating; - bool mClosed; - int mEndOfTrackDelta; - std::vector> mEvents; - - public: - static MidiTrack *createTempoTrack(); - - private: - void readTrackData(std::vector &data); - - public: - std::vector> getEvents() const; - int getEventCount() const; - int getSize(); - int getLengthInTicks(); - int getEndOfTrackDelta() const; - void setEndOfTrackDelta(int delta); - void insertNote(int channel, int pitch, int velocity, int tick, - int duration); - void insertEvent(const std::weak_ptr &newEvent); - bool removeEvent(event::MidiEvent *E) const; - void closeTrack(); - - private: - void recalculateSize(); - - public: - void writeToOutputStream(const std::shared_ptr &); - - MidiTrack(); - MidiTrack(const std::shared_ptr &); - }; -} // namespace mpc::file::mid diff --git a/src/main/file/mid/MidiWriter.cpp b/src/main/file/mid/MidiWriter.cpp deleted file mode 100644 index b9d00741..00000000 --- a/src/main/file/mid/MidiWriter.cpp +++ /dev/null @@ -1,389 +0,0 @@ -#include "file/mid/MidiWriter.hpp" - -#include "file/mid/MidiFile.hpp" -#include "file/mid/MidiTrack.hpp" -#include "file/mid/event/ChannelAftertouch.hpp" -#include "file/mid/event/Controller.hpp" -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/NoteAftertouch.hpp" -#include "file/mid/event/NoteOff.hpp" -#include "file/mid/event/NoteOn.hpp" -#include "file/mid/event/PitchBend.hpp" -#include "file/mid/event/ProgramChange.hpp" -#include "file/mid/event/SystemExclusive.hpp" -#include "file/mid/event/meta/InstrumentName.hpp" -#include "file/mid/event/meta/FrameRate.hpp" -#include "file/mid/event/meta/SmpteOffset.hpp" -#include "file/mid/event/meta/Tempo.hpp" -#include "file/mid/event/meta/Text.hpp" -#include "file/mid/event/meta/TimeSignatureEvent.hpp" -#include "file/mid/event/meta/TrackName.hpp" -#include "disk/AbstractDisk.hpp" -#include "sequencer/ChannelPressureEvent.hpp" -#include "sequencer/ControlChangeEvent.hpp" -#include "sequencer/MixerEvent.hpp" -#include "sequencer/Sequence.hpp" -#include "sequencer/Track.hpp" -#include "sequencer/PitchBendEvent.hpp" -#include "sequencer/PolyPressureEvent.hpp" -#include "sequencer/ProgramChangeEvent.hpp" -#include "sequencer/SystemExclusiveEvent.hpp" -#include "sequencer/TempoChangeEvent.hpp" - -#include "StrUtil.hpp" -#include "file/ByteUtil.hpp" - -#include -#include "file/mid/util/MidiUtil.hpp" -#include "sequencer/NoteOnEvent.hpp" - -using namespace mpc::file::mid::event; -using namespace mpc::file::mid; - -MidiWriter::MidiWriter(sequencer::Sequence *sequence) -{ - this->sequence = sequence; - mf = std::make_unique(); - auto meta = std::make_shared(); - auto seqParams = std::make_shared( - 0, 0, "LOOP=ON START=000 END=END TEMPO=ON "); - meta->insertEvent(seqParams); - auto seqName = std::make_shared( - 0, 0, - "MPC2000XL 1.00 " + StrUtil::padRight(sequence->getName(), " ", 16)); - meta->insertEvent(seqName); - std::vector> tempos; - int previousTick = 0; - auto tempo = sequence->getInitialTempo(); - auto mpqn = static_cast(6.0E7 / tempo); - tempos.push_back(std::make_shared(0, 0, mpqn)); - - for (auto &e : sequence->getTempoChangeEvents()) - { - tempo = e->getTempo(); - mpqn = static_cast(6.0E7 / tempo); - tempos.push_back(std::make_shared( - e->getTick(), e->getTick() - previousTick, mpqn)); - previousTick = e->getTick(); - } - - for (auto &t : tempos) - { - meta->insertEvent(t); - } - - meta->insertEvent(std::make_shared( - 0, 0, meta::FrameRate::FRAME_RATE_25, 0, 0, 0, 0, 0)); - std::set> tSigs; - auto tSigTick = 0; - auto lastAdded = std::vector(3); - - for (int i = 0; i < sequence->getLastBarIndex() + 1; i++) - { - auto actualTick = tSigTick; - if (lastAdded[0] == sequence->getNumerator(i) && - lastAdded[1] == sequence->getDenominator(i)) - { - actualTick = lastAdded[2]; - } - - auto vec = std::vector{sequence->getNumerator(i), - sequence->getDenominator(i), actualTick}; - - if (tSigs.emplace(vec).second) - { - lastAdded[0] = sequence->getNumerator(i); - lastAdded[1] = sequence->getDenominator(i); - lastAdded[2] = actualTick; - } - - tSigTick += sequence->getBarLength(i); - } - previousTick = 0; - for (auto &ia : tSigs) - { - meta->insertEvent(std::make_shared( - ia[2], ia[2] - previousTick, ia[0], ia[1], 24, 8)); - previousTick = ia[2]; - } - meta->setEndOfTrackDelta(sequence->getLastTick()); - mf->addTrack(meta); - - int firstUsedTrackIndex = -1; - int lastUsedTrackIndex = -1; - - for (int i = 0; i < 64; i++) - { - if (sequence->getTrack(i)->isUsed()) - { - if (firstUsedTrackIndex == -1) - { - firstUsedTrackIndex = i; - } - lastUsedTrackIndex = i; - } - } - - for (int trackIndex = firstUsedTrackIndex; - trackIndex >= 0 && trackIndex <= lastUsedTrackIndex; trackIndex++) - { - noteOffs.clear(); - variations.clear(); - noteOns.clear(); - miscEvents.clear(); - - auto t = sequence->getTrack(trackIndex); - - if (t->getIndex() > 63) - { - break; - } - - auto mt = std::make_shared(); - auto in = std::make_shared(0, 0, " "); - mt->insertEvent(in); - auto trackNumber = - StrUtil::padLeft(std::to_string(t->getIndex()), "0", 2); - std::string trackDevice = t->getDeviceIndex() == 0 ? "C0" : "E0"; - - if (t->getDeviceIndex() > 0) - { - auto value = stoi(trackDevice, nullptr, 16); - value += t->getDeviceIndex() - 1; - trackDevice = util::MidiUtil::byteToHex(static_cast(value)); - } - - const auto busIndex = util::MidiUtil::byteToHex( - static_cast(busTypeToIndex(t->getBusType()))); - const auto deviceNumber = util::MidiUtil::byteToHex( - static_cast(t->getDeviceIndex())); - - auto text = std::make_shared( - 0, 0, - "TRACK DATA:" + trackNumber + trackDevice + "006403 " + - deviceNumber + busIndex + deviceNumber + " "); - mt->insertEvent(text); - auto tn = std::make_shared( - 0, 0, StrUtil::padRight(t->getName(), " ", 16)); - mt->insertEvent(tn); - for (auto &event : t->getEvents()) - { - auto noteEvent = - std::dynamic_pointer_cast(event); - auto mpcSysExEvent = - std::dynamic_pointer_cast( - event); - auto pitchBendEvent = - std::dynamic_pointer_cast(event); - auto channelPressureEvent = - std::dynamic_pointer_cast( - event); - auto polyPressureEvent = - std::dynamic_pointer_cast(event); - auto controlChangeEvent = - std::dynamic_pointer_cast(event); - auto programChangeEvent = - std::dynamic_pointer_cast(event); - auto mixerEvent = - std::dynamic_pointer_cast(event); - if (noteEvent) - { - addNoteOn(std::make_shared( - noteEvent->getTick(), t->getIndex(), noteEvent->getNote(), - noteEvent->getVelocity())); - noteOffs.push_back(std::make_shared( - noteEvent->getTick() + noteEvent->getDuration(), - t->getIndex(), noteEvent->getNote(), 0)); - auto variation = false; - std::shared_ptr varNoteOff; - auto varType = noteEvent->getVariationType(); - auto varVal = noteEvent->getVariationValue(); - if (varType == 0 && varVal != 64) - { - variation = true; - } - - if ((varType == 1 || varType == 2) && varVal != 0) - { - variation = true; - } - - if (varType == 3 && varVal != 50) - { - variation = true; - } - - if (variation) - { - varNoteOff = std::make_shared( - noteEvent->getTick(), t->getIndex(), varType, varVal); - } - - if (varNoteOff != nullptr) - { - variations.push_back(varNoteOff); - } - } - else if (mpcSysExEvent) - { - auto sysExData = std::vector{ - static_cast(mpcSysExEvent->getByteA()), - static_cast(mpcSysExEvent->getByteB())}; - - auto see = std::make_shared( - 240, mpcSysExEvent->getTick(), sysExData); - miscEvents.push_back(see); - } - else if (pitchBendEvent) - { - auto amountBytes = - ByteUtil::ushort2bytes(pitchBendEvent->getAmount() + 8192); - auto pb = std::make_shared(pitchBendEvent->getTick(), - 1, amountBytes[0] & 255, - amountBytes[1] & 255); - pb->setBendAmount(pitchBendEvent->getAmount() + 8192); - miscEvents.push_back(pb); - } - else if (channelPressureEvent) - { - auto ca = std::make_shared( - channelPressureEvent->getTick(), 1, - channelPressureEvent->getAmount()); - miscEvents.push_back(ca); - } - else if (polyPressureEvent) - { - auto na = std::make_shared( - polyPressureEvent->getTick(), 1, - polyPressureEvent->getNote(), - polyPressureEvent->getAmount()); - miscEvents.push_back(na); - } - else if (controlChangeEvent) - { - auto c = std::make_shared( - controlChangeEvent->getTick(), 1, - controlChangeEvent->getController(), - controlChangeEvent->getAmount()); - miscEvents.push_back(c); - } - else if (programChangeEvent) - { - auto pc = std::make_shared( - programChangeEvent->getTick(), 1, - programChangeEvent->getProgram()); - miscEvents.push_back(pc); - } - else if (mixerEvent) - { - auto sysExData = std::vector(8); - sysExData[0] = 71; - sysExData[1] = 0; - sysExData[2] = 68; - sysExData[3] = 69; - sysExData[4] = mixerEvent->getParameter() + 1; - sysExData[5] = mixerEvent->getPad(); - sysExData[6] = mixerEvent->getValue(); - sysExData[7] = 0xF7; - auto see = std::make_shared( - 240, mixerEvent->getTick(), sysExData); - miscEvents.push_back(see); - } - } - - for (auto i = 0; i < sequence->getLastTick(); i++) - { - for (auto &no : noteOffs) - { - if (no->getTick() == i) - { - mt->insertEvent(no); - } - } - - for (auto &var : variations) - { - if (var->getTick() == i) - { - mt->insertEvent(var); - } - } - - for (auto &no : noteOns) - { - if (no->getTick() == i) - { - mt->insertEvent(no); - } - } - - for (auto &e : miscEvents) - { - if (e->getTick() == i) - { - mt->insertEvent(e); - } - } - } - createDeltas(mt); - mf->addTrack(mt); - } - mf->setType(1); -} - -void MidiWriter::addNoteOn(const std::shared_ptr ¬eOn) -{ - for (auto &no : noteOffs) - { - if (no->getNoteValue() == noteOn->getNoteValue() && - no->getTick() > noteOn->getTick()) - { - no = std::make_shared(noteOn->getTick(), no->getChannel(), - no->getNoteValue(), 0); - } - } - noteOns.push_back(noteOn); -} - -void MidiWriter::createDeltas(const std::weak_ptr &midiTrack) const -{ - const auto mt = midiTrack.lock(); - std::shared_ptr previousEvent; - - for (auto &me : mt->getEvents()) - { - if (const auto event = me.lock()) - { - if (previousEvent) - { - if (event->getTick() != previousEvent->getTick()) - { - event->setDelta(event->getTick() - - previousEvent->getTick()); - } - else - { - event->setDelta(0); - } - } - previousEvent = event; - } - } - const auto previousTick = !previousEvent ? 0 : previousEvent->getTick(); - mt->setEndOfTrackDelta(sequence->getLastTick() - previousTick); -} - -void MidiWriter::writeToOStream( - const std::shared_ptr &_ostream) const -{ - const auto _ofstream = std::dynamic_pointer_cast(_ostream); - if (_ofstream) - { - _ofstream->unsetf(std::ios::skipws); - } - mf->writeToOutputStream(_ostream); - if (_ofstream) - { - _ofstream->close(); - } -} diff --git a/src/main/file/mid/MidiWriter.hpp b/src/main/file/mid/MidiWriter.hpp deleted file mode 100644 index b47bbc30..00000000 --- a/src/main/file/mid/MidiWriter.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "file/mid/event/NoteOn.hpp" -#include "file/mid/event/NoteOff.hpp" -#include "file/mid/MidiFile.hpp" -#include "file/mid/MidiTrack.hpp" - -#include - -namespace mpc::sequencer -{ - class Sequence; -} - -namespace mpc::file::mid -{ - class MidiWriter - { - public: - MidiWriter(sequencer::Sequence *sequence); - void writeToOStream(const std::shared_ptr &) const; - - private: - std::vector> noteOffs; - std::vector> variations; - std::vector> noteOns; - std::vector> miscEvents; - sequencer::Sequence *sequence; - std::unique_ptr mf; - - void addNoteOn(const std::shared_ptr ¬eOn); - void createDeltas(const std::weak_ptr &midiTrack) const; - }; -} // namespace mpc::file::mid diff --git a/src/main/file/mid/event/ChannelAftertouch.cpp b/src/main/file/mid/event/ChannelAftertouch.cpp deleted file mode 100644 index e52c0742..00000000 --- a/src/main/file/mid/event/ChannelAftertouch.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "file/mid/event/ChannelAftertouch.hpp" - -#include "file/mid/event/ChannelEvent.hpp" - -using namespace mpc::file::mid::event; - -ChannelAftertouch::ChannelAftertouch(int tick, int channel, int amount) - : ChannelEvent(tick, CHANNEL_AFTERTOUCH, channel, amount, 0) -{ -} - -ChannelAftertouch::ChannelAftertouch(int tick, int delta, int channel, - int amount) - : ChannelEvent(tick, delta, CHANNEL_AFTERTOUCH, channel, amount, 0) -{ -} - -int ChannelAftertouch::getAmount() const -{ - return mValue1; -} - -void ChannelAftertouch::setAmount(int p) -{ - mValue1 = p; -} diff --git a/src/main/file/mid/event/ChannelAftertouch.hpp b/src/main/file/mid/event/ChannelAftertouch.hpp deleted file mode 100644 index ab01d540..00000000 --- a/src/main/file/mid/event/ChannelAftertouch.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "file/mid/event/ChannelEvent.hpp" - -namespace mpc::file::mid::event -{ - class ChannelAftertouch : public ChannelEvent - { - public: - int getAmount() const; - void setAmount(int p); - - ChannelAftertouch(int tick, int channel, int amount); - ChannelAftertouch(int tick, int delta, int channel, int amount); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/ChannelEvent.cpp b/src/main/file/mid/event/ChannelEvent.cpp deleted file mode 100644 index d2fcb07a..00000000 --- a/src/main/file/mid/event/ChannelEvent.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "file/mid/event/ChannelEvent.hpp" - -#include "file/mid/event/ChannelAftertouch.hpp" -#include "file/mid/event/Controller.hpp" -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/NoteAftertouch.hpp" -#include "file/mid/event/NoteOff.hpp" -#include "file/mid/event/NoteOn.hpp" -#include "file/mid/event/PitchBend.hpp" -#include "file/mid/event/ProgramChange.hpp" - -using namespace mpc::file::mid::event; - -ChannelEvent::ChannelEvent(int tick, int type, int channel, int param1, - int param2) - : ChannelEvent(tick, 0, type, channel, param1, param2) -{ -} - -ChannelEvent::ChannelEvent(int tick, int delta, int type, int channel, - int param1, int param2) - : MidiEvent(tick, delta) -{ - mType = type & 0x0F; - mChannel = channel & 0x0F; - mValue1 = param1 & 0xFF; - mValue2 = param2 & 0xFF; -} - -int ChannelEvent::getType() -{ - return mType; -} - -void ChannelEvent::setChannel(int c) -{ - if (c < 0) - { - c = 0; - } - else if (c > 15) - { - c = 15; - } - mChannel = c; -} - -int ChannelEvent::getChannel() -{ - return mChannel; -} - -int ChannelEvent::getEventSize() -{ - switch (mType) - { - case PROGRAM_CHANGE: - case CHANNEL_AFTERTOUCH: - return 2; - default: - return 3; - } -} - -int ChannelEvent::compareTo(MidiEvent *o) -{ - return 1; // hack to emulate MPC2000XL MID writing. this makes sure the - // event order is not changed after they are added -} - -bool ChannelEvent::requiresStatusByte(MidiEvent *prevEvent) -{ - if (prevEvent == nullptr) - { - return true; - } - if (dynamic_cast(prevEvent) == nullptr) - { - return true; - } - auto ce = dynamic_cast(prevEvent); - return !(mType == ce->getType() && mChannel == ce->getChannel()); -} - -void ChannelEvent::writeToOutputStream(std::ostream &out, bool writeType) -{ - MidiEvent::writeToOutputStream(out, writeType); - - if (writeType) - { - auto typeChannel = (mType << 4) + mChannel; - out << (char)typeChannel; - } - - out << (char)mValue1; - - if (mType != PROGRAM_CHANGE && mType != CHANNEL_AFTERTOUCH) - { - out << (char)mValue2; - } -} - -std::shared_ptr -ChannelEvent::parseChannelEvent(int tick, int delta, int type, int channel, - std::stringstream &in) -{ - int val1 = in.get(); - int val2 = 0; - if (type != PROGRAM_CHANGE && type != CHANNEL_AFTERTOUCH) - { - val2 = in.get(); - } - switch (type) - { - case NOTE_OFF: - return std::make_shared(tick, delta, channel, val1, val2); - case NOTE_ON: - return std::make_shared(tick, delta, channel, val1, val2); - case NOTE_AFTERTOUCH: - return std::make_shared(tick, delta, channel, val1, - val2); - case CONTROLLER: - return std::make_shared(tick, delta, channel, val1, - val2); - case PROGRAM_CHANGE: - return std::make_shared(tick, delta, channel, val1); - case CHANNEL_AFTERTOUCH: - return std::make_shared(tick, delta, channel, - val1); - case PITCH_BEND: - return std::make_shared(tick, delta, channel, val1, - val2); - default: - return std::make_shared(tick, delta, type, channel, - val1, val2); - } -} - -const int ChannelEvent::NOTE_OFF; -const int ChannelEvent::NOTE_ON; -const int ChannelEvent::NOTE_AFTERTOUCH; -const int ChannelEvent::CONTROLLER; -const int ChannelEvent::PROGRAM_CHANGE; -const int ChannelEvent::CHANNEL_AFTERTOUCH; -const int ChannelEvent::PITCH_BEND; diff --git a/src/main/file/mid/event/ChannelEvent.hpp b/src/main/file/mid/event/ChannelEvent.hpp deleted file mode 100644 index c742bf4d..00000000 --- a/src/main/file/mid/event/ChannelEvent.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "file/mid/event/MidiEvent.hpp" - -namespace mpc::file::mid::event -{ - - class ChannelEvent : public MidiEvent - { - - public: - int mType{0}; - int mChannel{0}; - int mValue1{0}; - int mValue2{0}; - - virtual int getType(); - virtual void setChannel(int c); - virtual int getChannel(); - - int getEventSize() override; - - virtual int compareTo(MidiEvent *other); - virtual bool requiresStatusByte(MidiEvent *prevEvent) override; - virtual void writeToOutputStream(std::ostream &out, - bool writeType) override; - static std::shared_ptr - parseChannelEvent(int tick, int delta, int type, int channel, - std::stringstream &in); - - static const int NOTE_OFF{8}; - static const int NOTE_ON{9}; - static const int NOTE_AFTERTOUCH{10}; - static const int CONTROLLER{11}; - static const int PROGRAM_CHANGE{12}; - static const int CHANNEL_AFTERTOUCH{13}; - static const int PITCH_BEND{14}; - - ChannelEvent(int tick, int type, int channel, int param1, int param2); - ChannelEvent(int tick, int delta, int type, int channel, int param1, - int param2); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/Controller.cpp b/src/main/file/mid/event/Controller.cpp deleted file mode 100644 index 1078936e..00000000 --- a/src/main/file/mid/event/Controller.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "file/mid/event/Controller.hpp" - -#include "file/mid/event/ChannelEvent.hpp" - -using namespace mpc::file::mid::event; - -Controller::Controller(int tick, int channel, int controllerType, int value) - : ChannelEvent(tick, CONTROLLER, channel, controllerType, value) -{ -} - -Controller::Controller(int tick, int delta, int channel, int controllerType, - int value) - : ChannelEvent(tick, delta, CONTROLLER, channel, controllerType, value) -{ -} - -int Controller::getControllerType() const -{ - return mValue1; -} - -int Controller::getValue() const -{ - return mValue2; -} - -void Controller::setControllerType(int t) -{ - mValue1 = t; -} - -void Controller::setValue(int v) -{ - mValue2 = v; -} diff --git a/src/main/file/mid/event/Controller.hpp b/src/main/file/mid/event/Controller.hpp deleted file mode 100644 index b637b5d3..00000000 --- a/src/main/file/mid/event/Controller.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "file/mid/event/ChannelEvent.hpp" - -namespace mpc::file::mid::event -{ - class Controller : public ChannelEvent - { - - public: - int getControllerType() const; - int getValue() const; - void setControllerType(int t); - void setValue(int v); - - Controller(int tick, int channel, int controllerType, int value); - Controller(int tick, int delta, int channel, int controllerType, - int value); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/MidiEvent.cpp b/src/main/file/mid/event/MidiEvent.cpp deleted file mode 100644 index cf4c54a6..00000000 --- a/src/main/file/mid/event/MidiEvent.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "file/mid/event/MidiEvent.hpp" - -#include "file/mid/event/ChannelEvent.hpp" -#include "file/mid/event/SystemExclusive.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" - -using namespace mpc::file::mid::event; - -MidiEvent::MidiEvent(int tick, int delta) -{ - mTick = tick; - mDelta = util::VariableLengthInt(delta); -} - -int MidiEvent::getTick() -{ - return mTick; -} - -int MidiEvent::getDelta() -{ - return mDelta.getValue(); -} - -void MidiEvent::setDelta(int d) -{ - mDelta.setValue(d); -} - -int MidiEvent::getSize() -{ - return getEventSize() + mDelta.getByteCount(); -} - -bool MidiEvent::requiresStatusByte(MidiEvent *prevEvent) -{ - if (prevEvent == nullptr) - { - return true; - } - - if (dynamic_cast(this) != nullptr) - { - return true; - } - - if (typeid(this) == typeid(prevEvent)) - { - return false; - } - - return true; -} - -void MidiEvent::writeToOutputStream(std::ostream &out, bool writeType) -{ - auto bytes = mDelta.getBytes(); - out.write(&bytes[0], bytes.size()); -} - -int MidiEvent::sId = -1; -int MidiEvent::sType = -1; -int MidiEvent::sChannel = -1; - -std::shared_ptr MidiEvent::parseEvent(int tick, int delta, - std::stringstream &in) -{ - auto reset = false; - - auto pos = in.tellg(); - - auto id = in.get() & 0xFF; - - if (!verifyIdentifier(id)) - { - in.seekg(pos); - reset = true; - } - - if (sType >= 8 && sType <= 14) - { - return ChannelEvent::parseChannelEvent(tick, delta, sType, sChannel, - in); - } - if (sId == 255) - { - return meta::MetaEvent::parseMetaEvent(tick, delta, in); - } - if (sId == 240 || sId == 247) - { - auto size = util::VariableLengthInt(in); - auto data = std::vector(size.getValue()); - in.read(&data[0], data.size()); - return std::make_shared(sId, tick, delta, data); - } - std::string error = - "Unable to handle status byte, skipping: " + std::to_string(sId); - if (reset) - { - in.ignore(1); - } - - return {}; -} - -bool MidiEvent::verifyIdentifier(int id) -{ - sId = id; - auto type = id >> 4; - auto channel = id & 15; - if (type >= 8 && type <= 14) - { - sId = id; - sType = type; - sChannel = channel; - } - else if (id == 255) - { - sId = id; - sType = -1; - sChannel = -1; - } - else if (type == 15) - { - sId = id; - sType = type; - sChannel = -1; - } - else - { - return false; - } - return true; -} - -std::string MidiEvent::toString() -{ - return std::to_string(mTick) + " (" + std::to_string(mDelta.getValue()) + - "): " + typeid(this).name(); -} diff --git a/src/main/file/mid/event/MidiEvent.hpp b/src/main/file/mid/event/MidiEvent.hpp deleted file mode 100644 index 4847b574..00000000 --- a/src/main/file/mid/event/MidiEvent.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "file/mid/util/VariableLengthInt.hpp" - -#include -#include -#include - -namespace mpc::file::mid::event -{ - class MidiEvent - { - public: - int mTick = 0; - util::VariableLengthInt mDelta; - - virtual int getTick(); - virtual int getDelta(); - virtual void setDelta(int d); - - virtual int getEventSize() = 0; - - virtual int getSize(); - virtual bool requiresStatusByte(MidiEvent *prevEvent); - virtual void writeToOutputStream(std::ostream &out, bool writeType); - - private: - static int sId; - static int sType; - static int sChannel; - - public: - static std::shared_ptr parseEvent(int tick, int delta, - std::stringstream &in); - - private: - static bool verifyIdentifier(int id); - - public: - virtual std::string toString(); - - MidiEvent(int tick, int delta); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/NoteAftertouch.cpp b/src/main/file/mid/event/NoteAftertouch.cpp deleted file mode 100644 index 7ec169cf..00000000 --- a/src/main/file/mid/event/NoteAftertouch.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "file/mid/event/NoteAftertouch.hpp" - -#include "file/mid/event/ChannelEvent.hpp" - -using namespace mpc::file::mid::event; - -NoteAftertouch::NoteAftertouch(int tick, int channel, int note, int amount) - : ChannelEvent(tick, NOTE_AFTERTOUCH, channel, note, amount) -{ -} - -NoteAftertouch::NoteAftertouch(int tick, int delta, int channel, int note, - int amount) - : ChannelEvent(tick, delta, NOTE_AFTERTOUCH, channel, note, amount) -{ -} - -int NoteAftertouch::getNoteValue() const -{ - return mValue1; -} - -int NoteAftertouch::getAmount() const -{ - return mValue2; -} - -void NoteAftertouch::setNoteValue(int p) -{ - mValue1 = p; -} - -void NoteAftertouch::setAmount(int a) -{ - mValue2 = a; -} diff --git a/src/main/file/mid/event/NoteAftertouch.hpp b/src/main/file/mid/event/NoteAftertouch.hpp deleted file mode 100644 index c98e7f8e..00000000 --- a/src/main/file/mid/event/NoteAftertouch.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "file/mid/event/ChannelEvent.hpp" - -namespace mpc::file::mid::event -{ - class NoteAftertouch : public ChannelEvent - { - - public: - int getNoteValue() const; - int getAmount() const; - void setNoteValue(int p); - void setAmount(int a); - - NoteAftertouch(int tick, int channel, int note, int amount); - NoteAftertouch(int tick, int delta, int channel, int note, int amount); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/NoteOff.cpp b/src/main/file/mid/event/NoteOff.cpp deleted file mode 100644 index 13e41020..00000000 --- a/src/main/file/mid/event/NoteOff.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "file/mid/event/NoteOff.hpp" - -#include "file/mid/event/ChannelEvent.hpp" - -using namespace mpc::file::mid::event; - -NoteOff::NoteOff(int tick, int channel, int note, int velocity) - : ChannelEvent(tick, NOTE_OFF, channel, note, velocity) -{ -} - -NoteOff::NoteOff(int tick, int delta, int channel, int note, int velocity) - : ChannelEvent(tick, delta, NOTE_OFF, channel, note, velocity) -{ -} - -int NoteOff::getNoteValue() const -{ - return mValue1; -} - -int NoteOff::getVelocity() const -{ - return mValue2; -} - -void NoteOff::setNoteValue(int p) -{ - mValue1 = p; -} - -void NoteOff::setVelocity(int v) -{ - mValue2 = v; -} diff --git a/src/main/file/mid/event/NoteOff.hpp b/src/main/file/mid/event/NoteOff.hpp deleted file mode 100644 index 725ef335..00000000 --- a/src/main/file/mid/event/NoteOff.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "file/mid/event/ChannelEvent.hpp" - -namespace mpc::file::mid::event -{ - class NoteOff : public ChannelEvent - { - public: - int getNoteValue() const; - int getVelocity() const; - void setNoteValue(int p); - void setVelocity(int v); - - NoteOff(int tick, int channel, int note, int velocity); - NoteOff(int tick, int delta, int channel, int note, int velocity); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/NoteOn.cpp b/src/main/file/mid/event/NoteOn.cpp deleted file mode 100644 index 1a0baa08..00000000 --- a/src/main/file/mid/event/NoteOn.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "file/mid/event/NoteOn.hpp" - -#include "file/mid/event/ChannelEvent.hpp" - -using namespace mpc::file::mid::event; - -NoteOn::NoteOn(int tick, int channel, int note, int velocity) - : ChannelEvent(tick, NOTE_ON, channel, note, velocity) -{ -} - -NoteOn::NoteOn(int tick, int delta, int channel, int note, int velocity) - : ChannelEvent(tick, delta, NOTE_ON, channel, note, velocity) -{ -} - -int NoteOn::getNoteValue() const -{ - return mValue1; -} - -int NoteOn::getVelocity() const -{ - return mValue2; -} - -void NoteOn::setNoteValue(int p) -{ - mValue1 = p; -} - -void NoteOn::setVelocity(int v) -{ - mValue2 = v; -} diff --git a/src/main/file/mid/event/NoteOn.hpp b/src/main/file/mid/event/NoteOn.hpp deleted file mode 100644 index f3eed6fc..00000000 --- a/src/main/file/mid/event/NoteOn.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "file/mid/event/ChannelEvent.hpp" - -namespace mpc::file::mid::event -{ - class NoteOn : public ChannelEvent - { - - public: - typedef ChannelEvent super; - - int getNoteValue() const; - int getVelocity() const; - void setNoteValue(int p); - void setVelocity(int v); - - NoteOn(int tick, int channel, int note, int velocity); - NoteOn(int tick, int delta, int channel, int note, int velocity); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/PitchBend.cpp b/src/main/file/mid/event/PitchBend.cpp deleted file mode 100644 index fdacf0a4..00000000 --- a/src/main/file/mid/event/PitchBend.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "file/mid/event/PitchBend.hpp" - -#include "file/mid/event/ChannelEvent.hpp" - -using namespace mpc::file::mid::event; - -PitchBend::PitchBend(int tick, int channel, int lsb, int msb) - : ChannelEvent(tick, PITCH_BEND, channel, lsb, msb) -{ -} - -PitchBend::PitchBend(int tick, int delta, int channel, int lsb, int msb) - : ChannelEvent(tick, delta, PITCH_BEND, channel, lsb, msb) -{ -} - -int PitchBend::getLeastSignificantBits() const -{ - return mValue1; -} - -int PitchBend::getMostSignificantBits() const -{ - return mValue2; -} - -int PitchBend::getBendAmount() const -{ - auto y = (mValue2 & 127) << 7; - auto x = mValue1; - return y + x; -} - -void PitchBend::setLeastSignificantBits(int p) -{ - mValue1 = p & 127; -} - -void PitchBend::setMostSignificantBits(int p) -{ - mValue2 = p & 127; -} - -void PitchBend::setBendAmount(int amount) -{ - amount = amount & 16383; - mValue1 = amount & 127; - mValue2 = amount >> 7; -} diff --git a/src/main/file/mid/event/PitchBend.hpp b/src/main/file/mid/event/PitchBend.hpp deleted file mode 100644 index aedcad8a..00000000 --- a/src/main/file/mid/event/PitchBend.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "file/mid/event/ChannelEvent.hpp" - -namespace mpc::file::mid::event -{ - class PitchBend : public ChannelEvent - { - - public: - int getLeastSignificantBits() const; - int getMostSignificantBits() const; - int getBendAmount() const; - void setLeastSignificantBits(int p); - void setMostSignificantBits(int p); - void setBendAmount(int amount); - - PitchBend(int tick, int channel, int lsb, int msb); - PitchBend(int tick, int delta, int channel, int lsb, int msb); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/ProgramChange.cpp b/src/main/file/mid/event/ProgramChange.cpp deleted file mode 100644 index b0e50e07..00000000 --- a/src/main/file/mid/event/ProgramChange.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "file/mid/event/ProgramChange.hpp" - -#include "file/mid/event/ChannelEvent.hpp" - -using namespace mpc::file::mid::event; - -ProgramChange::ProgramChange(int tick, int channel, int program) - : ChannelEvent(tick, PROGRAM_CHANGE, channel, program, 0) -{ -} - -ProgramChange::ProgramChange(int tick, int delta, int channel, int program) - : ChannelEvent(tick, delta, PROGRAM_CHANGE, channel, program, 0) -{ -} - -int ProgramChange::getProgramNumber() const -{ - return mValue1; -} - -void ProgramChange::setProgramNumber(int p) -{ - mValue1 = p; -} diff --git a/src/main/file/mid/event/ProgramChange.hpp b/src/main/file/mid/event/ProgramChange.hpp deleted file mode 100644 index 50bf6869..00000000 --- a/src/main/file/mid/event/ProgramChange.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "file/mid/event/ChannelEvent.hpp" - -namespace mpc::file::mid::event -{ - class ProgramChange : public ChannelEvent - { - public: - int getProgramNumber() const; - void setProgramNumber(int p); - - ProgramChange(int tick, int channel, int program); - ProgramChange(int tick, int delta, int channel, int program); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/SystemExclusive.cpp b/src/main/file/mid/event/SystemExclusive.cpp deleted file mode 100644 index 9cdf89e0..00000000 --- a/src/main/file/mid/event/SystemExclusive.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "file/mid/event/SystemExclusive.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event; - -SystemExclusiveEvent::SystemExclusiveEvent(int type, int tick, - const std::vector &data) - : SystemExclusiveEvent(type, tick, 0, data) -{ -} - -SystemExclusiveEvent::SystemExclusiveEvent(int type, int tick, int delta, - const std::vector &data) - : MidiEvent(tick, delta) -{ - mType = type & 255; - if (mType != 240 && mType != 247) - { - mType = 240; - } - mLength = new util::VariableLengthInt(data.size()); - mData = data; -} - -std::vector SystemExclusiveEvent::getData() -{ - return mData; -} - -void SystemExclusiveEvent::setData(std::vector data) -{ - mLength->setValue(data.size()); - mData = data; -} - -bool SystemExclusiveEvent::requiresStatusByte(MidiEvent *prevEvent) -{ - return true; -} - -void SystemExclusiveEvent::writeToOutputStream(std::ostream &out, - bool writeType) -{ - MidiEvent::writeToOutputStream(out, writeType); - out << (char)mType; - out.write(&mLength->getBytes()[0], mLength->getBytes().size()); - out.write(&mData[0], mData.size()); -} - -int SystemExclusiveEvent::compareTo(MidiEvent *other) -{ - if (this->mTick < other->mTick) - { - return -1; - } - - if (this->mTick > other->mTick) - { - return 1; - } - - if (mDelta.getValue() > other->mDelta.getValue()) - { - return -1; - } - - if (mDelta.getValue() < other->mDelta.getValue()) - { - return 1; - } - - if (dynamic_cast(other) != nullptr) - { - std::string curr; - - for (char c : mData) - { - curr.push_back(c); - } - - auto tmp = dynamic_cast(other)->mData; - - std::string comp; - - for (char c : tmp) - { - comp.push_back(c); - } - - return curr.compare(comp); - } - return 1; -} - -int SystemExclusiveEvent::getEventSize() -{ - return 1 + mLength->getByteCount() + mData.size(); -} diff --git a/src/main/file/mid/event/SystemExclusive.hpp b/src/main/file/mid/event/SystemExclusive.hpp deleted file mode 100644 index 12e182f7..00000000 --- a/src/main/file/mid/event/SystemExclusive.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "file/mid/event/MidiEvent.hpp" - -#include "file/mid/util/VariableLengthInt.hpp" - -namespace mpc::file::mid::event -{ - - class SystemExclusiveEvent : public MidiEvent - { - - int mType; - util::VariableLengthInt *mLength; - std::vector mData; - - public: - virtual std::vector getData(); - virtual void setData(std::vector data); - bool requiresStatusByte(MidiEvent *prevEvent) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - virtual int compareTo(MidiEvent *other); - - int getEventSize() override; - - SystemExclusiveEvent(int type, int tick, const std::vector &data); - SystemExclusiveEvent(int type, int tick, int delta, - const std::vector &data); - }; -} // namespace mpc::file::mid::event diff --git a/src/main/file/mid/event/meta/CopyrightNotice.cpp b/src/main/file/mid/event/meta/CopyrightNotice.cpp deleted file mode 100644 index 234dd45e..00000000 --- a/src/main/file/mid/event/meta/CopyrightNotice.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "file/mid/event/meta/CopyrightNotice.hpp" - -#include "file/mid/event/meta/MetaEvent.hpp" - -using namespace mpc::file::mid::event::meta; - -CopyrightNotice::CopyrightNotice(int tick, int delta, const std::string &text) - : TextualMetaEvent(tick, delta, COPYRIGHT_NOTICE, text) -{ -} - -void CopyrightNotice::setNotice(const std::string &t) -{ - setText(t); -} - -std::string CopyrightNotice::getNotice() -{ - return getText(); -} diff --git a/src/main/file/mid/event/meta/CopyrightNotice.hpp b/src/main/file/mid/event/meta/CopyrightNotice.hpp deleted file mode 100644 index 4912b91d..00000000 --- a/src/main/file/mid/event/meta/CopyrightNotice.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "file/mid/event/meta/TextualMetaEvent.hpp" - -#include - -namespace mpc::file::mid::event::meta -{ - class CopyrightNotice : public TextualMetaEvent - { - - public: - void setNotice(const std::string &t); - std::string getNotice(); - - CopyrightNotice(int tick, int delta, const std::string &text); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/CuePoint.cpp b/src/main/file/mid/event/meta/CuePoint.cpp deleted file mode 100644 index 40832a02..00000000 --- a/src/main/file/mid/event/meta/CuePoint.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "file/mid/event/meta/CuePoint.hpp" - -#include "file/mid/event/meta/MetaEvent.hpp" - -using namespace mpc::file::mid::event::meta; - -CuePoint::CuePoint(int tick, int delta, const std::string &marker) - : TextualMetaEvent(tick, delta, CUE_POINT, marker) -{ -} - -void CuePoint::setCue(const std::string &name) -{ - setText(name); -} - -std::string CuePoint::getCue() -{ - return getText(); -} diff --git a/src/main/file/mid/event/meta/CuePoint.hpp b/src/main/file/mid/event/meta/CuePoint.hpp deleted file mode 100644 index 285be89d..00000000 --- a/src/main/file/mid/event/meta/CuePoint.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "file/mid/event/meta/TextualMetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - class CuePoint : public TextualMetaEvent - { - - public: - void setCue(const std::string &name); - std::string getCue(); - - CuePoint(int tick, int delta, const std::string &marker); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/EndOfTrack.cpp b/src/main/file/mid/event/meta/EndOfTrack.cpp deleted file mode 100644 index ec5063f7..00000000 --- a/src/main/file/mid/event/meta/EndOfTrack.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "file/mid/event/meta/EndOfTrack.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -EndOfTrack::EndOfTrack(int tick, int delta) - : MetaEvent(tick, delta, END_OF_TRACK) -{ - mLength = util::VariableLengthInt(0); -} - -int EndOfTrack::getEventSize() -{ - return 3; -} - -void EndOfTrack::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - out << (char)0x00; -} - -void EndOfTrack::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -int EndOfTrack::compareTo(MidiEvent *other) const -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - if (dynamic_cast(other) == nullptr) - { - return 1; - } - return 0; -} diff --git a/src/main/file/mid/event/meta/EndOfTrack.hpp b/src/main/file/mid/event/meta/EndOfTrack.hpp deleted file mode 100644 index e2524c19..00000000 --- a/src/main/file/mid/event/meta/EndOfTrack.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -#include - -namespace mpc::file::mid::event::meta -{ - class EndOfTrack : public MetaEvent - { - - public: - int getEventSize() override; - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - - int compareTo(MidiEvent *other) const; - - EndOfTrack(int tick, int delta); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/FrameRate.cpp b/src/main/file/mid/event/meta/FrameRate.cpp deleted file mode 100644 index c2db42da..00000000 --- a/src/main/file/mid/event/meta/FrameRate.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "file/mid/event/meta/FrameRate.hpp" - -#include - -#ifdef __linux__ -#include -#endif // __linux__ - -using namespace mpc::file::mid::event::meta; - -FrameRate::FrameRate(const std::string &name, int ordinal, int v) -{ - this->name = name; - this->ordinal = ordinal; - value = v; -} - -FrameRate *FrameRate::FRAME_RATE_24 = new FrameRate("FRAME_RATE_24", 0, 0); -FrameRate *FrameRate::FRAME_RATE_25 = new FrameRate("FRAME_RATE_25", 1, 1); -FrameRate *FrameRate::FRAME_RATE_30_DROP = - new FrameRate("FRAME_RATE_30_DROP", 2, 2); -FrameRate *FrameRate::FRAME_RATE_30 = new FrameRate("FRAME_RATE_30", 3, 3); - -FrameRate *FrameRate::fromInt(int val) -{ - switch (val) - { - case 0: - return FRAME_RATE_24; - case 1: - return FRAME_RATE_25; - case 2: - return FRAME_RATE_30_DROP; - case 3: - return FRAME_RATE_30; - } - return nullptr; -} - -FrameRate *FrameRate::valueOf(const std::string &a0) -{ - if (FRAME_RATE_24->name == a0) - { - return FRAME_RATE_24; - } - if (FRAME_RATE_25->name == a0) - { - return FRAME_RATE_25; - } - if (FRAME_RATE_30->name == a0) - { - return FRAME_RATE_30; - } - if (FRAME_RATE_30_DROP->name == a0) - { - return FRAME_RATE_30_DROP; - } - throw std::invalid_argument("Illegal argument"); -} - -std::vector FrameRate::values() -{ - return std::vector{ - FRAME_RATE_24, - FRAME_RATE_25, - FRAME_RATE_30, - FRAME_RATE_30_DROP, - }; -} diff --git a/src/main/file/mid/event/meta/FrameRate.hpp b/src/main/file/mid/event/meta/FrameRate.hpp deleted file mode 100644 index 9ce7a2d3..00000000 --- a/src/main/file/mid/event/meta/FrameRate.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::mid::event::meta -{ - class FrameRate - { - std::string name; - int ordinal{-1}; - - public: - static FrameRate *FRAME_RATE_24; - static FrameRate *FRAME_RATE_25; - static FrameRate *FRAME_RATE_30_DROP; - static FrameRate *FRAME_RATE_30; - - int value{}; - - static FrameRate *fromInt(int val); - - private: - FrameRate(const std::string &name, int ordinal, int v); - - public: - static FrameRate *valueOf(const std::string &a0); - static std::vector values(); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/GenericMetaEvent.cpp b/src/main/file/mid/event/meta/GenericMetaEvent.cpp deleted file mode 100644 index 61b21f18..00000000 --- a/src/main/file/mid/event/meta/GenericMetaEvent.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "file/mid/event/meta/GenericMetaEvent.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -GenericMetaEvent::GenericMetaEvent(int tick, int delta, MetaEventData *info) - : MetaEvent(tick, delta, info->type) -{ - mData = info->data; - mLength = info->length; -} - -int GenericMetaEvent::getEventSize() -{ - return 1 + 1 + mLength.getByteCount() + mLength.getValue(); -} - -void GenericMetaEvent::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - auto length = mLength.getBytes(); - out.write(&length[0], length.size()); - out.write(&mData[0], mData.size()); -} - -void GenericMetaEvent::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -int GenericMetaEvent::compareTo(MidiEvent *other) -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - return 1; -} diff --git a/src/main/file/mid/event/meta/GenericMetaEvent.hpp b/src/main/file/mid/event/meta/GenericMetaEvent.hpp deleted file mode 100644 index b881b0e9..00000000 --- a/src/main/file/mid/event/meta/GenericMetaEvent.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - - class MetaEventData; - - class GenericMetaEvent : public MetaEvent - { - - std::vector mData; - - public: - int getEventSize() override; - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - - virtual int compareTo(MidiEvent *other); - - GenericMetaEvent(int tick, int delta, MetaEventData *info); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/InstrumentName.cpp b/src/main/file/mid/event/meta/InstrumentName.cpp deleted file mode 100644 index f6285397..00000000 --- a/src/main/file/mid/event/meta/InstrumentName.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "file/mid/event/meta/InstrumentName.hpp" - -#include "file/mid/event/meta/MetaEvent.hpp" - -using namespace mpc::file::mid::event::meta; - -InstrumentName::InstrumentName(int tick, int delta, const std::string &name) - : TextualMetaEvent(tick, delta, INSTRUMENT_NAME, name) -{ -} - -void InstrumentName::setName(const std::string &name) -{ - setText(name); -} - -std::string InstrumentName::getName() -{ - return getText(); -} diff --git a/src/main/file/mid/event/meta/InstrumentName.hpp b/src/main/file/mid/event/meta/InstrumentName.hpp deleted file mode 100644 index 97fb7014..00000000 --- a/src/main/file/mid/event/meta/InstrumentName.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "file/mid/event/meta/TextualMetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - class InstrumentName : public TextualMetaEvent - { - - public: - void setName(const std::string &name); - std::string getName(); - - InstrumentName(int tick, int delta, const std::string &name); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/KeySignature.cpp b/src/main/file/mid/event/meta/KeySignature.cpp deleted file mode 100644 index 5e74766d..00000000 --- a/src/main/file/mid/event/meta/KeySignature.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "file/mid/event/meta/KeySignature.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/GenericMetaEvent.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -KeySignature::KeySignature(int tick, int delta, int key, int scale) - : MetaEvent(tick, delta, KEY_SIGNATURE) -{ - setKey(key); - mScale = scale; - mLength = util::VariableLengthInt(2); -} - -const int KeySignature::SCALE_MAJOR; -const int KeySignature::SCALE_MINOR; - -void KeySignature::setKey(int key) -{ - mKey = static_cast(key); - if (mKey < -7) - { - mKey = -7; - } - else if (mKey > 7) - { - mKey = 7; - } -} - -int KeySignature::getKey() const -{ - return mKey; -} - -void KeySignature::setScale(int scale) -{ - mScale = scale; -} - -int KeySignature::getScale() const -{ - return mScale; -} - -int KeySignature::getEventSize() -{ - return 5; -} - -void KeySignature::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - out << (char)0x02; - out << (char)mKey; - out << (char)mScale; -} - -void KeySignature::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -std::shared_ptr KeySignature::parseKeySignature(int tick, int delta, - MetaEventData *info) -{ - if (info->length.getValue() != 2) - { - return std::make_shared(tick, delta, info); - } - int key = info->data[0]; - int scale = info->data[1]; - return std::make_shared(tick, delta, key, scale); -} - -int KeySignature::compareTo(MidiEvent *other) const -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - - if (dynamic_cast(other) == nullptr) - { - return 1; - } - - auto o = dynamic_cast(other); - - if (mKey != o->mKey) - { - return mKey < o->mKey ? -1 : 1; - } - - if (mScale != o->mScale) - { - return mKey < o->mScale ? -1 : 1; - } - - return 0; -} diff --git a/src/main/file/mid/event/meta/KeySignature.hpp b/src/main/file/mid/event/meta/KeySignature.hpp deleted file mode 100644 index 4dda0175..00000000 --- a/src/main/file/mid/event/meta/KeySignature.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - class MetaEventData; - - class KeySignature : public MetaEvent - { - - public: - static const int SCALE_MAJOR{0}; - static const int SCALE_MINOR{1}; - - private: - int mKey; - int mScale; - - public: - void setKey(int key); - int getKey() const; - void setScale(int scale); - int getScale() const; - - int getEventSize() override; - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - - static std::shared_ptr - parseKeySignature(int tick, int delta, MetaEventData *info); - int compareTo(MidiEvent *other) const; - - KeySignature(int tick, int delta, int key, int scale); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/Marker.cpp b/src/main/file/mid/event/meta/Marker.cpp deleted file mode 100644 index 5522d4cd..00000000 --- a/src/main/file/mid/event/meta/Marker.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "file/mid/event/meta/Marker.hpp" - -#include "file/mid/event/meta/MetaEvent.hpp" - -using namespace mpc::file::mid::event::meta; - -Marker::Marker(int tick, int delta, const std::string &marker) - : TextualMetaEvent(tick, delta, MARKER, marker) -{ -} - -void Marker::setMarkerName(const std::string &name) -{ - setText(name); -} - -std::string Marker::getMarkerName() -{ - return getText(); -} diff --git a/src/main/file/mid/event/meta/Marker.hpp b/src/main/file/mid/event/meta/Marker.hpp deleted file mode 100644 index 763ccf89..00000000 --- a/src/main/file/mid/event/meta/Marker.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "file/mid/event/meta/TextualMetaEvent.hpp" - -#include - -namespace mpc::file::mid::event::meta -{ - class Marker : public TextualMetaEvent - { - - public: - void setMarkerName(const std::string &name); - std::string getMarkerName(); - - Marker(int tick, int delta, const std::string &marker); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/MetaEvent.cpp b/src/main/file/mid/event/meta/MetaEvent.cpp deleted file mode 100644 index 62be86d3..00000000 --- a/src/main/file/mid/event/meta/MetaEvent.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "file/mid/event/meta/MetaEvent.hpp" - -#include "file/mid/event/meta/CopyrightNotice.hpp" -#include "file/mid/event/meta/CuePoint.hpp" -#include "file/mid/event/meta/EndOfTrack.hpp" -#include "file/mid/event/meta/GenericMetaEvent.hpp" -#include "file/mid/event/meta/InstrumentName.hpp" -#include "file/mid/event/meta/KeySignature.hpp" -#include "file/mid/event/meta/Marker.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/event/meta/MidiChannelPrefix.hpp" -#include "file/mid/event/meta/SequenceNumber.hpp" -#include "file/mid/event/meta/SequencerSpecificEvent.hpp" -#include "file/mid/event/meta/SmpteOffset.hpp" -#include "file/mid/event/meta/Tempo.hpp" -#include "file/mid/event/meta/Text.hpp" -#include "file/mid/event/meta/TimeSignatureEvent.hpp" -#include "file/mid/event/meta/TrackName.hpp" - -using namespace mpc::file::mid::event::meta; - -MetaEvent::MetaEvent(int tick, int delta, int type) : MidiEvent(tick, delta) -{ - mType = type & 255; -} - -void MetaEvent::writeToOutputStream(std::ostream &out, bool writeType) -{ - writeToOutputStream(out); -} - -void MetaEvent::writeToOutputStream(std::ostream &out) -{ - MidiEvent::writeToOutputStream(out, true); - out << (char)0xFF; - out << (char)mType; -} - -std::shared_ptr MetaEvent::parseMetaEvent(int tick, int delta, - std::stringstream &in) -{ - auto eventData = MetaEventData(in); - auto isText = false; - switch (eventData.type) - { - case SEQUENCE_NUMBER: - case MIDI_CHANNEL_PREFIX: - case END_OF_TRACK: - case TEMPO: - case SMPTE_OFFSET: - case TIME_SIGNATURE: - case KEY_SIGNATURE: - break; - case TEXT_EVENT: - case COPYRIGHT_NOTICE: - case TRACK_NAME: - case INSTRUMENT_NAME: - case LYRICS: - case MARKER: - case CUE_POINT: - case SEQUENCER_SPECIFIC: - default: - isText = true; - break; - } - - if (isText) - { - std::string text; - for (char c : eventData.data) - { - text.push_back(c); - } - switch (eventData.type) - { - case TEXT_EVENT: - return std::make_shared(tick, delta, text); - case COPYRIGHT_NOTICE: - return std::make_shared(tick, delta, text); - case TRACK_NAME: - return std::make_shared(tick, delta, text); - case INSTRUMENT_NAME: - return std::make_shared(tick, delta, text); - case LYRICS: - // return new Lyrics(tick, delta, text); - return nullptr; - case MARKER: - return std::make_shared(tick, delta, text); - case CUE_POINT: - return std::make_shared(tick, delta, text); - case SEQUENCER_SPECIFIC: - return std::make_shared(tick, delta, - eventData.data); - default: - return std::make_shared(tick, delta, - &eventData); - } - } - - switch (eventData.type) - { - case SEQUENCE_NUMBER: - return SequenceNumber::parseSequenceNumber(tick, delta, &eventData); - case MIDI_CHANNEL_PREFIX: - return MidiChannelPrefix::parseMidiChannelPrefix(tick, delta, - &eventData); - case END_OF_TRACK: - return std::make_shared(tick, delta); - case TEMPO: - return Tempo::parseTempo(tick, delta, &eventData); - case SMPTE_OFFSET: - return SmpteOffset::parseSmpteOffset(tick, delta, &eventData); - case TIME_SIGNATURE: - return TimeSignature::parseTimeSignature(tick, delta, &eventData); - case KEY_SIGNATURE: - return KeySignature::parseKeySignature(tick, delta, &eventData); - } - - std::string error = "Completely broken in MetaEvent.parseMetaEvent()"; - return nullptr; -} - -const int MetaEvent::SEQUENCE_NUMBER; -const int MetaEvent::TEXT_EVENT; -const int MetaEvent::COPYRIGHT_NOTICE; -const int MetaEvent::TRACK_NAME; -const int MetaEvent::INSTRUMENT_NAME; -const int MetaEvent::LYRICS; -const int MetaEvent::MARKER; -const int MetaEvent::CUE_POINT; -const int MetaEvent::MIDI_CHANNEL_PREFIX; -const int MetaEvent::END_OF_TRACK; -const int MetaEvent::TEMPO; -const int MetaEvent::SMPTE_OFFSET; -const int MetaEvent::TIME_SIGNATURE; -const int MetaEvent::KEY_SIGNATURE; -const int MetaEvent::SEQUENCER_SPECIFIC; diff --git a/src/main/file/mid/event/meta/MetaEvent.hpp b/src/main/file/mid/event/meta/MetaEvent.hpp deleted file mode 100644 index 875a57dc..00000000 --- a/src/main/file/mid/event/meta/MetaEvent.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include "file/mid/event/MidiEvent.hpp" - -#include "file/mid/util/VariableLengthInt.hpp" - -#include -#include - -namespace mpc::file::mid::event::meta -{ - - class MetaEvent : public MidiEvent - { - - protected: - int mType = 0; - util::VariableLengthInt mLength; - - public: - virtual void writeToOutputStream(std::ostream &output); - void writeToOutputStream(std::ostream &out, bool writeType) override; - - static std::shared_ptr parseMetaEvent(int tick, int delta, - std::stringstream &in); - static const int SEQUENCE_NUMBER{0}; - static const int TEXT_EVENT{1}; - static const int COPYRIGHT_NOTICE{2}; - static const int TRACK_NAME{3}; - static const int INSTRUMENT_NAME{4}; - static const int LYRICS{5}; - static const int MARKER{6}; - static const int CUE_POINT{7}; - static const int MIDI_CHANNEL_PREFIX{32}; - static const int END_OF_TRACK{47}; - static const int TEMPO{81}; - static const int SMPTE_OFFSET{84}; - static const int TIME_SIGNATURE{88}; - static const int KEY_SIGNATURE{89}; - static const int SEQUENCER_SPECIFIC{127}; - - MetaEvent(int tick, int delta, int type); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/MetaEventData.cpp b/src/main/file/mid/event/meta/MetaEventData.cpp deleted file mode 100644 index 53f24de0..00000000 --- a/src/main/file/mid/event/meta/MetaEventData.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "file/mid/event/meta/MetaEventData.hpp" - -using namespace mpc::file::mid::event::meta; - -MetaEventData::MetaEventData(std::stringstream &in) -{ - type = in.get(); - - length = util::VariableLengthInt(in); - - data = std::vector(length.getValue()); - - if (length.getValue() > 0) - { - in.read(&data[0], data.size()); - } -} diff --git a/src/main/file/mid/event/meta/MetaEventData.hpp b/src/main/file/mid/event/meta/MetaEventData.hpp deleted file mode 100644 index 02cba375..00000000 --- a/src/main/file/mid/event/meta/MetaEventData.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "file/mid/util/VariableLengthInt.hpp" - -#include - -namespace mpc::file::mid::event::meta -{ - - class MetaEventData - { - - public: - int type = 0; - util::VariableLengthInt length; - std::vector data; - - MetaEventData(std::stringstream &in); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/MidiChannelPrefix.cpp b/src/main/file/mid/event/meta/MidiChannelPrefix.cpp deleted file mode 100644 index 36cae0b6..00000000 --- a/src/main/file/mid/event/meta/MidiChannelPrefix.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "file/mid/event/meta/MidiChannelPrefix.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/GenericMetaEvent.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -MidiChannelPrefix::MidiChannelPrefix(int tick, int delta, int channel) - : MetaEvent(tick, delta, MIDI_CHANNEL_PREFIX) -{ - mChannel = channel; - mLength = util::VariableLengthInt(4); -} - -void MidiChannelPrefix::setChannel(int c) -{ - mChannel = c; -} - -int MidiChannelPrefix::getChannel() -{ - return mChannel; -} - -int MidiChannelPrefix::getEventSize() -{ - return 4; -} - -void MidiChannelPrefix::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - out << (char)1; - out << (char)mChannel; -} - -std::shared_ptr -MidiChannelPrefix::parseMidiChannelPrefix(int tick, int delta, - MetaEventData *info) -{ - if (info->length.getValue() != 1) - { - return std::make_shared(tick, delta, info); - } - int channel = info->data[0]; - return std::make_shared(tick, delta, channel); -} - -int MidiChannelPrefix::compareTo(MidiEvent *other) -{ - return 0; -} diff --git a/src/main/file/mid/event/meta/MidiChannelPrefix.hpp b/src/main/file/mid/event/meta/MidiChannelPrefix.hpp deleted file mode 100644 index 42b062a8..00000000 --- a/src/main/file/mid/event/meta/MidiChannelPrefix.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - class MetaEventData; -} - -namespace mpc::file::mid::event::meta -{ - class MidiChannelPrefix : public MetaEvent - { - - int mChannel; - - public: - virtual void setChannel(int c); - virtual int getChannel(); - - int getEventSize() override; - - void writeToOutputStream(std::ostream &out) override; - static std::shared_ptr - parseMidiChannelPrefix(int tick, int delta, MetaEventData *info); - virtual int compareTo(MidiEvent *other); - - MidiChannelPrefix(int tick, int delta, int channel); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/SequenceNumber.cpp b/src/main/file/mid/event/meta/SequenceNumber.cpp deleted file mode 100644 index 3703b40e..00000000 --- a/src/main/file/mid/event/meta/SequenceNumber.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "file/mid/event/meta/SequenceNumber.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/GenericMetaEvent.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -SequenceNumber::SequenceNumber(int tick, int delta, int number) - : MetaEvent(tick, delta, SEQUENCE_NUMBER) -{ - mNumber = number; - mLength = util::VariableLengthInt(2); -} - -int SequenceNumber::getMostSignificantBits() const -{ - return mNumber >> 8; -} - -int SequenceNumber::getLeastSignificantBits() const -{ - return mNumber & 255; -} - -int SequenceNumber::getSequenceNumber() const -{ - return mNumber; -} - -void SequenceNumber::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - out << (char)2; - out << (char)getMostSignificantBits(); - out << (char)getLeastSignificantBits(); -} - -void SequenceNumber::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -std::shared_ptr -SequenceNumber::parseSequenceNumber(int tick, int delta, MetaEventData *info) -{ - if (info->length.getValue() != 2) - { - return std::make_shared(tick, delta, info); - } - int msb = info->data[0]; - int lsb = info->data[1]; - auto number = (msb << 8) + lsb; - return std::make_shared(tick, delta, number); -} - -int SequenceNumber::getEventSize() -{ - return 5; -} - -int SequenceNumber::compareTo(MidiEvent *other) const -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - if (dynamic_cast(other) == nullptr) - { - return 1; - } - auto o = dynamic_cast(other); - if (mNumber != o->mNumber) - { - return mNumber < o->mNumber ? -1 : 1; - } - return 0; -} diff --git a/src/main/file/mid/event/meta/SequenceNumber.hpp b/src/main/file/mid/event/meta/SequenceNumber.hpp deleted file mode 100644 index 27bdd53c..00000000 --- a/src/main/file/mid/event/meta/SequenceNumber.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - - class MetaEventData; - - class SequenceNumber : public MetaEvent - { - - int mNumber; - - public: - int getMostSignificantBits() const; - int getLeastSignificantBits() const; - int getSequenceNumber() const; - - static std::shared_ptr - parseSequenceNumber(int tick, int delta, MetaEventData *info); - - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - int getEventSize() override; - - int compareTo(MidiEvent *other) const; - - SequenceNumber(int tick, int delta, int number); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/SequencerSpecificEvent.cpp b/src/main/file/mid/event/meta/SequencerSpecificEvent.cpp deleted file mode 100644 index 555c9a31..00000000 --- a/src/main/file/mid/event/meta/SequencerSpecificEvent.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "file/mid/event/meta/SequencerSpecificEvent.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/util/MidiUtil.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -SequencerSpecificEvent::SequencerSpecificEvent(int tick, int delta, - const std::vector &data) - : MetaEvent(tick, delta, SEQUENCER_SPECIFIC) -{ - mData = data; - util::VariableLengthInt(data.size()); -} - -void SequencerSpecificEvent::setData(std::vector data) -{ - mData = data; - mLength.setValue(mData.size()); -} - -std::vector SequencerSpecificEvent::getData() -{ - return mData; -} - -int SequencerSpecificEvent::getEventSize() -{ - return 1 + 1 + mLength.getByteCount() + mData.size(); -} - -void SequencerSpecificEvent::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - auto length = mLength.getBytes(); - out.write(&length[0], length.size()); - out.write(&mData[0], mData.size()); -} - -void SequencerSpecificEvent::writeToOutputStream(std::ostream &out, - bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -int SequencerSpecificEvent::compareTo(MidiEvent *other) -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - if (dynamic_cast(other) == nullptr) - { - return 1; - } - auto o = dynamic_cast(other); - if (util::MidiUtil::bytesEqual(mData, o->mData, 0, mData.size())) - { - return 0; - } - return 1; -} diff --git a/src/main/file/mid/event/meta/SequencerSpecificEvent.hpp b/src/main/file/mid/event/meta/SequencerSpecificEvent.hpp deleted file mode 100644 index 858732ee..00000000 --- a/src/main/file/mid/event/meta/SequencerSpecificEvent.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - - class SequencerSpecificEvent : public MetaEvent - { - std::vector mData; - - public: - virtual void setData(std::vector data); - virtual std::vector getData(); - - int getEventSize() override; - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - - virtual int compareTo(MidiEvent *other); - - SequencerSpecificEvent(int tick, int delta, - const std::vector &data); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/SmpteOffset.cpp b/src/main/file/mid/event/meta/SmpteOffset.cpp deleted file mode 100644 index eecdb04e..00000000 --- a/src/main/file/mid/event/meta/SmpteOffset.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "file/mid/event/meta/SmpteOffset.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/GenericMetaEvent.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/event/meta/FrameRate.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -SmpteOffset::SmpteOffset(int tick, int delta, FrameRate *fps, int hour, int min, - int sec, int fr, int subfr) - : MetaEvent(tick, delta, SMPTE_OFFSET) -{ - mFrameRate = fps; - mHours = hour; - mMinutes = min; - mSeconds = sec; - mFrames = fr; - mSubFrames = subfr; - mLength = util::VariableLengthInt(5); -} - -const int SmpteOffset::FRAME_RATE_24; -const int SmpteOffset::FRAME_RATE_25; -const int SmpteOffset::FRAME_RATE_30_DROP; -const int SmpteOffset::FRAME_RATE_30; - -void SmpteOffset::setFrameRate(FrameRate *fps) -{ - mFrameRate = fps; -} - -FrameRate *SmpteOffset::getFrameRate() -{ - return mFrameRate; -} - -void SmpteOffset::setHours(int h) -{ - mHours = h; -} - -int SmpteOffset::getHours() -{ - return mHours; -} - -void SmpteOffset::setMinutes(int m) -{ - mMinutes = m; -} - -int SmpteOffset::getMinutes() -{ - return mMinutes; -} - -void SmpteOffset::setSeconds(int s) -{ - mSeconds = s; -} - -int SmpteOffset::getSeconds() -{ - return mSeconds; -} - -void SmpteOffset::setFrames(int f) -{ - mFrames = f; -} - -int SmpteOffset::getFrames() -{ - return mFrames; -} - -void SmpteOffset::setSubFrames(int s) -{ - mSubFrames = s; -} - -int SmpteOffset::getSubFrames() -{ - return mSubFrames; -} - -int SmpteOffset::getEventSize() -{ - return 8; -} - -void SmpteOffset::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - out << (char)5; - out << (char)mHours; - out << (char)mMinutes; - out << (char)mSeconds; - out << (char)mFrames; - out << (char)mSubFrames; -} - -void SmpteOffset::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -std::shared_ptr SmpteOffset::parseSmpteOffset(int tick, int delta, - MetaEventData *info) -{ - if (info->length.getValue() != 5) - { - return std::make_shared(tick, delta, info); - } - int rrHours = info->data[0]; - auto rr = rrHours >> 5; - auto fps = FrameRate::fromInt(rr); - auto hour = rrHours & 31; - int min = info->data[1]; - int sec = info->data[2]; - int frm = info->data[3]; - int sub = info->data[4]; - return std::make_shared(tick, delta, fps, hour, min, sec, frm, - sub); -} - -int SmpteOffset::compareTo(MidiEvent *other) -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - if (dynamic_cast(other) == nullptr) - { - return 1; - } - return 0; -} diff --git a/src/main/file/mid/event/meta/SmpteOffset.hpp b/src/main/file/mid/event/meta/SmpteOffset.hpp deleted file mode 100644 index 54368b88..00000000 --- a/src/main/file/mid/event/meta/SmpteOffset.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - - class FrameRate; - - class MetaEventData; - - class SmpteOffset : public MetaEvent - { - - public: - static const int FRAME_RATE_24{0}; - static const int FRAME_RATE_25{1}; - static const int FRAME_RATE_30_DROP{2}; - static const int FRAME_RATE_30{3}; - - private: - FrameRate *mFrameRate{}; - int mHours{}; - int mMinutes{}; - int mSeconds{}; - int mFrames{}; - int mSubFrames{}; - - public: - virtual void setFrameRate(FrameRate *fps); - virtual FrameRate *getFrameRate(); - virtual void setHours(int h); - virtual int getHours(); - virtual void setMinutes(int m); - virtual int getMinutes(); - virtual void setSeconds(int s); - virtual int getSeconds(); - virtual void setFrames(int f); - virtual int getFrames(); - virtual void setSubFrames(int s); - virtual int getSubFrames(); - - int getEventSize() override; - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - - static std::shared_ptr parseSmpteOffset(int tick, int delta, - MetaEventData *info); - virtual int compareTo(MidiEvent *other); - - SmpteOffset(int tick, int delta, FrameRate *fps, int hour, int min, - int sec, int fr, int subfr); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/Tempo.cpp b/src/main/file/mid/event/meta/Tempo.cpp deleted file mode 100644 index e62eb331..00000000 --- a/src/main/file/mid/event/meta/Tempo.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "file/mid/event/meta/Tempo.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/GenericMetaEvent.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/util/MidiUtil.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -Tempo::Tempo() : Tempo(0, 0, DEFAULT_MPQN) {} - -Tempo::Tempo(int tick, int delta, int mpqn) : MetaEvent(tick, delta, TEMPO) -{ - setMpqn(mpqn); - mLength = util::VariableLengthInt(3); -} - -const int Tempo::DEFAULT_MPQN; - -float Tempo::getBpm() const -{ - return mBPM; -} - -void Tempo::setMpqn(int m) -{ - mMPQN = m; - mBPM = 6.0E7f / mMPQN; -} - -void Tempo::setBpm(float b) -{ - mBPM = b; - mMPQN = static_cast(60000000 / mBPM); -} - -int Tempo::getEventSize() -{ - return 6; -} - -void Tempo::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - out << (char)3; - auto mpqn = util::MidiUtil::intToBytes(mMPQN, 3); - out.write(&mpqn[0], mpqn.size()); -} - -void Tempo::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -std::shared_ptr Tempo::parseTempo(int tick, int delta, - MetaEventData *info) -{ - if (info->length.getValue() != 3) - { - return std::make_shared(tick, delta, info); - } - auto mpqn = util::MidiUtil::bytesToInt(info->data, 0, 3); - return std::make_shared(tick, delta, mpqn); -} - -int Tempo::compareTo(MidiEvent *other) -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - if (dynamic_cast(other) == nullptr) - { - return 1; - } - auto o = dynamic_cast(other); - if (mMPQN != o->mMPQN) - { - return mMPQN < o->mMPQN ? -1 : 1; - } - return 0; -} diff --git a/src/main/file/mid/event/meta/Tempo.hpp b/src/main/file/mid/event/meta/Tempo.hpp deleted file mode 100644 index 8b2da661..00000000 --- a/src/main/file/mid/event/meta/Tempo.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - class MetaEventData; -} - -namespace mpc::file::mid::event::meta -{ - class Tempo : public MetaEvent - { - - public: - static const int DEFAULT_MPQN{500000}; - - private: - int mMPQN; - float mBPM; - - public: - float getBpm() const; - void setMpqn(int m); - void setBpm(float b); - - int getEventSize() override; - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - - static std::shared_ptr parseTempo(int tick, int delta, - MetaEventData *info); - - virtual int compareTo(MidiEvent *other); - - Tempo(); - Tempo(int tick, int delta, int mpqn); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/Text.cpp b/src/main/file/mid/event/meta/Text.cpp deleted file mode 100644 index 2adf47f2..00000000 --- a/src/main/file/mid/event/meta/Text.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "file/mid/event/meta/Text.hpp" - -#include "file/mid/event/meta/MetaEvent.hpp" - -using namespace mpc::file::mid::event::meta; - -Text::Text(int tick, int delta, const std::string &text) - : TextualMetaEvent(tick, delta, TEXT_EVENT, text) -{ -} diff --git a/src/main/file/mid/event/meta/Text.hpp b/src/main/file/mid/event/meta/Text.hpp deleted file mode 100644 index 45508245..00000000 --- a/src/main/file/mid/event/meta/Text.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "file/mid/event/meta/TextualMetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - class Text : public TextualMetaEvent - { - - public: - Text(int tick, int delta, const std::string &text); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/TextualMetaEvent.cpp b/src/main/file/mid/event/meta/TextualMetaEvent.cpp deleted file mode 100644 index 97253fff..00000000 --- a/src/main/file/mid/event/meta/TextualMetaEvent.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "file/mid/event/meta/TextualMetaEvent.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -using namespace mpc::file::mid::event::meta; - -TextualMetaEvent::TextualMetaEvent(int tick, int delta, int type, - const std::string &text) - : MetaEvent(tick, delta, type) -{ - setText(text); - mLength = util::VariableLengthInt(text.length()); -} - -void TextualMetaEvent::setText(const std::string &t) -{ - mText = t; - mLength.setValue(t.length()); -} - -std::string TextualMetaEvent::getText() -{ - return mText; -} - -int TextualMetaEvent::getEventSize() -{ - return 1 + 1 + mLength.getByteCount() + mLength.getValue(); -} - -void TextualMetaEvent::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - auto length = mLength.getBytes(); - out.write(&length[0], length.size()); - out.write(&mText[0], mText.size()); -} - -void TextualMetaEvent::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -int TextualMetaEvent::compareTo(MidiEvent *other) const -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - if (dynamic_cast(other) == nullptr) - { - return 1; - } - auto o = dynamic_cast(other); - return mText.compare(o->mText); -} - -std::string TextualMetaEvent::toString() -{ - return MetaEvent::toString() + ": " + mText; -} diff --git a/src/main/file/mid/event/meta/TextualMetaEvent.hpp b/src/main/file/mid/event/meta/TextualMetaEvent.hpp deleted file mode 100644 index c64efb40..00000000 --- a/src/main/file/mid/event/meta/TextualMetaEvent.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -#include - -namespace mpc::file::mid::event::meta -{ - class TextualMetaEvent : public MetaEvent - { - - public: - std::string mText; - - void setText(const std::string &t); - std::string getText(); - - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - std::string toString() override; - int getEventSize() override; - - int compareTo(MidiEvent *other) const; - - TextualMetaEvent(int tick, int delta, int type, - const std::string &text); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/TimeSignatureEvent.cpp b/src/main/file/mid/event/meta/TimeSignatureEvent.cpp deleted file mode 100644 index 6f44fb72..00000000 --- a/src/main/file/mid/event/meta/TimeSignatureEvent.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "file/mid/event/meta/TimeSignatureEvent.hpp" - -#include "file/mid/event/MidiEvent.hpp" -#include "file/mid/event/meta/GenericMetaEvent.hpp" -#include "file/mid/event/meta/MetaEventData.hpp" -#include "file/mid/event/meta/MetaEvent.hpp" -#include "file/mid/util/VariableLengthInt.hpp" - -#include - -using namespace mpc::file::mid::event::meta; - -TimeSignature::TimeSignature() - : TimeSignature(0, 0, 4, 4, DEFAULT_METER, DEFAULT_DIVISION) -{ -} - -TimeSignature::TimeSignature(int tick, int delta, int num, int den, int meter, - int div) - : MetaEvent(tick, delta, TIME_SIGNATURE) -{ - setTimeSignature(num, den, meter, div); - mLength = util::VariableLengthInt(4); -} - -const int TimeSignature::METER_EIGHTH; -const int TimeSignature::METER_QUARTER; -const int TimeSignature::METER_HALF; -const int TimeSignature::METER_WHOLE; -const int TimeSignature::DEFAULT_METER; -const int TimeSignature::DEFAULT_DIVISION; - -void TimeSignature::setTimeSignature(int num, int den, int meter, int div) -{ - mNumerator = num; - mDenominator = log2(den); - mMeter = meter; - mDivision = div; -} - -int TimeSignature::getNumerator() const -{ - return mNumerator; -} - -int TimeSignature::getDenominatorValue() const -{ - return mDenominator; -} - -int TimeSignature::getRealDenominator() const -{ - return static_cast(pow(2, mDenominator)); -} - -int TimeSignature::getMeter() const -{ - return mMeter; -} - -int TimeSignature::getDivision() const -{ - return mDivision; -} - -int TimeSignature::getEventSize() -{ - return 7; -} - -void TimeSignature::writeToOutputStream(std::ostream &out) -{ - MetaEvent::writeToOutputStream(out); - out << (char)4; - out << (char)mNumerator; - out << (char)mDenominator; - out << (char)mMeter; - out << (char)mDivision; -} - -void TimeSignature::writeToOutputStream(std::ostream &out, bool writeType) -{ - MetaEvent::writeToOutputStream(out, writeType); -} - -std::shared_ptr -TimeSignature::parseTimeSignature(int tick, int delta, MetaEventData *info) -{ - if (info->length.getValue() != 4) - { - return std::make_shared(tick, delta, info); - } - int num = info->data[0]; - int den = info->data[1]; - int met = info->data[2]; - int fps = info->data[3]; - den = (int)pow(2, den); - return std::make_shared(tick, delta, num, den, met, fps); -} - -int TimeSignature::log2(int den) const -{ - switch (den) - { - case 2: - return 1; - case 4: - return 2; - case 8: - return 3; - case 16: - return 4; - case 32: - return 5; - } - - return 0; -} - -std::string TimeSignature::toString() -{ - return MetaEvent::toString() + " " + std::to_string(mNumerator) + "/" + - std::to_string(getRealDenominator()); -} - -int TimeSignature::compareTo(MidiEvent *other) -{ - if (mTick != other->getTick()) - { - return mTick < other->getTick() ? -1 : 1; - } - if (mDelta.getValue() != other->getDelta()) - { - return mDelta.getValue() < other->getDelta() ? 1 : -1; - } - if (dynamic_cast(other) == nullptr) - { - return 1; - } - auto o = dynamic_cast(other); - if (mNumerator != o->mNumerator) - { - return mNumerator < o->mNumerator ? -1 : 1; - } - if (mDenominator != o->mDenominator) - { - return mDenominator < o->mDenominator ? -1 : 1; - } - return 0; -} diff --git a/src/main/file/mid/event/meta/TimeSignatureEvent.hpp b/src/main/file/mid/event/meta/TimeSignatureEvent.hpp deleted file mode 100644 index 7d6257db..00000000 --- a/src/main/file/mid/event/meta/TimeSignatureEvent.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include "file/mid/event/meta/MetaEvent.hpp" - -namespace mpc::file::mid::event::meta -{ - class MetaEventData; -} - -namespace mpc::file::mid::event::meta -{ - class TimeSignature : public MetaEvent - { - - public: - static const int METER_EIGHTH{12}; - static const int METER_QUARTER{24}; - static const int METER_HALF{48}; - static const int METER_WHOLE{96}; - static const int DEFAULT_METER{24}; - static const int DEFAULT_DIVISION{8}; - - private: - int mNumerator; - int mDenominator; - int mMeter; - int mDivision; - - public: - void setTimeSignature(int num, int den, int meter, int div); - int getNumerator() const; - int getDenominatorValue() const; - int getRealDenominator() const; - int getMeter() const; - int getDivision() const; - - int getEventSize() override; - void writeToOutputStream(std::ostream &out) override; - void writeToOutputStream(std::ostream &out, bool writeType) override; - - static std::shared_ptr - parseTimeSignature(int tick, int delta, MetaEventData *info); - - private: - int log2(int den) const; - - public: - std::string toString() override; - virtual int compareTo(MidiEvent *other); - - TimeSignature(); - TimeSignature(int tick, int delta, int num, int den, int meter, - int div); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/event/meta/TrackName.cpp b/src/main/file/mid/event/meta/TrackName.cpp deleted file mode 100644 index 4d68f36b..00000000 --- a/src/main/file/mid/event/meta/TrackName.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "file/mid/event/meta/TrackName.hpp" - -#include "file/mid/event/meta/MetaEvent.hpp" - -using namespace mpc::file::mid::event::meta; - -TrackName::TrackName(int tick, int delta, const std::string &name) - : TextualMetaEvent(tick, delta, TRACK_NAME, name) -{ -} - -void TrackName::setName(const std::string &name) -{ - setText(name); -} - -std::string TrackName::getTrackName() -{ - return getText(); -} diff --git a/src/main/file/mid/event/meta/TrackName.hpp b/src/main/file/mid/event/meta/TrackName.hpp deleted file mode 100644 index 1fc52d26..00000000 --- a/src/main/file/mid/event/meta/TrackName.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "file/mid/event/meta/TextualMetaEvent.hpp" - -#include - -namespace mpc::file::mid::event::meta -{ - class TrackName : public TextualMetaEvent - { - - public: - void setName(const std::string &name); - std::string getTrackName(); - - TrackName(int tick, int delta, const std::string &name); - }; -} // namespace mpc::file::mid::event::meta diff --git a/src/main/file/mid/util/MidiUtil.cpp b/src/main/file/mid/util/MidiUtil.cpp deleted file mode 100644 index 9ca1b634..00000000 --- a/src/main/file/mid/util/MidiUtil.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "file/mid/util/MidiUtil.hpp" - -using namespace mpc::file::mid::util; - -int MidiUtil::bytesToInt(const std::vector &buff, int off, int len) -{ - int num = 0; - int shift = 0; - for (int i = off + len - 1; i >= off; i--) - { - num += (buff[i] & 255) << shift; - shift += 8; - } - return num; -} - -std::vector MidiUtil::intToBytes(int val, int byteCount) -{ - - auto buffer = std::vector(byteCount); - auto ints = std::vector(byteCount); - for (int i = 0; i < byteCount; i++) - { - ints[i] = val & 255; - buffer[byteCount - i - 1] = ints[i]; - val = val >> 8; - if (val == 0) - { - break; - } - } - return buffer; -} - -bool MidiUtil::bytesEqual(const std::vector &buf1, - const std::vector &buf2, int off, int len) -{ - for (int i = off; i < off + len; i++) - { - if (i >= buf1.size() || i >= buf2.size()) - { - return false; - } - if (buf1[i] != buf2[i]) - { - return false; - } - } - return true; -} - -std::string MidiUtil::HEX = "0123456789ABCDEF"; - -std::string MidiUtil::byteToHex(char b) -{ - - int high = (b & 240) >> 4; - int low = b & 15; - std::string res; - res.push_back(HEX[high]); - res.push_back(HEX[low]); - return res; -} - -std::string MidiUtil::bytesToHex(const std::vector &b) -{ - std::string res = ""; - for (int i = 0; i < b.size(); i++) - { - res += byteToHex(b[i]) + " "; - } - return res; -} diff --git a/src/main/file/mid/util/MidiUtil.hpp b/src/main/file/mid/util/MidiUtil.hpp deleted file mode 100644 index 50e3b154..00000000 --- a/src/main/file/mid/util/MidiUtil.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include - -namespace mpc::file::mid::util -{ - class MidiUtil - { - public: - static int bytesToInt(const std::vector &buff, int off, int len); - static std::vector intToBytes(int val, int byteCount); - static bool bytesEqual(const std::vector &buf1, - const std::vector &buf2, int off, int len); - - private: - static std::string HEX; - - public: - static std::string byteToHex(char b); - static std::string bytesToHex(const std::vector &b); - }; -} // namespace mpc::file::mid::util diff --git a/src/main/file/mid/util/VariableLengthInt.cpp b/src/main/file/mid/util/VariableLengthInt.cpp deleted file mode 100644 index f49ac9f1..00000000 --- a/src/main/file/mid/util/VariableLengthInt.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "file/mid/util/VariableLengthInt.hpp" - -#include "file/mid/util/MidiUtil.hpp" - -using namespace mpc::file::mid::util; - -VariableLengthInt::VariableLengthInt() : VariableLengthInt(0) {} - -VariableLengthInt::VariableLengthInt(int value) -{ - setValue(value); -} - -VariableLengthInt::VariableLengthInt(std::stringstream &in) -{ - parseBytes(in); -} - -void VariableLengthInt::setValue(int value) -{ - mValue = value; - buildBytes(); -} - -int VariableLengthInt::getValue() const -{ - return mValue; -} - -int VariableLengthInt::getByteCount() const -{ - return mSizeInBytes; -} - -std::vector VariableLengthInt::getBytes() -{ - return mBytes; -} - -void VariableLengthInt::parseBytes(std::stringstream &in) -{ - auto ints = std::vector(4); - mSizeInBytes = 0; - mValue = 0; - int shift = 0; - - auto b = in.get(); - - auto firstB = std::to_string(b); - - while (mSizeInBytes < 4) - { - mSizeInBytes++; - auto variable = (b & 128) > 0; - - if (!variable) - { - ints[mSizeInBytes - 1] = b & 127; - break; - } - - ints[mSizeInBytes - 1] = b & 127; - b = in.get(); - } - - for (int i = 1; i < mSizeInBytes; i++) - { - shift += 7; - } - mBytes = std::vector(mSizeInBytes); - - for (int i = 0; i < mSizeInBytes; i++) - { - mBytes[i] = static_cast(ints[i]); - mValue += ints[i] << shift; - shift -= 7; - } -} - -void VariableLengthInt::buildBytes() -{ - if (mValue == 0) - { - mBytes = std::vector(1); - mBytes[0] = 0; - mSizeInBytes = 1; - return; - } - mSizeInBytes = 0; - auto vals = std::vector(4); - auto tmpVal = mValue; - while (mSizeInBytes < 4 && tmpVal > 0) - { - vals[mSizeInBytes] = tmpVal & 127; - mSizeInBytes++; - tmpVal = tmpVal >> 7; - } - for (int i = 1; i < mSizeInBytes; i++) - { - vals[i] |= 128; - } - mBytes = std::vector(mSizeInBytes); - for (int i = 0; i < mSizeInBytes; i++) - { - mBytes[i] = static_cast(vals[mSizeInBytes - i - 1]); - } -} - -std::string VariableLengthInt::toString() const -{ - return MidiUtil::bytesToHex(mBytes) + " (" + std::to_string(mValue) + ")"; -} diff --git a/src/main/file/mid/util/VariableLengthInt.hpp b/src/main/file/mid/util/VariableLengthInt.hpp deleted file mode 100644 index 0512c0dc..00000000 --- a/src/main/file/mid/util/VariableLengthInt.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace mpc::file::mid::util -{ - - class VariableLengthInt - { - - int mValue = 0; - std::vector mBytes; - int mSizeInBytes = 0; - - public: - void setValue(int value); - int getValue() const; - int getByteCount() const; - std::vector getBytes(); - std::string toString() const; - - private: - void parseBytes(std::stringstream &in); - void buildBytes(); - - public: - VariableLengthInt(); - VariableLengthInt(int value); - VariableLengthInt(std::stringstream &in); - }; -} // namespace mpc::file::mid::util diff --git a/src/main/lcdgui/screens/SecondSeqScreen.hpp b/src/main/lcdgui/screens/SecondSeqScreen.hpp index 34255464..53a0043c 100644 --- a/src/main/lcdgui/screens/SecondSeqScreen.hpp +++ b/src/main/lcdgui/screens/SecondSeqScreen.hpp @@ -6,11 +6,6 @@ namespace mpc::disk class AllLoader; } -namespace mpc::file::all -{ - class AllSequencer; -} - namespace mpc::sequencer { class Sequencer; @@ -43,6 +38,5 @@ namespace mpc::lcdgui::screens friend class sequencer::Sequencer; friend class disk::AllLoader; - friend class file::all::AllSequencer; }; } // namespace mpc::lcdgui::screens diff --git a/src/main/lcdgui/screens/SyncScreen.cpp b/src/main/lcdgui/screens/SyncScreen.cpp index a35ca71c..05e625cc 100644 --- a/src/main/lcdgui/screens/SyncScreen.cpp +++ b/src/main/lcdgui/screens/SyncScreen.cpp @@ -222,3 +222,28 @@ int SyncScreen::getOut() const { return out; } + +int SyncScreen::getInput() const +{ + return in; +} + +int SyncScreen::getShiftEarly() const +{ + return shiftEarly; +} + +bool SyncScreen::isSendMMCEnabled() const +{ + return sendMMCEnabled; +} + +int SyncScreen::getFrameRate() const +{ + return frameRate; +} + +bool SyncScreen::isReceiveMMCEnabled() const +{ + return receiveMMCEnabled; +} diff --git a/src/main/lcdgui/screens/SyncScreen.hpp b/src/main/lcdgui/screens/SyncScreen.hpp index 5adeaf9c..bdab9ec6 100644 --- a/src/main/lcdgui/screens/SyncScreen.hpp +++ b/src/main/lcdgui/screens/SyncScreen.hpp @@ -7,12 +7,6 @@ namespace mpc::audiomidi class MidiInput; } // namespace mpc::audiomidi -namespace mpc::file::all -{ - class MidiSyncMisc; - class Misc; -} // namespace mpc::file::all - namespace mpc::disk { class AllLoader; @@ -30,6 +24,11 @@ namespace mpc::lcdgui::screens int getModeOut() const; int getModeIn() const; int getOut() const; + int getInput() const; + int getShiftEarly() const; + bool isSendMMCEnabled() const; + int getFrameRate() const; + bool isReceiveMMCEnabled() const; SyncScreen(Mpc &, int layerIndex); @@ -73,7 +72,5 @@ namespace mpc::lcdgui::screens friend class audiomidi::EventHandler; friend class audiomidi::MidiInput; friend class disk::AllLoader; - friend class file::all::MidiSyncMisc; - friend class file::all::Misc; }; } // namespace mpc::lcdgui::screens diff --git a/src/main/lcdgui/screens/UserScreen.hpp b/src/main/lcdgui/screens/UserScreen.hpp index b0407532..9cea5939 100644 --- a/src/main/lcdgui/screens/UserScreen.hpp +++ b/src/main/lcdgui/screens/UserScreen.hpp @@ -59,6 +59,7 @@ namespace mpc::lcdgui::screens int getPgm() const; int getVelo() const; sequencer::TimeSignature getTimeSig() const; + int8_t getTrackStatus() const; private: void displayTempo() const; @@ -92,8 +93,6 @@ namespace mpc::lcdgui::screens void setVelo(int i); void setTimeSig(int num, int den); - int8_t getTrackStatus() const; - void resetPreferences(); friend class InitScreen; diff --git a/src/main/nvram/DefaultsParser.cpp b/src/main/nvram/DefaultsParser.cpp index 405dfe16..0c1482e1 100644 --- a/src/main/nvram/DefaultsParser.cpp +++ b/src/main/nvram/DefaultsParser.cpp @@ -1,6 +1,5 @@ #include "DefaultsParser.hpp" -#include "file/all/AllParser.hpp" #include "file/all/Defaults.hpp" #include "Logger.hpp" @@ -21,7 +20,7 @@ Defaults DefaultsParser::AllDefaultsFromFile(Mpc &mpc, mpc_fs::path p) } const auto &data = *dataRes; - return {mpc, Util::vecCopyOfRange(data, 0, AllParser::DEFAULTS_LENGTH)}; + return {mpc, Util::vecCopyOfRange(data, 0, Defaults::TOTAL_LENGTH)}; } DefaultsParser::DefaultsParser(Mpc &mpc) diff --git a/src/main/nvram/NvRam.cpp b/src/main/nvram/NvRam.cpp index 8f326b03..d06e7c92 100644 --- a/src/main/nvram/NvRam.cpp +++ b/src/main/nvram/NvRam.cpp @@ -15,7 +15,6 @@ #include "hardware/Hardware.hpp" #include "sequencer/TimeSignature.hpp" -#include "file/all/AllParser.hpp" #include "file/all/Defaults.hpp" using namespace mpc::nvram; @@ -48,7 +47,7 @@ void NvRam::loadUserScreenValues(Mpc &mpc) return; } - if (*sizeValue != file::all::AllParser::DEFAULTS_LENGTH) + if (*sizeValue != file::all::Defaults::TOTAL_LENGTH) { return; } diff --git a/src/test/AllFileTest.cpp b/src/test/AllFileTest.cpp index bbf711b6..bf657a09 100644 --- a/src/test/AllFileTest.cpp +++ b/src/test/AllFileTest.cpp @@ -6,22 +6,20 @@ #include "sequencer/Track.hpp" #include "sequencer/NoteOnEvent.hpp" #include "sequencer/ProgramChangeEvent.hpp" +#include "sequencer/SystemExclusiveEvent.hpp" #include "sequencer/Song.hpp" #include "disk/AbstractDisk.hpp" #include "disk/AllLoader.hpp" #include "disk/MpcFile.hpp" -#include "file/all/AllParser.hpp" -#include "file/all/AllSequence.hpp" +#include "file/kaitai/AllIo.hpp" #include "sequencer/SequencerStateManager.hpp" using namespace mpc::disk; -using namespace mpc::file::all; using namespace mpc::sequencer; void saveAndLoadTestAllFile(mpc::Mpc &mpc) { - AllParser allParser(mpc); - auto bytes = allParser.getBytes(); + auto bytes = mpc::file::kaitai::AllIo::save(mpc); const auto sequencer = mpc.getSequencer(); const auto stateManager = sequencer->getStateManager(); @@ -36,8 +34,7 @@ void saveAndLoadTestAllFile(mpc::Mpc &mpc) stateManager->drainQueue(); - AllParser reparsed(mpc, bytes); - AllLoader::loadEverythingFromAllParser(mpc, reparsed); + AllLoader::loadEverythingFromBytes(mpc, bytes); } TEST_CASE("ALL file song", "[allfile]") @@ -100,17 +97,20 @@ TEST_CASE("ALL file save does not crash with sysex event", "[allfile]") seq->getTrack(0)->acquireAndInsertEvent(eventData); stateManager->drainQueue(); - AllParser allParser(mpc); - REQUIRE_NOTHROW(allParser.getBytes()); - - auto bytes = allParser.getBytes(); - AllParser reparsed(mpc, bytes); - auto allSequences = reparsed.getAllSequences(); - REQUIRE_FALSE(allSequences.empty()); - REQUIRE(allSequences[0]->getEventAmount() == 1); - REQUIRE(allSequences[0]->allEvents[0].type == EventType::SystemExclusive); - REQUIRE(allSequences[0]->allEvents[0].sysExByteA == 0x12); - REQUIRE(allSequences[0]->allEvents[0].sysExByteB == 0x34); + REQUIRE_NOTHROW(mpc::file::kaitai::AllIo::save(mpc)); + + saveAndLoadTestAllFile(mpc); + stateManager->drainQueue(); + + auto loadedSequence = sequencer->getSequence(0); + REQUIRE(loadedSequence->isUsed()); + auto loadedTrack = loadedSequence->getTrack(0); + REQUIRE(loadedTrack->getEvents().size() == 1); + auto loadedSystemExclusive = std::dynamic_pointer_cast(loadedTrack->getEvent(0)); + REQUIRE(loadedSystemExclusive); + REQUIRE(loadedSystemExclusive->getTick() == 0); + REQUIRE(loadedSystemExclusive->getByteA() == 0x12); + REQUIRE(loadedSystemExclusive->getByteB() == 0x34); } TEST_CASE("ALL file track is on, used and transmits program changes", diff --git a/src/test/AllLoadingTest.cpp b/src/test/AllLoadingTest.cpp index 643c0de5..e69de29b 100644 --- a/src/test/AllLoadingTest.cpp +++ b/src/test/AllLoadingTest.cpp @@ -1,67 +0,0 @@ -#include "catch2/catch_test_macros.hpp" - -#include "TestMpc.hpp" -#include "Mpc.hpp" -#include "file/all/SequenceNames.hpp" -#include "sequencer/Sequence.hpp" -#include "sequencer/Sequencer.hpp" -#include "disk/AbstractDisk.hpp" -#include "disk/MpcFile.hpp" -#include "disk/AllLoader.hpp" -#include "file/all/AllParser.hpp" -#include "sequencer/SequencerStateManager.hpp" - -#include -#include - -CMRC_DECLARE(mpctest); - -using namespace mpc; -using namespace mpc::disk; - -void prepareAllResources(Mpc &mpc) -{ - auto disk = mpc.getDisk(); - auto fs = cmrc::mpctest::get_filesystem(); - - for (auto &&entry : fs.iterate_directory("test/AllLoading")) - { - auto file = fs.open("test/AllLoading/" + entry.filename()); - std::vector data(file.begin(), file.end()); - auto newFile = disk->newFile(entry.filename()); - newFile->setFileData(data); - } - - disk->initFiles(); -} - -TEST_CASE("Load ALL and check sequence 21 is used", "[load-all]") -{ - Mpc mpc; - TestMpc::initializeTestMpc(mpc); - prepareAllResources(mpc); - - auto disk = mpc.getDisk(); - auto allFile = disk->getFile("ShouldLoadSeq21.ALL"); - - REQUIRE(allFile); - - file::all::AllParser parser(mpc, allFile->getBytes()); - - auto seqNames = parser.getSeqNames(); - - REQUIRE(seqNames->getNames()[20] == "Sequence21 "); - REQUIRE(seqNames->getUsednesses()[20]); - - AllLoader::loadEverythingFromAllParser(mpc, parser); - - mpc.getSequencer()->getStateManager()->drainQueue(); - - auto seq1 = mpc.getSequencer()->getSequence(0); - REQUIRE(seq1); - REQUIRE(seq1->isUsed()); - - auto seq21 = mpc.getSequencer()->getSequence(20); - REQUIRE(seq21); - REQUIRE(seq21->isUsed()); -} diff --git a/src/test/KaitaiAllTest.cpp b/src/test/KaitaiAllTest.cpp index 4e08268a..8b34fd94 100644 --- a/src/test/KaitaiAllTest.cpp +++ b/src/test/KaitaiAllTest.cpp @@ -3,24 +3,28 @@ #include "TestMpc.hpp" #include "Mpc.hpp" +#include "controller/ClientEventController.hpp" +#include "controller/ClientMidiEventController.hpp" #include "disk/AbstractDisk.hpp" #include "disk/AllLoader.hpp" #include "disk/MpcFile.hpp" -#include "file/all/AllParser.hpp" -#include "file/all/AllSong.hpp" -#include "file/all/AllSequence.hpp" -#include "file/all/AllSequencer.hpp" -#include "file/all/Defaults.hpp" -#include "file/all/Tracks.hpp" #include "file/kaitai/AllIo.hpp" #include "file/kaitai/generated/mpc2000xl_all.h" #include "lcdgui/ScreenId.hpp" #include "lcdgui/screens/UserScreen.hpp" #include "sequencer/BusType.hpp" +#include "sequencer/ChannelPressureEvent.hpp" +#include "sequencer/ControlChangeEvent.hpp" +#include "sequencer/MixerEvent.hpp" +#include "sequencer/NoteOnEvent.hpp" +#include "sequencer/PitchBendEvent.hpp" +#include "sequencer/PolyPressureEvent.hpp" +#include "sequencer/ProgramChangeEvent.hpp" #include "sequencer/Sequence.hpp" #include "sequencer/Sequencer.hpp" #include "sequencer/SequencerStateManager.hpp" #include "sequencer/Song.hpp" +#include "sequencer/SystemExclusiveEvent.hpp" #include "sequencer/Track.hpp" #include @@ -229,7 +233,7 @@ TEST_CASE("Kaitai MPC2000 ALL parses and rewrites real 2KXL ALL", "[kaitai-all][ REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); } -TEST_CASE("Kaitai MPC2000 ALL matches handwritten ALL bytes", "[kaitai-all]") +TEST_CASE("Kaitai MPC2000 ALL saves and reloads ShouldLoadSeq21 semantics", "[kaitai-all]") { mpc::Mpc mpc; mpc::TestMpc::initializeTestMpc(mpc); @@ -238,18 +242,27 @@ TEST_CASE("Kaitai MPC2000 ALL matches handwritten ALL bytes", "[kaitai-all]") auto allFile = mpc.getDisk()->getFile("ShouldLoadSeq21.ALL"); REQUIRE(allFile); - mpc::file::all::AllParser handwrittenLoader(mpc, allFile->getBytes()); - mpc::disk::AllLoader::loadEverythingFromAllParser(mpc, handwrittenLoader); + mpc::disk::AllLoader::loadEverythingFromFile(mpc, allFile.get()); mpc.getSequencer()->getStateManager()->drainQueue(); REQUIRE(mpc.getSequencer()->getSequence(0)->isUsed()); REQUIRE(mpc.getSequencer()->getSequence(20)->isUsed()); - mpc::file::all::AllParser handwrittenWriter(mpc); - const auto handwrittenBytes = handwrittenWriter.getBytes(); + auto footswitchController = + mpc.clientEventController->getClientMidiEventController() + ->getFootswitchAssignmentController(); + std::visit( + [](auto& binding) + { + binding.number = -1; + }, + footswitchController->bindings.at(0) + ); + + const auto kaitaiBytesVec = mpc::file::kaitai::AllIo::save(mpc); std::stringstream parseStream( - std::string(handwrittenBytes.begin(), handwrittenBytes.end()), + std::string(kaitaiBytesVec.begin(), kaitaiBytesVec.end()), std::ios::in | std::ios::out | std::ios::binary ); kaitai::kstream parseIo(&parseStream); @@ -259,6 +272,9 @@ TEST_CASE("Kaitai MPC2000 ALL matches handwritten ALL bytes", "[kaitai-all]") REQUIRE(parsed.sequences_metas() != nullptr); REQUIRE(parsed.sequences_metas()->at(0)->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE); REQUIRE(parsed.sequences_metas()->at(20)->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE); + REQUIRE(parsed.misc() != nullptr); + REQUIRE(parsed.misc()->midi_switch() != nullptr); + REQUIRE(parsed.misc()->midi_switch()->at(0)->controller() == 0xFF); std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); kaitai::kstream writeIo(&writeStream); @@ -267,18 +283,33 @@ TEST_CASE("Kaitai MPC2000 ALL matches handwritten ALL bytes", "[kaitai-all]") parsed._write(); const auto kaitaiBytes = writeStream.str(); - REQUIRE(kaitaiBytes.size() == handwrittenBytes.size()); - REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), handwrittenBytes.begin())); + REQUIRE(kaitaiBytes.size() == kaitaiBytesVec.size()); + REQUIRE(std::equal(kaitaiBytes.begin(), kaitaiBytes.end(), kaitaiBytesVec.begin())); mpc::Mpc reparsedMpc; mpc::TestMpc::initializeTestMpc(reparsedMpc); - std::vector kaitaiBytesVec(kaitaiBytes.begin(), kaitaiBytes.end()); - mpc::file::all::AllParser reparsed(reparsedMpc, kaitaiBytesVec); - mpc::disk::AllLoader::loadEverythingFromAllParser(reparsedMpc, reparsed); + auto reparsedFile = installAllBytes( + reparsedMpc, + std::vector(kaitaiBytes.begin(), kaitaiBytes.end()), + "ROUNDTRIP.ALL" + ); + REQUIRE(reparsedFile); + mpc::disk::AllLoader::loadEverythingFromFile(reparsedMpc, reparsedFile.get()); reparsedMpc.getSequencer()->getStateManager()->drainQueue(); REQUIRE(reparsedMpc.getSequencer()->getSequence(0)->isUsed()); REQUIRE(reparsedMpc.getSequencer()->getSequence(20)->isUsed()); + + auto reparsedFootswitchController = + reparsedMpc.clientEventController->getClientMidiEventController() + ->getFootswitchAssignmentController(); + std::visit( + [](auto& binding) + { + REQUIRE(binding.number == -1); + }, + reparsedFootswitchController->bindings.at(0) + ); } TEST_CASE("Kaitai MPC2000 ALL loads real 2KXL ALL through production seam", "[kaitai-all][real-2kxl]") @@ -337,6 +368,59 @@ TEST_CASE("Kaitai MPC2000 ALL loads real 2KXL ALL through production seam", "[ka REQUIRE(song1->getStep(mpc::SongStepIndex(1)).repetitionCount == 3); } +TEST_CASE("Kaitai MPC2000 ALL sequence meta infos expose expected real 2KXL names and usedness", "[kaitai-all][real-2kxl]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto allFile = installResourceFile( + mpc, + "test/RealMpc2000xl/All/ALL.ALL", + "ALL.ALL" + ); + REQUIRE(allFile); + + const auto metaInfos = mpc::disk::AllLoader::loadSequenceMetaInfosFromFile(mpc, allFile.get()); + REQUIRE(metaInfos.size() >= 64U); + REQUIRE(metaInfos[0].used); + REQUIRE(metaInfos[0].name == "Sequence01 "); + REQUIRE(metaInfos[1].used); + REQUIRE(metaInfos[1].name == "Sequence02 "); + REQUIRE_FALSE(metaInfos[2].used); + REQUIRE(metaInfos[2].name == "(Unused) "); + REQUIRE_FALSE(metaInfos[63].used); + REQUIRE(metaInfos[63].name == "(Unused) "); +} + +TEST_CASE("Kaitai MPC2000 ALL loads one real 2KXL sequence with expected defaults", "[kaitai-all][real-2kxl]") +{ + mpc::Mpc kaitaiMpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(kaitaiMpc); + auto kaitaiFile = installResourceFile( + kaitaiMpc, + "test/RealMpc2000xl/All/ALL.ALL", + "ALL.ALL" + ); + REQUIRE(kaitaiFile); + + const auto loaded = mpc::disk::AllLoader::loadOneSequenceFromFile( + kaitaiMpc, + kaitaiFile.get(), + mpc::SequenceIndex(1), + mpc::SequenceIndex(10) + ); + REQUIRE(loaded); + kaitaiMpc.getSequencer()->getStateManager()->drainQueue(); + + REQUIRE(loaded->isUsed()); + REQUIRE(loaded->getName() == "Sequence02"); + REQUIRE_THAT(loaded->getInitialTempo(), Catch::Matchers::WithinAbs(116.2, 0.001)); + REQUIRE(loaded->getTimeSignatureFromBarIndex(0).numerator == 4); + REQUIRE(loaded->getTimeSignatureFromBarIndex(0).denominator == 4); + REQUIRE(loaded->getTrack(0)->getBusType() == mpc::sequencer::BusType::DRUM2); + REQUIRE(loaded->getTrack(0)->getDeviceIndex() == 7); +} + TEST_CASE("AllParser reads mutated default tempo and song repeat count", "[kaitai-all]") { auto fs = cmrc::mpctest::get_filesystem(); @@ -362,14 +446,16 @@ TEST_CASE("AllParser reads mutated default tempo and song repeat count", "[kaita parsed._write(); const auto rewritten = writeStream.str(); - std::vector bytes(rewritten.begin(), rewritten.end()); - - mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); - mpc::file::all::AllParser handwritten(mpc, bytes); + std::stringstream reparsedStream( + rewritten, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream reparsedIo(&reparsedStream); + mpc2000xl_all_t reparsed(&reparsedIo); + reparsed._read(); - REQUIRE(handwritten.getDefaults()->getTempo() == 999); - REQUIRE(handwritten.getSongs().at(1)->getSteps().at(1).second == 7); + REQUIRE(reparsed.defaults()->tempo() == 999); + REQUIRE(reparsed.songs()->at(1)->steps()->at(1)->repeat_count() == 7); } TEST_CASE("AllLoader loads mutated default tempo and song repeat count", "[kaitai-all]") @@ -418,38 +504,43 @@ TEST_CASE("AllParser reads broad mutated defaults, track routing, and song loop { const auto bytes = buildBroadMutatedAllBytes(); - mpc::Mpc mpc; - mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); - mpc::file::all::AllParser handwritten(mpc, bytes); - - auto defaults = handwritten.getDefaults(); - REQUIRE(defaults->getTempo() == 875); - REQUIRE(defaults->getTimeSigNum() == 7); - REQUIRE(defaults->getTimeSigDen() == 8); - REQUIRE(defaults->getBusses().at(0) == 4); - REQUIRE(defaults->getDevices().at(0) == 31); - - auto sequences = handwritten.getAllSequences(); - REQUIRE(sequences.at(0) != nullptr); - REQUIRE(sequences.at(1) != nullptr); - REQUIRE(sequences.at(0)->tracks->getBus(0) == 3); - REQUIRE(sequences.at(0)->tracks->getDeviceIndex(0) == 29); - REQUIRE(sequences.at(1)->tracks->getBus(0) == 0); - REQUIRE(sequences.at(1)->tracks->getDeviceIndex(0) == 5); - - auto sequencer = handwritten.getSequencer(); - REQUIRE(sequencer->sequence == 1); - REQUIRE(sequencer->track == 3); - REQUIRE_THAT(sequencer->masterTempo, Catch::Matchers::WithinAbs(87.5, 0.001)); - - auto songs = handwritten.getSongs(); - REQUIRE(songs.at(0)->getSteps().at(0).first == 1); - REQUIRE(songs.at(0)->getSteps().at(0).second == 4); - REQUIRE(songs.at(0)->getSteps().at(1).first == 0); - REQUIRE(songs.at(0)->getSteps().at(1).second == 5); - REQUIRE(songs.at(0)->getLoopFirstStepIndex() == 0); - REQUIRE(songs.at(0)->getLoopLastStepIndex() == 1); - REQUIRE(songs.at(0)->isLoopEnabled()); + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + + REQUIRE(parsed.defaults()->tempo() == 875); + REQUIRE(parsed.defaults()->numerator() == 7); + REQUIRE(parsed.defaults()->denominator() == 8); + REQUIRE(parsed.defaults()->buses()->at(0) == mpc2000xl_all_t::BUS_DRUM4); + REQUIRE(parsed.defaults()->devices()->at(0) == 31); + + std::vector usedSequenceBodies; + for (const auto& sequence : *parsed.sequences()) { + if (sequence->body() != nullptr) { + usedSequenceBodies.push_back(sequence->body()); + } + } + REQUIRE(usedSequenceBodies.size() >= 2U); + REQUIRE(usedSequenceBodies.at(0)->tracks()->bus()->at(0) == mpc2000xl_all_t::BUS_DRUM3); + REQUIRE(usedSequenceBodies.at(0)->tracks()->device()->at(0) == 29); + REQUIRE(usedSequenceBodies.at(1)->tracks()->bus()->at(0) == mpc2000xl_all_t::BUS_MIDI); + REQUIRE(usedSequenceBodies.at(1)->tracks()->device()->at(0) == 5); + + REQUIRE(parsed.sequencer()->active_sequence() == 1); + REQUIRE(parsed.sequencer()->active_track() == 3); + REQUIRE(parsed.sequencer()->master_tempo() == 875); + + REQUIRE(parsed.songs()->at(0)->steps()->at(0)->sequence_index() == 1); + REQUIRE(parsed.songs()->at(0)->steps()->at(0)->repeat_count() == 4); + REQUIRE(parsed.songs()->at(0)->steps()->at(1)->sequence_index() == 0); + REQUIRE(parsed.songs()->at(0)->steps()->at(1)->repeat_count() == 5); + REQUIRE(parsed.songs()->at(0)->loop_first_step() == 0); + REQUIRE(parsed.songs()->at(0)->loop_last_step() == 1); + REQUIRE(parsed.songs()->at(0)->is_loop_enabled()); } TEST_CASE("AllLoader loads broad mutated defaults, track routing, and song loop semantics", "[kaitai-all]") @@ -492,3 +583,164 @@ TEST_CASE("AllLoader loads broad mutated defaults, track routing, and song loop REQUIRE(song0->getLastLoopStepIndex() == mpc::SongStepIndex(1)); REQUIRE(song0->isLoopEnabled()); } + +TEST_CASE("AllLoader loads representative ALL sequence event types through production seam", "[kaitai-all]") +{ + mpc::Mpc sourceMpc; + mpc::TestMpc::initializeTestMpc(sourceMpc); + + auto sourceSequencer = sourceMpc.getSequencer(); + auto sourceStateManager = sourceSequencer->getStateManager(); + auto sourceSequence = sourceSequencer->getSequence(0); + sourceSequence->init(1); + sourceStateManager->drainQueue(); + + auto footswitchController = + sourceMpc.clientEventController->getClientMidiEventController() + ->getFootswitchAssignmentController(); + for (int i = 0; i < footswitchController->bindings.size(); ++i) + { + std::visit( + [i](auto& binding) + { + binding.number = 20 + i; + }, + footswitchController->bindings[i] + ); + } + + auto sourceTrack = sourceSequence->getTrack(63); + auto openNote = sourceTrack->recordNoteEventNonLive( + 0, + mpc::NoteNumber(60), + mpc::Velocity(127), + 0 + ); + sourceTrack->finalizeNoteEventNonLive(openNote, mpc::Duration(1600)); + sourceStateManager->drainQueue(); + sourceTrack->getNoteEvents().front()->setVariationType(mpc::NoteVariationTypeFilter); + sourceStateManager->drainQueue(); + sourceTrack->getNoteEvents().front()->setVariationValue(mpc::NoteVariationValue(20)); + sourceStateManager->drainQueue(); + + mpc::sequencer::EventData programChange; + programChange.type = mpc::sequencer::EventType::ProgramChange; + programChange.tick = 96; + programChange.programChangeProgramIndex = mpc::ProgramIndex(7); + sourceTrack->acquireAndInsertEvent(programChange); + + mpc::sequencer::EventData controlChange; + controlChange.type = mpc::sequencer::EventType::ControlChange; + controlChange.tick = 120; + controlChange.controllerNumber = 12; + controlChange.controllerValue = 34; + sourceTrack->acquireAndInsertEvent(controlChange); + + mpc::sequencer::EventData pitchBend; + pitchBend.type = mpc::sequencer::EventType::PitchBend; + pitchBend.tick = 144; + pitchBend.amount = -1234; + sourceTrack->acquireAndInsertEvent(pitchBend); + + mpc::sequencer::EventData polyPressure; + polyPressure.type = mpc::sequencer::EventType::PolyPressure; + polyPressure.tick = 168; + polyPressure.noteNumber = mpc::NoteNumber(61); + polyPressure.amount = 45; + sourceTrack->acquireAndInsertEvent(polyPressure); + + mpc::sequencer::EventData channelPressure; + channelPressure.type = mpc::sequencer::EventType::ChannelPressure; + channelPressure.tick = 192; + channelPressure.amount = 55; + sourceTrack->acquireAndInsertEvent(channelPressure); + + mpc::sequencer::EventData systemExclusive; + systemExclusive.type = mpc::sequencer::EventType::SystemExclusive; + systemExclusive.tick = 216; + systemExclusive.sysExByteA = 0x12; + systemExclusive.sysExByteB = 0x34; + sourceTrack->acquireAndInsertEvent(systemExclusive); + + mpc::sequencer::EventData mixer; + mixer.type = mpc::sequencer::EventType::Mixer; + mixer.tick = 240; + mixer.mixerParameter = 3; + mixer.mixerPad = 9; + mixer.mixerValue = 87; + sourceTrack->acquireAndInsertEvent(mixer); + + sourceStateManager->drainQueue(); + + const auto bytes = mpc::file::kaitai::AllIo::save(sourceMpc); + + mpc::Mpc loadedMpc; + mpc::TestMpc::initializeTestMpc(loadedMpc); + auto allFile = installAllBytes(loadedMpc, bytes, "EVENTS.ALL"); + REQUIRE(allFile); + + mpc::disk::AllLoader::loadEverythingFromFile(loadedMpc, allFile.get()); + loadedMpc.getSequencer()->getStateManager()->drainQueue(); + + auto loadedSequence = loadedMpc.getSequencer()->getSequence(0); + REQUIRE(loadedSequence->isUsed()); + auto loadedTrack = loadedSequence->getTrack(63); + REQUIRE(loadedTrack->getEvents().size() == 8); + + auto noteEvent = + std::dynamic_pointer_cast(loadedTrack->getEvent(0)); + REQUIRE(noteEvent); + REQUIRE(noteEvent->getTick() == 0); + REQUIRE(noteEvent->getNote() == 60); + REQUIRE(noteEvent->getVelocity() == 127); + REQUIRE(noteEvent->getDuration() == 1600); + REQUIRE(noteEvent->getVariationType() == 3); + REQUIRE(noteEvent->getVariationValue() == 20); + + auto loadedProgramChange = + std::dynamic_pointer_cast(loadedTrack->getEvent(1)); + REQUIRE(loadedProgramChange); + REQUIRE(loadedProgramChange->getTick() == 96); + REQUIRE(loadedProgramChange->getProgram() == 7); + + auto loadedControlChange = + std::dynamic_pointer_cast(loadedTrack->getEvent(2)); + REQUIRE(loadedControlChange); + REQUIRE(loadedControlChange->getTick() == 120); + REQUIRE(loadedControlChange->getController() == 12); + REQUIRE(loadedControlChange->getAmount() == 34); + + auto loadedPitchBend = + std::dynamic_pointer_cast(loadedTrack->getEvent(3)); + REQUIRE(loadedPitchBend); + REQUIRE(loadedPitchBend->getTick() == 144); + REQUIRE(loadedPitchBend->getAmount() == -1234); + + auto loadedPolyPressure = + std::dynamic_pointer_cast(loadedTrack->getEvent(4)); + REQUIRE(loadedPolyPressure); + REQUIRE(loadedPolyPressure->getTick() == 168); + REQUIRE(loadedPolyPressure->getNote() == 61); + REQUIRE(loadedPolyPressure->getAmount() == 45); + + auto loadedChannelPressure = + std::dynamic_pointer_cast(loadedTrack->getEvent(5)); + REQUIRE(loadedChannelPressure); + REQUIRE(loadedChannelPressure->getTick() == 192); + REQUIRE(loadedChannelPressure->getAmount() == 55); + + auto loadedSystemExclusive = + std::dynamic_pointer_cast(loadedTrack->getEvent(6)); + REQUIRE(loadedSystemExclusive); + REQUIRE(loadedSystemExclusive->getTick() == 216); + REQUIRE(loadedSystemExclusive->getByteA() == 0x12); + REQUIRE(loadedSystemExclusive->getByteB() == 0x34); + + auto loadedMixer = + std::dynamic_pointer_cast(loadedTrack->getEvent(7)); + REQUIRE(loadedMixer); + REQUIRE(loadedMixer->getTick() == 240); + REQUIRE(loadedMixer->getParameter() == 3); + REQUIRE(loadedMixer->getPad() == 9); + REQUIRE(loadedMixer->getValue() == 87); +} diff --git a/src/test/KaitaiMidTest.cpp b/src/test/KaitaiMidTest.cpp index 3f590928..81ebe73d 100644 --- a/src/test/KaitaiMidTest.cpp +++ b/src/test/KaitaiMidTest.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,9 @@ CMRC_DECLARE(mpctest); namespace { +using midi_t = standard_midi_file_with_running_status_t; +using meta_type_t = midi_t::meta_event_body_t::meta_type_enum_t; + struct ParsedNoteSnapshot { int note; int velocity; @@ -47,6 +51,40 @@ struct ParsedNoteSnapshot { } }; +struct DetailedParsedNoteSnapshot { + int tick; + int note; + int velocity; + int duration; + int variationType; + int variationValue; + + bool operator==(const DetailedParsedNoteSnapshot& other) const + { + return tick == other.tick && + note == other.note && + velocity == other.velocity && + duration == other.duration && + variationType == other.variationType && + variationValue == other.variationValue; + } +}; + +struct MidiTimelineEventSnapshot { + int tick; + std::string kind; + int a; + int b; + + bool operator==(const MidiTimelineEventSnapshot& other) const + { + return tick == other.tick && + kind == other.kind && + a == other.a && + b == other.b; + } +}; + std::vector collectParsedNotes(const std::shared_ptr& track) { std::vector result; @@ -65,6 +103,153 @@ std::vector collectParsedNotes(const std::shared_ptr(body[0]) << 16) | + (static_cast(body[1]) << 8) | + static_cast(body[2]); + return mpqn == 0 ? 120.0 : 60000000.0 / static_cast(mpqn); +} + +int denominatorFromTimeSignatureBody(const std::string& body) +{ + return body.size() < 2 ? mpc::DefaultTimeSigDenominator + : 1 << static_cast(body[1]); +} + +std::vector collectDetailedParsedNotes( + const std::shared_ptr& track) +{ + std::vector result; + for (const auto& event : track->getEvents()) { + const auto note = std::dynamic_pointer_cast(event); + if (!note) { + continue; + } + result.push_back(DetailedParsedNoteSnapshot{ + note->getTick(), + note->getNote(), + note->getVelocity(), + note->getDuration(), + note->getVariationType(), + note->getVariationValue() + }); + } + return result; +} + +std::vector collectKaitaiTimeline(const std::vector& bytes, size_t trackIndex) +{ + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + midi_t parsed(&parseIo); + parsed._read(); + + REQUIRE(trackIndex < parsed.tracks()->size()); + const auto& track = parsed.tracks()->at(trackIndex); + + std::vector result; + int tick = 0; + for (const auto& eventPtr : *track->events()->event()) + { + tick += eventPtr->v_time()->value(); + if (const auto* meta = eventPtr->meta_event_body(); meta != nullptr) + { + switch (meta->meta_type()) + { + case meta_type_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME: + result.push_back({tick, "track_name", static_cast(asciiBody(meta->body()).size()), 0}); + break; + case meta_type_t::META_TYPE_ENUM_TEXT_EVENT: + result.push_back({tick, "text", static_cast(asciiBody(meta->body()).size()), 0}); + break; + case meta_type_t::META_TYPE_ENUM_TEMPO: + result.push_back({tick, "tempo", static_cast(std::lround(bpmFromTempoBody(meta->body()) * 10.0)), 0}); + break; + case meta_type_t::META_TYPE_ENUM_TIME_SIGNATURE: + result.push_back({tick, "time_signature", meta->body().empty() ? mpc::DefaultTimeSigNumerator : static_cast(meta->body()[0]), denominatorFromTimeSignatureBody(meta->body())}); + break; + case meta_type_t::META_TYPE_ENUM_END_OF_TRACK: + break; + default: + result.push_back({tick, "meta_other", static_cast(meta->meta_type()), static_cast(meta->body().size())}); + break; + } + continue; + } + + switch (eventPtr->event_type()) + { + case 0x80: + { + const auto* noteOff = dynamic_cast(eventPtr->event_body()); + result.push_back({tick, "note_off", noteOff->note(), noteOff->velocity()}); + break; + } + case 0x90: + { + const auto* noteOn = dynamic_cast(eventPtr->event_body()); + result.push_back({tick, "note_on", noteOn->note(), noteOn->velocity()}); + break; + } + case 0xA0: + { + const auto* noteAftertouch = dynamic_cast(eventPtr->event_body()); + result.push_back({tick, "poly_pressure", noteAftertouch->note(), noteAftertouch->pressure()}); + break; + } + case 0xB0: + { + const auto* controller = dynamic_cast(eventPtr->event_body()); + result.push_back({tick, "control_change", controller->controller(), controller->value()}); + break; + } + case 0xC0: + { + const auto* programChange = dynamic_cast(eventPtr->event_body()); + result.push_back({tick, "program_change", programChange->program(), 0}); + break; + } + case 0xD0: + { + const auto* channelPressure = dynamic_cast(eventPtr->event_body()); + result.push_back({tick, "channel_pressure", channelPressure->pressure(), 0}); + break; + } + case 0xE0: + { + const auto* pitchBend = dynamic_cast(eventPtr->event_body()); + result.push_back({tick, "pitch_bend", pitchBend->b1(), pitchBend->b2()}); + break; + } + case 0xF0: + { + const auto* sysEx = eventPtr->sysex_body(); + result.push_back({tick, "sysex", static_cast(sysEx->data().size()), sysEx->data().empty() ? -1 : static_cast(sysEx->data()[0])}); + break; + } + default: + result.push_back({tick, "other", eventPtr->event_type(), 0}); + break; + } + } + return result; +} + template std::shared_ptr findEventOfType(const std::shared_ptr& track) { @@ -123,6 +308,390 @@ std::shared_ptr loadSequenceWithMidIo( return sequenceOrError.value(); } +std::shared_ptr loadSequenceWithDirectGenericKaitai( + mpc::Mpc& mpc, + const std::vector& bytes, + const std::string& fileName) +{ + const auto stem = fileName.substr(0, fileName.find_last_of('.')); + auto sequence = mpc.getSequencer()->getSequence(mpc::TempSequenceIndex); + sequence->init(0); + mpc.getSequencer()->getStateManager()->drainQueue(); + + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + midi_t parsed(&parseIo); + parsed._read(); + + auto sequencer = mpc.getSequencer(); + auto transport = sequencer->getTransport(); + + std::vector> tempoChanges; + struct TimeSigChange { int tick; int numerator; int denominator; }; + std::vector timeSignatures; + + int lengthInTicks = 0; + for (const auto& midiTrack : *parsed.tracks()) + { + int trackTick = 0; + for (const auto& eventPtr : *midiTrack->events()->event()) + { + trackTick += eventPtr->v_time()->value(); + } + lengthInTicks = std::max(lengthInTicks, trackTick); + } + + int tick = 0; + for (const auto& eventPtr : *parsed.tracks()->at(0)->events()->event()) + { + tick += eventPtr->v_time()->value(); + const auto* meta = eventPtr->meta_event_body(); + if (meta == nullptr) + { + continue; + } + + if (meta->meta_type() == meta_type_t::META_TYPE_ENUM_TEMPO) + { + tempoChanges.push_back({tick, bpmFromTempoBody(meta->body())}); + } + else if (meta->meta_type() == meta_type_t::META_TYPE_ENUM_TIME_SIGNATURE) + { + timeSignatures.push_back( + TimeSigChange{ + tick, + meta->body().empty() + ? mpc::DefaultTimeSigNumerator + : static_cast(meta->body()[0]), + denominatorFromTimeSignatureBody(meta->body()) + } + ); + } + } + + UNSCOPED_INFO("direct-generic file=" << fileName); + UNSCOPED_INFO("direct-generic lengthInTicks=" << lengthInTicks); + UNSCOPED_INFO("direct-generic tempoChanges=" << tempoChanges.size()); + UNSCOPED_INFO("direct-generic timeSignatures=" << timeSignatures.size()); + for (size_t i = 0; i < timeSignatures.size(); ++i) + { + UNSCOPED_INFO( + "direct-generic timesig[" << i << "] tick=" << timeSignatures[i].tick + << " num=" << timeSignatures[i].numerator + << " den=" << timeSignatures[i].denominator + ); + } + + const auto initialTempo = tempoChanges.empty() ? 120.0 : tempoChanges[0].second; + sequence->setInitialTempo(initialTempo); + if (!transport->isTempoSourceSequence()) + { + transport->setTempo(initialTempo); + } + + for (size_t i = 1; i < tempoChanges.size(); ++i) + { + const auto ratio = tempoChanges[i].second / initialTempo; + sequence->addTempoChangeEvent( + tempoChanges[i].first, + static_cast(ratio * 1000.0) + ); + } + + if (timeSignatures.empty()) + { + timeSignatures.push_back( + TimeSigChange{0, mpc::DefaultTimeSigNumerator, mpc::DefaultTimeSigDenominator} + ); + } + + lengthInTicks = std::max(lengthInTicks, 1); + int accumLength = 0; + int barCounter = 0; + for (size_t i = 0; i < timeSignatures.size(); ++i) + { + const auto current = timeSignatures[i]; + const auto nextTick = + i + 1 < timeSignatures.size() ? timeSignatures[i + 1].tick : lengthInTicks; + + while (accumLength < nextTick) + { + sequence->setTimeSignature(barCounter, current.numerator, current.denominator); + const auto newDenTicks = 96 * (4.0 / current.denominator); + const auto barLength = static_cast(newDenTicks * current.numerator); + accumLength += barLength; + barCounter++; + } + } + + sequence->setLastBarIndex(barCounter - 1); + sequence->setFirstLoopBarIndex(mpc::BarIndex(-1)); + sequence->setLastLoopBarIndex(mpc::EndOfSequence); + + const std::string trackDataPrefix = "TRACK DATA:"; + + for (size_t i = 0; i < parsed.tracks()->size() && i < 64; ++i) + { + auto resolvedTrackIndex = static_cast(i); + auto deviceIndex = 0; + auto busType = mpc::sequencer::BusType::DRUM1; + + for (const auto& eventPtr : *parsed.tracks()->at(i)->events()->event()) + { + const auto* meta = eventPtr->meta_event_body(); + if (meta == nullptr || meta->meta_type() != meta_type_t::META_TYPE_ENUM_TEXT_EVENT) + { + continue; + } + + const auto body = asciiBody(meta->body()); + if (body.rfind(trackDataPrefix, 0) != 0) + { + continue; + } + + const auto payload = body.substr(trackDataPrefix.size()); + resolvedTrackIndex = std::stoi(payload.substr(0, 2)); + + const auto deviceIndexStr = payload.substr(2, 2); + if (deviceIndexStr != "C0") + { + deviceIndex = std::stoi(deviceIndexStr, nullptr, 16) - std::stoi(std::string("E0"), nullptr, 16) + 1; + } + + if (payload.size() >= 16) + { + busType = mpc::sequencer::busIndexToBusType(std::stoi(payload.substr(14, 2), nullptr, 16)); + } + break; + } + + if (resolvedTrackIndex < 0 || resolvedTrackIndex > mpc::Mpc2000XlSpecs::LAST_TRACK_INDEX) + { + continue; + } + + auto track = sequence->getTrack(resolvedTrackIndex); + track->setBusType(busType); + track->setDeviceIndex(deviceIndex); + std::string pendingTrackName; + bool hasPendingTrackName = false; + bool hasImportedEvents = false; + + struct OpenNote + { + mpc::sequencer::EventData event; + bool isClosed = false; + }; + + std::vector openNotes; + std::vector> noteOffs; + + int absoluteTick = 0; + for (const auto& eventPtr : *parsed.tracks()->at(i)->events()->event()) + { + absoluteTick += eventPtr->v_time()->value(); + + if (const auto* meta = eventPtr->meta_event_body(); meta != nullptr) + { + if (meta->meta_type() == meta_type_t::META_TYPE_ENUM_SEQUENCE_TRACK_NAME) + { + const auto body = asciiBody(meta->body()); + if (!body.empty()) + { + pendingTrackName = body.substr(0, mpc::Mpc2000XlSpecs::MAX_TRACK_NAME_LENGTH); + hasPendingTrackName = true; + } + } + continue; + } + + switch (eventPtr->event_type()) + { + case 0x80: + { + const auto* noteOff = + dynamic_cast(eventPtr->event_body()); + if (noteOff != nullptr) + { + noteOffs.push_back({noteOff->note(), absoluteTick}); + } + break; + } + case 0x90: + { + const auto* noteOn = + dynamic_cast(eventPtr->event_body()); + if (noteOn == nullptr) + { + break; + } + mpc::sequencer::EventData ne; + ne.type = mpc::sequencer::EventType::NoteOn; + ne.noteNumber = mpc::NoteNumber(noteOn->note()); + ne.tick = absoluteTick; + ne.velocity = mpc::Velocity(noteOn->velocity()); + ne.noteVariationType = mpc::NoteVariationTypeTune; + ne.noteVariationValue = mpc::DefaultNoteVariationValue; + ne.duration = mpc::Duration(24); + openNotes.push_back(OpenNote{ne}); + break; + } + case 0xA0: + { + const auto* noteAftertouch = + dynamic_cast(eventPtr->event_body()); + if (noteAftertouch == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::PolyPressure; + e.tick = absoluteTick; + e.noteNumber = mpc::NoteNumber(noteAftertouch->note()); + e.amount = noteAftertouch->pressure(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xB0: + { + const auto* controller = + dynamic_cast(eventPtr->event_body()); + if (controller == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ControlChange; + e.tick = absoluteTick; + e.controllerNumber = controller->controller(); + e.controllerValue = controller->value(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xC0: + { + const auto* programChange = + dynamic_cast(eventPtr->event_body()); + if (programChange == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ProgramChange; + e.tick = absoluteTick; + e.programChangeProgramIndex = mpc::ProgramIndex(programChange->program()); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xD0: + { + const auto* channelPressure = + dynamic_cast(eventPtr->event_body()); + if (channelPressure == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::ChannelPressure; + e.tick = absoluteTick; + e.amount = channelPressure->pressure(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xE0: + { + auto* pitchBend = + dynamic_cast(eventPtr->event_body()); + if (pitchBend == nullptr) + { + break; + } + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::PitchBend; + e.tick = absoluteTick; + e.amount = pitchBend->bend_value(); + track->acquireAndInsertEvent(e); + hasImportedEvents = true; + break; + } + case 0xF0: + { + const auto* sysEx = eventPtr->sysex_body(); + if (sysEx == nullptr) + { + break; + } + const auto& data = sysEx->data(); + if (data.size() == 8 && + static_cast(data[0]) == 71 && + static_cast(data[1]) == 0 && + static_cast(data[2]) == 68 && + static_cast(data[3]) == 69 && + static_cast(data[7]) == 247) + { + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::Mixer; + e.tick = absoluteTick; + e.mixerParameter = static_cast(data[4]) - 1; + e.mixerPad = static_cast(data[5]); + e.mixerValue = static_cast(data[6]); + track->acquireAndInsertEvent(e); + } + else + { + mpc::sequencer::EventData e; + e.type = mpc::sequencer::EventType::SystemExclusive; + e.tick = absoluteTick; + track->acquireAndInsertEvent(e); + } + hasImportedEvents = true; + break; + } + default: + break; + } + } + + for (auto& on : openNotes) + { + for (auto it = noteOffs.begin(); it != noteOffs.end(); ++it) + { + if (it->first == on.event.noteNumber && it->second >= on.event.tick) + { + on.event.duration = mpc::Duration(it->second - on.event.tick); + noteOffs.erase(it); + break; + } + } + + track->acquireAndInsertEvent(on.event); + hasImportedEvents = true; + } + + if (hasImportedEvents) + { + track->setUsedIfCurrentlyUnused(); + } + + if (hasPendingTrackName) + { + track->setName(pendingTrackName); + } + } + + auto stateManager = mpc.getSequencer()->getStateManager(); + stateManager->drainQueue(); + return sequence; +} + void insertNote( const std::shared_ptr& track, int tick, @@ -143,6 +712,27 @@ void insertNote( track->acquireAndInsertEvent(eventData); } +void requireDetailedNote( + const std::shared_ptr& track, + size_t noteIndex, + int tick, + int note, + int velocity, + int duration, + int variationType = mpc::NoteVariationTypeTune, + int variationValue = mpc::DefaultNoteVariationValue) +{ + const auto notes = collectDetailedParsedNotes(track); + REQUIRE(noteIndex < notes.size()); + const auto& actual = notes[noteIndex]; + REQUIRE(actual.tick == tick); + REQUIRE(actual.note == note); + REQUIRE(actual.velocity == velocity); + REQUIRE(actual.duration == duration); + REQUIRE(actual.variationType == variationType); + REQUIRE(actual.variationValue == variationValue); +} + } TEST_CASE("Kaitai standard MIDI parses and rewrites FRUTZLE", "[kaitai-mid]") @@ -177,6 +767,225 @@ TEST_CASE("Kaitai standard MIDI parses and rewrites FRUTZLE", "[kaitai-mid]") REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); } +TEST_CASE("Kaitai standard MIDI loads FRUTZLE with expected semantics", "[kaitai-mid]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/FRUTZLE.MID"); + std::vector bytes(file.begin(), file.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "FRUTZLE.MID"); + + REQUIRE(sequence->getName() == "Sequence01 "); + REQUIRE(sequence->getBarCount() == 4); + REQUIRE(sequence->getInitialTempo() == 96.0); + + const auto track0 = sequence->getTrack(0); + REQUIRE(track0->isUsed()); + REQUIRE(track0->getName() == "Track-01 "); + REQUIRE(track0->getBusType() == mpc::sequencer::BusType::DRUM1); + REQUIRE(track0->getDeviceIndex() == 0); + REQUIRE(track0->getEvents().size() == 18); + requireDetailedNote(track0, 0, 0, 37, 127, 13); + requireDetailedNote(track0, 3, 288, 37, 16, 12); + requireDetailedNote(track0, 17, 1440, 36, 127, 0); + + const auto track4 = sequence->getTrack(4); + REQUIRE(track4->isUsed()); + REQUIRE(track4->getName() == "Track-05 "); + REQUIRE(track4->getEvents().size() == 32); + requireDetailedNote(track4, 0, 0, 48, 96, 3); + requireDetailedNote(track4, 15, 722, 47, 91, 8); + requireDetailedNote(track4, 31, 1490, 47, 44, 5); + + const auto track8 = sequence->getTrack(8); + REQUIRE(track8->isUsed()); + REQUIRE(track8->getName() == "Track-09 "); + REQUIRE(track8->getEvents().size() == 6); + requireDetailedNote(track8, 0, 3, 82, 127, 180); + requireDetailedNote(track8, 5, 725, 82, 127, 31); +} + +TEST_CASE("Kaitai standard MIDI loads HWIF316 with expected semantics", "[kaitai-mid]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/HWIF316.MID"); + std::vector bytes(file.begin(), file.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "HWIF316.MID"); + + REQUIRE(sequence->getName() == "Sequence100"); + REQUIRE(sequence->getBarCount() == 16); + REQUIRE(std::abs(sequence->getInitialTempo() - 125.0) < 0.001); + + const auto track0 = sequence->getTrack(0); + REQUIRE_FALSE(track0->isUsed()); + REQUIRE(track0->getName() == "HWIF v3 t1 p6"); + REQUIRE(track0->getEvents().empty()); + + const auto track1 = sequence->getTrack(1); + REQUIRE(track1->isUsed()); + REQUIRE(track1->getName() == "Jupiter ARP? out"); + REQUIRE(track1->getEvents().size() == 111); + requireDetailedNote(track1, 0, 0, 67, 127, 25); + requireDetailedNote(track1, 31, 1537, 67, 110, 25); + requireDetailedNote(track1, 110, 5377, 67, 92, 24); + + const auto track2 = sequence->getTrack(2); + REQUIRE(track2->isUsed()); + REQUIRE(track2->getName() == "JUNO UNISON CHOR"); + REQUIRE(track2->getEvents().size() == 118); + requireDetailedNote(track2, 0, 1, 55, 73, 24); + requireDetailedNote(track2, 57, 3073, 55, 73, 24); + requireDetailedNote(track2, 117, 6144, 65, 0, 24); + + const auto track3 = sequence->getTrack(3); + REQUIRE(track3->isUsed()); + REQUIRE(track3->getName() == " JD880 pad"); + REQUIRE(track3->getEvents().size() == 48); + requireDetailedNote(track3, 0, 1, 70, 78, 24); + requireDetailedNote(track3, 24, 3074, 67, 81, 24); + requireDetailedNote(track3, 47, 5486, 67, 0, 24); +} + +TEST_CASE("Kaitai standard MIDI loads HWIF6-0V2 with expected semantics", "[kaitai-mid]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/HWIF6-0V2.MID"); + std::vector bytes(file.begin(), file.end()); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "HWIF6-0V2.MID"); + + REQUIRE(sequence->getName() == "Sequence100"); + REQUIRE(sequence->getBarCount() == 16); + REQUIRE(std::abs(sequence->getInitialTempo() - 125.0) < 0.001); + + const auto track0 = sequence->getTrack(0); + REQUIRE(track0->isUsed()); + REQUIRE(track0->getName() == "HWIF6-0v2"); + REQUIRE(track0->getEvents().size() == 204); + requireDetailedNote(track0, 0, 0, 67, 114, 24); + requireDetailedNote(track0, 52, 1536, 67, 83, 24); + requireDetailedNote(track0, 104, 3072, 67, 18, 24); + requireDetailedNote(track0, 200, 6144, 79, 93, 24); +} + +TEST_CASE("Kaitai standard MIDI parses and rewrites HWIF6-0V2", "[.][kaitai-mid-direct]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/HWIF6-0V2.MID"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + standard_midi_file_with_running_status_t parsed(&parseIo); + parsed._read(); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + REQUIRE(rewrittenBytes.size() == originalBytes.size()); + REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); +} + +TEST_CASE("Kaitai standard MIDI parses and rewrites HWIF316", "[.][kaitai-mid-direct]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/HWIF316.MID"); + const std::string originalBytes( + std::string_view(file.begin(), file.end() - file.begin()) + ); + + std::stringstream parseStream( + originalBytes, + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + standard_midi_file_with_running_status_t parsed(&parseIo); + parsed._read(); + + std::stringstream writeStream(std::ios::in | std::ios::out | std::ios::binary); + kaitai::kstream writeIo(&writeStream); + parsed._set_io(&writeIo); + parsed._check(); + parsed._write(); + + const auto rewrittenBytes = writeStream.str(); + REQUIRE(rewrittenBytes.size() == originalBytes.size()); + REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); +} + +TEST_CASE("Kaitai raw MIDI timeline exposes expected HWIF316 track 0 events", "[.][kaitai-mid-direct]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/HWIF316.MID"); + std::vector bytes(file.begin(), file.end()); + + const auto kaitai = collectKaitaiTimeline(bytes, 0); + + REQUIRE(kaitai.size() == 3); + REQUIRE(kaitai[0] == MidiTimelineEventSnapshot{0, "track_name", 13, 0}); + REQUIRE(kaitai[1] == MidiTimelineEventSnapshot{0, "tempo", 1250, 0}); + REQUIRE(kaitai[2] == MidiTimelineEventSnapshot{0, "other", 252, 0}); +} + +TEST_CASE("Kaitai raw MIDI timeline exposes expected HWIF316 track 3 events", "[.][kaitai-mid-direct]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/HWIF316.MID"); + std::vector bytes(file.begin(), file.end()); + + const auto kaitai = collectKaitaiTimeline(bytes, 3); + + REQUIRE(kaitai.size() == 49); + REQUIRE(kaitai[0] == MidiTimelineEventSnapshot{0, "track_name", 10, 0}); + REQUIRE(kaitai[1] == MidiTimelineEventSnapshot{1, "note_on", 70, 78}); + REQUIRE(kaitai[2] == MidiTimelineEventSnapshot{1, "note_on", 74, 67}); + REQUIRE(kaitai[3] == MidiTimelineEventSnapshot{2, "note_on", 67, 81}); + REQUIRE(kaitai[24] == MidiTimelineEventSnapshot{3074, "note_on", 67, 81}); + REQUIRE(kaitai[48] == MidiTimelineEventSnapshot{5486, "note_on", 67, 0}); +} + +TEST_CASE("Kaitai first raw event on HWIF316 track 0 is a meta event", "[.][kaitai-mid-direct]") +{ + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/MidiFile/HWIF316.MID"); + std::vector bytes(file.begin(), file.end()); + + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + midi_t parsed(&parseIo); + parsed._read(); + + const auto& firstEvent = parsed.tracks()->at(0)->events()->event()->at(0); + UNSCOPED_INFO("first delta=" << firstEvent->v_time()->value()); + UNSCOPED_INFO("first using_running_status=" << firstEvent->using_running_status()); + UNSCOPED_INFO("first status_byte_lookahead=" << static_cast(firstEvent->status_byte_lookahead())); + if (!firstEvent->_is_null_event_header()) + { + UNSCOPED_INFO("first event_header=" << static_cast(firstEvent->event_header())); + } + UNSCOPED_INFO("first event_type=" << firstEvent->event_type()); + REQUIRE(firstEvent->meta_event_body() != nullptr); +} + TEST_CASE("Kaitai standard MIDI saves and loads explicit sequence semantics", "[kaitai-mid]") { mpc::Mpc mpc; diff --git a/src/test/MidiFileTest.cpp b/src/test/MidiFileTest.cpp index 860f8a86..5e8f7a4a 100644 --- a/src/test/MidiFileTest.cpp +++ b/src/test/MidiFileTest.cpp @@ -7,13 +7,11 @@ #include "sequencer/Track.hpp" #include "sequencer/NoteOnEvent.hpp" -#include "file/mid/MidiReader.hpp" -#include "file/mid/MidiWriter.hpp" +#include "file/kaitai/MidIo.hpp" #include "sequencer/SequencerStateManager.hpp" #include #include -#include #include CMRC_DECLARE(mpctest); @@ -21,8 +19,6 @@ CMRC_DECLARE(mpctest); using namespace mpc; using namespace mpc::sequencer; using namespace mpc::disk; -using namespace mpc::file::mid; - namespace { struct NoteSnapshot @@ -65,6 +61,25 @@ namespace } return result; } + + std::shared_ptr loadSequenceWithMidIo( + Mpc &mpc, + const std::vector &bytes, + const std::string &fileName) + { + const auto stem = fileName.substr(0, fileName.find_last_of('.')); + const auto sequenceOrError = + mpc::file::kaitai::MidIo::loadBytes(mpc, bytes, stem); + REQUIRE(sequenceOrError.has_value()); + mpc.getSequencer()->getStateManager()->drainQueue(); + return sequenceOrError.value(); + } + + std::vector saveSequenceWithMidIo( + const std::shared_ptr &sequence) + { + return mpc::file::kaitai::MidIo::saveBytes(sequence); + } } // namespace SCENARIO("A MidiFile can be written", "[file]") @@ -95,52 +110,39 @@ SCENARIO("A MidiFile can be written", "[file]") track0->acquireAndInsertEvent(eventData); stateManager->drainQueue(); - MidiWriter midiWriter(sequence.get()); - auto ostream = std::make_shared(); - midiWriter.writeToOStream(ostream); - sequence->init(1); stateManager->drainQueue(); track0->removeEvents(); stateManager->drainQueue(); REQUIRE(track0->getEvents().empty()); - auto istream = std::make_shared(ostream->str()); - MidiReader midiReader(istream, sequence); - midiReader.parseSequence(mpc); - stateManager->drainQueue(); + auto loaded = loadSequenceWithMidIo( + mpc, + saveSequenceWithMidIo(sequence), + "ROUNDTRIP.MID"); - REQUIRE(sequence->getTrack(0)->getEvents().size() == 1); + REQUIRE(loaded->getTrack(0)->getEvents().size() == 1); REQUIRE(std::dynamic_pointer_cast( - sequence->getTrack(0)->getEvents()[0])); + loaded->getTrack(0)->getEvents()[0])); REQUIRE(std::dynamic_pointer_cast( - sequence->getTrack(0)->getEvents()[0]) + loaded->getTrack(0)->getEvents()[0]) ->getNote() == 37); - REQUIRE(sequence->getTrack(0)->getBusType() == BusType::DRUM2); - REQUIRE(sequence->getTrack(0)->getDeviceIndex() == 7); - REQUIRE(sequence->getTrack(1)->getDeviceIndex() == 0); + REQUIRE(loaded->getTrack(0)->getBusType() == BusType::DRUM2); + REQUIRE(loaded->getTrack(0)->getDeviceIndex() == 7); + REQUIRE(loaded->getTrack(1)->getDeviceIndex() == 0); } } -TEST_CASE("MidiReader parses FRUTZLE.MID without crashing", +TEST_CASE("MidIo parses FRUTZLE.MID without crashing", "[file][midi-file]") { Mpc mpc; TestMpc::initializeTestMpc(mpc); - auto sequence = mpc.getSequencer()->getSequence(0); - auto stateManager = mpc.getSequencer()->getStateManager(); - sequence->init(1); - stateManager->drainQueue(); - auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/MidiFile/FRUTZLE.MID"); - std::string bytes(file.begin(), file.end()); - auto stream = std::make_shared(bytes); - - MidiReader reader(stream, sequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); + std::vector bytes(file.begin(), file.end()); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "FRUTZLE.MID"); int totalEvents = 0; for (int trackIndex = 0; trackIndex < 64; ++trackIndex) @@ -153,25 +155,16 @@ TEST_CASE("MidiReader parses FRUTZLE.MID without crashing", REQUIRE(sequence->getBarCount() == 4); } -TEST_CASE("MidiReader parses FRUTZLE.MID into temp sequence without crashing", +TEST_CASE("MidIo parses FRUTZLE.MID into temp sequence without crashing", "[file][midi-file]") { Mpc mpc; TestMpc::initializeTestMpc(mpc); - auto sequence = mpc.getSequencer()->getSequence(TempSequenceIndex); - auto stateManager = mpc.getSequencer()->getStateManager(); - sequence->init(1); - stateManager->drainQueue(); - auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/MidiFile/FRUTZLE.MID"); - std::string bytes(file.begin(), file.end()); - auto stream = std::make_shared(bytes); - - MidiReader reader(stream, sequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); + std::vector bytes(file.begin(), file.end()); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "FRUTZLE.MID"); int totalEvents = 0; for (int trackIndex = 0; trackIndex < 64; ++trackIndex) @@ -183,115 +176,6 @@ TEST_CASE("MidiReader parses FRUTZLE.MID into temp sequence without crashing", REQUIRE(totalEvents > 0); } -TEST_CASE("Busy 8-track midi roundtrip preserves note events", - "[file][midi-file]") -{ - Mpc mpc; - TestMpc::initializeTestMpc(mpc); - - auto sequencer = mpc.getSequencer(); - auto sequence = sequencer->getSequence(0); - auto stateManager = sequencer->getStateManager(); - - sequence->init(1); - stateManager->drainQueue(); - - for (int trackIndex = 0; trackIndex < 8; ++trackIndex) - { - auto track = sequence->getTrack(trackIndex); - track->setUsedIfCurrentlyUnused(); - track->setDeviceIndex((trackIndex % 4) + 1); - - for (int eventIndex = 0; eventIndex < 32; ++eventIndex) - { - EventData eventData; - eventData.type = EventType::NoteOn; - eventData.tick = - (eventIndex * 11 + trackIndex * 17) % - static_cast(sequence->getLastTick()); - eventData.noteNumber = NoteNumber(35 + eventIndex); - eventData.velocity = Velocity(20 + ((trackIndex * 13 + - eventIndex * 5) % - 107)); - eventData.duration = Duration(1 + ((trackIndex * 7 + - eventIndex * 13) % - 95)); - eventData.noteVariationType = - NoteVariationType((trackIndex + eventIndex) % 4); - - switch (static_cast(eventData.noteVariationType)) - { - case 0: - eventData.noteVariationValue = - NoteVariationValue((eventIndex * 3) % 125); - break; - case 1: - case 2: - eventData.noteVariationValue = - NoteVariationValue((trackIndex * 11 + eventIndex) % - 101); - break; - default: - eventData.noteVariationValue = - NoteVariationValue((trackIndex * 9 + eventIndex * 4) % - 101); - break; - } - - track->acquireAndInsertEvent(eventData); - } - } - - stateManager->drainQueue(); - - std::array, 8> expectedPerTrack; - std::array expectedDeviceIndices{}; - for (int trackIndex = 0; trackIndex < 8; ++trackIndex) - { - auto track = sequence->getTrack(trackIndex); - expectedPerTrack[trackIndex] = collectNoteSnapshots(track); - expectedDeviceIndices[trackIndex] = track->getDeviceIndex(); - REQUIRE_FALSE(expectedPerTrack[trackIndex].empty()); - } - - MidiWriter writer(sequence.get()); - auto output = std::make_shared(); - writer.writeToOStream(output); - - sequence->init(1); - stateManager->drainQueue(); - - auto input = std::make_shared(output->str()); - MidiReader reader(input, sequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); - - for (int trackIndex = 0; trackIndex < 8; ++trackIndex) - { - auto track = sequence->getTrack(trackIndex); - const auto actual = collectNoteSnapshots(track); - - REQUIRE(track->getDeviceIndex() == expectedDeviceIndices[trackIndex]); - REQUIRE(actual.size() == expectedPerTrack[trackIndex].size()); - - for (size_t i = 0; i < actual.size(); ++i) - { - CAPTURE(trackIndex, i); - CAPTURE(actual[i].tick, expectedPerTrack[trackIndex][i].tick); - CAPTURE(actual[i].note, expectedPerTrack[trackIndex][i].note); - CAPTURE(actual[i].velocity, - expectedPerTrack[trackIndex][i].velocity); - CAPTURE(actual[i].duration, - expectedPerTrack[trackIndex][i].duration); - CAPTURE(actual[i].variationType, - expectedPerTrack[trackIndex][i].variationType); - CAPTURE(actual[i].variationValue, - expectedPerTrack[trackIndex][i].variationValue); - REQUIRE(actual[i] == expectedPerTrack[trackIndex][i]); - } - } -} - TEST_CASE("Cubase MID files load with valid bar count and name lengths", "[file][midi-file]") { @@ -306,19 +190,10 @@ TEST_CASE("Cubase MID files load with valid bar count and name lengths", Mpc mpc; TestMpc::initializeTestMpc(mpc); - auto sequence = mpc.getSequencer()->getSequence(TempSequenceIndex); - auto stateManager = mpc.getSequencer()->getStateManager(); - sequence->init(1); - stateManager->drainQueue(); - auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/MidiFile/" + fileName); - std::string bytes(file.begin(), file.end()); - auto stream = std::make_shared(bytes); - - MidiReader reader(stream, sequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); + std::vector bytes(file.begin(), file.end()); + auto sequence = loadSequenceWithMidIo(mpc, bytes, fileName); REQUIRE(sequence->getBarCount() > 0); REQUIRE(sequence->getName().size() <= @@ -338,19 +213,10 @@ TEST_CASE("HWIF316.MID loads with 16 bars", "[file][midi-file]") Mpc mpc; TestMpc::initializeTestMpc(mpc); - auto sequence = mpc.getSequencer()->getSequence(TempSequenceIndex); - auto stateManager = mpc.getSequencer()->getStateManager(); - sequence->init(1); - stateManager->drainQueue(); - auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/MidiFile/HWIF316.MID"); - std::string bytes(file.begin(), file.end()); - auto stream = std::make_shared(bytes); - - MidiReader reader(stream, sequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); + std::vector bytes(file.begin(), file.end()); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "HWIF316.MID"); REQUIRE(sequence->getBarCount() == 16); } @@ -361,19 +227,10 @@ TEST_CASE("Real 2KXL SEQ.MID preserves MPC note variation semantics", Mpc mpc; TestMpc::initializeTestMpc(mpc); - auto sequence = mpc.getSequencer()->getSequence(TempSequenceIndex); - auto stateManager = mpc.getSequencer()->getStateManager(); - sequence->init(1); - stateManager->drainQueue(); - auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/MidiFile/SEQ.MID"); - std::string bytes(file.begin(), file.end()); - auto stream = std::make_shared(bytes); - - MidiReader reader(stream, sequence); - REQUIRE_NOTHROW(reader.parseSequence(mpc)); - stateManager->drainQueue(); + std::vector bytes(file.begin(), file.end()); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "SEQ.MID"); REQUIRE(sequence->getBarCount() == 1); @@ -414,19 +271,10 @@ TEST_CASE("FRUTZLE.MID roundtrip keeps non-empty sequence", "[file][midi-file]") Mpc mpc; TestMpc::initializeTestMpc(mpc); - auto sequence = mpc.getSequencer()->getSequence(TempSequenceIndex); - auto stateManager = mpc.getSequencer()->getStateManager(); - sequence->init(1); - stateManager->drainQueue(); - auto fs = cmrc::mpctest::get_filesystem(); auto file = fs.open("test/MidiFile/FRUTZLE.MID"); - std::string bytes(file.begin(), file.end()); - auto initialInput = std::make_shared(bytes); - - MidiReader initialReader(initialInput, sequence); - REQUIRE_NOTHROW(initialReader.parseSequence(mpc)); - stateManager->drainQueue(); + std::vector bytes(file.begin(), file.end()); + auto sequence = loadSequenceWithMidIo(mpc, bytes, "FRUTZLE.MID"); int eventsAfterFirstLoad = 0; for (int trackIndex = 0; trackIndex < 64; ++trackIndex) @@ -437,25 +285,18 @@ TEST_CASE("FRUTZLE.MID roundtrip keeps non-empty sequence", "[file][midi-file]") REQUIRE(eventsAfterFirstLoad > 0); REQUIRE(sequence->getBarCount() == 4); - MidiWriter writer(sequence.get()); - auto output = std::make_shared(); - writer.writeToOStream(output); - - sequence->init(1); - stateManager->drainQueue(); - - auto secondInput = std::make_shared(output->str()); - MidiReader secondReader(secondInput, sequence); - REQUIRE_NOTHROW(secondReader.parseSequence(mpc)); - stateManager->drainQueue(); + auto reloaded = loadSequenceWithMidIo( + mpc, + saveSequenceWithMidIo(sequence), + "FRUTZLE.MID"); int eventsAfterRoundtrip = 0; for (int trackIndex = 0; trackIndex < 64; ++trackIndex) { eventsAfterRoundtrip += static_cast( - sequence->getTrack(trackIndex)->getEvents().size()); + reloaded->getTrack(trackIndex)->getEvents().size()); } REQUIRE(eventsAfterRoundtrip > 0); - REQUIRE(sequence->getBarCount() == 4); + REQUIRE(reloaded->getBarCount() == 4); } From 01df16f9b03bf22ef6bf117751f984cc33d6bb4b Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:03:20 +0200 Subject: [PATCH 26/52] Fix APS drum bus mapping in Kaitai loader --- src/main/file/kaitai/ApsIo.cpp | 6 ++++- src/test/KaitaiApsTest.cpp | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main/file/kaitai/ApsIo.cpp b/src/main/file/kaitai/ApsIo.cpp index a82180da..3623797b 100644 --- a/src/main/file/kaitai/ApsIo.cpp +++ b/src/main/file/kaitai/ApsIo.cpp @@ -503,7 +503,11 @@ void loadDrums(mpc2000xl_aps_t& parsed, mpc::Mpc& mpc) { for (int i = 0; i < mpc::Mpc2000XlSpecs::DRUM_BUS_COUNT; ++i) { - auto* drum = i == 0 ? parsed.drum1() : parsed.drum2(); + auto* drum = + i == 0 ? parsed.drum1() + : i == 1 ? parsed.drum2() + : i == 2 ? parsed.drum3() + : parsed.drum4(); mpc::performance::Drum perfDrum; perfDrum.drumBusIndex = mpc::DrumBusIndex(i); diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index 1d10e95b..7a8d53d7 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -540,6 +540,53 @@ TEST_CASE("ApsLoader loads mutated note tune", "[kaitai-aps]") REQUIRE(p1->getNoteParameters(35)->getTune() == -120); } +TEST_CASE("ApsLoader maps all four APS drum buses to distinct MPC drum buses", "[kaitai-aps]") +{ + const auto apsBytes = rewriteAllPgmsApsWithMutations([](mpc2000xl_aps_t& parsed) + { + parsed.drum1()->set_program(1); + parsed.drum1()->set_receive_program_change(mpc2000xl_aps_t::NO_YES_FALSE); + parsed.drum1()->set_receive_midi_volume(mpc2000xl_aps_t::NO_YES_TRUE); + + parsed.drum2()->set_program(2); + parsed.drum2()->set_receive_program_change(mpc2000xl_aps_t::NO_YES_TRUE); + parsed.drum2()->set_receive_midi_volume(mpc2000xl_aps_t::NO_YES_FALSE); + + parsed.drum3()->set_program(3); + parsed.drum3()->set_receive_program_change(mpc2000xl_aps_t::NO_YES_FALSE); + parsed.drum3()->set_receive_midi_volume(mpc2000xl_aps_t::NO_YES_FALSE); + + parsed.drum4()->set_program(4); + parsed.drum4()->set_receive_program_change(mpc2000xl_aps_t::NO_YES_TRUE); + parsed.drum4()->set_receive_midi_volume(mpc2000xl_aps_t::NO_YES_TRUE); + }); + + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + loadAllPgmsApsWithoutRender(mpc, apsBytes); + + auto drum0 = mpc.getSequencer()->getDrumBus(mpc::DrumBusIndex(0)); + auto drum1 = mpc.getSequencer()->getDrumBus(mpc::DrumBusIndex(1)); + auto drum2 = mpc.getSequencer()->getDrumBus(mpc::DrumBusIndex(2)); + auto drum3 = mpc.getSequencer()->getDrumBus(mpc::DrumBusIndex(3)); + + REQUIRE(drum0->getProgramIndex() == 1); + REQUIRE(!drum0->receivesPgmChange()); + REQUIRE(drum0->receivesMidiVolume()); + + REQUIRE(drum1->getProgramIndex() == 2); + REQUIRE(drum1->receivesPgmChange()); + REQUIRE(!drum1->receivesMidiVolume()); + + REQUIRE(drum2->getProgramIndex() == 3); + REQUIRE(!drum2->receivesPgmChange()); + REQUIRE(!drum2->receivesMidiVolume()); + + REQUIRE(drum3->getProgramIndex() == 4); + REQUIRE(drum3->receivesPgmChange()); + REQUIRE(drum3->receivesMidiVolume()); +} + TEST_CASE("Kaitai APS parses broad mutated APS semantics", "[kaitai-aps]") { const auto apsBytes = rewriteAllPgmsApsWithMutations(applyBroadApsMutation); From 3dff50dfa0b03100ee8c6b6f08a3b4eb79f3c520 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:36:26 +0200 Subject: [PATCH 27/52] Align APS IO with 16-bit sound references --- src/main/file/kaitai/ApsIo.cpp | 2 +- .../file/kaitai/generated/mpc2000xl_aps.cpp | 120 ++++++++---------- .../file/kaitai/generated/mpc2000xl_aps.h | 60 ++++----- src/test/KaitaiApsTest.cpp | 4 +- 4 files changed, 85 insertions(+), 101 deletions(-) diff --git a/src/main/file/kaitai/ApsIo.cpp b/src/main/file/kaitai/ApsIo.cpp index 3623797b..dc22db3b 100644 --- a/src/main/file/kaitai/ApsIo.cpp +++ b/src/main/file/kaitai/ApsIo.cpp @@ -430,7 +430,7 @@ void loadPrograms(mpc2000xl_aps_t& parsed, copyMixer(destNoteParams.stereoMixer, destNoteParams.indivFxMixer, *sourceMixer); const auto* srcNoteParams = body->note_parameters()->at(noteIndex).get(); - auto soundIndex = srcNoteParams->sound_index() == kUnassignedSoundIndex + auto soundIndex = srcNoteParams->sound_index() == 0xFFFF ? -1 : static_cast(srcNoteParams->sound_index()); diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp index 2033b9ca..8074ff3c 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.cpp +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.cpp @@ -37,36 +37,35 @@ void mpc2000xl_aps_t::_read() { if (!(m_magic == std::string("\x0A\x05", 2))) { throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); } - m_sound_count = m__io->read_u1(); - m__unnamed2 = m__io->read_bytes(1); + m_sound_count = m__io->read_u2le(); m_sound_names = std::unique_ptr>(new std::vector()); const int l_sound_names = sound_count(); for (int i = 0; i < l_sound_names; i++) { m_sound_names->push_back(std::move(kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"))); } - m__unnamed4 = m__io->read_bytes(2); + m__unnamed3 = m__io->read_bytes(2); m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(17), "ASCII"); m_global_parameters = std::unique_ptr(new global_parameters_t(m__io, this, m__root)); m_global_parameters->_read(); - m__unnamed7 = m__io->read_bytes(1); + m__unnamed6 = m__io->read_bytes(1); m_master_pad_to_note_mapping = std::unique_ptr>(new std::vector()); const int l_master_pad_to_note_mapping = 64; for (int i = 0; i < l_master_pad_to_note_mapping; i++) { m_master_pad_to_note_mapping->push_back(std::move(m__io->read_s1())); } - m__unnamed9 = m__io->read_bytes(7); + m__unnamed8 = m__io->read_bytes(7); m_drum1 = std::unique_ptr(new drum_t(m__io, this, m__root)); m_drum1->_read(); - m__unnamed11 = m__io->read_bytes(4); + m__unnamed10 = m__io->read_bytes(4); m_drum2 = std::unique_ptr(new drum_t(m__io, this, m__root)); m_drum2->_read(); - m__unnamed13 = m__io->read_bytes(4); + m__unnamed12 = m__io->read_bytes(4); m_drum3 = std::unique_ptr(new drum_t(m__io, this, m__root)); m_drum3->_read(); - m__unnamed15 = m__io->read_bytes(4); + m__unnamed14 = m__io->read_bytes(4); m_drum4 = std::unique_ptr(new drum_t(m__io, this, m__root)); m_drum4->_read(); - m__unnamed17 = m__io->read_bytes(1); + m__unnamed16 = m__io->read_bytes(1); m_aps_programs = std::unique_ptr>>(new std::vector>()); { int i = 0; @@ -102,62 +101,61 @@ void mpc2000xl_aps_t::_fetch_instances() { void mpc2000xl_aps_t::_write() { m__io->write_bytes(m_magic); - m__io->write_u1(m_sound_count); - m__io->write_bytes(m__unnamed2); + m__io->write_u2le(m_sound_count); if (m_sound_names == nullptr) { - throw std::runtime_error("/seq/3: repeated field is not set"); + throw std::runtime_error("/seq/2: repeated field is not set"); } for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { m__io->write_bytes((*it)); } - m__io->write_bytes(m__unnamed4); + m__io->write_bytes(m__unnamed3); m__io->write_bytes(m_name); if (m_global_parameters.get() == nullptr) { - throw std::runtime_error("/seq/6: nested object is not set"); + throw std::runtime_error("/seq/5: nested object is not set"); } m_global_parameters.get()->_set_io(m__io); m_global_parameters.get()->_write(); - m__io->write_bytes(m__unnamed7); + m__io->write_bytes(m__unnamed6); if (m_master_pad_to_note_mapping == nullptr) { - throw std::runtime_error("/seq/8: repeated field is not set"); + throw std::runtime_error("/seq/7: repeated field is not set"); } for (std::vector::const_iterator it = m_master_pad_to_note_mapping->begin(); it != m_master_pad_to_note_mapping->end(); ++it) { m__io->write_s1((*it)); } - m__io->write_bytes(m__unnamed9); + m__io->write_bytes(m__unnamed8); if (m_drum1.get() == nullptr) { - throw std::runtime_error("/seq/10: nested object is not set"); + throw std::runtime_error("/seq/9: nested object is not set"); } m_drum1.get()->_set_io(m__io); m_drum1.get()->_write(); - m__io->write_bytes(m__unnamed11); + m__io->write_bytes(m__unnamed10); if (m_drum2.get() == nullptr) { - throw std::runtime_error("/seq/12: nested object is not set"); + throw std::runtime_error("/seq/11: nested object is not set"); } m_drum2.get()->_set_io(m__io); m_drum2.get()->_write(); - m__io->write_bytes(m__unnamed13); + m__io->write_bytes(m__unnamed12); if (m_drum3.get() == nullptr) { - throw std::runtime_error("/seq/14: nested object is not set"); + throw std::runtime_error("/seq/13: nested object is not set"); } m_drum3.get()->_set_io(m__io); m_drum3.get()->_write(); - m__io->write_bytes(m__unnamed15); + m__io->write_bytes(m__unnamed14); if (m_drum4.get() == nullptr) { - throw std::runtime_error("/seq/16: nested object is not set"); + throw std::runtime_error("/seq/15: nested object is not set"); } m_drum4.get()->_set_io(m__io); m_drum4.get()->_write(); - m__io->write_bytes(m__unnamed17); + m__io->write_bytes(m__unnamed16); if (m_aps_programs == nullptr) { - throw std::runtime_error("/seq/18: repeated field is not set"); + throw std::runtime_error("/seq/17: repeated field is not set"); } if (m_aps_programs == nullptr) { - throw std::runtime_error("/seq/18: repeated field is not set"); + throw std::runtime_error("/seq/17: repeated field is not set"); } for (std::vector>::const_iterator it = m_aps_programs->begin(); it != m_aps_programs->end(); ++it) { if ((*it).get() == nullptr) { - throw std::runtime_error("/seq/18: nested object is not set"); + throw std::runtime_error("/seq/17: nested object is not set"); } (*it).get()->_set_io(m__io); (*it).get()->_write(); @@ -173,85 +171,82 @@ void mpc2000xl_aps_t::_check() { if (!(m_magic == std::string("\x0A\x05", 2))) { throw kaitai::validation_not_equal_error(std::string("\x0A\x05", 2), m_magic, m__io, std::string("/seq/0")); } - if (m__unnamed2.size() != static_cast(1)) { - throw std::runtime_error("/seq/2: size mismatch"); - } if (m_sound_names == nullptr) { - throw std::runtime_error("/seq/3: repeated field is not set"); + throw std::runtime_error("/seq/2: repeated field is not set"); } if (m_sound_names->size() != static_cast(sound_count())) { - throw std::runtime_error("/seq/3: repeat-expr size mismatch"); + throw std::runtime_error("/seq/2: repeat-expr size mismatch"); } for (std::vector::const_iterator it = m_sound_names->begin(); it != m_sound_names->end(); ++it) { if ((*it).size() != static_cast(17)) { - throw std::runtime_error("/seq/3: size mismatch"); + throw std::runtime_error("/seq/2: size mismatch"); } } - if (m__unnamed4.size() != static_cast(2)) { - throw std::runtime_error("/seq/4: size mismatch"); + if (m__unnamed3.size() != static_cast(2)) { + throw std::runtime_error("/seq/3: size mismatch"); } if (m_name.size() != static_cast(17)) { - throw std::runtime_error("/seq/5: size mismatch"); + throw std::runtime_error("/seq/4: size mismatch"); } if (m_global_parameters.get() == nullptr) { - throw std::runtime_error("/seq/6: nested object is not set"); + throw std::runtime_error("/seq/5: nested object is not set"); } m_global_parameters.get()->_set_io(m__io); m_global_parameters.get()->_check(); - if (m__unnamed7.size() != static_cast(1)) { - throw std::runtime_error("/seq/7: size mismatch"); + if (m__unnamed6.size() != static_cast(1)) { + throw std::runtime_error("/seq/6: size mismatch"); } if (m_master_pad_to_note_mapping == nullptr) { - throw std::runtime_error("/seq/8: repeated field is not set"); + throw std::runtime_error("/seq/7: repeated field is not set"); } if (m_master_pad_to_note_mapping->size() != static_cast(64)) { - throw std::runtime_error("/seq/8: repeat-expr size mismatch"); + throw std::runtime_error("/seq/7: repeat-expr size mismatch"); } for (std::vector::const_iterator it = m_master_pad_to_note_mapping->begin(); it != m_master_pad_to_note_mapping->end(); ++it) { } - if (m__unnamed9.size() != static_cast(7)) { - throw std::runtime_error("/seq/9: size mismatch"); + if (m__unnamed8.size() != static_cast(7)) { + throw std::runtime_error("/seq/8: size mismatch"); } if (m_drum1.get() == nullptr) { - throw std::runtime_error("/seq/10: nested object is not set"); + throw std::runtime_error("/seq/9: nested object is not set"); } m_drum1.get()->_set_io(m__io); m_drum1.get()->_check(); - if (m__unnamed11.size() != static_cast(4)) { - throw std::runtime_error("/seq/11: size mismatch"); + if (m__unnamed10.size() != static_cast(4)) { + throw std::runtime_error("/seq/10: size mismatch"); } if (m_drum2.get() == nullptr) { - throw std::runtime_error("/seq/12: nested object is not set"); + throw std::runtime_error("/seq/11: nested object is not set"); } m_drum2.get()->_set_io(m__io); m_drum2.get()->_check(); - if (m__unnamed13.size() != static_cast(4)) { - throw std::runtime_error("/seq/13: size mismatch"); + if (m__unnamed12.size() != static_cast(4)) { + throw std::runtime_error("/seq/12: size mismatch"); } if (m_drum3.get() == nullptr) { - throw std::runtime_error("/seq/14: nested object is not set"); + throw std::runtime_error("/seq/13: nested object is not set"); } m_drum3.get()->_set_io(m__io); m_drum3.get()->_check(); - if (m__unnamed15.size() != static_cast(4)) { - throw std::runtime_error("/seq/15: size mismatch"); + if (m__unnamed14.size() != static_cast(4)) { + throw std::runtime_error("/seq/14: size mismatch"); } if (m_drum4.get() == nullptr) { - throw std::runtime_error("/seq/16: nested object is not set"); + throw std::runtime_error("/seq/15: nested object is not set"); } m_drum4.get()->_set_io(m__io); m_drum4.get()->_check(); - if (m__unnamed17.size() != static_cast(1)) { - throw std::runtime_error("/seq/17: size mismatch"); + if (m__unnamed16.size() != static_cast(1)) { + throw std::runtime_error("/seq/16: size mismatch"); } if (m_aps_programs == nullptr) { - throw std::runtime_error("/seq/18: repeated field is not set"); + throw std::runtime_error("/seq/17: repeated field is not set"); } for (std::vector>::const_iterator it = m_aps_programs->begin(); it != m_aps_programs->end(); ++it) { const std::size_t i = static_cast(it - m_aps_programs->begin()); const aps_program_meta_t* _ = (*it).get(); if ((*it).get() == nullptr) { - throw std::runtime_error("/seq/18: nested object is not set"); + throw std::runtime_error("/seq/17: nested object is not set"); } (*it).get()->_set_io(m__io); (*it).get()->_check(); @@ -671,8 +666,7 @@ mpc2000xl_aps_t::note_t::note_t(kaitai::kstream* p__io, mpc2000xl_aps_t::aps_pro } void mpc2000xl_aps_t::note_t::_read() { - m_sound_index = m__io->read_u1(); - m__unnamed1 = m__io->read_bytes(1); + m_sound_index = m__io->read_u2le(); m_sound_generation_mode = static_cast(m__io->read_u1()); m_velocity_range_lower = m__io->read_u1(); m_also_play_use_note_1 = m__io->read_u1(); @@ -703,8 +697,7 @@ void mpc2000xl_aps_t::note_t::_fetch_instances() { } void mpc2000xl_aps_t::note_t::_write() { - m__io->write_u1(m_sound_index); - m__io->write_bytes(m__unnamed1); + m__io->write_u2le(m_sound_index); m__io->write_u1(static_cast(m_sound_generation_mode)); m__io->write_u1(m_velocity_range_lower); m__io->write_u1(m_also_play_use_note_1); @@ -733,9 +726,6 @@ void mpc2000xl_aps_t::note_t::_write() { } void mpc2000xl_aps_t::note_t::_check() { - if (m__unnamed1.size() != static_cast(1)) { - throw std::runtime_error("/types/note/seq/1: size mismatch"); - } m__dirty = false; } diff --git a/src/main/file/kaitai/generated/mpc2000xl_aps.h b/src/main/file/kaitai/generated/mpc2000xl_aps.h index 23c75a16..f196b3ca 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_aps.h +++ b/src/main/file/kaitai/generated/mpc2000xl_aps.h @@ -302,10 +302,8 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void _write(); void _check(); ~note_t(); - uint8_t sound_index() const { return m_sound_index; } - void set_sound_index(uint8_t _v) { m__dirty = true; m_sound_index = std::move(_v); } - std::string _unnamed1() const { return m__unnamed1; } - void set__unnamed1(std::string _v) { m__dirty = true; m__unnamed1 = std::move(_v); } + uint16_t sound_index() const { return m_sound_index; } + void set_sound_index(uint16_t _v) { m__dirty = true; m_sound_index = std::move(_v); } mpc2000xl_pgm_t::sound_generation_mode_t sound_generation_mode() const { return m_sound_generation_mode; } void set_sound_generation_mode(mpc2000xl_pgm_t::sound_generation_mode_t _v) { m__dirty = true; m_sound_generation_mode = std::move(_v); } uint8_t velocity_range_lower() const { return m_velocity_range_lower; } @@ -358,8 +356,7 @@ class mpc2000xl_aps_t : public kaitai::kstruct { void set__parent(mpc2000xl_aps_t::aps_program_body_t* _v) { m__dirty = true; m__parent = std::move(_v); } private: - uint8_t m_sound_index; - std::string m__unnamed1; + uint16_t m_sound_index; mpc2000xl_pgm_t::sound_generation_mode_t m_sound_generation_mode; uint8_t m_velocity_range_lower; uint8_t m_also_play_use_note_1; @@ -390,40 +387,38 @@ class mpc2000xl_aps_t : public kaitai::kstruct { public: std::string magic() const { return m_magic; } void set_magic(std::string _v) { m__dirty = true; m_magic = std::move(_v); } - uint8_t sound_count() const { return m_sound_count; } - void set_sound_count(uint8_t _v) { m__dirty = true; m_sound_count = std::move(_v); } - std::string _unnamed2() const { return m__unnamed2; } - void set__unnamed2(std::string _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + uint16_t sound_count() const { return m_sound_count; } + void set_sound_count(uint16_t _v) { m__dirty = true; m_sound_count = std::move(_v); } std::vector* sound_names() const { return m_sound_names.get(); } void set_sound_names(std::unique_ptr> _v) { m__dirty = true; m_sound_names = std::move(_v); } - std::string _unnamed4() const { return m__unnamed4; } - void set__unnamed4(std::string _v) { m__dirty = true; m__unnamed4 = std::move(_v); } + std::string _unnamed3() const { return m__unnamed3; } + void set__unnamed3(std::string _v) { m__dirty = true; m__unnamed3 = std::move(_v); } std::string name() const { return m_name; } void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } global_parameters_t* global_parameters() const { return m_global_parameters.get(); } void set_global_parameters(std::unique_ptr _v) { m__dirty = true; m_global_parameters = std::move(_v); } - std::string _unnamed7() const { return m__unnamed7; } - void set__unnamed7(std::string _v) { m__dirty = true; m__unnamed7 = std::move(_v); } + std::string _unnamed6() const { return m__unnamed6; } + void set__unnamed6(std::string _v) { m__dirty = true; m__unnamed6 = std::move(_v); } std::vector* master_pad_to_note_mapping() const { return m_master_pad_to_note_mapping.get(); } void set_master_pad_to_note_mapping(std::unique_ptr> _v) { m__dirty = true; m_master_pad_to_note_mapping = std::move(_v); } - std::string _unnamed9() const { return m__unnamed9; } - void set__unnamed9(std::string _v) { m__dirty = true; m__unnamed9 = std::move(_v); } + std::string _unnamed8() const { return m__unnamed8; } + void set__unnamed8(std::string _v) { m__dirty = true; m__unnamed8 = std::move(_v); } drum_t* drum1() const { return m_drum1.get(); } void set_drum1(std::unique_ptr _v) { m__dirty = true; m_drum1 = std::move(_v); } - std::string _unnamed11() const { return m__unnamed11; } - void set__unnamed11(std::string _v) { m__dirty = true; m__unnamed11 = std::move(_v); } + std::string _unnamed10() const { return m__unnamed10; } + void set__unnamed10(std::string _v) { m__dirty = true; m__unnamed10 = std::move(_v); } drum_t* drum2() const { return m_drum2.get(); } void set_drum2(std::unique_ptr _v) { m__dirty = true; m_drum2 = std::move(_v); } - std::string _unnamed13() const { return m__unnamed13; } - void set__unnamed13(std::string _v) { m__dirty = true; m__unnamed13 = std::move(_v); } + std::string _unnamed12() const { return m__unnamed12; } + void set__unnamed12(std::string _v) { m__dirty = true; m__unnamed12 = std::move(_v); } drum_t* drum3() const { return m_drum3.get(); } void set_drum3(std::unique_ptr _v) { m__dirty = true; m_drum3 = std::move(_v); } - std::string _unnamed15() const { return m__unnamed15; } - void set__unnamed15(std::string _v) { m__dirty = true; m__unnamed15 = std::move(_v); } + std::string _unnamed14() const { return m__unnamed14; } + void set__unnamed14(std::string _v) { m__dirty = true; m__unnamed14 = std::move(_v); } drum_t* drum4() const { return m_drum4.get(); } void set_drum4(std::unique_ptr _v) { m__dirty = true; m_drum4 = std::move(_v); } - std::string _unnamed17() const { return m__unnamed17; } - void set__unnamed17(std::string _v) { m__dirty = true; m__unnamed17 = std::move(_v); } + std::string _unnamed16() const { return m__unnamed16; } + void set__unnamed16(std::string _v) { m__dirty = true; m__unnamed16 = std::move(_v); } std::vector>* aps_programs() const { return m_aps_programs.get(); } void set_aps_programs(std::unique_ptr>> _v) { m__dirty = true; m_aps_programs = std::move(_v); } mpc2000xl_aps_t* _root() const { return m__root; } @@ -433,23 +428,22 @@ class mpc2000xl_aps_t : public kaitai::kstruct { private: std::string m_magic; - uint8_t m_sound_count; - std::string m__unnamed2; + uint16_t m_sound_count; std::unique_ptr> m_sound_names; - std::string m__unnamed4; + std::string m__unnamed3; std::string m_name; std::unique_ptr m_global_parameters; - std::string m__unnamed7; + std::string m__unnamed6; std::unique_ptr> m_master_pad_to_note_mapping; - std::string m__unnamed9; + std::string m__unnamed8; std::unique_ptr m_drum1; - std::string m__unnamed11; + std::string m__unnamed10; std::unique_ptr m_drum2; - std::string m__unnamed13; + std::string m__unnamed12; std::unique_ptr m_drum3; - std::string m__unnamed15; + std::string m__unnamed14; std::unique_ptr m_drum4; - std::string m__unnamed17; + std::string m__unnamed16; std::unique_ptr>> m_aps_programs; mpc2000xl_aps_t* m__root; kaitai::kstruct* m__parent; diff --git a/src/test/KaitaiApsTest.cpp b/src/test/KaitaiApsTest.cpp index 7a8d53d7..65fa8151 100644 --- a/src/test/KaitaiApsTest.cpp +++ b/src/test/KaitaiApsTest.cpp @@ -89,7 +89,7 @@ void applyBroadApsMutation(mpc2000xl_aps_t& parsed) { auto* program0 = parsed.aps_programs()->at(0)->body(); auto* note35 = program0->note_parameters()->at(0).get(); - note35->set_sound_index(255); + note35->set_sound_index(0xFFFF); note35->set_sound_generation_mode(mpc2000xl_pgm_t::SOUND_GENERATION_MODE_VEL_SW); note35->set_velocity_range_lower(1); note35->set_also_play_use_note_1(41); @@ -628,7 +628,7 @@ TEST_CASE("Kaitai APS parses broad mutated APS semantics", "[kaitai-aps]") REQUIRE(p1->program_change() == 126); auto* note35 = p1->note_parameters()->at(0).get(); - REQUIRE(note35->sound_index() == 255); + REQUIRE(note35->sound_index() == 0xFFFF); REQUIRE(note35->sound_generation_mode() == mpc2000xl_pgm_t::SOUND_GENERATION_MODE_VEL_SW); REQUIRE(note35->velocity_range_lower() == 1); REQUIRE(note35->also_play_use_note_1() == 41); From 81ed960424609d0d57d2a917cee7e1725ff89c47 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Wed, 1 Jul 2026 17:13:08 +0200 Subject: [PATCH 28/52] Ignore local build-codex directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cc0f797e..32e4bea0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build-xcode/ editables/ deps/ .idea/ +build-codex/ From f718bef013707888c45a5a3fce7336f6df70e0d4 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Wed, 1 Jul 2026 17:24:20 +0200 Subject: [PATCH 29/52] Document Kaitai parser maintenance --- PARSERS.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 PARSERS.md diff --git a/PARSERS.md b/PARSERS.md new file mode 100644 index 00000000..7a8de8a9 --- /dev/null +++ b/PARSERS.md @@ -0,0 +1,85 @@ +# Kaitai Parser Maintenance + +This repo vendors generated C++ Kaitai parsers under: + +- `src/main/file/kaitai/generated` + +The source `.ksy` files live in: + +- `/Users/izmar/git/mpc2000xl_kaitai` + +The generator we use is the C++ write-capable compiler from: + +- `/Users/izmar/git/kaitai_struct` +- branch: `cpp-serialization` + +## Formats currently generated + +- `mpc2000xl.snd.ksy` +- `mpc2000xl.pgm.ksy` +- `mpc2000xl.aps.ksy` +- `standard_midi_file_with_running_status.ksy` +- `mpc2000xl.mid.ksy` +- `mpc2000xl.all.ksy` + +## Regenerate parsers + +From anywhere: + +```sh +/Users/izmar/git/kaitai_struct/compiler/jvm/target/universal/stage/bin/kaitai-struct-compiler \ + -t cpp_stl \ + --cpp-standard 11 \ + -w \ + --outdir /Users/izmar/git/vmpc-juce/editables/mpc/src/main/file/kaitai/generated \ + -I /Users/izmar/git/mpc2000xl_kaitai \ + /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.snd.ksy \ + /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.pgm.ksy \ + /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.aps.ksy \ + /Users/izmar/git/mpc2000xl_kaitai/standard_midi_file_with_running_status.ksy \ + /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.mid.ksy \ + /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.all.ksy +``` + +## Typical update flow + +1. Change the relevant `.ksy` file in `mpc2000xl_kaitai`. +2. Regenerate the C++ outputs into `src/main/file/kaitai/generated`. +3. If needed, update the integration layer in: + - `src/main/file/kaitai/SndIo.*` + - `src/main/file/kaitai/PgmIo.*` + - `src/main/file/kaitai/ApsIo.*` + - `src/main/file/kaitai/MidIo.*` + - `src/main/file/kaitai/AllIo.*` +4. Run downstream tests. +5. Commit both the `.ksy` change and the regenerated vendored C++. + +## Verify in editables/mpc + +Build tests. Use any build directory you want. Examples below use `build`: + +```sh +cmake -G "Ninja Multi-Config" -B build +cmake --build build --target mpc-tests --config Debug +``` + +Run the focused Kaitai suite: + +```sh +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-snd],[kaitai-pgm],[kaitai-aps],[kaitai-mid],[kaitai-all]" +``` + +Run one format only if needed: + +```sh +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-aps]" +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-pgm]" +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-snd]" +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-mid]" +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-all]" +``` + +## Notes + +- Do not regenerate with upstream Kaitai compiler unless it has the same C++ serialization support as the `cpp-serialization` branch. +- `generated/` is vendored on purpose. As far as `editables/mpc` is concerned, generated parsers are ordinary source files. From d2ce8f34b76ed99fbe094d4dfdd10ab03acbca0a Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:04:30 +0200 Subject: [PATCH 30/52] Fix Kaitai MPC2000XL ALL RESIST roundtrip --- src/main/disk/AllLoader.cpp | 2 +- src/main/file/kaitai/AllIo.cpp | 84 ++++++++++++-- .../file/kaitai/generated/mpc2000xl_all.cpp | 13 ++- .../file/kaitai/generated/mpc2000xl_all.h | 16 ++- src/test/KaitaiAllTest.cpp | 108 +++++++++++++++++- .../RealMpc2000xl/Resist/RESIST.ALL | Bin 0 -> 67510 bytes 6 files changed, 199 insertions(+), 24 deletions(-) create mode 100644 test-resources/RealMpc2000xl/Resist/RESIST.ALL diff --git a/src/main/disk/AllLoader.cpp b/src/main/disk/AllLoader.cpp index 62be90aa..3541e4d2 100644 --- a/src/main/disk/AllLoader.cpp +++ b/src/main/disk/AllLoader.cpp @@ -288,7 +288,7 @@ void AllLoader::loadEverythingFromCanonicalBytes( auto userScreen = mpc.screens->get(); userScreen->setLastBar(static_cast(defaults->bar_count()) - 1); - userScreen->setLoop(defaults->unknown2()[4] == 0x01); + userScreen->setLoop(defaults->unknown2()[4] != 0x00); userScreen->setBus(mpc::sequencer::busIndexToBusType(static_cast(defaults->buses()->at(0)))); mpcSequencer->setDefaultSequenceName(bytesUntilNull(defaults->sequence_name())); diff --git a/src/main/file/kaitai/AllIo.cpp b/src/main/file/kaitai/AllIo.cpp index 946ef626..d988c695 100644 --- a/src/main/file/kaitai/AllIo.cpp +++ b/src/main/file/kaitai/AllIo.cpp @@ -129,7 +129,8 @@ std::unique_ptr makeDefaults(mpc::Mpc& mpc, all_t& root) constexpr size_t kUnknownNumberOffset = 32; constexpr size_t kDefaultsUnknown2Offset = 48; constexpr size_t kLoopEnabledOffset = 52; - constexpr size_t kDeviceNamesOffset = 120; +constexpr size_t kDeviceNamesOffset = 120; +constexpr size_t kDefaultsUnknown2Length = 68; constexpr size_t kTrackNamesOffset = 384; constexpr size_t kDevicesOffset = 1408; constexpr size_t kBusesOffset = 1472; @@ -176,7 +177,11 @@ std::unique_ptr makeDefaults(mpc::Mpc& mpc, all_t& root) bytes[kUnknownNumberOffset + i * 4 + 3] = static_cast((unknownNumber >> 24) & 0xFF); } - std::copy(std::begin(kDefaultsUnknown2), std::end(kDefaultsUnknown2), bytes.begin() + static_cast(kDefaultsUnknown2Offset)); + std::copy( + std::begin(kDefaultsUnknown2), + std::begin(kDefaultsUnknown2) + static_cast(kDefaultsUnknown2Length), + bytes.begin() + static_cast(kDefaultsUnknown2Offset) + ); bytes[kLoopEnabledOffset] = static_cast(userScreen->isLoopEnabled() ? 0x01 : 0x00); for (int i = 0; i < 33; ++i) @@ -408,6 +413,9 @@ std::unique_ptr makeStepEditOptions(mpc::Mpc& mpc, a return stepEditOptions; } +int countSequenceMetaSegments(mpc::sequencer::Sequence& seq); +int countSequenceBodySegments(mpc::sequencer::Sequence& seq); + std::unique_ptr>> makeSequenceMetas(mpc::Mpc& mpc, all_t& root) { auto result = std::make_unique>>(); @@ -419,7 +427,17 @@ std::unique_ptr>> makeSequen auto meta = std::make_unique(nullptr, &root, &root); const auto seq = sequencer->getSequence(static_cast(i)); meta->set_name(padRight(seq->getName(), kVisibleNameLength)); - meta->set_is_used(seq->isUsed() ? all_t::SEQUENCE_IS_USED_TRUE : all_t::SEQUENCE_IS_USED_FALSE); + auto segmentCount = countSequenceMetaSegments(*seq); + if ((segmentCount & 1) != 0) + { + segmentCount--; + } + auto lastEventIndex = 0; + if (seq->isUsed()) + { + lastEventIndex = 641 + std::max(0, segmentCount / 2); + } + meta->set_last_event_index(static_cast(lastEventIndex)); result->push_back(std::move(meta)); } @@ -473,7 +491,36 @@ std::unique_ptr>> makeSongs(mpc::Mpc& return result; } -int countSequenceEventSegments(mpc::sequencer::Sequence& seq) +int countSequenceMetaSegments(mpc::sequencer::Sequence& seq) +{ + int segmentCount = 0; + for (const auto& track : seq.getTracks()) + { + if (track->getIndex() > 63) + { + break; + } + + for (const auto& event : track->getEvents()) + { + switch (event->handle->type) + { + case mpc::sequencer::EventType::SystemExclusive: + segmentCount += 2; + break; + case mpc::sequencer::EventType::Mixer: + segmentCount += 2; + break; + default: + segmentCount += 1; + break; + } + } + } + return segmentCount; +} + +int countSequenceBodySegments(mpc::sequencer::Sequence& seq) { int segmentCount = 0; for (const auto& track : seq.getTracks()) @@ -801,8 +848,8 @@ std::vector makeSequenceEventChunk(mpc::sequencer::Sequence& seq) std::vector makeSequenceBytes(mpc::sequencer::Sequence& seq, int number) { - const auto segmentCountLastEventIndex = countSequenceEventSegments(seq); - auto segmentCount = segmentCountLastEventIndex; + const auto segmentCountLastEventIndex = countSequenceMetaSegments(seq); + auto segmentCount = countSequenceBodySegments(seq); const auto terminatorCount = (segmentCount & 1) == 0 ? 2 : 1; auto bytes = std::vector( kSequenceHeaderLength + segmentCount * kSequenceEventSegmentLength + terminatorCount * kSequenceEventSegmentLength, @@ -914,14 +961,29 @@ std::unique_ptr>> makeSequences(m auto sequencer = mpc.getSequencer(); const auto usedSequences = sequencer->getUsedSequences(); - const auto usedSequenceIndexes = sequencer->getUsedSequenceIndexes(); - result->reserve(usedSequences.size()); + if (usedSequences.empty()) + { + return result; + } - for (size_t i = 0; i < usedSequences.size(); ++i) + result->reserve(usedSequences.size() * 2); + + for (size_t usedSequenceCursor = 0; usedSequenceCursor < usedSequences.size(); ++usedSequenceCursor) { - auto sequenceBytes = makeSequenceBytes(*usedSequences[i], usedSequenceIndexes[i] + 1); + const auto sequenceIndex = sequencer->getUsedSequenceIndexes()[usedSequenceCursor]; + auto sequenceBytes = + makeSequenceBytes(*usedSequences[usedSequenceCursor], sequenceIndex + 1); result->push_back(parseSection(sequenceBytes, root)); + + // On disk, an even body segment count is followed by an extra 0xFF + // terminator segment that Kaitai parses as an empty sequence record. + if ((countSequenceBodySegments(*usedSequences[usedSequenceCursor]) & 1) == 0) + { + result->push_back( + parseSection(std::vector(8, static_cast(0xFF)), root) + ); + } } return result; @@ -963,7 +1025,7 @@ sequence_meta_infos_or_error AllIo::loadSequenceMetaInfos(mpc::Mpc &mpc, mpc::di { result.push_back( { - sequenceMeta->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE, + sequenceMeta->is_used(), sequenceMeta->name() } ); diff --git a/src/main/file/kaitai/generated/mpc2000xl_all.cpp b/src/main/file/kaitai/generated/mpc2000xl_all.cpp index 10cd635a..06bde019 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_all.cpp +++ b/src/main/file/kaitai/generated/mpc2000xl_all.cpp @@ -2679,11 +2679,12 @@ mpc2000xl_all_t::sequence_meta_t::sequence_meta_t(kaitai::kstream* p__io, mpc200 m__parent = p__parent; m__root = p__root; m__dirty = false; + f_is_used = false; } void mpc2000xl_all_t::sequence_meta_t::_read() { m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(16), "ASCII"); - m_is_used = static_cast(m__io->read_u2le()); + m_last_event_index = m__io->read_u2le(); m__dirty = false; } @@ -2692,7 +2693,7 @@ void mpc2000xl_all_t::sequence_meta_t::_fetch_instances() { void mpc2000xl_all_t::sequence_meta_t::_write() { m__io->write_bytes(m_name); - m__io->write_u2le(static_cast(m_is_used)); + m__io->write_u2le(m_last_event_index); _fetch_instances(); m__dirty = false; } @@ -2706,6 +2707,14 @@ void mpc2000xl_all_t::sequence_meta_t::_check() { mpc2000xl_all_t::sequence_meta_t::~sequence_meta_t() {} +bool mpc2000xl_all_t::sequence_meta_t::is_used() { + if (f_is_used) + return m_is_used; + f_is_used = true; + m_is_used = last_event_index() != 0; + return m_is_used; +} + mpc2000xl_all_t::sequencer_t::sequencer_t(kaitai::kstream* p__io, mpc2000xl_all_t* p__parent, mpc2000xl_all_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; diff --git a/src/main/file/kaitai/generated/mpc2000xl_all.h b/src/main/file/kaitai/generated/mpc2000xl_all.h index 50f2dd1e..1daa74db 100644 --- a/src/main/file/kaitai/generated/mpc2000xl_all.h +++ b/src/main/file/kaitai/generated/mpc2000xl_all.h @@ -1760,18 +1760,22 @@ class mpc2000xl_all_t : public kaitai::kstruct { void _write(); void _check(); ~sequence_meta_t(); + bool is_used(); + void _invalidate_is_used() { f_is_used = false; } std::string name() const { return m_name; } - void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } - sequence_is_used_t is_used() const { return m_is_used; } - void set_is_used(sequence_is_used_t _v) { m__dirty = true; m_is_used = std::move(_v); } + void set_name(std::string _v) { m__dirty = true; f_is_used = false; m_name = std::move(_v); } + uint16_t last_event_index() const { return m_last_event_index; } + void set_last_event_index(uint16_t _v) { m__dirty = true; f_is_used = false; m_last_event_index = std::move(_v); } mpc2000xl_all_t* _root() const { return m__root; } - void set__root(mpc2000xl_all_t* _v) { m__dirty = true; m__root = std::move(_v); } + void set__root(mpc2000xl_all_t* _v) { m__dirty = true; f_is_used = false; m__root = std::move(_v); } kaitai::kstruct* _parent() const { return m__parent; } - void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; m__parent = std::move(_v); } + void set__parent(mpc2000xl_all_t* _v) { m__dirty = true; f_is_used = false; m__parent = std::move(_v); } private: + bool f_is_used; + bool m_is_used; std::string m_name; - sequence_is_used_t m_is_used; + uint16_t m_last_event_index; mpc2000xl_all_t* m__root; mpc2000xl_all_t* m__parent; }; diff --git a/src/test/KaitaiAllTest.cpp b/src/test/KaitaiAllTest.cpp index 8b34fd94..c9c5e1e5 100644 --- a/src/test/KaitaiAllTest.cpp +++ b/src/test/KaitaiAllTest.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -82,6 +83,75 @@ std::shared_ptr installAllBytes( return newFile; } +std::string describeFirstByteDiff( + const std::vector& lhs, + const std::vector& rhs) +{ + const auto mismatch = std::mismatch(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + if (mismatch.first == lhs.end() && mismatch.second == rhs.end()) + { + return "no diff"; + } + + const auto offset = static_cast(mismatch.first - lhs.begin()); + std::ostringstream oss; + oss << "first diff at offset " << offset + << ": lhs=0x" + << std::hex << std::setw(2) << std::setfill('0') + << (static_cast(static_cast(*mismatch.first))) + << " rhs=0x" + << std::hex << std::setw(2) << std::setfill('0') + << (static_cast(static_cast(*mismatch.second))); + return oss.str(); +} + +std::vector parseAllSequenceBodyIndexes(const std::vector& bytes) +{ + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + kaitai::kstream parseIo(&parseStream); + mpc2000xl_all_t parsed(&parseIo); + parsed._read(); + + std::vector result; + if (parsed.sequences() == nullptr) + { + return result; + } + + for (const auto& sequence : *parsed.sequences()) + { + if (sequence->body() != nullptr) + { + result.push_back(sequence->body()->index()); + } + else + { + result.push_back(-1); + } + } + + return result; +} + +std::string describeSequenceBodyIndexes(const std::vector& indexes) +{ + std::ostringstream oss; + oss << "["; + for (size_t i = 0; i < indexes.size(); ++i) + { + if (i != 0) + { + oss << ", "; + } + oss << indexes[i]; + } + oss << "]"; + return oss.str(); +} + std::vector buildBroadMutatedAllBytes() { auto fs = cmrc::mpctest::get_filesystem(); @@ -189,8 +259,8 @@ TEST_CASE("Kaitai MPC2000 ALL parses and rewrites real 2KXL ALL", "[kaitai-all][ REQUIRE(parsed.sequences() != nullptr); REQUIRE(parsed.sequences_metas()->size() >= 2U); REQUIRE(parsed.sequences()->size() >= 2U); - REQUIRE(parsed.sequences_metas()->at(0)->is_used() == mpc2000xl_all_t::SEQUENCE_IS_USED_TRUE); - REQUIRE(parsed.sequences_metas()->at(1)->is_used() == mpc2000xl_all_t::SEQUENCE_IS_USED_TRUE); + REQUIRE(parsed.sequences_metas()->at(0)->is_used()); + REQUIRE(parsed.sequences_metas()->at(1)->is_used()); std::vector usedSequenceBodies; for (const auto& seq : *parsed.sequences()) { if (seq->body() != nullptr) { @@ -233,6 +303,36 @@ TEST_CASE("Kaitai MPC2000 ALL parses and rewrites real 2KXL ALL", "[kaitai-all][ REQUIRE(std::equal(rewrittenBytes.begin(), rewrittenBytes.end(), originalBytes.begin())); } +TEST_CASE("Kaitai MPC2000 ALL production save preserves real RESIST.ALL bytes", "[kaitai-all][real-2kxl][resist]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto allFile = installResourceFile( + mpc, + "test/RealMpc2000xl/Resist/RESIST.ALL", + "RESIST.ALL" + ); + REQUIRE(allFile); + + const auto originalBytes = allFile->getBytes(); + + mpc::disk::AllLoader::loadEverythingFromFile(mpc, allFile.get()); + mpc.getSequencer()->getStateManager()->drainQueue(); + + const auto savedBytes = mpc::file::kaitai::AllIo::save(mpc); + const auto originalSequenceBodyIndexes = parseAllSequenceBodyIndexes(originalBytes); + const auto savedSequenceBodyIndexes = parseAllSequenceBodyIndexes(savedBytes); + + INFO("original size: " << originalBytes.size()); + INFO("saved size: " << savedBytes.size()); + INFO(describeFirstByteDiff(originalBytes, savedBytes)); + INFO("original sequence bodies: " << describeSequenceBodyIndexes(originalSequenceBodyIndexes)); + INFO("saved sequence bodies: " << describeSequenceBodyIndexes(savedSequenceBodyIndexes)); + REQUIRE(savedBytes.size() == originalBytes.size()); + REQUIRE(std::equal(savedBytes.begin(), savedBytes.end(), originalBytes.begin())); +} + TEST_CASE("Kaitai MPC2000 ALL saves and reloads ShouldLoadSeq21 semantics", "[kaitai-all]") { mpc::Mpc mpc; @@ -270,8 +370,8 @@ TEST_CASE("Kaitai MPC2000 ALL saves and reloads ShouldLoadSeq21 semantics", "[ka parsed._read(); REQUIRE(parsed.sequences_metas() != nullptr); - REQUIRE(parsed.sequences_metas()->at(0)->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE); - REQUIRE(parsed.sequences_metas()->at(20)->is_used() != mpc2000xl_all_t::SEQUENCE_IS_USED_FALSE); + REQUIRE(parsed.sequences_metas()->at(0)->is_used()); + REQUIRE(parsed.sequences_metas()->at(20)->is_used()); REQUIRE(parsed.misc() != nullptr); REQUIRE(parsed.misc()->midi_switch() != nullptr); REQUIRE(parsed.misc()->midi_switch()->at(0)->controller() == 0xFF); diff --git a/test-resources/RealMpc2000xl/Resist/RESIST.ALL b/test-resources/RealMpc2000xl/Resist/RESIST.ALL new file mode 100644 index 0000000000000000000000000000000000000000..d80cedabe8089a4f3d231ea8a5aa03349d8cd170 GIT binary patch literal 67510 zcmeI5O>Y}j6ozNU6FXmR)0T#Q*CI~UEhx~OQPNCB0ltJr~x$}Vlff{nf4 z2ZT+;4kR{gkRpV{h7JE9zW{Z?f@K%%!+Y->C(fzbAsG;H<{il#pF8)SdG9l~o?yK* zURZiB{NUsJ<#+GjF9+{btIO@r*V~P1p7l6q12;nRmJpS@iT20SDWRUWB4R(Vb3b(P;z z`E8Zo*`Ehhl`DOL(ibRwfzlT!eSy*!D1Cv_7btz9(ibXyq0$#BeWB79Dt)2S7b<PlaIS6|i-Qa9t4_4uuf zTQTF7Rlga(<+}wFr_Fzot!1u)j?-)O8p+kp^$Px2u{1t0IW>La9-f;S;GjyxPUe)w>iC45-mb?CV*PsA7=v{-_-^P6Zy(;8E9>dQ3qqZK> zKPg||19!7!x^M9H)zkN8ylJpiDwQ(bH<+&Q^*#Qy_X`gCAj9=+_j)&IW+VX;AOR8} z0TLhq5+DH*AOR9M4g{KbI$F~yIL*F~SVSx#P9RPqPUFRm1W14cNPq-LfCNZ@1W14c zNPq-LfCNZ@1V)!YW3IRJJ>#4?B6i)6pm-wF`pNb zFO|@K8pkWyalazkaa*Px{b$Azp(`Fw#yv3+^F#FJrhARAO)O%brXBM{w8z8uhGxFM zA=>#?CzAFJ6O9hjZsu(w>Lc25OOwfdeCKG#Big!Kru_u;Od;a9@f6w(2NMkk6EROj zZ*Bs*Oho&(iD=heQ2k8kS;rHx8$ z8uid$d6fN?M{Ru`=CgBnjO!LM89s+=9p-&zzh^O<;qx$>hsV6+_mpd1a;+Qg$@e5c z0wh2JBtQZrKmsH{0wh2JBTk@+@35Q0e$Nq~59N~p36KB@kN^pg011!)36KB@kN^pg z011%55P_LSWe0vq$0=0c53D+gPq2x69)83Plf$RDW%i$iKT&c-+rR9hAKI5(^fUfR zs#D5 z`%w?y(-kW4KUNFqhw<=_+I|}*H#*IJw8KYg_ahc6zV(yZeoKDR4}MZRpDmN49(<*C z|I8S2=&6ojKjs5psr6AJ+Iel59DYjpOf8>nlbhq29DYmfue`VR;Ni2y_0`o!9cy`< zbzs-A&(oy8a-|(sljnVg^1RP5lsu9cORPz(OS~oVw!}M0jHF&9^%lOy1>T<&%| zcRTP`iXmy%@m=~W1Mx%BUrE0v{hIV^{&#-Ote1BBE3*-#zcL#?jwS&TAOR8}0TLhq z5+DH*Ab}AgK!4>3oh(Wv0TLhq5+DH*AOR8}0TLhq5+DH*AOR9MFoFK{5%X7Cy(8kU zOnx7HvAebakLBZbYt|W~zp_n#<)}RWkN!{kKS$aBdEl#|8bE)g0&>8V{>lRaV|NlD z0TLhq5+DH*AOR8}0TLKp0`ymo?zy9K5+DH*AOR8}0TLhq5+DH*AOR8}0TLjAR08Jr V!FT>ZH~v02evf?SU;cgYzX8a9N#Oth literal 0 HcmV?d00001 From 612c26d41c4f84271806f18fb3c1d4b722413d45 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:12:59 +0200 Subject: [PATCH 31/52] Fix kaitai MID consumption --- src/main/file/kaitai/MidIo.cpp | 16 +---- src/test/KaitaiMidTest.cpp | 104 +++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 14 deletions(-) diff --git a/src/main/file/kaitai/MidIo.cpp b/src/main/file/kaitai/MidIo.cpp index aafe8ab7..e78fd5e9 100644 --- a/src/main/file/kaitai/MidIo.cpp +++ b/src/main/file/kaitai/MidIo.cpp @@ -198,20 +198,8 @@ std::string hexByte(const int value) bool isDefaultNoteVariation(const mpc::sequencer::EventData& event) { - if (event.noteVariationType == mpc::NoteVariationTypeTune) - { - return event.noteVariationValue == mpc::DefaultNoteVariationValue; - } - if (event.noteVariationType == mpc::NoteVariationTypeDecay || - event.noteVariationType == mpc::NoteVariationTypeAttack) - { - return event.noteVariationValue == 0; - } - if (event.noteVariationType == mpc::NoteVariationTypeFilter) - { - return event.noteVariationValue == 50; - } - return false; + return event.noteVariationType == mpc::NoteVariationTypeTune && + event.noteVariationValue == mpc::DefaultNoteVariationValue; } std::string sequenceParamsText(const mpc::sequencer::Sequence& sequence) diff --git a/src/test/KaitaiMidTest.cpp b/src/test/KaitaiMidTest.cpp index 81ebe73d..cdc0ba85 100644 --- a/src/test/KaitaiMidTest.cpp +++ b/src/test/KaitaiMidTest.cpp @@ -2,6 +2,7 @@ #include "TestMpc.hpp" +#include "disk/AllLoader.hpp" #include "disk/AbstractDisk.hpp" #include "disk/MpcFile.hpp" #include "file/kaitai/MidIo.hpp" @@ -1186,6 +1187,109 @@ TEST_CASE("Kaitai standard MIDI production load preserves broad sequence semanti REQUIRE(collectParsedNotes(sequence->getTrack(1)) == expectedTrack1); } +TEST_CASE("Kaitai standard MIDI preserves zero-valued filter note variation", "[kaitai-mid]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto sequencer = mpc.getSequencer(); + auto stateManager = sequencer->getStateManager(); + auto sequence = sequencer->getSequence(0); + sequence->init(1); + sequence->setName("MIDFLT0"); + stateManager->drainQueue(); + + auto track = sequence->getTrack(0); + track->setUsedIfCurrentlyUnused(); + insertNote(track, 0, 37, 100, 24, mpc::NoteVariationTypeFilter, 0); + stateManager->drainQueue(); + + auto reloadSequence = loadSequenceWithMidIo(mpc, saveSequenceWithMidIo(sequence), "MIDFLT0.MID"); + auto reloadTrack = reloadSequence->getTrack(0); + + REQUIRE(reloadTrack->getEvents().size() == 1); + requireDetailedNote( + reloadTrack, + 0, + 0, + 37, + 100, + 24, + mpc::NoteVariationTypeFilter, + 0 + ); +} + +TEST_CASE("Kaitai standard MIDI preserves default-valued non-tune note variation", "[kaitai-mid]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto sequencer = mpc.getSequencer(); + auto stateManager = sequencer->getStateManager(); + auto sequence = sequencer->getSequence(0); + sequence->init(1); + sequence->setName("MIDFLT50"); + stateManager->drainQueue(); + + auto track = sequence->getTrack(0); + track->setUsedIfCurrentlyUnused(); + insertNote(track, 0, 37, 100, 24, mpc::NoteVariationTypeFilter, 50); + stateManager->drainQueue(); + + auto reloadSequence = loadSequenceWithMidIo(mpc, saveSequenceWithMidIo(sequence), "MIDFLT50.MID"); + auto reloadTrack = reloadSequence->getTrack(0); + + REQUIRE(reloadTrack->getEvents().size() == 1); + requireDetailedNote( + reloadTrack, + 0, + 0, + 37, + 100, + 24, + mpc::NoteVariationTypeFilter, + 50 + ); +} + +TEST_CASE("Kaitai standard MIDI preserves RESIST INTRO note variation semantics", "[kaitai-mid][resist]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpcWithoutMidiServices(mpc); + + auto allFile = installMidiResourceFile( + mpc, + "test/RealMpc2000xl/Resist/RESIST.ALL", + "RESIST.ALL" + ); + REQUIRE(allFile); + + mpc::disk::AllLoader::loadEverythingFromFile(mpc, allFile.get()); + mpc.getSequencer()->getStateManager()->drainQueue(); + + auto sourceSequence = mpc.getSequencer()->getSequence(0); + REQUIRE(sourceSequence->isUsed()); + REQUIRE(sourceSequence->getName() == "Intro"); + + const auto sourceNotes = collectDetailedParsedNotes(sourceSequence->getTrack(0)); + auto reloadedSequence = loadSequenceWithMidIo(mpc, saveSequenceWithMidIo(sourceSequence), "INTRO.MID"); + const auto reloadedNotes = collectDetailedParsedNotes(reloadedSequence->getTrack(0)); + + REQUIRE(reloadedNotes.size() == sourceNotes.size()); + for (size_t i = 0; i < sourceNotes.size(); ++i) + { + CAPTURE(i); + CAPTURE(sourceNotes[i].tick, reloadedNotes[i].tick); + CAPTURE(sourceNotes[i].note, reloadedNotes[i].note); + CAPTURE(sourceNotes[i].velocity, reloadedNotes[i].velocity); + CAPTURE(sourceNotes[i].duration, reloadedNotes[i].duration); + CAPTURE(sourceNotes[i].variationType, reloadedNotes[i].variationType); + CAPTURE(sourceNotes[i].variationValue, reloadedNotes[i].variationValue); + REQUIRE(reloadedNotes[i] == sourceNotes[i]); + } +} + TEST_CASE("Kaitai standard MIDI roundtrips MPC2000XL meta and channel events", "[kaitai-mid]") { mpc::Mpc mpc; From 34eac8b62b17344aad5f338dc22b5897f7da6b10 Mon Sep 17 00:00:00 2001 From: Izmar <3707432+izzyreal@users.noreply.github.com> Date: Sun, 5 Jul 2026 17:07:08 +0200 Subject: [PATCH 32/52] Add MPC60 SET import support --- PARSERS.md | 7 +- resources/screens/bg/conversion-table.png | Bin 0 -> 722 bytes .../screens/bg/load-a-set-replace-add.png | Bin 0 -> 1509 bytes resources/screens/bg/load-a-set-sound.png | Bin 0 -> 588 bytes resources/screens/bg/load-a-set.png | Bin 0 -> 1114 bytes resources/screens/layer2.json | 25 + resources/screens/layer3.json | 14 + src/main/concurrency/AtomicStateExchange.hpp | 4 + src/main/file/kaitai/Mpc60SetPreview.cpp | 151 ++++++ src/main/file/kaitai/Mpc60SetPreview.hpp | 48 ++ .../file/kaitai/Mpc60SetProgramLoader.cpp | 205 ++++++++ .../file/kaitai/Mpc60SetProgramLoader.hpp | 37 ++ src/main/file/kaitai/Mpc60SetSoundLoader.cpp | 410 ++++++++++++++++ src/main/file/kaitai/Mpc60SetSoundLoader.hpp | 44 ++ .../file/kaitai/generated/mpc60_set_v1.cpp | 445 ++++++++++++++++++ src/main/file/kaitai/generated/mpc60_set_v1.h | 349 ++++++++++++++ src/main/lcdgui/AllScreens.hpp | 4 + src/main/lcdgui/ScreenRegistry.hpp | 4 + src/main/lcdgui/screens/LoadScreen.cpp | 4 + .../lcdgui/screens/VmpcSettingsScreen.cpp | 4 + .../screens/window/ConversionTableScreen.cpp | 90 ++++ .../screens/window/ConversionTableScreen.hpp | 23 + .../window/LoadASetReplaceAddScreen.cpp | 125 +++++ .../window/LoadASetReplaceAddScreen.hpp | 24 + .../lcdgui/screens/window/LoadASetScreen.cpp | 81 ++++ .../lcdgui/screens/window/LoadASetScreen.hpp | 32 ++ .../screens/window/LoadASetSoundScreen.cpp | 189 ++++++++ .../screens/window/LoadASetSoundScreen.hpp | 26 + src/main/sampler/Program.cpp | 6 +- src/test/Mpc60SetPreviewTest.cpp | 96 ++++ src/test/Mpc60SetSoundLoaderTest.cpp | 126 +++++ src/test/Mpc60SetWholeLoadTest.cpp | 249 ++++++++++ src/test/SetFileUiTest.cpp | 333 +++++++++++++ test-resources/RealMpc60/Set/ROCK.SET | Bin 0 -> 769476 bytes test-resources/RealMpc60/Set/STUDIO.SET | Bin 0 -> 782412 bytes test-resources/RealMpc60/Set/UK-8.SET | Bin 0 -> 779352 bytes .../SetImportedSnd/Rock/BIG_CLAP.SND | Bin 0 -> 48042 bytes .../SetImportedSnd/Rock/HAT2CLSD.SND | Bin 0 -> 32042 bytes 38 files changed, 3150 insertions(+), 5 deletions(-) create mode 100644 resources/screens/bg/conversion-table.png create mode 100644 resources/screens/bg/load-a-set-replace-add.png create mode 100644 resources/screens/bg/load-a-set-sound.png create mode 100644 resources/screens/bg/load-a-set.png create mode 100644 src/main/file/kaitai/Mpc60SetPreview.cpp create mode 100644 src/main/file/kaitai/Mpc60SetPreview.hpp create mode 100644 src/main/file/kaitai/Mpc60SetProgramLoader.cpp create mode 100644 src/main/file/kaitai/Mpc60SetProgramLoader.hpp create mode 100644 src/main/file/kaitai/Mpc60SetSoundLoader.cpp create mode 100644 src/main/file/kaitai/Mpc60SetSoundLoader.hpp create mode 100644 src/main/file/kaitai/generated/mpc60_set_v1.cpp create mode 100644 src/main/file/kaitai/generated/mpc60_set_v1.h create mode 100644 src/main/lcdgui/screens/window/ConversionTableScreen.cpp create mode 100644 src/main/lcdgui/screens/window/ConversionTableScreen.hpp create mode 100644 src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.cpp create mode 100644 src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.hpp create mode 100644 src/main/lcdgui/screens/window/LoadASetScreen.cpp create mode 100644 src/main/lcdgui/screens/window/LoadASetScreen.hpp create mode 100644 src/main/lcdgui/screens/window/LoadASetSoundScreen.cpp create mode 100644 src/main/lcdgui/screens/window/LoadASetSoundScreen.hpp create mode 100644 src/test/Mpc60SetPreviewTest.cpp create mode 100644 src/test/Mpc60SetSoundLoaderTest.cpp create mode 100644 src/test/Mpc60SetWholeLoadTest.cpp create mode 100644 src/test/SetFileUiTest.cpp create mode 100755 test-resources/RealMpc60/Set/ROCK.SET create mode 100755 test-resources/RealMpc60/Set/STUDIO.SET create mode 100755 test-resources/RealMpc60/Set/UK-8.SET create mode 100644 test-resources/RealMpc60/SetImportedSnd/Rock/BIG_CLAP.SND create mode 100644 test-resources/RealMpc60/SetImportedSnd/Rock/HAT2CLSD.SND diff --git a/PARSERS.md b/PARSERS.md index 7a8de8a9..04b75dee 100644 --- a/PARSERS.md +++ b/PARSERS.md @@ -21,6 +21,7 @@ The generator we use is the C++ write-capable compiler from: - `standard_midi_file_with_running_status.ksy` - `mpc2000xl.mid.ksy` - `mpc2000xl.all.ksy` +- `mpc60.set.v1.ksy` ## Regenerate parsers @@ -38,7 +39,8 @@ From anywhere: /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.aps.ksy \ /Users/izmar/git/mpc2000xl_kaitai/standard_midi_file_with_running_status.ksy \ /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.mid.ksy \ - /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.all.ksy + /Users/izmar/git/mpc2000xl_kaitai/mpc2000xl.all.ksy \ + /Users/izmar/git/mpc2000xl_kaitai/mpc60.set.v1.ksy ``` ## Typical update flow @@ -66,7 +68,7 @@ cmake --build build --target mpc-tests --config Debug Run the focused Kaitai suite: ```sh -./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-snd],[kaitai-pgm],[kaitai-aps],[kaitai-mid],[kaitai-all]" +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-snd],[kaitai-pgm],[kaitai-aps],[kaitai-mid],[kaitai-all],[kaitai-set]" ``` Run one format only if needed: @@ -77,6 +79,7 @@ Run one format only if needed: ./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-snd]" ./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-mid]" ./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-all]" +./build/Debug/mpc-tests.app/Contents/MacOS/mpc-tests "[kaitai-set]" ``` ## Notes diff --git a/resources/screens/bg/conversion-table.png b/resources/screens/bg/conversion-table.png new file mode 100644 index 0000000000000000000000000000000000000000..6a1813d1febe33e4f5ba55d442082ab433698e25 GIT binary patch literal 722 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 literal 0 HcmV?d00001 diff --git a/resources/screens/bg/load-a-set.png b/resources/screens/bg/load-a-set.png new file mode 100644 index 0000000000000000000000000000000000000000..41a2a73412ca44c2fcac8ef7a410d6249b79f6e3 GIT binary patch literal 1114 zcmV-g1f~0lP) z(Q@1%3`I?+KbCxW@@dtb5z*8x{Bw5M( z>--COE9%qryR)C4pF?*^6kUB}9lbWu)i?sR5`Kv2T~9^5gR=1Zv!NyBdP;n>lULW&g0HFQ&5&hYs!5+0qZ=o(n2`s%miMk> zJ=OTT?{bQIoX7@EzU%T<8kI+7HrBI!k4#*zzReIyPo1o3rqDQAe#XAbqD3C)y3uJi z)+3pRMTco&PrrtOzF25~^c0b;(PtH1e0yd}#SS=uJ!^CT79*2Id7wjv!4{zC;0U1T z;0PS-x-jSG*I?d~$`N|cSv`Ndk(@2sk<7Qro|?kPt_$-pXodKd){Nz&4rE4lEx=~_ zUNe=}q^2IT)O4We_F?86`#D?oJygMmqSq|wu1RF1iWomNerl=iSL8b5Ucs#wO z`Dltg^@2-9X9CLzwQlmk)H66LeHSNU_??jbDY|_!<-7H+#aI)Retal;x_q3;TT%(2 zY~FuN&K6zIG<)g@2Z~HmhRlrUBdnPDa5I;A9jW0Tdk^0Tdk^ z0Tdk^0Tdk^fdfSkKhTm`NWW$+7E3a-wdRTyMthO9?u%w>fc;L%6xLSuqBsYmnCRC` zN;%f6{5WHs@p|Lw3@chp{a1r#9mWe2%07(QKVgvv=b|(Q6il zyccIO@f7D1LH1(NPWGW^?h?;6^Y$4b zXc{d3Q!Pis)Jn!du8S_z0d-NyG)&R*HJCHg?Apd>vG_Icq3D6lUgYx!o5_rHqVI7g zn}utw$8r@V?x{00K25deeeS_X&Z7fGZ)PtR3z@sJWpvZjXj`2nP0Q40nR~oHbTo$6 z9)hP+Z0l}hFRja67jQEEc3rkp+hh>fiJyB`J40(Q>LhRB@%UJyKab+;QJms?eo)ey z)YRc4FB^e#b6sjD9sCi=8q&>{o}bj~J=_S^=wlRr$cEql15y0i+|!tUJ&G@0Q%!n2 zd>B}xD(mMb zWJg-G#KKu`br23K6yUxVn+QzVLx gSjTnaRkmRM2LnNYD;^6O%K!iX07*qoM6N<$f_C*8;Q#;t literal 0 HcmV?d00001 diff --git a/resources/screens/layer2.json b/resources/screens/layer2.json index bd135ac9..be8425be 100644 --- a/resources/screens/layer2.json +++ b/resources/screens/layer2.json @@ -93,6 +93,31 @@ "fblabels" : [ null, null, "CLEAR", "CANCEL", "LOAD", null ], "fbtypes" : [ null, null, 1, 0, 1, null ] }, +"load-a-set": +{ + "fblabels" : [ null, null, "SOUND", "CANCEL", "LOAD", null ], + "fbtypes" : [ null, null, 1, 0, 1, null ] +}, +"conversion-table": +{ + "labels" : [ "MPC60 Pad:", "Becomes note:" ], + "x" : [ 67, 67 ], + "y" : [ 15, 37 ], + "tfsize" : [ 90, 36 ], + "parameters" : [ "mpc60-pad", "becomes-note" ], + "fblabels" : [ null, null, null, "CANCEL", "DO IT", null ], + "fbtypes" : [ null, null, null, 0, 1, null ] +}, +"load-a-set-replace-add": +{ + "labels" : [ ":" ], + "x" : [ 77 ], + "y" : [ 21 ], + "tfsize" : [ 60 ], + "parameters" : [ "load-replace-sound" ], + "fblabels" : [ null, null, "CLEAR", "CANCEL", "LOAD", null ], + "fbtypes" : [ null, null, 1, 0, 1, null ] +}, "save-all-file": { "labels" : [ "File\u00CEname:" ], diff --git a/resources/screens/layer3.json b/resources/screens/layer3.json index afd20243..6e635258 100644 --- a/resources/screens/layer3.json +++ b/resources/screens/layer3.json @@ -4,6 +4,20 @@ "fblabels" : [ null, null, "REPLAC", "CANCEL", "RENAME", null], "fbtypes" : [ null, null, 1, 0, 1, null ] }, +"load-a-set-sound": +{ + "labels" : [ "MPC60 pad:" ], + "x" : [ 64 ], + "y" : [ 21 ], + "tfsize" : [ 90 ], + "parameters" : [ "mpc60-pad" ], + "infowidgets" : [ "file" ], + "infox" : [ 95 ], + "infoy" : [ 35 ], + "infosize" : [ 126 ], + "fblabels" : [ null, null, null, "CANCEL", "LOAD", null ], + "fbtypes" : [ null, null, null, 0, 1, null ] +}, "vmpc-record-jam": { "fblabels" : [ null, null, null, "CANCEL", "OK", null], diff --git a/src/main/concurrency/AtomicStateExchange.hpp b/src/main/concurrency/AtomicStateExchange.hpp index 39572f3b..b8c89d58 100644 --- a/src/main/concurrency/AtomicStateExchange.hpp +++ b/src/main/concurrency/AtomicStateExchange.hpp @@ -47,6 +47,10 @@ namespace mpc::concurrency callbackQueue.enqueue(std::move(cb)); } + // Must be called by the owner thread for this state exchange. For + // PerformanceManager, that is the audio thread; other threads should + // enqueue messages and, if needed, enqueue a callback to observe + // completion after the owner thread has published the new state. void drainQueue() noexcept { alignas(Message) unsigned char msgBuf[sizeof(Message)]; diff --git a/src/main/file/kaitai/Mpc60SetPreview.cpp b/src/main/file/kaitai/Mpc60SetPreview.cpp new file mode 100644 index 00000000..e81de700 --- /dev/null +++ b/src/main/file/kaitai/Mpc60SetPreview.cpp @@ -0,0 +1,151 @@ +#include "Mpc60SetPreview.hpp" + +#include "disk/MpcFile.hpp" +#include "file/kaitai/generated/mpc60_set_v1.h" + +#include + +#include +#include +#include +#include +#include + +namespace +{ + constexpr uint8_t kNoSoundDirectoryEntry = 255; + + std::string trimRightSpaces(std::string value) + { + while (!value.empty() && value.back() == ' ') + { + value.pop_back(); + } + return value; + } + + constexpr std::array kMpc60PadNames{ + "hiht_clsd", "hiht_medm", "hiht_open", "snr1", "snr2", "bass", + "tom1", "tom2", "tom3", "tom4", "rid1", "rid2", + "crs1", "crs2", "prc1", "prc2", "prc3", "prc4", + "dr01", "dr02", "dr03", "dr04", "dr05", "dr06", + "dr07", "dr08", "dr09", "dr10", "dr11", "dr12", + "dr13", "dr14", "dr15", "dr16", + }; + + std::string formatSourceSlotLabel(const char bank, const int slotNumber) + { + std::ostringstream oss; + oss << bank << std::setw(2) << std::setfill('0') << slotNumber; + return oss.str(); + } +} + +const mpc::file::kaitai::Mpc60SetPreviewEntry * +mpc::file::kaitai::Mpc60SetPreview::assignedSoundAtMpc60Pad( + const size_t padIndex) const +{ + if (padIndex >= soundDirectoryEntryIndexByMpc60Pad.size()) + { + return nullptr; + } + + const auto soundIndex = soundDirectoryEntryIndexByMpc60Pad[padIndex]; + if (soundIndex >= soundDirectoryEntries.size()) + { + return nullptr; + } + + return &soundDirectoryEntries[soundIndex]; +} + +std::string +mpc::file::kaitai::Mpc60SetPreview::mpc60PadName(const size_t padIndex) +{ + if (padIndex >= kMpc60PadNames.size()) + { + return {}; + } + + return std::string(kMpc60PadNames[padIndex]); +} + +std::string +mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel( + const size_t padIndex) +{ + if (padIndex <= 2) + { + return formatSourceSlotLabel('A', 1); + } + + if (padIndex <= 17) + { + return formatSourceSlotLabel('A', static_cast(padIndex) - 1); + } + + if (padIndex <= 33) + { + return formatSourceSlotLabel('B', static_cast(padIndex) - 17); + } + + return {}; +} + +mpc::file::kaitai::Mpc60SetPreview +mpc::file::kaitai::Mpc60SetPreviewLoader::loadPreview( + const std::shared_ptr &file) +{ + return loadPreview(file->getBytes()); +} + +mpc::file::kaitai::Mpc60SetPreview +mpc::file::kaitai::Mpc60SetPreviewLoader::loadPreview( + const std::vector &bytes) +{ + std::stringstream parseStream( + std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | std::ios::binary + ); + ::kaitai::kstream parseIo(&parseStream); + mpc60_set_v1_t parsed(&parseIo); + parsed._read(); + + Mpc60SetPreview result; + result.totalNumberOfSampleWords = parsed.total_number_of_sample_words()->value(); + result.useMasterMixData = + parsed.use_master_mix_data() == mpc60_set_v1_t::USE_MASTER_MIX_DATA_USE; + + result.soundDirectoryEntries.reserve(parsed.sound_directory_entry()->size()); + for (const auto &entry : *parsed.sound_directory_entry()) + { + Mpc60SetPreviewEntry previewEntry; + previewEntry.name = trimRightSpaces(entry->name()); + previewEntry.sharedSoundLink = entry->shared_sound_link(); + previewEntry.lengthInSamples = entry->length_in_samples(); + previewEntry.startAddressForPlaying = entry->start_address_for_playing(); + previewEntry.soundDuration = entry->sound_duration(); + previewEntry.requestedStereoMixVolume = + entry->requested_stereo_mix_volume(); + previewEntry.requestedStereoMixPan = entry->requested_stereo_mix_pan(); + previewEntry.isHihat = + entry->sound_characteristics()->normal_or_hihat_sound() == + mpc60_set_v1_t::NORMAL_OR_HIHAT_HIHAT; + result.soundDirectoryEntries.push_back(std::move(previewEntry)); + } + + result.soundDirectoryEntryIndexByMpc60Pad.reserve( + parsed.sound_map()->size() + ); + for (const auto entryIndex : *parsed.sound_map()) + { + if (entryIndex != kNoSoundDirectoryEntry && + entryIndex >= result.soundDirectoryEntries.size()) + { + throw std::runtime_error("MPC60 SET sound_map entry index out of range"); + } + result.soundDirectoryEntryIndexByMpc60Pad.push_back(entryIndex); + } + + return result; +} diff --git a/src/main/file/kaitai/Mpc60SetPreview.hpp b/src/main/file/kaitai/Mpc60SetPreview.hpp new file mode 100644 index 00000000..9ceefc45 --- /dev/null +++ b/src/main/file/kaitai/Mpc60SetPreview.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::file::kaitai +{ + struct Mpc60SetPreviewEntry + { + std::string name; + uint8_t sharedSoundLink = 0; + uint32_t lengthInSamples = 0; + uint32_t startAddressForPlaying = 0; + uint16_t soundDuration = 0; + uint8_t requestedStereoMixVolume = 0; + uint8_t requestedStereoMixPan = 0; + bool isHihat = false; + }; + + struct Mpc60SetPreview + { + uint32_t totalNumberOfSampleWords = 0; + bool useMasterMixData = false; + std::vector soundDirectoryEntries; + std::vector soundDirectoryEntryIndexByMpc60Pad; + + const Mpc60SetPreviewEntry *assignedSoundAtMpc60Pad(size_t padIndex) const; + + static std::string mpc60PadName(size_t padIndex); + static std::string mpc60SourceSlotLabel(size_t padIndex); + }; + + class Mpc60SetPreviewLoader + { + public: + static Mpc60SetPreview + loadPreview(const std::shared_ptr &file); + + static Mpc60SetPreview loadPreview(const std::vector &bytes); + }; +} diff --git a/src/main/file/kaitai/Mpc60SetProgramLoader.cpp b/src/main/file/kaitai/Mpc60SetProgramLoader.cpp new file mode 100644 index 00000000..6e89b61c --- /dev/null +++ b/src/main/file/kaitai/Mpc60SetProgramLoader.cpp @@ -0,0 +1,205 @@ +#include "file/kaitai/Mpc60SetProgramLoader.hpp" + +#include "Mpc.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/Mpc60SetPreview.hpp" +#include "file/kaitai/Mpc60SetSoundLoader.hpp" +#include "lcdgui/LayeredScreen.hpp" +#include "performance/PerformanceManager.hpp" +#include "performance/PerformanceMessage.hpp" +#include "sampler/Pad.hpp" +#include "sampler/Program.hpp" +#include "sampler/Sampler.hpp" +#include "sequencer/Bus.hpp" +#include "sequencer/Sequencer.hpp" +#include "sequencer/Track.hpp" +#include "StrUtil.hpp" + +#include +#include +#include + +using namespace mpc::file::kaitai; + +namespace +{ +bool loadIntoProgram( + mpc::Mpc &mpc, + const std::shared_ptr &file, + const Mpc60SetPreview &preview, + const Mpc60SetProgramLoader::ConversionTable &conversionTable, + const std::shared_ptr &program, + mpc::performance::Program &perfProgram) +{ + auto sampler = mpc.getSampler(); + const auto existingSoundCount = sampler->getSoundCount(); + std::vector soundIndexByEntry(preview.soundDirectoryEntries.size(), -1); + + for (size_t entryIndex = 0; entryIndex < preview.soundDirectoryEntries.size(); + ++entryIndex) + { + const auto soundName = preview.soundDirectoryEntries[entryIndex].name; + if (preview.soundDirectoryEntries[entryIndex].lengthInSamples == 0) + { + continue; + } + + const auto msg = + "Loading " + + mpc::StrUtil::toUpper(mpc::StrUtil::padRight(soundName, " ", 16)); + const auto ls = mpc.getLayeredScreen(); + ls->postToUiThread(mpc::utils::Task( + [ls, msg] + { + ls->showPopup(msg); + })); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + auto sound = sampler->addSound(40000); + if (sound == nullptr) + { + return false; + } + + const auto result = + Mpc60SetSoundLoader::loadSoundDirectoryEntry(file, entryIndex, sound); + + if (!result.has_value()) + { + sampler->deleteSound(sound); + return false; + } + + soundIndexByEntry[entryIndex] = + existingSoundCount + static_cast(entryIndex); + } + + program->setName(file->getNameWithoutExtension()); + perfProgram.used = true; + + const auto &padNotes = mpc::sampler::Pad::getPadNotes(mpc); + for (int8_t padIndex = 0; + padIndex < mpc::Mpc2000XlSpecs::PROGRAM_PAD_COUNT; + ++padIndex) + { + perfProgram.pads[padIndex].note = padNotes[padIndex]; + } + + for (size_t mpc60PadIndex = 0; + mpc60PadIndex < preview.soundDirectoryEntryIndexByMpc60Pad.size() && + mpc60PadIndex < conversionTable.size(); + ++mpc60PadIndex) + { + const auto entryIndex = preview.soundDirectoryEntryIndexByMpc60Pad[mpc60PadIndex]; + if (entryIndex >= soundIndexByEntry.size()) + { + continue; + } + + const auto soundIndex = soundIndexByEntry[entryIndex]; + + if (soundIndex < 0) + { + continue; + } + + perfProgram + .noteParameters[conversionTable[mpc60PadIndex].get() - + mpc::MinDrumNoteNumber.get()] + .soundIndex = soundIndex; + } + + if (const auto track = mpc.getSequencer()->getSelectedTrack(); + mpc::sequencer::isDrumBusType(track->getBusType())) + { + const auto drumBus = mpc.getSequencer()->getDrumBus(track->getBusType()); + drumBus->setProgramIndex(program->getProgramIndex()); + } + + return true; +} + +void resetPerformancePrograms(mpc::Mpc &mpc) +{ + for (int i = 0; i < mpc::Mpc2000XlSpecs::MAX_PROGRAM_COUNT; ++i) + { + mpc::performance::UpdateProgramBulk msg; + msg.programIndex = mpc::ProgramIndex(i); + mpc.getPerformanceManager().lock()->enqueue( + mpc::performance::PerformanceMessage{std::move(msg)}); + } +} +} // namespace + +Mpc60SetProgramLoader::ConversionTable +Mpc60SetProgramLoader::defaultConversionTable() +{ + return ConversionTable{ + DrumNoteNumber(42), DrumNoteNumber(82), DrumNoteNumber(46), + DrumNoteNumber(38), DrumNoteNumber(37), DrumNoteNumber(36), + DrumNoteNumber(48), DrumNoteNumber(47), DrumNoteNumber(45), + DrumNoteNumber(43), DrumNoteNumber(51), DrumNoteNumber(53), + DrumNoteNumber(49), DrumNoteNumber(55), DrumNoteNumber(69), + DrumNoteNumber(54), DrumNoteNumber(56), DrumNoteNumber(39), + DrumNoteNumber(57), DrumNoteNumber(58), DrumNoteNumber(59), + DrumNoteNumber(60), DrumNoteNumber(61), DrumNoteNumber(62), + DrumNoteNumber(63), DrumNoteNumber(64), DrumNoteNumber(65), + DrumNoteNumber(66), DrumNoteNumber(67), DrumNoteNumber(68), + DrumNoteNumber(70), DrumNoteNumber(71), DrumNoteNumber(72), + DrumNoteNumber(73)}; +} + +bool Mpc60SetProgramLoader::load( + mpc::Mpc &mpc, + const std::shared_ptr &file, + const Mpc60SetPreview &preview, + const ConversionTable &conversionTable, + const bool clearExisting) +{ + auto sampler = mpc.getSampler(); + + if (clearExisting) + { + sampler->deleteAllSamples(); + resetPerformancePrograms(mpc); + + mpc::performance::UpdateProgramBulk msg; + msg.programIndex = mpc::ProgramIndex(0); + const auto loaded = loadIntoProgram(mpc, file, preview, conversionTable, + mpc.getSampler()->getProgram(0), + msg.program); + if (loaded) + { + mpc.getPerformanceManager().lock()->enqueue( + mpc::performance::PerformanceMessage{std::move(msg)}); + } + return loaded; + } + + std::shared_ptr program; + for (int i = 0; i < mpc::Mpc2000XlSpecs::MAX_PROGRAM_COUNT; ++i) + { + const auto candidate = sampler->getProgram(i); + if (!candidate->isUsed()) + { + program = candidate; + break; + } + } + + if (!program) + { + return false; + } + + mpc::performance::UpdateProgramBulk msg; + msg.programIndex = program->getProgramIndex(); + const auto loaded = loadIntoProgram(mpc, file, preview, conversionTable, + program, msg.program); + if (loaded) + { + mpc.getPerformanceManager().lock()->enqueue( + mpc::performance::PerformanceMessage{std::move(msg)}); + } + return loaded; +} diff --git a/src/main/file/kaitai/Mpc60SetProgramLoader.hpp b/src/main/file/kaitai/Mpc60SetProgramLoader.hpp new file mode 100644 index 00000000..87934505 --- /dev/null +++ b/src/main/file/kaitai/Mpc60SetProgramLoader.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "IntTypes.hpp" + +#include +#include + +namespace mpc +{ + class Mpc; +} + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::file::kaitai +{ + struct Mpc60SetPreview; + + class Mpc60SetProgramLoader + { + public: + static constexpr size_t kMpc60PadCount = 34; + using ConversionTable = std::array; + + static ConversionTable defaultConversionTable(); + + static bool load( + Mpc &mpc, + const std::shared_ptr &file, + const Mpc60SetPreview &preview, + const ConversionTable &conversionTable, + bool clearExisting); + }; +} diff --git a/src/main/file/kaitai/Mpc60SetSoundLoader.cpp b/src/main/file/kaitai/Mpc60SetSoundLoader.cpp new file mode 100644 index 00000000..e48cf89a --- /dev/null +++ b/src/main/file/kaitai/Mpc60SetSoundLoader.cpp @@ -0,0 +1,410 @@ +#include "file/kaitai/Mpc60SetSoundLoader.hpp" + +#include "SampleOps.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/generated/mpc60_set_v1.h" +#include "sampler/Sound.hpp" + +#include + +#include +#include +#include +#include + +namespace +{ + constexpr int kMpc60SampleRate = 40000; + constexpr uint16_t kMpc2000xlSetImportScale = 0x7fff; + + std::string trimRightSpaces(std::string value) + { + while (!value.empty() && value.back() == ' ') + { + value.pop_back(); + } + return value; + } + + uint16_t u16(const uint32_t value) + { + return static_cast(value & 0xffffU); + } + + int16_t s16(const uint32_t value) + { + return static_cast(u16(value)); + } + + uint16_t cwd(const uint16_t ax) + { + return (ax & 0x8000U) != 0 ? 0xffffU : 0U; + } + + uint16_t shl1(uint16_t &value) + { + const auto carry = static_cast((value & 0x8000U) != 0); + value = u16(static_cast(value) << 1U); + return carry; + } + + uint16_t rcl1(uint16_t &value, const uint16_t carryIn) + { + const auto carry = static_cast((value & 0x8000U) != 0); + value = u16((static_cast(value) << 1U) | (carryIn & 1U)); + return carry; + } + + uint16_t sar1(uint16_t &value) + { + const auto carry = static_cast(value & 1U); + value = u16((value >> 1U) | (value & 0x8000U)); + return carry; + } + + uint16_t rcr1(uint16_t &value, const uint16_t carryIn) + { + const auto carry = static_cast(value & 1U); + value = u16((value >> 1U) | ((carryIn & 1U) << 15U)); + return carry; + } + + uint16_t add16(uint16_t &a, const uint16_t b) + { + const auto sum = static_cast(a) + b; + a = u16(sum); + return static_cast(sum > 0xffffU); + } + + uint16_t adc16(uint16_t &a, const uint16_t b, const uint16_t carryIn) + { + const auto sum = static_cast(a) + b + (carryIn & 1U); + a = u16(sum); + return static_cast(sum > 0xffffU); + } + + uint16_t sub16(uint16_t &a, const uint16_t b) + { + const auto carry = static_cast(a < b); + a = u16(static_cast(a) - b); + return carry; + } + + uint16_t sbb16(uint16_t &a, const uint16_t b, const uint16_t carryIn) + { + const auto rhs = static_cast(b) + (carryIn & 1U); + const auto carry = static_cast(a < rhs); + a = u16(static_cast(a) - rhs); + return carry; + } + + void leftShift48(uint16_t &bx, uint16_t &ax, uint16_t &dx, const int count) + { + uint16_t carry = 0; + for (int i = 0; i < count; ++i) + { + carry = shl1(bx); + carry = rcl1(ax, carry); + carry = rcl1(dx, carry); + } + } + + void arithmeticRightShift32(uint16_t &hi, uint16_t &lo, const int count) + { + uint16_t carry = 0; + for (int i = 0; i < count; ++i) + { + carry = sar1(hi); + carry = rcr1(lo, carry); + } + } + + enum class TransformOp + { + Add, + Subtract, + ShiftOnly, + }; + + struct TransformStep + { + TransformOp op; + int shift; + }; + + std::pair + transform(const uint16_t lo, const uint16_t hi, + const std::initializer_list steps) + { + auto bx = lo; + auto ax = hi; + auto dx = cwd(ax); + const auto sign = dx; + + for (const auto &step : steps) + { + leftShift48(bx, ax, dx, step.shift); + + if (step.op == TransformOp::Add) + { + auto carry = add16(bx, lo); + carry = adc16(ax, hi, carry); + adc16(dx, sign, carry); + } + else if (step.op == TransformOp::Subtract) + { + auto carry = sub16(bx, lo); + carry = sbb16(ax, hi, carry); + sbb16(dx, sign, carry); + } + } + + arithmeticRightShift32(dx, ax, 4); + return {ax, dx}; + } + + class Mpc60SetSampleConverter + { + public: + int16_t convert(const uint64_t sampleWord, const bool isOddWordIndex) + { + const auto inputWord = + toFirmwareInputWord(sampleWord, isOddWordIndex); + + const auto oldLo = stateLo; + const auto oldHi = stateHi; + + const auto a = transform(oldLo, oldHi, + {{TransformOp::Add, 2}, + {TransformOp::Subtract, 4}, + {TransformOp::Add, 4}, + {TransformOp::Add, 4}, + {TransformOp::Add, 2}, + {TransformOp::Subtract, 3}}); + + auto newLo = oldLo; + auto newHi = inputWord; + arithmeticRightShift32(newHi, newLo, 8); + auto carry = add16(newLo, a.first); + adc16(newHi, a.second, carry); + + const auto b = transform(newLo, newHi, + {{TransformOp::Add, 1}, + {TransformOp::Subtract, 3}, + {TransformOp::Subtract, 3}, + {TransformOp::Subtract, 3}, + {TransformOp::Add, 5}, + {TransformOp::ShiftOnly, 3}}); + + const auto c = transform(oldLo, oldHi, + {{TransformOp::Subtract, 2}, + {TransformOp::Add, 3}, + {TransformOp::Add, 4}, + {TransformOp::Add, 1}, + {TransformOp::Subtract, 3}, + {TransformOp::Add, 2}}); + + auto mixedLo = b.first; + auto mixedHi = b.second; + carry = add16(mixedLo, c.first); + adc16(mixedHi, c.second, carry); + + stateLo = newLo; + stateHi = newHi; + + auto tmpLo = mixedLo; + auto tmpHi = mixedHi; + arithmeticRightShift32(tmpHi, tmpLo, 3); + + auto outLo = mixedLo; + auto outHi = mixedHi; + carry = add16(outLo, tmpLo); + carry = adc16(outHi, tmpHi, carry); + + arithmeticRightShift32(tmpHi, tmpLo, 1); + carry = add16(outLo, tmpLo); + adc16(outHi, tmpHi, carry); + + return scaleAndClip(outLo, outHi); + } + + private: + uint16_t stateLo = 0; + uint16_t stateHi = 0; + + // Generated read_bits_int_le(12) values preserve the firmware bytes, + // but the second word in each 3-byte pair has the shared nibble in the + // low bits. Normalize to the input word used by MPC2000XL firmware + // routine 35b0:1eac before applying the fixed-point converter. + static uint16_t toFirmwareInputWord(const uint64_t sampleWord, + const bool isOddWordIndex) + { + if (isOddWordIndex) + { + return static_cast((sampleWord & 0x0fffU) << 4U); + } + + return static_cast(((sampleWord & 0x00ffU) << 8U) | + ((sampleWord & 0x0f00U) >> 4U)); + } + + static int16_t scaleAndClip(uint16_t lo, uint16_t hi) + { + const auto negative = (hi & 0x8000U) != 0; + if (!negative) + { + if ((hi >> 8U) != 0) + { + return static_cast(kMpc2000xlSetImportScale - 1); + } + + const auto magnitude = static_cast( + ((hi & 0x00ffU) << 8U) | ((lo >> 8U) & 0x00ffU)); + if (magnitude >= kMpc2000xlSetImportScale) + { + return static_cast(kMpc2000xlSetImportScale - 1); + } + } + else + { + if ((hi >> 8U) != 0x00ffU) + { + return static_cast( + -static_cast(kMpc2000xlSetImportScale - 1)); + } + + const auto magnitude = static_cast( + -static_cast(static_cast( + ((hi & 0x00ffU) << 8U) | ((lo >> 8U) & 0x00ffU)))); + if (magnitude >= kMpc2000xlSetImportScale) + { + return static_cast( + -static_cast(kMpc2000xlSetImportScale - 1)); + } + } + + for (int i = 0; i < 7; ++i) + { + const auto carry = shl1(lo); + rcl1(hi, carry); + } + + const auto dividend = static_cast(s16(hi)) * 65536 + lo; + return static_cast(dividend / kMpc2000xlSetImportScale); + } + }; + + float sampleWordToFloat(Mpc60SetSampleConverter &converter, + const uint64_t sampleWord, + const bool isOddWordIndex) + { + return mpc::sampleops::short_to_float( + converter.convert(sampleWord, isOddWordIndex)); + } + + sound_or_error loadEntry(mpc60_set_v1_t &parsed, + const size_t soundDirectoryEntryIndex, + const std::shared_ptr &sound) + { + const auto *entries = parsed.sound_directory_entry(); + if (soundDirectoryEntryIndex >= entries->size()) + { + return tl::make_unexpected("SET sound entry index out of range"); + } + + const auto &entry = entries->at(soundDirectoryEntryIndex); + const auto start = + static_cast(entry->start_address_in_memory()); + const auto length = static_cast(entry->length_in_samples()); + const auto *sampleWords = parsed.sound_samples(); + + if (start > sampleWords->size() || length > sampleWords->size() - start) + { + return tl::make_unexpected("SET sound sample range out of bounds"); + } + + sound->setName(trimRightSpaces(entry->name())); + sound->setSampleRate(kMpc60SampleRate); + sound->setMono(true); + sound->setLevel(100); + sound->setTune(0); + sound->setLoopEnabled(false); + + auto sampleData = sound->getMutableSampleData(); + sampleData->clear(); + sampleData->reserve(length); + + Mpc60SetSampleConverter converter; + for (size_t i = 0; i < length; ++i) + { + sampleData->push_back(sampleWordToFloat(converter, + sampleWords->at(start + i), + ((start + i) % 2U) != 0)); + } + + sound->setStart(0); + sound->setEnd(sound->getLastFrameIndex()); + sound->setLoopTo(0); + + return sound; + } +} // namespace + +sound_or_error mpc::file::kaitai::Mpc60SetSoundLoader::loadSoundDirectoryEntry( + const std::shared_ptr &file, + const size_t soundDirectoryEntryIndex, + const std::shared_ptr &sound) +{ + return loadSoundDirectoryEntry(file->getBytes(), soundDirectoryEntryIndex, + sound); +} + +sound_or_error mpc::file::kaitai::Mpc60SetSoundLoader::loadSoundDirectoryEntry( + const std::vector &bytes, const size_t soundDirectoryEntryIndex, + const std::shared_ptr &sound) +{ + std::stringstream parseStream(std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | + std::ios::binary); + ::kaitai::kstream parseIo(&parseStream); + mpc60_set_v1_t parsed(&parseIo); + parsed._read(); + + return loadEntry(parsed, soundDirectoryEntryIndex, sound); +} + +sound_or_error +mpc::file::kaitai::Mpc60SetSoundLoader::loadAssignedSoundAtMpc60Pad( + const std::shared_ptr &file, const size_t mpc60PadIndex, + const std::shared_ptr &sound) +{ + return loadAssignedSoundAtMpc60Pad(file->getBytes(), mpc60PadIndex, sound); +} + +sound_or_error +mpc::file::kaitai::Mpc60SetSoundLoader::loadAssignedSoundAtMpc60Pad( + const std::vector &bytes, const size_t mpc60PadIndex, + const std::shared_ptr &sound) +{ + std::stringstream parseStream(std::string(bytes.begin(), bytes.end()), + std::ios::in | std::ios::out | + std::ios::binary); + ::kaitai::kstream parseIo(&parseStream); + mpc60_set_v1_t parsed(&parseIo); + parsed._read(); + + const auto *soundMap = parsed.sound_map(); + if (mpc60PadIndex >= soundMap->size()) + { + return tl::make_unexpected("SET MPC60 pad index out of range"); + } + + const auto entryIndex = soundMap->at(mpc60PadIndex); + const auto *entries = parsed.sound_directory_entry(); + if (entryIndex >= entries->size()) + { + return tl::make_unexpected("SET sound entry index out of range"); + } + + return loadEntry(parsed, entryIndex, sound); +} diff --git a/src/main/file/kaitai/Mpc60SetSoundLoader.hpp b/src/main/file/kaitai/Mpc60SetSoundLoader.hpp new file mode 100644 index 00000000..f9731292 --- /dev/null +++ b/src/main/file/kaitai/Mpc60SetSoundLoader.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "mpc_types.hpp" + +#include +#include +#include + +namespace mpc::disk +{ + class MpcFile; +} + +namespace mpc::sampler +{ + class Sound; +} + +namespace mpc::file::kaitai +{ + class Mpc60SetSoundLoader + { + public: + static sound_or_error loadSoundDirectoryEntry( + const std::shared_ptr &file, + size_t soundDirectoryEntryIndex, + const std::shared_ptr &sound); + + static sound_or_error loadSoundDirectoryEntry( + const std::vector &bytes, + size_t soundDirectoryEntryIndex, + const std::shared_ptr &sound); + + static sound_or_error loadAssignedSoundAtMpc60Pad( + const std::shared_ptr &file, + size_t mpc60PadIndex, + const std::shared_ptr &sound); + + static sound_or_error loadAssignedSoundAtMpc60Pad( + const std::vector &bytes, + size_t mpc60PadIndex, + const std::shared_ptr &sound); + }; +} diff --git a/src/main/file/kaitai/generated/mpc60_set_v1.cpp b/src/main/file/kaitai/generated/mpc60_set_v1.cpp new file mode 100644 index 00000000..94080a85 --- /dev/null +++ b/src/main/file/kaitai/generated/mpc60_set_v1.cpp @@ -0,0 +1,445 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "mpc60_set_v1.h" +#include "kaitai/exceptions.h" +#include +#include +const std::set mpc60_set_v1_t::_values_analog_output_jack_t{ + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_FALSE, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_1, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_2, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_3, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_4, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_5, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_6, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_7, + mpc60_set_v1_t::ANALOG_OUTPUT_JACK_JACK_8, +}; +bool mpc60_set_v1_t::_is_defined_analog_output_jack_t(mpc60_set_v1_t::analog_output_jack_t v) { + return mpc60_set_v1_t::_values_analog_output_jack_t.find(v) != mpc60_set_v1_t::_values_analog_output_jack_t.end(); +} +const std::set mpc60_set_v1_t::_values_filter_range_t{ + mpc60_set_v1_t::FILTER_RANGE_LESS_THAN_OR_EQUALS_47_KHZ, + mpc60_set_v1_t::FILTER_RANGE_GREATER_THAN_47_KHZ, +}; +bool mpc60_set_v1_t::_is_defined_filter_range_t(mpc60_set_v1_t::filter_range_t v) { + return mpc60_set_v1_t::_values_filter_range_t.find(v) != mpc60_set_v1_t::_values_filter_range_t.end(); +} +const std::set mpc60_set_v1_t::_values_normal_or_hihat_t{ + mpc60_set_v1_t::NORMAL_OR_HIHAT_NORMAL, + mpc60_set_v1_t::NORMAL_OR_HIHAT_HIHAT, +}; +bool mpc60_set_v1_t::_is_defined_normal_or_hihat_t(mpc60_set_v1_t::normal_or_hihat_t v) { + return mpc60_set_v1_t::_values_normal_or_hihat_t.find(v) != mpc60_set_v1_t::_values_normal_or_hihat_t.end(); +} +const std::set mpc60_set_v1_t::_values_physical_drum_t{ + mpc60_set_v1_t::PHYSICAL_DRUM_HIHT_CLSD, + mpc60_set_v1_t::PHYSICAL_DRUM_HIHT_MEDM, + mpc60_set_v1_t::PHYSICAL_DRUM_HIHT_OPEN, + mpc60_set_v1_t::PHYSICAL_DRUM_SNR1, + mpc60_set_v1_t::PHYSICAL_DRUM_SNR2, + mpc60_set_v1_t::PHYSICAL_DRUM_BASS, + mpc60_set_v1_t::PHYSICAL_DRUM_TOM1, + mpc60_set_v1_t::PHYSICAL_DRUM_TOM2, + mpc60_set_v1_t::PHYSICAL_DRUM_TOM3, + mpc60_set_v1_t::PHYSICAL_DRUM_TOM4, + mpc60_set_v1_t::PHYSICAL_DRUM_RID1, + mpc60_set_v1_t::PHYSICAL_DRUM_RID2, + mpc60_set_v1_t::PHYSICAL_DRUM_CRS1, + mpc60_set_v1_t::PHYSICAL_DRUM_CRS2, + mpc60_set_v1_t::PHYSICAL_DRUM_PRC1, + mpc60_set_v1_t::PHYSICAL_DRUM_PRC2, + mpc60_set_v1_t::PHYSICAL_DRUM_PRC3, + mpc60_set_v1_t::PHYSICAL_DRUM_PRC4, + mpc60_set_v1_t::PHYSICAL_DRUM_DR01, + mpc60_set_v1_t::PHYSICAL_DRUM_DR02, + mpc60_set_v1_t::PHYSICAL_DRUM_DR03, + mpc60_set_v1_t::PHYSICAL_DRUM_DR04, + mpc60_set_v1_t::PHYSICAL_DRUM_DR05, + mpc60_set_v1_t::PHYSICAL_DRUM_DR06, + mpc60_set_v1_t::PHYSICAL_DRUM_DR07, + mpc60_set_v1_t::PHYSICAL_DRUM_DR08, + mpc60_set_v1_t::PHYSICAL_DRUM_DR09, + mpc60_set_v1_t::PHYSICAL_DRUM_DR10, + mpc60_set_v1_t::PHYSICAL_DRUM_DR11, + mpc60_set_v1_t::PHYSICAL_DRUM_DR12, + mpc60_set_v1_t::PHYSICAL_DRUM_DR13, + mpc60_set_v1_t::PHYSICAL_DRUM_DR14, + mpc60_set_v1_t::PHYSICAL_DRUM_DR15, + mpc60_set_v1_t::PHYSICAL_DRUM_DR16, +}; +bool mpc60_set_v1_t::_is_defined_physical_drum_t(mpc60_set_v1_t::physical_drum_t v) { + return mpc60_set_v1_t::_values_physical_drum_t.find(v) != mpc60_set_v1_t::_values_physical_drum_t.end(); +} +const std::set mpc60_set_v1_t::_values_use_master_mix_data_t{ + mpc60_set_v1_t::USE_MASTER_MIX_DATA_IGNORE, + mpc60_set_v1_t::USE_MASTER_MIX_DATA_USE, +}; +bool mpc60_set_v1_t::_is_defined_use_master_mix_data_t(mpc60_set_v1_t::use_master_mix_data_t v) { + return mpc60_set_v1_t::_values_use_master_mix_data_t.find(v) != mpc60_set_v1_t::_values_use_master_mix_data_t.end(); +} + +mpc60_set_v1_t::mpc60_set_v1_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mpc60_set_v1_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root ? p__root : this; + m__dirty = false; +} + +void mpc60_set_v1_t::_read() { + m_file_id = m__io->read_bytes(1); + if (!(m_file_id == std::string("\x02", 1))) { + throw kaitai::validation_not_equal_error(std::string("\x02", 1), m_file_id, m__io, std::string("/seq/0")); + } + m_file_format_version = m__io->read_bytes(1); + if (!(m_file_format_version == std::string("\x00", 1))) { + throw kaitai::validation_not_equal_error(std::string("\x00", 1), m_file_format_version, m__io, std::string("/seq/1")); + } + m_total_number_of_sample_words = std::unique_ptr(new u3le_t(m__io, this, m__root)); + m_total_number_of_sample_words->_read(); + m_sound_directory_entry = std::unique_ptr>>(new std::vector>()); + const int l_sound_directory_entry = 34; + for (int i = 0; i < l_sound_directory_entry; i++) { + std::unique_ptr _t_sound_directory_entry = std::unique_ptr(new sound_directory_entry_t(m__io, this, m__root)); + try { + _t_sound_directory_entry->_read(); + } catch(...) { + m_sound_directory_entry->push_back(std::move(_t_sound_directory_entry)); + throw; + } + m_sound_directory_entry->push_back(std::move(_t_sound_directory_entry)); + } + m_sound_map = std::unique_ptr>(new std::vector()); + const int l_sound_map = 34; + for (int i = 0; i < l_sound_map; i++) { + m_sound_map->push_back(std::move(m__io->read_u1())); + } + m_use_master_mix_data = static_cast(m__io->read_u1()); + m_master_stereo_mix = m__io->read_bytes(32); + m_master_stereo_pan = m__io->read_bytes(32); + m_master_echo_mix = m__io->read_bytes(32); + m_master_drum_tuning = m__io->read_bytes(64); + m_double_play_assignments = m__io->read_bytes(32); + m_velocity_switch_on_off_for_each_double_play_assign = m__io->read_bytes(32); + m_velocity_switch_threshold_value_for_each_double_play_assign = m__io->read_bytes(32); + m__unnamed13 = m__io->read_bytes(770); + m_sound_samples = std::unique_ptr>(new std::vector()); + { + int i = 0; + uint64_t _; + do { + _ = m__io->read_bits_int_le(12); + m_sound_samples->push_back(_); + i++; + } while (!(_io()->is_eof())); + } + m__dirty = false; +} + +void mpc60_set_v1_t::_fetch_instances() { + m_total_number_of_sample_words.get()->_fetch_instances(); + for (std::size_t i = 0; i < m_sound_directory_entry->size(); ++i) { + m_sound_directory_entry->at(i).get()->_fetch_instances(); + } + for (std::size_t i = 0; i < m_sound_map->size(); ++i) { + } + for (std::size_t i = 0; i < m_sound_samples->size(); ++i) { + } +} + +void mpc60_set_v1_t::_write() { + m__io->write_bytes(m_file_id); + m__io->write_bytes(m_file_format_version); + if (m_total_number_of_sample_words.get() == nullptr) { + throw std::runtime_error("/seq/2: nested object is not set"); + } + m_total_number_of_sample_words.get()->_set_io(m__io); + m_total_number_of_sample_words.get()->_write(); + if (m_sound_directory_entry == nullptr) { + throw std::runtime_error("/seq/3: repeated field is not set"); + } + for (std::vector>::const_iterator it = m_sound_directory_entry->begin(); it != m_sound_directory_entry->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/3: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_write(); + } + if (m_sound_map == nullptr) { + throw std::runtime_error("/seq/4: repeated field is not set"); + } + for (std::vector::const_iterator it = m_sound_map->begin(); it != m_sound_map->end(); ++it) { + m__io->write_u1((*it)); + } + m__io->write_u1(static_cast(m_use_master_mix_data)); + m__io->write_bytes(m_master_stereo_mix); + m__io->write_bytes(m_master_stereo_pan); + m__io->write_bytes(m_master_echo_mix); + m__io->write_bytes(m_master_drum_tuning); + m__io->write_bytes(m_double_play_assignments); + m__io->write_bytes(m_velocity_switch_on_off_for_each_double_play_assign); + m__io->write_bytes(m_velocity_switch_threshold_value_for_each_double_play_assign); + m__io->write_bytes(m__unnamed13); + if (m_sound_samples == nullptr) { + throw std::runtime_error("/seq/14: repeated field is not set"); + } + for (std::vector::const_iterator it = m_sound_samples->begin(); it != m_sound_samples->end(); ++it) { + m__io->write_bits_int_le(12, (*it)); + } + _fetch_instances(); + m__dirty = false; +} + +void mpc60_set_v1_t::_check() { + if (m_file_id.size() != static_cast(1)) { + throw std::runtime_error("/seq/0: size mismatch"); + } + if (!(m_file_id == std::string("\x02", 1))) { + throw kaitai::validation_not_equal_error(std::string("\x02", 1), m_file_id, m__io, std::string("/seq/0")); + } + if (m_file_format_version.size() != static_cast(1)) { + throw std::runtime_error("/seq/1: size mismatch"); + } + if (!(m_file_format_version == std::string("\x00", 1))) { + throw kaitai::validation_not_equal_error(std::string("\x00", 1), m_file_format_version, m__io, std::string("/seq/1")); + } + if (m_total_number_of_sample_words.get() == nullptr) { + throw std::runtime_error("/seq/2: nested object is not set"); + } + m_total_number_of_sample_words.get()->_set_io(m__io); + m_total_number_of_sample_words.get()->_check(); + if (m_sound_directory_entry == nullptr) { + throw std::runtime_error("/seq/3: repeated field is not set"); + } + if (m_sound_directory_entry->size() != static_cast(34)) { + throw std::runtime_error("/seq/3: repeat-expr size mismatch"); + } + for (std::vector>::const_iterator it = m_sound_directory_entry->begin(); it != m_sound_directory_entry->end(); ++it) { + if ((*it).get() == nullptr) { + throw std::runtime_error("/seq/3: nested object is not set"); + } + (*it).get()->_set_io(m__io); + (*it).get()->_check(); + } + if (m_sound_map == nullptr) { + throw std::runtime_error("/seq/4: repeated field is not set"); + } + if (m_sound_map->size() != static_cast(34)) { + throw std::runtime_error("/seq/4: repeat-expr size mismatch"); + } + for (std::vector::const_iterator it = m_sound_map->begin(); it != m_sound_map->end(); ++it) { + } + if (m_master_stereo_mix.size() != static_cast(32)) { + throw std::runtime_error("/seq/6: size mismatch"); + } + if (m_master_stereo_pan.size() != static_cast(32)) { + throw std::runtime_error("/seq/7: size mismatch"); + } + if (m_master_echo_mix.size() != static_cast(32)) { + throw std::runtime_error("/seq/8: size mismatch"); + } + if (m_master_drum_tuning.size() != static_cast(64)) { + throw std::runtime_error("/seq/9: size mismatch"); + } + if (m_double_play_assignments.size() != static_cast(32)) { + throw std::runtime_error("/seq/10: size mismatch"); + } + if (m_velocity_switch_on_off_for_each_double_play_assign.size() != static_cast(32)) { + throw std::runtime_error("/seq/11: size mismatch"); + } + if (m_velocity_switch_threshold_value_for_each_double_play_assign.size() != static_cast(32)) { + throw std::runtime_error("/seq/12: size mismatch"); + } + if (m__unnamed13.size() != static_cast(770)) { + throw std::runtime_error("/seq/13: size mismatch"); + } + if (m_sound_samples == nullptr) { + throw std::runtime_error("/seq/14: repeated field is not set"); + } + if (m_sound_samples->empty()) { + throw std::runtime_error("/seq/14: repeat-until field must not be empty"); + } + for (std::vector::const_iterator it = m_sound_samples->begin(); it != m_sound_samples->end(); ++it) { + const std::size_t i = static_cast(it - m_sound_samples->begin()); + const uint64_t _ = (*it); + const bool _is_last = (i == m_sound_samples->size() - 1); + if ((_io()->is_eof()) != _is_last) { + throw std::runtime_error("/seq/14: repeat-until condition mismatch"); + } + } + m__dirty = false; +} + +mpc60_set_v1_t::~mpc60_set_v1_t() {} + +mpc60_set_v1_t::sound_directory_entry_t::sound_directory_entry_t(kaitai::kstream* p__io, mpc60_set_v1_t* p__parent, mpc60_set_v1_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc60_set_v1_t::sound_directory_entry_t::_read() { + m_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_terminate(m__io->read_bytes(17), static_cast(0), false), "ASCII"); + m_shared_sound_link = m__io->read_u1(); + if (!(m_shared_sound_link >= 0)) { + throw kaitai::validation_less_than_error(0, m_shared_sound_link, m__io, std::string("/types/sound_directory_entry/seq/1")); + } + if (!(m_shared_sound_link <= 33)) { + throw kaitai::validation_greater_than_error(33, m_shared_sound_link, m__io, std::string("/types/sound_directory_entry/seq/1")); + } + m_start_address_in_memory = m__io->read_u4le(); + m_length_in_samples = m__io->read_u4le(); + m_read_write_pointer = m__io->read_u4le(); + m_start_address_for_playing = m__io->read_u4le(); + m_time_from_start_of_data_to_start_play_msec = m__io->read_u2le(); + m_time_from_start_of_data_to_end_of_play_msec = m__io->read_u2le(); + m_attack_time_msec = m__io->read_u2le(); + m_decay_time_msec = m__io->read_u2le(); + m_pitch_factor = m__io->read_u2le(); + m_attack_rate_sent_to_sound_generator = m__io->read_u2le(); + m_decay_rate_sent_to_sound_generator = m__io->read_u2le(); + m_decay_start_time = m__io->read_u2le(); + m_sound_duration = m__io->read_u2le(); + m_analog_output_jack = static_cast(m__io->read_u1()); + m_requested_stereo_mix_volume = m__io->read_u1(); + m_requested_stereo_mix_pan = m__io->read_u1(); + m_left_level_sent_to_sound_generator = m__io->read_u1(); + m_right_level_sent_to_sound_generator = m__io->read_u1(); + m_echo_level_sent_to_sound_generator = m__io->read_u1(); + m_sound_characteristics = std::unique_ptr(new sound_characteristics_t(m__io, this, m__root)); + m_sound_characteristics->_read(); + m__dirty = false; +} + +void mpc60_set_v1_t::sound_directory_entry_t::_fetch_instances() { + m_sound_characteristics.get()->_fetch_instances(); +} + +void mpc60_set_v1_t::sound_directory_entry_t::_write() { + std::string _bufm_name = m_name; + if (_bufm_name.size() < static_cast(17)) { + _bufm_name += std::string(1, static_cast(0)); + } + if (_bufm_name.size() < static_cast(17)) { + _bufm_name.append(static_cast(17) - _bufm_name.size(), static_cast(0)); + } + m__io->write_bytes(_bufm_name); + m__io->write_u1(m_shared_sound_link); + m__io->write_u4le(m_start_address_in_memory); + m__io->write_u4le(m_length_in_samples); + m__io->write_u4le(m_read_write_pointer); + m__io->write_u4le(m_start_address_for_playing); + m__io->write_u2le(m_time_from_start_of_data_to_start_play_msec); + m__io->write_u2le(m_time_from_start_of_data_to_end_of_play_msec); + m__io->write_u2le(m_attack_time_msec); + m__io->write_u2le(m_decay_time_msec); + m__io->write_u2le(m_pitch_factor); + m__io->write_u2le(m_attack_rate_sent_to_sound_generator); + m__io->write_u2le(m_decay_rate_sent_to_sound_generator); + m__io->write_u2le(m_decay_start_time); + m__io->write_u2le(m_sound_duration); + m__io->write_u1(static_cast(m_analog_output_jack)); + m__io->write_u1(m_requested_stereo_mix_volume); + m__io->write_u1(m_requested_stereo_mix_pan); + m__io->write_u1(m_left_level_sent_to_sound_generator); + m__io->write_u1(m_right_level_sent_to_sound_generator); + m__io->write_u1(m_echo_level_sent_to_sound_generator); + if (m_sound_characteristics.get() == nullptr) { + throw std::runtime_error("/types/sound_directory_entry/seq/21: nested object is not set"); + } + m_sound_characteristics.get()->_set_io(m__io); + m_sound_characteristics.get()->_write(); + _fetch_instances(); + m__dirty = false; +} + +void mpc60_set_v1_t::sound_directory_entry_t::_check() { + if (m_name.size() > static_cast(17)) { + throw std::runtime_error("/types/sound_directory_entry/seq/0: size mismatch"); + } + if (m_name.find(static_cast(0)) != std::string::npos) { + throw std::runtime_error("/types/sound_directory_entry/seq/0: terminator must not appear in value"); + } + if (!(m_shared_sound_link >= 0)) { + throw kaitai::validation_less_than_error(0, m_shared_sound_link, m__io, std::string("/types/sound_directory_entry/seq/1")); + } + if (!(m_shared_sound_link <= 33)) { + throw kaitai::validation_greater_than_error(33, m_shared_sound_link, m__io, std::string("/types/sound_directory_entry/seq/1")); + } + if (m_sound_characteristics.get() == nullptr) { + throw std::runtime_error("/types/sound_directory_entry/seq/21: nested object is not set"); + } + m_sound_characteristics.get()->_set_io(m__io); + m_sound_characteristics.get()->_check(); + m__dirty = false; +} + +mpc60_set_v1_t::sound_directory_entry_t::~sound_directory_entry_t() {} + +mpc60_set_v1_t::sound_directory_entry_t::sound_characteristics_t::sound_characteristics_t(kaitai::kstream* p__io, mpc60_set_v1_t::sound_directory_entry_t* p__parent, mpc60_set_v1_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; +} + +void mpc60_set_v1_t::sound_directory_entry_t::sound_characteristics_t::_read() { + m_normal_or_hihat_sound = static_cast(m__io->read_bits_int_le(1)); + m_save_required = m__io->read_bits_int_le(1); + m__unnamed2 = m__io->read_bits_int_le(5); + m_filter = static_cast(m__io->read_bits_int_le(1)); + m__dirty = false; +} + +void mpc60_set_v1_t::sound_directory_entry_t::sound_characteristics_t::_fetch_instances() { +} + +void mpc60_set_v1_t::sound_directory_entry_t::sound_characteristics_t::_write() { + m__io->write_bits_int_le(1, static_cast(m_normal_or_hihat_sound)); + m__io->write_bits_int_le(1, ((m_save_required) ? 1 : 0)); + m__io->write_bits_int_le(5, m__unnamed2); + m__io->write_bits_int_le(1, static_cast(m_filter)); + _fetch_instances(); + m__dirty = false; +} + +void mpc60_set_v1_t::sound_directory_entry_t::sound_characteristics_t::_check() { + m__dirty = false; +} + +mpc60_set_v1_t::sound_directory_entry_t::sound_characteristics_t::~sound_characteristics_t() {} + +mpc60_set_v1_t::u3le_t::u3le_t(kaitai::kstream* p__io, mpc60_set_v1_t* p__parent, mpc60_set_v1_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m__dirty = false; + f_value = false; +} + +void mpc60_set_v1_t::u3le_t::_read() { + m_b12 = m__io->read_u2le(); + m_b3 = m__io->read_u1(); + m__dirty = false; +} + +void mpc60_set_v1_t::u3le_t::_fetch_instances() { +} + +void mpc60_set_v1_t::u3le_t::_write() { + m__io->write_u2le(m_b12); + m__io->write_u1(m_b3); + _fetch_instances(); + m__dirty = false; +} + +void mpc60_set_v1_t::u3le_t::_check() { + m__dirty = false; +} + +mpc60_set_v1_t::u3le_t::~u3le_t() {} + +int32_t mpc60_set_v1_t::u3le_t::value() { + if (f_value) + return m_value; + f_value = true; + m_value = b12() | b3() << 16; + return m_value; +} diff --git a/src/main/file/kaitai/generated/mpc60_set_v1.h b/src/main/file/kaitai/generated/mpc60_set_v1.h new file mode 100644 index 00000000..9ddf7fc8 --- /dev/null +++ b/src/main/file/kaitai/generated/mpc60_set_v1.h @@ -0,0 +1,349 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +class mpc60_set_v1_t; + +#include "kaitai/kaitaistruct.h" +#include +#include +#include +#include + +#if KAITAI_STRUCT_VERSION < 11000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required" +#endif + +class mpc60_set_v1_t : public kaitai::kstruct { + +public: + class sound_directory_entry_t; + class u3le_t; + + enum analog_output_jack_t { + ANALOG_OUTPUT_JACK_FALSE = 7, + ANALOG_OUTPUT_JACK_JACK_1 = 8, + ANALOG_OUTPUT_JACK_JACK_2 = 9, + ANALOG_OUTPUT_JACK_JACK_3 = 10, + ANALOG_OUTPUT_JACK_JACK_4 = 11, + ANALOG_OUTPUT_JACK_JACK_5 = 12, + ANALOG_OUTPUT_JACK_JACK_6 = 13, + ANALOG_OUTPUT_JACK_JACK_7 = 14, + ANALOG_OUTPUT_JACK_JACK_8 = 15 + }; + static bool _is_defined_analog_output_jack_t(analog_output_jack_t v); + +private: + static const std::set _values_analog_output_jack_t; + +public: + + enum filter_range_t { + FILTER_RANGE_LESS_THAN_OR_EQUALS_47_KHZ = 0, + FILTER_RANGE_GREATER_THAN_47_KHZ = 1 + }; + static bool _is_defined_filter_range_t(filter_range_t v); + +private: + static const std::set _values_filter_range_t; + +public: + + enum normal_or_hihat_t { + NORMAL_OR_HIHAT_NORMAL = 0, + NORMAL_OR_HIHAT_HIHAT = 1 + }; + static bool _is_defined_normal_or_hihat_t(normal_or_hihat_t v); + +private: + static const std::set _values_normal_or_hihat_t; + +public: + + enum physical_drum_t { + PHYSICAL_DRUM_HIHT_CLSD = 0, + PHYSICAL_DRUM_HIHT_MEDM = 1, + PHYSICAL_DRUM_HIHT_OPEN = 2, + PHYSICAL_DRUM_SNR1 = 3, + PHYSICAL_DRUM_SNR2 = 4, + PHYSICAL_DRUM_BASS = 5, + PHYSICAL_DRUM_TOM1 = 6, + PHYSICAL_DRUM_TOM2 = 7, + PHYSICAL_DRUM_TOM3 = 8, + PHYSICAL_DRUM_TOM4 = 9, + PHYSICAL_DRUM_RID1 = 10, + PHYSICAL_DRUM_RID2 = 11, + PHYSICAL_DRUM_CRS1 = 12, + PHYSICAL_DRUM_CRS2 = 13, + PHYSICAL_DRUM_PRC1 = 14, + PHYSICAL_DRUM_PRC2 = 15, + PHYSICAL_DRUM_PRC3 = 16, + PHYSICAL_DRUM_PRC4 = 17, + PHYSICAL_DRUM_DR01 = 18, + PHYSICAL_DRUM_DR02 = 19, + PHYSICAL_DRUM_DR03 = 20, + PHYSICAL_DRUM_DR04 = 21, + PHYSICAL_DRUM_DR05 = 22, + PHYSICAL_DRUM_DR06 = 23, + PHYSICAL_DRUM_DR07 = 24, + PHYSICAL_DRUM_DR08 = 25, + PHYSICAL_DRUM_DR09 = 26, + PHYSICAL_DRUM_DR10 = 27, + PHYSICAL_DRUM_DR11 = 28, + PHYSICAL_DRUM_DR12 = 29, + PHYSICAL_DRUM_DR13 = 30, + PHYSICAL_DRUM_DR14 = 31, + PHYSICAL_DRUM_DR15 = 32, + PHYSICAL_DRUM_DR16 = 33 + }; + static bool _is_defined_physical_drum_t(physical_drum_t v); + +private: + static const std::set _values_physical_drum_t; + +public: + + enum use_master_mix_data_t { + USE_MASTER_MIX_DATA_IGNORE = 0, + USE_MASTER_MIX_DATA_USE = 1 + }; + static bool _is_defined_use_master_mix_data_t(use_master_mix_data_t v); + +private: + static const std::set _values_use_master_mix_data_t; + +public: + +private: + bool m__dirty; + +public: + + mpc60_set_v1_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, mpc60_set_v1_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~mpc60_set_v1_t(); + + class sound_directory_entry_t : public kaitai::kstruct { + + public: + class sound_characteristics_t; + + private: + bool m__dirty; + + public: + + sound_directory_entry_t(kaitai::kstream* p__io, mpc60_set_v1_t* p__parent = nullptr, mpc60_set_v1_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sound_directory_entry_t(); + + class sound_characteristics_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + sound_characteristics_t(kaitai::kstream* p__io, mpc60_set_v1_t::sound_directory_entry_t* p__parent = nullptr, mpc60_set_v1_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~sound_characteristics_t(); + normal_or_hihat_t normal_or_hihat_sound() const { return m_normal_or_hihat_sound; } + void set_normal_or_hihat_sound(normal_or_hihat_t _v) { m__dirty = true; m_normal_or_hihat_sound = std::move(_v); } + bool save_required() const { return m_save_required; } + void set_save_required(bool _v) { m__dirty = true; m_save_required = std::move(_v); } + uint64_t _unnamed2() const { return m__unnamed2; } + void set__unnamed2(uint64_t _v) { m__dirty = true; m__unnamed2 = std::move(_v); } + filter_range_t filter() const { return m_filter; } + void set_filter(filter_range_t _v) { m__dirty = true; m_filter = std::move(_v); } + mpc60_set_v1_t* _root() const { return m__root; } + void set__root(mpc60_set_v1_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(mpc60_set_v1_t::sound_directory_entry_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + normal_or_hihat_t m_normal_or_hihat_sound; + bool m_save_required; + uint64_t m__unnamed2; + filter_range_t m_filter; + mpc60_set_v1_t* m__root; + mpc60_set_v1_t::sound_directory_entry_t* m__parent; + }; + + public: + std::string name() const { return m_name; } + void set_name(std::string _v) { m__dirty = true; m_name = std::move(_v); } + uint8_t shared_sound_link() const { return m_shared_sound_link; } + void set_shared_sound_link(uint8_t _v) { m__dirty = true; m_shared_sound_link = std::move(_v); } + uint32_t start_address_in_memory() const { return m_start_address_in_memory; } + void set_start_address_in_memory(uint32_t _v) { m__dirty = true; m_start_address_in_memory = std::move(_v); } + uint32_t length_in_samples() const { return m_length_in_samples; } + void set_length_in_samples(uint32_t _v) { m__dirty = true; m_length_in_samples = std::move(_v); } + uint32_t read_write_pointer() const { return m_read_write_pointer; } + void set_read_write_pointer(uint32_t _v) { m__dirty = true; m_read_write_pointer = std::move(_v); } + uint32_t start_address_for_playing() const { return m_start_address_for_playing; } + void set_start_address_for_playing(uint32_t _v) { m__dirty = true; m_start_address_for_playing = std::move(_v); } + uint16_t time_from_start_of_data_to_start_play_msec() const { return m_time_from_start_of_data_to_start_play_msec; } + void set_time_from_start_of_data_to_start_play_msec(uint16_t _v) { m__dirty = true; m_time_from_start_of_data_to_start_play_msec = std::move(_v); } + uint16_t time_from_start_of_data_to_end_of_play_msec() const { return m_time_from_start_of_data_to_end_of_play_msec; } + void set_time_from_start_of_data_to_end_of_play_msec(uint16_t _v) { m__dirty = true; m_time_from_start_of_data_to_end_of_play_msec = std::move(_v); } + uint16_t attack_time_msec() const { return m_attack_time_msec; } + void set_attack_time_msec(uint16_t _v) { m__dirty = true; m_attack_time_msec = std::move(_v); } + uint16_t decay_time_msec() const { return m_decay_time_msec; } + void set_decay_time_msec(uint16_t _v) { m__dirty = true; m_decay_time_msec = std::move(_v); } + uint16_t pitch_factor() const { return m_pitch_factor; } + void set_pitch_factor(uint16_t _v) { m__dirty = true; m_pitch_factor = std::move(_v); } + uint16_t attack_rate_sent_to_sound_generator() const { return m_attack_rate_sent_to_sound_generator; } + void set_attack_rate_sent_to_sound_generator(uint16_t _v) { m__dirty = true; m_attack_rate_sent_to_sound_generator = std::move(_v); } + uint16_t decay_rate_sent_to_sound_generator() const { return m_decay_rate_sent_to_sound_generator; } + void set_decay_rate_sent_to_sound_generator(uint16_t _v) { m__dirty = true; m_decay_rate_sent_to_sound_generator = std::move(_v); } + uint16_t decay_start_time() const { return m_decay_start_time; } + void set_decay_start_time(uint16_t _v) { m__dirty = true; m_decay_start_time = std::move(_v); } + uint16_t sound_duration() const { return m_sound_duration; } + void set_sound_duration(uint16_t _v) { m__dirty = true; m_sound_duration = std::move(_v); } + analog_output_jack_t analog_output_jack() const { return m_analog_output_jack; } + void set_analog_output_jack(analog_output_jack_t _v) { m__dirty = true; m_analog_output_jack = std::move(_v); } + uint8_t requested_stereo_mix_volume() const { return m_requested_stereo_mix_volume; } + void set_requested_stereo_mix_volume(uint8_t _v) { m__dirty = true; m_requested_stereo_mix_volume = std::move(_v); } + uint8_t requested_stereo_mix_pan() const { return m_requested_stereo_mix_pan; } + void set_requested_stereo_mix_pan(uint8_t _v) { m__dirty = true; m_requested_stereo_mix_pan = std::move(_v); } + uint8_t left_level_sent_to_sound_generator() const { return m_left_level_sent_to_sound_generator; } + void set_left_level_sent_to_sound_generator(uint8_t _v) { m__dirty = true; m_left_level_sent_to_sound_generator = std::move(_v); } + uint8_t right_level_sent_to_sound_generator() const { return m_right_level_sent_to_sound_generator; } + void set_right_level_sent_to_sound_generator(uint8_t _v) { m__dirty = true; m_right_level_sent_to_sound_generator = std::move(_v); } + uint8_t echo_level_sent_to_sound_generator() const { return m_echo_level_sent_to_sound_generator; } + void set_echo_level_sent_to_sound_generator(uint8_t _v) { m__dirty = true; m_echo_level_sent_to_sound_generator = std::move(_v); } + sound_characteristics_t* sound_characteristics() const { return m_sound_characteristics.get(); } + void set_sound_characteristics(std::unique_ptr _v) { m__dirty = true; m_sound_characteristics = std::move(_v); } + mpc60_set_v1_t* _root() const { return m__root; } + void set__root(mpc60_set_v1_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(mpc60_set_v1_t* _v) { m__dirty = true; m__parent = std::move(_v); } + + private: + std::string m_name; + uint8_t m_shared_sound_link; + uint32_t m_start_address_in_memory; + uint32_t m_length_in_samples; + uint32_t m_read_write_pointer; + uint32_t m_start_address_for_playing; + uint16_t m_time_from_start_of_data_to_start_play_msec; + uint16_t m_time_from_start_of_data_to_end_of_play_msec; + uint16_t m_attack_time_msec; + uint16_t m_decay_time_msec; + uint16_t m_pitch_factor; + uint16_t m_attack_rate_sent_to_sound_generator; + uint16_t m_decay_rate_sent_to_sound_generator; + uint16_t m_decay_start_time; + uint16_t m_sound_duration; + analog_output_jack_t m_analog_output_jack; + uint8_t m_requested_stereo_mix_volume; + uint8_t m_requested_stereo_mix_pan; + uint8_t m_left_level_sent_to_sound_generator; + uint8_t m_right_level_sent_to_sound_generator; + uint8_t m_echo_level_sent_to_sound_generator; + std::unique_ptr m_sound_characteristics; + mpc60_set_v1_t* m__root; + mpc60_set_v1_t* m__parent; + }; + + class u3le_t : public kaitai::kstruct { + + public: + + private: + bool m__dirty; + + public: + + u3le_t(kaitai::kstream* p__io, mpc60_set_v1_t* p__parent = nullptr, mpc60_set_v1_t* p__root = nullptr); + void _read(); + void _fetch_instances(); + void _write(); + void _check(); + ~u3le_t(); + int32_t value(); + void _invalidate_value() { f_value = false; } + uint16_t b12() const { return m_b12; } + void set_b12(uint16_t _v) { m__dirty = true; f_value = false; m_b12 = std::move(_v); } + uint8_t b3() const { return m_b3; } + void set_b3(uint8_t _v) { m__dirty = true; f_value = false; m_b3 = std::move(_v); } + mpc60_set_v1_t* _root() const { return m__root; } + void set__root(mpc60_set_v1_t* _v) { m__dirty = true; f_value = false; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(mpc60_set_v1_t* _v) { m__dirty = true; f_value = false; m__parent = std::move(_v); } + + private: + bool f_value; + int32_t m_value; + uint16_t m_b12; + uint8_t m_b3; + mpc60_set_v1_t* m__root; + mpc60_set_v1_t* m__parent; + }; + +public: + std::string file_id() const { return m_file_id; } + void set_file_id(std::string _v) { m__dirty = true; m_file_id = std::move(_v); } + std::string file_format_version() const { return m_file_format_version; } + void set_file_format_version(std::string _v) { m__dirty = true; m_file_format_version = std::move(_v); } + u3le_t* total_number_of_sample_words() const { return m_total_number_of_sample_words.get(); } + void set_total_number_of_sample_words(std::unique_ptr _v) { m__dirty = true; m_total_number_of_sample_words = std::move(_v); } + std::vector>* sound_directory_entry() const { return m_sound_directory_entry.get(); } + void set_sound_directory_entry(std::unique_ptr>> _v) { m__dirty = true; m_sound_directory_entry = std::move(_v); } + std::vector* sound_map() const { return m_sound_map.get(); } + void set_sound_map(std::unique_ptr> _v) { m__dirty = true; m_sound_map = std::move(_v); } + use_master_mix_data_t use_master_mix_data() const { return m_use_master_mix_data; } + void set_use_master_mix_data(use_master_mix_data_t _v) { m__dirty = true; m_use_master_mix_data = std::move(_v); } + std::string master_stereo_mix() const { return m_master_stereo_mix; } + void set_master_stereo_mix(std::string _v) { m__dirty = true; m_master_stereo_mix = std::move(_v); } + std::string master_stereo_pan() const { return m_master_stereo_pan; } + void set_master_stereo_pan(std::string _v) { m__dirty = true; m_master_stereo_pan = std::move(_v); } + std::string master_echo_mix() const { return m_master_echo_mix; } + void set_master_echo_mix(std::string _v) { m__dirty = true; m_master_echo_mix = std::move(_v); } + std::string master_drum_tuning() const { return m_master_drum_tuning; } + void set_master_drum_tuning(std::string _v) { m__dirty = true; m_master_drum_tuning = std::move(_v); } + std::string double_play_assignments() const { return m_double_play_assignments; } + void set_double_play_assignments(std::string _v) { m__dirty = true; m_double_play_assignments = std::move(_v); } + std::string velocity_switch_on_off_for_each_double_play_assign() const { return m_velocity_switch_on_off_for_each_double_play_assign; } + void set_velocity_switch_on_off_for_each_double_play_assign(std::string _v) { m__dirty = true; m_velocity_switch_on_off_for_each_double_play_assign = std::move(_v); } + std::string velocity_switch_threshold_value_for_each_double_play_assign() const { return m_velocity_switch_threshold_value_for_each_double_play_assign; } + void set_velocity_switch_threshold_value_for_each_double_play_assign(std::string _v) { m__dirty = true; m_velocity_switch_threshold_value_for_each_double_play_assign = std::move(_v); } + std::string _unnamed13() const { return m__unnamed13; } + void set__unnamed13(std::string _v) { m__dirty = true; m__unnamed13 = std::move(_v); } + std::vector* sound_samples() const { return m_sound_samples.get(); } + void set_sound_samples(std::unique_ptr> _v) { m__dirty = true; m_sound_samples = std::move(_v); } + mpc60_set_v1_t* _root() const { return m__root; } + void set__root(mpc60_set_v1_t* _v) { m__dirty = true; m__root = std::move(_v); } + kaitai::kstruct* _parent() const { return m__parent; } + void set__parent(kaitai::kstruct* _v) { m__dirty = true; m__parent = std::move(_v); } + +private: + std::string m_file_id; + std::string m_file_format_version; + std::unique_ptr m_total_number_of_sample_words; + std::unique_ptr>> m_sound_directory_entry; + std::unique_ptr> m_sound_map; + use_master_mix_data_t m_use_master_mix_data; + std::string m_master_stereo_mix; + std::string m_master_stereo_pan; + std::string m_master_echo_mix; + std::string m_master_drum_tuning; + std::string m_double_play_assignments; + std::string m_velocity_switch_on_off_for_each_double_play_assign; + std::string m_velocity_switch_threshold_value_for_each_double_play_assign; + std::string m__unnamed13; + std::unique_ptr> m_sound_samples; + mpc60_set_v1_t* m__root; + kaitai::kstruct* m__parent; +}; diff --git a/src/main/lcdgui/AllScreens.hpp b/src/main/lcdgui/AllScreens.hpp index cc592e30..6bdc46c3 100644 --- a/src/main/lcdgui/AllScreens.hpp +++ b/src/main/lcdgui/AllScreens.hpp @@ -88,6 +88,10 @@ #include "lcdgui/screens/window/VeloPitchScreen.hpp" #include "lcdgui/screens/window/DirectoryScreen.hpp" #include "lcdgui/screens/window/LoadAProgramScreen.hpp" +#include "lcdgui/screens/window/LoadASetScreen.hpp" +#include "lcdgui/screens/window/ConversionTableScreen.hpp" +#include "lcdgui/screens/window/LoadASetReplaceAddScreen.hpp" +#include "lcdgui/screens/window/LoadASetSoundScreen.hpp" #include "lcdgui/screens/window/LoadASequenceScreen.hpp" #include "lcdgui/screens/window/LoadASequenceFromAllScreen.hpp" #include "lcdgui/screens/window/LoadASoundScreen.hpp" diff --git a/src/main/lcdgui/ScreenRegistry.hpp b/src/main/lcdgui/ScreenRegistry.hpp index 63cd79f9..ec0e106c 100644 --- a/src/main/lcdgui/ScreenRegistry.hpp +++ b/src/main/lcdgui/ScreenRegistry.hpp @@ -98,6 +98,10 @@ X(screens, SaveScreen, "save") \ X(screens::window, DirectoryScreen, "directory") \ X(screens::window, LoadAProgramScreen, "load-a-program") \ + X(screens::window, LoadASetScreen, "load-a-set") \ + X(screens::window, ConversionTableScreen, "conversion-table") \ + X(screens::window, LoadASetReplaceAddScreen, "load-a-set-replace-add") \ + X(screens::window, LoadASetSoundScreen, "load-a-set-sound") \ X(screens::window, LoadASequenceScreen, "load-a-sequence") \ X(screens::window, LoadASequenceFromAllScreen, "load-a-sequence-from-all") \ X(screens::window, LoadASoundScreen, "load-a-sound") \ diff --git a/src/main/lcdgui/screens/LoadScreen.cpp b/src/main/lcdgui/screens/LoadScreen.cpp index 2b2bc06a..1d12065c 100644 --- a/src/main/lcdgui/screens/LoadScreen.cpp +++ b/src/main/lcdgui/screens/LoadScreen.cpp @@ -228,6 +228,10 @@ void LoadScreen::function(const int i) { openScreenById(ScreenId::LoadAProgramScreen); } + else if (StrUtil::eqIgnoreCase(ext, ".set")) + { + openScreenById(ScreenId::LoadASetScreen); + } else if (StrUtil::eqIgnoreCase(ext, ".mid")) { openScreenById(ScreenId::LoadASequenceScreen); diff --git a/src/main/lcdgui/screens/VmpcSettingsScreen.cpp b/src/main/lcdgui/screens/VmpcSettingsScreen.cpp index 7c50b961..ebafb9c9 100644 --- a/src/main/lcdgui/screens/VmpcSettingsScreen.cpp +++ b/src/main/lcdgui/screens/VmpcSettingsScreen.cpp @@ -2,6 +2,8 @@ #include "Mpc.hpp" #include "lcdgui/LayeredScreen.hpp" #include "lcdgui/screens/window/TimingCorrectScreen.hpp" +#include "sampler/Pad.hpp" +#include "sampler/Sampler.hpp" using namespace mpc::lcdgui::screens; @@ -99,6 +101,8 @@ void VmpcSettingsScreen::setInitialPadMapping(const int i) } initialPadMapping = i; + // Future PROGRAM/MASTER init-pad-assign operations copy from this cache. + *mpc.getSampler()->getInitMasterPadAssign() = sampler::Pad::getPadNotes(mpc); displayInitialPadMapping(); } diff --git a/src/main/lcdgui/screens/window/ConversionTableScreen.cpp b/src/main/lcdgui/screens/window/ConversionTableScreen.cpp new file mode 100644 index 00000000..11bde2ff --- /dev/null +++ b/src/main/lcdgui/screens/window/ConversionTableScreen.cpp @@ -0,0 +1,90 @@ +#include "ConversionTableScreen.hpp" + +#include "Mpc.hpp" +#include "file/kaitai/Mpc60SetPreview.hpp" +#include "StrUtil.hpp" +#include "lcdgui/screens/window/LoadASetScreen.hpp" +#include "sampler/Pad.hpp" +#include "sampler/Sampler.hpp" + +#include + +using namespace mpc::lcdgui::screens::window; +using namespace mpc::lcdgui::screens; + +ConversionTableScreen::ConversionTableScreen(Mpc &mpc, const int layerIndex) + : ScreenComponent(mpc, "conversion-table", layerIndex) +{ +} + +void ConversionTableScreen::open() +{ + displayPad(); + displayBecomesNote(); +} + +void ConversionTableScreen::turnWheel(const int i) +{ + const auto loadASetScreen = mpc.screens->get(); + + if (const auto focusedFieldName = getFocusedFieldNameOrThrow(); + focusedFieldName == "mpc60-pad") + { + selectedMpc60PadIndex = static_cast(std::clamp( + static_cast(selectedMpc60PadIndex) + i, 0, + 33)); + displayPad(); + displayBecomesNote(); + } + else if (focusedFieldName == "becomes-note") + { + const auto note = loadASetScreen->getConversionTargetNote(selectedMpc60PadIndex); + loadASetScreen->setConversionTargetNote( + selectedMpc60PadIndex, + DrumNoteNumber(std::clamp(static_cast(note) + i, + static_cast(MinDrumNoteNumber), + static_cast(MaxDrumNoteNumber)))); + displayBecomesNote(); + } +} + +void ConversionTableScreen::displayPad() const +{ + auto padLabel = + file::kaitai::Mpc60SetPreview::mpc60PadName(selectedMpc60PadIndex); + std::replace(padLabel.begin(), padLabel.end(), '_', ' '); + padLabel = StrUtil::padRight(StrUtil::toUpper(padLabel), " ", 10) + "(" + + file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel( + selectedMpc60PadIndex) + + ")"; + findField("mpc60-pad")->setText(StrUtil::padRight(padLabel, " ", 18)); +} + +void ConversionTableScreen::displayBecomesNote() const +{ + const auto loadASetScreen = mpc.screens->get(); + const auto note = loadASetScreen->getConversionTargetNote(selectedMpc60PadIndex); + const auto program = getProgram(); + const auto padIndices = + program ? program->getPadIndicesFromNote(note) + : std::vector{}; + const auto padName = padIndices.empty() + ? std::string("OFF") + : sampler.lock()->getPadName( + static_cast(padIndices.front())); + findField("becomes-note")->setText(std::to_string(note) + "/" + padName); +} + +void ConversionTableScreen::function(const int i) +{ + switch (i) + { + case 3: + openScreenById(ScreenId::LoadScreen); + break; + case 4: + openScreenById(ScreenId::LoadASetReplaceAddScreen); + break; + default:; + } +} diff --git a/src/main/lcdgui/screens/window/ConversionTableScreen.hpp b/src/main/lcdgui/screens/window/ConversionTableScreen.hpp new file mode 100644 index 00000000..f3cbf65c --- /dev/null +++ b/src/main/lcdgui/screens/window/ConversionTableScreen.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "lcdgui/ScreenComponent.hpp" + +#include + +namespace mpc::lcdgui::screens::window +{ + class ConversionTableScreen final : public ScreenComponent + { + public: + ConversionTableScreen(Mpc &mpc, int layerIndex); + + void open() override; + void turnWheel(int i) override; + void function(int i) override; + + private: + size_t selectedMpc60PadIndex = 0; + + void displayPad() const; + void displayBecomesNote() const; + }; +} // namespace mpc::lcdgui::screens::window diff --git a/src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.cpp b/src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.cpp new file mode 100644 index 00000000..3accbd6c --- /dev/null +++ b/src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.cpp @@ -0,0 +1,125 @@ +#include "LoadASetReplaceAddScreen.hpp" + +#include "Mpc.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/Mpc60SetProgramLoader.hpp" +#include "file/kaitai/Mpc60SetPreview.hpp" +#include "lcdgui/LayeredScreen.hpp" +#include "lcdgui/screens/LoadScreen.hpp" +#include "lcdgui/screens/window/LoadASetScreen.hpp" +#include "performance/PerformanceManager.hpp" +#include "utils/SimpleAction.hpp" + +#include + +using namespace mpc::lcdgui::screens::window; +using namespace mpc::lcdgui::screens; + +LoadASetReplaceAddScreen::LoadASetReplaceAddScreen(Mpc &mpc, + const int layerIndex) + : ScreenComponent(mpc, "load-a-set-replace-add", layerIndex) +{ +} + +LoadASetReplaceAddScreen::~LoadASetReplaceAddScreen() +{ + if (loadThread.joinable()) + { + loadThread.join(); + } +} + +void LoadASetReplaceAddScreen::open() +{ + displayLoadReplaceSound(); +} + +void LoadASetReplaceAddScreen::turnWheel(const int i) +{ + if (const auto focusedFieldName = getFocusedFieldNameOrThrow(); + focusedFieldName == "load-replace-sound") + { + loadReplaceSameSound = i > 0; + displayLoadReplaceSound(); + } +} + +void LoadASetReplaceAddScreen::function(const int i) +{ + switch (i) + { + case 2: + case 4: + { + const auto loadASetScreen = mpc.screens->get(); + const auto preview = loadASetScreen->getPreview(); + const auto file = mpc.screens->get()->getSelectedFile(); + + if (preview == nullptr || file == nullptr) + { + ls.lock()->showPopupAndThenOpen(ScreenId::LoadScreen, + "Can't read SET", 1000); + break; + } + + const bool clearExisting = i == 2; + auto previewCopy = std::make_shared(*preview); + auto conversionTableCopy = + std::make_shared( + loadASetScreen->getConversionTable()); + const auto layeredScreen = mpc.getLayeredScreen(); + + layeredScreen->showPopup("Loading " + file->getName()); + + if (loadThread.joinable()) + { + loadThread.join(); + } + + loadThread = std::thread( + [this, file, previewCopy, conversionTableCopy, clearExisting, + layeredScreen] + { + const auto loaded = + file::kaitai::Mpc60SetProgramLoader::load( + mpc, file, *previewCopy, *conversionTableCopy, + clearExisting); + + if (!loaded) + { + layeredScreen->postToUiThread(mpc::utils::Task( + [layeredScreen] + { + layeredScreen->showPopupAndThenOpen( + ScreenId::LoadScreen, "Can't read SET", + 1000); + })); + return; + } + + mpc.getPerformanceManager().lock()->enqueueCallback( + mpc::utils::SimpleAction( + [layeredScreen] + { + layeredScreen->postToUiThread(mpc::utils::Task( + [layeredScreen] + { + layeredScreen->openScreenById( + ScreenId::LoadScreen); + })); + })); + }); + break; + } + case 3: + openScreenById(ScreenId::LoadScreen); + break; + default:; + } +} + +void LoadASetReplaceAddScreen::displayLoadReplaceSound() const +{ + findField("load-replace-sound") + ->setText(std::string(loadReplaceSameSound ? "YES" : "NO(FASTER)")); +} diff --git a/src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.hpp b/src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.hpp new file mode 100644 index 00000000..2c01cbc1 --- /dev/null +++ b/src/main/lcdgui/screens/window/LoadASetReplaceAddScreen.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "lcdgui/ScreenComponent.hpp" + +#include + +namespace mpc::lcdgui::screens::window +{ + class LoadASetReplaceAddScreen final : public ScreenComponent + { + public: + LoadASetReplaceAddScreen(Mpc &mpc, int layerIndex); + ~LoadASetReplaceAddScreen() override; + + void open() override; + void turnWheel(int i) override; + void function(int i) override; + + private: + std::thread loadThread; + bool loadReplaceSameSound = false; + + void displayLoadReplaceSound() const; + }; +} // namespace mpc::lcdgui::screens::window diff --git a/src/main/lcdgui/screens/window/LoadASetScreen.cpp b/src/main/lcdgui/screens/window/LoadASetScreen.cpp new file mode 100644 index 00000000..c62e1253 --- /dev/null +++ b/src/main/lcdgui/screens/window/LoadASetScreen.cpp @@ -0,0 +1,81 @@ +#include "LoadASetScreen.hpp" + +#include "Mpc.hpp" +#include "file/kaitai/Mpc60SetPreview.hpp" +#include "lcdgui/LayeredScreen.hpp" +#include "lcdgui/screens/LoadScreen.hpp" + +#include + +using namespace mpc::lcdgui::screens::window; +using namespace mpc::lcdgui::screens; + +LoadASetScreen::LoadASetScreen(Mpc &mpc, const int layerIndex) + : ScreenComponent(mpc, "load-a-set", layerIndex) +{ +} + +LoadASetScreen::~LoadASetScreen() = default; + +void LoadASetScreen::open() +{ + preview.reset(); + conversionTable = file::kaitai::Mpc60SetProgramLoader::defaultConversionTable(); + + try + { + preview = std::make_unique( + file::kaitai::Mpc60SetPreviewLoader::loadPreview( + mpc.screens->get()->getSelectedFile())); + } + catch (const std::exception &) + { + const auto layeredScreen = ls.lock(); + layeredScreen->postToUiThread(utils::Task( + [layeredScreen] + { + layeredScreen->showPopupAndThenOpen(ScreenId::LoadScreen, + "Can't read SET", 1000); + })); + } +} + +void LoadASetScreen::function(const int i) +{ + switch (i) + { + case 2: + openScreenById(ScreenId::LoadASetSoundScreen); + break; + case 3: + openScreenById(ScreenId::LoadScreen); + break; + case 4: + openScreenById(ScreenId::ConversionTableScreen); + break; + default:; + } +} + +const mpc::file::kaitai::Mpc60SetPreview *LoadASetScreen::getPreview() const +{ + return preview.get(); +} + +const mpc::file::kaitai::Mpc60SetProgramLoader::ConversionTable & +LoadASetScreen::getConversionTable() const +{ + return conversionTable; +} + +mpc::DrumNoteNumber LoadASetScreen::getConversionTargetNote( + const size_t mpc60PadIndex) const +{ + return conversionTable.at(mpc60PadIndex); +} + +void LoadASetScreen::setConversionTargetNote(const size_t mpc60PadIndex, + const DrumNoteNumber note) +{ + conversionTable.at(mpc60PadIndex) = note; +} diff --git a/src/main/lcdgui/screens/window/LoadASetScreen.hpp b/src/main/lcdgui/screens/window/LoadASetScreen.hpp new file mode 100644 index 00000000..527d823c --- /dev/null +++ b/src/main/lcdgui/screens/window/LoadASetScreen.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "file/kaitai/Mpc60SetProgramLoader.hpp" +#include "lcdgui/ScreenComponent.hpp" + +namespace mpc::file::kaitai +{ + struct Mpc60SetPreview; +} + +namespace mpc::lcdgui::screens::window +{ + class LoadASetScreen final : public ScreenComponent + { + public: + LoadASetScreen(Mpc &mpc, int layerIndex); + ~LoadASetScreen() override; + + void open() override; + void function(int i) override; + + const file::kaitai::Mpc60SetPreview *getPreview() const; + const file::kaitai::Mpc60SetProgramLoader::ConversionTable & + getConversionTable() const; + DrumNoteNumber getConversionTargetNote(size_t mpc60PadIndex) const; + void setConversionTargetNote(size_t mpc60PadIndex, DrumNoteNumber note); + + private: + std::unique_ptr preview; + file::kaitai::Mpc60SetProgramLoader::ConversionTable conversionTable = + file::kaitai::Mpc60SetProgramLoader::defaultConversionTable(); + }; +} // namespace mpc::lcdgui::screens::window diff --git a/src/main/lcdgui/screens/window/LoadASetSoundScreen.cpp b/src/main/lcdgui/screens/window/LoadASetSoundScreen.cpp new file mode 100644 index 00000000..cc9418c5 --- /dev/null +++ b/src/main/lcdgui/screens/window/LoadASetSoundScreen.cpp @@ -0,0 +1,189 @@ +#include "LoadASetSoundScreen.hpp" + +#include "Mpc.hpp" +#include "disk/MpcFile.hpp" +#include "file/kaitai/Mpc60SetPreview.hpp" +#include "file/kaitai/Mpc60SetSoundLoader.hpp" +#include "lcdgui/LayeredScreen.hpp" +#include "lcdgui/screens/LoadScreen.hpp" +#include "lcdgui/screens/window/LoadASetScreen.hpp" +#include "sampler/Pad.hpp" +#include "sampler/Sampler.hpp" +#include "StrUtil.hpp" +#include "lcdgui/Label.hpp" + +#include +#include + +using namespace mpc::lcdgui::screens::window; +using namespace mpc::lcdgui::screens; + +LoadASetSoundScreen::LoadASetSoundScreen(Mpc &mpc, const int layerIndex) + : ScreenComponent(mpc, "load-a-set-sound", layerIndex) +{ +} + +void LoadASetSoundScreen::open() +{ + assignedMpc60PadIndexes.clear(); + selectedAssignedPadIndex = 0; + + const auto loadScreen = mpc.screens->get(); + const auto file = loadScreen->getSelectedFile(); + if (file == nullptr) + { + ls.lock()->showPopupAndAwaitInteraction("No SET selected"); + return; + } + + const auto setScreen = mpc.screens->get(); + const auto *preview = setScreen->getPreview(); + + if (preview == nullptr) + { + ls.lock()->showPopupAndAwaitInteraction("Can't read SET"); + return; + } + + assignedMpc60PadIndexes.reserve( + preview->soundDirectoryEntryIndexByMpc60Pad.size()); + for (size_t padIndex = 0; + padIndex < preview->soundDirectoryEntryIndexByMpc60Pad.size(); + ++padIndex) + { + assignedMpc60PadIndexes.push_back(padIndex); + } + + displayMpc60Pad(); + displayFile(); +} + +void LoadASetSoundScreen::turnWheel(const int i) +{ + if (assignedMpc60PadIndexes.empty()) + { + return; + } + + const auto current = static_cast(selectedAssignedPadIndex); + selectedAssignedPadIndex = static_cast(std::clamp( + current + i, 0, + static_cast(assignedMpc60PadIndexes.size() - 1))); + displayMpc60Pad(); + displayFile(); +} + +void LoadASetSoundScreen::displayMpc60Pad() const +{ + if (assignedMpc60PadIndexes.empty()) + { + findField("mpc60-pad")->setText(""); + return; + } + + const auto padIndex = assignedMpc60PadIndexes[selectedAssignedPadIndex]; + auto padName = file::kaitai::Mpc60SetPreview::mpc60PadName(padIndex); + std::replace(padName.begin(), padName.end(), '_', ' '); + padName = StrUtil::toUpper(padName); + const auto sourceSlot = + file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(padIndex); + findField("mpc60-pad")->setText( + StrUtil::padRight(padName, " ", 10) + "(" + sourceSlot + ")"); +} + +void LoadASetSoundScreen::displayFile() const +{ + const auto setScreen = mpc.screens->get(); + const auto *preview = setScreen->getPreview(); + const auto entryIndex = getSelectedSoundDirectoryEntryIndex(); + + if (preview == nullptr || !entryIndex) + { + findLabel("file")->setText("File:(no assign)"); + return; + } + + if (*entryIndex >= preview->soundDirectoryEntries.size() || + preview->soundDirectoryEntries[*entryIndex].lengthInSamples == 0) + { + findLabel("file")->setText("File:(no assign)"); + return; + } + + findLabel("file")->setText( + "File:" + + StrUtil::padRight(preview->soundDirectoryEntries[*entryIndex].name, " ", + 16)); +} + +std::optional +LoadASetSoundScreen::getSelectedSoundDirectoryEntryIndex() const +{ + const auto setScreen = mpc.screens->get(); + const auto *preview = setScreen->getPreview(); + + if (preview == nullptr || assignedMpc60PadIndexes.empty()) + { + return std::nullopt; + } + + const auto padIndex = assignedMpc60PadIndexes[selectedAssignedPadIndex]; + const auto entryIndex = + preview->soundDirectoryEntryIndexByMpc60Pad[padIndex]; + + if (entryIndex >= preview->soundDirectoryEntries.size()) + { + return std::nullopt; + } + + return entryIndex; +} + +void LoadASetSoundScreen::function(const int i) +{ + switch (i) + { + case 3: + ls.lock()->closeCurrentScreen(); + break; + case 4: + { + const auto loadScreen = mpc.screens->get(); + const auto file = loadScreen->getSelectedFile(); + + if (file == nullptr) + { + ls.lock()->showPopupAndAwaitInteraction("No SET selected"); + break; + } + + const auto entryIndex = getSelectedSoundDirectoryEntryIndex(); + if (!entryIndex) + { + break; + } + + auto sound = sampler.lock()->addSound(40000); + if (sound == nullptr) + { + break; + } + + const auto soundOrError = + file::kaitai::Mpc60SetSoundLoader::loadSoundDirectoryEntry( + file, *entryIndex, sound); + + if (!soundOrError.has_value()) + { + sampler.lock()->deleteSound(sound); + ls.lock()->showPopupAndAwaitInteraction("Can't read SET"); + break; + } + + const auto msg = "LOADING " + sound->getName(); + ls.lock()->showPopupAndThenOpen(ScreenId::LoadASoundScreen, msg, 300); + break; + } + default:; + } +} diff --git a/src/main/lcdgui/screens/window/LoadASetSoundScreen.hpp b/src/main/lcdgui/screens/window/LoadASetSoundScreen.hpp new file mode 100644 index 00000000..e3ecc8fa --- /dev/null +++ b/src/main/lcdgui/screens/window/LoadASetSoundScreen.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "lcdgui/ScreenComponent.hpp" + +#include +#include + +namespace mpc::lcdgui::screens::window +{ + class LoadASetSoundScreen final : public ScreenComponent + { + public: + LoadASetSoundScreen(Mpc &mpc, int layerIndex); + + void open() override; + void turnWheel(int i) override; + void function(int i) override; + + private: + std::vector assignedMpc60PadIndexes; + size_t selectedAssignedPadIndex = 0; + + void displayMpc60Pad() const; + void displayFile() const; + std::optional getSelectedSoundDirectoryEntryIndex() const; + }; +} // namespace mpc::lcdgui::screens::window diff --git a/src/main/sampler/Program.cpp b/src/main/sampler/Program.cpp index 11fe7da1..bcf21f22 100644 --- a/src/main/sampler/Program.cpp +++ b/src/main/sampler/Program.cpp @@ -156,7 +156,7 @@ Program::getPadIndexFromNote(const DrumNoteNumber note) const for (int8_t i = 0; i < Mpc2000XlSpecs::PROGRAM_PAD_COUNT; i++) { - if (pads[i]->getNote() == note) + if (getSnapshot(index).getPad(ProgramPadIndex(i)).note == note) { return ProgramPadIndex{i}; } @@ -208,7 +208,7 @@ void Program::initPadAssign() const mpc::DrumNoteNumber Program::getNoteFromPad(const ProgramPadIndex i) const { - return pads[i]->getNote(); + return getSnapshot(index).getPad(i).note; } std::vector @@ -218,7 +218,7 @@ Program::getPadIndicesFromNote(const DrumNoteNumber note) const for (int i = 0; i < pads.size(); i++) { - if (pads[i]->getNote() == note) + if (getSnapshot(index).getPad(ProgramPadIndex(i)).note == note) { result.push_back(ProgramPadIndex(i)); } diff --git a/src/test/Mpc60SetPreviewTest.cpp b/src/test/Mpc60SetPreviewTest.cpp new file mode 100644 index 00000000..64f46f23 --- /dev/null +++ b/src/test/Mpc60SetPreviewTest.cpp @@ -0,0 +1,96 @@ +#include + +#include "file/kaitai/Mpc60SetPreview.hpp" + +#include + +#include +#include + +CMRC_DECLARE(mpctest); + +namespace +{ + std::vector readResource(const std::string &path) + { + const auto fs = cmrc::mpctest::get_filesystem(); + const auto file = fs.open(path); + return std::vector(file.begin(), file.end()); + } +} + +TEST_CASE("MPC60 SET preview maps MPC60 pads to directory entries", + "[kaitai-set][real-mpc60]") +{ + using mpc::file::kaitai::Mpc60SetPreviewLoader; + + const auto rockPreview = Mpc60SetPreviewLoader::loadPreview( + readResource("test/RealMpc60/Set/ROCK.SET")); + const auto studioPreview = Mpc60SetPreviewLoader::loadPreview( + readResource("test/RealMpc60/Set/STUDIO.SET")); + const auto uk8Preview = Mpc60SetPreviewLoader::loadPreview( + readResource("test/RealMpc60/Set/UK-8.SET")); + + REQUIRE(rockPreview.totalNumberOfSampleWords == 510936U); + REQUIRE(studioPreview.totalNumberOfSampleWords == 519560U); + REQUIRE(uk8Preview.totalNumberOfSampleWords == 517520U); + + REQUIRE(rockPreview.useMasterMixData); + REQUIRE(studioPreview.useMasterMixData); + REQUIRE(uk8Preview.useMasterMixData); + + REQUIRE(rockPreview.soundDirectoryEntries.size() == 34U); + REQUIRE(studioPreview.soundDirectoryEntries.size() == 34U); + REQUIRE(uk8Preview.soundDirectoryEntries.size() == 34U); + REQUIRE(rockPreview.soundDirectoryEntryIndexByMpc60Pad.size() == 34U); + REQUIRE(studioPreview.soundDirectoryEntryIndexByMpc60Pad.size() == 34U); + REQUIRE(uk8Preview.soundDirectoryEntryIndexByMpc60Pad.size() == 34U); + + REQUIRE(rockPreview.soundDirectoryEntryIndexByMpc60Pad[0] == 19); + REQUIRE(rockPreview.soundDirectoryEntryIndexByMpc60Pad[1] == 20); + REQUIRE(rockPreview.soundDirectoryEntryIndexByMpc60Pad[2] == 21); + REQUIRE(rockPreview.soundDirectoryEntryIndexByMpc60Pad[10] == 16); + + REQUIRE(studioPreview.soundDirectoryEntryIndexByMpc60Pad[0] == 19); + REQUIRE(studioPreview.soundDirectoryEntryIndexByMpc60Pad[1] == 20); + REQUIRE(studioPreview.soundDirectoryEntryIndexByMpc60Pad[2] == 21); + REQUIRE(studioPreview.soundDirectoryEntryIndexByMpc60Pad[10] == 23); + + REQUIRE(uk8Preview.soundDirectoryEntryIndexByMpc60Pad[0] == 0); + REQUIRE(uk8Preview.soundDirectoryEntryIndexByMpc60Pad[18] == 255); + REQUIRE(uk8Preview.soundDirectoryEntryIndexByMpc60Pad[25] == 255); + REQUIRE(uk8Preview.soundDirectoryEntryIndexByMpc60Pad[33] == 20); + + REQUIRE(rockPreview.assignedSoundAtMpc60Pad(0)->name == "HAT2CLSD"); + REQUIRE(rockPreview.assignedSoundAtMpc60Pad(1)->name == "HAT2MED"); + REQUIRE(rockPreview.assignedSoundAtMpc60Pad(2)->name == "HAT2OPN"); + REQUIRE(rockPreview.assignedSoundAtMpc60Pad(10)->name == "RIDE4B"); + + REQUIRE(studioPreview.assignedSoundAtMpc60Pad(0)->name == "HAT1CLSD"); + REQUIRE(studioPreview.assignedSoundAtMpc60Pad(1)->name == "HAT1MED"); + REQUIRE(studioPreview.assignedSoundAtMpc60Pad(2)->name == "HAT1OPN"); + REQUIRE(studioPreview.assignedSoundAtMpc60Pad(10)->name == "RIDE_#1"); + + REQUIRE(uk8Preview.assignedSoundAtMpc60Pad(0)->name == "S7_HH_CL"); + REQUIRE(uk8Preview.assignedSoundAtMpc60Pad(10)->name == "S7_RIDE1"); + REQUIRE(uk8Preview.assignedSoundAtMpc60Pad(18) == nullptr); + REQUIRE(uk8Preview.assignedSoundAtMpc60Pad(25) == nullptr); + REQUIRE(uk8Preview.assignedSoundAtMpc60Pad(33)->name == "SCRATCH4"); + + REQUIRE(rockPreview.assignedSoundAtMpc60Pad(0)->isHihat); + REQUIRE(rockPreview.assignedSoundAtMpc60Pad(1)->isHihat); + REQUIRE(rockPreview.assignedSoundAtMpc60Pad(2)->isHihat); + REQUIRE_FALSE(rockPreview.assignedSoundAtMpc60Pad(16)->isHihat); + + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60PadName(0) == "hiht_clsd"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60PadName(10) == "rid1"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60PadName(33) == "dr16"); + + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(0) == "A01"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(1) == "A01"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(2) == "A01"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(3) == "A02"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(17) == "A16"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(18) == "B01"); + REQUIRE(mpc::file::kaitai::Mpc60SetPreview::mpc60SourceSlotLabel(33) == "B16"); +} diff --git a/src/test/Mpc60SetSoundLoaderTest.cpp b/src/test/Mpc60SetSoundLoaderTest.cpp new file mode 100644 index 00000000..341f666a --- /dev/null +++ b/src/test/Mpc60SetSoundLoaderTest.cpp @@ -0,0 +1,126 @@ +#include + +#include "SampleOps.hpp" +#include "file/kaitai/Mpc60SetSoundLoader.hpp" +#include "sampler/Sound.hpp" + +#include + +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +namespace +{ + std::vector readResource(const std::string &path) + { + const auto fs = cmrc::mpctest::get_filesystem(); + const auto file = fs.open(path); + return std::vector(file.begin(), file.end()); + } + + uint32_t readU4le(const std::vector &bytes, const size_t offset) + { + return static_cast( + static_cast(bytes[offset]) | + (static_cast(bytes[offset + 1]) << 8U) | + (static_cast(bytes[offset + 2]) << 16U) | + (static_cast(bytes[offset + 3]) << 24U)); + } + + std::vector readMpc2000xlSndPcm(const std::string &path) + { + const auto bytes = readResource(path); + REQUIRE(bytes.size() >= 42); + REQUIRE(static_cast(bytes[0]) == 0x01); + REQUIRE(static_cast(bytes[1]) == 0x04); + + const auto stereo = (static_cast(bytes[21]) & 1U) != 0; + REQUIRE_FALSE(stereo); + + const auto frameCount = readU4le(bytes, 30); + REQUIRE(bytes.size() == 42U + frameCount * 2U); + + std::vector result; + result.reserve(frameCount); + + for (size_t offset = 42; offset < bytes.size(); offset += 2) + { + const auto value = static_cast( + static_cast(bytes[offset]) | + (static_cast(bytes[offset + 1]) << 8U)); + result.push_back(static_cast(value)); + } + + return result; + } + + void requireMatchesMpc2000xlSnd(const mpc::sampler::Sound &sound, + const std::string &referencePath) + { + const auto expected = readMpc2000xlSndPcm(referencePath); + const auto sampleData = sound.getSampleData(); + + REQUIRE(sampleData->size() == expected.size()); + + for (size_t i = 0; i < expected.size(); ++i) + { + REQUIRE(mpc::sampleops::mean_normalized_float_to_short( + sampleData->at(i)) == expected[i]); + } + } +} // namespace + +TEST_CASE("MPC60 SET single-sound loader decodes the default assigned sound", + "[kaitai-set][real-mpc60]") +{ + auto sound = std::make_shared(40000); + + const auto result = + mpc::file::kaitai::Mpc60SetSoundLoader::loadAssignedSoundAtMpc60Pad( + readResource("test/RealMpc60/Set/ROCK.SET"), 0, sound); + + REQUIRE(result.has_value()); + REQUIRE(sound->getName() == "HAT2CLSD"); + REQUIRE(sound->isMono()); + REQUIRE(sound->getSampleRate() == 40000); + REQUIRE(sound->getFrameCount() == 16000); + REQUIRE(sound->getStart() == 0); + REQUIRE(sound->getEnd() == 15999); + REQUIRE_FALSE(sound->isLoopEnabled()); + + const auto sampleData = sound->getSampleData(); + REQUIRE(sampleData->size() == 16000U); + REQUIRE(std::any_of(sampleData->begin(), sampleData->end(), + [](const float sample) + { + return sample < 0.0f; + })); + REQUIRE(std::any_of(sampleData->begin(), sampleData->end(), + [](const float sample) + { + return sample > 0.0f; + })); + requireMatchesMpc2000xlSnd( + *sound, "test/RealMpc60/SetImportedSnd/Rock/HAT2CLSD.SND"); +} + +TEST_CASE("MPC60 SET single-sound loader decodes a selected directory entry", + "[kaitai-set][real-mpc60]") +{ + auto sound = std::make_shared(40000); + + const auto result = + mpc::file::kaitai::Mpc60SetSoundLoader::loadSoundDirectoryEntry( + readResource("test/RealMpc60/Set/ROCK.SET"), 17, sound); + + REQUIRE(result.has_value()); + REQUIRE(sound->getName() == "BIG_CLAP"); + REQUIRE(sound->getFrameCount() == 24000); + REQUIRE(sound->getEnd() == 23999); + requireMatchesMpc2000xlSnd( + *sound, "test/RealMpc60/SetImportedSnd/Rock/BIG_CLAP.SND"); +} diff --git a/src/test/Mpc60SetWholeLoadTest.cpp b/src/test/Mpc60SetWholeLoadTest.cpp new file mode 100644 index 00000000..9b35c9f3 --- /dev/null +++ b/src/test/Mpc60SetWholeLoadTest.cpp @@ -0,0 +1,249 @@ +#include + +#include "Mpc.hpp" +#include "TestMpc.hpp" +#include "StrUtil.hpp" +#include "disk/AbstractDisk.hpp" +#include "disk/MpcFile.hpp" +#include "engine/EngineHost.hpp" +#include "lcdgui/LayeredScreen.hpp" +#include "lcdgui/ScreenId.hpp" +#include "lcdgui/screens/LoadScreen.hpp" +#include "lcdgui/screens/window/LoadASetScreen.hpp" +#include "sampler/Sampler.hpp" +#include "sequencer/Bus.hpp" +#include "sequencer/Sequencer.hpp" +#include "sequencer/Track.hpp" + +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +namespace +{ + void prepareSetFile(mpc::Mpc &mpc, const std::string &setFileName) + { + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc60/Set/" + setFileName); + std::vector data(file.begin(), file.end()); + auto newFile = mpc.getDisk()->newFile(setFileName); + newFile->setFileData(data); + mpc.getDisk()->initFiles(); + } + + void selectSetFile(mpc::Mpc &mpc, const std::string &setFileName) + { + auto layeredScreen = mpc.getLayeredScreen(); + layeredScreen->openScreen("load"); + + const auto loadScreen = + mpc.screens->get(); + const auto fileNames = mpc.getDisk()->getFileNames(); + const auto setFileIt = + std::find_if(fileNames.begin(), fileNames.end(), + [&setFileName](const std::string &fileName) + { + return mpc::StrUtil::eqIgnoreCase(fileName, + setFileName); + }); + REQUIRE(setFileIt != fileNames.end()); + loadScreen->setFileLoad( + static_cast(std::distance(fileNames.begin(), setFileIt))); + loadScreen->function(5); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set"); + } + + void waitForLoadScreen(mpc::Mpc &mpc) + { + constexpr auto timeout = std::chrono::seconds(5); + const auto start = std::chrono::steady_clock::now(); + + while (mpc.getLayeredScreen()->getCurrentScreenName() != "load") + { + REQUIRE(std::chrono::steady_clock::now() - start < timeout); + mpc.getEngineHost()->prepareProcessBlock(512); + mpc.getLayeredScreen()->timerCallback(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + + void requireSelectedDrumProgramIsUsed(mpc::Mpc &mpc, + const mpc::ProgramIndex expected) + { + const auto track = mpc.getSequencer()->getSelectedTrack(); + REQUIRE(mpc::sequencer::isDrumBusType(track->getBusType())); + + const auto drumBus = mpc.getSequencer()->getDrumBus(track->getBusType()); + REQUIRE(drumBus->getProgramIndex() == expected); + REQUIRE(mpc.getSampler()->getProgram(expected.get())->isUsed()); + } +} + +TEST_CASE("MPC60 SET CLEAR load imports sounds and assigns converted notes", + "[kaitai-set][load-set]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + mpc.getEngineHost()->prepareProcessBlock(512); + prepareSetFile(mpc, "ROCK.SET"); + + auto existing = mpc.getSampler()->addSound(); + REQUIRE(existing != nullptr); + existing->setName("dummy"); + + selectSetFile(mpc, "ROCK.SET"); + + const auto setScreen = + mpc.screens->get(); + const auto hiHatNote = setScreen->getConversionTargetNote(0); + const auto rideNote = setScreen->getConversionTargetNote(10); + + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "conversion-table"); + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "load-a-set-replace-add"); + mpc.getLayeredScreen()->getCurrentScreen()->function(2); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "popup"); + waitForLoadScreen(mpc); + + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "load"); + REQUIRE(mpc.getSampler()->getProgramCount() == 1); + REQUIRE(mpc.getSampler()->getSoundCount() == 34); + REQUIRE(mpc.getSampler()->getProgram(0)->getName() == "ROCK"); + REQUIRE(mpc.getSampler()->getSoundName(19) == "HAT2CLSD"); + REQUIRE(mpc.getSampler()->getSoundName(16) == "RIDE4B"); + REQUIRE(mpc.getSampler()->getProgram(0)->getNoteParameters(hiHatNote)->getSoundIndex() == 19); + REQUIRE(mpc.getSampler()->getProgram(0)->getNoteParameters(rideNote)->getSoundIndex() == 16); + requireSelectedDrumProgramIsUsed(mpc, mpc::ProgramIndex(0)); +} + +TEST_CASE("MPC60 SET default conversion table matches MPC2000XL", + "[kaitai-set][load-set]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + prepareSetFile(mpc, "ROCK.SET"); + selectSetFile(mpc, "ROCK.SET"); + + const auto setScreen = + mpc.screens->get(); + + const std::vector expectedNotes{ + 42, 82, 46, 38, 37, 36, 48, 47, 45, 43, 51, 53, 49, 55, 69, 54, 56, + 39, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73}; + + REQUIRE(expectedNotes.size() == 34); + + for (size_t i = 0; i < expectedNotes.size(); ++i) + { + REQUIRE(static_cast( + setScreen->getConversionTargetNote(static_cast(i))) == + expectedNotes[i]); + } +} + +TEST_CASE("MPC60 SET LOAD adds imported program and offsets sound indices", + "[kaitai-set][load-set]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + mpc.getEngineHost()->prepareProcessBlock(512); + prepareSetFile(mpc, "ROCK.SET"); + + auto existing = mpc.getSampler()->addSound(); + REQUIRE(existing != nullptr); + existing->setName("dummy"); + + selectSetFile(mpc, "ROCK.SET"); + + const auto setScreen = + mpc.screens->get(); + const auto hiHatNote = setScreen->getConversionTargetNote(0); + + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "popup"); + waitForLoadScreen(mpc); + + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "load"); + REQUIRE(mpc.getSampler()->getProgramCount() == 2); + REQUIRE(mpc.getSampler()->getSoundCount() == 35); + REQUIRE(mpc.getSampler()->getSoundName(0) == "dummy"); + REQUIRE(mpc.getSampler()->getProgram(1)->getName() == "ROCK"); + REQUIRE(mpc.getSampler()->getProgram(1)->getNoteParameters(hiHatNote)->getSoundIndex() == 20); + requireSelectedDrumProgramIsUsed(mpc, mpc::ProgramIndex(1)); +} + +TEST_CASE("MPC60 STUDIO SET CLEAR load imports sounds and assigns converted notes", + "[kaitai-set][load-set]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + mpc.getEngineHost()->prepareProcessBlock(512); + prepareSetFile(mpc, "STUDIO.SET"); + + selectSetFile(mpc, "STUDIO.SET"); + + const auto setScreen = + mpc.screens->get(); + const auto hiHatNote = setScreen->getConversionTargetNote(0); + const auto rideNote = setScreen->getConversionTargetNote(10); + + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "conversion-table"); + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "load-a-set-replace-add"); + mpc.getLayeredScreen()->getCurrentScreen()->function(2); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "popup"); + waitForLoadScreen(mpc); + + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "load"); + REQUIRE(mpc.getSampler()->getProgramCount() == 1); + REQUIRE(mpc.getSampler()->getSoundCount() == 34); + REQUIRE(mpc.getSampler()->getProgram(0)->getName() == "STUDIO"); + REQUIRE(mpc.getSampler()->getSoundName(19) == "HAT1CLSD"); + REQUIRE(mpc.getSampler()->getSoundName(23) == "RIDE_#1"); + REQUIRE(mpc.getSampler()->getProgram(0)->getNoteParameters(hiHatNote)->getSoundIndex() == 19); + REQUIRE(mpc.getSampler()->getProgram(0)->getNoteParameters(rideNote)->getSoundIndex() == 23); + requireSelectedDrumProgramIsUsed(mpc, mpc::ProgramIndex(0)); +} + +TEST_CASE("MPC60 UK-8 SET load skips unassigned source pads and blank entries", + "[kaitai-set][load-set]") +{ + mpc::Mpc mpc; + mpc::TestMpc::initializeTestMpc(mpc); + mpc.getEngineHost()->prepareProcessBlock(512); + prepareSetFile(mpc, "UK-8.SET"); + + selectSetFile(mpc, "UK-8.SET"); + + const auto setScreen = + mpc.screens->get(); + const auto hiHatNote = setScreen->getConversionTargetNote(0); + const auto unassignedNote = setScreen->getConversionTargetNote(18); + const auto scratchNote = setScreen->getConversionTargetNote(33); + + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "conversion-table"); + mpc.getLayeredScreen()->getCurrentScreen()->function(4); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "load-a-set-replace-add"); + mpc.getLayeredScreen()->getCurrentScreen()->function(2); + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "popup"); + waitForLoadScreen(mpc); + + REQUIRE(mpc.getLayeredScreen()->getCurrentScreenName() == "load"); + REQUIRE(mpc.getSampler()->getProgramCount() == 1); + REQUIRE(mpc.getSampler()->getSoundCount() == 26); + REQUIRE(mpc.getSampler()->getProgram(0)->getName() == "UK-8"); + REQUIRE(mpc.getSampler()->getSoundName(0) == "S7_HH_CL"); + REQUIRE(mpc.getSampler()->getSoundName(20) == "SCRATCH4"); + REQUIRE(mpc.getSampler()->getProgram(0)->getNoteParameters(hiHatNote)->getSoundIndex() == 0); + REQUIRE(mpc.getSampler()->getProgram(0)->getNoteParameters(unassignedNote)->getSoundIndex() == -1); + REQUIRE(mpc.getSampler()->getProgram(0)->getNoteParameters(scratchNote)->getSoundIndex() == 20); + requireSelectedDrumProgramIsUsed(mpc, mpc::ProgramIndex(0)); +} diff --git a/src/test/SetFileUiTest.cpp b/src/test/SetFileUiTest.cpp new file mode 100644 index 00000000..099543f0 --- /dev/null +++ b/src/test/SetFileUiTest.cpp @@ -0,0 +1,333 @@ +#include "catch2/catch_test_macros.hpp" + +#include "TestMpc.hpp" +#include "Mpc.hpp" +#include "disk/AbstractDisk.hpp" +#include "disk/MpcFile.hpp" +#include "engine/EngineHost.hpp" +#include "lcdgui/Label.hpp" +#include "lcdgui/LayeredScreen.hpp" +#include "lcdgui/screens/LoadScreen.hpp" +#include "lcdgui/screens/window/LoadASetScreen.hpp" +#include "sampler/Pad.hpp" +#include "sampler/Program.hpp" +#include "sampler/Sampler.hpp" +#include "sequencer/Bus.hpp" +#include "sequencer/Sequencer.hpp" +#include "StrUtil.hpp" + +#include +#include +#include +#include + +CMRC_DECLARE(mpctest); + +using namespace mpc; +using namespace mpc::lcdgui; +using namespace mpc::lcdgui::screens; + +namespace +{ + constexpr auto kSetFileName = "ROCK.SET"; + + void prepareSetFile(Mpc &mpc) + { + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc60/Set/ROCK.SET"); + std::vector data(file.begin(), file.end()); + auto newFile = mpc.getDisk()->newFile(kSetFileName); + newFile->setFileData(data); + mpc.getDisk()->initFiles(); + } + + void prepareBrokenSetFile(Mpc &mpc) + { + auto newFile = mpc.getDisk()->newFile("BROKEN.SET"); + std::vector data{'B', 'A', 'D'}; + newFile->setFileData(data); + mpc.getDisk()->initFiles(); + } + + void waitForLoadScreen(Mpc &mpc) + { + constexpr auto timeout = std::chrono::seconds(5); + const auto start = std::chrono::steady_clock::now(); + + while (mpc.getLayeredScreen()->getCurrentScreenName() != "load") + { + REQUIRE(std::chrono::steady_clock::now() - start < timeout); + mpc.getEngineHost()->prepareProcessBlock(512); + mpc.getLayeredScreen()->timerCallback(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + + void waitForTimedPopup(Mpc &mpc) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1100)); + mpc.getLayeredScreen()->timerCallback(); + } +} + +TEST_CASE(".SET file opens discovered UI flow", "[load-set][ui]") +{ + Mpc mpc; + TestMpc::initializeTestMpc(mpc); + prepareSetFile(mpc); + + auto layeredScreen = mpc.getLayeredScreen(); + layeredScreen->openScreen("load"); + + const auto loadScreen = mpc.screens->get(); + const auto fileNames = mpc.getDisk()->getFileNames(); + const auto setFileIt = + std::find_if(fileNames.begin(), fileNames.end(), + [](const std::string &fileName) + { + return StrUtil::eqIgnoreCase(fileName, kSetFileName); + }); + REQUIRE(setFileIt != fileNames.end()); + loadScreen->setFileLoad( + static_cast(std::distance(fileNames.begin(), setFileIt))); + loadScreen->function(5); + + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set"); + + layeredScreen->getCurrentScreen()->function(4); + REQUIRE(layeredScreen->getCurrentScreenName() == "conversion-table"); + + layeredScreen->getCurrentScreen()->function(3); + REQUIRE(layeredScreen->getCurrentScreenName() == "load"); + + loadScreen->function(5); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set"); + + layeredScreen->getCurrentScreen()->function(4); + REQUIRE(layeredScreen->getCurrentScreenName() == "conversion-table"); + + layeredScreen->getCurrentScreen()->function(4); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set-replace-add"); + REQUIRE(layeredScreen->getCurrentScreen() + ->findField("load-replace-sound") + ->getText() == "NO(FASTER)"); + + layeredScreen->getCurrentScreen()->turnWheel(1); + REQUIRE(layeredScreen->getCurrentScreen() + ->findField("load-replace-sound") + ->getText() == "YES"); + + layeredScreen->getCurrentScreen()->turnWheel(-1); + REQUIRE(layeredScreen->getCurrentScreen() + ->findField("load-replace-sound") + ->getText() == "NO(FASTER)"); + + layeredScreen->getCurrentScreen()->function(4); + REQUIRE(layeredScreen->getCurrentScreenName() == "popup"); + waitForLoadScreen(mpc); + REQUIRE(layeredScreen->getCurrentScreenName() == "load"); + + loadScreen->function(5); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set"); + + layeredScreen->getCurrentScreen()->function(2); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set-sound"); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "HIHT CLSD (A01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:HAT2CLSD "); + + layeredScreen->getCurrentScreen()->function(3); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set"); + + layeredScreen->getCurrentScreen()->function(2); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set-sound"); + + layeredScreen->getCurrentScreen()->turnWheel(1); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "HIHT MEDM (A01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:HAT2MED "); + + layeredScreen->getCurrentScreen()->turnWheel(1); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "HIHT OPEN (A01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:HAT2OPN "); + + layeredScreen->getCurrentScreen()->turnWheel(15); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "PRC4 (A16)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:BIG_CLAP "); + + layeredScreen->getCurrentScreen()->function(4); + REQUIRE(layeredScreen->getCurrentScreenName() == "popup"); + std::this_thread::sleep_for(std::chrono::milliseconds(350)); + layeredScreen->timerCallback(); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-sound"); + REQUIRE(mpc.getSampler()->getPreviewSound()->getName() == "BIG_CLAP"); + REQUIRE(mpc.getSampler()->getPreviewSound()->getSampleRate() == 40000); +} + +TEST_CASE("Unreadable .SET file reports error and returns to LOAD", + "[load-set][ui]") +{ + Mpc mpc; + TestMpc::initializeTestMpc(mpc); + prepareBrokenSetFile(mpc); + + auto layeredScreen = mpc.getLayeredScreen(); + layeredScreen->openScreen("load"); + + const auto loadScreen = mpc.screens->get(); + const auto fileNames = mpc.getDisk()->getFileNames(); + const auto setFileIt = + std::find_if(fileNames.begin(), fileNames.end(), + [](const std::string &fileName) + { + return StrUtil::eqIgnoreCase(fileName, "BROKEN.SET"); + }); + REQUIRE(setFileIt != fileNames.end()); + loadScreen->setFileLoad( + static_cast(std::distance(fileNames.begin(), setFileIt))); + loadScreen->function(5); + + layeredScreen->timerCallback(); + REQUIRE(layeredScreen->getCurrentScreenName() == "popup"); + waitForTimedPopup(mpc); + REQUIRE(layeredScreen->getCurrentScreenName() == "load"); +} + +TEST_CASE(".SET conversion table resolves pad names through DRUM1 program", + "[load-set][ui]") +{ + Mpc mpc; + TestMpc::initializeTestMpc(mpc); + prepareSetFile(mpc); + + auto layeredScreen = mpc.getLayeredScreen(); + layeredScreen->openScreen("vmpc-settings"); + REQUIRE(layeredScreen->setFocus("initial-pad-mapping")); + layeredScreen->getCurrentScreen()->turnWheel(1); + REQUIRE(layeredScreen->getCurrentScreen() + ->findField("initial-pad-mapping") + ->getText() == "ORIGINAL"); + + layeredScreen->openScreen("load"); + + const auto loadScreen = mpc.screens->get(); + const auto fileNames = mpc.getDisk()->getFileNames(); + const auto setFileIt = + std::find_if(fileNames.begin(), fileNames.end(), + [](const std::string &fileName) + { + return StrUtil::eqIgnoreCase(fileName, kSetFileName); + }); + REQUIRE(setFileIt != fileNames.end()); + loadScreen->setFileLoad( + static_cast(std::distance(fileNames.begin(), setFileIt))); + loadScreen->function(5); + + auto drum1Program = + mpc.getSampler()->createNewProgramAddFirstAvailableSlotAndThen({}).lock(); + REQUIRE(drum1Program); + drum1Program->initPadAssign(); + mpc.getSequencer()->getDrumBus(mpc::sequencer::BusType::DRUM1)->setProgramIndex( + drum1Program->getProgramIndex()); + mpc.getEngineHost()->prepareProcessBlock(512); + layeredScreen->timerCallback(); + REQUIRE(drum1Program->getNoteFromPad(ProgramPadIndex(0)) == DrumNoteNumber(37)); + REQUIRE(drum1Program->getNoteFromPad(ProgramPadIndex(1)) == DrumNoteNumber(36)); + REQUIRE(drum1Program->getNoteFromPad(ProgramPadIndex(2)) == DrumNoteNumber(42)); + REQUIRE(drum1Program->getNoteFromPad(ProgramPadIndex(3)) == DrumNoteNumber(82)); + + layeredScreen->getCurrentScreen()->function(4); + REQUIRE(layeredScreen->getCurrentScreenName() == "conversion-table"); + + layeredScreen->getCurrentScreen()->open(); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "HIHT CLSD (A01) "); + REQUIRE(layeredScreen->getCurrentScreen()->findField("becomes-note")->getText() == + "42/A03"); + + mpc.screens->get()->setConversionTargetNote(0, DrumNoteNumber(82)); + layeredScreen->getCurrentScreen()->open(); + REQUIRE(layeredScreen->getCurrentScreen()->findField("becomes-note")->getText() == + "82/A04"); +} + +TEST_CASE(".SET single-sound browser keeps unassigned UK-8 pads visible", + "[load-set][ui]") +{ + Mpc mpc; + TestMpc::initializeTestMpc(mpc); + + auto fs = cmrc::mpctest::get_filesystem(); + auto file = fs.open("test/RealMpc60/Set/UK-8.SET"); + std::vector data(file.begin(), file.end()); + auto newFile = mpc.getDisk()->newFile("UK-8.SET"); + newFile->setFileData(data); + mpc.getDisk()->initFiles(); + + auto layeredScreen = mpc.getLayeredScreen(); + layeredScreen->openScreen("load"); + + const auto loadScreen = mpc.screens->get(); + const auto fileNames = mpc.getDisk()->getFileNames(); + const auto setFileIt = + std::find_if(fileNames.begin(), fileNames.end(), + [](const std::string &fileName) + { + return StrUtil::eqIgnoreCase(fileName, "UK-8.SET"); + }); + REQUIRE(setFileIt != fileNames.end()); + loadScreen->setFileLoad( + static_cast(std::distance(fileNames.begin(), setFileIt))); + loadScreen->function(5); + + layeredScreen->getCurrentScreen()->function(2); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set-sound"); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "HIHT CLSD (A01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:S7_HH_CL "); + + layeredScreen->getCurrentScreen()->turnWheel(1); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "HIHT MEDM (A01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:S7_HH_MD "); + + layeredScreen->getCurrentScreen()->turnWheel(1); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "HIHT OPEN (A01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:S7_HH_OP "); + + layeredScreen->getCurrentScreen()->turnWheel(1); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "SNR1 (A02)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:UK-SN31 "); + + layeredScreen->getCurrentScreen()->turnWheel(15); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "DR01 (B01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:(no assign)"); + + layeredScreen->getCurrentScreen()->function(4); + REQUIRE(layeredScreen->getCurrentScreenName() == "load-a-set-sound"); + REQUIRE(layeredScreen->getCurrentScreen()->findField("mpc60-pad")->getText() == + "DR01 (B01)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:(no assign)"); + + layeredScreen->getCurrentScreen()->turnWheel(7); + REQUIRE(layeredScreen->getCurrentScreen() + ->findField("mpc60-pad") + ->getText() == "DR08 (B08)"); + REQUIRE(layeredScreen->getCurrentScreen()->findLabel("file")->getText() == + "File:(no assign)"); +} diff --git a/test-resources/RealMpc60/Set/ROCK.SET b/test-resources/RealMpc60/Set/ROCK.SET new file mode 100755 index 0000000000000000000000000000000000000000..f4cbfed0001ed1ee9e591553438144f7317e5ec9 GIT binary patch literal 769476 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
by-vsqTirs;!u_HPt|g}T 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 )2Q~ukDm9p>sGr&fAeAT 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

HsyFzQo1(DU(G|{REHFDTRzWVU>nB+ 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


&z5I(DHmPP+-xgM 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 dE!OPNH3-FNhetdayv~GRW@g)U{MS+ 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 XG{a zSp=+(yRO|_No`hfPHbCWjcxpg#KEOe)cZjg>c9ro+15^c1rO7eqa#)xbi_8DWI)tB z+p6xYHt`kXk{NDN|GsdgqJ<0k}F_K`v}g_#=0*caJ+<9vA<1_&>ROnhgK| literal 0 HcmV?d00001 diff --git a/test-resources/RealMpc60/Set/STUDIO.SET b/test-resources/RealMpc60/Set/STUDIO.SET new file mode 100755 index 0000000000000000000000000000000000000000..8d372d9147c431c970a55f04f41949b95374cf9c GIT binary patch literal 782412 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 literal 0 HcmV?d00001 diff --git a/test-resources/RealMpc60/Set/UK-8.SET b/test-resources/RealMpc60/Set/UK-8.SET new file mode 100755 index 0000000000000000000000000000000000000000..efe89f49f436fe80d6d604d515278cff2dad3574 GIT binary patch literal 779352 zcmeFZcYIXE+c!L?@7dmWlT9y#1VRbD_a;R^P^2lMU_((v1W^u%Ku;e0+~YD(pwlNz?p5*+7T`-aQ6OuILba6w9pk^Df6Ka5D(--e z8@XWdUFgWsJ^u?;qK81mr4&Q^i>ZIe&eM{KvC25duQDHFBXs|E?{@5 zHrR2{G5(wC1#sOA*ZcwPpa^J|0}r@z7dm0|nEybj4jDUSHM-Ed^8QWr!d+R9!^sL& z-J0UccNYBv{g14w4oC-d>Ou4_{J(=vd++vL=&0%U{Yx|p&>fJerxly7!tTNWXu<*b zhw38m3eYbBRp73yqsC8|GU8tit2-ba8U~Nycj5nU7ztps0MOBQTmY<6u78X}0WF}Wfp5VgFn+|8(F$JJU;xy@qF)y-0+Ywg81b*~cTm;6G?)OD3bdo|xB%Gpe?nJIdGGup@WA*9Q~x)r z`l&Ms@Y+yC!%E+ADSo9m;^%jb^OIuN&VcHW^>5=SF7Y4Z7&=^`LrqIpgjsFi-+l`IH-;+-1 zJH~%|({`|0@!{=o47eXq5BAvj=$HRM|3lSk?4eLoWbNoXuD==n$F3cdj(TwVL!15^ zsO5ix&b7fcpNUx@A5e3qFZl9b=zkbC|Mv{HV=pODBC5ou1q#(}pD*|q`mg^3M~_!Y z(9jKlyZu@cWPq-Un*L$f4qSkm>H22Ce*?AuPtb4eaLocy4=f5aZQG!Kq5pA-6ywhS zr6#36v8RJ-M_99h4GO~#N}Uy#pk^-awf(<=I{zo=-)hPLxr(fh4*Ky+MfLx;{r^$} z2#VnZX)u~76|L52b$a-}n%&_{G21LwWb)*34=!K6?71~-maLh!aOIi@l(u~N@)a{@ z&U{d5bBYF!91MC)SyMa>tN}$+){Go7d^qSbbB!x)@uNMuO`qOr&6-Y&l-8?Pr%t_; zHu?W(AnWg+9y!CaPh@`HY$u^kePjbPEDE<owgvohbejXHHreANEef=GuDVXGk0b!IC7NlbIt1AvW_`I>IASXMCigT_=A-gv0^ufqkIE6xqOS?SH| z-aaLkwm%kh*|d92+f&B3qS1-xe$PA|$ygk1IoIp#Qk}K=#MG4ImUwp6wZdymk2_9d z;$2VvcA=1NkGaLhC(MbDJDD#x7|;3w7t(GWq*At~fi-QGj7z!SM}+ru`L|l_MWx>R zdyuEu3yY`RYIHIYf8G|nG=$n`)jOU9>_ttMJBdxNv%Kh!e5EOD_6w)^wq-hfv^IAGpL{;|as?{R z3iYtH!Q<)WzqlH|(p#6@>K-rCpDH-9E>*Xz$$UFJ@X0g6uOkn>)wS)N+R^9kq<>wb z`SYn*M{! z`mC)2&AOV&o!d{Ph8IxoN7B^Y>ocorooNyM%l=U5q+dt%Mk=bZ`dl9{KO%Dy=L=~s zTG5ZxwX;pNeNu>f+8v%&WRsEdd%3*{;fjI;yy96r%!S*z!0QN^{+;Yo%T)*vhr zK-}pCdTvlt-sg4tSIuF&25N(rUz>~cEn<7&rF@I#kC=UUyXJUUCiBaaX0+ViSZRrl zMAU~l2;(_(FPGF->8A^PcGitGspi&p<^^?hsm@=T9$BGl9+(oIS=aC7*0cjxJALXl ztRmVnoK;2L&%D%yvD_IjqsDYXAU31d=^?)P*07;5uS@07p%wTixOrGc@0 zJ?E}INqG?uKNkDl`Dg__NZo z3~$??V`JTRxh11U7>dd3 zgorM)1sJi7fy{vsZf1yU?c`oen)+i2Th#JfdDcc<<)eCge|Un7>o4O zH4JmHuhHs-t;WOt^kq!o%g*&8VLs4onc>sVfudLMeoIeojetf3eM8U9r^C~Mv^A2s zFhQ7#>D!^se~2WN-lrlU-ATSmhh4*52r`P2)J0`Mk=Zk7|1WMfXqnrwyp zWjvMQUR4Lblq`v6BNihCZ7Z4TTS$BSM*E6ZEBZOxFt>NWmB(vL^_%UGBOYA%#I5g_r9+f?2`dkDj0jA-l=e5zV%${r~iHH#YGGg4vk&7YxU5W+~tt#Qz&$jxFi91@f5RJJ=S!9WaA=t%f zM+*q5ZZ|^HZwMe0)M7FFxi)6J{?3MM{r)EH?;t+TQnxf$7{H;LfaVoRzacK=8rX>t ze}d5vD$x)^-;(ixga#JB_`hht(oA*~aw)rqi|BA)=^foA_p zG_MAlJcv&Y@(WGu3_>aiYv*y=83MI|Mb0o#PbcoE@uw506G}cr^IHrbAaQQ1mo`K< zsdyI0M+L3d68JcVzLwM+Cq1)`+y@x!l_ZS-zNSjH5@M}{KgG!7wTLYOTPV1USM3OE zmVwAy82u~G_u|5*#Q1BhF()8FObo8Lb@U7&LB(*MAt(85=`n;x?NGr5kGo`@SW9) z%|xP>CiaJ%v%T1S5ZP#9W2WGXv{;_hro;_N2(sv4x6JeUsOk5bF~Wb(Zv zeh;2Rjq%yMWm63Pf?KtkdmiNs z81+${9wx^R>AArm_Occ{$I1mNF+wEzV5+W3{B52n6S2vFi6dkf5&RHY$5MlMP>I2* zm~bB%N7QmEhOA_$_JE@>&ONA)deq$O7{3)E9>T$g33Y1>eGDVsM-uPjjEe&ES=B+7 zn2kpLMz)AI_U45PA|?^S3P=)hFjXHz^>9oa*^k2+I6nf#t#NJV1UZyP-lzC}5ZNz_ z%hh5965mOnS9nzpltmu7iNZcS_6tH5N91OUZxTjs6EtU{vL9y;sMuaOHY-kcMUY=a zek~EN!ud2By*FZ77C^63%yb0%0gBn`XdNk>MA7R!dX`r`8P~80`gbnLnuFhJ`G*nW z`GoEWht&%BV~{BSOGvp>AtePTHl*8{h9)-d!RLZ0912J`>Ak4>+dw{$U%5US+ zLgmmWVt*q+lFuGqC zN>zj95cTnxQ;^EEp`;4mB;izy0wPr;ieUm>%few2xgO=;MCIquL{}Vsi6TFX{445Y zDkP&kdJjY%Wyu*5vIv5!2%Nzq4k+y)8;0_^XV)hI3&QPLa^QK>i&Q%Ouo@%9)sSAAtQ)>}wXgARzlO z-a-JCKui*dQ>gI01j{gF4wN@xi8_`1nJga`Rr!K!CdBt;bTO|v&&WM6`CCNTk3s;X z!+^MxgtJI-6998$If}p^BzOXY&jZ;6!C@I)0p)>$`~W2{m#_x}bejy%;%qe`>;o7O z=slb~j}WQ=%E{<%0bPNJE=*EpeLDnd0sRP(M`7Y@6kHea^$_hR!WU7gE6KM4G)5L8W{Y z4i$+ncpxD18!~~2C<=rS$!|npqks+VxD}j(zzZy~6lLGQ;NuXDAwmfPuL;-);5xJZ7)kqJTGg-E~S!Vv^cfXH|W*^Iy^AXqAc3#jq{ zfa(O~Q&i4Cr9u?>4Z=Z)@Eal65s;AZdj-@Xqdi1$9Fu>BO2P;11j6qKctr+3LHLt| zodrTJBHMB4dkKGBLbk}_1XMOdh2$50|IWJ@TWblQAoIto4D#fwohalXJ!ng>2 z?zlhlw1kX66$h5n5rl-|lNcNV;U$QUgYpysHQ?fRC{iXt4kEt*v51ga5q}=Q7i1(; zLX%LYaQK&m91&p@m;DHOk0jlT!s8MsM&-8=c?l*dDncMWLtAY*(1XK0C__K(`Bp<%4I;>h=R8uoGnY$D7=P>8zE>Cu^%OL7F5z5 z*da;Uib|_cBv*!CLHIQU0z^*9vJVC80sKOSJ0aYK0s_Ku2$C;@UW(M1d;x;l5Zxy$ zxl!<-3}lGxP$mc>PefoR0B=Ji0_DyK{8dIy0w_z^6-CcLUVw_7Q8-pYKU1cOvhV>o z0l>KsT_?&ORNg70Z340pfSv$$2J$Wd?GU*ig4IAi0pw=^coBdHWVjoGKOpijkV+9b zO_3U+H)Ld~3~c~e1Y|`727nNh&mwRkM214R9KaVLaskRY2=aprHY?E^K~4e40r5Nl z$0SsRfTSc3MB(QUY*DhI5=;R3Ap~*A@~a5k4AG}#IRnT?0g?@2DhhhYKv_E9m61oF zT#LY|sPqm3cgbJ^Q1k#5B`7X^M8X?n#0-^;wfs6Ne+iIhCFnxHk21nYU^ODG1j;;x zZv(kW2JZr}8p5|BTnmv#MgOwYf`D-{m;zxHkRJu06v8zS@`}eor2E}-#ZD0RN5EhJ z#!FxafEN%@B6pl9s!{oU1a6TP4S=-}evE(?8CW3l5Cms{tW39oN^n5nYf4N2$RG%2 z0@wp6w?+HP;8g%hP|*#*VW@C1-{0#GM|$_}oSsV5gf@Hqkl z0G^OR7a)re!DJ`_pzIpHfUpg~6rkJ(=?&pVME(fCw}4VL0FTJX!w^==h+_I?NvU0s zyCZT>1g?Wn;rT@fUjxcEA5rYM8^}JnBTZZm;e9}UMcJwVFd2e9GFYpWB>=D=!b1=c z%C4m2C>5@U;6tEWz+~k6;z1An*hEGVLJc?5KaOh0XwX75yEZ&=?P^wMB47U z$37)WK=3qFA`BSOk%Wb{GF*UwMIuI4#HLln(rP>zX_B? zX2-9?6=MO|M@hHKKvC~Hh@6w5;%sUJDlw#72Ca8h{T1x+Pi3*&1HqdR)I+H3cj^Ef z2^6~k<#0-zOwoifZvV2h0W3}vM};Q;`D zk-=jMhsy3r5f*_Xfb#eRzl4fuz;y`!k~;#XrsLdS@f>Kl`wH*2zsJg}LPhx~s4U9> z9#i6&!Y71}LEuC2sRR=8MdsM>i8{j>xAPIYDh(zC)$#FF9;RP4V zP?B1WdpipTx|Px{PmaRcC{JuO{%|XU#0q`!+s&!f)&1p{ z+)`~y&B8>%h#OkHSwf6$EN^+(V|k{fu$j|Q*OFzavBhcO8V&9@pGLCe9ymX-_ff?4hGZZye}l)+qP~L`Cqq8ny$$r|qP{8f%*REsT~Y13KI+vFXVOX2qmeIFSjquI4i}^*V(e(i^qp{agpR6mmlkhl3 zBB2qkXoJcGt{dDulM@-Ka^HG;#<9iO4uZM5e&Vq+#GvA{y<7emyWpm=n@(7HNxIhi z&kqKvmb=Ls>**`m(Q7KhS2(ks&$X2r&-&BKb&VgAsw3XCTWGjm}riMwI=iHD&6sey{(;)ciL%l#+e6mZZGW| z9tW@J_i^Vzoe zeV4x$oZb8_Z)Y~m93$^8OCDmBb#T_>-*mgI_CB8?d=ZFva_&4$+m7X3ds^+3+K|sA z!==iCN~C6Y-#^X_H67gBt;7(|Ez3L@?1h8q?fhSUPHlfv+jEe{zzIlIE`P-Q)(2};^d~_pa$>lPB@Hc%kyuC44E4Tt} ziNzH^+6LB(Ck=g?>zcpm`ZLJyc`Omwtt;hvC5qkMirR0D%55~{IIx=on{KNO-ho37 z>)z^i;L?bTzU<^5EyauD^)7Y>S$gM((e=Gr^45EVbAxII*{h9Bx*t`{AXnznE3?l3 zaHj9v#KW{bQL1T_B4cHp%36Pp(LbtBt{Za({5k273VliMufOUtto*XE3m2)f<7Y^? zydrb#?VhY=^TIjA(iT)>#`{&}?z5LlRV9AE>4>purOJO6>k|1b@63>|X5CYK-VqCFzV}WW6K1*E+sUh)mhO{@MutXTIT;MIrgT>_Qd))l+=T>h0aXIb2S`G;R8X%k=AAFLWa5Z<4Cj+DJjco$Xf& zDth`?-MXj!V%B_jTVvPwD3kDc8*~jj+Zxh5np?h!>2dkubk{Xs*KyyZ*>z|5qIpU8 zCt+&m;MKs5h&n@O@m^Eo6Mr z(lRm(zr3fSZ=i=O$@i+o7i1)E5Zoqf15r_wJ@||yMwhB%E0aAMl9;i~x=ze`q1?z0 zKVBa0vNOS@q)nN1(2=+h5%9WNP> zl-6=Y(%kG;lO6M^53b4yoiine3b~F3;~1!O`SV{XHP4BQ?tHhZ>(!@OY62$pP3Ax8 z^Eorxb~)MS+NG7bA;eu!dLu)MOW&l{m{nvyr(91~RU`|FE_9z|ideFbxJcD{wV*pO zW;zIYB(Ob4JWG_0V0(7Ifxb62w*CUP0rx$d8Tyv!j@;sRx%fpl9WgSX9J!p=2Kyzo zbY}f>y6P3@ue$rABpoqAShL1jeQ?wmQ?QRCWn(8Ro+Xj(^_it+cd$Qaa{cA#gT| zFKBZ$JhEeV+nCP}sn-pTUGis6y~CFdtJ-GJf*Ec)kpLAkU?sT6QY*`&k zUwdSHUE0aFdfg~YX!fL6L^WCauj_Q0ybnuL?g@DIcHNWKbNI32V5_O6OZJ^vcvjLA zd z&PkGY3CDfr%gi%j(-MIpnWpD2F=vc=58=7MrVeG8(N@=Ix3AtXxEgyO8(@o6NSPmA z>bF~adqi8->NfjtxO|9eUTw&TdjGn2pjB!ko={FVv*;c|d`ITBH+_>zkEFOztEX;c(ge7?LMAZs2{|R#)1N=Ebhuur3W`bT+vcTJogB z;XE`wF8>AL7j2fHXrcgGUnX2gm5yal$#XRhZx+_k(SYIutDyBXai$-0%e zRgzF`aWD&U_L8mpvBS>KasO?PpS%F4mZ*cbeEDCbUmkjM z&_2L036e;acV3o)>fjG)o_N1o+1?)05}G?ca;sN{Y~ z7xZ;&gWb+s+uyIudniu6+Fslh9AFFD(o+nNBC)?}1hYf`geLe!nES|ve5XtkZ^5rY z)8Pcl2C8EHtUK$hJFHi8o!Y+TT_!Ne`LyRm*T5MJzjdaoN7p#1K>WCkcu@jZ0`wvw zb-w=27E*i_ChwuhM$Fw;IflV~nj}G*1Doiy!!<$4Kx{Bzo9YZ(fLtlHJP*+#r)E&A zp`3$qHClm8PNj7}OSQ`>+vPU$F;cc$xJQ!N zMNRB9C)uOS@)l;eU@x7l@n4R13xydyz((FO&F}5QeMFbk^M045mnD*!5canf#}d|& zq1cxCVedEA{LriXwL!i=neZ_Ld0%u~YP4;Lx2bdEbF~I6XqkOM|H8DJ=i^9A97TLX z&n7)%>6-TFx`2Dwo0jx;VV;%TK(?H7;-jkbl8uSB`;ui1t#20A^h`s>MyXM5q?;PwK%p~gn0aWI zC2f}XTez4rJVV#=Vn){Qb?!9|`u;fm9CS<$m%pnPqj?c6uA5LU^-YUL(}M+Z{crWDq?%zV;lU7#tCYP`ET?-TOzPi7bZ6UgbfyNP#x=7& z_0LXKC+Ya7xOEE~^2hySJEyF!@_t{~c0VP3b!T|`HU3&JUv0!c2XXCI*B{n9M%C-5 zOO(SdC*!1s>H)S+*OC9C;6(%(dA5 z5;~ji_d9aK?Bp(x zPV#%)yh@HH0@ABw_f34|mmbT9W~4z%zK2F^8Q48|^9@X|4XE>yXh=$DMQaJu{A83p zR!rs9huRX(GhOPh@N9W=`tZz}wID56ZdgV7d*stnO=6X#p3l14kmEU{<4fA(-IKk~ zwdxOeEbXy?u8ZoO_J)U2!UZ(@iZjW5c!cW(^d=B`m$ z0nZ*7u#KrnwRwLXQhT^1k8jkD>3n-+O61pDLif?pk8Tc3yUL9(j6UtpiU(p5SL-5M zXq^h%<5$0!G_BOt&$R>wN|uzQ$)IlC%x0U*UBAlO%`vV?8`vwU`dJ#^OAlPJ+w0HL z-;nBeA~(|NCJ(OvJ(kt~s_K+cYDZPC2>fN0d?KjU8hkI7I(HMB=*690~hJuXNV@6?RePM;FW;bTT1B}6* zoMR8JDbITgtzG8IdZIpTb2K<|sB~}Uvo-Ok7EW}U`d8JyGTJvjVGsklyarvI(od#z zrFAS$w@1?O1B~>ZCH7{UWr_q3YvMmp)K{u1lO2gdeP*3wp5DuG^iSsYS1bGW)P-Fk z;XX4mga)15@t-5+$Bohc1lyIWdnwnk^>pqwr16D#J_A~M@ z)*R7JRg+^lw09u9&TJl4Ll!&Rmf4u@vAEV@moIeRVY&QfcGFmE?!aC7rUcbus<)Ti zeBFZV^U4KcT9Wn3hOEK0#(8a+-i*2NrjsNs%6N0$@ei^C+v}%)atcq;fgi7RG7UR) zux0Et`gW=9Cg>7{6v^|NGqrRr?6tgwofl;ZU35zk&$h-#P-GpJJRZzF&_))M4I489 z&j`KC6K*S^dW>P#k@c<&VpS}4c9^3iwpHX`4i3BC8hBkBvSoM|XyR+Fk%ve@&t<1K zMKdYqP@nKj9^(ii4FG#eIe*qB+<}zot+qKtAUh-ZV^UZ{i^})5W}z)dbqP#u+T>1u zELL~Dw$nx*A)tW@EK?c>P#30D_&nRX7fdn%Ahn zOBPQ*LQBVdyGmllr1j{{B3n4J5o+FN4dXQx3yr#>AalwP^c1&7f&O3h1bx{_Za<;Bs0UQzT&@tJAP2xW?)n)s`?GpK^6z&|* zG^MuAHOEgz;>i;4*oyAU4SSz0>^1qAjczyd1r>$XJDe@q9-b1p-FRHxaxCN*6h4i&?oxGmT{j3ZH z9KXgI_&udvud??NDu7ESJ>Bl}rgjSZ{gUG&HfGnfu2qwzYVH@D@1ID%-q~BL6Rx!< z0N0O+CR-y~y*4_$dPsAuc8JE1l~T%D@W~0`^H^cL(K|5{j)f7QD!Ptjv<}Nqs{P}* znn~&_*%Yj-<|Au%o*VyOXYM6j-`u@^o25OJo?E%!wh?m)Zt){jUhh}W(KgQ*T=gxJ zht?x2327!tm&)8{UT#B{Fjy1s&jbe>9UoTrz3RE$Q&hjv1vQtcUssCUNd6wJ;f082 zy^DR`UA&}~dRkpIU6(vc! zrm&-vbg@h~sA9wTz&S_MLu-cwjKLZQndFuu+ToNx&4|7mLkGvHw_NQXqT016KbYs* z+0elOptvj#LvP&4Y#Sj_FPYVq4PCx0ZF#m&+oyp69|gqd&AfwlP48Oadgs%dQ<^Ui z@ckU7Ym>&eBGd!8bNEg5ZEN*nI%}{yb%$`}R8jOhl_XKlXfw5_HB%c8y+8;z?2Q{! z>26w*;z7&=lUhxGUjpAZNwJ zFzj-OE3MTUhwyMEYo8TX?dQ5zWb=gf1Q;9_RTLl#rnXWx<^Nr8%cz+XtpZ zETQV0=GmVa@ZITozuPYsRFBN!ORCMU0cKW8d}_kB*Qa{}#f(hzH~EIlvg~C@+jG{| zhb-iVkY;+)6y_82115u=JrGOWpM!5{OT1!Fe#G-5C0CL`GVnke;^Urr|gc$UNK1@GtQ%}?gd$q z&6Klr<6}`5%ADSDt{@y?)@CIj! zM!=K(y@nQOZn@QYv#Q~ksluBj9D~NK_4?DO*GKlu@c98=y>h6#53u}H<9r>Bzp6nq z;^Av*^#Zq}zoRju^)0*UW42-f5 zOEFcX+N~wGkQu7pt=i^e8gIRHig)Xg<`DsItp7+^|Us6 zsX9dC>MvPt2}$jUlTXua$873oE1yYOkMm4aW_nXZRKO`VVo_5=qr%0Mnxkst7xB;s zYV(+;%-Sfz1&~#m#N(Mkgw(XQs`_g}tV&<&$8tg9VFPRq>*a{5*$_%iFApcpL6DbQ z3ol^8F>7K+NMoQQUXeVR(liHC(~@pMBRN(D#;f7CGJ8*mew=0rC+yBOj=?%V*`nL4 zZm3it;dtr@DWK%XUuE=OeKG4u887A=1~s9VU8ht&QpdiiNltKmH!JGYpE z(}MPeJiR!8I0ZaM6V6SEuZg?P`@E+L!ee>!D!=7go%vCju&H9JbP0#KdQ=LZq>&A6 z)-54vez?b1V%t_-^HE*e!FD95YGG58O8w0INP3kwQIXpIC#h94+$QB*5%MosRCkj8 zft=yfHs?#WNcV_-b-QkBPGn09z6Es;DTaT9HTqDv23UU3G7EX)Stgdy%1*uTJZ?PH z7TLoV`nbq_B-Jw}G-$z5LtsuwZ&5>sx~a&;wzsCF_~9;-_7^vz)rGd{7#oUyCq@VJ zol;s%jdZw%^-oLJJE8l2bux`oc?1>YLk7JDRHk=Hf_1Js64$I3xDPB`Jui5g^Qc79 zmgWB`Lj9=|*)YC~O3XBbGD4kl81|i{ih$^=R-vW=6qwtY6k??awkw-dF>@nJejMd~ z&|;|(aLy?5ZTd$*IU zv-l#+ZJh3(Xzg7n_F+K3pmP`Eo1f(^Vpe&9jR zs@1=H5gWo9jqY$p4LeuLF0@ym}l2^&hm-#G3rZwvIcN#bl$;|@iHOb zz&)L<;OnONsh%oNEBXo#e=r2ffi1t0SkBwNZMK{THOWF>*QoItMLe%07Ik$vO?;(K zDn)CT7}v(IMnV(4pneq}c^T?%1~t2q#$FOJfMxC&{NppLO3d=xOxK%j?aw+rcPQ+B ziWpp@*>7(?tksU@@$v1cYgyfBx9S}%(obVu7K@EAc{o$DUgceCrB8?OiAniWLKveb z9c4~X5HND+$;c{)lvVb&OCDdw?(`EHJk-txk)RLjy z-i!ylX-5*~A@Q~|2I&|c8>5%5q1xsUzY_OdqEo*T=y_~~H#hPrf?p8$?U5`y7QZ(p zzQbx|ju;BbX&Udl68asdo+fAlc;LFOt~EY>qz{BF^Cee z0|w&ZU}{>FFGPjs%=`|&{I;1tAc|LjW~(5MRk0sL`PF9n4c33akowsT=TMaCE5&V2 z?huw-ri!dYz#UG#Qb^X5MCVp}LKFA`pgROjIg@C0@KKNL00%GP(vRBEPMWb0O6`H6 zjYTwK=%h*L!s)dl6q{0Rs0BS9N;QUuX~>cQy#(i<#8d|x^ zxPAz=+-JJSr$@BXDo~%5#yqA$j>zb*5n>%4x)-DO#9YNO`IRKtM90~5-vQb^%VeJ7 zqYVM#F=M30*Qp|g&qG`44Z=`0zYB-UBSggOxJ64RgyHJ|roui}AhQwWx zrZlN~9Em(iCq76C*nrL1szqgfBR<@46YqXpsKP=Cyud=6ULMY%xZcL1`MMWIU7tu3;uOKfWt z=m6OiG=B!8hX`9`O#CD+y=zpB;^Y;Uviua`tT$^iml#7x3!(juMv5VX&jI0f`uh9K zM`HXmz29giNtT=peWzpQm;v6D;xZ3uQS+HTAj!JV!`cfZ^`IPX;l=KhnuF+f9&IJ> z`zu|jC8$Y^`@BkhlEqi4#dibrb7XA07GEt<3u?*cRQZFbYP?MMi-pEG*$**pmnqpA zG%pQVi|Dq85}FNw-l}WW>ewZsx>*w`WaRUL=3c+u#p%B${5p}2$C2+W>^@Di))HK$ z7M?>>-fwaYtkqX*Vt>*}n?TPn1Xt@qoh9U4%={P7ZxRBbh`mJ}`jKEDhCPn5M zr_+-}0DD|Aevc-%>HWLn*7cFZU}5v3+q|+hKS8gfct50 zS=0nDBvn>ViwXOb%{GocC6P3q)FOZYXaORH)Nv&4oM-g&@pj5+9OB7*Iu056W`hcSPQ)IJsZszDXZTXB{1J3Y&7n_dVg{=jh%-GgcUf9|9aK#U zW6cPuPttp-KphtG=+%D&@zH{%DiF`LDqjH*b+YaczWt{(VOz{(_8A3%eLsRBotUN&_E)E;AP>G1CY9(v{=3i`M{Xye=;I!<4wH+T)LUR#iJjP$&q6A#zy>cj9W^hH7HYq z#vW30YYg#NoZcZ3PZ02zB=?6t`ZZ}?5rof5v|a>4&~Z*;bTIg;84a=64Q(VL5xrUJ z6dtTKGZ%REMGg!i(32ATmt^`TN(|&X>K?yUb9Hp`cmkcQfklYqVz38P+`Ew896~11 zN=X$rSs=RbD2a%hbOMR-yW{HZ3|N~I`Y=of2>ccY?3_|gChjxH?@Ra>tguC$_yFiE z2_%b5DwVf4fcy=C{TedFh*&$L+8GGORiJ_Ow!9GT1dx%ej#0am}EznCP zW}z{WDF*jxjWuofr;dOhq7TTzVO+H-rnyJpyP<|)Gta?T+V-g2BB_<)|KCXe0F{2C6kLGo ze`Nz1RO-BXahQSVjKppO`7}@sh`(K9`cFis-X4k1G{+ zqFhUH$9Z*0ST`@puQElKQt?U()Uj}_q%Oe#;8bsiNslC}3G`ti+69;M@reHa;px1? ztEiqne#-9Nnw#ExNJ8knR{`lt6;MGe6uY8`3N~zrSU^RvA|MDhst78b&zD2!__tF|s@$Xnd?oS22A~3-dzxPD`fXS9- z1swH4?%08Rqp-Bw;+!d)ALhY(R4b7KV?1q{4aobMn z{3n7Px>hLTl}ccsfgez`#YnVZ*~#U<-287-a9CKNy(954uW1ABSfhkfe_&HgV}#kX zD`@V^gOfGsu%s;luvWYL43Q3s_H;8jW_KNCVhANas!@}C_zmL8#+Kc>t+(M{5Z*S( z0$mksALpYz=24!6SLL=71W#r1K%I8u#vQA(*<^XCO}57P-s8bPgO)wIL`+5v_B~GJ zi>m$U4pUF2Tcb2bJF8D>OE(4XbI0%1#o`X-ve~~1vr=q2;bN=8eQ!z1W@p4vzkbT1 z?nPvr-T8?L3ggY+8JeH75yWz@@Lw^^_SU!tjXcYZQI=2>;wZ)Y3dd80G&*3jXzDZx zAF}i0K;V{Q79R75nAHTLDw(I5dYLKgCFH-PYky!fs zG%Z8;UEW@CR6QWIoW z9Na^rGCe3u)7OO?`!N0x;Xjf8)r>NOEgrFi5Xp|07{|ZGc@R%2iF> z8r}{?EXM-MN;$C6puKg+WG#>v?i((YJUoEN$y}^7$Ivdo<3OV?zT*ny@!z5q6t{`ew#Gx;ot7 ztc$TW<3-i>f?GZ&tM_5H8ly2b-+KZ3E)=|k&6hl(WwGAWaono=&3uc-^W0Hm5bH{U z`#FEy5x8q8eRcdQ=BqSIJ=3yHbaQ}j!=k^LM2g^By1dP*_A_vVtS1B=3sh0T>HS3W zVra@U{bqIBBK&1u+i=WZ4n$)gPr$(`7QR~YMM~!TJkVmH{v{hznC)Ak{UQ0j<(3ra z1+%rg6?B-J43}+5AZ$^)*kvZKXhvs(3HArVXPwI#rq=Iq(B`DpBkY8xsX0n<#le;P?I)Jg0@)I zCL(&N+De2^Ao?8Xcss_IZ&+RqNEw{GOleQAu|%P_G+rxFvzxY<{542git!=I4Po+k zEI2ldyy=WKxc8#nJDJ-*BI*`~p_lm?ER|r_MH4DvBFTh5(Di>1`dkZ7)b+B^iuR_BOHC{3Bbj&^@(xVz)>UH#BP>xPI>HIatcrnbGz{3aez*AUiS$EAm0qaf)$1~$=?s(2k z&5C!ZFzwgKVO@JGTJP$or?@^ULZ9WAz74{ePSA;zxf)u>_(+qnnoHXQmU(_{k5zmi zxtCIPiemZQZEBSGYeF54jq@`31GD#n_DO9fYczNtl%UHK%>Khzdqk5yG2>>#_qi|) zKqAYaDT+Q1@twMyrJKXKfZqCdO}vJ<|Ff|OU)Xj{-hlj{LMMVbn5>XUzp@DX3(b7C zLTb1qAUid5;pLF+ga3>fDB3{_I(gdkZ(+qT$@ zhb`uecEuJDCmf!~skA-FU$O9RjKx#Yp;_|$h?w#;Z6U?K>xQndOm1GO z(fb4RKa+o2z`R#sW3dWKV2IFOP)LIxIvMqFiM(XhA|a8b;E6#wmIRg(c>&cfarzY3 z^JTFjfT!qT2XR}rNrC2q{u(-B;8~P74ANw{9m45m zLw*M7shVVy<(*#Ba247~q|G{xwgi_Wc138AsrgPb!Yu0J$o8C1?oj0#C2*I3Ockx1 zz688GL#)R9Bdk-y`h(xNXz3`E?e7I-doZ}ykYBXS?D)vcJ zu*Ys=4=`ynk}FjIeHISA4F3`3H#a*i5s3uHbLk($x+7q8BhddPf2`8S5q*-XROx7u z`6e5*hw!F=d9@Ig437}6(WU z#?eS2-v~(Cb;(TJ?N*c}q!zFIFVgo*9Qx&-G6il+z5pUm3k$Szmk4r6Hy`%18M5z3 z*@S8E9UZ@*OV47xjna=b@eAjT#AuhPn#|-jVnZvc6YxFUOXf2DwE&pUIMwp_iC6Nwemw zhH4g2AvRKC8ztz5(`Qpimf~?Z)IHRT1)?VJLgm?;&!DPV;@H&YV7Dh&~Gc*B}c~aIn>V!67F2Z3RK{x{f*M3g}Nb!8RP^9*@4VRf?h2Gi#fSthz*(tIYL;No*X&LC1}+1Df+jfk}n`XcNg z27O`T8kdh5yc-RgCDb3|3%ZdM#vq$KR-glZ=~rZVS_Er2ozK`OQmENVCU~pP4-0xn zpr4Qyz(yYv+2b=(WbzLe!#Mhy8H2Et$H&$g;=np84r9_;Bby{`DdHa@$^^cbi&7yK2JwfKmtg%X zCPhQzA?6)OFvgyxXk<`&m7rK`>|i)UV$h^^kxRV;%1H^9vG#(jLAT>4T;6Gf&GH$u zv3O6>|E5N=q;A7>Ad-4`EN`;FaEUB2YhMLuJvCxwG%cv~(}P28;#HL#Cdh$}kBAt< z@La4PrBWA-vQcQe7=#Df!1(^!QlLUEP zQa>kboS^x-5`%q6A>$2tnwh)lzBw|)T+nW58K#PdneH&7EMnVQNz$VRfgalmqC>mZT!t=j|+-hBV&ye3I+5#z1%B4-% zv`1BQ3EdO4{=>BC)Hq30OSpJim;dmy4=H&MNW_dj9csX2%NVYdBttW%VmzJGuL(}j z)LUk>$-wa#4d(0;#XsxxTU{#P{-Y++q0=K++bY;q8C9bomdQ-RvNFh~FuAvCdK?)O zu#qk6xhA7Xms5%Ujvz@?+k;Vqjt+6UUnnOvV-VHrWo3o%J!xP!SJr|_=i*0+{3vL& zW~`y&eI_+<27TG@a2|!|mz=GpYJ+4M=fPoSV>uI%hV%o+oh9*vhL>QpMq;B0xKXl# zqY9!Pp!%;e94iQiq9^EPFQbctbR;4(17wdZcIf)kSosX=Q)T}xt6t4ucT4LT+N7Gi zsyrXD_0WtjM6`jYnzT8x|1tt|O7GXC*ECX!&|$^fozP8~eaG-?*mzz-O$KlY`}hSzyoSi@9N%RjJ9AYJbv`~y z*=}Tvr1U1|%NVKACA$D#lg}cPX@)qC=yn5b!6HFN2MK$g&>cb4BI~Ip!>pRtGBK61 zo>=oCI*pUr!q_I`X&Ty&#CXhZOKdYo^%(EarLjzp$JUiPhu`BQ?VQB>60x1Znh|z0 zt7Uu&;rn$3Qg96F16A9TLJgPI9t5oyxE<-gAgnSBf&me}6r)sV_r^+tO8?=k0`m=u z@w-4TVFqoU49;CCJJR=fLzwmS5`HWDF5k! z`BrrWmfC{~7NW#J(-8hlla?azYh*ps1B$vv63YxJV33|dJi`P`*#{VZgtXp5-o(WK zhI(N%n?Ng;_BkPym_ZZk?_5k1tPu;HN!O5m8KF-(NdlyRf#(aHgn~y*e67Gm8W;h- zLlVy+eJ$7lVZZJsdu9G-kWNrM1y%%6gN>P{Xc$pmp!1WMn-pGcAc?X?gy^ccD5GeG zr_*4pAb;xAA@eB=f1~r$1VcmgBUEkHNh{^LL7<&HOp{Jf7J<~qEXMPkPSDJ~!4z=g zn#t(SOptas&Ct`Bw=>=#afoyroKKb5kC0k75WtA4Ilmg})rFOBJd6>Xqe1s)1jo^g z#*n~16V29XfyU-z$w7jTQTC5O12H)xjNuGNOMH)kT^!qyQI60c!~890KpV(3M3kcb zB8B|pWSxY8Ji}6kU=Qf%8^VKoENOW{8VUbmNKX>}o6(mHU{!l(MVfBQ&X%NgE7O%>z>veu;>2(5uVDAVkJ9={;^(CFU_m zo@BJr;HTVj&_FY>xTYaH70ZAJBI!jOw`p<)hs1?Z3_Zezd`=UqsW>Qv1p;%^?m^4i1LnLlRtWwb-3IL=GG<5$5_Kg8i zfk4CcDI$^#xrZUzG5cIHHeh;FCF3doSm2&QY@$t`udSimuq_c^3kFIjrJQv(85PAX&vW)K<`o=0NDPgj zO3uTG(Hkqbbuo+45`zYiF-eeGp}A#|!>GjB0fj;L`aH~^A!r1Xpq>9Uj@dOt>zxFdjOgRSI47XHoX!)xim^W=JV&RUnP@^}9%k_L z1dN6VK;QE(uz+EC4v`AMJ{JgV!b-*$QFM^;#e|;J#WIXO*FzAD6cZqPNFrgih#U-% z?uzIvxRc?Z1ZkoiK1&H=qo@FyP%8;urRb!=+Yw%=%aC;m!<=EhSa42^UIg0ANhd}= zGsql)`cmB^L=6H}5~33T#o{cJh%Sx7VgMIaOuU7S!4mpV!@w1JUJ*}0t3GDuFkYz1 zCQY8e_#j#P0@1BRzs2Z4F218Y4I41ye;CpMfz5(_MZk`UCsot)I$Mm%ZN$eSJ)GiV zj;aKQED|7kHZtj5gi1KSf{hf!-X`=3hU^AT6rg^EMvdnX`$}Si5dN3Zu?BvEkb4-k zoNEtavIyuF0-X>7;4tvRzYw&ZYyVPIp`#cu9VA3TNJH8M8fsVnkMl%?>o|!5GJ}pg zk&sEL>Ui10#AA4NLwLskoZLEvjT?gt1jtR2A0gG`*~x{t_%INA-` z%;1BRU^xM9J?|#yV1|cq>2Zb<5kG+WC}cnk)fF1yDL(>BMc{vQxvPQKBEv;k8xoIW zoT)+Ti5(ZXHxm(9{)urjVGj%J1)PXrZSWBgDPe36Hm(u^OpO1K5Dfo__4$-nGV&#` z4hWs9qn9}Oo8fr?3&LRf^*D|%ViG6V`v?OACRMOB#4;p_b3G1`??C+$=`1vfBi4kq zLz0+)KqSZuROu_ijxwxptjPR^0istdrurfxTNrv!=0iM|G5ii? ze{xvoOyTH0;D>NxMtl_#Ll|~o_JTmaA_6>w$vRq#(Qblw>bM3OFBAL>;;7DJ_&eN51CgRBtjXF>Yo5JzGLa1TK03vL(MJW6(O@;+z1 zCGvs6Cs6KT5*W80oX^F$fJr;JHc{fofbt>42!y*Mwh90#5Jh4Jn(RlJw;|TX1@Kdk z0VB&m<%IX*sHecMa^4L0jR*m3lZP08OEvaD(gXB8q zwOG8s`CY}AOGXqx0r!oRlTmvSRux=c#=3q$@_64Q4g}zYI#~|XsWV#CC3pp|W z0gD$I2aeMu$#8QFNwZTDcrLnG#YaPM8_4&I0wJD2cpL$34`y80u^4Me`#4i*Xlh?K zaG8#Nl0xXD4UA8wcpSpfLZ6MuW&|7}o3)V^)x~ive1LA_ zXf;QG5ZQ)NqQOC`RU_>VrROx7is6ODFNAji9t)s63^J6HLxfczQE9MOD2AN^$d>_} z)Dm$B7$5+q4ecgaDq;b{8#!<(`RfdQfjM-x!STvGPCIk{3T0nX{uIaiIKZ!Hks)BG zj1pwLVBcZ(G8LC#b_@zYD;Rti;a)DX3D0N5!|0cc{J^=Luo|KRbqZWQ0BoKH;u#iC z8<5gRQ!pz;fVe?lKt5lmu&p59HGu%(1XW?4k9dQCXHi(wkTH7zvtuD94B5pQ2%Dvd z+!5?1r1dxkK3ETdX9L_uP>8wq2@aon2o~Fr@hoM>IK7S7b_B%(#+XVlefNVq0 zAk-}IMb5$LccJJU+%RL{uK}~hDTFg!1O`Hy3v-0nZ$kV{84%3o2p*0R~O zbKw@O7r_TP`C3DVu{aV+{;)JjKmm!$jROcTz00vEDGYZt5#h8B(g1umf zGJfLtDWG2oHbLUR)at@HILdn{IwizOCQd{C)*x?j0d8mr$6z@tG4beVw8SCj76-~! zpk^ZS4Fp`Noe+2u0NwC|O#Z|m$Akfhtw&&jhyjrogfkPcc$7gJA=31~d)KFy6MetQXQbPD) zh+-I)!25Ij9_HbpR~73iKMa~d@O23F5*#d5SBhoI1BIeHQqf09rZu8_ln#C3wE2;K*nV;rl5_vNG~ zobpfZk{3C>q=mJ1V7dc8n z=sBQZAy}@cl#2@l(nKKb(0`!WfVqds#~jE%Fy`VvjJ62@D4|ao+JZvxrT&Op1xmvr zIRyT~J2-!vu*VVk8)OyOAIKfSeiWb^(Jw^bN%^A)f5*slj`KK>%8*;2C15!biUisf zX1%Dm1qKImu-uyv5K8fE2Jm83&&6k$fripaKe%2@6%AhXrcF3|wAk%q>)$=DePW3mS#f&wB+@g;>habt<}mK^9P? zkD<^G#u)%~(@_X|HjPUGrb|Gz70^|OvKRqC;_Dn6oS}} z$T$Yp6@(mz;Ohe{er2>l7>f~s9k&OtQQ*@#_+s%iLb-qw1Yj4#UsGcj;%hL5=f)y* z(SXA#{ya<^79S%K4Hzqq0I=qU??GZKqG>w%0f}3H7bAQo0=J8!5J)l%-Q2*}`bLCM zjfEki8mpolh)*Md;D^YA0$pa106`Fbp2mC}1fhr@<-86uJPZSKyQhHpf+*Ek0I(^7 z`Z7KbJT(&O0wr?kG#42HLO!f@JhkAaC{2!cVX&7a4L}uXFx#r z;;8fgs9b}wfJ9AKEcOWy$uJK54GTLCEsx{+bP*{$Okvb?Yw zwlaJ_7YPJzh=354!x9C`76cJ<2wuYZcw#t13MT~DQW5IM(ItW25vUdOvm9bT5FY$j zhNfXWl#6o=K~w_gQ)2;2#z~>zj|kBpauf(#815|aFM_`VNJfa-V2FhHjDf5$Y7jmv z&^0KDp$K?}Ai7Rtk%90`120Bsq2NHI`~-^)p*@S=;XpiN69oC0qgo+K!QvraBg9TY z1_1gJ8PLO`2wcsjE%3#B;%I3BDV_(Sz6xMob_D za}^8-;_$*C!v8>!F(9LbfN$=BL9UC${{hh65(tQP?EQ5FKEA@=ELhs3)weiVRs7+nU7 z#7JKO9*0eUT^6F`36OKi2))aZ3$e=p(gdZU!{&m(3Xa9mgP1Q2nKh`AgU~}v;CLv3 z5=21|>4%sffh-h|a{LOUHAX)HXfBjdAsLthW^FcRKSPirLJYbJ0Rb%eiUXuhfGJxG zwk`w=6klND87$ru#KPH|C}c_Cun5-DDuh8)#|ktP@ozDP;|+LfFTKJKK`r-iFud;uzOPx6!|bO!X*qv5S9d_I|LI4_j@sT|II*|6Qt50 z`$JaISb!ieDn8-jk`U`Ldi#Ig=QG4w5w2lqBu3vev=6FkA!R4fApy0wkoJM3F(_4} zaB&v%;h~tC@5e;ffv_j45rWLpE+kBZ|1CmTMOe2G#V3T^I#5Q%7y$ZV_$(+Aiy?@s zP^b@dJ0XBhss9fWxQ%1r?0tpAZwxmJa2#TX2#KG)g0~4AjUhP<_*3=*A`7{IX# zbzlxpbU};&K1)Evb6ab!0s2#8(J3gpL4{h(PM}1<)d37(wv@MON@5U@(ywi9=Y( zBP_)2Oh-HwiHSn!u&)Ig|36~|pJJ#GnHbf8=>`eSLYU33P$=h?i8yc<;f0eSS{Ddt zjX)#34CaCZ)Dg5dj0S!OaS&R$2>utW5V4yh2wjiEmjXbh;vI}2Mh0h^EYMC+O&})_ zeo62vp^XpkkHATRoZAd$IYg%n#nIr2AR{qF2zY;Z*7XoHQq+cspdvf8(ilY3=>UBN zTPlFi$a{i35aMNs%QyxR0;2~L`YQNh1WN^N0KtF}p6CB>kh9Lq)KFIZn5DIk%1T})gV7>^d9t=CjZ*w>y;_z(`!KebF zlVgapz(;?I(5%p^28oLxwFsq9_apvv2qPTY3l9je;rI;PN(s9#1bYne9^vo*{|kHp zdE_H2{jEPM{uiC` zHgnS=9BZh)2~rpoP(@m3#tm}1cguQ19aqzHd9^-!Tp`pS8n--uj3~ZGB<^lX8s6G? z%94G&+-8xl{FxL#`gYd^v@y-$Dm2w~^e)%=m@U6_Kj6E2a9n|#_6|E8x3%A2{?z7$ z?Oi8X+Z3BLq9p2fTiZOIntsc%CIUTH=Q`h<{OjZkhyAf{dej%e3a(;E>LqrBwlm- zJ@%IRWM5^?qeIWuAI!Td+q*5(`B9txFuAn9um6SG>`C6J7ko+oR+kq>_xtNw!+Yay zRHlYM|3}ZEC^&o2%@Jlk#pB+MyR2z!c!+BLK2?txncrUOZ*Q*ed(YJ=cKv>LUU;*) z;#_1030xXd_Jblj3zd1LX>r{O{!EqLt8uOwQk+^fu3Ks5lE%^#_q9%FAnAAVwxoLR zpqAZ<{A;;>u&Mu|zf)JaVw3vpzL~1N&7CVHlP`{cuDPeVV`5~fyzHK5k0(y_XKx4= z{5Gy+TT)XmgT2^YsVj2DhDrC;4_k5F?4r$s2Q+MuPbT(@M=f_<$z3XMWb8dMAYWC# ziz!UXY5&4ccVFs$&W;ZnPTHmTF=6{U*h}A)`FT{^s77 zeG4VEU$x%!wr1W?)Af&L?U~4`mqu1T?6)_ASld_uab6hdSMP8V#{lq^vHt%(xae z$Z=Pi`uEGRtvmS>Y_dz;e0k|hXTIFVBGbbf*rBFW*2mLY3tB5$E0ds#eR?BzV_SHa`+|>geo~ z=%}bOF9=aia^4B1EUs_U-Q>SR36N$Sx>XRYqCu>)G_|37R|a7`z}-&S8}VT z`0hby%e9oMi&E?QnGH7CUw^LC0!t>VQ2q_3T)&n!LAjGQ zq+ownrOE3}EzEmZuKa1p$>r9JPDV zk|&>!KI!tm(iq*nf7y-{Ti231`MGdsL0t1qoHpo6DwGn%++9$gv!S>b+~yNz_N}>U z_ji}ZI+L#33nr$wbn|DtS(G{7Ruezy_l*Nu6IzD6aU8wd)mB>`PRr$WO*xg4Ei1Zg zeppjiOWcg`*2~Sg)8u~}6Rpphcmq(leG#APO~)cL@^6FBBEv@SMlm@`UV#XX85VgpG=?SlPSuPh#Kas2bTYjFcKQ_w;#bbYWR)T=bv+&;bY9 zojbcZQ{3pA3VB%%>j$L~OUi3j_tTfTg2Vm2-zIyzrVLwLWfGBR^HOu}?i!t)o4+#C zbw;+sU3e!VvmZPotu%BwyJbRTS|Bo2>ZtI^W|jyFJzvYSH7Vo@B@+~Pd)Oj0PyG8vXXnQ zTB=@7EX{lOS;x*+4tSxhn{ku-`}|D%^-Mi85Z$!3rk;!H>Qc2thno3TrBM@E z_E^;D869V;Q=L!xaZ5Tv0Hpu6y0!VfOPkyJ+8>PJLsbf7;#LJ;jw@_0Gw^;syXOK}}i4^-qK)r;D-;#S_0QPh5DbZGQ}!k$(HBAm7>b@*sQ9oKu;5i=qcvCx5_O) z#8;2CX3RaNY|0Byyo$qELcY1UvTNxSYtEWWcPC}pUQ9S=kL~nfqc~+LUehbHyf|zB z@#ML>e@RrQ^s`wTrITZZTc%fsUk~5?^_cogeBkrfZ)A+JeNt~5D(p#}8;;(}X)Lm{ z1oVBSk0^SX_kOA7dJ&25;!`Q)R>u*gC9Br`-42yfwomR82 zd!XyCIl*qPT1!r3_K5k_vwYy?egjgjUurMQ^iT9ee>r8_FIsoCyyyOspwrso4@3+| z&$4Y%erM@6?b->GbTlV+;SF`8L>Eom^K7E^Eq>wffXMlW9$R+tR+sLQej{^~^!LDY zM~!Nkv3Ho(sc5hR$x{1De|A&P9W~=z+l!{mt*jf8SG_TM@Xgbvmr>+bEp3Bh%O^y~ zyS&+ z^N%G2*7>F_u4^s{zu7e>{mt02dM>r5)eJlE$QQxdCv3inRhE~LIxnw&$EkaMj=0h< z)1O66ml7R=k92&L*05-d|JSow-KtyOP4aGK(wKy%m)kl!+uG+v(JijD&90&==B~rI zduYbl*}PA4Fc8y0hSv_8e%pH?^SYLivdDDtOah&7d(c+D>#?LLIaoF?LSJpqbs5c< zn-i~;clN7y!iKt*S5$34iVB1jV_xS^lxX}llO1$o& zzn{6e^-=!|cRWY)T9>MF%$ZyTNByhR?S=a^GvvaG)cL`f)mOu8(X1)9_FmkUV7HF8 zIA_=*J}&b>obqHuM{KX=_Ns0l-Rk~f9ApGz?nn9ty`xW9{3{KRB*fc0X+PO+zFC|2 z8Z%r%dzFUeUUyu)cmHeNVedBDCMGubHj!P|6)n;Ff-7QH>iPTBq!qVue3!)j$8LN3 zuu7hDyQO)8tz)e(Vq=e6cSwe*B!V`_eio(AGPyoiYfg!g50c6;<;t{l;xSyGbgd|C ziJz`Sp5kpAi0iD9@@Z92b|m&tD`LU}hr<sf{y3aV} zeDMs%YyDXZp2>`PJZ>%PE78%gqzaO?FpHl)C68+z5iBDA5o=>Lpe5o!=(^Qr@$)%sOHXZb{WpS>j)YKWS=J#x= zFT3j(4N(8RF`-{;(adP~ZF}I`Cp`o`ou*{S5Ej!F5aA_fM^<{?`|crYus(%UOHkY-}k3pk4m#nIdT;JGp zTiosJq>{7xfPQr((^~w8VSlo9%x(S7w^>GNH9OL)&TvMgxqMrrT)C3z^o{UiX3yFN z`hA*5_LhvMdDN8B-GyI>xN@+4fYzeE-m~pdHHFrb+|=@15x3!7`0||A&Ix5NstvQ! zyM*6{BFcsZjh%RAk!ngiSC#W{;*oG8ez;=qA9RPColmmpp)ps+JJULXQC$+uMP<_P zz+KY>^VWRctF?*B)uRa)JGW*hSCjJaOj8tU zB-ebb!I2nw#{QwX{=KpFyn4jhl44W$u*tT%`Bv{QDPiwdYIzCNk{`7q)sa!_TIWw$ zZTW378n+DH{l+_b=-o@_Mv>z|?{t!6N3FNpe{Vnr%PFyVhw)yO}&UwY9sg z>-vL%9{nzr1~RizU};!QacYKgoy;F!`j98$XlcTM$V$$5yxDbBPyM{9TT%FBTo?b8 zUF(eEcFDKuJ=U7O+DE@;zB=Oeu=@wE8bu+`hP` zy0%VkU*rkEdTZrW5D_fSk*Z$0g5W5sMo%nw!8Pjbl$bLsV_yjIcC%b9W2TeT?`&2c+V z|EY-PB)Ep z();9=58Bi2L!R$UqBcgGQH7!$-tP>lZ-Y5CUbX~9yhW?G@fuAVZP4Yy-$!#?2`Iy< zeVy(09$UmO73}#=+Ty#)?pSXNb99G$fWyKI3;j7s>iDB@PQXGq@%751X1T2Z~AbMYZw=d&Yvh@>Zr?tEpL@X8BUlMpNyJ>XDsG z@P+8h_fEK0XZQZy-v9mzbdTOJz}$Tq)t{pJ*xHt%2$L_ zI4#{B`|l=uvZ-a%y;Ya8le6~Rv9%AowAtTK9_;dKyKRsGeE9HJucmmL#3xGRp>oU8 z^aBkOVwME)GuInLXTylF553~!c5Oyf=X)>2c!Gh2QTlu7%{P5*S;O0}RFT=P!PBpr z$98L<6XyE#mbtX&g=L-a>i?3acJ!SS?-rKpdzy1TjQ2d7S5k0(95l=v%52(oqi=I` z(Q(OrH~LuB!1T`#M0`JhENbmG?4OpA-EXpl0ef#3JTgIQI@Nnz?u9kBz$ebcopS8` zH&WlNsb5c1PDHevwE8kgOWfdwK_2DdHmfK8W^AN+?9E|MkZ>j6yg{!0eay|0E9v8` zo;MS7Tz4BcM(a7mxyVeGxRq>w-Ya2u*Y~SyZZS35v!m}~dsB4JD)pDn9rcNNqi}ia znlu&fX@j=ublrHHPyTp6dhHga;Mc!S;e(fo> z`y4T);S=QWY(r9g4I_Hp#Eo5VmBwA_S@A|EpTE%aS9F@z=&>Y~%KxJL zwqJq@J5$EIfc$Yw!?XR1egPX`Hm%WWXQJ%L!mxcPOitgYCe{3w(+wZV{N7_Rw`QM= zZ%`8soo!9ah6eNo={hdk;!2K>RV}fB*rTaOxt^NdzQS?$aT{N%WIyM!S?iAu>Ye*< zWprO2mv^^xaaf{Pv$)DVYX>wZo7h@M)0;8;j~jii`<=NYVXaYdZ!+6l8UIXV-2hk8 z;RN(<;C55@m_IIOx0RVM+shsgTKNR$Ayc8PaiVs*(%hqcRlMoWg&y-=Nylm{zwcC0 z6W4qzJ#xDZaM)Q!sY=NpY4b%}m=#?A1;k-cu+lJVrW zSi@?KjMc7OGYxEtdnrSurfRLtItberCKMbrTL!eHK36Cv1uKS8YSGkFNxNuS;o77AaNgYN709wr8@h zC^pD@772DS}nRH+M&sNW1wzqSnn%7)`%J&D(x1VY!8;j#M8PMDu3Zo24wA=IHhQL zOt&RJ^)IG1bJD7R5euI`)Nwnm?n5cOS&$W4^Y}3LnkfIKaAjm^!o!;OM10%y7JjqM z5!to9M5u@JO2@>-eqU$4awR@JLI2cgJLHXf{&wnX!TQ6)3ZzcV-r+xM5s%0DMMbBF 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⋘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 z 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 z