リピート再生を実現する
A点、B点のボタンがタップされた際の処理を担当するposAButonTappedとposBButtonTappedの各メソッドは、当然ながらいずれもビューコントローラー内に記述します。
A点では、プレーヤーの現在の再生位置(秒)をpositionAに代入し、その値を「分:秒」のフォーマットでラベルに表示します。またその値が0.0でなければ、リピートモードを表すrepPlayをtrueに設定しています。
B点も同様に、現在の再生位置をpositionBに代入し、ラベルに表示します。その値が音楽ファイルの長さ、つまり再生位置の最後尾に一致していない場合は、リピートモードをtrueにします。なお、B点の値をプレーヤーの再生位置(currentTime)そのものにせずに、スライダーの位置から計算しているのは、スライダーが最後尾にあっても、プレーヤーのcurrentTimeの値が0.0になってしまう場合があるからです。
再生位置を表す秒の数値(Double)を「分:秒」の文字列に変換する処理がよく出てくるので、後の方で記述するformatTimeというメソッドを作りました。前回に記述したtSliderMovedのメソッドも、それを使うように書き換えています。
実際のリピート処理は、時間スライダーの位置をアップデートするupdateSliderメソッドの中で実行しています。といっても非常に簡単で、リピートモードがtrueのときにプレーヤーの再生位置(currentTime)がB点の値を超えたら、再生位置を強制的にA点に戻すだけです。これによって、A点とB点の間の再生を繰り返すようになります。
なお、この図には秒の数値を「分:秒」の文字列に変換するformatTimeメソッドも含まれています。中身は、前回に書いたDateComponentFormatterクラスを利用したものとまったく同じです。
以上のプログラムで、ABリピート機能が実現できました。外国語学習にも、演奏の耳コピーにも便利に使えるでしょう。
プログレスバーをレベルメーターとして代用する
次にレベルメーター機能を追加しましょう。すでに述べたようにメーター自体はプログレスバー(UIProgressView)で代用します。ビューコントローラーの先頭部分で、2チャンネルの音楽ファイルを想定してlPowerとrPowerの2本を用意します。チャンネルの名前を表示するラベル、lMarkとrMarkも追加します。
viewDidLoadメソッドの中では、その2組のラベルとプログレスバーも初期設定しておきます。チャンネル名は文字の両側をスペースで挟んで「 L 」と「 R 」にしました。ラベルの背景色は黄色、プログレスバーの溝の部分の色は緑にしています。ここは好きな色に設定してください。
AVAudioPlayerの再生中の音声のレベルを知るためには、あらかじめ設定しておかなければならないことが1つあります。それは、プレーヤーのプロパティ、isMeteringEnabledをtrueに設定しておくことです。これもviewDidLoadメソッドの最後に設定します。
2組のラベルとプログレスバーのレイアウトも、viewWillLayoutSubviewsメソッドの中で設定します。この例では、ABリピートのためとボタンとラベルのさらに下に、LチャンネルとRチャンネルが縦に重なるように配置してみました。
平均パワーの測定結果を連続表示する
レベルメーターの表示自体には直接関係ありませんが、時間スライダーの表示をアップデートするのに使っているコアアニメーションのタイマーの設定も変更しておきます。前回は、スライダーの更新だけだったので1秒に1回で十分ということで、preferredFramesPerSecondを1に設定していました。レベルメーターの更新には、これでは更新(フレーム)レートが低過ぎて、カクカクした動きになってしまいます。これは1秒に10回を表す10にしてみました。再生ボタンのタップを処理するpButtonTappedメソッドの最後に近い部分の設定を変更します。
実際にレベルメーターを更新するコードは、時間スライダーの位置を更新するupdateSliderメソッドの中に追加します。レベルメーターに表示する値を取得する直前にプレーヤーのupdateMetersメソッドを実行してから、averagePowerメソッドでチャンネルを指定して読み込みます。読み取った値はデシベル値なので、簡単な式で0.0〜1.0の間の値に変換し、それをそのままプログレスバーの値として書き込んでいるだけです。アニメーションをオンにしているので、適当に補間が入ってスムーズなバーの動きになります。
実際に動かしてみると、再生音に応じてレベルメーターが動くようすが観察できます。
なお、このプログラムではプログラム内のボリュームスライダーの値に関係なく、元の音楽ファイルの再生レベルを表示しています。もしボリューム設定を反映したレベルメーターにしたい場合は、レベルメーターのプログレスバーの値に、ボリューム(vSlider)の値を掛け合わせるだけで実現できます。パンの設定につても同様です。
次回の予定
3回にわたって作り込み、徐々に機能を追加してきたオーディオプレーヤーですが、とりあえず今回で完成したものとします。オーディオの次はビデオ、ということで次回はビデオプレーヤーの作成取り組みたいと考えています。これについても、フレームワークの選択により、いろいろなレベルのものが考えられますが、とりあえずはもっとも簡単に実現できるものから入るつもりです。