100日後に完成するゲームシステム 75日目「サウンド機能の深刻な問題(解決編)」

2021年5月5日

テクノロジー 特集

eyecatch プログラムで詰まったことがあると、夜まるで眠れない、弓削田です。 おかげで、ここ1週間ほど睡眠不足ですが、 仕事ストレスというわけではないので、毎日ジョギング5kmは、手を抜いていませんよ!! そして、なんと、ここ数日悩ましかった、WebAudioAPIのsafari問題が解決しました。 いや〜めでたい。 ということで、今回は、解決方法の備忘録と、そもそもの問題点などを書き残しておきたいと思います。 これが難しいからWebAudioが難しいと言われているのかな?

問題点のおさらい

そもそも、何が問題だったのかを、思い出しながら、リストアップしておきます。 1、iPhoneで全く音が出ない -> メモリ不足? ※挙動も遅くなった感じがあったので、Audioメモリというよりは、webブラウザの許容量の問題だったのかも・・・ 2、Macのsafariブラウザで、音が鳴らない時がある。 setTimeoutとの組み合わせで、他のブラウザでは問題ないのに、webkitプレフィックスベースであるsafariだけ何故か挙動が違う! 3、ブラウザのクリック(タッチ、キー)イベントの後でないと、AudioContext設定が出ない ※その前にセットすると、コンソールにガッツリエラ〜メッセージが表示されてしまう。 とりあえず、大きく分けてこの3パターンの問題点だね。 全くもって、めんどくさいしワケワカメなのである。

解決方法

とりあえず、解決方法も、リストアップしてみる。 1、AudioContextの宣言位置が非常に重要 WebAudioAPIのことでソースコードを記述しているサイトは、山のようにあるので、 コピペで使ってみて、うまく動くものも多いだろう。 でも、イベントに絡めたり、実際にゲームで使えるレベルでの書き込みをしてくれているサイトは 皆無なのである。 connectやbufferやgainの仕組みを図入りのconnect解説してくれているサイトはあるが、 こうしたサイトでも、問題は解決できる内容にはなっていなかった。 1つだけのmp3ファイルや、音を出すレベルは、基本的に、今回のような問題は起きないからだ! 実践プログラミングで初めて体験することができる事象と考えてもいいので、 こうした経験はある意味重要とも言えるかもね。 そして、肝心のAudioContext宣言は、どのサイトも次のように書かれている。 window.AudioContext = window.AudioContext || window.webkitAudioContext; let context = new AudioContext(); let osc = context.createOscillator(); let source = context.createBufferSource(); 上記のプログラムはかなり端折ってかいているんだけど、 oscとbufferSourceは、1つの出力で同居することはないので、 このままコピペしても動かないよ。 そして、今回わかったのが、AudioContextをnewするタイミングを、音を出すたびに行うのではなく、 最初にイベントが発生した1回のみでいいのだったのだ。 これが、他のサイトで説明がない点であった! なので、グローバル変数に格納して(定数でもいいかも) bufferSourceでも、Oscillatorでも、使いまわすというやりかたがいいようだ。 そして、重要なのが、イベントのタイミングと機能の制限が次のようになっている。
1. AudioContextは、イベント後でないとworningメッセージがjsコンソールに表示される。 2. サウンドを鳴らすのは、さらにAudioContextをセットした後にイベント処理が必要
何となく、2回のイベントがあれば、成り立つのだが、1番目のAudioContextのworningは、 出ていても何の問題もなさそう(2021年4月の現段階において) なので、ページ読み込み直後にAudioContextを定義して、音源データの読み込み後(設定後)に 画面をクリックさせるような仕組みができれば、問題位というワケ。 2、currentTimeの値取得が重要。 次に、Oscillatorの時に、上記だけでは、いまいち音がならなかったので、 試しにやってみたんだけど、startするtimeの基準を0として扱っていたんだけど、 osc.start(0)ってやってたってことね。 これを、 osc.start(context.currentTime); として、他の音の数値を、全て、currentTimeの値を追加するという手順をすっ飛ばしていたのが原因で 音が鳴っていなかったようだ。 let t0 = context.currentTime; などとして、使いまわせばいい感じにプログラムが綺麗に、効率的に、できた。

改めて使える道筋が見えたWebAudio

とりあえず、上記解決策を元に、コードを改修してみたところ、 GoogleChrome , safari , スマホブラウザで、問題なく、音がでるようになりました。 繰り返し音も、setTimeoutなどの時間差も、何の問題もなくなった!!!!! こりゃめでたい!! 今日はうまい酒が飲めそうだ。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ