这不是交叉衰落操作。但是,这可以通过使用 NSOperation 的新线程一次淡入/淡出一个,并且可以以任何顺序将淡入/淡出效果添加到线程中。
我发现了由 Andrew Mackenzie-Ross 于 2010 年 11 月 30 日创建的 Linear fade Object MXAudioPlayerFadeOperation。
麦克罗斯网。
MXAudioPlayerFadeOperation.h
#import <Foundation/Foundation.h>
@class AVAudioPlayer;
@interface MXAudioPlayerFadeOperation : NSOperation {
AVAudioPlayer *_audioPlayer;
NSTimeInterval _fadeDuration;
NSTimeInterval _delay;
float _finishVolume;
BOOL _pauseAfterFade;
BOOL _stopAfterFade;
BOOL _playBeforeFade;
}
// The AVAudioPlayer that the volume fade will be applied to.
// Retained until the fade is completed.
// Must be set with init method.
@property (nonatomic, strong, readonly) AVAudioPlayer *audioPlayer;
// The duration of the volume fade.
// Default value is 1.0
@property (nonatomic, assign) NSTimeInterval fadeDuration;
// The delay before the volume fade begins.
// Default value is 0.0
@property (nonatomic, assign) NSTimeInterval delay;
// The volume that will be faded to.
// Default value is 0.0
@property (nonatomic, assign) float finishVolume;
// If YES, audio player will be sent a pause message when the fade has completed.
// Default value is NO, however, if finishVolume is 0.0, default is YES
@property (nonatomic, assign) BOOL pauseAfterFade;
// If YES, when the fade has completed the audio player will be sent a stop message.
// Default value is NO.
@property (nonatomic, assign) BOOL stopAfterFade;
// If YES, audio player will be sent a play message after the delay.
// Default value is YES.
@property (nonatomic, assign) BOOL playBeforeFade;
// Init Methods
- (id)initFadeWithAudioPlayer:(AVAudioPlayer*)player toVolume:(float)volume overDuration:(NSTimeInterval)duration withDelay:(NSTimeInterval)timeDelay;
- (id)initFadeWithAudioPlayer:(AVAudioPlayer*)player toVolume:(float)volume overDuration:(NSTimeInterval)duration;
- (id)initFadeWithAudioPlayer:(AVAudioPlayer*)player toVolume:(float)volume;
- (id)initFadeWithAudioPlayer:(AVAudioPlayer*)player;
@end
MXAudioPlayerFadeOperation.m
#import "MXAudioPlayerFadeOperation.h"
#import <AVFoundation/AVFoundation.h>
#define SKVolumeChangesPerSecond 15
@interface MXAudioPlayerFadeOperation ()
- (void)beginFadeOperation;
- (void)finishFadeOperation;
@end
@implementation MXAudioPlayerFadeOperation
#pragma mark -
#pragma mark Properties
@synthesize audioPlayer = _audioPlayer;
@synthesize fadeDuration = _fadeDuration;
@synthesize finishVolume = _finishVolume;
@synthesize playBeforeFade = _playBeforeFade;
@synthesize pauseAfterFade = _pauseAfterFade;
@synthesize stopAfterFade = _stopAfterFade;
@synthesize delay = _delay;
#pragma mark -
#pragma mark Accessors
- (AVAudioPlayer *)audioPlayer {
AVAudioPlayer *result;
@synchronized(self) {
result = _audioPlayer;
}
return result;
}
- (void)setAudioPlayer:(AVAudioPlayer *)anAudioPlayer {
@synchronized(self) {
if (_audioPlayer != anAudioPlayer) {
_audioPlayer = nil;
_audioPlayer = anAudioPlayer;
}
}
}
#pragma mark -
#pragma mark NSOperation
-(id) initFadeWithAudioPlayer:(AVAudioPlayer*)player toVolume:(float)volume overDuration:(NSTimeInterval)duration withDelay:(NSTimeInterval)timeDelay {
if (self = [super init]) {
self.audioPlayer = player;
[player prepareToPlay];
_fadeDuration = duration;
_finishVolume = volume;
_playBeforeFade = YES;
_stopAfterFade = NO;
_pauseAfterFade = (volume == 0.0) ? YES : NO;
_delay = timeDelay;
}
return self;
}
- (id)initFadeWithAudioPlayer:(AVAudioPlayer*)player toVolume:(float)volume overDuration:(NSTimeInterval)duration {
return [self initFadeWithAudioPlayer:player toVolume:volume overDuration:duration withDelay:0.0];
}
- (id)initFadeWithAudioPlayer:(AVAudioPlayer*)player toVolume:(float)volume {
return [self initFadeWithAudioPlayer:player toVolume:volume overDuration:1.0];
}
- (id)initFadeWithAudioPlayer:(AVAudioPlayer*)player {
return [self initFadeWithAudioPlayer:player toVolume:0.0];
}
- (id) init {
NSLog(@"Failed to init class (%@) with AVAudioPlayer instance, use initFadeWithAudioPlayer:",[self class]);
return nil;
}
- (void)main {
@autoreleasepool {
[NSThread sleepForTimeInterval:_delay];
if ([self.audioPlayer isKindOfClass:[AVAudioPlayer class]]) {
[self beginFadeOperation];
}
else {
NSLog(@"AudioPlayerFadeOperation began with invalid AVAudioPlayer");
}
}
}
- (void)beginFadeOperation {
if (![self.audioPlayer isPlaying] && _playBeforeFade) [self.audioPlayer play];
if (_fadeDuration != 0.0) {
NSTimeInterval sleepInterval = (1.0 / SKVolumeChangesPerSecond);
NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];
NSTimeInterval now = startTime;
float startVolume = [self.audioPlayer volume];
while (now < (startTime + _fadeDuration)) {
float ratioOfFadeCompleted = (now - startTime)/_fadeDuration;
float volume = (_finishVolume * ratioOfFadeCompleted) + (startVolume * (1-ratioOfFadeCompleted));
[self.audioPlayer setVolume:volume];
[NSThread sleepForTimeInterval:sleepInterval];
now = [[NSDate date] timeIntervalSinceReferenceDate];
}
[self.audioPlayer setVolume:_finishVolume];
[self finishFadeOperation];
}
else {
[self.audioPlayer setVolume:_finishVolume];
[self finishFadeOperation];
}
}
- (void)finishFadeOperation {
if ([self.audioPlayer isPlaying] && _pauseAfterFade) [self.audioPlayer pause];
if ([self.audioPlayer isPlaying] && _stopAfterFade) [self.audioPlayer stop];
}
@end
带有使用 AudioManagerController 的示例
AudioManagerController.h
/*
* Hedgewars-iOS, a Hedgewars port for iOS devices
* Copyright (c) 2009-2011 Vittorio Giovara <vittorio.giovara@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* File created on 23/09/2011.
*/
#import <Foundation/Foundation.h>
@interface AudioManagerController : NSObject {
}
+(void) playBackgroundMusic;
+(void) pauseBackgroundMusic;
+(void) stopBackgroundMusic;
+(void) fadeInBackgroundMusic;
+(void) fadeOutBackgroundMusic;
+(void) playClickSound;
+(void) playBackSound;
+(void) playSelectSound;
+(void) releaseCache;
@end
AudioManagerController.m
/*
* Hedgewars-iOS, a Hedgewars port for iOS devices
* Copyright (c) 2009-2011 Vittorio Giovara <vittorio.giovara@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* File created on 23/09/2011.
*/
#import "AudioManagerController.h"
#import "AVFoundation/AVAudioPlayer.h"
#import <AudioToolbox/AudioToolbox.h>
#import "MXAudioPlayerFadeOperation.h"
static AVAudioPlayer *backgroundMusic = nil;
static SystemSoundID clickSound = -1;
static SystemSoundID backSound = -1;
static SystemSoundID selSound = -1;
static NSOperationQueue *audioFaderQueue = nil;
static MXAudioPlayerFadeOperation *fadeIn = nil;
static MXAudioPlayerFadeOperation *fadeOut = nil;
@implementation AudioManagerController
#pragma mark -
#pragma mark background music control
+(void) loadBackgroundMusic {
NSString *musicString = [[NSBundle mainBundle] pathForResource:@"hwclassic" ofType:@"mp3"];
backgroundMusic = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:musicString] error:nil];
backgroundMusic.delegate = nil;
backgroundMusic.volume = 0;
backgroundMusic.numberOfLoops = -1;
[backgroundMusic prepareToPlay];
}
+(void) playBackgroundMusic {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"music"] boolValue] == NO)
return;
if (backgroundMusic == nil)
[AudioManagerController loadBackgroundMusic];
backgroundMusic.volume = 0.45f;
[backgroundMusic play];
}
+(void) pauseBackgroundMusic {
[backgroundMusic pause];
}
+(void) stopBackgroundMusic {
[backgroundMusic stop];
}
+(void) fadeOutBackgroundMusic {
if (audioFaderQueue == nil)
audioFaderQueue = [[NSOperationQueue alloc] init];
if (backgroundMusic == nil)
[AudioManagerController loadBackgroundMusic];
if (fadeOut == nil)
fadeOut = [[MXAudioPlayerFadeOperation alloc] initFadeWithAudioPlayer:backgroundMusic toVolume:0.0 overDuration:3.0];
[audioFaderQueue addOperation:fadeOut];
}
+(void) fadeInBackgroundMusic {
if (audioFaderQueue == nil)
audioFaderQueue = [[NSOperationQueue alloc] init];
if (backgroundMusic == nil)
[AudioManagerController loadBackgroundMusic];
if (fadeIn == nil)
fadeIn = [[MXAudioPlayerFadeOperation alloc] initFadeWithAudioPlayer:backgroundMusic toVolume:0.45 overDuration:2.0];
[audioFaderQueue addOperation:fadeIn];
}
#pragma mark -
#pragma mark sound effects control
+(SystemSoundID) loadSound:(NSString *)snd {
// get the filename of the sound file:
NSString *path = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] resourcePath],snd];
// declare a system sound id and get a URL for the sound file
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
// use audio sevices to create and play the sound
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
return soundID;
}
+(void) playClickSound {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"sound"] boolValue] == NO)
return;
if (clickSound == -1)
clickSound = [AudioManagerController loadSound:@"clickSound.wav"];
AudioServicesPlaySystemSound(clickSound);
}
+(void) playBackSound {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"sound"] boolValue] == NO)
return;
if (backSound == -1)
backSound = [AudioManagerController loadSound:@"backSound.wav"];
AudioServicesPlaySystemSound(backSound);
}
+(void) playSelectSound {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"sound"] boolValue] == NO)
return;
if (selSound == -1)
selSound = [AudioManagerController loadSound:@"selSound.wav"];
AudioServicesPlaySystemSound(selSound);
}
#pragma mark -
#pragma mark memory management
+(void) releaseCache {
[backgroundMusic stop];
[backgroundMusic release], backgroundMusic = nil;
[fadeOut release], fadeOut = nil;
[fadeIn release], fadeIn = nil;
[audioFaderQueue release], audioFaderQueue = nil;
AudioServicesDisposeSystemSoundID(clickSound), clickSound = -1;
AudioServicesDisposeSystemSoundID(backSound), backSound = -1;
AudioServicesDisposeSystemSoundID(selSound), selSound = -1;
MSG_MEMCLEAN();
}
@end
参考:对冲战争