anthonyalfimov / Stable-Delay

AU, VST3. A WIP delay/chorus/flanger plugin
GNU General Public License v3.0
3 stars 1 forks source link

Audio glitches in Chorus and Flanger mode on record-enabled tracks in Logic #40

Closed anthonyalfimov closed 3 years ago

anthonyalfimov commented 3 years ago
DAW Bug
Logic 10.6.1 Intel [ + ]
Reaper 6.23 ARM beta [ - ]
Reaper 6.23 Intel [ - ]
Logic 10.6.1 ARM [ + ]
Logic 10.5.1 Intel [ + ]

Discontinuities in the audio output of the plugin in Chorus and Flanger when a track in Logic is connected to a physical input. The audio glitches only appear when the track is armed for recording and/or when input monitoring is enabled on the track. Glitches are independent of the plugin gain settings.

Glitches are not present in delay mode.

Glitches get worse with smaller audio buffer size, while increasing it can solve the problem.


Solution:

With Logic's "Process Buffer Range" setting (Audio -> Devices), it uses a larger block size when no physical inputs are being monitored. This larger block size is the one that is supplied to prepareToPlay(). When a physical input is being monitored, Logic reduces the block size to the one defined by the "I/O Buffer Size" setting. The smaller block size is only supplied as the numSamplesToRender to the process() function, without prepareToPlay() being called.

Therefore, assuming that the block size is equal to the one passed to prepareToPlay() can lead to problems. prepareToPlay() should be only used to set the maximum block size.

anthonyalfimov commented 3 years ago

Hypotheses

Things to explain: source of discontinuities; connection to the audio buffer size; connection to delay time modulation; why the problem is present on some systems, but not on others.

  1. ~CPU cannot finish the instructions in time - actual performance issue. As far as I know, in this case one of the CPU core load meters in Logic should be maxing out. Might be possible due to differences in instruction optimisation on different CPUs. Doesn't seem very likely to me right now. Should be easily testable by observing the CPU load meters.~

  2. ~Discontinuities due to processor thread being locked / other threading issues. As I understand, different systems/CPUs can handle threading differently. It might be that certain threading issues don't arise on my machines, but exist in the code. It's unlikely that it's connected to atomics, because then everything would produce glitches, not just the modulation. Is there something unique in terms of threading to the LFO module?~

  3. Discontinuities in the modulation buffer. Modulation in the plugin is directly connected to the block size: a modulation buffer is allocated to have the same size as the block size. Maybe the LFO or Delay module are relying on some undefined behaviour that can differ between systems? Not handling or incorrectly handling some system-dependent behaviour?

  4. ✅ Some unaccounted difference in testing setup is causing the glitch, not a difference in the system / hardware. The reason why I couldn't reproduce the problem is that I wasn't reproducing the testing conditions exactly. This unaccounted factor could be not properly handled by the plugin, which causes the discontinuities in audio output. For example,~ the plugin is forced into mono->stereo channel configuration (mono audio file on a stereo track?)~, or enabled recording + input monitoring on the track?

anthonyalfimov commented 3 years ago

No luck reproducing this so far. My old iMac runs a universal binary compiled on the M1 with no issues; no glitches even at 32 sample buffer size.

anthonyalfimov commented 3 years ago

Things to test

anthonyalfimov commented 3 years ago

Hypothesis 4 confirmed: glitches are caused by arming a track for recording or enabling input monitoring (track must be connected to a physical input).

I have now successfully reproduced the bug.

H4, however, does not explain the actual cause of the glitches. Based on the tests above, it does not appear that this is a performance or threading issues.

anthonyalfimov commented 3 years ago

Hypotheses

Things to explain: glitches are caused by arming a track for recording or enabling input monitoring (track must be connected to a physical input); the glitches are linked to the delay time modulation; higher modulation rate and depth produces more glitches and vice versa; glitches disappear at modulation depth = 0; glitches are affected by the buffer size: smaller buffer size produces more glitches, larger - less.

4.1. Logic uses a smaller buffer size than defined by the settings when input monitoring is enabled. In this case, prepareToPlay() might not be called. LFO module cannot handle resizing of the buffer without prepareToPlay() being called by the host.

anthonyalfimov commented 3 years ago

With Logic's "Process Buffer Range" setting (Audio -> Devices), it uses a larger block size when no physical inputs are being monitored. This larger block size is the one that is supplied to prepareToPlay(). When a physical input is being monitored, Logic reduces the block size to the one defined by the "I/O Buffer Size" setting. The smaller block size is only supplied as the numSamplesToRender to the process() function, without prepareToPlay() being called.

Therefore, assuming that the block size is equal to the one passed to prepareToPlay() can lead to problems. prepareToPlay() should be only used to set the maximum block size.