Import Midi Into Track

I’m missing something on importing midi into a track.

    File file{};
    FileChooser fileChooser("Open Midi File", file, "*.mid");

    if (fileChooser.browseForFileToOpen())
    {
         file = fileChooser.getResult();

         FileInputStream stream(file);

         MidiFile midiFile{};

         if (midiFile.readFrom(stream))
         {
		     midiFile.convertTimestampTicksToSeconds();

		     const auto numTracks = midiFile.getNumTracks();
		     for (auto i = 0; i < numTracks; i++)
		     {
	 		     if (auto midiTrack = midiFile.getTrack(i))
			    {
				    midiTrack->extractMidiChannelMessages(1, sequence, false);// ????
			    }
	 	      }
           }
        }

This might not even be the correct approach. Any suggestions are welcome!

Bump.

I suppose this boils down to how to get the “sequence” into the track. But, I am stumbling over finding the correct syntax for that.

Or, again, maybe this is the wrong approach?

Importing MIDI is actually fairly complex depending on what you want to do. If you just want to take a MIDI file, and create one clip, and match the tempo of the existing edit, try and copy what is done in Edit::createEditForPreviewingFile

Here is a stripped down, untested version:

        if (auto fin = std::unique_ptr<juce::FileInputStream> (file.createInputStream()))
        {
            juce::MidiFile mf;
            mf.readFrom (*fin);
            mf.convertTimestampTicksToSeconds();

            juce::MidiMessageSequence sequence;

            for (int i = 0; i < mf.getNumTracks(); ++i)
                sequence.addSequence (*mf.getTrack (i), 0.0, 0.0, 1.0e6);

            sequence.updateMatchedPairs();

            if (auto mc = track->insertMIDIClip ({ 0.0, 1.0 }, nullptr))
            {
                // add midi notes
                mc->mergeInMidiSequence (sequence, MidiList::NoteAutomationType::none);
                auto length = sequence.getEndTime();

                mc->setPosition ({ { 0.0, length }, 0.0 });
            }
        }

If you have a multi track midi file with tempo changes, and you want all the tracks created, create a media object for the midi file

    ProjectItem::Ptr mo;
    File f (originalFile);

        mo = project.createNewItem (f, ProjectItem::midiItemType(),
                                    f.getFileNameWithoutExtension(),
                                    TRANS("Imported from directory") + ": " + originalFile.getParentDirectory().getFullPathName(),
                                    ProjectItem::Category::imported,
                                    true);

and then paste it into the edit:

        Clipboard::ContentType::EditPastingOptions options (editView.edit, editView.insertPoint, editView.getSelectionManager());
        options.silent = silent;
        options.preferredLayout = preferredLayout;
        options.setTransportToEnd = setTransportToEnd;
        editView.insertPoint.chooseInsertPoint (options.startTrack, options.startTime, false, editView.getSelectionManager());

        if (options.startTrack != nullptr)
        {
            Clipboard::ProjectItems content;

            for (auto& item : importedProjectItems)
                content.itemIDs.push_back ({ item->getID(), {} });

            content.pasteIntoEdit (options);
        }

I will get started on this code and see what I can come up with. I may try to implement both scenarios.

Thank yo so much!

The code below, which is only slightly modified from your example, works perfectly on the first try!

File file{};
FileChooser fileChooser("Open Midi File", file, "*.mid");

if (fileChooser.browseForFileToOpen())
{
	file = fileChooser.getResult();
	FileInputStream stream(file);

	MidiFile midiFile{};

	if (midiFile.readFrom(stream))
	{
		midiFile.convertTimestampTicksToSeconds();
		juce::MidiMessageSequence sequence;

		for (auto i = 0; i < midiFile.getNumTracks(); i++)
			sequence.addSequence(*midiFile.getTrack(i), 0.0, 0.0, 1.0e6);

		sequence.updateMatchedPairs();

		const auto midiTrack{ dynamic_cast<te::AudioTrack*>(trackPtr.get()) };

		if (auto midiClip = midiTrack->insertMIDIClip({ 0.0, 1.0 }, nullptr))
		{
			// add midi notes
			midiClip->mergeInMidiSequence(sequence, te::MidiList::NoteAutomationType::none);
			auto length = sequence.getEndTime();
			midiClip->setPosition({ { 0.0, length }, 0.0 });
		}
	}
}

When time permits I’ll work on the second example for importing multiple tracks into an edit.

Thank you so much!

1 Like