2018年10月20日土曜日

Sony Network Walkman NW-ZX100 - 128GB

携帯電話の空き容量が足りないので音楽プレイヤー兼用としての運用を諦めて、いわゆるふつうのDMPを買おうをと思いました。

漠然とNW-ZX300かなと考えていたんですが、ちょっと思っていたものと違ったんですね。USB DAC機能はいらないし、バランス接続もいらないし、DSDネイティブ再生もいらないし、Androidベースである必要もない。Bluetoothホスト機能はちょっと欲しかったけど、そこはマルチポイントでどうとでもなるだろうという感覚で、型落ちのNW-ZX100に行き着きました。ソニーの悪い癖ですよね、後継機で全部ひっくり返しちゃうの。

最後の? 組み込みOS型Walkman

NW-ZX100は、Androidベースではない、ソニー独自の組み込みOSで実装されたWalkmanです。24bit/192kHzまでのHi-Res対応なフルデジタルアンプ『S-Master HX』を駆動させるための専用OSでもあります。現行のWalkmanはすべてAndroidベースになってしまったので、たぶんこれが最後の専用OSだと思います。

組み込みOSとハードウェアが一体で設計されているので、UIなども無理ない自然な仕上がりになっていて、とくに説明書など読まなくてもわかるでしょ的な感じがあります。

Wi-Fiが載っていないのでmoraから直接Hi-Res音源をダウンロードするみたいなことはできませんが、BluetoothはあるのでBT接続のヘッドフォンも駆動させられます。また、Androidだと通常はできない、音にイコライザ等のサウンドエフェクトをかけた状態でBTに乗せることもできます。デジタルアンプ様様です。Bluetoothでファイルを受けたり送りつけることもできます。

ID3タグの話

タグの形式がID3 v2.3/ISO-8859-1でないと、うまく認識されない場合があるようです。また、同一ファイルにID3v1/ID3v2が同居していると、どちらのタグも認識されなくなる癖があります。あと、RIFF形式のタグはそもそも読めません。

SuperTagEditor (Windows)のようなツールで、ID3v1タグを一括削除し、ID3 v2.3/ISO-8859-1へ変換してやると良いでしょう。

プレイリストをひとつひとつ人の手のぬくもりある手書き作業でやる方法

Macなど、Windowsでない環境からWalkmanを扱う場合、直接ファイルを /Music フォルダに放り込むのが一般的だと思うのですが、この場合はプレイリストも手書きで書かなければなりません。以下のような書式になります。

/Music/アーティスト A/アルバム A/01 曲名.m4a
&
/Music/アーティスト A/アルバム A/02 曲名.m4a
&
  :
  :
/Music/アーティスト A/アルバム Z/13 曲名.flac
&

つまり、曲名をフルパスで表記した次の行に & (半角のアンパサンド)だけの行を入れます。これはNW-M505なども同じ手法で行けていたので、「同じソニーの組み込みOSだし行けるじゃろ」とやってみたらうまく行きましたという事例です。

これを、/Playlists とか適当なフォルダを作って拡張子 .m3u8 としてUTF-8 (改行コード LF)で書き込めばOKだと思います。

人の手で書きたくないよ! という場合

とは言っても人間の手で書きたくないので、こんなPHPスクリプトを作りました。

<?php
  $_dir = "/Music";
  $_ext = "{*.mp3,*.m4a,*.flac,*.wav}";
  $_playlists_dir = "./Playlists";

  main();
  exit();

  function main() {
    global $_dir, $_playlists_dir;

    $files = array();

    // メディアフォルダ内を再帰検索してプレイリストを生成する
    foreach (glob("." . $_dir . "/*", GLOB_ONLYDIR) as $dir) {
      // メディアファイルの一覧を得る
      $files = getMediaFiles($dir);
      // 配列内のファイル名を絶対表記へ整形
      foreach ($files as $key => $value) {
        $file = explode(".", $value, 2);
        $file = $file['1'];
        $files[$key] = $file;
      }

      // プレイリストフォルダの存在確認
      if (!file_exists($_playlists_dir)) {
        if (!mkdir($_playlists_dir)) {
          print("ERROR: Can not create playlists folder.");
        }
      } else {
        if (!is_dir($_playlists_dir)) {
          print("ERROR: Playlists folder name is already exist.");
        }
      }
      if (is_dir($_playlists_dir)) {
        // プレイリストのファイル名決定
        $file = explode("/", $dir);
        $file = $_playlists_dir . "/" . $file['2'];
        if (file_exists($file . ".m3u8")) {
          $file = $file . " " . gmdate("Ymd\THis\Z");
        }
        $file = $file . ".m3u8";

        // プレイリストの書き込み
        print($file . "\n");
        $res = fopen($file, "w");
        if (!$res) {
          print("  ERROR: Can not write playlists to file.");
        } else {
          foreach ($files as $value) {
            // print("  " . $value . "\n");
            fwrite($res, $value . "\n" . "&" . "\n");
          }
          fclose($res);
        }
      }
    }
  }

  // 指定されたディレクトリの該当ファイル一覧を返す
  function getMediaFiles ($dir) {
    global $_ext;

    $_files = array();

    // サブディレクトリを再帰検索する
    foreach (glob($dir . "/*", GLOB_ONLYDIR) as $dir) {
      $_sub_files = getMediaFiles($dir);
      $_files = array_merge($_files, $_sub_files);
    }
    // メディアファイルの配列を生成する
    foreach (glob($dir . "/" . $_ext, GLOB_BRACE) as $file) {
      if (is_file($file)) {
        $_files[] = $file;
      }
    }

    return $_files;
  }
?>

php ./genPlaylists.php などとして実行すると、カレントディレクトリにある Music フォルダ内を漁って、各サブディレクトリのプレイリストを /Playlists へ吐き出してくれます(重複するファイルがすでにあった場合は、ファイル名の末尾にGMT時刻を付けて吐き出します)。以下のようなファイル配置のときに特に威力を発揮します。

  + Music
    + アーティスト A
      + アルバム A
        - 01 曲名 A.mp3
          :
        - 13 曲名 M.mp3
      + シングル B
        - 01 曲名 A.m4a
        - 02 曲名 B.m4a
    + アーティスト B
      + アルバム A
        - 01 曲名 A.mp3
          :
        - 12 曲名 L.mp3
    + アーティスト C
      - 01 曲名 A.flac
      :
      - 13 曲名 M.flac
    + アーティスト D
      + アルバム A
        - 01 曲名 A.wav
          :
        - 13 曲名 M.wav

この場合、『アーティスト A.m3u8』『アーティスト B.m3u8』『アーティスト C.m3u8』『アーティスト D.m3u8』が作られます。あとは適宜テキストエディタで分割するなり結合するなりしてください。

ファイル名のNFD問題にハマる

うっかりファイルをMacで大量に書き込んでしまったのですが、この問題があることを忘れていました。macOSにはファイル名に含まれる濁点や半濁点が分離して記録されてしまう、いわゆるNFD問題というものがあります。

これは各OSのUnicodeにおける濁点や半濁点を扱う際の正規化処理の違いから起こるもので、WindowsやLinuxなどは NFC と呼ばれる手法を、macOSは NFD と呼ばれる手法を使うことから発生する問題です。

通常はだいたいよきに計らってくれるのですが、Walkmanの組み込みOSはmacOSのそれを適切に扱ってくれないので(いや、それが正しい挙動なのですが)、ファイル名の濁点や半濁点はただ単に分離しているもの(つまりNFD)として扱われてしまいます。どこで問題になるかと言うと、プレイリストに記録されているファイル名と不整合が起こる可能性があります。

Macで書き込んじゃったよ!!!! という場合

Javaソースで以下のようなツールが提供されています。

JDKをインストールしてあれば、javac Nfd2nfc.java などとしてコンパイル後、java sandbox.Nfd2nfc などと実行すれば、カレントフォルダ以下のNFDなファイル名をすべてNFCに変換してくれます。Walkmanのストレージのルートに Nfd2nfc.class をコピーしておくと便利ですね。 ただ、このツールは再帰処理にちょっと問題があるので、1回では処理しきれないケースがあって、何度か java sandbox.Nfd2nfc と実行する必要があるかもしれません。

Windowsだと以下のようなたいへん便利なツールが公開されています。

プレイリスト内もおかしいよ!!!! という場合

プレイリストをファイラからコピペで作った場合、プレイリスト内の文字列もおかしくなっているケースが起こりえます。先ほどのPHPスクリプトでも同様です。 プレイリストをテキストエディタで開いて全選択してコピペしたのち、以下のような変換ツールで変換して保存すれば良いと思います。

こちらのページでは変換ツールがWebアプリとして実装されているので、NFDが起こっているテキストをペーストして変換すれば、NFCな状態に変換してくれます。