4

iOS でオーディオをリアルタイムで録音し、生のオーディオ データを分析し、録音データの一部を保存したいと考えています。このコードでデータを記録しています: https://gist.github.com/hotpaw2/ba815fc23b5d642705f2b1dedfaf0107

現在、データは Float 配列に保存されており、それをオーディオ ファイルに保存したいと考えています。私はこのコードでそれをやってみました:

let fileMgr = FileManager.default
    let dirPaths = fileMgr.urls(for: .documentDirectory, in: .userDomainMask)
    let recordSettings = [AVEncoderAudioQualityKey: AVAudioQuality.min.rawValue,
                      AVEncoderBitRateKey: 16,
                      AVNumberOfChannelsKey: 2,
                      AVSampleRateKey: 44100] as [String: Any]
    let soundFileUrl = dirPaths[0].appendingPathComponent("recording-" + getDate() + ".pcm")


    do {
        let audioFile = try AVAudioFile(forWriting: soundFileUrl, settings: recordSettings)
        let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44100, channels: 2, interleaved: true)

        let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: 3000)

        for i in 0..<circBuffer.count {
            audioFileBuffer.int16ChannelData?.pointee[i] = Int16(circBuffer[i])
        }

        try audioFile.write(from: audioFileBuffer)

    }

最後の行で、次のようなエラーが表示されます。

エラー: >avae> AVAudioFile.mm:306: -[AVAudioFile writeFromBuffer:error:]: エラー -50amplitudeDemo(79264,0x70000f7cb000) malloc: * オブジェクト 0x7fc5b9057e00 のエラー: 解放されたオブジェクトのチェックサムが正しくありません - オブジェクトは解放後に変更された可能性があります. * malloc_error_break にブレークポイントを設定してデバッグする

すでに他の多くの質問を検索しましたが、役立つものは見つかりませんでした。

4

2 に答える 2

1

この行のコードで:

let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: 3000)

AVAudioPCMBuffer容量 3000 フレーム * 2 チャネルを宣言します。これは、割り当てられたバッファにaudioFileBuffer6000 サンプルを含めることができることを意味します。チャネル データのインデックスがこの制限を超えると、コードによってヒープ内の近くの領域が破棄され、オブジェクトが変更された可能性があるというエラーが発生します。

したがって、circBuffer.countおそらくこの制限を超えている可能性があります。に十分なバッファ サイズを割り当てる必要がありAVAudioPCMBufferます。

    do {
        //### You need to specify common format
        let audioFile = try AVAudioFile(forWriting: soundFileUrl, settings: recordSettings, commonFormat: .pcmFormatInt16, interleaved: true)

        let channels = 2
        let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44100, channels: AVAudioChannelCount(channels), interleaved: true)
        let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(circBuffer.count / channels)) //<-allocate enough frames
        //### `stride` removed as it seems useless...
        let int16ChannelData = audioFileBuffer.int16ChannelData! //<-cannot be nil for the `format` above

        //When interleaved, channel data of AVAudioPCMBuffer is not as described in its doc:
        //  https://developer.apple.com/reference/avfoundation/avaudiopcmbuffer/1386212-floatchanneldata .
        //  The following code is modified to work with actual AVAudioPCMBuffer.
        //Assuming `circBuffer` as
        //  Interleaved, 2 channel, Float32
        //  Each sample is normalized to [-1.0, 1.0] (as usual floating point audio format)
        for i in 0..<circBuffer.count {
            int16ChannelData[0][i] = Int16(circBuffer[i] * Float(Int16.max))
        }
        //You need to update `frameLength` of the `AVAudioPCMBuffer`.
        audioFileBuffer.frameLength = AVAudioFrameCount(circBuffer.count / channels)

        try audioFile.write(from: audioFileBuffer)

    } catch {
        print("Error", error)
    }

コメントとしていくつかのメモが追加されています。このコードを試す前に確認してください。


更新 申し訳ありませんが、テストされていないコードを表示するため、2 つの点が修正されました。

  • commonFormat:インスタンス化時に指定する必要がありますAVAudioFile
  • int16ChannelData(およびその他のチャネル データ) は、実際の動作に合わせて変更されたデータ充填ループをインターリーブしたときに、ドキュメントに記載されているように期待されるポインターを返しません。

してみてください。

于 2017-01-05T17:01:34.533 に答える
1

frameCapacityを勝手に選んだようです3000

実際のサンプル数に設定します。

let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(circBuffer.count))

于 2017-01-05T17:03:33.243 に答える