CoreAudio/swift3で録音を行うサンプルです。
iPhoneのマイクから取得した音声データをレベル値に変換して画面に表示します。
import Foundation import AVFoundation import AudioUnit class MyAudioRecorder: NSObject { var level: Float = 0.0 var frameCount: UInt32 = 0 private var _audioUnit: AudioUnit? private var _abl: AudioBufferList? private let kInputBus: UInt32 = 1 private let kNumberOfChannels: Int = 1 func start() { // AudioSession セットアップ do { let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(AVAudioSessionCategoryRecord) try audioSession.setActive(true) } catch { } // CoreAudio セットアップ var componentDesc: AudioComponentDescription = AudioComponentDescription( componentType: OSType(kAudioUnitType_Output), componentSubType: OSType(kAudioUnitSubType_RemoteIO), componentManufacturer: OSType(kAudioUnitManufacturer_Apple), componentFlags: UInt32(0), componentFlagsMask: UInt32(0) ) let component: AudioComponent! = AudioComponentFindNext(nil, &componentDesc) var tau: AudioUnit? AudioComponentInstanceNew(component, &tau) _audioUnit = tau guard let au = _audioUnit else { return } // RemoteIO のマイクを有効にする var enable: UInt32 = 1 AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &enable, UInt32(MemoryLayout<UInt32>.size)) // マイクから取り出すデータフォーマット // 32bit float, linear PCM guard let fmt = AVAudioFormat(standardFormatWithSampleRate: 44100, channels: UInt32(kNumberOfChannels)) else { return } // RemoteIO のマイクバスから取り出すフォーマットを設定 AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, fmt.streamDescription, UInt32(MemoryLayout<AudioStreamBasicDescription>.size)) // AudioUnit に録音コールバックを設定 var inputCallbackStruct = AURenderCallbackStruct(inputProc: recordingCallback, inputProcRefCon: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())) AudioUnitSetProperty(au, AudioUnitPropertyID(kAudioOutputUnitProperty_SetInputCallback), AudioUnitScope(kAudioUnitScope_Global), kInputBus, &inputCallbackStruct, UInt32(MemoryLayout<AURenderCallbackStruct>.size)) // データ取り出し時に使う AudioBufferListの設定 _abl = AudioBufferList( mNumberBuffers: 1, mBuffers: AudioBuffer( mNumberChannels: fmt.channelCount, mDataByteSize: fmt.streamDescription.pointee.mBytesPerFrame, mData: nil)) AudioUnitInitialize(au) AudioOutputUnitStart(au) } let recordingCallback: AURenderCallback = { ( inRefCon, ioActionFlags, inTimeStamp, inBusNumber, frameCount, ioData ) -> OSStatus in let audioObject = unsafeBitCast(inRefCon, to: MyAudioRecorder.self) if let au = audioObject._audioUnit { // マイクから取得したデータを取り出す AudioUnitRender(audioObject._audioUnit!, ioActionFlags, inTimeStamp, inBusNumber, frameCount, &audioObject._abl!) } audioObject.frameCount = frameCount let inputDataPtr = UnsafeMutableAudioBufferListPointer(&audioObject._abl!) let mBuffers: AudioBuffer = inputDataPtr[0] let bufferPointer = UnsafeMutableRawPointer(mBuffers.mData) if let bptr = bufferPointer { let dataArray = bptr.assumingMemoryBound(to: Float.self) // マイクから取得したデータからRMS(RootMeanSquare)レベルを計算する var sum:Float = 0.0 if frameCount > 0 { for i in 0 ..< Int(frameCount) { sum += (dataArray[i]*dataArray[i]) } audioObject.level = sqrt(sum / Float(frameCount)) } } return 0 } }
まず、Info.plistに
Privacy - Microphone Usage Description
の項目を追加します。
これを行わないとiPhoneのマイクが使えません。
次に、オーディオセッションのカテゴリを録音にします。
let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(AVAudioSessionCategoryRecord) try audioSession.setActive(true)
録音を行う RemoteIO を作り、RemoteIO のマイクを有効にします。
マイクから取り出すデータフォーマットを設定します。
ここでは、32bit float モノラル サンプルレート44.1kHzとしました。
RemoteIOに録音コールバック関数を設定します。
録音を開始すると、例えば1024サンプル録音される毎にこのコールバック関数が呼ばれるので、 コールバック関数内でバッファからデータを取り出して処理します。
ここでは、取り出したデータの平均値(RMS)を計算します。
ViewController上にはこの値を画面に表示しています。
以下、ViewController のソースです。
class ViewController: UIViewController { @IBOutlet var progress:UIProgressView! @IBOutlet var label:UILabel! var recorder:MyAudioRecorder! var timer: Timer! override func viewDidLoad() { super.viewDidLoad() recorder = MyAudioRecorder() recorder?.start() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) timer = Timer.scheduledTimer(timeInterval: 0.005, target: self, selector: #selector(self.update), userInfo: nil, repeats: true) timer.fire() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) timer.invalidate() } @objc func update(tm: Timer){ progress.progress = recorder.level label.text = "\(recorder.frameCount)" } }
録音を開始した後、5ms間隔でレベル値を画面に表示するようにしています。
ソースはこちら https://github.com/pebble8888/AudioRecorderSwift
Macデジタルオーディオプログラミング (Mynavi Advanced Library)
- 作者: 音羽良
- 出版社/メーカー: マイナビ出版
- 発売日: 2015/01/22
- メディア: Kindle版
- この商品を含むブログを見る