質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • Swift

    7658questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

swift3 効果音 引っかかり?

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 575

komeo

score 3

iPadのアプリを制作しています。

ドラッグで移動するViewのy座標に合わせて効果音を1回だけ再生したいです。

yが150のときに「雨の音」
yが300のときは「風の音」など

一応出来たんですが・・
効果音が再生されるときにドラッグに引っかかりが出るというか
再生待ち?になるのか、一瞬(というか再生開始まで)止まってしまい
スムーズに動きません。

再生後はまたスムーズに動くという感じになります。
初回の効果音が特にそうなります。

Xcodeのシミュレーターでは問題無く動くのですが
実機テストでは上記のようになりました。

上手く伝わらないかも知れずで恐縮です、、、

以下、コードです。

ちなみに試してみた事として
効果音を用意したときに
ボリューム0で先に再生しておくと多少マシにはなるようではあるのですが、、
完全に無くなるという事でも無いようです

何か重くなるコードを書いてをしてしまっているんでしょうか。

よろしくお願い致します。

OSX 10.11.6
Xcode 8.2.1
Swift 3
テスト実機 iPad Air2 MNV72J/A iOS10.2

import UIKit
import AVFoundation

class ViewController: UIViewController {

    //ドラッグ用のView
    var my:UIView = UIView()

    //雨の音    
    var rain:AVAudioPlayer! = nil
    //雨の音監視用
    var rainPlay:Bool = true

    //風の音
    var wind:AVAudioPlayer! = nil
    //風の音監視用
    var windPlay:Bool = true

    //ドラッグのy座標監視 タイマーにて
    var timer:Timer!

    override func viewDidLoad() {
        super.viewDidLoad()

        //View設置
        my.frame = CGRect(x:100, y:100, width:200, height:200)
        my.backgroundColor = UIColor.gray
        self.view.addSubview(my)

        //効果音用意(雨の音)
        var url = NSURL.fileURL(withPath: Bundle.main.path(forResource: "rain", ofType: "mp3")!)
        do{
            rain = try AVAudioPlayer(contentsOf: url)
        }catch{
            print("no rain")
        }
        rain.prepareToPlay()

        //先にボリューム0で再生してみたテストです
        //rain.volume = 0
        //rain.play()
        //先再生したテストでは多少はましになります。

        //効果音用意(風の音)
        url = NSURL.fileURL(withPath: Bundle.main.path(forResource: "wind", ofType: "mp3")!)
        do{
            wind = try AVAudioPlayer(contentsOf: url)
        }catch{
            print("no wind")
        }
        wind.prepareToPlay()
    }

    //ドラッグはtouchMovedで
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {        
        let e = touches.first!
        let dx = e.location(in:self.view).x - e.previousLocation(in:self.view).x
        let dy = e.location(in:self.view).y - e.previousLocation(in:self.view).y

        my.frame.origin.x += dx
        my.frame.origin.y += dy
    }

    //座標監視はas3で云うenterFrame的なそれで
    func enterFrame(){
        let y = my.frame.origin.y

        //最初の効果音(雨の音)
        //ここでドラッグが効果音に引っかる?ように一旦止まり、効果音再生後にはまたスムーズにドラッグ操作が出来きます
        if(y > 150){
            if(rainPlay){
                rainPlay = false
                //先再生テスト用
                //rain.volume = 1
                rain.play()
            }
        }else{rainPlay = true}

        //2番目の効果音(風の音)
        //初回ほどでは無いですが、やや引っかかりがあったり無かったりです
        if(y > 300){
            if(windPlay){
                windPlay = false
                wind.play()
            }
        }else{windPlay = true}

        //以下、、、3番目、4番目と続きます

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(true)
        //タイマー監視
        timer = Timer.scheduledTimer(timeInterval:0.5,target:self,selector:#selector(self.enterFrame),userInfo:nil,repeats:true)
        timer.fire()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(true)
        //タイマー破棄?
        timer.invalidate()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

+1

iPadやSwiftに暗いのですが一般的な問題と捉えた範囲でのコメントをします。

音声の再生が始まるとハードウェアによるバックグラウンド処理により発音されるのですが、ハードウェアを動かすための初期動作に多少時間がかかることはよくあると思います。例えばバッファを確保してそこへ全部あるいは一部の音声データを読み込んだりといったことが考えられます。あらかじめ音量0で鳴らすと現象が軽減されるというのは、初期動作で行ったI/O結果がキャッシュされたためと考えられます。

いずれにせよ音を鳴らすための処理に数10msec~100msecオーダーの時間がかかるとしてそれをUIスレッドで直接行ってしまうとご質問のような影響が出る結果になると思います。

対応としては一般的に以下のような考え方にすると思います。

  • バックグラウンド処理を行うためのスレッドをあらかじめ起動しておく
    例えばマウスドラッグで音を鳴らすような画面を開いた時点でスレッドを起動してしまいます。音を鳴らす処理はこのスレッド上で行うようにします。
  • UIスレッドではバックグラウンドスレッドへ簡単な指示(この音を鳴らせなど)のみ行う
    どんな言語・ライブラリーでもスレッド間の同期をとるための機能が提供されていると思いますのでそうしたものを使いスレッド間で情報のやりとりを行います。ただ今回のようなものですと厳密なスレッド間同期の必要性は低く、単にUIスレッドから鳴らしたい音が変化した際に大域変数的なものへ音の種類を直接設定し、バックグラウンドスレッドでは100msec前後の間隔でその変数を監視しつつ音を鳴らすといったシンプルな作りでもよい気もします。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/22 08:27

    ご回答ありがとうございます。
    勉強になります。急ぎその方向での検証をしてみます。

    キャンセル

同じタグがついた質問を見る

  • Swift

    7658questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています