【发布时间】:2021-06-14 23:11:44
【问题描述】:
我正在构建一个应用程序,该应用程序需要对其从麦克风接收到的音频进行实时分析。在我的应用程序中,我还需要同时播放哔声并开始录制音频,也就是说,我无法播放哔声然后开始录制。这引入了在我的录音中听到哔声的问题,(这可能是因为我正在通过扬声器播放哔声,但不幸的是我在这方面也不能妥协)。由于哔声只是大约 2350 kHz 的音调,我想知道如何在我的录音中排除该频率范围(例如从 2300 kHz 到 2400 kHz)并防止它影响我的音频样本。在做了一些谷歌搜索之后,我想出了我认为可能是解决方案,带阻滤波器。根据 Wikipedia 的说法:“带阻滤波器或带阻滤波器是一种通过大多数频率不变的滤波器,但将特定范围内的频率衰减到非常低的水平”。这似乎是我需要在我的录音中排除 2300 kHz 到 2400 kHz 的频率(或者至少在播放哔声时录音的第一秒)。我的问题是:我将如何使用 AVAudioEngine 实现这一点?有没有办法可以在录制的第一秒后关闭过滤器,当哔声播放完毕而不停止录制?
由于我是使用 AVAudioEngine 处理音频的新手(我一直坚持使用更高级别的 AVFoundation),因此我遵循this 教程来帮助我创建一个类来处理所有杂乱的东西。这是我的代码的样子:
class Recorder {
enum RecordingState {
case recording, paused, stopped
}
private var engine: AVAudioEngine!
private var mixerNode: AVAudioMixerNode!
private var state: RecordingState = .stopped
private var audioPlayer = AVAudioPlayerNode()
init() {
setupSession()
setupEngine()
}
fileprivate func setupSession() {
let session = AVAudioSession.sharedInstance()
//The original tutorial sets the category to .record
//try? session.setCategory(.record)
try? session.setCategory(.playAndRecord, options: [.mixWithOthers, .defaultToSpeaker])
try? session.setActive(true, options: .notifyOthersOnDeactivation)
}
fileprivate func setupEngine() {
engine = AVAudioEngine()
mixerNode = AVAudioMixerNode()
// Set volume to 0 to avoid audio feedback while recording.
mixerNode.volume = 0
engine.attach(mixerNode)
//Attach the audio player node
engine.attach(audioPlayer)
makeConnections()
// Prepare the engine in advance, in order for the system to allocate the necessary resources.
engine.prepare()
}
fileprivate func makeConnections() {
let inputNode = engine.inputNode
let inputFormat = inputNode.outputFormat(forBus: 0)
engine.connect(inputNode, to: mixerNode, format: inputFormat)
let mainMixerNode = engine.mainMixerNode
let mixerFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: inputFormat.sampleRate, channels: 1, interleaved: false)
engine.connect(mixerNode, to: mainMixerNode, format: mixerFormat)
//AudioPlayer Connection
let path = Bundle.main.path(forResource: "beep.mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
let file = try! AVAudioFile(forReading: url)
engine.connect(audioPlayer, to: mainMixerNode, format: nil)
audioPlayer.scheduleFile(file, at: nil)
}
//MARK: Start Recording Function
func startRecording() throws {
print("Start Recording!")
let tapNode: AVAudioNode = mixerNode
let format = tapNode.outputFormat(forBus: 0)
let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// AVAudioFile uses the Core Audio Format (CAF) to write to disk.
// So we're using the caf file extension.
let file = try AVAudioFile(forWriting: documentURL.appendingPathComponent("recording.caf"), settings: format.settings)
tapNode.installTap(onBus: 0, bufferSize: 4096, format: format, block: {
(buffer, time) in
try? file.write(from: buffer)
print(buffer.description)
print(buffer.stride)
let floatArray = Array(UnsafeBufferPointer(start: buffer.floatChannelData![0], count:Int(buffer.frameLength)))
})
try engine.start()
audioPlayer.play()
state = .recording
}
//MARK: Other recording functions
func resumeRecording() throws {
try engine.start()
state = .recording
}
func pauseRecording() {
engine.pause()
state = .paused
}
func stopRecording() {
// Remove existing taps on nodes
mixerNode.removeTap(onBus: 0)
engine.stop()
state = .stopped
}
}
【问题讨论】:
标签: ios swift audio avaudioplayer avaudioengine