点击安装在音频引擎上只生成短文件

时间:2015-12-30 20:52:16

标签: ios swift avfoundation avaudioengine

我正在制作一个应用程序,允许用户录制音频,在改变音高的同时播放,然后将他们所做的内容记录为单独的文件。

代码似乎正在运行,但新文件的持续时间仅为0.37秒(原始5秒)。 我猜测当我从缓冲区写入时它会一直保存,因此只留下最后一段。如果这是我的问题,我如何附加文件而不是写它?

    let recordSettings:[String : AnyObject] = [
        AVFormatIDKey: NSNumber(unsignedInt:kAudioFormatAppleLossless),
        AVEncoderAudioQualityKey : AVAudioQuality.Max.rawValue,
        AVEncoderBitRateKey : 320000,
        AVNumberOfChannelsKey: 2,
        AVSampleRateKey : 44100.0
    ]


    var outputFile = AVAudioFile()

    let format = NSDateFormatter()
    format.dateFormat="dd-HH-mm-ss"
    let currentFileName = "recording-\(format.stringFromDate(NSDate())).m4a"
    print(currentFileName)

    let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
    self.url2 = documentsDirectory.URLByAppendingPathComponent(currentFileName)

    let inputNode = engine.inputNode
    let bus = 0

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

        do {

            let outputFile = try AVAudioFile(forWriting: self.url2, settings: recordSettings, commonFormat: AVAudioCommonFormat.PCMFormatFloat32, interleaved: false)

            try outputFile.writeFromBuffer(buffer)
            outputFile.framePosition = outputFile.length

        } catch let error as NSError {
            NSLog("Error writing %@", error.localizedDescription)
        }

    }

更新了代码,创建了一个持续时间为0.0的文件:

func play() {

    let duration = CMTimeGetSeconds(AVAsset(URL: url).duration)
    print("Duration")
    print(duration)

    let file = try! AVAudioFile(forReading: url)

    let buffer = AVAudioPCMBuffer(PCMFormat: file.processingFormat, frameCapacity: AVAudioFrameCount(file.length))
    do {
        try file.readIntoBuffer(buffer)
    } catch _ {
    }

    engine = AVAudioEngine()
    player = AVAudioPlayerNode()

    pitch.pitch = 500


    engine.attachNode(player)
    engine.attachNode(pitch)

    engine.connect(player, to: pitch, format: buffer.format)
    engine.connect(pitch, to: engine.mainMixerNode, format: nil)

    let format = NSDateFormatter()
    format.dateFormat="dd-HH-mm-ss"
    let currentFileName = "recording-\(format.stringFromDate(NSDate())).m4a"
    print(currentFileName)

    let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
    self.url2 = documentsDirectory.URLByAppendingPathComponent(currentFileName)

    let outputFile = try! AVAudioFile(forWriting: url2, settings:  [
        AVFormatIDKey: NSNumber(unsignedInt:kAudioFormatAppleLossless),
        AVEncoderAudioQualityKey : AVAudioQuality.Max.rawValue,
        AVEncoderBitRateKey : 320000,
        AVNumberOfChannelsKey: 2,
        AVSampleRateKey : 44100.0
    ])

    done = false
    distortion.installTapOnBus(0, bufferSize: 2048, format: outputFile.processingFormat) {
        (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in

        let dataptrptr = buffer.floatChannelData
        let dataptr = dataptrptr.memory
        let datum = dataptr[Int(buffer.frameLength) - 1]
        if self.done && fabs(datum) < 0.000001 {
            print("stopping")
            self.engine.stop()
            return
        }

        do {
            try outputFile.writeFromBuffer(buffer)

        } catch let error as NSError {
            NSLog("Error writing %@", error.localizedDescription)
        }
    }

        player.scheduleBuffer(buffer, atTime: nil, options: AVAudioPlayerNodeBufferOptions.Loops, completionHandler: {
            dispatch_async(dispatch_get_main_queue(),{
            self.done = true
            self.player.stop()
                self.engine.stop()
            print("complete")
            })
        })

    engine.prepare()
    do {
        try engine.start()
        player.play()
    } catch _ {
        print("Play session Error")
    }

}

1 个答案:

答案 0 :(得分:3)

请记住,installTapOnBus处理程序将被多次调用:每次缓冲区填满时。把它想象成一个循环。因此,每次通过该循环创建输出文件都没有意义!您想要创建输出文件一次然后反复写入 。因此,您的整体结构需要如下所示:

let outfile = try! AVAudioFile(forWriting: outurl, settings: // ...
node.installTapOnBus(bus, bufferSize: size, format: outfile.processingFormat) {
    (buffer : AVAudioPCMBuffer!, time : AVAudioTime!) in
        do {
            try outfile.writeFromBuffer(buffer)
        } catch {
            print(error)
        }
    }

要记住的另一件事是,只要引擎保持运行,你的缓冲区就会完全填充和写入,所以不要过早地停止引擎(我不知道你是否这样做,但它是重要的是要记住。)