diff --git a/include/midi/Binasc.h b/include/midi/Binasc.h index 6aa57f09478..686cc407c7c 100644 --- a/include/midi/Binasc.h +++ b/include/midi/Binasc.h @@ -13,11 +13,11 @@ #ifndef _BINASC_H_INCLUDED #define _BINASC_H_INCLUDED -#include +#include #include +#include #include -#include -#include /* needed for MinGW */ + namespace smf { @@ -149,6 +149,8 @@ class Binasc { int getWord (std::string& word, const std::string& input, const std::string& terminators, int index); + static const char *GMinstrument[128]; + }; } // end of namespace smf diff --git a/include/midi/MidiEvent.h b/include/midi/MidiEvent.h index 39f141ee9b1..f8141d17bba 100644 --- a/include/midi/MidiEvent.h +++ b/include/midi/MidiEvent.h @@ -15,8 +15,11 @@ #define _MIDIEVENT_H_INCLUDED #include "MidiMessage.h" + +#include #include + namespace smf { class MidiEvent : public MidiMessage { @@ -63,6 +66,10 @@ class MidiEvent : public MidiMessage { }; + +std::ostream& operator<<(std::ostream& out, MidiEvent& event); + + } // end of namespace smf #endif /* _MIDIEVENT_H_INCLUDED */ diff --git a/include/midi/MidiEventList.h b/include/midi/MidiEventList.h index e3bfb13cf5b..f9b1e8538e2 100644 --- a/include/midi/MidiEventList.h +++ b/include/midi/MidiEventList.h @@ -14,8 +14,10 @@ #define _MIDIEVENTLIST_H_INCLUDED #include "MidiEvent.h" + #include + namespace smf { class MidiEventList { diff --git a/include/midi/MidiFile.h b/include/midi/MidiFile.h index 4a363da5658..4972218f627 100644 --- a/include/midi/MidiFile.h +++ b/include/midi/MidiFile.h @@ -16,19 +16,24 @@ #include "MidiEventList.h" -#include -#include -#include #include +#include +#include +#include -#define TIME_STATE_DELTA 0 -#define TIME_STATE_ABSOLUTE 1 - -#define TRACK_STATE_SPLIT 0 -#define TRACK_STATE_JOINED 1 namespace smf { +enum { + TRACK_STATE_SPLIT = 0, // Tracks are separated into separate vector postions. + TRACK_STATE_JOINED = 1 // Tracks are merged into a single vector position, +}; // like a Type-0 MIDI file, but reversible. + +enum { + TIME_STATE_DELTA = 0, // MidiMessage::ticks are in delta time format (like MIDI file). + TIME_STATE_ABSOLUTE = 1 // MidiMessage::ticks are in absolute time format (0=start time). +}; + class _TickTime { public: int tick; @@ -217,7 +222,7 @@ class MidiFile { MidiEvent* addTempo (int aTrack, int aTick, double aTempo); MidiEvent* addKeySignature (int aTrack, int aTick, - int key, bool mode = 0); + int fifths, bool mode = 0); MidiEvent* addTimeSignature (int aTrack, int aTick, int top, int bottom, int clocksPerClick = 24, diff --git a/include/midi/MidiMessage.h b/include/midi/MidiMessage.h index 49bd88a73e7..b298e15b9a0 100644 --- a/include/midi/MidiMessage.h +++ b/include/midi/MidiMessage.h @@ -14,10 +14,12 @@ #ifndef _MIDIMESSAGE_H_INCLUDED #define _MIDIMESSAGE_H_INCLUDED +#include #include #include #include + namespace smf { typedef unsigned char uchar; @@ -122,6 +124,12 @@ class MidiMessage : public std::vector { void makePatchChange (int channel, int patchnum); void makeTimbre (int channel, int patchnum); void makeController (int channel, int num, int value); + void makePitchBend (int channel, int lsb, int msb); + void makePitchBend (int channel, int value); + void makePitchBendDouble (int channel, double value); + void makePitchbend (int channel, int lsb, int msb) { makePitchBend(channel, lsb, msb); } + void makePitchbend (int channel, int value) { makePitchBend(channel, value); } + void makePitchbendDouble (int channel, double value) { makePitchBendDouble(channel, value); } // helper functions to create various continuous controller messages: void makeSustain (int channel, int value); @@ -199,6 +207,9 @@ class MidiMessage : public std::vector { }; +std::ostream& operator<<(std::ostream& out, MidiMessage& event); + + } // end of namespace smf diff --git a/src/midi/Binasc.cpp b/src/midi/Binasc.cpp index f49aa563201..446dc03b9b0 100644 --- a/src/midi/Binasc.cpp +++ b/src/midi/Binasc.cpp @@ -11,12 +11,37 @@ #include "Binasc.h" +#include #include -#include namespace smf { +const char* Binasc::GMinstrument[128] = { + "acoustic grand piano", "bright acoustic piano", "electric grand piano", "honky-tonk piano", "rhodes piano", "chorused piano", + "harpsichord", "clavinet", "celeste", "glockenspiel", "music box", "vibraphone", + "marimba", "xylophone", "tubular bells", "dulcimer", "hammond organ", "percussive organ", + "rock organ", "church organ", "reed organ", "accordion", "harmonica", "tango accordion", + "nylon guitar", "steel guitar", "jazz guitar", "clean guitar", "muted guitar", "overdriven guitar", + "distortion guitar", "guitar harmonics", "acoustic bass", "fingered electric bass", "picked electric bass", "fretless bass", + "slap bass 1", "slap bass 2", "synth bass 1", "synth bass 2", "violin", "viola", + "cello", "contrabass", "tremolo strings", "pizzcato strings", "orchestral harp", "timpani", + "string ensemble 1", "string ensemble 2", "synth strings 1", "synth strings 1", "choir aahs", "voice oohs", + "synth voices", "orchestra hit", "trumpet", "trombone", "tuba", "muted trumpet", + "frenc horn", "brass section", "syn brass 1", "synth brass 2", "soprano sax", "alto sax", + "tenor sax", "baritone sax", "oboe", "english horn", "bassoon", "clarinet", + "piccolo", "flute", "recorder", "pan flute", "bottle blow", "shakuhachi", + "whistle", "ocarina", "square wave", "saw wave", "calliope lead", "chiffer lead", + "charang lead", "voice lead", "fifths lead", "brass lead", "newage pad", "warm pad", + "polysyn pad", "choir pad", "bowed pad", "metallic pad", "halo pad", "sweep pad", + "rain", "soundtrack", "crystal", "atmosphere", "brightness", "goblins", + "echoes", "sci-fi", "sitar", "banjo", "shamisen", "koto", + "kalimba", "bagpipes", "fiddle", "shanai", "tinkle bell", "agogo", + "steel drums", "woodblock", "taiko drum", "melodoc tom", "synth drum", "reverse cymbal", + "guitar fret noise", "breath noise", "seashore", "bird tweet", "telephone ring", "helicopter", + "applause", "gunshot" +}; + ////////////////////////////// // // Binasc::Binasc -- Constructor: set the default option values. @@ -717,7 +742,9 @@ int Binasc::readMidiEvent(std::ostream& out, std::istream& infile, output << " '" << std::dec << (int)byte1; if (m_commentsQ) { output << "\t"; - comment += "patch-change"; + comment += "patch-change ("; + comment += GMinstrument[byte1 & 0x7f]; + comment += ")"; } break; case 0xD0: // channel pressure: 1 bytes diff --git a/src/midi/MidiEvent.cpp b/src/midi/MidiEvent.cpp index 945e3c532eb..0cf590d8c97 100644 --- a/src/midi/MidiEvent.cpp +++ b/src/midi/MidiEvent.cpp @@ -13,7 +13,7 @@ #include "MidiEvent.h" -#include +#include namespace smf { @@ -278,6 +278,20 @@ double MidiEvent::getDurationInSeconds(void) const { } + +////////////////////////////// +// +// operator<<(MidiMessage) -- Print tick value followed by MIDI bytes for event. +// The tick value will be either relative or absolute depending on the state +// of the MidiFile object containing it. +// + +std::ostream& operator<<(std::ostream& out, MidiEvent& event) { + out << event.tick << '(' << static_cast(event) << ')'; + return out; +} + + } // end namespace smf diff --git a/src/midi/MidiEventList.cpp b/src/midi/MidiEventList.cpp index 52749c5d837..f38fefbc2ca 100644 --- a/src/midi/MidiEventList.cpp +++ b/src/midi/MidiEventList.cpp @@ -10,15 +10,14 @@ // Description: A class which stores a MidiEvents for a MidiFile track. // - #include "MidiEventList.h" -#include #include +#include #include #include +#include -#include namespace smf { @@ -54,8 +53,8 @@ MidiEventList::MidiEventList(const MidiEventList& other) { // MidiEventList::MidiEventList(MidiEventList&& other) { - list = std::move(other.list); - other.list.clear(); + list = std::move(other.list); + other.list.clear(); } @@ -124,12 +123,12 @@ const MidiEvent& MidiEventList::last(void) const { // MidiEvent& MidiEventList::getEvent(int index) { - return *list[index]; + return *list[index]; } const MidiEvent& MidiEventList::getEvent(int index) const { - return *list[index]; + return *list[index]; } @@ -141,10 +140,10 @@ const MidiEvent& MidiEventList::getEvent(int index) const { // void MidiEventList::clear(void) { - for (int i=0; i<(int)list.size(); i++) { - if (list[i] != NULL) { - delete list[i]; - list[i] = NULL; + for (auto& item : list) { + if (item != NULL) { + delete item; + item = NULL; } } list.resize(0); @@ -245,10 +244,10 @@ int MidiEventList::push_back(MidiEvent& event) { void MidiEventList::removeEmpties(void) { int count = 0; - for (int i=0; i<(int)list.size(); i++) { - if (list[i]->empty()) { - delete list[i]; - list[i] = NULL; + for (auto& item : list) { + if (item->empty()) { + delete item; + item = NULL; count++; } } @@ -257,9 +256,9 @@ void MidiEventList::removeEmpties(void) { } std::vector newlist; newlist.reserve(list.size() - count); - for (int i=0; i<(int)list.size(); i++) { - if (list[i]) { - newlist.push_back(list[i]); + for (auto& item : list) { + if (item) { + newlist.push_back(item); } } list.swap(newlist); @@ -292,8 +291,8 @@ int MidiEventList::linkNotePairs(void) { // dimension 3: List of active note-ons or note-offs. std::vector>> noteons; noteons.resize(16); - for (int i=0; i<(int)noteons.size(); i++) { - noteons[i].resize(128); + for (auto& noteon : noteons) { + noteon.resize(128); } // Controller linking: The following General MIDI controller numbers are @@ -433,7 +432,7 @@ void MidiEventList::clearLinks(void) { ////////////////////////////// // -// MidiEventList::clearSequence -- Remove any seqence serial numbers from +// MidiEventList::clearSequence -- Remove any sequence serial numbers from // MidiEvents in the list. This will cause the default ordering by // sortTracks() to be used, in which case the ordering of MidiEvents // occurring at the same tick may switch their ordering. @@ -454,7 +453,7 @@ void MidiEventList::clearSequence(void) { // to preseve the order of MIDI messages in a track when they occur // at the same tick time. Particularly for use with joinTracks() // or sortTracks(). markSequence will be done automatically when -// a MIDI file is read, in case the ordering of events occuring at +// a MIDI file is read, in case the ordering of events occurring at // the same time is important. Use clearSequence() to use the // default sorting behavior of sortTracks() when events occur at the // same time. Returns the next serial number that has not yet been diff --git a/src/midi/MidiFile.cpp b/src/midi/MidiFile.cpp index fa1534d79df..55956c8ce79 100644 --- a/src/midi/MidiFile.cpp +++ b/src/midi/MidiFile.cpp @@ -15,14 +15,14 @@ #include "MidiFile.h" #include "Binasc.h" -#include -#include -#include -#include +#include #include -#include +#include +#include #include -#include +#include +#include +#include namespace smf { @@ -71,21 +71,21 @@ const char* MidiFile::GMinstrument[128] = { ////////////////////////////// // -// MidiFile::MidiFile -- Constuctor. +// MidiFile::MidiFile -- Constructor. // MidiFile::MidiFile(void) { m_events.resize(1); - for (int i=0; i<(int)m_events.size(); i++) { - m_events[i] = new MidiEventList; + for (auto &event : m_events) { + event = new MidiEventList; } } MidiFile::MidiFile(const std::string& filename) { m_events.resize(1); - for (int i=0; i<(int)m_events.size(); i++) { - m_events[i] = new MidiEventList; + for (auto &event : m_events) { + event = new MidiEventList; } read(filename); } @@ -93,8 +93,8 @@ MidiFile::MidiFile(const std::string& filename) { MidiFile::MidiFile(std::istream& input) { m_events.resize(1); - for (int i=0; i<(int)m_events.size(); i++) { - m_events[i] = new MidiEventList; + for (auto &event : m_events) { + event = new MidiEventList; } read(input); } @@ -507,7 +507,7 @@ bool MidiFile::readSmf(std::istream& input) { m_events[i]->clear(); // Read MIDI events in the track, which are pairs of VLV values - // and then the bytes for the MIDI message. Running status messags + // and then the bytes for the MIDI message. Running status messages // will be filled in with their implicit command byte. // The timestamps are converted from delta ticks to absolute ticks, // with the absticks variable accumulating the VLV tick values. @@ -597,7 +597,7 @@ bool MidiFile::write(std::ostream& out) { shortdata = static_cast(getNumTracks()); writeBigEndianUShort(out, shortdata); - // 5. write out the number of ticks per quarternote. (avoiding SMTPE for now) + // 5. write out the number of ticks per quarternote. (avoiding SMPTE for now) shortdata = static_cast(getTicksPerQuarterNote()); writeBigEndianUShort(out, shortdata); @@ -774,7 +774,7 @@ bool MidiFile::writeHex(std::ostream& out, int width) { int wordcount = 1; int linewidth = width >= 0 ? width : 25; for (int i=0; iremoveEmpties(); + for (auto &event : m_events) { + event->removeEmpties(); } } @@ -954,7 +954,7 @@ void MidiFile::removeEmpties(void) { // a track when they occur at the same tick time. Particularly // for use with joinTracks() or sortTracks(). markSequence will // be done automatically when a MIDI file is read, in case the -// ordering of m_events occuring at the same time is important. +// ordering of m_events occurring at the same time is important. // Use clearSequence() to use the default sorting behavior of // sortTracks(). // @@ -982,7 +982,7 @@ void MidiFile::markSequence(int track, int sequence) { ////////////////////////////// // -// MidiFile::clearSequence -- Remove any seqence serial numbers from +// MidiFile::clearSequence -- Remove any sequence serial numbers from // MidiEvents in the MidiFile. This will cause the default ordering by // sortTracks() to be used, in which case the ordering of MidiEvents // occurring at the same tick may switch their ordering. @@ -1311,7 +1311,7 @@ void MidiFile::deltaTicks(void) { // absolute time, which means that the time field // in the MidiEvent struct represents the exact tick // time to play the event rather than the time since -// the last event to wait untill playing the current +// the last event to wait until playing the current // event. // @@ -1422,7 +1422,7 @@ int MidiFile::getFileDurationInTicks(void) { // in units of quarter notes. If the MidiFile is in delta tick mode, // then temporarily got into absolute tick mode to do the calculations. // Note that this is expensive, so you should normally call this function -// while in aboslute tick (default) mode. +// while in absolute tick (default) mode. // double MidiFile::getFileDurationInQuarters(void) { @@ -1434,7 +1434,7 @@ double MidiFile::getFileDurationInQuarters(void) { ////////////////////////////// // // MidiFile::getFileDurationInSeconds -- returns the duration of the -// logest track in the file. The tracks must be sorted before +// longest track in the file. The tracks must be sorted before // calling this function, since this function assumes that the // last MidiEvent in the track has the highest timestamp. // The file state can be in delta ticks since this function @@ -1906,7 +1906,7 @@ MidiEvent* MidiFile::addTimeSignature(int aTrack, int aTick, int top, int bottom // // MidiFile::addCompoundTimeSignature -- Add a time signature meta message // (meta #0x58), where the clocksPerClick parameter is set to three -// eighth notes for compount meters such as 6/8 which represents +// eighth notes for compound meters such as 6/8 which represents // two beats per measure. // // Default values: @@ -2347,7 +2347,7 @@ int MidiFile::getTicksPerQuarterNote(void) const { // setting for 25 frames a second with 40 subframes // which means one tick per millisecond. When SMPTE is // being used, there is no real concept of the quarter note, - // so presume 60 bpm as a simiplification here. + // so presume 60 bpm as a simplification here. // return 1000; } return m_ticksPerQuarterNote; @@ -2696,7 +2696,7 @@ double MidiFile::linearSecondInterpolationAtTick(int ticktime) { // MidiFile::buildTimeMap -- build an index of the absolute tick values // found in a MIDI file, and their corresponding time values in // seconds, taking into consideration tempo change messages. If no -// tempo messages are given (or untill they are given, then the +// tempo messages are given (or until they are given, then the // tempo is set to 120 beats per minute). If SMPTE time code is // used, then ticks are actually time values. So don't build // a time map for SMPTE ticks, and just calculate the time in @@ -2956,15 +2956,17 @@ int MidiFile::extractMidiData(std::istream& input, std::vector& array, ulong MidiFile::readVLValue(std::istream& input) { uchar b[5] = {0}; - for (int i=0; i<5; i++) { - b[i] = readByte(input); - if (!status()) { return m_rwstatus; } - if (b[i] < 0x80) { - break; - } - } + for (uchar &item : b) { + item = readByte(input); + if (!status()) { + return m_rwstatus; + } + if (item < 0x80) { + break; + } + } - return unpackVLV(b[0], b[1], b[2], b[3], b[4]); + return unpackVLV(b[0], b[1], b[2], b[3], b[4]); } @@ -3005,7 +3007,7 @@ ulong MidiFile::unpackVLV(uchar a, uchar b, uchar c, uchar d, uchar e) { // // MidiFile::writeVLValue -- write a number to the midifile // as a variable length value which segments a file into 7-bit -// values and adds a contination bit to each. Maximum size of input +// values and adds a continuation bit to each. Maximum size of input // aValue is 0x0FFFffff. // @@ -3392,7 +3394,7 @@ std::string MidiFile::base64Encode(const std::string& input) { output.reserve(((input.size()/3) + (input.size() % 3 > 0)) * 4); int vala = 0; int valb = -6; - for (unsigned char c : input) { + for (uchar c : input) { vala = (vala << 8) + c; valb += 8; while (valb >=0) { @@ -3423,7 +3425,7 @@ std::string MidiFile::base64Decode(const std::string& input) { std::string output; int vala = 0; int valb = -8; - for (unsigned char c : input) { + for (uchar c : input) { if (c == '=') { break; } else if (MidiFile::decodeLookup[c] == -1) { diff --git a/src/midi/MidiMessage.cpp b/src/midi/MidiMessage.cpp index 7b9eb33c289..5b19a36eb8a 100644 --- a/src/midi/MidiMessage.cpp +++ b/src/midi/MidiMessage.cpp @@ -14,10 +14,10 @@ #include "MidiMessage.h" #include +#include +#include #include #include -#include - namespace smf { @@ -315,11 +315,13 @@ bool MidiMessage::isMetaMessage(void) const { // bool MidiMessage::isNoteOff(void) const { - if (size() != 3) { + const MidiMessage& message = *this; + const vector& chars = message; + if (message.size() != 3) { return false; - } else if (((*this)[0] & 0xf0) == 0x80) { + } else if ((chars[0] & 0xf0) == 0x80) { return true; - } else if ((((*this)[0] & 0xf0) == 0x90) && ((*this)[2] == 0)) { + } else if (((chars[0] & 0xf0) == 0x90) && (chars[2] == 0x00)) { return true; } else { return false; @@ -676,7 +678,7 @@ bool MidiMessage::isInstrumentName(void) const { ////////////////////////////// // // MidiMessage::isLyricText -- Returns true if message is a meta message -// describing some lyric text (for karakoke MIDI files) +// describing some lyric text (for karaoke MIDI files) // (meta message type 0x05). // @@ -857,7 +859,7 @@ int MidiMessage::getKeyNumber(void) const { ////////////////////////////// // -// MidiMessage::getVelocity -- Return the key veolocity. If the message +// MidiMessage::getVelocity -- Return the key velocity. If the message // is not a note-on or a note-off, then return -1. If the value is // out of the range 0-127, then chop off the high-bits. // @@ -961,7 +963,7 @@ void MidiMessage::setP1(int value) { ////////////////////////////// // -// MidiMessage::setP2 -- Set the second paramter value. +// MidiMessage::setP2 -- Set the second paramater value. // If the MidiMessage is too short, add extra spaces // to allow for P2. The command byte and/or the P1 value // will be undefined if extra space needs to be added and @@ -980,7 +982,7 @@ void MidiMessage::setP2(int value) { ////////////////////////////// // -// MidiMessage::setP3 -- Set the third paramter value. +// MidiMessage::setP3 -- Set the third paramater value. // If the MidiMessage is too short, add extra spaces // to allow for P3. The command byte and/or the P1/P2 values // will be undefined if extra space needs to be added and @@ -1364,7 +1366,7 @@ void MidiMessage::setSpelling(int base7, int accidental) { // pc + octave * 7 // where pc is the numbers 0 through 6 representing the pitch classes // C through B, the octave is MIDI octave (not the scientific pitch -// octave which is one less than the MIDI ocatave, such as C4 = middle C). +// octave which is one less than the MIDI octave, such as C4 = middle C). // The second number is the accidental for the base-7 pitch. // @@ -1544,8 +1546,8 @@ void MidiMessage::setMetaContent(const std::string& content) { // add the size of the meta message data (VLV) int dsize = (int)content.size(); std::vector vlv = intToVlv(dsize); - for (int i=0; i<(int)vlv.size(); i++) { - this->push_back(vlv[i]); + for (uchar item : vlv) { + this->push_back(item); } std::copy(content.begin(), content.end(), std::back_inserter(*this)); } @@ -1764,6 +1766,61 @@ void MidiMessage::makeController(int channel, int num, int value) { +///////////////////////////// +// +// MidiMessage::makePitchBend -- Create a pitch-bend message. lsb is +// least-significant 7 bits of the 14-bit range, and msb is the +// most-significant 7 bits of the 14-bit range. The range depth +// is determined by a setting in the synthesizer. Typically it is +// +/- two semitones by default. See MidiFile::setPitchBendRange() +// to change the default (or change to the typical default). +// + +void MidiMessage::makePitchBend(int channel, int lsb, int msb) { + resize(0); + push_back(0xe0 | (0x0e & channel)); + push_back(0x7f & lsb); + push_back(0x7f & msb); +} + +// +// value is a 14-bit number, where 0 is the lowest pitch of the range, and +// 2^15-1 is the highest pitch of the range. +// + +void MidiMessage::makePitchBend(int channel, int value) { + resize(0); + int lsb = value & 0x7f; + int msb = (value >> 7) & 0x7f; + push_back(0xe0 | (0x7f & channel)); + push_back(lsb); + push_back(msb); +} + +// +// Input value is a number between -1.0 and +1.0. +// + +void MidiMessage::makePitchBendDouble(int channel, double value) { + // value is in the range from -1 for minimum and 2^18 - 1 for the maximum + resize(0); + double dvalue = (value + 1.0) * (pow(2.0, 15.0)); + if (dvalue < 0.0) { + dvalue = 0.0; + } + if (dvalue > pow(2.0, 15.0) - 1.0) { + dvalue = pow(2.0, 15.0) - 1.0; + } + ulong uivalue = (ulong)dvalue; + uchar lsb = uivalue & 0x7f; + uchar msb = (uivalue >> 7) & 0x7f; + push_back(0xe0 | (0x7f & channel)); + push_back(lsb); + push_back(msb); +} + + + ///////////////////////////// // // MidiMessage::makeSustain -- Create a sustain pedal message. @@ -1999,8 +2056,8 @@ void MidiMessage::makeSysExMessage(const std::vector& data) { int msize = endindex - startindex + 2; std::vector vlv = intToVlv(msize); - for (int i=0; i<(int)vlv.size(); i++) { - this->push_back(vlv[i]); + for (uchar item : vlv) { + this->push_back(item); } for (int i=startindex; i<=endindex; i++) { this->push_back(data.at(i)); @@ -2095,18 +2152,18 @@ void MidiMessage::makeMts2_KeyTuningsBySemitone(std::vector vlv = intToVlv((int)mapping.size()); - for (int i=0; i<(int)vlv.size(); i++) { - data.push_back(vlv[i]); + for (uchar item : vlv) { + data.push_back(item); } - for (int i=0; i<(int)mapping.size(); i++) { - int keynum = mapping[i].first; + for (auto &item : mapping) { + int keynum = item.first; if (keynum < 0) { keynum = 0; } else if (keynum > 127) { keynum = 127; } data.push_back((uchar)keynum); - double semitones = mapping[i].second; + double semitones = item.second; int sint = (int)semitones; if (sint < 0) { sint = 0; @@ -2120,8 +2177,8 @@ void MidiMessage::makeMts2_KeyTuningsBySemitone(std::vector> 7) & 0x7f; data.push_back(msb); data.push_back(lsb); - } - this->makeSysExMessage(data); + } + this->makeSysExMessage(data); } @@ -2204,8 +2261,8 @@ void MidiMessage::makeTemperamentBad(double maxDeviationCents, int referencePitc maxDeviationCents = 100.0; } std::vector temperament(12); - for (int i=0; i<(int)temperament.size(); i++) { - temperament[i] = ((rand() / (double)RAND_MAX) * 2.0 - 1.0) * maxDeviationCents; + for (double &item : temperament) { + item = ((rand() / (double)RAND_MAX) * 2.0 - 1.0) * maxDeviationCents; } this->makeMts9_TemperamentByCentsDeviationFromET(temperament, referencePitchClass, channelMask); } @@ -2294,6 +2351,30 @@ void MidiMessage::makeTemperamentMeantoneCommaHalf(int referencePitchClass, int } + +////////////////////////////// +// +// operator<<(MidiMessage) -- Print MIDI messages as text. 0x80 and above +// are printed as hex, below as dec (will look strange for meta messages +// and system exclusives which could be dealt with later). +// + +std::ostream& operator<<(std::ostream& out, MidiMessage& message) { + for (int i=0; i<(int)message.size(); i++) { + if (message[i] >= 0x80) { + out << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int)message[i]; + out << std::dec << std::setw(0) << std::setfill(' '); + } else { + out << (int)message[i]; + } + if (i<(int)message.size() - 1) { + out << ' '; + } + } + return out; +} + + } // end namespace smf