Today I bumped into an error which seems to have historically plagued AU MIDI FX plug-ins. The TLDR is that Logic Pro for iPad seems to never give MIDI FX plug-ins the proper sample rate. JUCE defaults to the sample rate being 44100, so the plug-in always thinks that the sample rate is 44100.
Thankfully, this is the only DAW I’ve encountered with this behavior. As far as I can tell, it works fine for other iOS environments (e.g., AUM) and every desktop DAW that I’ve tried (including Logic for macOS).
I dug up these relevant old threads, but I’m surprised that there hasn’t really been mention of it in the past ~5 years (unless my google-fu is terrible).:
Out of those past threads, the only practical suggestion I can find is to check the wall clock time in each processBlock and try to guess the sample rate from there. I suppose I could do this just for AUv3s, but it still doesn’t feel like an incredible solution. Is there a canonical way to handle this these days?
I also saw mention that this could possibly be due to the MIDI FX plug-in having no audio channels, but I verified that in both AUM and Logic Pro for iOS that the plug-in is loaded as {2,2}. I suppose it’s also possible that this is some sort of regression with Logic Pro for iOS, and that’s why there hasn’t been mention in years, though I have no earthly idea who I’d report that to.
Logic for iPad was only released in mid-2023 (IIRC) so it’s possible there just wasn’t enough data about this.
Additionally, we make a MIDI plugin for iOS but I don’t think we have a need for the sample rate information in the MIDI version, it’s possible this also contributed to the lack of bug reporting there.
Why would a MIDI effect need the sample rate? If it’s for keeping track of time then perhaps the playhead could replace it?
I feel like the sample rate is pretty necessary for anything regarding time, no? Even if you were to make a super simple “note length” plug-in that lets you change the length of notes to 250ms or 500ms, etc., wouldn’t you need the sample rate to determine how many samples that is?
Using the PPQ of the playhead could be a solid idea, though. Perhaps if the plug-in is running as an AUv3, I can just sniff the PPQ, BPM, and samples processed since playback started and adjust the sample rate if it seems wrong.
What about the timeInSeconds field of the playhead?
That would work if the playhead were actually moving, but IMO an effect like that should work just as well if the playhead weren’t moving and you were just playing notes into it.
Seems like the only solution would be to inspect timeInSeconds or getPpqPosition when the transport starts moving and do a sanity check against the alleged sample rate from prepareToPlay.
I can see now how you could build a lot of pure MIDI functionality without really referencing the sample rate, but IMHO it’s far easier and more grokable to just use the sample rate and keep things relatively consistent between MIDI and audio plug-ins. And it seems like every DAW except Logic for iPad agrees on that.
FYI for anyone who happens to be in the same boat: I just did some testing and it looks like timeInSeconds relies on the sample rate that came in through prepareToPlay (which defaults to 44100 if none is provided). So if you just do getTimeInSamples() / getTimeInSeconds(), you’ll just get the same value.
However, if you actually use the PPQ position and the BPM, you’ll get the right value. Something like this:
double calculatedSecondsElapsed = ppqPosition * (60.0 / bpm);
if (!juce::approximatelyEqual(calculatedSecondsElapsed, 0.0))
sampleRate = samplesElapsed / calculatedSecondsElapsed;
In testing, this calculation seems to work pretty much instantaneously as soon as the transport starts moving.
1 Like