AVAudioPlayer淡出音量

我有一个AVAudioPlayer播放一些audio(杜!)

audio在用户按下button时启动。 当他们释放它,我想audio淡出。

我正在使用接口生成器…所以我试图挂钩一个function“触摸里面”,淡出audio超过1秒,然后停止。

有任何想法吗?

谢谢

以下是我如何做到这一点:

-(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; } } 

我使用NSOperation子类来解决这个问题,所以淡出音量不会阻塞主线程。 它也允许淡入淡出,并被遗忘。 这对于在最后一个淡入淡出完成之后处理淡入和淡出效果的单曲声音特别有用。

 // 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]; 

对于MXAudioPlayerFadeOperation类代码,请参阅这篇文章 。

Swift有一个AVAudioPlayer方法,你可以使用它作为iOS 10.0包含的淡出function:

 var audioPlayer = AVAudioPlayer() ... audioPlayer.setVolume(0, fadeDuration: 3) 

我结束了一些答案的结合,并将其转换为Swift结束在这种方法:

 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 } } 

这些都是很好的答案,但是它们并不涉及指定渐变的速率(或者将渐变的对数曲线应用到某个渐变中,这有时是可取的),或者指定从渐变的单位中减去dB的数量。

这是一个除了我的应用程序之一,删除了一些“花里胡哨”,这是不相关的这个问题。

请享用!

 #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]; } 

我在Swift中编写了一个帮助类,用于淡入淡出AvAudioPlayer 。 您可以使用对数音量函数来获得更渐进的衰落效果。

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

这里有一个演示应用程序: https : //github.com/evgenyneu/sound-fader-ios

这在我看来是一个NSOperationQueue的下降使用。

因此,这是我的解决scheme:

 -(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]; }]; } } 

从最受投票的答案启发迅速3的延伸。 对于那些喜欢复制粘贴:)

 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 } } } 

Swift 3

我喜欢Ambroise Collon的答案,所以我投票了,但Swift静态types,所以performSelector :方法将在路边,也许替代可能是调度asynchronous(在这个版本中,我也添加了目标卷作为参数)

 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 } } } 

怎么样(如果时间stream逝是负面的,那么淡出声音,否则淡入)

 - (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)]; } } 

Swift解决scheme:

这里评分最高的答案很好,但是由于0.1的体积步数太大,会产生口吃效果。 使用0.01会使听起来更平滑的淡入淡出效果。

使用此代码,您可以指定要淡入淡出过渡到最后的时间。

 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) } 

您可以使用fadeTime常量调整时间。