Export MIDI

I am beginning to cobble together an “Export MIDI” function and I have run into an issue with te::MidiClip::getSequence() which, in fact, does not return a sequence but instead returns a te::MidiList.

File file;
FileChooser fileChooser("Choose Midi File", file, "*.mid");

if (fileChooser.browseForFileToSave(true))
{
	file = fileChooser.getResult();
	
	MidiFile midiFile;
	midiFile.setTicksPerQuarterNote(960);

	MidiMessageSequence midiMessageSequence;

	if (const auto clipTrack{ dynamic_cast<te::ClipTrack*> (trackPtr) })
	{
		Array<te::MidiClip*> midiClips;
		for (const auto& clip : clipTrack->getClips())
		{
			if (const auto & midiClip{ dynamic_cast<te::MidiClip*> (clip) })
			{
				midiMessageSequence.addSequence(midiClip->getSequence(), 0.0);//??????
			}
		}
		midiMessageSequence.updateMatchedPairs();
	}

	midiMessageSequence.addEvent(MidiMessage::endOfTrack());

	midiFile.addTrack(midiMessageSequence);

	const auto stream = file.createOutputStream();
	midiFile.writeTo(*stream);
}

This made me think that I am missing something here. Or perhaps there is already an “Export MIDI” function somewhere that I have overlooked.

What is the canonical way to export midi?

It’s best to use the Render class.

            auto& edit = c->edit;
            int idx = 0;
            BigInteger tracksToDo;

            for (auto t : getAllTracks (edit))
            {
                if (c->getTrack() == t)
                    tracksToDo.setBit (idx);
                idx++;
            }

            auto clipPos = c->getPosition();

            Array<Clip*> clips;
            clips.add (c);

            const bool usePlugins = false; 
            const bool audio = dynamic_cast<AudioClipBase*> (c);

            File dir = // your output dir;

            auto f = dir.getNonexistentChildFile (File::createLegalFileName (c->getName()), audio ? ".wav" : ".mid");

            WeakReference<Component> root = getTopLevelComponent();

            Renderer::renderToFile (TRANS("Render Clip"), f, edit, clipPos.time,
                                    tracksToDo, usePlugins, clips, true);

Yes, well, as I thought…I would not have considered doing it that way.

I’ll give it a try.

Thank you!

For the benefit of others, my version is as follows;

File renderFile;
FileChooser fileChooser("Choose Midi File", renderFile, "*.mid");
if (fileChooser.browseForFileToSave(true))
{
	renderFile = fileChooser.getResult();
	
	const auto edit{ &trackPtr->edit };

	BigInteger tracksToDo{ 0 };

	auto index{ 0 };
	for (const auto& track : getAllTracks(*edit))
	{
		if (track == trackPtr)
		{
			tracksToDo.setBit(index);
			break;
		}
		index++;
	}

	const auto clips{ audioTrack->getClips() };
	const auto clipPosition = clips[0]->getPosition();

	te::Renderer::renderToFile("Render MIDI", renderFile, *edit, clipPosition.time, tracksToDo, false, clips, true);
}

It works as intended. Thank you again!

1 Like