Midifile View on GitHub

Reverse notes.


Reverse the order of notes in a MIDI file. The following example program will reverse the order of pitches in a MIDI file, while at the same time preserve the original rhythms. First note-ons and note-offs are linked by calling the MidiFile::linkNotePairs function. Then a list of note-ons are extracted by iterating through each event in each track. And finally the extracted note list is used to switch the key numbers in reverse order in the list. If the MIDI file is monophonic (single melody), then this program will reverse the order of notes in the music, but keep the rhythms in theor original locations. If the music is polyphonic, the sonorities will likely change. See the mirror tutorial for how to reverse both pitch and durations.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "MidiFile.h"
#include "Options.h"

using namespace std;

void swapNotes(vector<MidiEvent*>& notes, int index1, int index2);

int main(int argc, char** argv) {
   Options options;
   options.process(argc, argv);
   if (options.getArgCount() != 2) {
      cerr << "two MIDI filenames are required.\n";
      exit(1);
   }
   MidiFile midifile;
   midifile.read(options.getArg(1));
   if (!midifile.status()) {
      cerr << "Error reading MIDI file " << options.getArg(1) << endl;
      exit(1);
   }
   midifile.linkNotePairs();
   vector<MidiEvent*> notes;
   notes.reserve(123456);
   for (int track=0; track<midifile.size(); track++) {
      for (int event=0; event<midifile[track].size(); event++) {
         if (midifile[track][event].isNoteOn()) {
            if (midifile[track][event].isLinked()) {
               notes.push_back(&midifile[track][event]);
            }
         }
      }
   }
   int count = notes.size();
   for (int i=0; i<count/2; i++) {
      swapNotes(notes, i, count-1-i);
   }
   midifile.write(options.getArg(2));
   return 0;
}

void swapNotes(vector<MidiEvent*>& notes, int index1, int index2) {
   MidiEvent* noteon1  = notes[index1];
   MidiEvent* noteon2  = notes[index2];
   MidiEvent* noteoff1 = notes[index1]->getLinkedEvent();
   MidiEvent* noteoff2 = notes[index2]->getLinkedEvent();
   if (noteon1  == NULL) { return; }
   if (noteon2  == NULL) { return; }
   if (noteoff1 == NULL) { return; }
   if (noteoff2 == NULL) { return; }
   int pitch1 = noteon1->getKeyNumber();
   int pitch2 = noteon2->getKeyNumber();
   if (pitch1 == pitch2) { return; }
   if (pitch1 < 0) { return; }
   if (pitch2 < 0) { return; }
   noteon1->setKeyNumber(pitch2);
   noteoff1->setKeyNumber(pitch2);
   noteon2->setKeyNumber(pitch1);
   noteoff2->setKeyNumber(pitch1);
}
Library functions used in this example:
  • MidiEvent::getLinkedEvent
  • MidiEvent::isLinked
  • MidiEventList::operator[]
  • MidiFile::getEventCount
  • MidiFile::getTrackCount
  • MidiFile::linkNotePairs
  • MidiFile::operator[]
  • MidiFile::read
  • MidiFile::size
  • MidiFile::status
  • MidiFile::write
  • MidiMessage::getKeyNumber
  • MidiMessage::isNoteOn
  • MidiMessage::setKeyNumber
  • Options::getArg
  • Options::getArgCount
  • Options::process