Problem writing a MIDI file

Hello everyone, this is my first topic in the forum, first of all thank you for your help and your time in advance.
After following the tutorial Create MIDI data (https://docs.juce.com/master/tutorial_midi_message.html) I wanted to try to code a simple program for writing MIDI messages into a local file, as I need to implement this in a bigger program.
The code is the following:

#include "../JuceLibraryCode/JuceHeader.h"

static String getMidiMessageDescription(const MidiMessage& m)
{
	if (m.isNoteOn())           return "Note on " + MidiMessage::getMidiNoteName(m.getNoteNumber(), true, true, 3);
	if (m.isNoteOff())          return "Note off " + MidiMessage::getMidiNoteName(m.getNoteNumber(), true, true, 3);
	if (m.isProgramChange())    return "Program change " + String(m.getProgramChangeNumber());
	if (m.isPitchWheel())       return "Pitch wheel " + String(m.getPitchWheelValue());
	if (m.isAftertouch())       return "After touch " + MidiMessage::getMidiNoteName(m.getNoteNumber(), true, true, 3) + ": " + String(m.getAfterTouchValue());
	if (m.isChannelPressure())  return "Channel pressure " + String(m.getChannelPressureValue());
	if (m.isAllNotesOff())      return "All notes off";
	if (m.isAllSoundOff())      return "All sound off";
	if (m.isMetaEvent())        return "Meta event";

	if (m.isController())
	{
		String name(MidiMessage::getControllerName(m.getControllerNumber()));

		if (name.isEmpty())
			name = "[" + String(m.getControllerNumber()) + "]";

		return "Controller " + name + ": " + String(m.getControllerValue());
	}

	return String::toHexString(m.getRawData(), m.getRawDataSize());
}
//==============================================================================
int main (int argc, char* argv[])
{

	//Messsage Generation
	int midiChannel = 10;
	double startTime= Time::getMillisecondCounterHiRes() * 0.001;
	int c3 = 60;
	MidiMessage message = MidiMessage::noteOn(1, c3, (uint8)100);
	message.setTimeStamp(Time::getMillisecondCounterHiRes() * 0.001 - startTime);
	std::wcout<< getMidiMessageDescription(message) << std::endl;
	MidiMessage messageOff = MidiMessage::noteOff(message.getChannel(), message.getNoteNumber());
	messageOff.setTimeStamp(message.getTimeStamp() + 0.5);
	std::wcout << getMidiMessageDescription(messageOff) << std::endl;

	//MIDIFile and MidiMessageSequenceObject
	MidiFile midiFile;
	MidiMessageSequence mmSeq;
	//Adding MIDI Messages to MidiMessageSequence
	mmSeq.addEvent(message, 0);
	mmSeq.addEvent(messageOff, 0);
	//Adding MidiMessageSequence to MIDI file
	midiFile.addTrack(mmSeq);
	//Writing all to the outputStream
	File file("D:/JUCEProjects/PruebaGenMidi/prueba.mid");
	FileOutputStream stream(file);
	if (midiFile.writeTo(stream, 1)) {
		std::cout << "WriteTo method->true\n";
	}
	else {
		std::cout << "WriteTo method->false\n";
	}
	stream.flush();
    return 0;
}

As you can see, it is very simple and make use of the getMidiMessageDescription from the tutorial. After executing the program I get the following output in the console:
Note on C3
Note off C3
WriteTo method->true
The problem comes when I try to open this file with any DAW, altough the writeTo method returns true. In Ableton I cannot even put the prueba.mid in a MIDI Channel. In Reaper when I drag the file I get the following MIDI notes:

Does someone knows how to solve this issue?
Thanks in advance,
Andrés

If you’re not already, you should be aware of:

https://docs.juce.com/develop/classMidiMessage.html#a868d95a096fad999de5ba11f9a2f6340

String MidiMessage::getDescription	(		)	const
Returns a human-readable description of the midi message as a string, for example "Note On C#3 Velocity 120 Channel 1".

Second, you need to use this function:

https://docs.juce.com/develop/classMidiFile.html#ab18143cad013db21a71735b01aef2a9f

i’m just not sure where in the order of adding tracks to the MidiFile that it goes, if it’s before or after you add the MidiMessageSequence. But I know you need to make use of it.

1 Like

Thanks for the response, I didn’t know that I had to use the setTicksPerQuarterNote() method.
Finally I’ve been able to write the file. If anyone is interesed this is the code I tried for writing a chord (also messing around with sending each MidiOff message at a different time) into a MIDI File:

  int main (int argc, char* argv[])
 {
//Messsage Generation
int midiChannel = 10;
double startTime= Time::getMillisecondCounterHiRes() * 0.001;
int c3 = 60;
MidiMessage message = MidiMessage::noteOn(1, c3, (uint8)100);
message.setTimeStamp(Time::getMillisecondCounterHiRes() * 0.001 - startTime);
//Extra noteOn
MidiMessage message1 = MidiMessage::noteOn(1, c3+7, (uint8)100);
message1.setTimeStamp(message.getTimeStamp());
MidiMessage messageOff = MidiMessage::noteOff(message.getChannel(), message.getNoteNumber());
//If 96 ticks per quarter note then 192 are 2 beats
messageOff.setTimeStamp(message.getTimeStamp() + 192);
//Extra noteOff
MidiMessage messageOff1 = MidiMessage::noteOff(message1.getChannel(), message1.getNoteNumber());
messageOff1.setTimeStamp(message1.getTimeStamp() + 96);


//MIDIFile and MidiMessageSequenceObject
MidiFile midiFile;
MidiMessageSequence mmSeq;
//Adding MIDI Messages to MidiMessageSequence
mmSeq.addEvent(message, 0);
mmSeq.addEvent(message1, 0);
mmSeq.addEvent(messageOff, 0);
mmSeq.addEvent(messageOff1, 0);
//Adding extra messages:

//Adding MidiMessageSequence to MIDI file	

midiFile.addTrack(mmSeq);	
midiFile.setTicksPerQuarterNote(96);

//Writing all to the outputStream
File file("D:/JUCEProjects/PruebaGenMidi/prueba.mid");
FileOutputStream stream(file);
if (midiFile.writeTo(stream, 1)) {
	std::cout << "WriteTo method->true\n";
}
else {
	std::cout << "WriteTo method->false\n";
}
stream.flush();
return 0;

}