スマホに機種変更してきました。
機種は、モトローラのRAZR。
http://plusd.itmedia.co.jp/mobile/articles/1202/27/news065.html
決め手は、Android4.0へのアップデートを予定しているという点。
私が開発・販売するアプリケーションの対象OSは、Android2.3系統ですが。
タブレット(ideapad)の方を「想定最低OS」のデバッグ専用機にする方向。
スマホ(RAZR)の方は、最終点検+私用用途ということで、最新状態を保ちます。
料金は、来月から2年間、3980円(定額通信)+399円(保険)+780円(基本料金)/月。
3年目以降、4480円+399円+780円/月。
ちょっと想定(月5k未満)よりも高くなってしまった...
どうやら、5460円の中には、電話+EZWEBの基本料金(780円)が含まれないらしい。
まぁ、良いか。
「アプリ販売で賄えるようにする」
という目標ができたということで良しとしておきます。
使用実績が少なければ、固定定額プラン(5,460円/月)から約2,000円/月~6,000円/月の範囲の変動プランにすれば、概ね許容範囲にできるようですし。
あと、どうでも良いことですが、初期費用=本体価格(約55,000円)が、月賦でも一括払いでも支払額が同じというのが微妙な気分。
ちなみに、INVADER BLOCK 2をスマホ(RAZR)にインストールして遊んでみましたが、タブレットよりもかなり遊び易い。
画面が小さくて遊びづらいんじゃないかな?と心配していたのですが、安心しました。
2012年3月10日土曜日
変え時か
Androidアプリを作ってはいるけど、実はスマートフォンを持っていません。
3G契約不要のタブレットで使えば良いので。
ネックなのは、月額費の高さ。
普通の携帯電話なら月1,000円ぐらいですが、スマートフォンだと月5,480円ぐらい。
ただ、どうもauの光通信に加入していれば、月1,500円程度安くなるらしい。
ただし、1,500円安くなるのは最大2年で、3年目以降は月1,000円引き(月4,480円)らしいですが。
まぁ、月5,000円未満なら、悪く無さそうだと思い始めました。
2012年3月8日木曜日
音が鳴らない問題 (更新3※解決)
今日、会社でINVADER BLOCK 2で遊んでいたのデバッグをしていたところ、何故か、音が鳴らない現象が発生し、一瞬「バグかな?」と思い、焦りました。
しかし、INVADER BLOCK 2のプロセスを止めて再起動しても現象が再発します。
なので、どうやら、INVADER BLOCK 2のバグではなさそうです。(推測ですが)
帰宅後にlogcatでログを確認してみたところ、AudioFlingerというプロセスが、「TrackBase::getBuffer buffer out of range:」みたいな感じのエラーを延々と出し続けていました。
AudioFlingerというのは、Androidの音声入出力を担うプログラムのようです。
ググればソースコードも見つかります。
問題のエラーを出している部分の実装は、以下のような感じでした。
■AudioFlinger.cppより抜粋
※このソースのライセンスはApache License 2.0です
たぶん、波形情報のバッファを取り出して再生をおこなうための処理だと思います。
何らかの原因でバッファが不整合な状態になり、それが継続してしまい、音が鳴らなくなった・・・という感じでしょうか。
別のプログラムが不正なバッファを渡し続けていて、それに巻き込まれたのかな?
または、AudioFlingerの不良?
こういう場合の調査は、「非は自分にある」と断定してするのが鉄則なので、愚直にINVADER BLOCK 2の処理に問題がないのかも点検しておきます。
ちなみに、INVADER BLOCK 2は、OpenSLを使って音声出力の処理を行っていますが、OpenSL自体、まだ出て間もないもののようなので、OpenSLのバグという可能性も・・・まぁ、そこは気にせず、「非は自分にある」と断定して。
■追記1 (2012/03/09 00:30頃)
愚直にコードを見直してますが、「コレだ!」と確証の持てるバグは無いです。
あと、現象を再現させるために、色々怪しそうな操作をしていますが、一度も再現してません。
海外に幾らか同件と思しき現象の報告のようなものがありますが、解決はしていなさそう。
ちょっと、OS側のソースを解析してみようか考え中。(今日はもうやりませんが)
■追記2 (2012/03/10 00:30頃)
やはり、アプリケーション(INVADER BLOCK 2)の問題ではなさそうな気がします。
そもそも、アプリのプロセスを止めているのに発生し続けていた時点で、その点は確定ですが。
(この問題が発生すると、Androidを再起動するまで現象が発生し続けます)
仮に、アプリレベルで引き起こせる問題だと、もっと世界中で大問題になっている筈。
それにしては、情報が少な過ぎます。
同件と思しき現象が発生しているっぽい情報は以下。(2009年の情報)
http://code.google.com/p/android/issues/detail?id=3197
ちなみにこの現象ですが、開発中は1回も発生したことが無いです。
開発が終了した3月1日に、ちょっとした勘違いでOSのアップデートをしてしまったのですが、それ以降発生したという点がちょっと怪しい。つまり、OSがアップデートでデグった可能性もゼロではないのではないかと。ちなみに、現象が発生したOSは、現時点(3月10日時点)でLenovoの IdeaPad Tablet A1 に適用できる最新のAndroid 2.3.4。(リリースされてから日が浅いため、情報が少ないとか)
もうひとつ、考えられるのが、常駐プログラムの不具合。
OSの不具合だとすると情報が少な過ぎるので、可能性としてはそっちの方が高い。
ちなみに、私の端末で常駐させているプロセスは、
①設定
②Androidシステム
③Googleサービス
④マップ
⑤GO Keyboard for Lenovo
とりあえず、「④マップ」は要らないので消そうとしたところ、結構中核のもの?っぽいことが書いてあったし、音は出さないだろうから放置で。
「⑤GO Keyboard for Lenovo」は音を出すアプリなのでちょっと関係しそう。
念のため、普通のAndroidキーボード(無音)に変更。
この状態で再発したら、再び更新します。
それまで様子見。
■追記3 (2012/03/18 00:30頃)
再現はしてませんが、OS側の実装を調査した結果、原因が判明しました。
INVADER BLOCK 2のバグということになります。
修正版のINVADER BLOCK 2は先ほどリリースしました。
で、問題の原因ですが、OpenSLのリソース解放関連の処理手続きに問題がありました。
解放(Destroy)を行う前にSetPlayStateでSL_PLAYSTATE_STOPPEDにする必要があるようです。
SL_PLAYSTATE_STOPPEDとDestroyでググれば、色々と情報が出てきました。
↓日本語の情報も有りました。
http://www.ku6.jp/report/5.html
上記記事で書かれている通り、SL_PLAYSTATE_STOPPEDにしなければなりません。そうしないと、音声バッファが不整合な状態になることで、AudioFlingerにヘンなデータが渡ってしまい、結果として「TrackBase::getBuffer buffer out of range」の洪水が起きる形になり得ます。
しかし、INVADER BLOCK 2のプロセスを止めて再起動しても現象が再発します。
なので、どうやら、INVADER BLOCK 2のバグではなさそうです。(推測ですが)
帰宅後にlogcatでログを確認してみたところ、AudioFlingerというプロセスが、「TrackBase::getBuffer buffer out of range:」みたいな感じのエラーを延々と出し続けていました。
AudioFlingerというのは、Androidの音声入出力を担うプログラムのようです。
ググればソースコードも見つかります。
問題のエラーを出している部分の実装は、以下のような感じでした。
■AudioFlinger.cppより抜粋
void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { audio_track_cblk_t* cblk = this->cblk(); int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize; int8_t *bufferEnd = bufferStart + frames * cblk->frameSize; // Check validity of returned pointer in case the track control block would have been corrupted. if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) { LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ server %d, serverBase %d, user %d, userBase %d, channels %d", bufferStart, bufferEnd, mBuffer, mBufferEnd, cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels); return 0; } return bufferStart; } |
たぶん、波形情報のバッファを取り出して再生をおこなうための処理だと思います。
何らかの原因でバッファが不整合な状態になり、それが継続してしまい、音が鳴らなくなった・・・という感じでしょうか。
別のプログラムが不正なバッファを渡し続けていて、それに巻き込まれたのかな?
または、AudioFlingerの不良?
こういう場合の調査は、「非は自分にある」と断定してするのが鉄則なので、愚直にINVADER BLOCK 2の処理に問題がないのかも点検しておきます。
ちなみに、INVADER BLOCK 2は、OpenSLを使って音声出力の処理を行っていますが、OpenSL自体、まだ出て間もないもののようなので、OpenSLのバグという可能性も・・・まぁ、そこは気にせず、「非は自分にある」と断定して。
■追記1 (2012/03/09 00:30頃)
愚直にコードを見直してますが、「コレだ!」と確証の持てるバグは無いです。
あと、現象を再現させるために、色々怪しそうな操作をしていますが、一度も再現してません。
海外に幾らか同件と思しき現象の報告のようなものがありますが、解決はしていなさそう。
ちょっと、OS側のソースを解析してみようか考え中。(今日はもうやりませんが)
■追記2 (2012/03/10 00:30頃)
やはり、アプリケーション(INVADER BLOCK 2)の問題ではなさそうな気がします。
そもそも、アプリのプロセスを止めているのに発生し続けていた時点で、その点は確定ですが。
(この問題が発生すると、Androidを再起動するまで現象が発生し続けます)
仮に、アプリレベルで引き起こせる問題だと、もっと世界中で大問題になっている筈。
それにしては、情報が少な過ぎます。
同件と思しき現象が発生しているっぽい情報は以下。(2009年の情報)
http://code.google.com/p/android/issues/detail?id=3197
ちなみにこの現象ですが、開発中は1回も発生したことが無いです。
開発が終了した3月1日に、ちょっとした勘違いでOSのアップデートをしてしまったのですが、それ以降発生したという点がちょっと怪しい。つまり、OSがアップデートでデグった可能性もゼロではないのではないかと。ちなみに、現象が発生したOSは、現時点(3月10日時点)でLenovoの IdeaPad Tablet A1 に適用できる最新のAndroid 2.3.4。(リリースされてから日が浅いため、情報が少ないとか)
もうひとつ、考えられるのが、常駐プログラムの不具合。
OSの不具合だとすると情報が少な過ぎるので、可能性としてはそっちの方が高い。
ちなみに、私の端末で常駐させているプロセスは、
①設定
②Androidシステム
③Googleサービス
④マップ
⑤GO Keyboard for Lenovo
とりあえず、「④マップ」は要らないので消そうとしたところ、結構中核のもの?っぽいことが書いてあったし、音は出さないだろうから放置で。
「⑤GO Keyboard for Lenovo」は音を出すアプリなのでちょっと関係しそう。
念のため、普通のAndroidキーボード(無音)に変更。
この状態で再発したら、再び更新します。
それまで様子見。
■追記3 (2012/03/18 00:30頃)
再現はしてませんが、OS側の実装を調査した結果、原因が判明しました。
INVADER BLOCK 2のバグということになります。
修正版のINVADER BLOCK 2は先ほどリリースしました。
で、問題の原因ですが、OpenSLのリソース解放関連の処理手続きに問題がありました。
解放(Destroy)を行う前にSetPlayStateでSL_PLAYSTATE_STOPPEDにする必要があるようです。
SL_PLAYSTATE_STOPPEDとDestroyでググれば、色々と情報が出てきました。
↓日本語の情報も有りました。
http://www.ku6.jp/report/5.html
上記記事で書かれている通り、SL_PLAYSTATE_STOPPEDにしなければなりません。そうしないと、音声バッファが不整合な状態になることで、AudioFlingerにヘンなデータが渡ってしまい、結果として「TrackBase::getBuffer buffer out of range」の洪水が起きる形になり得ます。
2012年3月7日水曜日
性能良好
作成した自作PSG音源エミュレータ+ドライバでベンチマークをしてみました。
あんまり厳密な解析じゃないけど。
ちなみに測定環境は、
という、環境。
CPUに関しては、性能の悪さに定評のあるAtom。
この環境で開発もやっているから、Android用のコンパイルには物凄く時間が掛かります。
ですが、ベンチマーク用としては妥当です。
グラフィック(GPU)性能がちょっと良すぎる点がアレですが。
まず、VG-Engine(グラフィックのみ)でプロセスを起動した場合、CPU使用率は約5%前後。
で、VG-Sound(と、命名したオリジナルPSG音源エミュレータ)で、6ch同時に発音した状態で測定したところ、CPU使用率は概ね約7~8%前後。
ちょっとだけ、上がってしまいました。
ですが、この程度であれば、Android上でもサクサク動けます。(多分)
かなり、性能面には気をつけました。主に、
前者は単純に分岐回数を可能な限り少なくするだけ。
(ループ値は論理積を使うなど)
後者は、本当に性能upに寄与するか、ケースバイケース。
例えば、エンベロープの計算に百分率が必須ですが、百分率を整数のみで計算する場合、
※ここでは説明をし易くするために百分率といってますが、 実際は128分率とか64分率などで計算するのが一般的
FPUが高性能な場合、全ての数値を浮動小数点数で計算すれば、結果的には浮動小数点数のみで計算した方が命令の実行ステップが少ない分、高速になる可能性があります。ただ、実数は精度が悪い(表現できない数が多い)ので、「全てを浮動小数点数で」という部分がネック。音の場合、波形データは整数(16bitの2の補数)だから、FPUが早くても整数・実数間の変換がボトルネックになるし、パイプラインハザードは極力実装レベルでも防いでいるからステップ数はあまり問題にならない筈だ・・・
ということを悶々と考えた結果、実数を排除するのがベストと判断。
(単純に、実数がキライだというのもあります)
結果、Windowsではそこそこ良い性能結果だったので、読みは当ったんだろうと、思っておきます。
Androidでも同じ結果になるかは、定かではないですが。
あんまり厳密な解析じゃないけど。
ちなみに測定環境は、
- 型式:Acer AspireRevo R3610
- CPU:Atom330 / 1.6GHz / 64Bit
- メモリー:4GB
という、環境。
CPUに関しては、性能の悪さに定評のあるAtom。
この環境で開発もやっているから、Android用のコンパイルには物凄く時間が掛かります。
ですが、ベンチマーク用としては妥当です。
グラフィック(GPU)性能がちょっと良すぎる点がアレですが。
まず、VG-Engine(グラフィックのみ)でプロセスを起動した場合、CPU使用率は約5%前後。
で、VG-Sound(と、命名したオリジナルPSG音源エミュレータ)で、6ch同時に発音した状態で測定したところ、CPU使用率は概ね約7~8%前後。
ちょっとだけ、上がってしまいました。
ですが、この程度であれば、Android上でもサクサク動けます。(多分)
かなり、性能面には気をつけました。主に、
- パイプラインハザードの防止
- 浮動小数点は使わない
前者は単純に分岐回数を可能な限り少なくするだけ。
(ループ値は論理積を使うなど)
後者は、本当に性能upに寄与するか、ケースバイケース。
例えば、エンベロープの計算に百分率が必須ですが、百分率を整数のみで計算する場合、
- 割られる数×100 ÷ 割る数 = p(100%なら100)
- n×p÷100 = nのp%の値
※ここでは説明をし易くするために百分率といってますが、 実際は128分率とか64分率などで計算するのが一般的
FPUが高性能な場合、全ての数値を浮動小数点数で計算すれば、結果的には浮動小数点数のみで計算した方が命令の実行ステップが少ない分、高速になる可能性があります。ただ、実数は精度が悪い(表現できない数が多い)ので、「全てを浮動小数点数で」という部分がネック。音の場合、波形データは整数(16bitの2の補数)だから、FPUが早くても整数・実数間の変換がボトルネックになるし、パイプラインハザードは極力実装レベルでも防いでいるからステップ数はあまり問題にならない筈だ・・・
ということを悶々と考えた結果、実数を排除するのがベストと判断。
(単純に、実数がキライだというのもあります)
結果、Windowsではそこそこ良い性能結果だったので、読みは当ったんだろうと、思っておきます。
Androidでも同じ結果になるかは、定かではないですが。
音源ドライバ完成
週末は、MMLコンパイラを作る作業に専念したいため、前記事の分解率の問題を平日中に直してしまおう・・・と、思い昨夜、AM2:00ぐらいまで頑張っていたら、今日会社でグロッキー状態でした。
30を過ぎると、2時寝・6時起きはキツイ。
その甲斐あって、無事、音源ドライバ部分も完成。
以下のような感じで発音(KEYON)や消音(KEYOFF)などの指示情報をズラズラ並べれば・・・
↓こんな感じで演奏してくれます。
http://www.k2.dion.ne.jp/~ysuzuki/seikou3.mp3
若干、音程が切り替わる間のプツッという部分が気になります。
こういう風になる原因は、音が切り替わった時の直前の波形からの差異が大きいため。
パッと考え付く限り、回避する手段は、
あたりかな。
前者は、MMLコンパイラで回避でき、後者はアルゴリズムで回避。
どっちが良いのかが、よく分からない。
30を過ぎると、2時寝・6時起きはキツイ。
その甲斐あって、無事、音源ドライバ部分も完成。
以下のような感じで発音(KEYON)や消音(KEYOFF)などの指示情報をズラズラ並べれば・・・
↓こんな感じで演奏してくれます。
http://www.k2.dion.ne.jp/~ysuzuki/seikou3.mp3
若干、音程が切り替わる間のプツッという部分が気になります。
こういう風になる原因は、音が切り替わった時の直前の波形からの差異が大きいため。
パッと考え付く限り、回避する手段は、
- 消音のエンベロープ時間を短くし、キーオフの待ち時間中に波形相異0で安定させる
- キー切り替え時に近似値を算出し、乖離を少なくする
あたりかな。
前者は、MMLコンパイラで回避でき、後者はアルゴリズムで回避。
どっちが良いのかが、よく分からない。
2012年3月5日月曜日
分解率(解決)
昨日、独自PSG音源の分解率(分解性能)のことで難産してましたが、解が見えてきました。
VG-Engineの音声システムは、100ミリ秒の周期で発音情報をD/A変換(ディジタルデータを音に変換)する形で音声を鳴らしています。WindowsとAndroidで、この部分の実装に用いる仕組みは違いますが、理屈は同じ。
で、独自PSG音源+ドライバ(音源を発音させたり、消音させたりする処理部分のこと)は、何れも「100ms分の音バッファを作る」処理部分で実装してます。
問題があったのは、独自PSG音源の①発音(キーオン)、②消音(キーオフ)、③無音で処理をスイッチ的に切り分けていたこと。だから、そこでドライバのキーオンやキーオフの指示を処理するのが難しかった訳です。
なので、その部分の処理をスイッチ的に切り分けるのではなく、キーオン、キーオフ、無音などの状態に関係無く、常に(元々の)①発音(キーオン)相当として処理すれば良い訳です。
偉そうに言ってますが、実はコレ(スイッチ的に切り分けること自体が)、単純なバグじゃないか・・・
・・・ということに、この記事を書いていて気付きました。
何故昨日、気付かなかったし。
まぁ、バグとは得てしてそういうものか。
(ロジック的なバグは、処理を言葉で書いて整理すれば、解決し易い)
VG-Engineの音声システムは、100ミリ秒の周期で発音情報をD/A変換(ディジタルデータを音に変換)する形で音声を鳴らしています。WindowsとAndroidで、この部分の実装に用いる仕組みは違いますが、理屈は同じ。
- Windows(DirectSound)の場合: 次の動作をする専用スレッドでループ処理
- 100ms分の音バッファを作る
- D/A変換
- 100再生完了のイベント待機
- Android(OpenSL|ES)の場合: 100ms再生完了する都度、次の処理を実行(コールバック)
- 100ms分の音バッファを作る
- D/A変換
で、独自PSG音源+ドライバ(音源を発音させたり、消音させたりする処理部分のこと)は、何れも「100ms分の音バッファを作る」処理部分で実装してます。
問題があったのは、独自PSG音源の①発音(キーオン)、②消音(キーオフ)、③無音で処理をスイッチ的に切り分けていたこと。だから、そこでドライバのキーオンやキーオフの指示を処理するのが難しかった訳です。
なので、その部分の処理をスイッチ的に切り分けるのではなく、キーオン、キーオフ、無音などの状態に関係無く、常に(元々の)①発音(キーオン)相当として処理すれば良い訳です。
偉そうに言ってますが、実はコレ(スイッチ的に切り分けること自体が)、単純なバグじゃないか・・・
・・・ということに、この記事を書いていて気付きました。
何故昨日、気付かなかったし。
まぁ、バグとは得てしてそういうものか。
(ロジック的なバグは、処理を言葉で書いて整理すれば、解決し易い)
分解率=分解性能(かなり厄介)
先ほどの記事で、独自PSG音源のドライバ(バイナリのMMLを鳴らす機能)の分解率(分解性能と呼ぶべきか?)を22050回/秒にしようとしましたが、処理実装上、それは不可能・・・ではないけど、もの凄く複雑なことになりそうです。
素直に、音源とドライバは別スレッドで独立させてあげれば楽。
中々面倒です。
しかも、そうなると、分解率は1000回/秒か。
まぁ、1秒間に1000回も音符を鳴らす音楽は想定されないけど。
もの凄い複雑な処理をあくまでもシングルスレッドで実装するか。
又は、簡素にマルチスレッドで実装するか。
私の好みは前者ですが。
スレッドはオーバーヘッドが大きいので、不可避な事情が無い限り、使わない派。
プログラミングを始めた頃(11歳頃)から現在にかけて出会った、難しいロジックのベスト30位以内に入ると思います。公私で膨大な量のプログラムを日々作り続けているから、あまり定かではないですが。
さて、どうしたものか。。。
全然関係ありませんが、、プログラミングを始めた歳を書いて気付きました。
来年でプログラミング歴20年のようです。
時が経つのは、何とはやいことか・・・
素直に、音源とドライバは別スレッドで独立させてあげれば楽。
中々面倒です。
しかも、そうなると、分解率は1000回/秒か。
まぁ、1秒間に1000回も音符を鳴らす音楽は想定されないけど。
もの凄い複雑な処理をあくまでもシングルスレッドで実装するか。
又は、簡素にマルチスレッドで実装するか。
私の好みは前者ですが。
スレッドはオーバーヘッドが大きいので、不可避な事情が無い限り、使わない派。
プログラミングを始めた頃(11歳頃)から現在にかけて出会った、難しいロジックのベスト30位以内に入ると思います。公私で膨大な量のプログラムを日々作り続けているから、あまり定かではないですが。
さて、どうしたものか。。。
全然関係ありませんが、、プログラミングを始めた歳を書いて気付きました。
来年でプログラミング歴20年のようです。
時が経つのは、何とはやいことか・・・
登録:
投稿 (Atom)
合理的ではないものを作りたい
ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...
-
家電量販店のPCゲームパッドコーナーに行くと、軒並みWindows用のゲームパッドしか売っていません。稀に「Mac OS X対応」を謳っているゲームパッドも置いてありますが、実際に動かしてみると妙に誤動作をして更にガッカリしたりとか(経験済み)。 色々と試してみたのですが、最...
-
ゲームボーイのCPUについて、誤った技術情報が検索トップの方に表示されるので、私が把握する限りでZ80との仕様差を書いておきます。 ゲームボーイのCPUとは? ☓ 8080 ☓ Z80 ○ 8080カスタム or Z80カスタム(正確にはSHARPのLR35902) ...
-
MSX開発の関係者を匂わせるタイトルかもしれませんが、私は全然関係ない(外野)です。 私はマイコン世代(死語)の人間ですが、実はリアルタイムでMSXは触ったことすら無いです。私が最初に触ったパソコンはPC-9801(16bit機)で、8bit機のMSXは触る機会すらありませんでし...