svcore  1.9
MIDIFileWriter.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     
00008     This program is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU General Public License as
00010     published by the Free Software Foundation; either version 2 of the
00011     License, or (at your option) any later version.  See the file
00012     COPYING included with this distribution for more information.
00013 */
00014 
00015 
00016 /*
00017    This is a modified version of a source file from the 
00018    Rosegarden MIDI and audio sequencer and notation editor.
00019    This file copyright 2000-2007 Richard Bown and Chris Cannam
00020    and copyright 2007 QMUL.
00021 */
00022 
00023 #include "MIDIFileWriter.h"
00024 
00025 #include "data/midi/MIDIEvent.h"
00026 #include "model/NoteData.h"
00027 
00028 #include "base/Pitch.h"
00029 
00030 #include <algorithm>
00031 #include <fstream>
00032 
00033 using std::ofstream;
00034 using std::string;
00035 using std::ios;
00036 
00037 using namespace MIDIConstants;
00038 
00039 MIDIFileWriter::MIDIFileWriter(QString path, const NoteExportable *exportable,
00040                                int sampleRate, float tempo) :
00041     m_path(path),
00042     m_exportable(exportable),
00043     m_sampleRate(sampleRate),
00044     m_tempo(tempo),
00045     m_midiFile(0)
00046 {
00047     if (!convert()) {
00048         m_error = "Conversion from model to internal MIDI format failed";
00049     }
00050 }
00051 
00052 MIDIFileWriter::~MIDIFileWriter()
00053 {
00054     for (MIDIComposition::iterator i = m_midiComposition.begin();
00055          i != m_midiComposition.end(); ++i) {
00056         
00057         for (MIDITrack::iterator j = i->second.begin();
00058              j != i->second.end(); ++j) {
00059             delete *j;
00060         }
00061 
00062         i->second.clear();
00063     }
00064 
00065     m_midiComposition.clear();
00066 }
00067 
00068 bool
00069 MIDIFileWriter::isOK() const
00070 {
00071     return m_error == "";
00072 }
00073 
00074 QString
00075 MIDIFileWriter::getError() const
00076 {
00077     return m_error;
00078 }
00079 
00080 void
00081 MIDIFileWriter::write()
00082 {
00083     writeComposition();
00084 }
00085 
00086 string
00087 MIDIFileWriter::intToMIDIBytes(int number) const
00088 {
00089     MIDIByte upper;
00090     MIDIByte lower;
00091 
00092     upper = (number & 0xFF00) >> 8;
00093     lower = (number & 0x00FF);
00094 
00095     string rv;
00096     rv += upper;
00097     rv += lower;
00098     return rv;
00099 }
00100 
00101 string
00102 MIDIFileWriter::longToMIDIBytes(unsigned long number) const
00103 {
00104     MIDIByte upper1;
00105     MIDIByte lower1;
00106     MIDIByte upper2;
00107     MIDIByte lower2;
00108 
00109     upper1 = (number & 0xff000000) >> 24;
00110     lower1 = (number & 0x00ff0000) >> 16;
00111     upper2 = (number & 0x0000ff00) >> 8;
00112     lower2 = (number & 0x000000ff);
00113 
00114     string rv;
00115     rv += upper1;
00116     rv += lower1;
00117     rv += upper2;
00118     rv += lower2;
00119     return rv;
00120 }
00121 
00122 // Turn a delta time into a MIDI time - overlapping into
00123 // a maximum of four bytes using the MSB as the carry on
00124 // flag.
00125 //
00126 string
00127 MIDIFileWriter::longToVarBuffer(unsigned long number) const
00128 {
00129     string rv;
00130 
00131     long inNumber = number;
00132     long outNumber;
00133 
00134     // get the lowest 7 bits of the number
00135     outNumber = number & 0x7f;
00136 
00137     // Shift and test and move the numbers
00138     // on if we need them - setting the MSB
00139     // as we go.
00140     //
00141     while ((inNumber >>= 7 ) > 0) {
00142         outNumber <<= 8;
00143         outNumber |= 0x80;
00144         outNumber += (inNumber & 0x7f);
00145     }
00146 
00147     // Now move the converted number out onto the buffer
00148     //
00149     while (true) {
00150         rv += (MIDIByte)(outNumber & 0xff);
00151         if (outNumber & 0x80)
00152             outNumber >>= 8;
00153         else
00154             break;
00155     }
00156 
00157     return rv;
00158 }
00159 
00160 bool
00161 MIDIFileWriter::writeHeader()
00162 {
00163     *m_midiFile << MIDI_FILE_HEADER;
00164 
00165     // Number of bytes in header
00166     *m_midiFile << (MIDIByte) 0x00;
00167     *m_midiFile << (MIDIByte) 0x00;
00168     *m_midiFile << (MIDIByte) 0x00;
00169     *m_midiFile << (MIDIByte) 0x06;
00170 
00171     // File format
00172     *m_midiFile << (MIDIByte) 0x00;
00173     *m_midiFile << (MIDIByte) m_format;
00174 
00175     *m_midiFile << intToMIDIBytes(m_numberOfTracks);
00176 
00177     *m_midiFile << intToMIDIBytes(m_timingDivision);
00178 
00179     return true;
00180 }
00181 
00182 bool
00183 MIDIFileWriter::writeTrack(int trackNumber)
00184 {
00185     bool retOK = true;
00186     MIDIByte eventCode = 0;
00187     MIDITrack::iterator midiEvent;
00188 
00189     // First we write into the trackBuffer, then write it out to the
00190     // file with its accompanying length.
00191     //
00192     string trackBuffer;
00193 
00194     for (midiEvent = m_midiComposition[trackNumber].begin();
00195          midiEvent != m_midiComposition[trackNumber].end();
00196          midiEvent++) {
00197 
00198         // Write the time to the buffer in MIDI format
00199         trackBuffer += longToVarBuffer((*midiEvent)->getTime());
00200 
00201         if ((*midiEvent)->isMeta()) {
00202             trackBuffer += MIDI_FILE_META_EVENT;
00203             trackBuffer += (*midiEvent)->getMetaEventCode();
00204 
00205             // Variable length number field
00206             trackBuffer += longToVarBuffer((*midiEvent)->
00207                                            getMetaMessage().length());
00208 
00209             trackBuffer += (*midiEvent)->getMetaMessage();
00210         } else {
00211             // Send the normal event code (with encoded channel information)
00212             if (((*midiEvent)->getEventCode() != eventCode) ||
00213                 ((*midiEvent)->getEventCode() == MIDI_SYSTEM_EXCLUSIVE)) {
00214                 trackBuffer += (*midiEvent)->getEventCode();
00215                 eventCode = (*midiEvent)->getEventCode();
00216             }
00217 
00218             // Send the relevant data
00219             //
00220             switch ((*midiEvent)->getMessageType()) {
00221             case MIDI_NOTE_ON:
00222             case MIDI_NOTE_OFF:
00223             case MIDI_POLY_AFTERTOUCH:
00224                 trackBuffer += (*midiEvent)->getData1();
00225                 trackBuffer += (*midiEvent)->getData2();
00226                 break;
00227 
00228             case MIDI_CTRL_CHANGE:
00229                 trackBuffer += (*midiEvent)->getData1();
00230                 trackBuffer += (*midiEvent)->getData2();
00231                 break;
00232 
00233             case MIDI_PROG_CHANGE:
00234                 trackBuffer += (*midiEvent)->getData1();
00235                 break;
00236 
00237             case MIDI_CHNL_AFTERTOUCH:
00238                 trackBuffer += (*midiEvent)->getData1();
00239                 break;
00240 
00241             case MIDI_PITCH_BEND:
00242                 trackBuffer += (*midiEvent)->getData1();
00243                 trackBuffer += (*midiEvent)->getData2();
00244                 break;
00245 
00246             case MIDI_SYSTEM_EXCLUSIVE:
00247                 // write out message length
00248                 trackBuffer +=
00249                     longToVarBuffer((*midiEvent)->getMetaMessage().length());
00250 
00251                 // now the message
00252                 trackBuffer += (*midiEvent)->getMetaMessage();
00253                 break;
00254 
00255             default:
00256                 break;
00257             }
00258         }
00259     }
00260 
00261     // Now we write the track - First the standard header..
00262     //
00263     *m_midiFile << MIDI_TRACK_HEADER;
00264 
00265     // ..now the length of the buffer..
00266     //
00267     *m_midiFile << longToMIDIBytes((long)trackBuffer.length());
00268 
00269     // ..then the buffer itself..
00270     //
00271     *m_midiFile << trackBuffer;
00272 
00273     return retOK;
00274 }
00275 
00276 bool
00277 MIDIFileWriter::writeComposition()
00278 {
00279     bool retOK = true;
00280 
00281     m_midiFile =
00282         new ofstream(m_path.toLocal8Bit().data(), ios::out | ios::binary);
00283 
00284     if (!(*m_midiFile)) {
00285         m_error = "Can't open file for writing.";
00286         delete m_midiFile;
00287         m_midiFile = 0;
00288         return false;
00289     }
00290 
00291     if (!writeHeader()) {
00292         retOK = false;
00293     }
00294 
00295     for (unsigned int i = 0; i < m_numberOfTracks; i++) {
00296         if (!writeTrack(i)) {
00297             retOK = false;
00298         }
00299     }
00300 
00301     m_midiFile->close();
00302     delete m_midiFile;
00303     m_midiFile = 0;
00304 
00305     if (!retOK) {
00306         m_error = "MIDI file write failed";
00307     }
00308 
00309     return retOK;
00310 }
00311 
00312 bool
00313 MIDIFileWriter::convert()
00314 {
00315     m_timingDivision = 480;
00316     m_format = MIDI_SINGLE_TRACK_FILE;
00317     m_numberOfTracks = 1;
00318 
00319     int track = 0;
00320     int midiChannel = 0;
00321 
00322     MIDIEvent *event;
00323 
00324     event = new MIDIEvent(0, MIDI_FILE_META_EVENT, MIDI_CUE_POINT,
00325                           "Exported from Sonic Visualiser");
00326     m_midiComposition[track].push_back(event);
00327 
00328     event = new MIDIEvent(0, MIDI_FILE_META_EVENT, MIDI_CUE_POINT,
00329                           "http://www.sonicvisualiser.org/");
00330     m_midiComposition[track].push_back(event);
00331 
00332     long tempoValue = long(60000000.0 / m_tempo + 0.01);
00333     string tempoString;
00334     tempoString += (MIDIByte)(tempoValue >> 16 & 0xFF);
00335     tempoString += (MIDIByte)(tempoValue >> 8 & 0xFF);
00336     tempoString += (MIDIByte)(tempoValue & 0xFF);
00337 
00338     event = new MIDIEvent(0, MIDI_FILE_META_EVENT, MIDI_SET_TEMPO,
00339                           tempoString);
00340     m_midiComposition[track].push_back(event);
00341 
00342     // Omit time signature
00343 
00344     NoteList notes = m_exportable->getNotes();
00345 
00346     for (NoteList::const_iterator i = notes.begin(); i != notes.end(); ++i) {
00347 
00348         int frame = i->start;
00349         int duration = i->duration;
00350         int pitch = i->midiPitch;
00351         int velocity = i->velocity;
00352 
00353         if (pitch < 0) pitch = 0;
00354         if (pitch > 127) pitch = 127;
00355 
00356         // Convert frame to MIDI time
00357 
00358         double seconds = double(frame) / double(m_sampleRate);
00359         double quarters = (seconds * m_tempo) / 60.0;
00360         unsigned long midiTime = int(quarters * m_timingDivision + 0.5);
00361 
00362         // Get the sounding time for the matching NOTE_OFF
00363         seconds = double(frame + duration) / double(m_sampleRate);
00364         quarters = (seconds * m_tempo) / 60.0;
00365         unsigned long endTime = int(quarters * m_timingDivision + 0.5);
00366 
00367         // At this point all the notes we insert have absolute times
00368         // in the delta time fields.  We resolve these into delta
00369         // times further down (can't do it until all the note offs are
00370         // in place).
00371 
00372         event = new MIDIEvent(midiTime,
00373                               MIDI_NOTE_ON | midiChannel,
00374                               pitch,
00375                               velocity);
00376         m_midiComposition[track].push_back(event);
00377 
00378         event = new MIDIEvent(endTime,
00379                               MIDI_NOTE_OFF | midiChannel,
00380                               pitch,
00381                               127); // loudest silence you can muster
00382 
00383         m_midiComposition[track].push_back(event);
00384     }
00385     
00386     // Now gnash through the MIDI events and turn the absolute times
00387     // into delta times.
00388     //
00389     for (unsigned int i = 0; i < m_numberOfTracks; i++) {
00390 
00391         unsigned long lastMidiTime = 0;
00392 
00393         // First sort the track with the MIDIEvent comparator.  Use
00394         // stable_sort so that events with equal times are maintained
00395         // in their current order.
00396         //
00397         std::stable_sort(m_midiComposition[i].begin(),
00398                          m_midiComposition[i].end(),
00399                          MIDIEventCmp());
00400 
00401         for (MIDITrack::iterator it = m_midiComposition[i].begin();
00402              it != m_midiComposition[i].end(); it++) {
00403             unsigned long deltaTime = (*it)->getTime() - lastMidiTime;
00404             lastMidiTime = (*it)->getTime();
00405             (*it)->setTime(deltaTime);
00406         }
00407 
00408         // Insert end of track event (delta time = 0)
00409         //
00410         event = new MIDIEvent(0, MIDI_FILE_META_EVENT,
00411                               MIDI_END_OF_TRACK, "");
00412 
00413         m_midiComposition[i].push_back(event);
00414     }
00415 
00416     return true;
00417 }
00418