2015-07-05 6 views
7

Ich muss eine iOS-App in Swift entwickeln, die einen Schlag im Mikrofon von einem Benutzer erkennt. Dies muss ein Challenge-Game sein, bei dem zwei Spieler nacheinander in das iPhone-Mikrofon blasen müssen. Die Dezibelwerte sollten gemessen und in Meter oder Kilometer umgerechnet werden, damit ich einen Gewinner ermitteln kann. Der Spieler, der "weiter bläst" (Spieler1: 50km, Spieler2: 70km), gewinnt.iOS - Erkennen Sie Schlag in Mic und konvertieren Sie die Ergebnisse! (swift)

Ist dies eine mögliche Implementierung?

Ich habe diesen Code in einem schnellen und ich weiß nicht, wie es weitergeht:

voraus
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); 
} 
} 

Dank!

Antwort

9

Schließen. Sie haben ein paar Probleme. Ihr Selektor-Aufruf stürzt die App ab, weil Sie kein Argument übergeben und levelTimerCallback() eins erwartet.

averagePowerPerChannel scheint mir eine Dosierung in Echtzeit zu geben, damit ich, dass statt peakPowerPerChannel

Auch verwendet, erhalten Sie eine Audio-Sitzung einrichten müssen. Ich war mir nicht wirklich sicher, worum es bei all der Mathematik ging, also habe ich es hier einfach losgeworden. Ich habe den gesamten View-Controller unten für die grundlegende Mikrofonerkennung eingefügt.

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. 
} 


} 
3

Ich konvertierte Andrews Antwort auf Swift 4, und es funktioniert super! Vielen Dank!

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. 
    } 


} 
Verwandte Themen