Can one drag and drop MIDI from a JUCE plug-in to the DAW timeline?
How?
Can one drag and drop MIDI from a JUCE plug-in to the DAW timeline?
How?
Iâm pretty sure @Rail_Jon_Rogut did it for his plugin
As long as the DAW supports it⊠yes⊠Just create a temporary MIDI File and drag/drop that⊠then clean up the temporary file.
Rail
So which DAWs support it?
All that I can think of⊠as long as they accept dropping a Standard MIDI File onto the timeline⊠itâll work⊠There may be some esoteric DAW that may not support that (which is why I put in the disclaimer).
Rail
Yes. Works at least in Logic and Ableton on MacOS.
Hi, how do I make the file draggable from a JUCE component? thx
DragAndDropContainer::performExternalDragDropOfFiles
Any chance you can post some code here on how you did it? Thanks.
File outf = File::getSpecialLocation( File::SpecialLocationType::tempDirectory ).getChildFile( "file.mid" );
MidiFile mf;
MidiMessageSequence ms;
ms.addEvent( MidiMessage::textMetaEvent( 3, "Clip Name" );
ms.addSequence( m_ms.get_midi( m_index ), 0 );
mf.setTicksPerQuarterNote( 24 );
mf.addTrack( ms );
if ( ScopedPointer<FileOutputStream> p_os = outf.createOutputStream() ) {
mf.writeTo( *p_os, 0 );
DBG( "drag clip file name: " << outf.getFullPathName() );
performExternalDragDropOfFiles( { outf.getFullPathName() }, false, nullptr, [ =, &mel_sauce ] ( void ) {
DBG( "clip dropped" );
outf.deleteFile();
} );
}
Works like a charm on most DAWs, thanks!
I do have some plugin users who report its not working on Bitwig (and some older versions of other DAWs) Itâs weird because it does work when you change the focus away from the DAW and back again (for example by pressing Alt-Tab twice) otherwise there is no result coming into Bitwig but âperformExternalDragDropofFilesâ still return true which should only happen if the drop was successful⊠Has anybody else experienced these issues as well?
I havenât tried that myself in Bitwig, but I can say that their dev team has been responsive in the past to bug reports, if you have exhausted your investigation and want to reach out to them.
They are indeed very responsive but unfortunately did not have a solution for my problem right away. Will experiment some more very soon
Hey everyone, Iâm new here but wanted to chime in with an update regarding Bitwig.
Our JUCE plugin has been pretty well tested (over 1k downloads) across many different DAWs on both MacOS and Windows. The drag to midi functionality works with Ableton, Logic, FL, Reaper, Pro Tools, and Garage Band.
For some reason though, Bitwig rejects the MIDI files that our JUCE plugin creates. And to make things more confusing, weâve tested against another app (Scaler 2) which has a drag to midi feature that does work with Bitwig.
We successfully captured a video of this bug in real time, showing our app (AudioCipher) on the left and Scaler 2 on the right. You can view the gif here.
Key Observation about our Bitwig drag to midi bug:
This is why I think the problem could have something to do with the MIDI format that weâre using. It could be that the header chunk requires something special to be compatible with Bitwig, but I donât know.
As a new user I canât upload files, so I uploaded a sample of MIDI output here. Someone else can upload it to this thread for review if they feel itâs appropriate.
Here is a screenshot of an email from Bitwig themselves, confirming this is a known problem.
For those who donât want to view the screenshot, the Bitwig message reads: âIt does not seem to be a drag and drop problem but it seems Bitwig Studio does not accept the midi file itself. Are you sure it is formatted correctly including headers etc.?â
Would greatly appreciate support from anyone who has the knowledge of MIDI and a copy of Bitwig to help us test and resolve the issue.
Hey gm, Did you ever solve this issue?
how does âperformDragAndDropOFIlesâ work? Does it open a new dialog box that allows to drag some file to a DAW? Can this be used to drag a file icon(which represents a saved file somewhere) to a DAW?
Hello,
Resurrecting this thread because Iâm having issues with a similar function. Here is my code within the component:
void mouseDrag(const MouseEvent& event) override
{
File outf = File::getSpecialLocation( File::SpecialLocationType::tempDirectory ).getChildFile( "file.mid" );
if (auto p_os = std::unique_ptr<FileOutputStream> (outf.createOutputStream())) {
DBG("Drag and Drop, MidiFile has numtracks:" << midiFile.getNumTracks());
midiFile.writeTo( *p_os, 0 );
DBG( "drag clip file name: " << outf.getFullPathName() );
performExternalDragDropOfFiles( { outf.getFullPathName() }, false, nullptr, [&outf] ( void ) {
DBG("File dragged");
outf.deleteFile();
DBG("file deleted???");
} );
}
The problem is that the file is not actually deleting at the end of the lambda function; I can still see it in my system. The first time I perform the drag, it works as intended (itâs a single channel midi file). The second time, it drags a midi file with two tracks. The third time, three tracks. Each time, it seems to âappendâ the single midi file to the file before dragging it.
Any insight would be greatly appreciated here - Iâve tried a number of things and nothing seems to successfully delete the file (including deleteRecursively()).
For the lambda: outf is a local variable that you capture by reference. That means you are reading free memory when the lambda is eventually executed, which is undefined behaviour.
There is no problem when you capture it by value, File is a lightweight object simply consisting of a string as filename.
To write the file, that is a bit annoying. The FileOutputStream is created to append, which is unexpected. If it was me, I would add a bool parameter. But thatâs up to the juce team, and I guess we have to live with what we have.
Solution one:
p_os->setPosition (0);
p_os->truncate();
My favourite is using juce::TemporaryFile though. This returns a unique temp file, and once you are done writing, it replaces the actual file.
The main benefit is, you donât get half written files. And as an additional plus, it always starts with a fresh file.
Thank you Daniel, that was exactly the solution!
In the interest of âpaying it forwardâ, here is my full code now that it works, in case other users stumble on this thread:
void mouseDrag(const MouseEvent& event) override
{
File outf = File::getSpecialLocation( File::SpecialLocationType::tempDirectory ).getChildFile( "file.mid" );
TemporaryFile tempf (outf);
if (auto p_os = std::unique_ptr<FileOutputStream> (tempf.getFile().createOutputStream())) {
midiFile.writeTo( *p_os, 0 );
bool succeeded = tempf.overwriteTargetFileWithTemporary();
performExternalDragDropOfFiles( { outf.getFullPathName() }, false, nullptr, [&outf] ( void ) {
outf.deleteFile();
} );
}
}
Just a little oversight, you still capture a local variable by reference:
Should be:
performExternalDragDropOfFiles( { outf.getFullPathName() }, false, nullptr, [outf] ( void ) {
outf.deleteFile();
} );