Here is some MIDI file stuff I played with a while ago to figure out the same sort of issues. It’s possibly incomplete as I haven’t used it for anything serious yet.
[code]class MainComponent : public Component,
public FilenameComponentListener
{
private:
FilenameComponent* selectFileWrite;
FilenameComponent* selectFileRead;
public:
MainComponent ()
{
addAndMakeVisible(selectFileWrite = new FilenameComponent(T(“selectFileWrite”),
File::nonexistent,
false,
false,
true,
T("*.mid"),
String::empty,
T(“Choose a Midi file to write…”)));
selectFileWrite->addListener(this);
addAndMakeVisible(selectFileRead = new FilenameComponent(T("selectFileRead"),
File::nonexistent,
false,
false,
false,
T("*.mid"),
String::empty,
T("Choose a Midi file to read...")));
selectFileRead->addListener(this);
}
~MainComponent ()
{
deleteAllChildren();
}
void resized ()
{
selectFileWrite->setBounds(10, 10, getWidth()-20, 24);
selectFileRead->setBounds(10, 40, getWidth()-20, 24);
}
void filenameComponentChanged (FilenameComponent* fileComponentThatHasChanged)
{
if(selectFileWrite == fileComponentThatHasChanged)
{
File file = selectFileWrite->getCurrentFile();
if(file.existsAsFile())
file.deleteFile();
//writeToFileSMPTE(file);
writeToFileBBT(file);
}
else if(selectFileRead == fileComponentThatHasChanged)
{
File file = selectFileRead->getCurrentFile();
if(file.existsAsFile())
{
readFromFile(file);
}
}
}
// BBT bars beats ticks
void writeToFileBBT(File const& file)
{
MidiFile midiFile;
MidiMessageSequence seq;
const int tickPQN = 96;
midiFile.setTicksPerQuarterNote(96);
// timestamps seem to be in multiples of: ticks per quarter note
seq.addEvent(MidiMessage::noteOn(1, 60, 1.f), 0 * tickPQN);
seq.addEvent(MidiMessage::noteOn(1, 60, 0.f), 1 * tickPQN);
seq.addEvent(MidiMessage::noteOn(1, 72, 1.f), 2 * tickPQN);
seq.addEvent(MidiMessage::noteOn(1, 72, 0.f), 3 * tickPQN);
midiFile.addTrack(seq);
FileOutputStream outputStream(file);
midiFile.writeTo(outputStream);
}
/* SMPTE
Can't get Logic to read this it gives the error "Can't read SMPTE format"
maybe this is saying that Logic can only read BBT Midi files NOT SMPTE
ones, not that there's generally a problem with our file?
*/
void writeToFileSMPTE(File const& file)
{
MidiFile midiFile;
MidiMessageSequence seq;
const int fps = 25;
const int smpteSubframeResolution = 80;
midiFile.setSmpteTimeFormat(fps, smpteSubframeResolution);
seq.addEvent(MidiMessage::noteOn(1, 60, 1.f), 0 * fps); // not not sure if this arithmetic is correct: can't check it
seq.addEvent(MidiMessage::noteOn(1, 60, 0.f), 1 * fps);
seq.addEvent(MidiMessage::noteOn(1, 72, 1.f), 2 * fps);
seq.addEvent(MidiMessage::noteOn(1, 72, 0.f), 3 * fps);
midiFile.addTrack(seq);
FileOutputStream outputStream(file);
midiFile.writeTo(outputStream);
}
void readFromFile(File const& file)
{
MidiFile midiFile;
FileInputStream inputStream(file);
midiFile.readFrom(inputStream);
for(int trackIndex = 0; trackIndex < midiFile.getNumTracks(); trackIndex++)
{
const MidiMessageSequence *seq = midiFile.getTrack(trackIndex);
for(int eventIndex = 0; eventIndex < seq->getNumEvents(); eventIndex++)
{
MidiMessageSequence::MidiEventHolder* event = seq->getEventPointer(eventIndex);
printMessage(event->message);
MidiMessageSequence::MidiEventHolder* offEvent = event->noteOffObject;
if(offEvent != 0)
{
printMessage(offEvent->message);
}
}
}
}
void printMessage(MidiMessage const& message)
{
const int size = message.getRawDataSize();
const uint8* data = message.getRawData();
String logMessage = "message[time: ";
logMessage << message.getTimeStamp();
logMessage << "] ";
for(int i = 0; i < size; i++)
{
logMessage << data[i] << " ";
}
Logger::outputDebugString(logMessage);
}
};
[/code]