performExternalDragDropOfFiles not working in Ableton

I have a working implementation of performExternalDragDropOfFiles that has been tested in several DAWs on Mac/Windows as follows:

Mac OSX 10.15.7 / Xcode 12.1 / Juce 6.0.4

  • AU works in latest Logic Pro X
  • VST3 works in latest FL Studio
  • VST3 works in latest Studio One
  • VST3 works in latest Reaper
  • VST3 fails in latest Ableton

Windows 10 / Visual Studio 2019 / Juce 6.0.4

  • VST3 works in latest FL Studio
  • VST3 works in latest Studio One
  • VST3 works in latest Reaper
  • VST3 fails in latest Ableton

The exact same issue occurs in Ableton on Mac or Windows. If I drag and drop from the plugin onto an Ableton clip location, I get a pop up dialog that says:

The file “/Users/trackbout/Library/Application Support/Trackbout/Ripchord/recorded.mid” could not be opened.

I can click OK to close the dialog and nothing crashes, but the drag and drop does not complete obviously.

There is a workaround which is to drag and drop the same file from the plugin to the desktop, and then drag the resulting file from the desktop onto an Ableton clip, which works fine, so the issue does not seem to be related to the file itself.

Changing the directory of the temporary file to be drag and dropped does not have any effect, so it also does not seem to be related to the temporary file’s location.

I used this post from @leehu as a guide: Can one drag and drop MIDI from a JUCE plug-in to the DAW timeline? - #9 by franksaraceno

Here is the relevant plugin code:

void RecordedMidiComponent::mouseDown (const MouseEvent& inEvent)
{
    MidiMessage tempoEvent = MidiMessage::tempoMetaEvent ((60000.f / BPM) * 1000.f);
    tempoEvent.setTimeStamp (0);

    MidiMessageSequence recordedSequence = getRecordedSequence();
    recordedSequence.addEvent (tempoEvent);
    recordedSequence.updateMatchedPairs();
    recordedSequence.sort();

    MidiFile midiFile;
    midiFile.setTicksPerQuarterNote (960.f);
    midiFile.addTrack (recordedSequence);

    File tempFile = RIPCHORD_FOLDER.getChildFile ("recorded.mid");

    if (auto stream = std::unique_ptr<FileOutputStream> (tempFile.createOutputStream()))
    {
        midiFile.writeTo (*stream, 0);
        performExternalDragDropOfFiles ({ tempFile.getFullPathName() }, false, nullptr,
                                        [=](void){ tempFile.deleteFile(); });
    }
}

Here is an example of a resulting MIDI file from the plugin:
recorded.mid (120 Bytes)

Anybody have an idea what the issue might be?

does it work without tempFile.deleteFile() ?

1 Like

Yup! That fixed it. :tada: Thanks for the clue :pray:t3:

I guess that callback must be firing before Ableton completes the operation. In the mean time, this works well everywhere now:

void RecordedMidiComponent::mouseDown (const MouseEvent& inEvent)
{
    if (RIPCHORD_FOLDER.getChildFile (TEMP_FILE_NAME).existsAsFile())
    {
        RIPCHORD_FOLDER.getChildFile (TEMP_FILE_NAME).deleteFile();
    }

    MidiMessage tempoEvent = MidiMessage::tempoMetaEvent ((60000.f / BPM) * 1000.f);
    tempoEvent.setTimeStamp (0);

    MidiMessageSequence recordedSequence = getRecordedSequence();
    recordedSequence.addEvent (tempoEvent);
    recordedSequence.updateMatchedPairs();
    recordedSequence.sort();

    MidiFile midiFile;
    midiFile.setTicksPerQuarterNote (960.f);
    midiFile.addTrack (recordedSequence);

    File tempFile = RIPCHORD_FOLDER.getChildFile (TEMP_FILE_NAME);

    if (auto stream = std::unique_ptr<FileOutputStream> (tempFile.createOutputStream()))
    {
        midiFile.writeTo (*stream, 0);
        performExternalDragDropOfFiles ({ tempFile.getFullPathName() }, false);
    }
}

Actually, I like this implementation better anyway, completely removes the dependency on the behavior of the host DAW.

3 Likes