5

I want to use AVAudioPlayer and cross fade more than 2 mp3 files.

I have 5 mp3 files and 5 pages "myScrollView" with UIScrollView class and pagingEnabled = YES.

When user move page, I want to play each songs for each page with volume fade out for previous mp3 file and fade in for next mp3.

Please help this problem.

4

2 回答 2

4

这是一个非常古老的线程,但我只是寻找有关交叉淡入淡出问题的解决方案并找到了它。我是这样解决的:

-(void)crossFadePlayerOne:(AVAudioPlayer *)player1 andPlayerTwo:(AVAudioPlayer *)player2 withCompletion:(void(^)())completion{
    if([player1 volume] > 0){
        [player1 setVolume:[player1 volume] - 0.05];
        [player2 setVolume:[player2 volume] + 0.05];

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC),dispatch_get_main_queue(),^{
            [self crossFadePlayerOne:player1 andPlayerTwo:player2 withCompletion:completion];
        });

    }else{
        if(completion){
            completion();
        }
    }
}
于 2015-03-22T18:45:55.820 回答
3

这不是交叉衰落操作。但是,这可以通过使用 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

参考:对冲战争

于 2012-10-02T17:05:56.217 回答