|
From: Lasse Kärkkäi. <tr...@us...> - 2011-02-24 16:43:07
|
Author: Lasse Kärkkäinen <tronic+ndrm at trn.iki.fi> Date: Thu Feb 24 17:34:41 2011 +0100 Some MIDI writer support --- midifile.cc | 14 +++++++------- midifile.hh | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/midifile.cc b/midifile.cc index d359dc5..b4f7102 100644 --- a/midifile.cc +++ b/midifile.cc @@ -33,16 +33,16 @@ bool Reader::nextTrack() { void Reader::parseRiff(char const* name) { if (!std::equal(name, name + 4, m_pos)) throw std::runtime_error("MIDI header " + std::string(name) + " not found, instead found " + std::string(m_pos, m_pos + 4)); m_pos += 4; - unsigned size = read<uint32_t>(); + unsigned size = read<4>(); if (m_fileEnd - m_pos < size) throw std::runtime_error("Unexpected end of file within MIDI header " + std::string(name)); m_riffEnd = m_pos + size; } void Reader::parseMThd() { parseRiff("MThd"); - unsigned fmt = read<uint16_t>(); - m_tracks = read<uint16_t>(); - m_division = read<uint16_t>(); + unsigned fmt = read<2>(); + m_tracks = read<2>(); + m_division = read<2>(); if (fmt == 2) throw std::runtime_error("MIDI format 2 not supported."); if (fmt == 0 && m_tracks == 1) return; // Old single track format if (fmt == 1 && m_tracks > 1) return; // New format (timing info on first track) @@ -61,7 +61,7 @@ bool Reader::parseEvent(Event& ev) { // Event header { ev.timecode = read_varlen(); - unsigned event = read<uint8_t>(); + unsigned event = read<1>(); if (event & 0x80) { if (event < 0xF0) m_runningStatus = event; // Stored for regular (0x00..0xEF) else if (event < 0xF8) m_runningStatus = 0; // Cleared for System Common Category (0xF0..0xF7) @@ -74,7 +74,7 @@ bool Reader::parseEvent(Event& ev) { ev.type = static_cast<Event::Type>(event & 0xF0); ev.channel = event & 0x0F; } - if (ev.type != Event::SPECIAL || ev.channel >= 8) ev.arg1 = read<uint8_t>(); // Everything except System Common takes one argument + if (ev.type != Event::SPECIAL || ev.channel >= 8) ev.arg1 = read<1>(); // Everything except System Common takes one argument unsigned tmp; switch (ev.type) { case Event::NOTE_ON: @@ -82,7 +82,7 @@ bool Reader::parseEvent(Event& ev) { case Event::NOTE_AFTERTOUCH: case Event::CONTROLLER: case Event::PITCH_BEND: - ev.arg2 = read<uint8_t>(); + ev.arg2 = read<1>(); break; case Event::PROGRAM_CHANGE: case Event::CHANNEL_AFTERTOUCH: diff --git a/midifile.hh b/midifile.hh index 3d90431..6dd7718 100644 --- a/midifile.hh +++ b/midifile.hh @@ -66,9 +66,9 @@ namespace mid { void parseMThd(); void parseMTrk(); void parseRiff(char const* name); - template <typename T> T read() { - T value = 0; - for (int i = sizeof(T) - 1; i >= 0; --i) value |= *m_pos++ << (8 * i); + template <unsigned N> unsigned read() { + unsigned value = 0; + for (unsigned i = N - 1; i < N; --i) value |= *m_pos++ << (8 * i); return value; } @@ -91,6 +91,44 @@ namespace mid { unsigned m_division; unsigned m_runningStatus; }; - + + class Writer { + public: + private: + void writeMThd(unsigned tracks, unsigned division) { + beginRiff("MThd"); + write<2>(1); // fmt 1 (multitrack) + write<2>(tracks); + write<2>(division); + endRiff(); + } + void writeMTrk() { + beginRiff("MTrk"); + } + void beginRiff(char const* name) { + m_riffBegin = m_data.size(); + m_data.resize(m_riffBegin + 8); // Add space for header + std::copy(name, name + 4, m_data.begin() + m_riffBegin); // Set RIFF name + } + void endRiff() { + unsigned size = m_data.size() - 8 - m_riffBegin; + m_data[m_riffBegin + 4] = size >> 24; + m_data[m_riffBegin + 5] = size >> 16; + m_data[m_riffBegin + 6] = size >> 8; + m_data[m_riffBegin + 7] = size; + } + template <unsigned N> void write(unsigned value) { + for (unsigned i = N - 1; i < N; --i) m_data.push_back(value >> (8 * i)); + } + void write_varlen(unsigned value) { + if (value >= 0x10000000U) throw std::logic_error("Value cannot be MIDI varlen encoded"); + if (value >= 0x200000U) m_data.push_back(0x80 | (value >> 21)); + if (value >= 0x4000U) m_data.push_back(0x80 | (value >> 14)); + if (value >= 0x80U) m_data.push_back(0x80 | (value >> 7)); + m_data.push_back(value & 0x7F); + } + std::vector<value_type> m_data; + unsigned m_riffBegin; + }; } |