Exporting a MIDI File


#1

Hi everyone.

I need to export a vector of Events in a midi file. But… actually it doesn’t work at all.

I’ve tried several times to open it on Garage Band but the first beat only seems to be fill in (and not with the good notes !).

Here it is :

void Pattern::ExportMidiFile(File file)
{
  MidiFile mymidifile;
  MidiMessageSequence myTrack[16];
  int microsecondsperquarter = 60.0*1000000.0/(mTempo*4);
  
  mymidifile.setTicksPerQuarterNote(960);
  
  for(int i = 0; i < 16; i++)
  {
    myTrack[i].addEvent(MidiMessage::timeSignatureMetaEvent(mTotalLength, 4));
    myTrack[i].addEvent(MidiMessage::tempoMetaEvent(microsecondsperquarter));
    myTrack[i].addEvent(MidiMessage::midiChannelMetaEvent(i+1));
  }
  
  for(vector<Event>::const_iterator it = mEvents.begin(); it != mEvents.end(); ++it)
  {
   //Adding an Event. GetTime() is a double which represents the start beat of the note (0.0 for the first beat, 1.25 for the second quarter note of the second beat)
    myTrack[it->GetChannel()-1].addEvent(MidiMessage::noteOn(it->GetChannel(), it->GetNoteNumber(), it->GetVelocity()), it->GetTime());
    myTrack[it->GetChannel()-1].updateMatchedPairs();
   //GetNoteLength() is a double which represents the end of note (0.5 for a half note, 0.25 for a quarter note per examples)
    myTrack[it->GetChannel()-1].addEvent(MidiMessage::noteOff(it->GetChannel(), it->GetNoteNumber()), it->GetTime() + it->GetNoteLength());
  }
  
  for(int i = 0; i < 16; i++)
  {
    if(myTrack[i].getNumEvents() > 3)
    {
      myTrack[i].addEvent(MidiMessage::endOfTrack(), mTotalLength);
      mymidifile.addTrack(myTrack[i]);
    }
  }
  
  FileOutputStream fos(file);
  
  mymidifile.writeTo(fos);
}

Thanks a lot.


#2

I’m sure the midi file stuff works ok, you’re probably just feeding it weird times or something. The timestamps are supposed to be in ticks, and it looks like you’re feeding it some kind of bars or beats?


#3

Yes i thought it was in beats because it is supposed to be a double.

I’m beginning with midi file standards but a tick is an integer isn’t it (like frames ?) ? So why does the addEvent function ask for a double ?


#4

The MidiMessageSequence has no concept of what units the timestamps use, they could be seconds, or beats, or anything. The MidiFile expects them to contain the actual numbers that will go into the file, which are ticks.


#5

Ok I did’nt get this point.

Thank you.


#6

It works!

The correct one :

[code]void Pattern::ExportMidiFile(File file)
{
MidiFile mymidifile;
MidiMessageSequence myTrack[16];
int microsecondsperquarter = 60.01000000.0/(mTempo4);

mymidifile.setTicksPerQuarterNote(960);

for(int i = 0; i < 16; i++)
{
myTrack[i].addEvent(MidiMessage::timeSignatureMetaEvent(mTotalLength, 4));
myTrack[i].addEvent(MidiMessage::tempoMetaEvent(microsecondsperquarter));
myTrack[i].addEvent(MidiMessage::midiChannelMetaEvent(i+1));
}

for(vector::const_iterator it = mEvents.begin(); it != mEvents.end(); ++it)
{
uint starttime = floor(it->GetTime()9604);
uint endtime = floor((it->GetTime() + it->GetNoteLength())9604);
myTrack[it->GetChannel()-1].addEvent(MidiMessage::noteOn(it->GetChannel(), it->GetNoteNumber(), it->GetVelocity()), starttime);
myTrack[it->GetChannel()-1].updateMatchedPairs();
myTrack[it->GetChannel()-1].addEvent(MidiMessage::noteOff(it->GetChannel(), it->GetNoteNumber()), endtime);
}

for(int i = 0; i < 16; i++)
{
if(myTrack[i].getNumEvents() > 3)
{
myTrack[i].addEvent(MidiMessage::endOfTrack(), floor(mTotalLength9604));
mymidifile.addTrack(myTrack[i]);
}
}

FileOutputStream fos(file);

mymidifile.writeTo(fos);
}
[/code]