project_files/HedgewarsMobile/Classes/MXAudioPlayerFadeOperation.m
author Wuzzy <almikes@aol.com>
Wed, 04 Oct 2017 18:34:02 +0200
changeset 12644 59b46e6f36ff
parent 11137 14f50dde3e8c
child 12872 00215a7ec5f5
permissions -rw-r--r--
Fix Birdy descending into water if hog took damage before it got picked up (bug #160)

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