ハイレゾ音楽のメディアサーバーを立てる -その2

メディアサーバー用に新たなPCを用意することにしたわけですが、ではどんなPCにするか、結構悩みました。

要求はこんなかんじ

  • 基本メディアサーバーで性能はそこそこでよい
  • でも他のことにもちょこっと使えるよう、そこそこの性能は欲しい
  • 省電力
  • 静音。ただしファンレスは目指さない
  • できれば省スペースが良いが、静音を優先
  • CドライブはNVMeのSSD
  • メインとバックアップの2台の3.5インチHDDを内蔵
  • さらに作業用の小さな容量のSATAのSSDも内蔵

小さなPCにしたいが、容量を小さくするとどうしても熱がこもる上に排気ファンの径を確保できず五月蝿くなる傾向にあるので、どちらかを犠牲にしなければならない場合は静音性を優先で。

データの安全な管理であるが、いろいろ調べてみるとRAID5とかであっても過信は禁物のようだ。
また保管するのは音楽ファイルのみ。基本的に、購入した音楽データを放り込んでいくだけで頻繁にデータの更新が発生する訳ではない。それだとRAIDを組んでのデータの冗長性確保はどうにも過剰に思える。なので、データ保管HDDとそのバックアップHDDという原始的な構成を選択。
RAIDだと組んだHDDが同じように稼働して同じような時期に同時に故障する確率がわりかし高いようだが、バックアップHDDの構成の場合はうまくやればバックアップ側のHDDの稼働を抑えることができて「同時に故障するリスク」が減るんじゃないだろうかという安直な発想による。これはただの思い込みで裏付けは何もない。

なので3.5インチHDDを2台接続する。これが外付けHDDで外にでっぱるといろいろと面倒だし見た目もアレなので、内蔵したい。

冷却方法だけれど、CPUなりの熱源があって、メインの熱の放出を空冷に頼る以上は空気の流れは必要になる。ファンがないとどうやっても熱がこもる。なので、できるだけ少ない数のファン、できるだけ大きなファンで、できるだけゆっくり回転させて静音を目指すことにする。
HDDを内蔵したいのも、外付けHDDケースの中のHDDは熱がこもって熱くなりそう。。。というのも理由のひとつだったりする。内蔵して、多少なり空気が循環する中にHDDを置きたい。

さて、既製品か。自作か。
上記を満たす既製品PCは。。。。  ないですよね。 ないです。 ハイ。

もうちょっと楽してベアボーンキット。。。 やっぱり、いい具合のないですね。。。

自作しかないですね。。。 自作します。

小さくしたいのでM/Bは Mini-ITXサイズで。
グラフィックはCPU内蔵でいいのでCPUはインテルので。RyZen+VegaなAPUが出てたらAMDに凸したかったところなのですが。

ケースは、 ケース。。。  うーん。。。。 なんかいかにもPCですみたいなケースしかない。。
しかも大きなファンを低速で回したいという希望に沿うものがない。。。
ケース自作するか。。。。  ケース自作しよう。。

かなり荊の道に足をつっこんだ気がします。

さてメディアサーバーなPCはいつになったら完成するだろうか。
というか完成するのだろうか。

以下続く

ハイレゾ音楽のメディアサーバーを立てる -その1

 iPodの時からずっとアップルのiTunesを使っていたのだけれど、アップルさん全然ハイレゾやる気なさそうなので他所のハイレゾ配信サイトに移行することにしました。

 数年前から考えてはいたものの先立つものがなくて環境を整えられないでいたのだけれど、長らく愛用してきたシャープのステレオシステムSD-HX500SのCDピックアップ部がいよいよ怪しくなり更新を決意。それで購入したSonyのSTR-DN1080がUSBリーダーが付いてたりネットワークのDLNAサーバ内の音楽ファイルを再生できたりするので、ハイレゾ再生環境を整えることにしたのでした。 STR-1080とUBP-X800についてはまた別エントリーで書きます。

 それで早速いくつかハイレゾの楽曲を購入してみたのだけれど、音質と引き換えにやたらとファイルサイズがデカい。DSDの5.6MHzだと1曲が1GBを超えるものもある。アルバム5、6枚購入したところですでに20GBを超えてしまった。
 さらに、利用したe-onkyoではダウンロードの期限はないものの最大10回までの回数制限がある。購入した音楽ファイルの管理は基本的に購入者が行わなければならない。「ハイレゾ配信サイト」というよりは「ハイレゾデータ販売サイト」ですよね。。。

 というワケで、以下の課題が持ち上がった。

  1. 巨大なファイルを保管するストレージを用意する。大容量をSSDで構築するのはまだまだ手が届かないのでHDDで。
  2. データを安全に保管する。RAIDを組むか、少なくとも原始的なバックアップで。
  3. データの保管場所でDSD音源を扱えるDLNAサーバーを動かす。ハイレゾ配信音楽データだけを扱うので、DRMとかDTCPなどの著作権保護されたファイルやプロトコルは扱えなくてもよい

一番楽そうなのはメディアサーバー機能を持ったNASを買ってしまうことである。
ただしNASにはいい印象を持っていない。過去にふたつほどNASを購入しているのだが、TimeMachineの保存先にして酷使したせいかどちらも3年持たずにダメにしてしまっている。また買ったNASは直径数センチのファンが付いていて、小さなファン特有のキーンという音が結構気になった。
メディアサーバーにできて静かでデータを冗長管理できるNASはどうもなさそうなかんじなのでこの選択肢は無しに。

それでWinでもMacでもLinuxでもなんでもいいので、DLNAのメディアサーバーを稼働することにした。
DLNAサーバーにできるプログラムを探したところ、Universal Media Server とかいうのがWinでもMacでLinuxでも動いていいな!、と思ったのも束の間、これDSD音源に対応してない(‘A`)。
しかも、DLNAクライアント側ではディレクトリをそのまま辿って音楽ファイルにアクセスすることしかできないっぽい。。。 MP3黎明期に戻ったかのような音楽ファイルの扱いで、iTunesのテキトーな使いやすさに慣れきってしまってる身としてはとても辛い。
そしてなにより、JAVAで動くのが気にくわない。却下。

別のものを探したところ、ソニーが無償で提供しているMedia Goという楽曲管理ソフトがDSDを扱えるうえにDLNAでのメディア共有機能があるではありませんか。しかもアーティストやアルバム単位で音楽を扱える。そしてDLNAクライアント側でもそれをブラウズできる。Media Go上で作成したプレイリストもDLNAクライアント側でアクセスできる。これですよこれ。こういうのを望んでいました。

というわけで、Windowsマシンで Media Go を使って楽曲の管理とDLNA共有を行うことに決定。

さて、ではPCをどうするか。家にあるPCは現在2台。1台は内蔵SSDが256GBのノートPCで、音楽データ保管用の外付HDDを付けて動かすのは運用が面倒くさそうである。もう1台は仕事用のデスクトップPCで、これはムダにデカくてHDD4台くらい突っ込めるドライブベイも余ってるのだが、ムダに電力喰いのグラボとか挿さってるので音楽聴くためだけに電源を入れるのはやめたい。仕事マシンとは別けたい。

そんなこんなでメディアサーバーにするPCを新たに用意することにしたのです。
無駄に長くなったので続きは別記事で。

COM と WRL::ComPtr

これまで中途半端にOpenGLESとMetalを使ったことがあるくらいでDirect3Dはまったくいじったことのないオッサンが「まあMetalとそんな変わらんだろう」といきなりDirect3D12に挑戦して四苦八苦してます。ロートルオジサンにはつらい。。。

で表題の件ですがDirectXのオブジェクトは基本COM。Direct3D12になってもCOM。
D3D12からは言語はC++しかサポートせず、そしてオブジェクトの保持や破棄は全てプログラマが責任持って管理するようになったのにCOMを使う利点って何だろう。。。
もうValkanのようにイチから設計し直して欲しかったがそれならValkanをどうぞということだろうか。

それでCOMですが、アラフィフになってえっCOMって何? なロートルおっさんなので勉強しました。

  • 参照カウント方式。AddRefしたらReleaseする。カウンタがゼロになったら解放される
  • 戻り値や引数でCOMを返却する関数は関数側でAddRefして返す。関数から受け取った側は必要なくなったらReleaseする。

MRC時代のObjective-Cの参照カウンタと似たかんじで、これはOK。

次に WRL::ComPtr。 参照カウンタの面倒を自動化してくれる。すばらしい。

ただ、参照カウンタをどう扱うかのポリシーみたいなやつのドキュメントが見当たらない。どう使っていいのかいまいちピンとこない。しかたないのでComPtrのヘッダをみてみる。

WRL::ComPtrはコンストラクタや代入でCOMオブジェクトを受け取る時に必ずAddRefし、管理しなくなる時に必ずReleaseする。
これは徹底している。参照カウンタが元に戻ることが保証される。
右辺値参照にも対応し、moveする場合は参照カウンタは増えない。

これはなかなか良い。

だけども、Create系関数から返却されたオブジェクトをComPtrで扱おうとするとあれっとなる。
Create系関数から返却されたオブジェクトはすでにAddRefされた状態で返ってくるので、こいつはAddRefせずにReleaseだけ行う。
だけどコンストラクタや代入でWRL::ComPtrに渡すとAddRefしてしまう!!

で、どうするんだろうとサンプルコードなどをみると、ComPtrでCOMオブジェクトを受けるのはこんなカンジになってる

ファッ!?? ってなりますよね。 なりますよね?

&deviceって何??
なんでComPtrのアドレスを直にD3D12CreateDeviceの引数にぶっこんでるの??

と思ってComPtrのヘッダをみると、単項 & 演算子がオーバーロードされていた。こいつがDetails::ComPtrRef<ComPtr<T>>を返す。さらに Details::ComPtrRefの operator InterfaceType**() が呼ばれて、元のComPtrのReleaseAndGetAddressOf()を呼ぶ。。。。 つまり、上記のCreateDeviceのところは

と書くのと同じである。

これでようやく、ああ、ComPtr内部で持ってるオブジェクトのポインタのアドレスを渡して直接オブジェクトを得るんだな。この時AddRefはされないんだな。そしてComPtrのデストラクタで無事Releaseされるんだな。というのが理解できた。

これくらいのことをヘッダ辿って調べるのは一般的なC++erだったらきっと至極当然のことなのであろう。だからWRL::ComPtrのこの辺の挙動を疑問に思うエントリがぐぐっても出てこないんだ。たぶん。
でもロートルおじさんはこの辺の挙動を理解するのに苦労したのでこうして書き留めるよ。

しかしこれ、 &device って書くよりも device.ReleaseAndGetAddressOf() って書く方が圧倒的にわかりやすいよねえ。。。