2015-11-23

MP3のタグと文字コードについてあれこれ

Medoly開発において気になったので、ちょっとだけMP3のタグの話。


MP3は汎用性は高いですが、そのタグの仕様が大変に厄介です。MP3が登場して20年ぐらい経ってると思いますが、未だに安定せず、頻繁に問題事を持ち込んでくれます。
 
まず、MP3のタグはID3タグと呼ばれる標準の規格が存在し、ID3.org において規格が管理されています。
ID3には大きく分けて、ID3v1と、ID3v2が存在します。細かく分けると、 ID3v1はID3v1と、ID3v1.1があり、ID3v2にはID3v2.2, ID3v2.3, ID3v2.4があります。ID3v1とID3v2は共存できますが、ID3v1は、今となっては使い物にならないので忘れましょう。
問題は ID3v2です。ID3v2.2, ID3v2.3, ID3v2.4は互いに互換性はありません。とりあえず一番新しいバージョンを使えばいいと思われそうですが、そうは問屋が卸しません。ID3v2.4はハードウェアやソフトウェアが対応していない事も多々あり、Windows Media PlayerやiTunesといった主要なソフトウェアは、少し前まで対応していませんでした。ID3v2.4は、文字コードにUTF-8が使えるようになったり、年だけでなく年月日が入力できるようになったりしてるといったいくつか変更はありますが、v2.3とそんなに大差はないです。現在、最も普及しているのはv2.3なので、それにしておくのが無難です。
 
そして、更に問題となるのが文字コード。 ID3v2タグには、文字コードを設定することができます。…が、文字コードとして設定できるのは、「ISO-8859-1」と「UTF-16」だけです。(v2.4はあまり使わないので、UTF-8が設定できることは忘れましょう。設定してもいいですが、多分読めないプレイヤー多数です。Medolyは読めるはずです。)

日本語を扱う上で、文字コードに「ISO-8859-1」を設定した上で、Shift_JISを入力する場面が多々あります。私から言いたい事は『金輪際そんなタグは入力しないでください』ということです。ISO-8859-1はあくまでも英語等のアルファベット文字を使う言語圏で使われる文字コードです。日本語はサポートされていません。「ISO-8859-1」と設定されているのに日本語が読めるのは、ISO-8859-1と設定した上で、Shift_JISの文字を入力しているからです。何故そのような事が慣例化しているかと言えば、MP3の黎明期、ID3v2のサポートが少なかったり、Unicodeのサポートが満足に行われていなかった時代があり、日本においては日本語の表示はこちらの方が安定していたためです。
ところが、MP3の仕様上はあくまでもISO-8859-1です。海外のソフトウェアでは日本語を読み込むことはまずできませんし、多言語が混在していた場合、それが日本語なのか、あるいは別言語なのか判別する手段がありません。
そのため今現代においては、全ての言語をサポートするUTF-16で入力した方が、確実に文字を読み込むことができます。MP3にはタグの文字コードがUTF-16と判別させる方法が存在するため、読み間違いが起こりません。


…が、事がそう単純にはいかない点もあります。ID3v2のタグの規格上、このタグの文字コードは「タグ毎に」設定することが出来てしまいます。すなわち、タイトルがISO-8859-1、アーティスト名がUTF-16となっているMP3が存在する可能性がある、という事です。例えば、作りが雑なタグ編集ソフトの場合、タグを編集した際にそのタグだけに勝手に文字コードを設定してしまうという場合もあるでしょう。

ところで、MedolyではShift_JISで入力された文字も判別できていますが、これは文字コード判別ライブラリを使って強制的に文字コードを判別させているためで す。文字コードの判別処理というは、通常かなり力業な処理が行われており、特定の文字コードにしか登場しないコードパターンの出現で判別したり、といった 事を行います。すなわち、文字数が少なければ判定を誤る可能性が高い、ということです。タイトルだけ、アルバム名だけ、といった文字数程度では判別が失敗する可能性が高いです。ちなみにMedolyでは現状、タイトル、アーティスト名、アルバム名の文字を繋げて文字コードを判別させています。

つまり、UTF-16とISO-8859-1で入力された多言語がタグに混在したMP3は、正直こちらではお手上げ状態です。Meodlyでは、現状そのようなMP3は想定していません。最初に取得したタグに応じて残り全部の文字コードを決定しています(この処理は少し変更するかもしれませんが)。何せ文字コードの自動判定がアテにならないため、それがShift_JISなのか、はたまた中国語なのか韓国語なのか、こちらで判別する手段がないためです。
ちなみに、Medolyでは本当に何も判定できない場合は、最終的に端末使用言語に応じて文字コードを分岐させています。日本語ならShift_JISになります。

そんな感じで長々と書いてみましたが、MP3のタグの読み込み(特に文字化け)については、こちらで対応できる事に限界があります。Medolyは恐らく英語圏のソフトよりは、文字が読み取られる可能性が高いですが、それでも完璧というわけにはいきません。
文字コードについていくつかご質問やご意見を頂く場合がありますが、個人的には「質問を投げるぐらいなら、さっさと自分でタグをID3v2.3、UTF-16に直してしまった方が遙かに早い」と思ってます。M4A等の別の音楽形式使うのも有りです。

最後に言いたい事まとめ。
『MP3のタグはさっさと全部ID3v2.3のUTF-16に直すこと。話はそれから。』
『MP3タグの文字コードはタグ個別に設定できる。使用するタグ編集ソフトが吐き出す文字コードをきちんと確認。英語圏のソフトはISO-8859-1のタグとか平気で吐き出す場合がある。』
『MP3のタグ仕様は本当にクソ』


2015-11-06

車を買いました

唐突ですが、最近車を買いました。1ヶ月ぐらい前の話です。というか、携帯を変えたのとほぼ同時期です。車の維持費の代わりに、携帯の回線費用を抑えたとも言います。
購入動機は、すぐ移動できる足が欲しかったのと、色々試したいことがあったためです。


もちろん、車内の音楽再生にはMedolyを使用しているのですが、その際以下のような使い方をしています。





ダッシュボードの上にクレードルを貼り付けて、その上に携帯を置く感じになってます。クレードルは少し緩衝材を挟んで、車体が揺れても携帯が落ちないようにしています。
この配置により、歌詞を見たり、再生キューから曲を選択するといった簡単な操作をスムーズに行うことができたりします。

そんな環境のため、以降の更新ではこの環境を想定した変更が行われるかもしれません。具体的には、

・クレードル設置時のアクション設定
・全画面表示状態での操作改善
・Bluetoothとの連携強化

等です。ちなみに、最近の更新でBluetoothのレイテンシ設定を追加したり、ボタンの長押しリピートを追加したのは、この環境のためです。

こうした利用について、もっとこうした方が良い等のアイデアを頂けると嬉しいです。

携帯を変えました

1ヶ月以上前の話ですが、メインで使用している携帯電話を変更しました。

[変更前]
回線キャリア:au
端末:XPeria SOL22 (Android 4.2)

[変更後]
回線キャリア:iijmio
端末:Xperia Z3 Compact (Android 5.0)

この変更の目的は、回線料金の削減他、Android の新バージョン利用を目的としていました。
最近、Android 5.0絡みの変更が多かったのは、この変更によるものです。
私の使い方では、あまり通信量が多くならないため、MVNOの回線で十分でした。回線料金が1/4以下になり、個人的には十分満足です。

あと、Android 4.2ではBluetooth のAVRCPプロファイルが1.2までしか対応していませんでした。この場合、Bluetooth接続先に再生中の曲情報を送付することができません。Android 5.0では、AVRCPが1.3まで対応しています。この辺りの機能を利用したかったため、携帯を変更したという経緯もあったりします。


Medoly Ver. 2.4.0

2015-10-23 Ver. 2.4.0
- 同期歌詞の長押しによるシーク機能追加
- 出力デバイスのレイテンシ設定追加
- 出力デバイスのスピーカー/ヘッドセット廃止
- ボタンの長押しリピート追加


同期歌詞の長押しによるシーク機能追加


これはユーザ様からの要望です。
同期歌詞を表示している時に、表示タブ上で歌詞を長押しすると、歌詞のテキストが再生される時間に曲をシークするようにしました。
これは同期歌詞のみで、非同期歌詞は非対象です。何故ならば、非同期歌詞は厳密な歌詞位置を取得することができないためです。

なお、歌詞以外の位置を長押しすると、従来同様に長押しアクションが実行されます(設定画面で切り替え)。設定で無効化することもできます。


出力デバイスのレイテンシ設定追加


以前追加した「出力デバイス」ダイアログに、レイテンシの設定を追加しました。レイテンシとは、Android内部で再生処理が行われてから、実際に音声がスピーカーやイヤホンから出力されるまでの遅延のことです。



この値を設定すると、同期歌詞の表示タイミングが調整されます(今のところは、同期歌詞だけです)。出力先を切り替えると自動的に適用されます。


これは、Bluetoothの出力先を切り替えた際に 歌詞のタイミングがズレてしまうのが以前から気になっていたため、今回追加してみました。なお、これに伴い従来設定画面に存在していた固定オフセット値(表示誤差)の設定は廃止しています。

レイテンシには、共通レイテンシと各出力デバイス固有のレイテンシを設定できます。実際のレイテンシは、双方の合計値になります。レイテンシの値は、デバイスやAndroidのバージョンによって異なります。Androidは総じて、iPhoneと比べてこの値が大きいです。

参考: スマホやタブレットの「オーディオレイテンシー」性能ランキングと自分でも可能な測定方法 - GIGAZINE

最近のNEXUSだと50ms以下になるようですが、遅い機種だと数百msにもなります。この値はユーザ自身で調整いただくしかありません。また、プログラム上の遅延もあるため、どこかに参考値として書かれている機種別レイテンシの値をそのまま設定しても、歌詞のタイミングが綺麗に調整されないかもしれません。

また、上記の値はスピーカー等から出力される場合の話で、Bluetooth出力の場合は更に遅延が発生します。また、同じBluetooth接続でも、コーデックの違いにより遅延が異なるようです。一応、参考値を画面上に記述していますが、あくまでも目安と考えてください。実際はこれよりも大きな値になる場合が多いようです。


出力デバイスのスピーカー/ヘッドセット廃止


以前のバージョンには、上記の出力デバイスダイアログに、スピーカー出力固定と、イヤホン出力固定の設定がありましたが、これらを廃止しました。理由はAndroid 5.0以降で使えないからです。また、これらを選択した状態は、音楽を流す上で不自然な状態であり、あまり推奨される状態ではなかったため、思い切って廃止してしまいました。
ご利用頂いていた方には申し訳ありません。


ボタンの長押しリピート追加


表示タブ上のボタンを長押しした際、ボタンのタップがリピートされるようにしました。ちょっとした機能改善です。

2015-11-05

Medoly Ver. 2.3.5

2015-10-17 Ver. 2.3.5
- Android 5.0以降におけるSDカード書き込み対応
- 歌詞取得プラグイン対応
- 歌詞フォルダ検索機能追加
- 再生予約解除機能追加
- シャッフル再生時、再生キュー完了で再シャッフルする機能追加
- ロック画面に画像を表示しないオプション追加
- その他細かい修正



Android 5.0以降におけるSDカード書き込み対応


Android 5.0以降でSDカード書き込みに対応させました。「設定」→「その他」→「外部ストレージの空き込み」を実行し、表示されるフォルダから対象のSDカード(外部ストレージ)のルートフォルダを選択してください。
Androidは、4.4以降では従来と同様にSDカード等の外部ストレージに書き込むことができなくなりました(読込は可能)。少し混乱があるようですが、ここで言うSDカードとは、携帯に後から追加する本当のSDカードのことで、最初から内蔵されているストレージのことではありません(フォルダ名がsdcardとなっているかどうかは無関係です)。内蔵ストレージは従来と同様に書き込みが可能です。
Android 4.4以降では、SDカードへの書き込みは、Googleが用意した特定の機能を使用するようになりました。SDカードの書き込みを行う場合、以下のような画面を表示させる必要があります。これは、ユーザに「この場所に書き込みますよ」と確認させるための共通画面で、これによりプログラムがバックグラウンドで勝手に書き込みを行うことができなくなります。これは、セキュリティ上の安全性を考慮した仕様変更のようです。



ここで問題になるのは、プログラムからSDカードに勝手に書き込みを行う処理を作成したい場合です。上記画面を選択した後、書き込み先を示すURIが取得できるため、これを保持しておくことで、プログラム上から同じ場所に何度も書き込むことはできます。
ところが、「指定フォルダ以下に自由に書き込みを行いたい」場合は少し話が変わります。 フォルダを示すURIを取得し、そのURIを基準にしてサブフォルダを検索する処理を作成する必要があります。ところが、このフォルダを選択する処理はAndroid 4.4には存在しません。Android 4.4はファイルの選択のみです。そのため、Android 4.4ではプログラムからSDカードへの書き込みが著しく制限されます。Android 5.0からはフォルダ選択が可能となり、そのフォルダ以下への書き込み操作ができるようになりました。SDカードへの書き込みが必要なファイラ等のアプリの多くで、最初にこの画面でSDカードを指定させているのは、そういう理由によるものです。
今回の変更ではこの機能を使用し、Android 5.0以降でもSDカードへの書き込みが行えるようにしました。SDカードの書き込みが必要となるのは、以下の3つの処理です。

・ M3Uプレイリストファイル出力処理
・歌詞取得プラグインの書き込み処理 (新規追加)
・設定のエクスポート処理


このうち、設定のエクスポートは単純にファイルを出力する画面を呼び出しているだけなので、Android 4.4でも可能です。ついでに言えば、Google Driveがインストールされていると、Google Driveへの書き込みもできるようになります(そういう仕様です)。以前から、Google Driveを介して複数の端末で設定を共有する機能が欲しいと思っていたのですが、思いがけず実現できてしまった形です。

残る2つについてですが、 この2点については、メディアファイルとの相対パスが必要になるため、単純にファイル書き込みを行うだけというわけにはいきませんでした。そこでSDカードを利用する場合は、最初にユーザにSDカードのルートディレクトリのURIを画面から指定してもらいます。指定されたパスがSDカードのルートディレクトリであると認識できた場合、アプリはそのURIを保持します。その上で、書き込み時はURIからパスを辿って書き込ませる、という手法を採ってます。ちょっと無理矢理な処理ですが、これぐらいしか思いつきませんでした。

余談ですが、画面から指定されたURIが「SDカードのルートディレクトリである」と判別する確実な手法が無いため、指定されたディレクトリ内にあるファイルの内容と更新日時を比較して判定しています。そのため、SDカードのルートディレクトリと同じファイル構成・同じファイル日時のファイルを用意したディレクトリを用意し、そこを指定してもルートディレクトリと誤認します。ご勘弁ください…。
ちなみに、先頭に「.」(ドット)を含む隠しフォルダへの書き込みはできない可能性があるので、使わないでください…。原因がよく分かってないのですが、新しい方式がそれをサブフォルダとしてうまく認識してくれません。現在のところ問題として認識はしていますが、解決できるかどうか不明。

長々と解説してみましたが、この辺は本当に苦労しました。この苦労でよく分かったのは、「Androidでストレージ扱うの、超めんどくせぇ」です。


歌詞取得プラグイン対応


従来、Twitterに自動的にツイートしたりするプラグインはありましたが、新たに歌詞取得プラグインというものをこさえてみました。これは、現在選択されているメディアに対する歌詞を余所から取得するというものです。(プラグインの詳細は別のエントリにて)

取得した歌詞は画面上に表示されますが、ファイルとして書き込むことも出来ます。書き込み先は、 メディアファイルと同一フォルダと、今回新たに追加した歌詞検索フォルダの2カ所です。メディアファイルへのタグ書き込みは今のところ考えていません。ファイル名はメディアファイルと同一名称で固定です…今のところは。書き込みタイプは、ファイルが存在しない場合のみ新規保存、または常に上書きの2種類があります。
イベント動作で、メディアが選択された時に自動的に読み込みに行くような動きも可能です。ただし、以下の2つの条件を満たす必要があります。

・Medoly側で歌詞が読み込まれていない、または歌詞が強制的に読み込まれる設定になっている
・プラグイン側がイベントに対応し、自動読み込みが行われる設定になっている。

歌詞のあるボーカルではなく、インストを主体にして聞く人も多いかと思うので、基本的に勝手には読みにいかない事が標準動作となることが望ましいと考えています。

2つ以上のプラグインが存在した場合の動作も設定できるようにしていますが、プラグインがまだ2つも無いので 意味がありません。

ちなみに、歌詞取得という事は、アルバムアートの取得もあるのかという話になりますが、まぁ、機能的にはほぼ同じなので作れます。機能的には大体埋まってますので、そのうち作ります。作ってないのは、単純に時間の問題です。というか、このプラグイン開発に時間割きすぎて飽きてしまったので、少しインターバル挟みます。疲れた。


歌詞フォルダ検索機能追加


こちらはユーザ様からの要望となります。従来、外部ファイルの歌詞を読み込むのは、メディアファイルと同一フォルダにある歌詞のみでしたが、今回、設定画面からフォルダを指定することで、そのサブフォルダにある歌詞ファイルを検索するようになりました。

この機能では、タグの内容から歌詞ファイルを探しに行くことができます。設定画面で検索対象のタグにチェックを入れると、チェックされたタグの値が全て含まれるファイル名のファイルを探しに行きます。なお、メディアファイルのファイル名は標準で検索対象に含まれます。そのため「01.mp3」等と単純なファイル名の場合、歌詞が誤爆する可能性が高まります。

ちなみに、歌詞は必ず全てのフォルダを探しに行き、対象となるファイルをリストアップしてから対象を決定します。これは歌詞の誤爆の可能性を下げるためです。単純に最初に発見したファイルを選択してしまうと、例えば、「サンプル歌.txt」と「サンプル歌 (アレンジバージョン).txt」という2つのファイルがあった場合、本来欲しいのは「サンプル歌.txt」なのに、「サンプル歌 (アレンジバージョン).txt」が選択されてしまう可能性があります。より目的のファイル名に近いファイルを選択する必要があると考えられるため、このような動作となっています。

注意点としては、対象フォルダにある全サブフォルダを探しに行くため、 ファイルが大量にあったり、深い階層があるフォルダを検索すると毎回歌詞の検索に時間がかかる可能性があります。こればっかりは仕方ないと思うので、運用でカバーしていただけると助かります。

ちなみに、歌詞の優先度は、メディアファイルと同一フォルダにある歌詞 → 内蔵歌詞 → 歌詞検索フォルダの歌詞 となっています。この優先度の根拠は、メディアファイルと同一フォルダにある歌詞は、表示させたい意思が一番強い歌詞であると考えられるため最優先、検索フォルダは誤爆の可能性が高いため、優先度を低くしてあります。ちなみに、今回の変更で各歌詞を読み込まない設定を追加しています。

そんな感じで、とりあえず思いつく限り誤爆を避ける実装をしてみましたが、イマイチ自信がありません。
私自身はこの機能をあまり利用していないため、この機能を使用している方は、この歌詞検索ルーチンについて、何か意見を頂けると助かります。「こんな風に間違った歌詞が表示された」といった、実際のファイル名を提示してくれると嬉しいです。

余談ですが、この機能を作成している途中で、「歌詞検索フォルダを作ろう」→「
歌詞検索プラグインで取得した歌詞を保存できるようにしよう」→「SDカードに書き込みできるようにしよう」という感じで、各機能を連鎖的に作るハメになったので、作るまでに異様に時間がかかっています。


再生予約解除機能追加


再生キューを長押ししたメニューから、次に再生する曲を予約することができますが、同じ曲で再度長押しすると、予約を解除できるメニューが表示されるようにしました。予約を取りやめたい場合に使用してください。


シャッフル再生時、再生キュー完了で再シャッフルする機能追加

これはユーザ様からの要望です。
シャッフル再生の際、再生キューは固定された再生順を保持します。これは、再生キューを更新したり、再生順を切り替えるまでずっと保持していたのですが、再生キューの内容が全部再生完了した時点で、再シャッフルしてほしいという要望がありましたので、そのように実装しました。
一応、従来の動作もできるように再生順を保持する設定項目も追加しています。

ロック画面に画像を表示しないオプション追加


音楽再生時、ロック画面からの操作コントローラは欲しいけど、画像はあまり人に見られたくないという人も多いと思いますので、画像だけ表示しない設定を追加しました。
特にLollipopは、ロック画面にアルバムアートを表示させると、画像が画面全体に引き伸ばされて表示され、かなり目立ちますので、こういう設定は結構需要があるかな…と。

その他細かい修正


その他、多数の変更やバグ修正が加えられています。
目立ったところでは、最近のバージョンのAndroidだと、同一プレイリストが保存できなくなってたりしてるようなので、その辺の挙動を少し変更したりとか。

携帯のメールには返信できない場合があります

最近、携帯のメールアドレスからメールを何件か頂いていますが、返信してもエラーが返ってきます。恐らく、PCからのメールを拒否する設定にしているか、強力な迷惑メールフィルタリングを設定しているものと思われます。

私は、所謂日本の三大携帯キャリアは利用していないため、携帯向けのキャリアメールアドレス(docomo.ne.jp, ezweb.ne.jp, softbank.ne.jp, など)は持っていません。そのため、返信で拒否された場合、こちらから返信する手段がありません。

お心当たりのある方は、適当なフリーのやつで構わないので、PCのメールから返信できるメールアドレスから連絡いただけると助かります。Google Playのコメントに書いていただくのが一番いいです。このブログのコメント欄でもいいです。とにかく、何でもいいからキャリアメール以外の方法で連絡していただけると助かります。



最近のキャリアメールは、PCからのメールを受け付けない(特定のドメインからしか受け付けない)ような設定が、契約直後の標準状態やメールフィルタリングに含まれているようです。なお、docomoはメール不達エラーが返ってくるのでまだマシですが、auやsoftbankに至ってはそれすら戻ってこないという話なので、届いたかどうかがまったく分かりません。
この特定のキャリアからしか受け付けないような設定を推奨している携帯キャリアのやり方には、個人的に大きな憤りを感じます。
メールは相手に届くことが前提です。ユーザ自身が意識せずにいるとにメールが届かない設定が適用されるのは論外ですし、ユーザ自身にメールが届いたかどうを調べさせたり、届かない原因を調べさせたりするようなサービスは、非常に品質が悪いと言わざるを得ません。日本のインフラを担う通信キャリアが、こんなツールとしての信頼性を損なうような所業をするのは、全く納得できません。市場を牛耳る企業としての奢りを強く感じます。
何故か多くの人は「キャリアメールは信用できる」と思い込んでいますが、信用できるのはあくまでも送信元の身元が保証できるという意味であって、届く・届かないの通信品質に対する信用は全く別問題です。そして、その点においてキャリアメールは「全く信用できない」、「信用するべきではない」と断言していいと思います。ちなみに、キャリアメールからも迷惑メールはよく飛んでくるので、身元が保証されていても、それがユーザの健全性に結びついているかどうかは別の話のようです。
いずれにせよ、メールの設定やフィルタリングの特性を把握している人以外は、確実に届かせる必要のある重要な連絡にキャリアメールは不向きであると思います。



そんなこんなで最後になりますが、私に対してメールを送る場合、出来ればキャリアメールで送ってこないようお願いします。