簡體   English   中英

將AKAudioFile拆分成由靜音分隔的塊

[英]Split AKAudioFile into chunks separated by silence

給定一個AKAudioFile已經從創建AKNodeRecorder包含一系列的口語單詞, 每個單詞是由至少1秒鍾分離 ,是什么,最終創造出了一系列包含一個字每一個文件的文件的最好的方法?

我相信,如果有一種方法可以迭代文件(例如100 ms的塊)並測量每個塊的平均幅度,則可以實現此目的。 “靜音塊”可能是低於任意小幅度的那些。 進行迭代時,如果遇到一個具有非靜默振幅的塊,則可以獲取此“非靜默”塊的開始時間戳,以創建一個從此處開始並在下一個“靜默”塊的開始時間結束的音頻文件。

無論是使用上述手動方法還是AudioKit內置的處理技術,任何建議都將不勝感激。

我沒有完整的解決方案,但是我已經開始從事與此類似的工作。 此功能可以作為您所需的起點。 基本上,您希望將文件讀入緩沖區,然后分析緩沖區數據。 那時,您可以將其切成較小的緩沖區,然后將其寫入文件。

public class func guessBoundaries(url: URL, sensitivity: Double = 1) -> [Double]? {
    var out: [Double] = []

    guard let audioFile = try? AVAudioFile(forReading: url) else { return nil }
    let processingFormat = audioFile.processingFormat
    let frameCount = AVAudioFrameCount(audioFile.length)

    guard let pcmBuffer = AVAudioPCMBuffer(pcmFormat: processingFormat, frameCapacity: frameCount) else { return nil }
    audioFile.framePosition = 0

    do {
        audioFile.framePosition = 0
        try audioFile.read(into: pcmBuffer, frameCount: frameCount)

    } catch let err as NSError {
        AKLog("ERROR: Couldn't read data into buffer. \(err)")
        return nil
    }

    let channelCount = Int(pcmBuffer.format.channelCount)
    let bufferLength = 1024
    let inThreshold: Double = 0.001 / sensitivity
    let outThreshold: Double = 0.0001 * sensitivity
    let minSegmentDuration: Double = 1
    var counter = 0
    var thresholdCrossed = false
    var rmsBuffer = [Float](repeating: 0, count: bufferLength)
    var lastTime: Double = 0

    AKLog("inThreshold", inThreshold, "outThreshold", outThreshold)

    for i in 0 ..< Int(pcmBuffer.frameLength) {
        // n is the channel
        for n in 0 ..< channelCount {
            guard let sample: Float = pcmBuffer.floatChannelData?[n][i] else { continue }

            if counter == rmsBuffer.count {
                let time: Double = Double(i) / processingFormat.sampleRate

                let avg = rmsBuffer.reduce(0, +) / rmsBuffer.count
                // AKLog("Average Value at frame \(i):", avg)

                if avg > inThreshold && !thresholdCrossed && time - lastTime > minSegmentDuration {
                    thresholdCrossed = true
                    out.append(time)
                    lastTime = time
                } else if avg <= outThreshold && thresholdCrossed && time - lastTime > minSegmentDuration {
                    thresholdCrossed = false
                    out.append(time)
                    lastTime = time
                }
                counter = 0
            }
            rmsBuffer[counter] = abs(sample)
            counter += 1
        }
    }

    rmsBuffer.removeAll()
    return out
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM