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 }