AVAudioPlayer fade observer

I'm new here, and this is my first post. I've been working in Swift for the past 9 or 10 months trying to convert a program I wrote in Python to a native macOS app. I've been doing pretty well reading, following tutorials, and asking questions over at StackOverflow. But, it seems I'm not finding any help with my current issue.

I have written a small app that mimics the scan function of a radio that tunes in a local station and plays the the station for 5-10 seconds. If the user presses the tune (or whichever) button, the tuner stops scanning and continues to play that station. If the user does nothing, the next available station is tuned in and the cycle repeats. I'm sure many of you have used this function of your car stereo.

In my app, I am scanning a playlist within the iTunes Library and a random track is played. I set the volume of the AVAudioPlayer to zero, and then start the track anywhere from 15-20 seconds into the track by setting the AVAudioPlayer.currentTime property and then use the .setVolume(_:fadeDuration:) method to fade in the track. Regardless of any interaction from the user (none, or click play to end button) I want the current track to fade out before moving on to the next track.

The issue I am having is the .setVolume(_:fadeDuration:) immediately reports the volume as zero on a subsequent call, regardless of the fadeDuration value as shown in this example Playground code:

import AVFoundation

let url = URL(fileURLWithPath: "/Users/Shared/Sample.mp3")
var player = AVAudioPlayer()
do {
    player = try AVAudioPlayer(contentsOf: url)
} catch {
    print("An error, \(error), occurred.")
// Set the time index to start playback
let startTime:TimeInterval = 20
// Set the fade duration
let fadeTime:TimeInterval = 10
player.currentTime = startTime
player.volume = 0
player.setVolume(1, fadeDuration: fadeTime)
print(player.volume) // Shows 1 immediately
// Let the track play for 15 seconds
sleep(15) // Allows the track to play at full volume for 5 seconds)
player.setVolume(0, fadeDuration: 10)
print(player.volume) // Shows 0 immediately
if player.volume == 0 { // Shouldn't execute if volume is being ramped by the setVolume method

I would like to extend AVAudioPlayer to observe the fade ramp status if that is possible.

I wouldn't implement this exactly as written so it doesn't block the main thread, but I want the ability to do something like:

var fading:Bool = player.fading
while fading {
    fading = player.fading

The other option I was thinking of was to create a timer that exists for the duration of the fade, but felt that was not 'clean' or 'Swiftly.'

Thoughts? Suggestions?

I forgot to mention that I found a very old blog post from 2011 by Pete Goodliffe where he created a fader for AVAudioPlayer in Objective-C, I guess before that functionality existed in AVAudioPlayer, and it appears he was observing the fade ramp. However, I do not know Objective-C in order to try and convert this to a swift extension and implement it in a Swiftly manner.

This is really about Apple frameworks, not Swift. You might have better luck over on the Apple Audio frameworks Developer forums or another Apple developer-oriented web site.

Terms of Service

Privacy Policy

Cookie Policy