Files
Mastermind/native/MastermindPOC/Sources/MastermindPOC/MicrophonePCMConverter.swift
T

58 lines
2.1 KiB
Swift

import AVFoundation
import Foundation
import MastermindPOCCore
enum MicrophonePCMConverter {
static func extractFrame(from buffer: AVAudioPCMBuffer) -> PCMFrame? {
let frameCount = Int(buffer.frameLength)
guard frameCount > 0 else {
return nil
}
let channelCount = max(1, Int(buffer.format.channelCount))
let sourceRate = Int(buffer.format.sampleRate.rounded())
let samples: [Float]
if let floatData = buffer.floatChannelData {
samples = mixFloatChannels(floatData, channelCount: channelCount, frameCount: frameCount)
} else if let int16Data = buffer.int16ChannelData {
samples = mixInt16Channels(int16Data, channelCount: channelCount, frameCount: frameCount)
} else {
return nil
}
let mono16k = PCM16LE.resampleLinear(samples: samples, sourceRate: sourceRate, targetRate: 16_000)
let data = PCM16LE.encode(samples: mono16k)
return PCMFrame(source: .microphone, sampleRate: 16_000, channels: 1, pcmS16LE: data)
}
private static func mixFloatChannels(_ channelData: UnsafePointer<UnsafeMutablePointer<Float>>, channelCount: Int, frameCount: Int) -> [Float] {
var mono = [Float](repeating: 0, count: frameCount)
let divisor = Float(channelCount)
for channel in 0..<channelCount {
let channelPointer = channelData[channel]
for frame in 0..<frameCount {
mono[frame] += channelPointer[frame] / divisor
}
}
return mono
}
private static func mixInt16Channels(_ channelData: UnsafePointer<UnsafeMutablePointer<Int16>>, channelCount: Int, frameCount: Int) -> [Float] {
var mono = [Float](repeating: 0, count: frameCount)
let divisor = Float(channelCount)
for channel in 0..<channelCount {
let channelPointer = channelData[channel]
for frame in 0..<frameCount {
mono[frame] += (Float(channelPointer[frame]) / Float(Int16.max)) / divisor
}
}
return mono
}
}