























@@ -0,0 +1,86 @@
1+@preconcurrency import AVFoundation
2+3+enum SpeechAudioBufferNormalizer {
4+static func speechCompatibleBuffer(from buffer: AVAudioPCMBuffer) -> AVAudioPCMBuffer {
5+let format = buffer.format
6+guard format.channelCount > 2, format.sampleRate > 0 else {
7+return buffer
8+}
9+return self.downmixFloatBuffer(buffer) ?? self.convertBuffer(buffer) ?? buffer
10+}
11+12+private static func downmixFloatBuffer(_ buffer: AVAudioPCMBuffer) -> AVAudioPCMBuffer? {
13+let format = buffer.format
14+guard format.commonFormat == .pcmFormatFloat32,
15+ !format.isInterleaved,
16+let source = buffer.floatChannelData,
17+let targetFormat = AVAudioFormat(
18+ commonFormat: .pcmFormatFloat32,
19+ sampleRate: format.sampleRate,
20+ channels: 1,
21+ interleaved: false),
22+let output = AVAudioPCMBuffer(
23+ pcmFormat: targetFormat,
24+ frameCapacity: buffer.frameCapacity),
25+let target = output.floatChannelData?[0]
26+else {
27+return nil
28+}
29+30+ output.frameLength = buffer.frameLength
31+let channelCount = Int(format.channelCount)
32+let frameCount = Int(buffer.frameLength)
33+guard channelCount > 0, frameCount > 0 else { return output }
34+35+let scale = 1.0 / Float(channelCount)
36+for frame in 0..<frameCount {
37+var sum: Float = 0
38+for channel in 0..<channelCount {
39+ sum += source[channel][frame]
40+}
41+target[frame] = sum * scale
42+}
43+return output
44+}
45+46+private static func convertBuffer(_ buffer: AVAudioPCMBuffer) -> AVAudioPCMBuffer? {
47+guard let targetFormat = AVAudioFormat(
48+ commonFormat: .pcmFormatFloat32,
49+ sampleRate: buffer.format.sampleRate,
50+ channels: 1,
51+ interleaved: false),
52+let converter = AVAudioConverter(from: buffer.format, to: targetFormat)
53+else {
54+return nil
55+}
56+57+let frameCapacity = AVAudioFrameCount(
58+max(1, ceil(Double(buffer.frameLength) * targetFormat.sampleRate / buffer.format.sampleRate)))
59+guard let output = AVAudioPCMBuffer(pcmFormat: targetFormat, frameCapacity: frameCapacity) else {
60+return nil
61+}
62+63+let input = ConverterInput(buffer)
64+var error: NSError?
65+let status = converter.convert(to: output, error: &error) { _, outStatus in
66+if input.didProvide {
67+ outStatus.pointee = .noDataNow
68+return nil
69+}
70+ input.didProvide = true
71+ outStatus.pointee = .haveData
72+return input.buffer
73+}
74+guard status != .error else { return nil }
75+return output
76+}
77+78+private final class ConverterInput: @unchecked Sendable {
79+let buffer: AVAudioPCMBuffer
80+var didProvide = false
81+82+init(_ buffer: AVAudioPCMBuffer) {
83+self.buffer = buffer
84+}
85+}
86+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。