ios - 将 AKAudioFile 拆分为由静音分隔的 block

标签 ios swift audiokit

给定一个从 AKNodeRecorder 创建的单个 AKAudioFile,其中包含一系列口语单词,其中每个单词至少间隔 1 秒,最终创建一系列文件且每个文件包含一个单词的最佳方法是什么?

我相信,如果有一种方法可以在例如 100 毫秒的 block 中迭代文件,并测量每个 block 的平均振幅,就可以实现这一点。 “静音 block ”可能是低于某个任意小幅度的 block 。在迭代时,如果我遇到一个具有非无声振幅的 block ,我可以获取这个“非无声” block 的开始时间戳来创建一个音频文件,该文件从这里开始并在下一个“无声” block 的开始时间结束。

无论是使用像上面那样的手动方法还是 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
}

关于ios - 将 AKAudioFile 拆分为由静音分隔的 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51432115/

相关文章:

ios - 从 nib 创建的 UICollectionViewCell 中的奇怪 UIView

ios - 如何在动画中更改 UITableView 标签 textColor 两次?

audiokit - 如何消除使用振荡器时的滑音效果?

swift - AKAudioPlayer 节点在到达文件/缓冲区末尾之前停止后是否会应用 10 毫秒的淡出?

ios - UIGraphicsBeginImageContextWithOptions - 返回的图像有不需要的边框

ios - 如何从同一个类中的 prepareForSegue 方法访问覆盖 func tableView 属性

ios - 为什么我在 Swift playground 中进行简单的加法操作时会出错?

ios - 使用 KeyPath 编辑效果属性

ios - 使用 NSSortDescriptor、Core Data 和 NSFetchedResultsController 按日期和名称对 UITableView 进行排序

iphone - 如何在 iOS 中翻转视频帧