First off, I just want to say thanks to the team at AudioKit for shedding some light on some difficult problems through their code. I have a few questions.
1: It does not appear the the AKAudioPlayer class applies on-the-spot fades if a player is stopped before reaching the end of the file/buffer. Is there another place in the AudioKit library where this is handled?
2: Does anybody know if the AVAudioMixer node’s volume can be adjusted in real time? E.G. can I make adjustments every 1/441 ms to follow the curve of my fade envelope? There is also the AVAudioUnitEQ with its globalGain property.
3: Is it possible to write to an AVAudioPCMBuffer’s floatChannelData after it has been scheduled, and while it is being played?
I’m writing a sampler app with AVFoundation. When it came time to tackle the problem of applying fades to loaded audio files within AVAudioPlayerNodes my first plan was to adjust the volume of the mixer node attached to my player node(s) in real time. This did not seem to have any sort of effect. It is entirely possible that my timing was off when doing this.
When I finally looked at the AKAudioPlayer class, I realized that one could adjust the actual buffer associated with an audio file. After a day or two of debugging, I was able to adapt the code from the AKAudioPlayer class into my PadModel class, with a few minor differences, and it works great.
However, I’m still getting those nasty little clicks whenever I stop one of my Pads from playing before the end of the file because the fades I apply are only in place at the start and the end of the file/buffer.
As far as my first question is concerned, in looking through the AKAudioPlayer class, it appears that the only fades applied to the buffer occur at the beginning and end of the buffer. The stop() method does not appear to apply any sort of on-the-spot fade to the buffer.
In my mind, the only way to have a fade out happen once a stop event happens is to apply it after said stop event, correct?
I have tried doing this, playing a 10 ms long faded-out buffer consisting of the buffer 10 ms after the stop position immediately after I call stop on my player node. It does not have the desired affect. I did not have much confidence in this scheme from the onset, but it seemed worth a try.
To be clear, once my stop() method is called, before actually stopping the the player node, I allocate the 10 ms fade buffer, read into the buffer at the position it is currently at, for the number of frames my fade buffer consists of. I then apply the envelope to the recently allocated fade out buffer, just as it is done in fadeBuffer() method in the AKAudioPlayer class. At this point I finally call stop() on the playing node, then schedule and play the fade out buffer.
Obviously there is going to be a discontinuity between stopping the buffer and playing the fade out buffer, e.g. by the time I apply the fade to the fade out buffer, the stop frame position I assigned to a local variable will no longer be valid, etc. And indeed, once I let off a pad, the sound that is played can only be described as discontinuous.
The only other solution to the problem I can think of strikes me as a daunting task, which would be to continually apply the fade envelope in realtime to the samples immediately ahead of the current play position as the buffer is being played. I currently do not believe I have the coding chops to pull this off.
Anyway, I looked through all the questions on S.O. concerned with AudioKit and this particular subject did not seem to come up. So anybodies thoughts on the matter would be greatly appreciated. Thanks in advance!
If anybody wants to look at my code, the PadModel class starts on line 223 of this file: