2015-07-05 9 views
7

Muszę opracować aplikację na iOS, która wykryje uderzenie mikrofonu od użytkownika. To musi być gra typu Challenge, w której dwóch graczy musi uderzać w mikrofon iPhone'a jeden po drugim. Wartości decybeli powinny być mierzone i przeliczane w metrach lub kilometrach, aby można było określić zwycięzcę. Gracz, który "wieje dalej" (gracz1: 50km, gracz2: 70km) wygrywa.iOS - Wykryj przedmuch i sprawdź wyniki! (swift)

Czy to możliwe wdrożenie?

Mam ten kod w szybki i nie wiem, jak postępować:

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

Dzięki przodu!

Odpowiedz

9

Zamknij. Masz kilka problemów. Wywołanie selektora powoduje awarię aplikacji, ponieważ nie przekazujesz argumentu i oczekuje ona jednego.

averagePowerPerChannel wydaje się dać mi więcej czasu rzeczywistego pomiaru tak kiedyś, że zamiast peakPowerPerChannel

Ponadto, należy skonfigurować sesję audio. Nie bardzo wiedziałem, o co chodzi w tej matematyce, więc po prostu pozbyłem się jej tutaj. Wkleiłem cały kontroler widoku poniżej w celu wykrycia podstawowego mikrofonu.

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

konwertowane odpowiedź Andrzeja do Swift 4, i działa świetnie! Dzięki!

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


}