我需要在swift中开发一个iOS应用程序,用于检测用户对麦克风的打击。这必须是一个挑战游戏,两个玩家必须一个接一个地吹入iPhone麦克风。分贝值应该以米或公里为单位进行测量和转换,这样我才能确定胜利者。 “进一步吹”(球员1:50公里,球员2:70公里)的球员获胜。
这是可能的实施吗?
我在swift中有这个代码,我不知道如何继续:
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);
}
}
非常感谢!
答案 0 :(得分:12)
关闭。你有几个问题。你的选择器调用会崩溃应用程序,因为你没有传递参数而levelTimerCallback()
期望一个。
averagePowerPerChannel
似乎给了我一个更实时的计量,所以我使用了它而不是peakPowerPerChannel
此外,您需要设置音频会话。我不太确定所有的数学是什么,所以我在这里摆脱它。我已粘贴下面的整个视图控制器进行基本的麦克风检测。
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.
}
}
答案 1 :(得分:8)
我转换了安德鲁对Swift 4的回答:
"message": "Unexpected apiai response format: Empty speech response",
"apiResponse": {
"id": "905d5727-bea8-4630-8d3a-e6c173159a94",
"timestamp": "2017-09-28T02:20:06.954Z",
"lang": "en",
"result": {},
"status": {
"code": 206,
"errorType": "partial_content",
"errorDetails": "Webhook call failed. Error: Webhook response was empty."
},
"sessionId": "1506565201634"
}