Tuesday, May 20, 2014

僕とFlacとの格闘

Flacのような長い音楽ファイルの再生にAndoridは特化しているわけではない。とくにFlacの場合CueSheetにも対応していないので、自前で頭出しを実装する必要がある。
これは、僕とFlacファイルとの格闘を、今後この問題が解決し後に振り返るためのメモである。

Day1-Day8
Day1〜Day8としたけど、実際何日たったかなんて覚えてない。
メモをしないといけないと気づいたからだ。そしてそれが今日である。
事の発端は、ある長い音楽ファイルである。
この音楽ファイルはファイルフォーマットはMP3だが、ファイルサイズが1G近くもあり、再生時間も6時間ほどもある。本来このファイルは垂れ流しで聞くものなので、用途を間違えなければ問題はない。
しかし、途中まで聞いていて次に再生するときに頭から聞くのはつらいし、またお気に入りの曲からはじめるといったことも難しい。
そこで、インデックスを別途準備し、分割されてないにも関わらず分割されているような操作性を提供できないかと思った。

調べると、同様のことをFlacは既に実現しているらしい、フォーマットはCueSheetというファイルのようだ、独自フォーマットを作るのもやぶさかではないが、まずはCueSheetを調査し、良い部分を取り込む方向で作業をすすめることにした。
つまり、遠回りにはなるけど、まずはFlacCueSheet対応をしてみることにした。

結果、なんとかCueSheet対応ができた。
同様のアプリは既にPlayStoreにもあるため、新規性はないが容量の大きいファイルでもストレスなく再生できる点で他のアプリより優位性があるように思える。

同じ手法で、暫定的なフォーマットを作成し、MP3でも再生できることを確認した。

実用性が出てきた為、実装はこのあとさらに加速していく。
プレイリスト、フォルダ選択だけに限るが、曲の選択ができるように実装した。
再生中の画面としてビジュアライザーを実装した。
次はイコライザの実装にとりかかる。

そして、現在躓いている。

容量の大きい音楽ファイルの再生でイコライザーを設定すると、曲の頭出し時に”ジッ”というノイズがはいる。

これの除去がうまくいかない。

ここまで書いて、考えがまとまっていないことに気づいた。
まずは状況を分析することからはじめようとおもう。

・MediaPlayer1とMediaPlayer2
曲のギャップを減らすために、この2つに音楽ファイルを設定する、
ただし、次の曲が同じファイルの場合は2つ同じファイルを読むのは無駄なので、MediaPlayer2はPositionだけを保持した空のMediaPlayerになる。
これを実現するためにMediaPlayerをラップしている。

・AudioEffect
AudioEffectはMediaPlayerと1:1である必要はないため、MediaPlayer1とMediaPlayer2で共有している。つまりAudioSessionIDで一個つくっている。
これはサービス側の話。 イコライザーの設定画面でも一個もっている、こちらはAudioSessionIDをサービスから取得し生成している。
この際、イコライザー設定画面のイコライザーの優先順位を高くするためプライオリティーを高く設定している。

・Config
イコライザー設定画面からイコライザーの設定を変更したら、一旦Preferenceに値を保存する。
その後、Service側に変更を通知し、再読み込みを行う。


現在は上記のような実装になっている、ここまでくるのに、いくつかのTryErrorがあった、結局上記の手法でもノイズがはいるのだが。

現時点までの工夫として
・AudioEffectは何度も生成しないようにする。
・onPreparedのほかに、onSeekCompleteも実装し、曲が再生可能な状態になってからstartを行う。

以前、イコライザーのEnableをStartの直後にTrueにするようにしてみると、上手くいっていたことがあった、しかしこの場合、意図的に初期読み込み時はEnableをFalseしておく必要があるため状態管理に苦労した。動作が不安定になったのもこの処理が複雑になりすぎたためであるため、現在他の方法を模索している。

曲の読み込み時の一回目だけジッというのノイズがはいる、その後は曲の移動(Seek)ではノイズがはいらない、ロジックにどのような違いがあるのかもう一度見なおしてみる。










No comments:

Post a Comment