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

sysexToMidi.cpp (2910B)


      1 #include "sysexToMidi.h"
      2 
      3 #include <fstream>
      4 
      5 namespace synthLib
      6 {
      7 	constexpr uint16_t g_ppq = 96;
      8 	constexpr uint16_t g_beatsBetweenMessages = 1;
      9 
     10 	bool SysexToMidi::write(const char* _filename, const std::vector<std::vector<uint8_t>>& _messages)
     11 	{
     12 		std::ofstream f(_filename, std::ios::binary);
     13 		if(!f.is_open())
     14 			return false;
     15 		try
     16 		{
     17 			write(f, _messages);
     18 		}
     19 		catch (...)
     20 		{
     21 			return false;
     22 		}
     23 		return true;
     24 	}
     25 
     26 	void SysexToMidi::write(std::ostream& _dst, const std::vector<std::vector<uint8_t>>& _messages)
     27 	{
     28 		write(_dst, "MThd");	// header
     29 		writeUInt32(_dst, 6);	// chunk length = 6
     30 		writeUInt16(_dst, 0);	// format = single multi-channel track
     31 		writeUInt16(_dst, 1);	// number of tracks = 1
     32 		writeUInt16(_dst, 96);	// ticks per quarter note = 96
     33 
     34 		// track chunk
     35 		write(_dst, "MTrk");
     36 		const auto trackChunkBegin = _dst.tellp();
     37 		writeUInt32(_dst, 0);		// will be replaced later
     38 
     39 		for (const auto& message : _messages)
     40 		{
     41 			writeVarLen(_dst, g_ppq * g_beatsBetweenMessages);				// delta time
     42 			writeUInt8(_dst, message.front());								// f0 comes first...
     43 			writeVarLen(_dst, static_cast<uint32_t>(message.size() - 1));		// ...then the length
     44 			_dst.write(reinterpret_cast<const char*>(&message[1]), static_cast<std::streamsize>(message.size() - 1));
     45 		}
     46 		const auto newPos = _dst.tellp();
     47 		const auto trackChunkLength = newPos - trackChunkBegin - 4;	// exclude the chunk length
     48 
     49 		writeBuf(_dst, {0xff,0x2f,0x00});	// end of track
     50 
     51 		const auto end = _dst.tellp();
     52 		_dst.seekp(trackChunkBegin);
     53 		writeUInt32(_dst, static_cast<uint32_t>(trackChunkLength));
     54 		_dst.seekp(end);
     55 	}
     56 
     57 	void SysexToMidi::writeBuf(std::ostream& _dst, const std::vector<uint8_t>& _data)
     58 	{
     59 		_dst.write(reinterpret_cast<const char*>(_data.data()), static_cast<std::streamsize>(_data.size()));
     60 	}
     61 
     62 	void SysexToMidi::writeUInt8(std::ostream& _dst, uint8_t _data)
     63 	{
     64 		_dst.write(reinterpret_cast<const char*>(&_data), 1);
     65 	}
     66 
     67 	void SysexToMidi::writeUInt32(std::ostream& _dst, const uint32_t& _data)
     68 	{
     69 		writeBuf(_dst, 
     70 		{
     71 			static_cast<unsigned char>((_data >> 24) & 0xff),
     72 			static_cast<unsigned char>((_data >> 16) & 0xff),
     73 			static_cast<unsigned char>((_data >> 8) & 0xff),
     74 			static_cast<unsigned char>(_data & 0xff)
     75 		});
     76 	}
     77 
     78 	void SysexToMidi::writeUInt16(std::ostream& _dst, const uint16_t& _data)
     79 	{
     80 		writeBuf(_dst,
     81 		{
     82 			static_cast<unsigned char>((_data >> 8) & 0xff),
     83 			static_cast<unsigned char>(_data & 0xff)
     84 		});
     85 	}
     86 
     87 	void SysexToMidi::write(std::ostream& _dst, const std::string& _data)
     88 	{
     89 		_dst << _data;
     90 	}
     91 
     92 	void SysexToMidi::writeVarLen(std::ostream& _dst, uint32_t _len)
     93 	{
     94 		auto buffer = _len & 0x7f;
     95 
     96 		while ( (_len >>= 7) )
     97 		{
     98 			buffer <<= 8;
     99 			buffer |= ((_len & 0x7f) | 0x80);
    100 		}
    101 
    102 		while (true)
    103 		{
    104 			const auto byte = static_cast<uint8_t>(buffer & 0xff);
    105 			writeUInt8(_dst, byte);
    106 			if ((byte & 0x80) == 0)
    107 				break;
    108 			buffer >>= 8;
    109 		}
    110 	}
    111 }