project_files/HedgewarsMobile/Classes/MXAudioPlayerFadeOperation.m
author nemo
Wed, 09 Aug 2017 12:46:52 -0400
changeset 12446 48ee3777e42e
parent 11137 14f50dde3e8c
child 12872 00215a7ec5f5
permissions -rw-r--r--
trying to eliminate that annoying impact sound for gears that are well under the water and not even exiting it. sheepluva might want to look this over since this is modifying his code and should perhaps be part of the addSplashForGear checks, but hadn't had much luck getting him to examine it past year or so

//  MXAudioPlayerFadeOperation.m
//
//  Created by Andrew Mackenzie-Ross on 30/11/10.
//  mackross.net.
//

#import "MXAudioPlayerFadeOperation.h"
#import <AVFoundation/AVFoundation.h>

#define SKVolumeChangesPerSecond 15

@interface MXAudioPlayerFadeOperation ()
@property (nonatomic, retain, readwrite) AVAudioPlayer *audioPlayer;
- (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 retain];
  }
  return [result autorelease];
}

- (void)setAudioPlayer:(AVAudioPlayer *)anAudioPlayer {
  @synchronized(self) {
    if (_audioPlayer != anAudioPlayer) {
      [_audioPlayer release];
      _audioPlayer = [anAudioPlayer retain];
    }
  }
}

#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 {
  ALog(@"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 {
    ALog(@"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];
}

- (void)dealloc {
  releaseAndNil(_audioPlayer);
  [super dealloc];
}

@end