2014年1月26日日曜日

音の迷宮事件 Xperia と SoundPool

1月冒頭の記事(これの2つ前)で、ディスプレイのアスペクト比が変わったらどうのこうの… と心配していましたが、実機で確認した結果は問題なしでした。
SC-02B(4.0 inch)(800x480 比率1.67倍)
SO-02F(4.3 inch)(1280x720 比率1.78倍)
F-02F(10.1 inch)(2560x1600 比率1.6倍)

LC-20DZ3(20 inch)(1366x768 比率1.78倍)<シャープの液晶LED/TV>
PSP(4.3 inch)(480x272 比率1.76倍)<ポータブルゲーム機>

参考までに家にあったスマートフォン以外のディスプレイも調べてみました。 Xperia は20インチテレビとほぼ同等の解像度。 Arrows のタブレットは余裕で20インチテレビをぶっちぎっています。 まあ、そんなことより重要なのは縦横比が 1.6~1.78倍という限られた範囲で推移しているということです。 android でアプリを作る場合は様々な機種に対応するように配慮しなければなりませんが、 かといって 1200x600 みたいな存在しないケースは無視してしまって構わない。 あくまで実勢の範囲内で適合させていく努力が必要ということです。 まあ、私はまったくやったことありませんが iPhone でのアプリ開発の方がその点では楽勝ですね。

で、機種毎による違いというものはディスプレイ関係だけではすまない。 実際に実機でテストしてみると「はぁ!?」という事態がときどき起こり得ます。 今回は音の問題です。

SoundPool というものを使って効果音をだしていました。 10秒未満な短い音を同時多発的に出していく場合に有効な手段です。 で、去年まではデバッグ用実機としてギャラクシーしかありませんでしたから、それで音が鳴れば「よっしゃよっしゃ」と開発を進めていた次第です。 で、今回 Xperia と Arrows で実機テストを行った際、Arrows では問題なく音が鳴りましたが、 Xperia だと音がちっちゃい。「えっ?」って思いますよね。

そもそも SoundPool で鳴らされる音量はどうやって決まるのか?

streamID = sp.play( seID[1], volLevel, volLevel, 1, 0, 1.2F);

たしかに↑でいうところの volLevel には 0.1~1.0 の変数を入れ込みます。 これによって音量が変わる仕様です。 で、0.1~1.0 まで数値を変えたら出力されるボリュームが段階的に変わるのか? といったら、う~ん、という感じです。 まあ、これはちょっと置いておいて、ベースの音量というものがあります。

sp = new SoundPool( 8, AudioManager.STREAM_MUSIC, 0 );

↑みたいな初期設定を onCreate() あたりで行いますが、STREAM_MUSIC、要するに音楽やゲームで使われる音量がベースとなります。

sp = new SoundPool( 8, AudioManager.STREAM_ALARM, 0 );

↑みたいにすれば、STREAM_ALARM、アラームの音量がベースとなります。 いずれにせよ SoundPool を利用する際は何らかの音源(他には電話音量 STREAM_RING なども)を拠り所にしています。

とりあえず Xperia で音が小さかったので音を大きくしてやろう。 いろいろ試した結果、 play の前に

AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
int max_volume = am.getStreamMaxVolume(AudioManager.STREAM_ALARM);
am.setStreamVolume(AudioManager.STREAM_ALARM, max_volume, 0);

このようにすればアラームの最大音量を取得しセット、それを play に適用しますから大きな音で SoundPool が鳴ります。 なぜ、STREAM_MUSIC ではなく STREAM_ALARM にするかというと、 bgm をメディアプレイヤーで鳴らしており、それの音量が STREAM_MUSIC に由来しているからです。 つまり、STREAM_MUSIC を下手にいじれば bgm に干渉してしまう、だから、STREAM_ALARM を使ってみました。 勝手に(ユーザー端末の)アラーム音量をいじるわけですから、用が済んだら元のアラーム音量に戻しておくのはマナーとして忘れずに。 とにかく、このやり方だと Xperia でも音が大きく鳴りました (最終的にはMAX音量から -1 した値で音量セットするようにしました)。 しかし、Galaxy や Arrows で試したらばかでっかい音が鳴ってしまう。うるせぇ!

本当にいろいろ試しました。試行錯誤といやつでしょうか? まず考えた大筋はユーザーに効果音量を設定させて、 その設定を保存しておく、というものでした。 なにせ、3機種でしか実機テストを行っていませんので、他の端末ではどうなるのかは分かりません。 だから、ユーザー側で任意に調整できるようにしておくのが親切かつフレキシブルだろうと判断しました。 できたら、1~5段階くらいの効果音設定をしたかったのですが、いろいろ試した挙句、
極小<<<<<適音(やや小さめ)<適音<適音(やや大きめ)<<<<<爆音
みたいな感じにしかできなかったので、「強・弱」の2段階設定に落ち着きました。 つまり初期設定は弱であり、Galaxy と Arrows だとこれで普通に効果音が聞こえます。下手に強にしてしまうと 爆音地獄になりますが、すぐにユーザーは元の弱設定に戻すことでしょう。 Xperia だと初期設定ではもろもろの効果音がとても小さく再生されます。 これを強に変えると適当な音量に落ち着きます。

        if(Otsu4Activity.seVolLevel==0) {
            sp = new SoundPool( 8, AudioManager.STREAM_MUSIC, 0 );
        } else {
            sp = new SoundPool( 8, AudioManager.STREAM_ALARM, 0 );
        }
↑こういう感じで強設定なら STREAM_ALARM でいき、弱設定なら STREAM_MUSIC でいきます。 弱設定の場合は道なりで行くので、SoundPool の音量は STREAM_MUSIC に比例します。 つまり、BGM の音量にリンクします。 しかし、STREAM_MUSIC のボリュームが 10以上になると爆音領域に突入するので STREAM_MUSIC のボリュームが 10以上の際はボリューム 9 という扱いにしています。

なかなか仕様書どおりにはいきませんねえ、という話でしたが、 Galaxy と Arrows ではまったく同じ挙動を示したので、 おろらく Xperia 以外の機種だったら弱設定でうまくいくのではなかろうか? と思います。 ググったら Xperia で SoundPool を処理させる場合に不具合がでやすいみたいな記事をいくつか見かけました。 真相は分かりませんが、こういった端末間における(予期せぬ)再現性の違いというものが Android につきものなのは 間違いなく、iPhone でのアプリ開発の方がその点では楽勝ですね。

0 件のコメント:

コメントを投稿