録音している時の音量を可視化するAudioMeterViewを作った

AudioMeterViewというライブラリを作りました。

AudioMeterViewを使うと、録音している時の音量をプログレスバー形式で表示することができます。

上のgifアニメのコードは以下のようになります。


import UIKit
import AVFoundation

class ViewController: UIViewController,AVAudioRecorderDelegate {
    @IBOutlet var audioMeterView: AudioMeterView! = AudioMeterView()
    var timer:NSTimer!
    var loaded:Bool = false
    var fname:String!
    var currentPath:NSURL!
    var soundRecorder:AVAudioRecorder!


    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupRecorder()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        if self.loaded == false {
            // setup audiometerView  
            self.audioMeterView.setup(0.4, backgroundColor: UIColor.lightGrayColor(), overLayColor: UIColor.redColor())
        }
    }

    func record(path:NSURL){
        let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
        try! audioSession.setCategory(AVAudioSessionCategoryRecord)
        try! audioSession.setActive(true)
    }


    func setupRecorder(){
        self.fname = NSUUID().UUIDString + ".caf"
        let documentDirectoryURL = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
        let fileDestinationUrl = NSURL(string: documentDirectoryURL)!.URLByAppendingPathComponent(fname)
        self.currentPath = fileDestinationUrl
        self.record(self.currentPath)

        let recordSettings:[String:AnyObject] = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVEncoderAudioQualityKey: AVAudioQuality.Max.rawValue,
            AVEncoderBitRateKey: 320000,
            AVNumberOfChannelsKey: 2,
            AVSampleRateKey: 44100.0
        ]


        self.soundRecorder = try! AVAudioRecorder(URL: self.currentPath, settings: recordSettings)
        self.soundRecorder.updateMeters()
        self.soundRecorder.delegate = self
        self.soundRecorder.prepareToRecord()
        self.soundRecorder.meteringEnabled = true


    }





    @IBAction func onToggleRecord(button: UIButton) {
        // Record/Stopボタンが押された時の挙動
        if button.titleLabel!.text == "Record" {
            button.setTitle("Stop", forState: .Normal)
            self.timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "updated", userInfo: nil, repeats: true)
            self.soundRecorder.record()
        }else{
            button.setTitle("Record", forState: .Normal)
            self.soundRecorder.stop()
            self.timer.invalidate()
        }




    }


    func updated(){
        //0.4秒ごとに音量を取得してself.audioMeterViewに反映させる
        self.audioMeterView.updateRecorderMeter(self.soundRecorder, duration: 0.4, channel: 0)
    }


AudioMeterViewのGitHubのリンクからサンプルプロジェクトをダウンロードできます。

[iOS] AVAudioSessionで再生するときの音量を大きくする


AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
で録音した音源を再生すると、音量を最大にしても小さすぎたのでいろいろ調べてみたところ、 録音するときは
let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
try! audioSession.setCategory(AVAudioSessionCategoryRecord)
に、再生するときは
let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
try! audioSession.setCategory(AVAudioSessionCategoryPlay)
にAVAudioSessionのCategoryを切り替えれば音量を大きくすることができた。

iOSアプリでデータを保存する時の注意

データの参照場所を絶対パスでCoreData等に永続化する作りにしてしまうと、アプリを実行するごとにドキュメントディレクトリの場所が変更されてしまうので次回アプリを立ち上げるとデータを開くことができなくなる。

なのでファイル名のみを保存しておき、以下のようにして取り出す必要がある。

let fname = "demo.png" // ファイル名
let abspath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0].stringByAppendingString(fname) 
let url = NSURL(string: abspath)!
let data = NSData(contentsOfURL: NSURL(string: url))!

アプリ内課金の実装を簡単にするStoreMangerクラスを作った

StoreManager.swfit

import Foundation
import UIKit
import StoreKit

class StoreManager:NSObject ,SKProductsRequestDelegate, SKPaymentTransactionObserver{
    static let sharedInstance = StoreManager()
    var transactionInProgress = false
    var productIDs:Array = [""]
    var productsArray: Array = []
    var selectedProductIndex: Int!
    var restore = false
    var payment:SKPayment!

    func requestProductInfo() {
        if SKPaymentQueue.canMakePayments() {
            let productIdentifiers = NSSet(array: StoreManager.sharedInstance.productIDs)
            let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set)
            productRequest.delegate = self
            productRequest.start()

        }
        else {
            print("Cannot perform In App Purchases.")
        }
    }

 
    func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
        print("productsRequest")
        if response.products.count != 0 {
            for product in response.products {
                print("validProduct:\(product)")
                StoreManager.sharedInstance.productsArray.append(product)
                self.payment = SKPayment(product: product)
                self.transactionInProgress = true
                SKPaymentQueue.defaultQueue().addPayment(self.payment)
                request.delegate = self
                request.start()
            }
        }
        else {
            print("There are no products.")
        }

        if response.invalidProductIdentifiers.count != 0 {
            print("invalidProductIdnetfiers:\(response.invalidProductIdentifiers.description)")
        }
    }


    func paymentQueue(queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: NSError) {
        print(error.description)
        print("paymentque restore")

    }

    // 購入履歴が確認できた場合
    func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {
        var restore = false
        print("paymentQueueRestore")

        //すでに商品を購入していたら、復元を行う

        for transaction in queue.transactions {
            print(transaction.payment.productIdentifier)

            if transaction.payment.productIdentifier == "Pro" {
                restore = true

               
            }
        }
  
        if restore == true {
            NSUserDefaults.standardUserDefaults().setBool(true, forKey: "pro")
            let av = UIAlertView(title: "", message: "Restored Successfully", delegate: nil, cancelButtonTitle: "OK")
            av.show()
        }else{
            print("called")
            // failed restore
            let av = UIAlertView(title: "", message: "There is no item to restore", delegate: nil, cancelButtonTitle: "OK")
            av.show()
        }
    }



    func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        print("update Transaction")
    
        for transaction in transactions {
            switch transaction.transactionState {
            case SKPaymentTransactionState.Purchased:
                print("Transaction completed successfully.")
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                self.transactionInProgress = false
                NSUserDefaults.standardUserDefaults().setBool(true, forKey: "pro")
                NSUserDefaults.standardUserDefaults().synchronize()

            case SKPaymentTransactionState.Failed:
                print("Transaction Failed");
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                self.transactionInProgress = false


            case SKPaymentTransactionState.Purchasing:
                print("purchasing")

            case SKPaymentTransactionState.Restored:
                print("SKPaymentTransactionState.Restored")
                self.transactionInProgress = false
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                
            default:
                print("default")
                
            }
        }
    }

    

使い方

購入

StoreManager.sharedInstance.requestProductInfo()

リストア

SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
SKPaymentQueue.defaultQueue().addTransactionObserver(StoreManager.sharedInstance)

コードはGistからもダウンロードできます。