ラベル Windows の投稿を表示しています。 すべての投稿を表示
ラベル Windows の投稿を表示しています。 すべての投稿を表示

2015年4月5日日曜日

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

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

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

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

minmpc (github)

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

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

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形式で調達すれば良いです。

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というものは知らなかったのですが面白そうです。

2012年8月19日日曜日

キーボード G510 のLCDアプレット作成

エアコンのリモコンとか作った そのに。

Arduinoが検知した温度をどこに表示させようかと考えて思い立ったのが、Logicool Gaming Keyboard G510 のLCD。

軽く調べてみて分かったことは
  • Logitech/Logicool の G-Series と呼ばれる機器の幾つかはLCD(と幾つかのボタンのセット)を搭載しており、このLCDはWindows上で動くAppletと呼ばれるソフトウェアから制御する。
  • Applet は G-Series のユーティリティソフトウェアから制御する。
  • G-Series のユーティリティソフトウェアのインストール先にある LCDSDK フォルダ内に、AppletのSDKがある

なんだかいい感じです。

Applet開発はどうやるのか


取り敢えずSDKを覗いてみると、プログラミングガイドライン、APIリファレンス、サンプルコードなど情報は揃っていました。開発言語はC/C++, ビルド環境は Visual Studio でいいみたい。

SDKは大きく二つに分かれています。
  • LCDSDK
    • テキスト表示、ビットマップ表示、プログレスバーなど、便利なライブラリが用意されたセット
  • LCDSDKCore
    • LCDとの接続、LCD横のボタン操作イベント、LCDのドット単位操作など、必要最小限のAPIセット

ぱっと見で単純そうだったので LCDSDKCore の方を使うことにしました。

SDKに含まれるサンプル ColorAndMono を参考にします。
このサンプルは、接続されているLCDがカラーかモノクロかを判断して、ランダムなノイズのような画像をLCDに表示するだけのものですが、LCDの接続/切断、LCD横についているボタンのイベント、その他各種イベントについても一通り書かれているので参考にするにはうってつけ。
ソースを見れば分かりますが、WndProcに処理を実装していくタイプの標準的なWin32アプリケーションに、LCD用の初期化処理とイベント処理が追加されたようなものです。

まず、私が持っている G-Series 機器は G510 だけなので、カラー判別処理とカラーLCD用の処理はバッサリ無視。
G510のLCDは、横160 × 縦43 ドット、単色です。


LCDの表示更新処理には lgLcdBitmap160x43x1 というスゴい名前の構造体を使います。
メンバは2つ。
  • hdr … ビットマップのフォーマットを指定。
  • pixels … 表示させる画像データ。unsigned char の配列。
pixels の各Byteがドットを表し、先頭ビットが 1 だと対応するLCDのドットが明るくなる、といった感じ。lgLcdUpdateBitmap 関数に hdr のアドレスを渡すと、ヘッダの後ろに続く pixels が読まれてLCDに反映されるみたいです。

ここまでわかればAppletを作る最低限の情報は揃っています。

製作

こんなアプリケーションを作ることにしました。 

  • G-Seriesのユーティリティソフト起動時に自動起動
  • 1秒ごとにLCDを更新する (WM_TIMER 使用)
  • USBシリアルポートへArduinoが送り続けてくる温度情報を読み取る
  • 温度情報をLCDに表示
  • 日時も表示
  • 余ったスペースに何か絵を表示できればいいな


LCDのための定型処理は ColorAndMono を参考に必要な処理を実装。
ColorAndMonoサンプルのソースを読めば分かることばかりなのでここでは割愛。

絵はモノクロ2値ビットマップを読み込みます。

文字描画関数なんてものは用意されていないのでそこは何とかする必要があります。
素直に LCDSDK を使うか、別途DIBに描いてコピーするか、自前でビットマップフォントを作るか、まぁどれでもいけると思います。
今回は絵の表示処理が使い回せるのでビットマップフォントを作りました。
日時と温度を表示するだけなので数字+αがあればいいのです。


ちょっとハマったところ その1

Windowsでは fopen("COM3", "r") とかやってもシリアルポートからの入力を読めないみたいです。
この制限を書いた正式なドキュメントは見つからなかったのだけれど、とりあえずダメなものはダメなのだと諦めて Win32 API から読むことにしました。

HANDLE hCom = CreateFile(
    port,            // シリアルポート。"COM3" みたいな文字列
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL
);

if (hCom == INVALID_HANDLE_VALUE) {
    // このへんでエラー処理
    return -1;
}

DCB dcb;
GetCommState(hCom, &dcb);

dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;

SetCommState(hCom, &dcb);

// あとは ReadFile でごにょごにょ。

ちょっとハマったところ その2

2値ビットマップのピクセルデータは 1bit = 1dot なのですが、横ライン1行が 32bit 境界で揃っています。

こちらの説明が分かりやすかったです。
BMP ファイルフォーマット

MSDNには 16bit 境界みたいに書いてあるけど違うと思うの。。。

こんなの出来ました

LCDでネギを振るミクさん

LCDでネギを振るミクさん