2

I have a sound file which listens as beep sound and I have to play this sound repeatedly with changing its pitch depending on some condition. I am using AVAudioEngine, AVAudioPlayerNode, and AVAudioUnitTimePitch to achieve this objective. There are two buttons in my view namely Play and Stop. When I press on the Play button for the first time, the sound is playing repeatedly but after clicking on the Stop button once and then again clicking on the Play button, the sound is not playing and giving no errors as well. I have been looking into this issue for a long time but unable to get the solution and I came here. Could you please help me to fix this issue. Or are there any other alternate solutions for my problem? My code is as below:

import UIKit
import AVFoundation

class ViewController: UIViewController {

    let engine = AVAudioEngine()
    let audioPlayer = AVAudioPlayerNode()
    let pitchUnit = AVAudioUnitTimePitch()

    var avAudioFile: AVAudioFile!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let path = Bundle.main.path(forResource: "Beep", ofType: "wav")!
        let url = NSURL.init(fileURLWithPath: path)
        avAudioFile = try? AVAudioFile(forReading: url as URL)

        setup()
    }

    func setup() {
        engine.attach(audioPlayer)
        engine.attach(pitchUnit)
        engine.connect(audioPlayer, to: pitchUnit, format: nil)
        engine.connect(pitchUnit, to:engine.mainMixerNode, format: nil)

        try? engine.start()

        audioPlayer.volume = 1.0
        audioPlayer.play()

    }
    @IBAction func playSound(_ sender: UIButton) {

        pitchUnit.pitch = 1

        // interrupt playing sound if you have to
        if audioPlayer.isPlaying {
            audioPlayer.stop()
            audioPlayer.play()
        }
        let buffer = AVAudioPCMBuffer(pcmFormat: avAudioFile.processingFormat, frameCapacity: AVAudioFrameCount(avAudioFile.length))
        try? avAudioFile.read(into: buffer!)
        audioPlayer.scheduleBuffer(buffer!, at: nil, options: AVAudioPlayerNodeBufferOptions.loops, completionHandler: nil)
    }

    @IBAction func stopSound(_ sender: UIButton) {
        audioPlayer.stop()
    }
}
Simant
  • 3,142
  • 4
  • 32
  • 61
  • Is it always the same sound? You know you don't need to restart the sound to change its pitch. Also you might want to be using `pitchUnit.rate` instead of `pitch`, which is in 1200ths of an octave. – Rhythmic Fistman Apr 23 '18 at 11:43
  • @RhythmicFistman Yes, it is the same sound but if the distance of the device is like within 5 meters from some point, it plays beep sound and when one is getting closer to the point it increases pitch or rate and when goes away than 5 meters the sound stops. I was getting the problem to restart the sound once the device comes back in the range of 5 meters. – Simant Apr 23 '18 at 13:02

1 Answers1

0

The problem lies in your playSound func.

// interrupt playing sound if you have to
if audioPlayer.isPlaying {
    audioPlayer.stop()
    audioPlayer.play()
}

You are trying to play the player only if its already playing. so that doesnt make any sense. you can remove these lines and can simply use just this.

 audioPlayer.play()
Satizh J
  • 307
  • 4
  • 14