AVAudioPlayer attenuates the volume

I have AVAudioPlayer playing some sound (duh!)

The sound starts when the user presses a button. When they let it go, I want the sound to fade.

I use the interface builder ... so I'm trying to connect the "touch inward" function, which fades out the audio after 1 second and then stops.

Any ideas?

thank

+44
iphone avaudioplayer volume
Aug 01 '09 at 13:24
source share
11 answers

Here is how I do it:

-(void)doVolumeFade { if (self.player.volume > 0.1) { self.player.volume = self.player.volume - 0.1; [self performSelector:@selector(doVolumeFade) withObject:nil afterDelay:0.1]; } else { // Stop and get the sound ready for playing again [self.player stop]; self.player.currentTime = 0; [self.player prepareToPlay]; self.player.volume = 1.0; } } 
+116
Nov 03 '09 at 14:10
source share

I solved this problem using a subclass of NSOperation, so volume attenuation does not block the main thread. It also allows you to fade out in line and forget. This is especially useful for reproducing the sounds of a single picture with fade and fade effects, as they are released after the last fade is completed.

 // Example of MXAudioPlayerFadeOperation in NSOperationQueue NSOperationQueue *audioFaderQueue = [[NSOperationQueue alloc] init]; [audioFaderQueue setMaxConcurrentOperationCount:1]; // Execute fades serially. NSString *filePath = [[NSBundle mainBundle] pathForResource:@"bg" ofType:@"mp3"]; // path to bg.mp3 AVAudioPlayer *player = [[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath] error:NULL] autorelease]; [player setNumberOfLoops:-1]; [player setVolume:0.0]; // Note that delay is delay after last fade due to the Operation Queue working serially. MXAudioPlayerFadeOperation *fadeIn = [[MXAudioPlayerFadeOperation alloc] initFadeWithAudioPlayer:player toVolume:1.0 overDuration:3.0]; [fadeIn setDelay:2.0]; MXAudioPlayerFadeOperation *fadeDown = [[MXAudioPlayerFadeOperation alloc] initFadeWithAudioPlayer:player toVolume:0.1 overDuration:3.0]; [fadeDown setDelay:0.0]; MXAudioPlayerFadeOperation *fadeUp = [[MXAudioPlayerFadeOperation alloc] initFadeWithAudioPlayer:player toVolume:1.0 overDuration:4.0]; [fadeUp setDelay:0.0]; MXAudioPlayerFadeOperation *fadeOut = [[MXAudioPlayerFadeOperation alloc] initFadeWithAudioPlayer:player toVolume:0.0 overDuration:3.0]; [fadeOut setDelay:2.0]; [audioFaderQueue addOperation:fadeIn]; // 2.0s - 5.0s [audioFaderQueue addOperation:fadeDown]; // 5.0s - 8.0s [audioFaderQueue addOperation:fadeUp]; // 8.0s - 12.0s [audioFaderQueue addOperation:fadeOut]; // 14.0s - 17.0s [fadeIn release]; [fadeDown release]; [fadeUp release]; [fadeOut release]; 

For MXAudioPlayerFadeOperation class code, see this post .

+16
Dec 01 2018-10-12T00:
source share

Swift has an AVAudioPlayer method that you can use to fade, which was included as iOS 10.0 :

 var audioPlayer = AVAudioPlayer() ... audioPlayer.setVolume(0, fadeDuration: 3) 
+14
Dec 01 '16 at 10:35
source share

In the end, I combined the response part and converted it in Swift to this method:

 func fadeVolumeAndPause(){ if self.player?.volume > 0.1 { self.player?.volume = self.player!.volume - 0.1 var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) dispatch_after(dispatchTime, dispatch_get_main_queue(), { self.fadeVolumeAndPause() }) } else { self.player?.pause() self.player?.volume = 1.0 } } 
+9
Mar 02 '15 at 12:43 on
source share

These are all good answers, but they do not concern the indication of the decay rate (or the application of the logarithmic curve to the decay, which is sometimes desirable), or specifying the amount of dB reduction from one that you disappear to.

this is an exception from one of my applications, with the removal of several "bells and whistles" that are not relevant to this issue.

enjoy it!

 #define linearToDecibels(linear) (MIN(10,MAX(-100,20.0 * log10(linear)))) #define decibelsToLinear(decibels) (pow (10, (0.05 * decibels))) #define fadeInfoId(n) [fadeInfo objectForKey:@#n] #define fadeInfoObject(NSObject,n) ((NSObject*) fadeInfoId(n)) #define fadeInfoFloat(n) [fadeInfoId(n) floatValue] #define useFadeInfoObject(n) * n = fadeInfoId(n) #define useFadeInfoFloat(n) n = fadeInfoFloat(n) #define setFadeInfoId(n,x) [fadeInfo setObject:x forKey:@#n] #define setFadeInfoFloat(n,x) setFadeInfoId(n,[NSNumber numberWithFloat:x]) #define setFadeInfoFlag(n) setFadeInfoId(n,[NSNumber numberWithBool:YES]) #define saveFadeInfoId(n) setFadeInfoId(n,n) #define saveFadeInfoFloat(n) setFadeInfoFloat(n,n) #define fadeAVAudioPlayer_default nil #define fadeAVAudioPlayer_linearFade @"linearFade" #define fadeAVAudioPlayer_fadeToStop @"fadeToStop" #define fadeAVAudioPlayer_linearFadeToStop @"linearFadeToStop" -(void) fadeAVAudioPlayerTimerEvent:(NSTimer *) timer { NSMutableDictionary *fadeInfo = timer.userInfo; NSTimeInterval elapsed = 0 - [fadeInfoObject(NSDate,startTime) timeIntervalSinceNow]; NSTimeInterval useFadeInfoFloat(fadeTime); float useFadeInfoFloat(fadeToLevel); AVAudioPlayer useFadeInfoObject(player); double linear; if (elapsed>fadeTime) { if (fadeInfoId(stopPlaybackAtFadeTime)) { [player stop]; linear = fadeInfoFloat(fadeFromLevel); } else { linear = fadeToLevel; } [timer invalidate]; [fadeInfo release]; } else { if (fadeInfoId(linearCurve)) { float useFadeInfoFloat(fadeFromLevel); float fadeDelta = fadeToLevel-fadeFromLevel; linear = fadeFromLevel + (fadeDelta * (elapsed/fadeTime)); } else { float useFadeInfoFloat(fadeToDB); float useFadeInfoFloat(fadeFromDB); float fadeDelta = fadeToDB-fadeFromDB; float decibels = fadeFromDB + (fadeDelta * (elapsed/fadeTime)); linear = decibelsToLinear(decibels); } } [player setVolume: linear]; //[self displayFaderLevelForMedia:player]; //[self updateMediaVolumeLabel:player]; } -(void) fadeAVAudioPlayerLinear:(AVAudioPlayer *)player over:(NSTimeInterval) fadeTime fadeToLevel:(float) fadeToLevel fadeMode:(NSString*)fadeMode { NSMutableDictionary *fadeInfo = [[NSMutableDictionary alloc ]init]; saveFadeInfoId(player); float fadeFromLevel = player.volume;// to optimize macros put value in var, so we don't call method 3 times. float fadeFromDB = linearToDecibels(fadeFromLevel); float fadeToDB = linearToDecibels(fadeToLevel); saveFadeInfoFloat(fadeFromLevel); saveFadeInfoFloat(fadeToLevel); saveFadeInfoFloat(fadeToDB); saveFadeInfoFloat(fadeFromDB); saveFadeInfoFloat(fadeTime); setFadeInfoId(startTime,[NSDate date]); if([fadeMode isEqualToString:fadeAVAudioPlayer_fadeToStop]||[fadeMode isEqualToString:fadeAVAudioPlayer_linearFadeToStop]){ setFadeInfoFlag(stopPlaybackAtFadeTime); } if([fadeMode isEqualToString:fadeAVAudioPlayer_linearFade]||[fadeMode isEqualToString:fadeAVAudioPlayer_linearFadeToStop]){ setFadeInfoFlag(linearCurve); } [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(fadeAVAudioPlayerTimerEvent:) userInfo:fadeInfo repeats:YES]; } -(void) fadeAVAudioPlayer:(AVAudioPlayer *)player over:(NSTimeInterval) fadeTime fadeToDB:(float) fadeToDB fadeMode:(NSString*)fadeMode { [self fadeAVAudioPlayerLinear:player over:fadeTime fadeToLevel:decibelsToLinear(fadeToDB) fadeMode:fadeMode ]; } -(void) fadeoutAVAudioPlayer:(AVAudioPlayer *)player { [self fadeAVAudioPlayerLinear:player over:5.0 fadeToLevel:0 fadeMode:fadeAVAudioPlayer_default]; } -(void) fadeinAVAudioPlayer:(AVAudioPlayer *)player { [self fadeAVAudioPlayerLinear:player over:5.0 fadeToLevel:0 fadeMode:fadeAVAudioPlayer_default]; } 
+8
Sep 29 '11 at 10:44
source share

I wrote a helper class in Swift to damp AvAudioPlayer inputs and outputs. You can use the logarithmic function of the volume for a more gradual fading effect.

 let player = AVAudioPlayer(contentsOfURL: soundURL, error: nil) let fader = iiFaderForAvAudioPlayer(player: player) fader.fadeIn() fader.fadeOut() 

Here is a demo application: https://github.com/evgenyneu/sound-fader-ios

+4
Dec 31 '15 at 9:37
source share

It seems to me that this is the descent of NSOperationQueue.

Therefore, this is my solution:

 -(void) fadeIn { if (self.currentPlayer.volume >= 1.0f) return; else { self.currentPlayer.volume+=0.10; __weak typeof (self) weakSelf = self; [NSThread sleepForTimeInterval:0.2f]; [self.fadingQueue addOperationWithBlock:^{ NSLog(@"fading in %.2f", self.currentPlayer.volume); [weakSelf fadeIn]; }]; } } -(void) fadeOut { if (self.currentPlayer.volume <= 0.0f) return; else { self.currentPlayer.volume -=0.1; __weak typeof (self) weakSelf = self; [NSThread sleepForTimeInterval:0.2f]; [self.fadingQueue addOperationWithBlock:^{ NSLog(@"fading out %.2f", self.currentPlayer.volume); [weakSelf fadeOut]; }]; } } 
+2
May 11 '14 at 14:13
source share

Extension for swift 3 , inspired by the most voted answer. For those of you who like to copy :)

 extension AVAudioPlayer { func fadeOut() { if volume > 0.1 { // Fade volume -= 0.1 perform(#selector(fadeOut), with: nil, afterDelay: 0.1) } else { // Stop and get the sound ready for playing again stop() prepareToPlay() volume = 1 } } } 
+2
Sep 28 '16 at 2:00
source share

Swift 3

I like Ambroise Collon's answer, so I voted, but Swift is statically typed, so the performSelector : methods should fall on the sidelines, maybe sending async as an alternative (in this version I also added the destination as a parameter)

 func dispatchDelay(delay:Double, closure:@escaping ()->()) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: closure) } extension AVAudioPlayer { func fadeOut(vol:Float) { if volume > vol { //print("vol is : \(vol) and volume is: \(volume)") dispatchDelay(delay: 0.1, closure: { [weak self] in guard let strongSelf = self else { return } strongSelf.volume -= 0.01 strongSelf.fadeOut(vol: vol) }) } else { volume = vol } } func fadeIn(vol:Float) { if volume < vol { dispatchDelay(delay: 0.1, closure: { [weak self] in guard let strongSelf = self else { return } strongSelf.volume += 0.01 strongSelf.fadeIn(vol: vol) }) } else { volume = vol } } } 
+2
Oct 01 '16 at 17:02
source share

How about this: (if the time has passed negatively, then the sound will go out, otherwise it will disappear)

 - (void) fadeInOutVolumeOverTime: (NSNumber *)time { #define fade_out_steps 0.1 float theVolume = player.volume; NSTimeInterval theTime = [time doubleValue]; int sign = (theTime >= 0) ? 1 : -1; // before we call this, if we are fading out, we save the volume // so that we can restore back to that level in the fade in if ((sign == 1) && ((theVolume >= savedVolume) || (theTime == 0))) { player.volume = savedVolume; } else if ((sign == -1) && (theVolume <= 0)) { NSLog(@"fading"); [player pause]; [self performSelector:@selector(fadeInOutVolumeOverTime:) withObject:[NSNumber numberWithDouble:0] afterDelay:1.0]; } else { theTime *= fade_out_steps; player.volume = theVolume + fade_out_steps * sign; [self performSelector:@selector(fadeInOutVolumeOverTime:) withObject:time afterDelay:fabs(theTime)]; } } 
+1
Aug 03 '09 at 9:55
source share

Swift Solution :

The highest rating here is excellent, but it gives the effect of stuttering, since a step of 0.1 is too much. Using 0.01 gives a smoother fading effect.

Using this code, you can specify how long you want the last transition to disappear.

 let fadeVolumeStep: Float = 0.01 let fadeTime = 0.5 // Fade time in seconds var fadeVolumeStepTime: Double { return fadeTime / Double(1.0 / fadeVolumeStep) } func fadeOut() { guard let player = self.player else { return } if !player.playing { return } func fadeOutPlayer() { if player.volume > fadeVolumeStep { player.volume -= fadeVolumeStep delay(time: fadeVolumeStepTime, closure: { fadeOutPlayer() }) } else { player.stop() player.currentTime = 0 player.prepareToPlay() } } fadeOutPlayer() } func fadeIn() { guard let player = self.player else { return } if player.playing { return } player.volume = 0 player.play() func fadeInPlayer() { if player.volume <= 1 - fadeVolumeStep { player.volume += fadeVolumeStep delay(time: fadeVolumeStepTime, closure: { fadeInPlayer() }) } else { player.volume = 1 } } fadeInPlayer() } func delay(time delay:Double, closure:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure) } 

You can adjust the time using the fadeTime constant.

+1
Aug 22 '16 at 8:42 on
source share



All Articles