Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
341 views
in Technique[技术] by (71.8m points)

iphone - iOS - Detect Blow into Mic and convert the results! (swift)

I need to develop an iOS App in swift which detects a blow in the microphone from a user. This has to be a Challenge-Game where two players have to blow into the iPhone mic one after the other. The decibel values should be measured and converted in meter or kilometer so I can determine a winner. The player which "blows further" (player1: 50km, player2: 70km) wins.

Is this a possible implementation?

I have this code in swift and I don't know how to proceed:

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

Thanks ahead!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I converted Andrew's answer to 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.
    }


}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...