iOS – 检测吹到麦克风和转换的结果! (迅速)

我需要快速开发一个iOS应用程序,它检测到用户对麦克风的打击。 这必须是一个挑战 – 两名玩家必须一个接一个地吹进iPhone麦克风的游戏。 分贝值应该以米或公里为单位进行测量和转换,这样我才能确定赢家。 “吹得更远”的选手(选手1:50km,选手2:70km)获胜。

这是一个可能的实现?

我有这个代码在迅速,我不知道如何进行:

import Foundation import UIKit import AVFoundation import CoreAudio class ViewController: UIViewController { // @IBOutlet weak var mainImage: UIImageView! var recorder: AVAudioRecorder! var levelTimer = NSTimer() var lowPassResults: Double = 0.0 override func viewDidLoad() { super.viewDidLoad() let url = NSURL.fileURLWithPath("dev/null") //numbers are automatically wrapped into NSNumber objects, so I simplified that to [NSString : NSNumber] var settings : [NSString : NSNumber] = [AVSampleRateKey: 44100.0, AVFormatIDKey: kAudioFormatAppleLossless, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.Max.rawValue] var error: NSError? // mainImage?.image = UIImage(named: "flyForReal.png"); recorder = AVAudioRecorder(URL:url, settings:settings, error:&error) if((recorder) != nil){ recorder.prepareToRecord() recorder.meteringEnabled = true recorder.record() levelTimer = NSTimer.scheduledTimerWithTimeInterval(0.05, target: self, selector: Selector("levelTimerCallback"), userInfo: nil, repeats: true) } else{ NSLog("%@", "Error"); } } func levelTimerCallback(timer:NSTimer) { recorder.updateMeters() let ALPHA: Double = 0.05 var peakPowerForChannel = pow(Double(10), (0.05 * Double(recorder.peakPowerForChannel(0)))) lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults; if(lowPassResults > 0.95){ NSLog("@Mic blow detected"); } NSLog("@Average input: %f Peak input: %f Low pass results: %f", recorder.averagePowerForChannel(0), recorder.peakPowerForChannel(0), lowPassResults); } } 

谢谢!

关。 你有几个问题。 您的select器调用会导致应用程序崩溃,因为您没有传递参数,并且levelTimerCallback()需要一个参数。

averagePowerPerChannel似乎给了我一个更实时的计量,所以我使用,而不是peakPowerPerChannel

另外,您需要设置audio会话。 我不确定这个math是什么意思,所以我在这里摆脱了它。 我粘贴了下面的整个视图控制器来进行基本的麦克风检测。

 import Foundation import UIKit import AVFoundation import CoreAudio class ViewController: UIViewController { var recorder: AVAudioRecorder! var levelTimer = NSTimer() var lowPassResults: Double = 0.0 override func viewDidLoad() { super.viewDidLoad() //make an AudioSession, set it to PlayAndRecord and make it active var audioSession:AVAudioSession = AVAudioSession.sharedInstance() audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, error: nil) audioSession.setActive(true, error: nil) //set up the URL for the audio file var documents: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] var str = documents.stringByAppendingPathComponent("recordTest.caf") var url = NSURL.fileURLWithPath(str as String) // make a dictionary to hold the recording settings so we can instantiate our AVAudioRecorder var recordSettings: [NSObject : AnyObject] = [AVFormatIDKey:kAudioFormatAppleIMA4, AVSampleRateKey:44100.0, AVNumberOfChannelsKey:2,AVEncoderBitRateKey:12800, AVLinearPCMBitDepthKey:16, AVEncoderAudioQualityKey:AVAudioQuality.Max.rawValue ] //declare a variable to store the returned error if we have a problem instantiating our AVAudioRecorder var error: NSError? //Instantiate an AVAudioRecorder recorder = AVAudioRecorder(URL:url, settings: recordSettings, error: &error) //If there's an error, print that shit - otherwise, run prepareToRecord and meteringEnabled to turn on metering (must be run in that order) if let e = error { println(e.localizedDescription) } else { recorder.prepareToRecord() recorder.meteringEnabled = true //start recording recorder.record() //instantiate a timer to be called with whatever frequency we want to grab metering values self.levelTimer = NSTimer.scheduledTimerWithTimeInterval(0.02, target: self, selector: Selector("levelTimerCallback"), userInfo: nil, repeats: true) } } //This selector/function is called every time our timer (levelTime) fires func levelTimerCallback() { //we have to update meters before we can get the metering values recorder.updateMeters() //print to the console if we are beyond a threshold value. Here I've used -7 if recorder.averagePowerForChannel(0) > -7 { print("Dis be da level I'm hearin' you in dat mic ") println(recorder.averagePowerForChannel(0)) println("Do the thing I want, mofo") } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

我把Andrew的答案转换成了Swift 4,而且效果很棒! 谢谢!

 import Foundation import UIKit import AVFoundation import CoreAudio class ViewController: UIViewController { var recorder: AVAudioRecorder! var levelTimer = Timer() let LEVEL_THRESHOLD: Float = -10.0 override func viewDidLoad() { super.viewDidLoad() let documents = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0]) let url = documents.appendingPathComponent("record.caf") let recordSettings: [String: Any] = [ AVFormatIDKey: kAudioFormatAppleIMA4, AVSampleRateKey: 44100.0, AVNumberOfChannelsKey: 2, AVEncoderBitRateKey: 12800, AVLinearPCMBitDepthKey: 16, AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue ] let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord) try audioSession.setActive(true) try recorder = AVAudioRecorder(url:url, settings: recordSettings) } catch { return } recorder.prepareToRecord() recorder.isMeteringEnabled = true recorder.record() levelTimer = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(levelTimerCallback), userInfo: nil, repeats: true) } @objc func levelTimerCallback() { recorder.updateMeters() let level = recorder.averagePower(forChannel: 0) let isLoud = level > LEVEL_THRESHOLD // do whatever you want with isLoud } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }