2016-08-14 13 views
6

Opracowuję aplikację, dzięki której można nagrywać i zmieniać głosy za pośrednictwem aplikacji i udostępniać je. Zasadniczo tak wiele rzeczy, a teraz czas poprosić cię o pomoc. Oto moja funkcja odtwarzania, która odtwarza nagrany plik audio i dodaje na nim efekty.Zapisywanie dźwięku po Efektach w iOS

private func playAudio(pitch : Float, rate: Float, reverb: Float, echo: Float) { 
     // Initialize variables 
     audioEngine = AVAudioEngine() 
     audioPlayerNode = AVAudioPlayerNode() 
     audioEngine.attachNode(audioPlayerNode) 

     // Setting the pitch 
     let pitchEffect = AVAudioUnitTimePitch() 
     pitchEffect.pitch = pitch 
     audioEngine.attachNode(pitchEffect) 

     // Setting the platback-rate 
     let playbackRateEffect = AVAudioUnitVarispeed() 
     playbackRateEffect.rate = rate 
     audioEngine.attachNode(playbackRateEffect) 

     // Setting the reverb effect 
     let reverbEffect = AVAudioUnitReverb() 
     reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral) 
     reverbEffect.wetDryMix = reverb 
     audioEngine.attachNode(reverbEffect) 

     // Setting the echo effect on a specific interval 
     let echoEffect = AVAudioUnitDelay() 
     echoEffect.delayTime = NSTimeInterval(echo) 
     audioEngine.attachNode(echoEffect) 

     // Chain all these up, ending with the output 
     audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil) 
     audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil) 
     audioEngine.connect(pitchEffect, to: reverbEffect, format: nil) 
     audioEngine.connect(reverbEffect, to: echoEffect, format: nil) 
     audioEngine.connect(echoEffect, to: audioEngine.outputNode, format: nil) 

     audioPlayerNode.stop() 

     let length = 4000 
     let buffer = AVAudioPCMBuffer(PCMFormat: audioPlayerNode.outputFormatForBus(0),frameCapacity:AVAudioFrameCount(length)) 
     buffer.frameLength = AVAudioFrameCount(length) 

     try! audioEngine.start() 


     let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] 
     let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound.m4a")) 


     do{ 
      print(dirPaths) 
      let settings = [AVFormatIDKey: NSNumber(unsignedInt: kAudioFormatMPEG4AAC), AVSampleRateKey: NSNumber(integer: 44100), AVNumberOfChannelsKey: NSNumber(integer: 2)] 
      self.newAudio = try AVAudioFile(forWriting: tmpFileUrl, settings: settings) 

      audioEngine.outputNode.installTapOnBus(0, bufferSize: (AVAudioFrameCount(self.player!.duration)), format: self.audioPlayerNode.outputFormatForBus(0)){ 
       (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in 

       print(self.newAudio.length) 
       print("=====================") 
       print(self.audioFile.length) 
       print("**************************") 
       if (self.newAudio.length) < (self.audioFile.length){ 

        do{ 
         //print(buffer) 
         try self.newAudio.writeFromBuffer(buffer) 
        }catch _{ 
         print("Problem Writing Buffer") 
        } 
       }else{ 
        self.audioPlayerNode.removeTapOnBus(0) 
       } 

      } 
     }catch _{ 
      print("Problem") 
     } 

     audioPlayerNode.play() 

    } 

Myślę, że problemem jest to, jestem installTapOnBus do audioPlayerNode ale dokonanej audio jest na audioEngine.outputNode .Jednak próbowałem installTapOnBus do audioEngine.outputNode ale daje mi error.Also Próbowałem połączyć efekty do audioEngine.mixerNode, ale nie jest to również rozwiązanie. Czy masz jakieś doświadczenia z zapisywaniem pliku audio? Jak mogę uzyskać ten efekt audio?

Każda pomoc jest mile widziana

Dziękuję

Odpowiedz

4

Tu jest moje rozwiązanie na pytanie:

func playAndRecord(pitch : Float, rate: Float, reverb: Float, echo: Float) { 
    // Initialize variables 

// These are global variables . if you want you can just (let audioEngine = etc ..) init here these variables 
    audioEngine = AVAudioEngine() 
    audioPlayerNode = AVAudioPlayerNode() 
    audioEngine.attachNode(audioPlayerNode) 
    playerB = AVAudioPlayerNode() 

    audioEngine.attachNode(playerB) 

    // Setting the pitch 
    let pitchEffect = AVAudioUnitTimePitch() 
    pitchEffect.pitch = pitch 
    audioEngine.attachNode(pitchEffect) 

    // Setting the platback-rate 
    let playbackRateEffect = AVAudioUnitVarispeed() 
    playbackRateEffect.rate = rate 
    audioEngine.attachNode(playbackRateEffect) 

    // Setting the reverb effect 
    let reverbEffect = AVAudioUnitReverb() 
    reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral) 
    reverbEffect.wetDryMix = reverb 
    audioEngine.attachNode(reverbEffect) 

    // Setting the echo effect on a specific interval 
    let echoEffect = AVAudioUnitDelay() 
    echoEffect.delayTime = NSTimeInterval(echo) 
    audioEngine.attachNode(echoEffect) 

    // Chain all these up, ending with the output 
    audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil) 
    audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil) 
    audioEngine.connect(pitchEffect, to: reverbEffect, format: nil) 
    audioEngine.connect(reverbEffect, to: echoEffect, format: nil) 
    audioEngine.connect(echoEffect, to: audioEngine.mainMixerNode, format: nil) 


    // Good practice to stop before starting 
    audioPlayerNode.stop() 

    // Play the audio file 
// this player is also a global variable AvAudioPlayer 
    if(player != nil){ 
    player?.stop() 
    } 

    // audioFile here is our original audio 
    audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: { 
     print("Complete") 
    }) 


    try! audioEngine.start() 


    let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] 
    let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound2.m4a")) 

//Save the tmpFileUrl into global varibale to not lose it (not important if you want to do something else) 
filteredOutputURL = tmpFileUrl 

    do{ 
     print(dirPaths) 

     self.newAudio = try! AVAudioFile(forWriting: tmpFileUrl, settings: [ 
      AVFormatIDKey: NSNumber(unsignedInt:kAudioFormatAppleLossless), 
      AVEncoderAudioQualityKey : AVAudioQuality.Low.rawValue, 
      AVEncoderBitRateKey : 320000, 
      AVNumberOfChannelsKey: 2, 
      AVSampleRateKey : 44100.0 
      ]) 

     let length = self.audioFile.length 


     audioEngine.mainMixerNode.installTapOnBus(0, bufferSize: 1024, format: self.audioEngine.mainMixerNode.inputFormatForBus(0)) { 
      (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in 


      print(self.newAudio.length) 
      print("=====================") 
      print(length) 
      print("**************************") 

      if (self.newAudio.length) < length {//Let us know when to stop saving the file, otherwise saving infinitely 

       do{ 
        //print(buffer) 
        try self.newAudio.writeFromBuffer(buffer) 
       }catch _{ 
        print("Problem Writing Buffer") 
       } 
      }else{ 
       self.audioEngine.mainMixerNode.removeTapOnBus(0)//if we dont remove it, will keep on tapping infinitely 

       //DO WHAT YOU WANT TO DO HERE WITH EFFECTED AUDIO 

      } 

     } 
    }catch _{ 
     print("Problem") 
    } 

    audioPlayerNode.play() 

} 
+1

- czy możemy zapisać plik dźwiękowy z efektami –

+0

Chcesz tylko zapisać nowo utworzony plik audio. powyższy kod również odtwarza plik. czy mimo to mogę przestać odtwarzać dźwięk podczas miksowania dźwięku? –

4

To nie wydaje się być podłączone prawidłowo. Sam się tego wszystkiego nauczyłem, ale odkryłem, że efekty są poprawne, gdy podłączasz je do węzła miksera. Ponadto, będziesz chciał dotknąć miksera, a nie węzła wyjściowego silnika. Właśnie skopiowałem twój kod i wprowadziłem kilka modyfikacji, aby wziąć to pod uwagę.

private func playAudio(pitch : Float, rate: Float, reverb: Float, echo: Float) { 
    // Initialize variables 
    audioEngine = AVAudioEngine() 
    audioPlayerNode = AVAudioPlayerNode() 
    audioEngine.attachNode(audioPlayerNode) 

    // Setting the pitch 
    let pitchEffect = AVAudioUnitTimePitch() 
    pitchEffect.pitch = pitch 
    audioEngine.attachNode(pitchEffect) 

    // Setting the playback-rate 
    let playbackRateEffect = AVAudioUnitVarispeed() 
    playbackRateEffect.rate = rate 
    audioEngine.attachNode(playbackRateEffect) 

    // Setting the reverb effect 
    let reverbEffect = AVAudioUnitReverb() 
    reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral) 
    reverbEffect.wetDryMix = reverb 
    audioEngine.attachNode(reverbEffect) 

    // Setting the echo effect on a specific interval 
    let echoEffect = AVAudioUnitDelay() 
    echoEffect.delayTime = NSTimeInterval(echo) 
    audioEngine.attachNode(echoEffect) 

    // Set up a mixer node 
    let audioMixer = AVAudioMixerNode() 
    audioEngine.attachNode(audioMixer) 

    // Chain all these up, ending with the output 
    audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil) 
    audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil) 
    audioEngine.connect(pitchEffect, to: reverbEffect, format: nil) 
    audioEngine.connect(reverbEffect, to: echoEffect, format: nil) 
    audioEngine.connect(echoEffect, to: audioMixer, format: nil) 
    audioEngine.connect(audioMixer, to: audioEngine.outputNode, format: nil) 

    audioPlayerNode.stop() 

    let length = 4000 
    let buffer = AVAudioPCMBuffer(PCMFormat: audioPlayerNode.outputFormatForBus(0),frameCapacity:AVAudioFrameCount(length)) 
    buffer.frameLength = AVAudioFrameCount(length) 

    try! audioEngine.start() 


    let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] 
    let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound.m4a")) 


    do{ 
     print(dirPaths) 
     let settings = [AVFormatIDKey: NSNumber(unsignedInt: kAudioFormatMPEG4AAC), AVSampleRateKey: NSNumber(integer: 44100), AVNumberOfChannelsKey: NSNumber(integer: 2)] 
     self.newAudio = try AVAudioFile(forWriting: tmpFileUrl, settings: settings) 

     audioMixer.installTapOnBus(0, bufferSize: (AVAudioFrameCount(self.player!.duration)), format: self.audioMixer.outputFormatForBus(0)){ 
      (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in 

      print(self.newAudio.length) 
      print("=====================") 
      print(self.audioFile.length) 
      print("**************************") 
      if (self.newAudio.length) < (self.audioFile.length){ 

       do{ 
        //print(buffer) 
        try self.newAudio.writeFromBuffer(buffer) 
       }catch _{ 
        print("Problem Writing Buffer") 
       } 
      }else{ 
       self.audioMixer.removeTapOnBus(0) 
      } 

     } 
    }catch _{ 
     print("Problem") 
    } 

    audioPlayerNode.play() 

} 

Wystąpił również problem z prawidłowym sformatowaniem pliku. W końcu udało mi się to zrobić, gdy zmieniłem ścieżkę pliku wyjściowego z m4a na caf. Jedną z innych sugestii jest brak parametru nil dla parametru. Użyłem . Mam nadzieję, że to pomoże. Moje efekty audio/miksowanie są funkcjonalne, chociaż nie przyłączyłem efektów. Więc możesz zadawać pytania.

+0

@KBB Mam pytanie, gdzie jest oryginalny plik dźwiękowy? Czy jest wcześniej nagrywane, a następnie odtwarzane? Jeśli tak, zechcesz zaplanować ten plik - 'audioPlayerNode.scheduleFile (recordedAudioFile, atTime: nil, completionHandler: nil)' i uruchomić audioEngine zanim zadzwonisz 'audioPlayerNode.play()' – FromTheStix

+0

to jest zdecydowanie to, co zamierzam napisać jako odpowiedź na moje własne pytanie: DI rozwiązał to z podłączeniem ostatniego efektu do węzła miksera i stuknięciem w węzeł miksera, zamierzam napisać własne rozwiązanie poniżej – KBB

+0

nie mam problemu z uzyskaniem dźwięku w formacie m4a – KBB

0

Dla wszystkich, którzy mają problem konieczności odtworzyć plik audio dwukrotnie, aby go uratować, po prostu dodaje się następujący wiersz w odpowiednim miejscu i go rozwiązać mój problem. może pomóc komuś w przyszłości.

P.S: Użyłem kodu EXACT tego samego, co sprawdzona odpowiedź z góry, po prostu dodałem tę linię i rozwiązałem mój problem.

//Do what you want to do here with effected Audio 

    self.newAudio = try! AVAudioFile(forReading: tmpFileUrl) 
Powiązane problemy