[英]Capture audio samples with specific Sample Rate like Android in iOS Swift
[英]How to capture audio samples in iOS with Swift?
我在网上找到了许多用于在iOS中处理音频的例子,但是大多数都已经过时了,并不适用于我想要完成的任务。 这是我的项目:
我需要从两个来源捕获音频样本 - 麦克风输入和存储的音频文件。 我需要对这些样本执行FFT以产生整个剪辑的“指纹”,以及应用一些额外的过滤器。 最终目标是构建一种类似于Shazam等的歌曲识别软件。
在iOS 8中捕获单个音频样本以执行快速傅里叶变换的最佳方法是什么? 我想最终会有大量的这些,但我怀疑它可能不会像那样。 其次,如何使用Accelerate框架处理音频? 它似乎是在iOS中对音频执行复杂分析的最有效方式。
我在网上看到的所有例子都使用旧版本的iOS和Objective-C,但我无法将它们成功转换为Swift。 iOS 8是否为这类东西提供了一些新的框架?
在iOS录制:
AVAudioRecorder
的实例,如var audioRecorder: AVAudioRecorder? = nil
var audioRecorder: AVAudioRecorder? = nil
AVAudioRecorder
以存储样本和一些记录设置 录制会话顺序:
prepareToRecord()
record()
stop()
完整的Swift / AVAudioRecorder示例
在录制方法的核心,您可以:
func record() {
self.prepareToRecord()
if let recorder = self.audioRecorder {
recorder.record()
}
}
要准备录制(流式传输到file
),您可以:
func prepareToRecord() {
var error: NSError?
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
let soundFileURL: NSURL? = NSURL.fileURLWithPath("\(documentsPath)/recording.caf")
self.audioRecorder = AVAudioRecorder(URL: soundFileURL, settings: recordSettings as [NSObject : AnyObject], error: &error)
if let recorder = self.audioRecorder {
recorder.prepareToRecord()
}
}
最后,要停止录制,请使用:
func stopRecording() {
if let recorder = self.audioRecorder {
recorder.stop()
}
}
上面的示例还需要import AVFoundation
和一些recordSettings
,留待您选择。 recordSettings
的示例可能如下所示:
let recordSettings = [
AVFormatIDKey: kAudioFormatAppleLossless,
AVEncoderAudioQualityKey : AVAudioQuality.Max.rawValue,
AVEncoderBitRateKey : 320000,
AVNumberOfChannelsKey: 2,
AVSampleRateKey : 44100.0
]
这样做,你已经完成了。
您可能还想查看此Stack Overflow应答 ,其中包括一个演示项目 。
AVAudioEngine是实现这一目标的方法。 来自Apple的文档:
- 要播放和录制单个音轨,请使用AVAudioPlayer和AVAudioRecorder。
- 对于更复杂的音频处理,请使用AVAudioEngine。 AVAudioEngine包括用于音频输入和输出的AVAudioInputNode和AVAudioOutputNode。 您还可以使用AVAudioNode对象处理和混合音频效果
我会直截了当地说:AVAudioEngine是一个非常挑剔的API,带有模糊的文档,很少有用的错误消息,几乎没有在线代码示例演示超过最基本的任务。 但如果你花时间来克服小的学习曲线,你可以相对容易地做一些神奇的事情。
我已经构建了一个简单的“游乐场”视图控制器,它可以演示串联的麦克风和音频文件采样:
import UIKit
class AudioEnginePlaygroundViewController: UIViewController {
private var audioEngine: AVAudioEngine!
private var mic: AVAudioInputNode!
private var micTapped = false
override func viewDidLoad() {
super.viewDidLoad()
configureAudioSession()
audioEngine = AVAudioEngine()
mic = audioEngine.inputNode!
}
static func getController() -> AudioEnginePlaygroundViewController {
let me = AudioEnginePlaygroundViewController(nibName: "AudioEnginePlaygroundViewController", bundle: nil)
return me
}
@IBAction func toggleMicTap(_ sender: Any) {
if micTapped {
mic.removeTap(onBus: 0)
micTapped = false
return
}
let micFormat = mic.inputFormat(forBus: 0)
mic.installTap(onBus: 0, bufferSize: 2048, format: micFormat) { (buffer, when) in
let sampleData = UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength))
}
micTapped = true
startEngine()
}
@IBAction func playAudioFile(_ sender: Any) {
stopAudioPlayback()
let playerNode = AVAudioPlayerNode()
let audioUrl = Bundle.main.url(forResource: "test_audio", withExtension: "wav")!
let audioFile = readableAudioFileFrom(url: audioUrl)
audioEngine.attach(playerNode)
audioEngine.connect(playerNode, to: audioEngine.outputNode, format: audioFile.processingFormat)
startEngine()
playerNode.scheduleFile(audioFile, at: nil) {
playerNode .removeTap(onBus: 0)
}
playerNode.installTap(onBus: 0, bufferSize: 4096, format: playerNode.outputFormat(forBus: 0)) { (buffer, when) in
let sampleData = UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength))
}
playerNode.play()
}
// MARK: Internal Methods
private func configureAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: [.mixWithOthers, .defaultToSpeaker])
try AVAudioSession.sharedInstance().setActive(true)
} catch { }
}
private func readableAudioFileFrom(url: URL) -> AVAudioFile {
var audioFile: AVAudioFile!
do {
try audioFile = AVAudioFile(forReading: url)
} catch { }
return audioFile
}
private func startEngine() {
guard !audioEngine.isRunning else {
return
}
do {
try audioEngine.start()
} catch { }
}
private func stopAudioPlayback() {
audioEngine.stop()
audioEngine.reset()
}
}
音频样本通过installTap的完成处理程序提供给您,该处理程序在音频通过分接节点(麦克风或音频文件播放器)实时通过时连续调用。 您可以通过索引我在每个块中创建的sampleData指针来访问单个样本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.