iOS: Hosting plugins: correct host time for plugins

Hi,

some plugins rely on the host time in the timestamp param in the AUInternalRenderBlock to render their audio.

Usually this timestamp is provided by iOS, but in JUCE it is created via the GetCurrentHostTime in juce_AudioUnitPluginFormat.mm:1983 .

This way though the timestamps are not created at regular intervals, making it impossible for those plugins to render correctly their audio.

Is there any workaround or could the system timestamp be propagated to the processBlock of the plugins?

1 Like

Please can you provide some examples of plugins for which the current behaviour is problematic?

Unfortunately the documentation for the mHostTime field is a bit opaque, but it is hinted that the host time should be derived from AudioGetCurrentHostTime or mach_absolute_time. It sounds like calling these functions on each render callback is introducing jitter. An alternative approach might just be to increment the current host time by the buffer duration on each process callback, but I’d like to test out this approach to see whether it works in practice.

@reuk Loopy Pro from ATastyPixel.

1 Like

Thanks for that. I’ve tested a bit with some simple loops, but as far as I can tell the timing seems alright with and without my potential fix. I’m guessing that the project has to be set up in a certain way for the problem to become evident.

Please can you try applying this change and see whether it resolves the issue you were seeing?

0001-AU-Host-Ensure-that-host-time-increases-linearly-wit.patch (3.5 KB)

If this patch doesn’t resolve the problem, please provide some instructions so that I can properly reproduce the issue locally. If you have e.g. an AudioPluginHost project that exhibits the problem that would be useful.

@reuk thank you for the patch.

The issue with the stable increment of the host time is resolved with the patch, in fact Loopy Pro now seems to be able to render properly. But it seems to break all other plugins: some of them crash, some make some weird sound, some don’t emit any sound. Easily reproducible in the AudioPluginHost.

As a test, I took the host time in iOSAudioIODevice and passed it down to the processBlock of the plugins, and this seems to be working fine.

Thanks for testing that out. Unfortunately I don’t have a great selection of AUv3 plugins to test with, and as I said previously Loopy Pro seemed to behave correctly before and after the proposed change. Are you testing on a specific device? I’ve been using an iPhone SE 2, but I wonder whether the problem is more obvious on other devices.

I had a look at propagating the audio callback timestamp through to the plugins, but this looks like it could be quite a substantial (possibly breaking) change. To get the timestamp into the plugin, it would probably need to go via the AudioPlayHead in order to maintain source compatibility, and the AU wrapper would need to extract this information and do something sensible if it was not set. We’d also need a way of signalling whether or not this timestamp held a valid value (it wouldn’t for JUCE plugin clients, for example). We’d also need to add timestamp support to the AudioIODevice - for consistency, I’d want to add this for all audio device types, or at least provide an API capable of supporting all device types in the future.

To be clear, I’m not dismissing this approach completely. However, I’m keen to try out other approaches too, in case the issue can be resolved with a less disruptive change.

I notice that the AudioTimeStamp struct has a flags field that allows the host to specify which members are valid. I tried removing kAudioTimeStampHostTimeValid from mFlags, zeroing mHostTime, and testing Loopy Pro in the AudioPluginHost, and it still seemed to work correctly. I tried a couple of other plugins too (Viking Synth and Filterstep) and those both seemed to cope too. Would you be able to test this out yourself and see how the results compare to the other approaches? Thanks!

I found a way to consistently reproduce one of the problems in the AudioPluginHost.

Since there’s no transport or playhead in AudioPluginHost, the trick is to use Ableton Link, with another peer on the network.

This is the setup:

  • add one instance of Loopy Pro
  • insert a loop in one of the circles
  • enable Link in the upper right menu > synchronisation
  • start Link from another device / app
  • if necessary tap on the loop to play it

The problem manifests when the loop restarts: you can hear a glitch or a silence.

For reference: it works fine when using the host time from the audio callback. Here’s a patch if you want to try it (it savagely passes the timestamp to the plugins :wink: )

0001-Use-host-time-from-audio-callback.patch (40.4 KB)

Thanks, I’ve tried out those steps and haven’t been able to reproduce any glitching so far when the kAudioTimeStampHostTimeValid flag is not set. I do get glitching when building from develop, though. I’ll try a bit more.

Did you try disabling the mHostTime flag altogether like I suggested? Did this reduce or remove the glitching for you?

Just tried, I still get the glitches if I turn off the kAudioTimeStampHostTimeValid flag. I’m testing on an iPad Pro 2nd gen

Thanks for your patience. I’ve now put together a patch that should provide a way of communicating the callback timestamp from the audio device all the way to a hosted audiounit. At the moment the timestamp goes via the AudioPlayHead, so you’ll need to override the new function on an AudioPlayHead instance and then pass this playhead to any hosted plugins in order for them to receive the correct timestamp information. I’ve implemented this for the AudioProcessorPlayer, so this should work automatically in the AudioPluginHost.

I’ve tested this patch a bit with Loopy Pro and it seems to improve the audio quality a little. I’d feel a lot more confident in the change if you could test it too and see whether it resolves the issues you were seeing.

At the moment, I’ve only implemented timestamp reporting for iOS. If the patch looks good to you, I can investigate adding support for other audio device types too. VST2 and VST3 formats additionally provide an interface for reading the host time in nanoseconds during the process callback, so I can investigate adding support for that too.

0001-AudioProcessor-Allow-querying-of-the-host-timestamp-.patch (42.0 KB)

@reuk thank you so much for the patch, I made some preliminary tests and the problem with Loopy Pro seems to be gone.
We’ll do some more tests and let you know in the next few days

Hi, just wondering whether you have any further information about the suitability of the change.

Sorry for taking so long, the change fixed the problem with Loopy Pro and works correctly with other plugins :+1:

1 Like

Great, thanks! We’ll try to get the change merged shortly, once it’s been reviewed properly by the team.

Thanks for your patience. As this looked like a potentially breaking change, we’ve put it on the JUCE 7 branch: