MidiFX Plugin issues in Logic Pro X
-
@Christoph-Hart It seems as soon as another track, than the plugin track, is selected, the plugin stops modifying the recorded events, and also jumps in to a "midi through" state.
-
@Christoph-Hart I found this thread in Juce forum:
https://forum.juce.com/t/garbage-midi-data-midi-fx-logic-pro-mac-m1/51774/13The garbage seems to come out only when Logic runs in Apple silicon processors, I switched my logic to run under Rosetta and that made the garbage go away.
I also found a fix patch from Februari this year, in the Juce code, for this behavior under silicon.
https://github.com/juce-framework/JUCE/commit/d5ad26a162ebde406f685ab36738b878c9b2d4efCould we have that fix in Hise as well (the juce code in the Hise code is older than Februari this year I suspect?)
-
@Christoph-Hart I downloaded Juce 7 and then built the ArppegiatorDemo project from the Juce examples, with these settings in Projucer:
Plugin Charasteristics:
- Plugin Midi Input
- Plugin Midi Output
- Midi Effect Plugin
Valid Architectures:
- X86_64
- arm64
- arm64e
I launched it in Logic Pro X under silicon processor M1, and all works as it should.
- No garbage midi events logged
- The Midi FX Plugin runs and outputs plugin generated events even if I have another track selected than the Midi FX plugin track
See/hear the result here:
The Juce plugin code for this project
/* ============================================================================== This file is part of the JUCE examples. Copyright (c) 2022 - Raw Material Software Limited The code included in this file is provided under the terms of the ISC license http://www.isc.org/downloads/software-support-policy/isc-license. Permission To use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ /******************************************************************************* The block below describes the properties of this PIP. A PIP is a short snippet of code that can be read by the Projucer and used to generate a JUCE project. BEGIN_JUCE_PIP_METADATA name: ArpeggiatorPlugin version: 1.0.0 vendor: JUCE website: http://juce.com description: Arpeggiator audio plugin. dependencies: juce_audio_basics, juce_audio_devices, juce_audio_formats, juce_audio_plugin_client, juce_audio_processors, juce_audio_utils, juce_core, juce_data_structures, juce_events, juce_graphics, juce_gui_basics, juce_gui_extra exporters: xcode_mac, vs2022 moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1 type: AudioProcessor mainClass: Arpeggiator useLocalCopy: 1 pluginCharacteristics: pluginWantsMidiIn, pluginProducesMidiOut, pluginIsMidiEffectPlugin END_JUCE_PIP_METADATA *******************************************************************************/ #pragma once //============================================================================== class Arpeggiator : public AudioProcessor { public: //============================================================================== Arpeggiator() : AudioProcessor (BusesProperties()) // add no audio buses at all { addParameter (speed = new AudioParameterFloat ({ "speed", 1 }, "Arpeggiator Speed", 0.0, 1.0, 0.5)); } //============================================================================== void prepareToPlay (double sampleRate, int samplesPerBlock) override { ignoreUnused (samplesPerBlock); notes.clear(); currentNote = 0; lastNoteValue = -1; time = 0; rate = static_cast<float> (sampleRate); } void releaseResources() override {} void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midi) override { // A pure MIDI plugin shouldn't be provided any audio data jassert (buffer.getNumChannels() == 0); // however we use the buffer to get timing information auto numSamples = buffer.getNumSamples(); // get note duration auto noteDuration = static_cast<int> (std::ceil (rate * 0.25f * (0.1f + (1.0f - (*speed))))); for (const auto metadata : midi) { const auto msg = metadata.getMessage(); if (msg.isNoteOn()) notes.add (msg.getNoteNumber()); else if (msg.isNoteOff()) notes.removeValue (msg.getNoteNumber()); } midi.clear(); if ((time + numSamples) >= noteDuration) { auto offset = jmax (0, jmin ((int) (noteDuration - time), numSamples - 1)); if (lastNoteValue > 0) { midi.addEvent (MidiMessage::noteOff (1, lastNoteValue), offset); lastNoteValue = -1; } if (notes.size() > 0) { currentNote = (currentNote + 1) % notes.size(); lastNoteValue = notes[currentNote]; midi.addEvent (MidiMessage::noteOn (1, lastNoteValue, (uint8) 127), offset); } } time = (time + numSamples) % noteDuration; } using AudioProcessor::processBlock; //============================================================================== bool isMidiEffect() const override { return true; } //============================================================================== AudioProcessorEditor* createEditor() override { return new GenericAudioProcessorEditor (*this); } bool hasEditor() const override { return true; } //============================================================================== const String getName() const override { return "Arpeggiator"; } bool acceptsMidi() const override { return true; } bool producesMidi() const override { return true; } double getTailLengthSeconds() const override { return 0; } //============================================================================== int getNumPrograms() override { return 1; } int getCurrentProgram() override { return 0; } void setCurrentProgram (int) override {} const String getProgramName (int) override { return "None"; } void changeProgramName (int, const String&) override {} //============================================================================== void getStateInformation (MemoryBlock& destData) override { MemoryOutputStream (destData, true).writeFloat (*speed); } void setStateInformation (const void* data, int sizeInBytes) override { speed->setValueNotifyingHost (MemoryInputStream (data, static_cast<size_t> (sizeInBytes), false).readFloat()); } private: //============================================================================== AudioParameterFloat* speed; int currentNote, lastNoteValue; int time; float rate; SortedSet<int> notes; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Arpeggiator) };
Would it be possible to make Hise compile like this?
-
@Christoph-Hart do you think it's possible to fix this in Hise?
Or do we need to integrate Juce v.7 for this to work? -
@Christoph-Hart bump...
-
@Christoph-Hart this is a minimal MidiFX example, when any key is pressed a timer will spit out that key every 100ms
NotePnl.setTimerCallback(function() { var ev = Synth.addNoteOn(1, this.data.nn, this.data.vel, 0); Synth.noteOffDelayedByEventId(ev, 1000); });
Still I get all the crazy data from it when using Logic, and if a different track, than the plugin track, is selected, it will not work.
Do you think you have the time to take look and see what is wrong?HiseSnippet 925.3oc4V0saiSDEdljZfDnRrR7.XsW4JEhRfkEjPUTZRJJZosQjREb0po1GGOpimwxdbVrP7.v6FOL7F.mi+Yi8RVZUD6UDoVkyOey7Mm47MmrJ03CYYlTFevMEI.i+QNqKz1nYQBolsbNieryZYbhBbuAxrryKRDYYP.iy6+cTJ7AGwJ+7mey4BkP6C6bwX2Zj9v2Kik1cdWc1KjJ0Eh.3FYbqre1YK8M5YFkIGoSemIrDg+8hMvUBJsdNL96sHPZMoqsBKjw3GctInXcj4U5p7uUlIuSAjwT1ZbgpbegQEPLl7xlEIUAqZN1YLbUVsqHzupH7INWJCju1+thwGWFvcGh10CdutzqeG5MsM8lzhd6gR8ZQoipnzSbV6mJSr6hP74CcVpsPZn.K6soRUtrd+dOmYFLCscbr3d3hTz30H7d9jIibw+cxWObHV5yrtaEotWYrvJsx8T2Fna.6LSbhQiFdOsN9SIT0eebFXoKyzYBk5N7VyKLW6akFs2IC+0gCnkE1hqXYu0XQP.A7Zs2zQt1HY13.gULVqaasETibIpMnBjlPDFNGThBH37hEaQ1rLvC1Nxc5jxCwug+0rwtFc8dTxfKwZF1JMVtQaRgRrd1zbfV+gCZNF0z.IZS93QmBdUd7cPpGkcmbQR1M4aAkwWZK5jZlUjVUe7lVQzgtuIOCCeLDUF55UUNHhkGuJEnq7W.EYdm3d5oXAa3fV6qIoZa+G6Ic0lZTJJ1CrscAVudDl8ujd5xZ0HrWRg3aRDaj6pNbd6pi1hW+pdvVIZzK0R60If9sIoY0Mt329wkyw6ITRwq8g4k.oVIQA9bXK99Tk.afybH6drhUlac2Ni+91xnG2H+DZPwjAT90kY1uz9Euh1FuRFXi143mOKBjahrs8rs4Xy6ydrp9AkuBcctceZd9e339.hfLPGbiodM7db8iO.l2re5+ecM641CmVXBxUBa2QHzby5.XMnycH81rNCe+n8b0+ylq7Xo3SbVIs9Q6mi81CGoQVuC3X8z3icVDFB91cD7HmK9o2MidY+fI2J0atTXSknv1AejcM9CR7Ab20n1m5A48ntkJ6IjMUAViBjRi+B+TGbJYyqCNsIHKV3mZdoeUmOMu+CJ8fbRW9ScP8MY6NkUpFPbNSFOgEihuW56SG+OEaf2OlO6.v74G.lmc.X9hC.yyO.Le4Af4q9WwPu68s4VSbkb.crZQ4SDb9Bs.6rJ6BY+M2dkKcB
-
@ulrik you should use the synth timer. In a non deferred script.
-
@d-healey yeah but this will make no difference to the issue, still the same garbage events and will still not work if another track is selected
-
@ulrik You've tried the synth timer? A panel timer isn't accurate so I would expect problems with that.
-
@d-healey yes, same issue
-
@Christoph-Hart
Is it possible to modify Hise to compile working MidiFX plugins?
I know that you have been very busy the last days and I don't expect you to make this happen right away, but what do you think, will it be on the roadmap for Hise in a near future? -
@Christoph-Hart bump
-
@Christoph-Hart bumpelibump
-
@Christoph-Hart I feel I'm a bit nagging but do you have any plans for making Hise compile decent MidiFX plugins?
-
@Christoph-Hart A friendly bump!
-
@ulrik Have you checked other hosts?
Also, what David said. The example is never supposed to work correctly (and the timer might even be deactivated when the UI isn't visible, which is a feature not a bug.
For this kind of stuff you HAVE to use the synth timer callback, this guarantees sample accurate execution.
-
@Christoph-Hart Here's the same snippet as before but using the synth timer
HiseSnippet 840.3oc4V0saSCCE1osAQJLIlDO.QiaRkpJMv3GooIF8OT0naUzwD2M4kbZq0bsqbbJqBwaHOL7F.Gmjslt0oNUwthbQa742Oe7243zWICfnHohX4bx7o.w5o1ClKziaNlxDjtsHVaYOgExFdoqFhzjFymRihfPhkUwOYLwxoDI442enAkSEAvBQDxoRV.7Y1Dldgz9GbHiy6PCgSXSxY8tGzMPJZJ4xXDNEsqSlRCtfNBNhZLqfMw5QsCYZoZflhfgXUpgLb9fwxuKRs+TVD6bNXV3SFfAJUbGIOzfXiTRywLdX+q11QDLJ8WTDJlVDdtcObOes7EEimknvcgG4qGVEVFdEWBd94gW8bvaEPpPNHUJERaaOHPwlpWnwfmmX2UnA0PJV1yCkTaIEdQA6lRzBgt1D5EPGEt3ZO7da85UcweprW4xJXjqPrWx+y.NJYXrHPyjBWo3HoFNV3Uo7OJ6zCyNdnTiMRHUP6YXr8zpX.ChSYGgvce2qLYDnMddT7jyAkmw.LxKq+TfKCX54IZSXd0hzTk1PMTd9uz2.teV18lfY3v6CZXCc8RCpAJwS5q.SE5PXdjWE2822sdkxNWmV4zzrdqLZJgJImazsljtriYwy3CtMobWXFt8SyGMLLqr5WEq7UMU8pt0WTGDo6yV.mNGBaLOIOcC8fYUc8qmbp4fHKRxgZSULDC6nM4am6B+dhjCBLSTNBVCpLFhTrk4s12MuMeaUPJwJmgRQWASe7TPbWMajL1H91W61hpoHY2JSFZ2TPoYFHX0BlgSNRo9N1sfnKviGb1w8ruvIoO83X8p5Jr9ks6ZH2QfH7DYVL7teTv03yMIQ2MU4+nSObdpLLlS0KOj0byRlBrFrzYnY5kHBmXj+lm+YSduuPba69Lcv3UiwBq.ilg5O.XL69psraObHDnW.vR1c91CykSjuHi0LwndTshcIx2v4pCvqrC.L6BAvMbPqBF1R555l0lJv.rAIYwevmLk9l0VYJ8uRIYBMPIOKHk4atQ7wIRPLIR9X.r+1r10mjzMjuNa9ZkyBBVNT2xwWsoN95M0wc2TGeyl53a2TGe2l536Wuil4ieLVKmj11PH852NYThkUaAEYfIrUxewQXqfq
I still have the same problems in Logic, it's working when the instrument track is selected, both playback and record, as soon as I select another track, the MidiFX function stop working. it seems like it gets "bypassed"
That doesn't happen when I run the Juce compiled MidiFXHere's 2 videos comparing this simple snippet from Hise, with the arpeggiator project compiled in Juce
HISE:
HISE MidiFXJUCE:
JUCE MidiFXAs you can see the Hise MidiFX is not fully functional but the Juce MidiFX is.
How can I build a fully functional MidiFX in Hise, is there some code in Juce that is not implemented in Hise?
Is it possible to implement it myself (I doubt that :)) If so, can you give a hint? -
@ulrik I don't know if it will make a difference since the script isn't deferred in your snippet, but you should put this stuff outside of the UI Midi Processor.
-
@d-healey said in MidiFX Plugin issues in Logic Pro X:
@ulrik I don't know if it will make a difference since the script isn't deferred in your snippet, but you should put this stuff outside of the UI Midi Processor.
It made no difference, I moved the stuff to a different script processor and compiled again, same issue
-
@Christoph-Hart Ok, new example using an Arpeggiator module
Still same malformed "Midi messages" inside Logic if another track than the arp track is selected
Compiled as MidiFX au versionSee video here:
ArpLogicCompiled as VST3 Instrument works as it should in both Live and Reaper
Videos here:
ArpLive
ArpReaperTested on MacOS 14.2
Is it possible to fix this?
Project SnippetHiseSnippet 1596.3oc6Y0sbSaDEVxIKD6j.DZlVtnSGeQmNIsLdroTfNbQj+KTC4GOQlzxMkQQZs8Rj2UHsJfam1oOJ8Qo8MnOJ4Mn8rRx1qrkcTLFlBC9BM4r+bNemyd1yOaZ5xLwddLWE0rs56fUTWCo2mx6VsqAgpznFLNprqSKrGWoReGCOOrkhp5RORLsZ1kUB9c9NULrMnl3QConbLiXh2izivGMZSsmPrs20vB2hzSZ02UqgIiVkYy7AnrDpnhig4oFcvGXHVVFjh5UpaQ3LWctAG6ontbElUe8trWQCW+wDOxI1XAQIEcfQgCuKy1RfXwnJU6RrsZNPk8T.l1bjAXoPCvln8IVjgiOxPbifIxOZGx1C0Lwg2RwfWIY3UTBdI.oLRPZ4PHsAR2zk3vGMi.OqhZP4X21FfYWFJgqUQ8uQUYvBn7B8LNEuqKPLbCacuhEucd3y1OLWaepImvn4YzCXb7gzs1N2ulKateKW9wmpc6DmSHGWlsM1MwoEG0tyZiaQ86cB1814Oyv1GObgf9G2nhltQU9L2LTskVHi1fR3G5foSySPIxVI7IhPErTdf4+ZQl+J9bNipPrD1d3RQnQWI.zxN9JCYvxgL3lQLP2lXgcaBd1ALYcjvndPftOAaVQyxfann9Mn67fBvOZgxv2p6AeZ0TLP4pEJzrVM3udrf9rBUSsfygNFayLI79iK0aMlTeQEPpzFfTZ6HjxiBnerPpLA82Wtbpk5Jn8vzN7tiKyy2IlLaepPFEBjgoPFGKnONf1VPWohrLG6LJTlAxaMDXZComv594ZogCWEo6fgKUis4uVS4oMpIvLbcKxuA7kbvtbhvMUsF9LHzW3c2rnZXuS4Lm.GqdNLpvKSckT4Z85QB8.s9iHpo8JhEXIGNvyz5hIc5xkWhy.26F.WuhfqkfnptP.UHHfXrqgBESjvUjf2UuDNtSAj+wwiCxeeBP9rDAoxj1oK1QdJn3u5LunXjnZPsvudPfizBsgd6SAX4cWf.6Nw.1po6JwT.1e1ebf8yS.rFZ8Lj1dQMON1Qm7KwtU2iXYYiax7Hhn8ilI+E6Yd8.bJ3YH1k0t0tvqqiPl1KdyTr6eoTru5hUrUCg3SnrSTrvsM7s4GOQvkIqIYcAqvc5PL3QI+iXdrRPVJ0kfTZlkfHkK7SRQtvwBiLizgSmGqiNB6g4WZVHc5OtOybEwGNe.NDfk4CE2HfA5mRlBLNemzXN.tvb4OA226MwhH6rMYJrwYvMhX.bU6DVE1qCXADbC+ReLTY+vgSuBIAk0QGZxMNCejAsCd9zlrH8t9saaimOOrUQ0oFf6eKBdVpvrKgYSvbzizBhDIMw6vB21bX9toK+2lkvcynjZSW5Kjh4RzUbCDzJFkhs0w1XSQbvK1SLQF8YnC84N97ED61.sey5PLW2ALbB+yTdW65BFUmZME1TTKMt4WA8CPGuIbEYxtJg9YYV91hTJxM4J5rOZBQ1M4LLh1GodhpsjrRKrNeSKD2.0jvM6lLFyj.FEMU+V.iCyMWucavCZD.WFs6O814wAjE+JS48ZVKnsefB6VZQ7jMNo9IaFu.jEySzr7++dhF0z9DMYCvCDtIoGnIyWnhxOkGeANB8X13BNtDJeq8ANZzAWnClOpwqs1d6GlK6fo7vTqVrHosELyLd8lEMy+f54elqV6+Xz0OHhtdDymSnc12f6Rft.CZn.htAE+FlRV3CplQ3sDRWTPKr.5vEj.h+E9EMYIAsZzjkFLorJdsPUDJSGBVGDEOPA+z.57+HTtb9Gggv3hCnXgxyDOT9+r3CkGVsdKWCpmCyKFiGTArm7fO0CuqK9kGI7XjGuJyvMwoNemcAkLw8nav8cCb8J2i4S4wb0lYJlRevjh48f.JwxBlc.F0I8brw0omA8o.iHv3MgvjAuzwfQiWVx9LJyoKiRLkOnOBC2A6zA6Ji8DUnxbtnOjgiro1QPE8FxNseo1dfylgKXmvyosnzkthfDOutEJDt4EW.y+9ahfk9Xhf2zDAuKjQOCSW1yMCKyR3mtRvHfdSC9+pB0mJnyWZxFF6AQ4dtoYbVMwFuy7twucd23cm2M9cy6Fu27tw6Oua7AW7FEIgJ6yY8BuZpnrey5A0sppF9NWA2HT9OPzW.23