2022年7月1日金曜日

お気に入り編集機能を検討中(東方VGS)

先日追加した東方VGSのお気に入り機能ですが、さっそくユーザーから「旧バージョンの頃(マイリスト)の方が使いやすかった」というご指摘をAppStore上のレビューで頂いたので、何がマズかったのかな...と考えてみましたが、お気に入り追加が曲を再生しないとできないので、リストエディット的な用途としては確かに不便かもしれません。

ある程度意図的にそうしてみたのですが、不満が出てしまった以上は改善検討します。

という訳で「お気に入り編集」機能を考え中です。

Favorites ページに【+】ボタンを追加して、

【+】ボタンを押せば纏めて編集できる感じのもを検討中です。

プラスだけでなくマイナスもできるので正確には【±】ですが、初見ユーザーが最初に Favorites ページを開いた時、リストが空っぽの確率が高いので、【+】があれば「あぁ、これで追加できるのか」という感じになり、その時【±】だと一定数「なんじゃこりゃ?」となるリスクがあるかも...ということで【+】にしてみました。

✎でも良いかもしれませんが。



2022年6月30日木曜日

Android版東方VGSでワイヤレスイヤフォンが使えない件の調査状況

ここ数日、Android版の東方VGSがワイヤレスイヤフォンを使うと再生できないという不具合の調査をしています。

https://github.com/suzukiplan/tohovgs4-android/issues/34

現象は モダンUI でのみ発生して RETRO UI では発生しません。

モダンUI と RETRO UI では内部的に音声の再生方法が異なります。

  • モダンUI = AudioTrack
  • RETRO UI = OpenSL/ES

という訳で、AudioTrack の使い方が誤っているのかも?と疑って調査をしたのですが、実装レベルでの誤りは見つかっていません。

「AudioTrackの初期化が失敗している」といった分りやすい事象が起こってくれれば良いのですが、そのような形跡はなく、疑わしいログ出力もありませんでした。

どうやら、ワイヤレスイヤフォンを接続するとAudioTrackが見た目上は正常に動くけど、バッファリングしたデータが勝手に破棄されるような挙動をしているようです。現象発生時の adb logcat を確認したところ、OS の bluetooth インタフェースと思しきものが一時停止(suspend)の状態になっている事が確認できす。

06-29 21:11:18.367  2320  2728 I btif_av : system/bt/btif/src/btif_av.cc:3098 btif_av_stream_suspend: btif_av_stream_suspend
06-29 21:11:18.368  2320  3010 I bt_bta_av: system/bt/bta/av/bta_av_api.cc:281 BTA_AvStop: BTA_AvStop: bta_handle=0x41 suspend=true
06-29 21:11:18.403  2320  3010 I bt_btif_a2dp: system/bt/btif/src/btif_a2dp.cc:131 btif_a2dp_on_suspended: btif_a2dp_on_suspended: ## ON A2DP SUSPENDED ## p_av_suspend=0x6e002963c0
06-29 21:11:18.403  2320  3010 I bt_btif_a2dp_source: system/bt/btif/src/btif_a2dp_source.cc:733 btif_a2dp_source_on_suspended: btif_a2dp_source_on_suspended: state=STATE_RUNNING
06-29 21:11:18.403  2320  3010 I bt_stack: [INFO:a2dp_encoding.cc(503)] ack_stream_suspended: result=SUCCESS_FINISHED
06-29 21:11:18.403  1123  1756 I BTAudioProviderSession: ReportControlStatus - status=SUCCESS for SessionType=A2DP_HARDWARE_OFFLOAD_DATAPATH, bluetooth_audio=0x0200 suspended

多分、アプリ → AudioTrack::write → AudioFlinger → bluetooth I/F → bluetooth earphone という流れで音声ビットストリームが流れていく筈で、suspend になった bluetooth インタフェースが音声ビットストリームを破棄しているから AudioFlinger が永久に stream end を検出できず、その結果 AudioTrack の PlaybackPositionUpdateLister が永久に発火しない(発火しないと音楽の再生が進まない)状況に陥っているのではないかと推理しました。

今回のテストで3000円ぐらいの激安ワイヤレスイヤフォンを調達したので、ハード(ワイヤレスイヤフォン側)の問題かも?と疑って、そのワイヤレスイヤフォンをiPhoneに接続してテストしてみましたが、iPhoneでは全く問題無く再生できました。

なので、ハードではなくソフト(アプリ or OS)側の問題であることは間違いありません。

幸い、OpenSL/ESは問題無く動作するので、モダンUI も RETRO UI と同様、OpenSL/ESを使うようにするという回避策もあるかもしれませんが、OpenSL/ES には別の問題があります。(2016年以前のAndroid版東方VGSでは長い間この問題に悩まされていました...)

OpenSL/ESだと何故か、バックグラウンド再生をすると音飛びが発生する仕様です。これはAndroid 8以降で発生するようになったOS側の仕様変更によるもので、Android 12でもまだ治っていません。(OpenSL/ES自体がマニアックなAPIなので多分治ることは無いと想定しています)

※RETRO UI のバックグラウンド再生を制限しているのはこれが理由です(RETRO UI は C言語で作られている関係で、C言語で使えるオーディオ・インタフェースを使わなければならないため、AudioTrackに置き換えることができません)

念の為、AudioTrack→OpenSL/ESに実装を書き換えてテストもしてみましたが、やはりバックグラウンドの音飛び問題は健在でした...

つまり、OpenSL/ESを使ってしまうと事実上バックグラウンド再生に対応できないため、対応したければAudioTrackを使うしかないというのが実情です。

なお、exo-player という Google が公開しているAndroid用動画再生ライブラリ(OSS)があって、その実装でも AudioTrack が使われています。

exo-player は Android版YouTubeでも使われているので、問題のワイヤレスイヤフォンを使ってAndroid版YouTubeで動作確認をしてみましたが、特に問題無く再生できるようです。

東方VGSとYouTubeの音声再生では、音声ビットストリームのエンコーディング形式に違いがあります。

  • 東方VGS: 22050Hz 16bit mono の raw PCM
  • YouTube: AACなど(動画のコーデックを見て切り替え)

bluetoothの帯域はかなり狭いので、リアルタイムに音声データを通信しようとすると raw PCM だと十分なバッファを確保できません。そのため、AAC等の圧縮形式でデータパケットを流す必要があるのですが、もしかするとAudioTrackはその辺を気にせず raw PCM でそのまま bluetooth にデータを流しているかもしれません。(Androidのベーシック層の設計思想は割とこういうパターンが多いので...)

その場合、AudioTrackのエンコーディングを raw PCM から AAC にして、MediaCodec で AAC エンコードしたデータをwriteしてあげれば何とかなるのかな?(OpenSL/ESの場合、そもそもraw PCM以外 buffer write できない仕様だから、bluetoothへ流す時にOS側でAACなりにエンコードしているから正常に動作している...という推測が成り立ちそうな気がします)

AudioTrackをAPI仕様通りに扱っていて正常に動かないので、本件はOS側の不具合だと言える気がするので、一旦この件の対策はせずにOS側の対策を待つしかないかもしれません。

まぁ、そんなこと言ってたらAndroidでプログラムなんか作れない訳ですが...

APIが必ずしも仕様通りに動くと思ってはならない

という訳で内心は早々にギブアップしたいところではありますが、もう少し粘って調査します。

追記: 無事回避策が見つかったので qiita で詳述してみました。(これで、同じ問題に躓く人が出てきた時、ググれば助かる...かもしれない)


 

2022年6月29日水曜日

中学2年生の時に書いた暗黒日記を二十歳になってから読むあの感じ

約7年前に書いた「東方VGSができるまで」 という記事が最近上位にサジェストされてくるので、内容が気になって恐る恐る読み返してみたのですが、中々面白かったです。

Bloggerのサジェストは直近のPVの多い順にされるようで、管理ツールでその記事のPV数を見たら7691でした。

当時と今で思想や考え方が変わっているかな?と思ったのですが、大筋では変わってないようです。

まるで成長してない...

中学2年生の時に書いた暗黒日記を二十歳になってから読むあの感じをイメージしていたのですが、良い意味で期待はずれでした。

WTC1 on VGS も完成させたいですね...東方VGSが終わったら。

まだまだ先は長いですが、健康を損なわなければ恐らく原作に追いつけると思います。(ちなみに私の年齢はZUNさんより少し若いぐらいでだいたい同年代)

若くはないので健康には気をつけてます。

先月受けた人間ドッグで、血圧(B: 低すぎ)と視力(C: 悪い)以外はオールAでした。血液検査でオールAは初めてです。(LDLコレステロールが低い体質なので総コレステロール値が低すぎてCがデフォルト)

健康に悪い(?)ことといえば、若干ワーカーホリック気味なのと喫煙習慣があることぐらい。

タバコは10年ぐらい前に半年間ぐらい禁煙したことがあるのですが、やめたら逆に体が悪くなってストレスで円形脱毛症になったりしたので、健康のために再開しました。再開したら無事毛が生えてきたので幸いまだハゲてませんが、円形脱毛症になったところから生えてくる毛が全部白髪になり若干後悔してます。「禁煙が健康」みたいな風潮があって、それ自体を否定するつもりはありませんが。

ちなみに1年ぐらい前からほぼ禁酒してるところ(誘われたら機会飲酒する程度)で、こちらは特に健康上の問題が出てなくて、逆に血液検査の数値が改善しているところから見て禁酒は健康に良さそうです。

禁酒したから血液検査が良くなった訳ではなく、ここ2年ぐらい(フルリモートになってから)毎週サイクリングをするようになったことが大きな要因かもしれません。荒川サイクリングロードをゆっくり走って自宅から18kmぐらいのところのマクドナルドでランチを食べて帰るという、健康に良いのか悪いのかイマイチ分からない謎ルーチンをほぼ毎週やっています。昔、実家で飼っていたペットの犬が、毎回ほぼ同じコースでも散歩を心待ちにしていた気持ちをようやく理解できた気がします。

あとは、人間とリアルに接するのが苦手で可能な限り家から出たくない引き篭もりタイプなので、2年間フルリモートを続けたことでストレスが溜まらなくなったことも大きいかもしれません。もう、イーロン・マスクの配下では働くことができない体になってしまったようです。

2022年6月28日火曜日

Android版のUI大幅改修(東方VGS)

 Android版のUIをiOS版に寄せる修正を入れました。

下図の左→右に変わります。

内部構造は色々改善しましたが、ユーザーエクスペリエンスが改善できたかは未知数...

内部構造的には、画面下部メニューを独自Viewから BottomNavigationView に変更してます。本当は画面下部メニューにインジケーター(カーソル)を表示したかったのですが、BottomNavigationViewにはその機能が無かったので、現在選択中のページを色の濃淡で表示してます。(色弱者に優しくないかも?)

iOS版に寄せたのは、ユーザーさんのRR(維持率)が明らかにiOSの方が高く、UI以外の機能は等価なので、これはもうUIが原因だろう...ということで。

直近5週間のRRの傾向でも、やはりiOSの方が3割増しぐらいで高い傾向があります。

海外のPlayStore(Android)上のレビューで「UIが残念」という指摘が何件か頂いていて、これが一番の決め手です。(数字は飽くまでも行動を納得させるためのオマケ)

OS標準UIのマテリアルデザインで設計することで、アプリのデザイン手間がいくらか楽になる反面、安っぽくなってしまうという根拠のない仮説もありますが、ただ、見た目のカッコ良さだけで1ヶ月後のRRに差が出てくるとは思えないという疑心も未だにあります。

デザインが共通化されていればエンハンス時のデザインコストを圧縮できますが、脳内設計なのでデザインコストはせいぜい10分間もあれば事足ります。つまり、その作業工程を圧縮するメリット・デメリットはほぼ無い※です。(だから約半年も様子見していた訳です...)

※ワンオペで企画・設計・開発をしている場合に限る

2022年6月27日月曜日

お気に入り機能(東方VGS)

東方VGSにお気に入り機能を入れてみました。

楽曲再生中に右側のハートマークを押すとファボることができ、ALLの「お気に入り」タブでファボった曲がリストアップされ、シャッフル再生とかもできる感じの機能です。

元々はAndroid版のレビューで「プレイリスト機能が欲しい」という要望を頂いたので、要望通りそのままプレイリスト(MyList)を追加しようと思ったのですが、ボトムメニューを6個以上にするとデザイン的に破綻するので迷っていました。

ユーザーさんとTwitterでやりとりしていたら「曲をお気に入りにすることができ、ALL内のお気に入りタブでフィルタすればOK」というナイスアイディアに帰結。

お気に入り機能って何かSNSっぽいですね。

ただ、SNS的な要素は無いシンプルなスタンドアローン機能です。

スマホアプリや機能を開発する時、

  1. W0 (Standalone)
  2. W1 (C/S model = Web 1.0)
  3. W2 (SNS model = Web 2.0)

という3つの選択肢のどれにしようか迷うかもしれませんが、私は迷うこと無くまずW0(Standalone)で作ります。

最近は「Web3.0」なんてものもありますね。

Web 3.0 は簡単に言うと「分散管理台帳を使った非C/Sのピア通信モデル」で、個人的には「それってそもそもWebなの?」というツッコミを入れたい点はとりあえずさておき、仮に選択肢にWeb3.0があってもW0一択です。

というより、ソフトウェアサービス全般に言えることですが、まずはアイディアが思いついたらW0の前提で作ってみることを強くオススメします。

理由はシンプルに「安い」ので。

  • サーバ不要なので初期投資が安い
  • サーバ不要なのでランニングコストが掛からない

W0でニーズが低いものは、W1にしてもW2にしても(恐らくW3にしても)ニーズが低いので、まずはW0で作ってリリースしてみてウケたら次(W1)、更にウケたら次(W2)という形で発展させるのが良いと思っています。

実際、東方VGSがその考え方で開発していて、

  • 2013〜2016年以前の東方VGSはW0(Standalone)モデル
  • 2022年以降の東方VGSはW1(C/S model)モデル

という具合にアップデートしてます。

2022年のアップデートでようやく自前のコンテンツ配信サーバ(GitHub actions + Firebase Hosting)を持ち、サーバ経由で配信した最新楽曲をクライアントからダウンロードできる Web 1.0 になりました。

東方VGSのW1までの進化は時間を掛けすぎですが、ここから W2 へ進化させるべきかについては悩ましいです。

技術やコストの面では問題無いのですが「そもそもやる意味があるのか?」と Web 2.0(SNS)に対してまだまだ懐疑的です。

ちなみに、SNSという略語は英語圏でほぼ使わなくて、英語圏では「Social Media」と呼びますが、Social Mediaは直訳すると「社交媒体」で、C2CでコミュニケーションができるWebサービスを指します。

東方VGS自体がSNSになるのは無意味で、SNSを使って上手いこと東方VGSを拡散できるなにがしかを考えるのは有用だと思いますが...

という訳で東方VGS関連のSNSリンクをSettingsに片っ端から載せてみたりしました。

TwitterとGitHubは元々載せてましたが、YouTubeとTikTokも載せてみました。もちろん、これは単なる雑なリンク貼り付け対応なので、これで「Web2.0は完璧です」とドヤろうとは思っていません。

もう少し高度なWeb2.0化の路線も考えてはいるのですが、考えれば考えるほど「Twitterで良いじゃん」「YouTubeで良いじゃん」という結論に帰結してしまいます。(例えば、アプリ内にVGS版の楽曲ランキングとか入れて、ニコニコ動画の広告みたいな感じの曲毎に運営に投げ銭できる機能とかは割とすぐに思いつきますが、その辺のインフラストラクチャは既にYouTubeで整いつつある...みたいな)

W2については自前で持つより既存のW2サービスを利用していくスタイルが、何やかや一番筋が良いというのが現在の私見です。


2022年6月26日日曜日

iPhoneをオススメする理由

世界には、きのこたけのこ戦争などの宗教戦争が溢れていますが、Android vs iPhone も今となっては宗教戦争の様相を呈しています。

どちらにも良いところと悪いところがあるので、どっちが良いかは各々の好みで良いと思います。

ただ一点言えることは、スペック戦争については2016年にiPhoneが廉価版(SEシリーズ)を出したことで完全に終結したという認識です。

スマートフォン出荷台数の伸びは2016年以降、前年比で明らかに鈍化していて、2019年には前年比割れしています。

2015年以前のスマートフォンはまだ「年々進化するガジェット機器」でしたが、2016年以降はコモディティ製品になったことで、変態新機能よりも標準的な機能が安定的に安く使えることが求められるようになりました。(スマートフォンには個人のファイナンスデータも入るのでセキュリティも重要)

私は2016年から Android → iPhone SE にして、2021年から iPhone SE を第二世代にアップデートしました。

スマホ自体の機能の進化速度はAndroidの方が早いですが、AndroidだとOS自体にベンダー別のカスタマイズが多く入ることに加えて、ベンダーによるOSサポート期間も2〜3年という短い期間で打ち切られます。実際、2017年10月に発売した Google Pixel 2 は 2020年12月(約3年)でサポートが打ち切られました。

一方iPhoneの場合、2013年9月に発売した iPhone 5s は、2019年9月(約6年間)でサポートが打ち切られました。

Pixel 2 も iPhone 5s も定価はだいたい同じ8万〜9万円ぐらいですが、サポート期間フルで使い続けた場合、iPhoneの1日あたりのコストはAndroidの半額 ということになります。

Androidの 3〜4万円の激安端末を使っておけば、iPhoneよりも安く使えました。

しかし、2016年にiPhone SE(約5万円)が登場したことで、コストパフォーマンスの面でiPhoneがAndroidを抜き去っています。(だから私は2016からiPhoneユーザになりました)

「それでもAndroidじゃなきゃ嫌だ」という方が一定数居ることも分かるので、スマホアプリ開発をする私は粛々と両OSをサポートし続けるしかない訳ですが...

2022年6月25日土曜日

サピエンス全史読書ノート(#2 農業革命 (1))

【農業革命】

12,000年前ごろから、自生する植物や動物を狩猟する生活から、植物と動物の生産(栽培化、家畜化)への変化が始まる。
  • 11,500年前 トルコ南部、イラン西部、レヴァント地方の丘陵地帯で始まる
    • 中東、中国、中央アメリカ(概ね赤道のやや北側)でほぼ同時期に発祥後、世界各地に伝来
    • ほとんどの植物や動物は栽培化・家畜化が困難なため限られた地域で発祥
  • 11,000年前 小麦が栽培化、ヤギが家畜化
  • 10,500年前 人類が定住を始めた痕跡(中東エリコ)
  • 10,000年前 えんどう豆、レンズ豆が栽培化
  • 7,000年前 オリーブの木が栽培化
  • 6,000年前 馬が家畜化
  • 5,500年前 ぶどうが栽培化(この辺で新種の栽培化・家畜化がピークアウト)
  • 3,000年前 中国で淡水魚が養殖化
  • 2,000年前〜現代 新種の栽培化・家畜化が始まった形跡が無い
【小麦による世界征服】
  • 小麦は簡単に育たない非常に手が掛かる草である
  • 岩や石があると育たない → 畑を作らなければならない
  • 養分や水を他の草と共有できない → 草刈りが必要
  • 非常に病弱 → 農薬などが必要
  • 他の生き物に無抵抗で食べられる → 虫よけ、動物よけが必要
  • 大量の水が必要 → 川などから水を運んだり水道施設が必要
  • 大量の養分が必要 → 肥料(動物のうんこ等)が必要
  • ミネラルとビタミンが乏しく消化しにくい → そればかり食べてると病気になる
  • 雨が降らなかったり虫が大量発生すると不作 → 飢饉になる
  • 栽培には多大な時間が掛かる → 定住が必要になる → 定住により人類同士で土地の奪い合い → 成体のホモ・サピエンス同士での殺し合いが増加(農業革命以降、成人の暴力による死亡率が急上昇)
  • 単位面積あたりの食物量が増える → 人口が増加(定住化もその一因)
  • 多大な労力を要する → 組織が拡大 → ヒエラルキーが高度化 → ごく少数の貴族が多くの奴隷を使役する統治体制になる
「農業革命により人類は豊かになった」と錯覚している歴史学者が多いが、狩猟採集民の時代より平均的なQOLが著しく低下している。結果的に農業革命は罠(禁断の果実というか穀物)だった訳だが、気づいた頃には数世代経過して後戻りができなくなった。

現代のホモ・サピエンス全員が明日から狩猟採集民に戻ったとしても大半がすぐに餓死するのと同じことがネイティブ農耕民族にも言える。

10,000年前の時点で全ての人類が農耕民になった訳ではなく、狩猟採集民であることを選んだ人類も居たが、科学革命以前の戦争では総量が多い民族が必ず勝つので、科学革命までの間にその殆どが滅んだ。

状況を俯瞰的に見ると、「ホモ・サピエンスが小麦を栽培化した」というより、農業革命により ホモ・サピエンスが小麦の家畜になった という理解が正しい。

有機生命体の勝利条件(KPI)は「DNA総量」だと考えられ、人類は農業革命により人口(=DNA総量)が増加したが、我々の領主である小麦様は人類を酷使することでより多くのDNAを獲得することに成功した。
2020年の全世界の小麦のDNA総量は少なく見積もっておよそ1,100百万トン(※消費量+在庫量の合算なので未収穫を除く)で、一方ホモ・サピエンスのDNA総量はおよそ481百万トン(77.53億人x平均62kg)。有機生命体としては小麦が人類にダブルスコア以上の大差で完全勝利している。
余談だが「小麦ばかり食べていると病気になる」という点からアレルギーを連想した。厚生労働省の記事によると50年前まで日本人にはアレルギーはほぼ無かったが、最近では33%の日本人が何らかのアレルギーを持つという。牛乳、鶏卵、小麦、米、大豆が5大アレルゲンとして知られている。牛乳は論外(そもそも牛乳はホモ・サピエンスではなく仔牛専用の飲み物なのでホモ・サピエンスの体に合わなくて当然)だが、穀物アレルギーが出てきている点については、ホモ・サピエンスの免疫系が小麦の支配から抵抗しているのかもしれない。1946年より以前の日本ではパンはほぼ食べられていなかったが、(米国の事情+日本の食料不足で)小麦と防腐加工をした牛乳(脱脂粉乳)などを大量輸入したことで、パンと牛乳が日本の食文化として定着を始めたが、それぐらいの時期からアレルギーが発生し始めている点が中々興味深い。(厚生労働省曰く「工業化・文明化とアレルギーは密接に関係があるようです」とのこと)

DNA総量で見ると、家畜化された牛(およそ10億頭) もホモ・サピエンスに次ぐ勝者と言える。有機生命体として勝ち残っている状態が必ずしも「個々の生き物にとっての幸福」を意味しない。生まれた瞬間から死刑囚として生死を管理される家畜より、絶滅寸前の野生のサイの方が恐らく幸福だと思われる。


合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...