2015年4月5日日曜日

メディアキーで操作できる小型MPDクライアント minmpc

Raspberry Pi 2 とフリスクDACでオーディオメディアサーバーを作っていい感じに音楽垂れ流し環境が出来たのはいいのだけれど、ちょっと停止したい! とか 今の曲もう一回聴きたい! とか、そんな操作が少しばかり不便なことに気付きました。

最近のキーボードによくついてるメディアキー(再生/一時停止、次の曲、前の曲 とかのボタン)でさくっと操作できればいいなと思ったのですが、気に入るものは見つけられませんでした。
欲しいのは次のような感じ。

  • Windowsで動作
  • ウィンドウがアクティブでなくてもメディアキーから操作可能
  • ウィンドウは小さくて勝手に隠れてくれる
  • プレイリストの操作等は優秀なソフトが他にあるのでなくてもいい
というわけでRxの勉強がてら作ってみました。

minmpc (github)

  • メディアキーでホットキー的に操作できて再生中の曲が表示されるだけです。
  • インストーラやビルド済みの実行ファイルは準備してません。
  • Visual Studio Community 2013 で「NuGet パッケージの復元の有効化」がONになっていればビルドできると思います。

作りはかなり粗い&荒いものなのでソースの公開に留めておきます。
決してめんどくさがってるわけじゃないですよ?_(:3 」∠)_

2015年3月28日土曜日

Raspberry Pi 2 とフリスクDACでオーディオメディアサーバー

自宅サーバーをRaspberry pi 2 にしたら、メディアサーバーにしてみたくなって実際にやってみた記録です。
Raspberry Pi 2 はHDMIケーブルや3.5mmのミニジャックから音声出力が可能です。USBでDACを接続すれば音質の向上も期待できるはず。

今回は最近ちらほら話を聞くようになったMusic Player Daemon (MPD)を使います。 MPDとは、LinuxやUNIXで動作する、オーディオファイルを再生したりプレイリストを管理したりするデーモンです。 よく使われる FLAC, MP3, MP4/AAC, Ogg Vorbis, wave 辺りのサポートは万全なので安心。 DACがサポートしていればハイレゾ音源もいけるらしいですね。そんなモノ持ってないけど。

準備

音声の出力先から実際に音が出るようにしておきます。 いきなりUSB-DACを繋ぐと上手くいかなかったときに問題の切り分けが面倒なので、まずは Raspberry Pi 2 標準搭載の音声出力で試します。
NOOBSからのインストールで特に変更していなければ、デフォルトでHDMIか3.5mmのいずれかが自動で使われるようです。
設定の変更は raspi-config > 8 Advanced Options > A9 Audio から。
テレビとかにHDMIで繋いで作業しているなら何もしなくていいです。

MPDインストール

mpd と mpc をインストールします。mpcはCLIのmpdクライアント。動作の確認に便利なのでmpdと一緒にインストールします。

$ sudo apt-get install mpd mpc

mpdの設定ファイルを書き換えます。
/etc/mpd.conf

music_directory       "/mnt/data/music"
playlist_directory    "/mnt/data/playlists"
db_file               "/mnt/data/mpd/tag_cache"
log_file              "/mnt/data/mpd/mpd.log"
sticker_file          "/mnt/data/mpd/sticker.sql"
#bind_to_address      "localhost"
music_directory のフォルダーがメディアファイルの格納場所です。mpdが読めるようにパーミッションを設定します。 playlist_directory, db_file, log_file, sticker_file のファイル/フォルダーはmpdが書き込めるようにパーミッションを設定します。 bind_to_address の行はコメントアウトすればどこからでもTCP経由でコマンドを受け付けるようになります。

とりあえず動かすだけならこの設定だけで十分。mpd.confにはもっと細かい設定があるので man page は読んでおいた方がいいと思う。

mpdを起動します。

$ sudo service mpd start

mpcでmpdにコマンドを送ってみます。

$ mpc ls
music_directory 配下のフォルダーが表示されるはず。

プレイリストに音楽ファイルを登録します。

$ mpc add pops
pops フォルダー以下のすべての音楽ファイルをプレイリストに突っ込みました。

再生!

$ mpc play
簡単!
テンションあがりますね(・∀・)

これだけで、あとはLANに繋がっているマシンにクライアントソフトを入れておけばそこから音楽再生をコントロールできるようになります。 クライアントは Gnome Music Player Client がいいのかな? Windowsなら Auremo もよさげ。Android なら MPDroid とか Droid MPD Client とか。

USB-DACで音を出したい

なんでこんなことを始めたかというと、PU-2111(いわゆるフリスクDAC)が眠っていたからです。
価格の割に良い音が出ると聞いて買ってみて暫く使っていたのですが、音楽周りの環境が変わってから使わなくなってました。

まずデバイスの認識から

とりあえずPU-2111を直接繋いでみたらOSが突然の死。そして奇妙な再起動の連続でまともに起動しなくなりました。 挙動からなんとなく電圧不足のような印象。バスパワーに頼るのはやめて電源付きのUSBハブを経由して接続したら起動しました。 Raspberry Pi の電源に使っていた古いXperiaの付属品では出力不足っぽい? ケチった結果がこれだよ。

$ less /proc/asound/cards
0 [ALSA           ]: bcm2835 - bcm2835 ALSA
                     bcm2835 ALSA
1 [DAC            ]: USB-Audio - USB AUDIO    DAC
                     BurrBrown from Texas Instruments USB AUDIO    DAC at usb-bcm2708_usb-1.4.3, ful
認識されたっぽい。
$ sudo aplay -l
card 1: DAC [USB AUDIO    DAC], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
ALSAでも見えてる。いい感じ。
あ、これは sudo しないと見れません。ちょっとハマった。

デフォルトの再生デバイスにする

モジュール名を調べます

$ cat /proc/asound/modules
0 snd_bcm2835
1 snd_usb_audio

モジュールの優先順位を設定します(optionsの2行を追記)
/etc/modprobe.d/alsa-base.conf

options snd_usb_audio index=0
options snd_bcm2835 index=1

そして再起動してみて…

$ sudo reboot

優先順位が変わってたらOKなのかな?

$ cat /proc/asound/modules
0 snd_usb_audio
1 snd_bcm2835

再生してみます。

$ mpc play
キター!(・∀・)


Linuxのサウンドデバイス周りの知識は皆無でぐーぐる先生を頼りにやっただけなので、これでいいのかちょっと不安だったり……

おまけ: PU-2111でのノイズ

一通り組み上がって配線周りを整理したらピーって高音(4242Hz)のノイズが聞こえるようになりました。それもかなり目立つ音量で。 そういえばこのPU-2111、以前使っていた環境では小さい音ですがサーってタイプのノイズが気になってました。
試しにUSBハブのACアダプタを同じ出力の別のものに変えてみたら聞こえなくなりました。 電子回路はよく分からないけど電源からのノイズを拾いやすいのかもしれません。

2015年3月24日火曜日

自宅サーバーをRaspberry Pi 2 にした

古いタワー型PCで動いていた自宅サーバーを Raspberry Pi 2 に置き換えました。
GPIOを使ってどうこうとかそういう面白そうなことはやってません。
Raspberry Pi 2 を単なる省電力小型Linuxマシンとして使っているだけです。
このエントリは通常のタワー型PCサーバーではやることが無かった類の作業の記録です。

自宅サーバーなんてイマドキ外部のサービスに頼れば殆ど不要なのですが、データ量がTB単位になるような深い業を背負った人間のファイルサーバーはちょっと困ります。そこに一ヶ月の電気代が50円未満なんて言われる小型PCがあれば惹かれていくのは人の性というものです。

用途

NASが主な用途です。sambaです。
HDDは2台接続して、それぞれメインとバックアップにします。
RAIDではありません。個人用途では常時クローンされることよりも誤操作時の復元容易性の方を重視していいと思っています。
ついでにRSSリーダーにも使っています。Tiny Tiny RSS です。

ハードウェアの準備

Raspberry Pi 2 本体の他に幾つか準備するものがあります。

  • 電源 ― ACアダプタなどは付属していません。本体側はマイクロUSB端子なので、スマートフォン用の充電ACアダプタがお手軽にそれなりのパワーを供給できてよいです。ケチな電源を使うと外部機器を繋いだときにシステムがダウンします。
  • HDMIケーブル ― 画面がないと始まりません。
  • キーボード ― USB接続の標準的なやつでいいです。セットアップが終わったら取り外してもOK。
  • マウス ― なくてもいいけど、あればNOOBSの始めにちょっとだけストレスが減ります。
  • 本体ケース ― サーバー用途なので放置することになります。基盤剥き出しではホコリとか被ってあまりよろしくなさそうです。カメラのフラッシュでも死ぬし。
  • microSD ― OSをインストールするストレージです。4GB程度だと apt-get update が失敗したりと残念な気持ちになれます。16GBぐらいあればとりあえず安心じゃないでしょうか。
準備は計画的に。

OSインストール

Raspbianにします。
Debianをベースにした Raspberry Pi 用のOSで、DebianUbuntu をよく使っている人ならあまり悩まず使えそうです。
インストールにはNOOBSを使って手を抜きます。
ダウンロードしたファイルをmicroSDに書き込んで電源ケーブルを差し込むだけなので超楽ちん。
NOOBSでのRaspbianインストール方法については既に多くの方が記事にしているので省略。

途中でマウスじゃないと選択しづらいボタンがあった気がします。マウスを使ったのはここだけ。

インストール中に日本語が化けて幾つかの項目を選ぶのが大変でした。
インストール後も sudo raspi-config で同じ設定画面を開けるので後回しにしてもいいです。

インストールが終わったらとりあえずOSのバージョン確認。

$ uname -a
Linux raspinas 3.18.7-v7+

$ cat /etc/debian_version
7.8

HDD接続

HDDは駆動部がある精密機械で、貴重なデータが詰まっています。裸で放置するのはちょっと躊躇われます。
はじめは段ボールで適当にHDDケースを作ったのですが、それなりに発熱する機械なので恐くなってやめました。
USB接続できるHDDケースに入れ、それを設置場所にしっかり固定。地震が来ても安心。
また電源のACアダプタが増え、ACアダプタが隣のコンセントを塞ぐ問題が予想されます。そのための短い延長コードがあると安心。

HDDを接続できたら、
マウントして、
パーミッションを設定して、
fstabで再起動時も自動でマウントされるようにして、
sambaを適当に設定してWindows機からの読み書きを確認し、
cron に rsync を仕込んで定期的にバックアップを取るようにして、
NAS完成。

SDカードの寿命を延ばしたい

このままだとログやスワップに使うストレージはSDカードなので、きっと1年ぐらいサーバーとして運用したら死ぬんじゃないかと思います。
予備のSDカードを用意して壊れたら入れ替えればいいじゃないという発想もありますが、出来ることなら寿命は延ばしたいですよね。
とりあえず2つの対策を実施します。

  • swapを無効に ― メモリが1GBもあるので無茶しなければswapなしでも暮らしていけます。
  • logをHDDに ― HDDは常時接続の前提なので。/var/log にHDDをマウントするだけです。一部書かれないログがありそうだけどまぁいいでしょ。
私はやってないですがRAMディスクを使うのもありだと思います。

swapを無効にする

まずは現状確認。

$ free -h
             total       used       free     shared    buffers     cached
Mem:          927M       916M        10M         0B        67M       758M
-/+ buffers/cache:        90M       837M
Swap:          99M         0B        99M
使われていないけど100MBぐらい予約されてる。
無効にしよう。
$ sudo swapoff --all
$ free -h
             total       used       free     shared    buffers     cached
Mem:          927M       914M        12M         0B        68M       755M
-/+ buffers/cache:        90M       836M
Swap:           0B         0B         0B
swapはいなくなったけど再起動したらきっと復活してくるので...
$ sudo apt-get remove dphys-swapfile
$ sudo reboot
再起動後
$ free -h
             total       used       free     shared    buffers     cached
Mem:          927M       652M       274M         0B        18M       574M
-/+ buffers/cache:        59M       867M
Swap:           0B         0B         0B
OK. swapいなくなってる。

他にも

/tmp をRAMディスクに逃がす とか
LAMPやLAPP環境を組むならデータベースファイルをHDDに置く とか
そんな風に書き込み頻度の高い部分を待避させていくのがよさそうです。
でもパフォーマンスは犠牲になります。
ご利用は計画的に。

2013年5月13日月曜日

アクリルLEDパネルお試し

とあるイベントでアクリルLEDパネルの展示&作成をやってたのを見て、自分もやってみたくなったので挑戦してみました。

とりあえず雰囲気を掴むため、出来るだけあり合わせの道具で。
アクリル板だけ東急ハンズで買ってきました。
  • 削る道具: ダイソールーター
  • 光る仕組み: Arduino + フルカラーLED (OSTA5131A)
  • アクリル板: 透明 2mm厚
  • パネルの固定: 洗濯バサミ:)
パネルの作成はシンプルに
  1. 紙に絵を下書き
  2. アクリル板を紙に乗せて下絵をペンでトレース
  3. アクリル板に書いた線をなぞってルーターで軽く削る
削る作業だけは集中力が要求されますが、あとは適当。

完成したパネルをLEDの上に垂直に立てて置いただけですが、ちゃんとLEDパネルっぽくなりました。
LEDひとつだと光量が足りないかも?とか、ちゃんと絵が光るのかな?とか不安でしたが杞憂だったみたい。

お手軽でなおかつ面白い。
道具を揃えてパネル台も含めてきちんと作るのもいいかなー。

シンプルな絵ということで、Minecraftで人気のCreeperさんにご登場願いました:)

2013年1月14日月曜日

one-liner時報

終日一人で自宅に引き篭っていると、時間の感覚が無くなってアレな感じです。
最近、職場で時報が鳴るようになったら時間が分かりやすくてよかったので、自宅でも導入してみました。

その辺で公開されているソフトを使ってもいいのですが、折角なので自前で。

サウンドの再生自体は.NETでお手軽にできるので、PowerShellから一発。
(New-Object Media.SoundPlayer("C:\time-signal\signal.wav")).PlaySync()
これをタスクスケジューラで毎時59分56秒とかに実行するよう登録すると、一応時報になります。

ですがこのままではタスク実行時にコマンドプロンプトウィンドウが表示されてちょっと残念。

こういうときはWshShellオブジェクトからRun
第2引数IntWindowStyleを0にすればウィンドウは表示されません。

こんな.vbsファイルをタスクスケジューラに登録すれば目的達成。
CreateObject("WScript.Shell").Run "powershell (New-Object Media.SoundPlayer(\""C:\time-signal\signal.wav\"")).PlaySync()",0
one-linerといいつつ .vbsファイルをタスクスケジューラから呼ぶという邪道な感じになってしまいました。

サウンドデータは好きなものを.WAV形式で調達すれば良いです。

2013年1月4日金曜日

P/Invokeの規定の呼び出し規約

自前のunmanagedなdllを、.NETなアプリケーションからP/Invokeで使おうとした際に  pInvokeStackImbalance で躓いたメモです。
環境は Visual Studio 2010 / .NET Framework 4.0

unmanaged DLL 側はC++でこんな感じ。
extern "C" {
 __declspec(dllexport) bool
 ReadValue(wchar_t* buffer, unsigned int bufferLength) {
  wcscpy_s(buffer, bufferLength, L"hogehoge");
  return true;
 }
}
それをこんなC#コードで呼び出すと、デバッグ実行時に pInvokeStackImbalance で怒られます。
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public static extern bool ReadValue(StringBuilder buffer, uint bufferLength);
MSDN: DllImportAttribute.CallingConvention フィールド によると
DllImportAttribute.CallingConvention の規定値は Winapi。
これはプラットフォーム標準の呼び出し規約を使用することを示す。Windows なら StdCall。
よくP/InvokeされるWin32APIの場合はすべてStdCallなので規定値でOKですね。

というわけで今回は次ように呼び出し規約をきちんと指定してあげないといけない。
[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern bool ReadValue(
    StringBuilder buffer, uint bufferLength);
ちなみにこのエラーを検出している MDA (Managed Debugging Assistant) は、.NET Framework 3.5 では規定値で無効になっているらしいです。

2012年8月26日日曜日

AndroidとPC(Winamp)の楽曲同期

AndroidとPC(Winamp)の楽曲プレイリスト同期に手こずった記録です。

前提

  • 自宅では楽曲ファイルの再生とプレイリスト管理をWindows PC上のWinampで行う
  • 楽曲ファイルはすべてUbuntu PCに保存されていて、Windows PCからはsamba経由でアクセス
  • 外出時にはAndroid (NEC N-01D) で音楽を聴く

やりたいこと

  • Winampの任意のプレイリストのファイルをAndroidで同期・聴けるようにしたい
  • 対象のプレイリストは時々更新するので出来る限り手軽に同期したい
  • USBケーブルでPCとAndroid機を繋ぐのはめんどくさいのでWi-Fiで済ませたい

まずはWinampの世界で


Android版Winampを使えばWi-Fi経由で任意のプレイリストを同期できるらしい! 素敵!

  • PCのWinampからAndroidデバイスが見つからない
    1. とりあえずUSBで繋いでみると当然見つかります
    2. 無線LAN接続のノートPCのWinampからもOK(・∀・
    3. 有線LANで接続されたPCから無線LAN接続のAndroid機は見つけられない……?
    4. ルーターが無線LANポートへのマルチキャストパケットの転送を制限していたので解除
    5. 同期できた!(・∀・
  • 文字化け
    • 同期できた楽曲をAndroidで見るといくつか文字化けが見つかる
    • Webで検索したら、ID3タグがUnicode系でないとAndroidでは文字化けするという情報多数
    • ID3Uniで全部Unicode化
    • だいぶ改善されました。が、まだ文字化けしている楽曲が残っています…
  • ファイル名が文字化け or 失われる
    • ファイル名が失われていた
    • Winampは転送時にファイル名の変更をしている?
    • ダメなファイル名の特徴を調べればわかるかもしれませんがここで気力が尽きました
  • Wi-Fiでの転送が不安定
    • 同期中に途中で通信が切れる
    • 症状は、Android側のWinampがクラッシュするか、Wi-Fi接続が切れる
    • どちらが発生するかは不定

…Winampの世界で完結させるのは諦めることにしました。


次の戦略 - rsync backup for android で同期

  1. WinampからプレイリストをM3U形式で出力
    • Winampのプレイリストビューで保存(Ctrl+S)するだけです
  2. Ubuntu PCでM3Uを解釈して必要な楽曲ファイルのシンボリックリンクを同期用フォルダに作る
    • 同期用フォルダには、楽曲フォルダのツリーをそのままコピーして、必要なファイルのみシンボリックリンクを作ります
    • cronで固定のパスのm3uを読み、実行
  3. rsync backup for android で同期
    • シンボリックリンクを解決してコピーする設定

M3Uを解釈して同期用フォルダを構築
  • Winampが吐き出すM3Uは次の通りということにしています。
    • Shift-JIS (CP932)
    • '#' から始まる行以外がファイルのリスト
  • 波ダッシュ問題
  • ファイルパスと正規表現
    • '/' で囲むとわけわかんなくなります。
    • '|' がいいと思います。
#!/bin/bash

if [ ! -f "$1" ]; then
  echo "no playlist is specified."
  exit
fi

WINDIRARR=(S:/sound/ T:/sound2/)
SRCDIRARR=(/home/library/sound1/ /home/library/sound2/)
OUTDIRARR=(/home/users/android-rsync/data/1/ /home/users/android-rsync/data/2/)
TMPFILE=$1.tmp

for (( i = 0; i < ${#OUTDIRARR[*]}; i++ )); do
  find ${OUTDIRARR[$i]} -type l -exec rm {} \;
done

sed -e 's|\\|\/|g' $1 > $TMPFILE

while read LINE; do
  LINE=`echo $LINE | nkf --ic=CP932 --oc=UTF-8 | sed 's|\\s*$||g'`
  
  if test 0 -ne ${#LINE} && ! echo $LINE | grep -sq '^#'; then
    RELPATH=$LINE
    for (( i = 0; i < ${#WINDIRARR[*]}; i++ )); do
      WINDIR=${WINDIRARR[$i]}
      SRCDIR=${SRCDIRARR[$i]}
      OUTDIR=${OUTDIRARR[$i]}
      RELPATH=`echo "$LINE" | perl -pe "s|$WINDIR||i"`
      if [ "$LINE" != "$RELPATH" ]; then break; fi
    done
    
    if [ "$LINE" != "$RELPATH" ]; then
      RELDIR=${RELPATH%/*}
      if [ ! -d "$OUTDIR$RELDIR" ]; then mkdir -p "$OUTDIR$RELDIR"; fi
      ln -s "$SRCDIR$RELPATH" "$OUTDIR$RELPATH"
    else
      echo "ERROR: $RELPATH"
    fi
  fi
done < $TMPFILE

rsync backup for android
  • Ubuntu側にコレ専用のユーザを作り、鍵を登録します
    •  鍵は rsync backup for android で作ったものを使います
  • Additional rsync options
    • 同期方向は Ubuntu→Android への一方通行になるように設定
    • シンボリックリンクを解決してコピー
      • -l    copy symlinks as symlinks    ←初期状態ではこちら
      • -L    transform symlink into referent file/dir    ←これに変更
Rescan Media
  • Androidはメディアストレージサービスというプロセスでプレイリストを管理しています。
  • 通常はOS起動時やストレージのマウント時にスキャンしてプレイリストを構築するらしいです。
  • なので rsync で引いてきただけでは楽曲はプレイリストに入りません。
  • メディアストレージサービスのスキャンを手軽に手動実行できるのがこのアプリ。
  • 初回起動時は "Auto quit?" が off になっています。チェックをONにしたあと手動でアプリケーションを明示的に終了させないと、2度目以降rescanされていないようでした。
  • アプリを起動したタイミングでrescanが実行されるのかな?

他の戦略 - FUSE


シンボリックリンクではなく Filesystem in Userspace(FUSE) がいいのでは? というアドバイスも貰いました。FUSEというものは知らなかったのですが面白そうです。