gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 70fec21a8e418a59563ac9b0fe7cbd8b4e2d87ef
parent 82ad36aa39114ecf69b00ab336646883d460a49e
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sun,  4 Dec 2022 02:33:19 +0100

implement SysEx to midi converter

Diffstat:
Msource/synthLib/CMakeLists.txt | 1+
Asource/synthLib/sysexToMidi.cpp | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/synthLib/sysexToMidi.h | 21+++++++++++++++++++++
3 files changed, 131 insertions(+), 0 deletions(-)

diff --git a/source/synthLib/CMakeLists.txt b/source/synthLib/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES plugin.cpp plugin.h resampler.cpp resampler.h resamplerInOut.cpp resamplerInOut.h + sysexToMidi.cpp sysexToMidi.h wavWriter.cpp wavWriter.h ) diff --git a/source/synthLib/sysexToMidi.cpp b/source/synthLib/sysexToMidi.cpp @@ -0,0 +1,109 @@ +#include "sysexToMidi.h" + +#include <fstream> + +namespace synthLib +{ + constexpr uint16_t g_ppq = 96; + constexpr uint16_t g_beatsBetweenMessages = 1; + + bool SysexToMidi::write(const char* _filename, const std::vector<std::vector<uint8_t>>& _messages) + { + std::ofstream f(_filename, std::ios::binary); + if(!f.is_open()) + return false; + try + { + write(f, _messages); + } + catch (...) + { + return false; + } + return true; + } + + void SysexToMidi::write(std::ostream& _dst, const std::vector<std::vector<uint8_t>>& _messages) + { + write(_dst, "MThd"); // header + writeUInt32(_dst, 6); // chunk length = 6 + writeUInt16(_dst, 0); // format = single multi-channel track + writeUInt16(_dst, 1); // number of tracks = 1 + writeUInt16(_dst, 96); // ticks per quarter note = 96 + + // track chunk + write(_dst, "MTrk"); + const auto trackChunkBegin = _dst.tellp(); + writeUInt32(_dst, 0); // will be replaced later + + for (const auto& message : _messages) + { + writeVarLen(_dst, g_ppq * g_beatsBetweenMessages); // delta time + writeUInt8(_dst, message.front()); // f0 comes first... + writeVarLen(_dst, static_cast<uint32_t>(message.size() - 1)); // ...then the length + _dst.write(reinterpret_cast<const char*>(&message[1]), static_cast<std::streamsize>(message.size() - 1)); + } + const auto newPos = _dst.tellp(); + const auto trackChunkLength = newPos - trackChunkBegin; + + writeBuf(_dst, {0xff,0x2f,0x00}); // end of track + + _dst.seekp(trackChunkBegin); + writeUInt32(_dst, static_cast<uint32_t>(trackChunkLength)); + } + + void SysexToMidi::writeBuf(std::ostream& _dst, const std::vector<uint8_t>& _data) + { + _dst.write(reinterpret_cast<const char*>(&_data[0]), static_cast<std::streamsize>(_data.size())); + } + + void SysexToMidi::writeUInt8(std::ostream& _dst, uint8_t _data) + { + _dst.write(reinterpret_cast<const char*>(&_data), 1); + } + + void SysexToMidi::writeUInt32(std::ostream& _dst, const uint32_t& _data) + { + writeBuf(_dst, + { + static_cast<unsigned char>((_data >> 24) & 0xff), + static_cast<unsigned char>((_data >> 16) & 0xff), + static_cast<unsigned char>((_data >> 8) & 0xff), + static_cast<unsigned char>(_data & 0xff) + }); + } + + void SysexToMidi::writeUInt16(std::ostream& _dst, const uint16_t& _data) + { + writeBuf(_dst, + { + static_cast<unsigned char>((_data >> 8) & 0xff), + static_cast<unsigned char>(_data & 0xff) + }); + } + + void SysexToMidi::write(std::ostream& _dst, const std::string& _data) + { + _dst << _data; + } + + void SysexToMidi::writeVarLen(std::ostream& _dst, uint32_t _len) + { + auto buffer = _len & 0x7f; + + while ( (_len >>= 7) ) + { + buffer <<= 8; + buffer |= ((_len & 0x7f) | 0x80); + } + + while (true) + { + const auto byte = static_cast<uint8_t>(buffer & 0xff); + writeUInt8(_dst, byte); + if ((byte & 0x80) == 0) + break; + buffer >>= 8; + } + } +} diff --git a/source/synthLib/sysexToMidi.h b/source/synthLib/sysexToMidi.h @@ -0,0 +1,21 @@ +#pragma once + +#include <ostream> +#include <vector> + +namespace synthLib +{ + class SysexToMidi + { + public: + static bool write(const char* _filename, const std::vector<std::vector<uint8_t>>& _messages); + static void write(std::ostream& _dst, const std::vector<std::vector<uint8_t>>& _messages); + private: + static void writeBuf(std::ostream& _dst, const std::vector<uint8_t>& _data); + static void writeUInt8(std::ostream& _dst, uint8_t _data); + static void writeUInt32(std::ostream& _dst, const uint32_t& _data); + static void writeUInt16(std::ostream& _dst, const uint16_t& _data); + static void write(std::ostream& _dst, const std::string& _data); + static void writeVarLen(std::ostream& _dst, uint32_t _len); + }; +}