2011年2月21日月曜日

デスクトップを有効活用するためのルール

どうも意識的に掃除をしないと、散らかしたままにしてしまう。机の上が汚なけりゃ、デスクトップも然り。後で後では永久に来ない、掃除の時間。

広い画面と、スリープを繰り返しても安定している OS のお陰で、この傾向が一段と悪化。広げたウィンドウ群の下に広がるカオスの世界。

そのうちどこに何があるのかわからなくなり、整理しないでアクセスするメリットが失われていく。

この癖を直すには、もう意識的な縛りをかけるしかないと感じてきた。

この際、以下のルールを遵守して運用することに。

  • ルール1 : デスクトップには一時的なもの以外置かない。
  • ルール2 : 定期的に使わなくなったものを片づける。
  • ルール3 : 「使うかもしれない」の誘惑に打ち勝つ。

LibreOffice でページ番号を付ける

メニューより「挿入 > フッター > 標準」にチェック。

CropperCapture[86]

挿入 > フィールド > ページ番号」を選択。

CropperCapture[87]

 

参考サイト

Windows 7 64bit でも「ぴたすちお」 - オートレイズ、ウィンドウの最小化 、縦方向に最大化

1. 「ひたすちお」が Windows 7 64bit で動作しなかった

OS を Windows 7 64bit版 に変更した。ウィンドウの操作に欠かせないユーティリティとして、「ぴたすちお」をインストール。しかし、ひたすちを起動していると、一部のアプリケーションの動作が動作がおかしくなる。そのため、利用を控えていた。

OS が 64bit になり、メモリをたくさん使用できるので、快適になった。しかし、ぴたすちお で、

  1. ウィンドウを最小化したり、
  2. 縦方向に最大化すること

が簡単にできなくなったので、ストレスを感じる。 (+_+)

  • マウスオーバーでウィンドウをアクティブすること

は、別のツールで実現できた。しかし、ウィンドウの最小化と、縦方向に最大化をする、代替となるツ-ルを見つけることができなかった。

Windows 7 では、ウィンドウの下端を画面下までドラッグすると、縦方向に最大化してくれる。しかし、ウィンドウの枠は細くて掴みにくい。だから、この機能を使っていない。

追記(2012/05/14): 現在、Windows 7 において、マウスオーバーでウィンドウをアクティブにする時間と、タスクバーのプレビュー表示の時間を、レジストリで設定している。

 

2. 「ぴたすちお」の64bit版をインストール

久しぶりに、「ぴたすち」のサイトを覗いたら、

ぴたすちお ver.2.27 64bit版 2010.12.08

64bit版が随分前に出ていたことに気がつかなかった。ありがたやぁ~ ^^

早速、ダウンロードしてインストール。しかし、起動しようとする、

コンピューターに mfc100.dll がないため、プログラムを開始できません。この問題を解決するには、プログラムを再インストールしてみてください。

mfc100.dll – なたでぽぽ によると、

mfc100.dllというのは、Visual C++ 2010で作ったソフトを動かすときに必要なdllのひとつでして、いわゆるランライムライブラリというやつです。…

32ビット版と64ビット版が別々に用意されているので、各自の環境にあった方をインストールして下さい。

上記をインストールしたら起動できるようになった。

 

3. オートレイズの設定

  1. タスクトレイにある「ぴたすちお」を右クリック > 設定。
  2. 「オートレイズの設定」ボタンをクリック。
  3. 「オートレイズ機能を有効にする」をチェック。

CropperCapture[84][4]

 

4. タイトルバーをクリックしたときの設定

タイトルバーをクリックしたときの動作を設定した。

  • 「マウスショートカットの設定」ボタンをクリック。
  • タイトルバーを…
    • 右クリック : 最小化
    • Shift + 右クリック : 最大化 (縦方向)
    • Ctrl + Shift + 右クリック : 常に最前面を切替

CropperCapture[85][4]

追記(2012/05/14): 現在、仮想デスクトップ に Dexpot を使い、ホットキーの設定とタイトルバーへのマウス操作をカスタマイズしている。ウィンドウの枠を素早くつかむには、hMouseLimit を併用すると良い。または、ウィンドウ の枠を太くしてマウスでつかみやすくする

2011年2月17日木曜日

Haskell の Data.IORef を使い IO モナドの中で変数を更新

Haskell で変数の更新を伴うインデックス付きループを再帰で置き換えるには」のつづき

1. Data.IORef で変数の更新

Python のような言語では、変数の更新はごく普通に書ける。

x = 100
print x      #=> 100
x = 200
print x      #=> 200
x = 200 * 2
print x      #=> 400

Haskell では Data.IORef を使うと、一見、変数の更新をしているかのような記述ができる。

このモジュールの機能は、

Mutable references in the IO monad.

使う関数は以下の 4 つ。返される値が IO で包まれている。

それぞれ関数名が示しているように、IORef 型の値を生成し、読み取り、書き出し、変更する。

import Data.IORef

main = newIORef 100 >>= \x ->
       readIORef x  >>= print >>   -- 100
       writeIORef x 200       >>   
       readIORef x  >>= print >>   -- 200
       modifyIORef x (*2)     >>
       readIORef x  >>= print      -- 400

do 式を使うなら、

main = do x <- newIORef 100
          print =<< readIORef x   -- 100
          writeIORef x 200        
          print =<< readIORef x   -- 200
          modifyIORef x (*2)
          print =<< readIORef x  -- 400

 

2. 変数を更新する例

「文字列の配列の中から最長の文字列と、そのインデックスを返す」関数Data.IORef を使って書くなら、

import Data.IORef

longestWord :: [String] -> IO (String, Int)
longestWord (x:xs) = newIORef x >>= \word ->
                     newIORef 0 >>= \idx ->
                     loop word idx 1 xs 
    where
      loop word idx i []     = readIORef word >>= \word' ->
                               readIORef idx  >>= \idx'  ->
                               return (word', idx')
      loop word idx i (x:xs) = readIORef word >>= \word' ->
                               (if length word' < length x 
                                then writeIORef word x   >>
                                     writeIORef idx i 
                                else return ())          >>
                               loop word idx (i+1) xs 
                                     
main = (longestWord $ words "The quick brown fox") >>= print

うーん、読みやすくはないなぁ。。 (@_@;

do 式で置き換えるなら、

longestWord :: [String] -> IO (String, Int)
longestWord (x:xs) = do word <- newIORef x 
                        idx  <- newIORef 0
                        loop word idx 1 xs 
    where
      loop word idx i []     = do word' <- readIORef word
                                  idx'  <- readIORef idx
                                  return (word', idx')
      loop word idx i (x:xs) = do word' <- readIORef word
                                  if length word' < length x 
                                     then do writeIORef word x
                                             writeIORef idx i 
                                     else return ()
                                  loop word idx (i+1) xs

ループのインデックスに相当する変数も IORef 型の値にするなら、

longestWord :: [String] -> IO (String, Int)
longestWord (x:xs) = do word <- newIORef x 
                        idx  <- newIORef 0
                        i    <- newIORef 1
                        loop word idx i xs 
    where
      loop word idx i []     = do word' <- readIORef word
                                  idx'  <- readIORef idx
                                  return (word', idx')
      loop word idx i (x:xs) = do word' <- readIORef word
                                  i'    <- readIORef i
                                  if length word' < length x 
                                     then do writeIORef word x
                                             writeIORef idx i' 
                                     else return ()
                                  modifyIORef i (+1)
                                  loop word idx i xs

 

参考サイト

2011年2月14日月曜日

Windows Live Writer で投稿前に確認ダイアログを表示させる

Windows Live Writer でブログの下書きをしていたら、誤って投稿ボタンを押してしまった。本当は左隣のクリップボードを押すつもりだったのだけれど。 (+_+)

CropperCapture[72]

そういえば、ブログを投稿する前に

「投稿してもいいですか?」

の確認ダイアログが出ないことにはじめて気がついた。

操作を誤るといけないから、オプションで「投稿前に確認ダイアログを表示する」設定を探したけれど、それらしいものが見当らず。

仕方がないので、使っていない「タグ」の機能を利用して、確認ダイアログを表示させることに。

  • オプション > 基本設定 > 投稿 の「タグが未挿入の場合、投稿前に通知する」をチェック。

CropperCapture[71]

これにより投稿ボタンを押すと以下のダイアログが表示されるようになり、「はい」を押すことによって投稿処理が行なわれる。

CropperCapture[70]

ちなみに「タグ」とは、「挿入 > 記事のタグ」で設定できるようで、

CropperCapture[73]

Windows Live Writer Tips: いろいろタグ挿入 によると、

Windows Live Writer には Blog のシステムに依存しないタグ挿入機能が付いてます。タグをそのまま記事の中にリンクとして挿入するだけですが。…

規定では、Technoratilivedoorはてな などのタグが選択できます。

この機能を使っていないので、苦肉の策として。

しかし、どこかに設定があるのかな?

JINS でメガネを激安購入

使っているメガネの汚れが取れない。専用のメガネ拭きでゴシゴシ頑張ってもダメ。(+_+)

… と思ったら、お店の人曰く

「これは表面のコートが剥がれていますね。」

と。あ~、また余計な出費が。。と悩んでいたら、JINS

ここ数年メガネを変えてなかったので、こんなに安い店があることを知らなかった。 (@_@;

眼鏡市場 の方がブランドを多く取り扱っていて魅力的だったけれど、値段が比較にならなかったので JINS で躊躇なく購入。これならメガネもサングラス感覚で買うことができる。

DSC03228

昔はレンズだけで 2万くらいしたと思うのだけれど、どうなってるんだろう。

こういうビジネスモデルが台頭すると、消費者としてはありがたいけれど、昔お世話になった眼鏡屋さんは絶対にやっていけない。便利な世の中がいいのか、それとも普通の人がお店出して、普通に暮らせる時代が良かったのか。

いやはや複雑な心境。。

追記(2010.2.15) : 「着替える眼鏡女子HD」 とか見ると、メガネも昔よりファッション性が高くなってきたなぁ。メガネがあるとそちらに注意が向けられることと、メガネにより隠れた部分を脳内で補完するからカワイク見えるのかな。

2011年2月13日日曜日

Haskell で変数の更新を伴うインデックス付きループを再帰で置き換えるには

1. ループ内における変数の更新はややこしい

Programming in Scala (p354) に次のような関数の例が書かれている。

これを Python で書くなら、

def longestWord(words):
    word = words[0]
    idx = 0
    for i in range(1, len(words)):
        if len(word) < len(words[i]): 
            word = words[i]
            idx = i
    return (word, idx)

print longestWord("The quick brown fox".split())

やってることは単純。しかし、昔からこういうコードを読むのは苦手だった。

最初にローカル変数を複数用意して、ループ内でごちゃごちゃと更新。この程度ならまだしも、ループが二重以上になると頭が沸騰してくる。 (+_+)

曲者はループ内での変数の更新。

CropperCapture[60]

更新されている変数は、

  • 最長の文字列を保持する word 
  • 最長の文字列のインデックスを保持する idx
  • 文字列の配列要素を走査するための i

配列を走査するイメージを頭に描きつつ、状況に応じて変数を更新。

CropperCapture[61]

誰かに計算を任せ、その結果を受け取るという楽な方法ではない。

 

2. 「再帰」と更新用の引数を用いて、変数の更新を模倣する

では、これを変数の更新が許されず、for ループも用意されていない Haskell でどう書くのか?

次の 2 点を覚えておく。

  1. ループを「再帰」で置き換える。
  2. 変数の更新は、再帰で与える引数において、更新後と想定する値を渡すことで代替。

加えて、Haskell では配列ではなくリストがよく用いられ、配列的な発想とは異なることに注意。

構造的な違いとして、配列は要素が格納されている場所にインデックス情報が存在するのに対して、リストはそれがない。リストが再帰的な構造を基盤として要素を走査するが、配列はインデックスによりそれを行うこと。

よって、完全に対応したものを考えているのではなく、結果として同等な方法の比較をする。

 

更新される値を考えない場合

まずは、インデックスは無視して、最長の文字列を返すだけの関数を考える。

longestWord [x]    = x
longestWord (x:xs) = let word = longestWord xs
                     in if length x < length word 
                        then word 
                        else x

リストに対する関数を考えるときは、オブジェクト指向のアナロジーで考えているので、上記二行目のコード、

longestWord xs

を以下のように頭の中で置き換えている。

xs.longestWord()

全体としては下図のようなイメージ。

CropperCapture[62]

 

更新される値に相当する引数を使う

次に、インデックスも返すために、更新用の変数と同じ役割をする引数 idx を関数に追加する。 idx 変数に配列のインデックスに相当する値を累積させる。(これを累積と言うのか微妙だけれど。。)

longestWord' idx [x]      = (x, idx)
longestWord' idx (x1:xs1) = let (x2, idx2) = longestWord' (idx+1) xs1
                            in if length x1 < length x2
                               then (x2, idx2)
                               else (x1, idx)

longestWord xs = longestWord' 0 xs

先ほどと同じく上記二行目のコード、

longestWord’ (idx+1) xs1

を以下のように頭の中で置き換えている。

xs1.longestWord’(idx+1)

これより、インデックスを累積 (更新) するための変数は、リストのある要素が次の要素に対して、特定の計算の結果を渡す先だと見ることができる。

リスト処理における再帰的な関数は、オブジェクト指向の考え方と親和性が高い。

CropperCapture[64]

 

3. 予めインデックスを用意しておく方法

別の方法としては、対象のリストとは別にインデックスのリストを用意し、それと組み合わせた結果に対して関数を定義する。

longestWord' :: [(String, Int)] -> (String, Int)
longestWord' [x]             = x
longestWord' (x1@(x,idx):xs) = let x2@(x', idx') = longestWord' xs
                               in if length x < length x' 
                                  then x2 else x1
                                  

longestWord xs = longestWord' $ zip xs [0..]

この方法は、インデックス情報を持った配列に構造を予め似させてから計算を行なっていると言える。ただし、ループはリストの再帰的な構造を利用することにより代替していることは先ほどと変わりはない。

また、遅延評価の Haskell では、予めどのくらいインデックスが必要か考えておく必要はない。

 

4. State モナドで試したら

ところで、状態の「更新」と聞いて連想するのは State モナド。「longestWord’ 関数を再帰的に適用するごとにインデックスの状態を更新する」と見なして考えたら、どのように書けるのだろう?

 

s –> (a, s) 型の関数

最初は、ライブラリに用意されている State モナドを利用するのではなく、関数をつなげる関数も自分で定義して考える。

State モナドで、状態の変更をシミュレートした関数として用いられるのは、

s –> (a, s)

という型を持つ。

先ほど定義した longestWord’ 関数の場合であれば、第1引数と第2引数を逆転させ、適当に配列を与えたときの型がこれに相当する。

*Main> :t (flip longestWord') ["The","quick","brown","fox"]
(flip longestWord') ["The","quick","brown","fox"]
  :: (Num a) => a -> ([Char], a)

この関数を再帰によりつなぎ、計算が進行するに連れ、インデックスを保持する変数が更新されていくと考えてみる。

 

計算をつなげる関数

最初に以下の型を持つ関数に対して、

s –> (a, s)

  1. 何らかの状態を持つ型 s の値を引数に与えると、
  2. その値が更新されたことに付随して、
  3. 結果 a が生じる
  4. … と解釈できる関数を「つなげる」関数

を考える。( 詳しくは「Haskell の State モナド (1) - 状態を模倣する」を参照 )

読みやすさを考慮して、上記関数の型に別名を付けておく。

type State s a = s -> (a, s)

この State s a 型をつなげる計算を comb とする。 (>>= に相当)

comb :: State s a -> (a -> State s b) -> State s b
comb m k = \s -> let (x1, s') = m s in k x1 s'

comb の第1引数の結果に対して、第2引数が関心を持たない関数を comb_ とする。 (>> に相当)

comb_ :: State s a -> State s b -> State s b
comb_ m n = m `comb` \_ -> n

状態の変更を行わず、与えた引数を結果とする関数を ret とする。 (return に相当)

ret :: a -> State s a
ret x = \s -> (x, s)

 

計算をつなげる関数を使って longestWord’ を定義

準備ができたので、longestWord’ 関数の定義をする。

ここでは「インデックスを保持する変数」が更新されることに付随して、「最長の文字列」という結果が生じると見なして考える。上記で定義した 3 つの関数を使うと、更新されるインデックスを隠蔽できる。

State s a の s に相当するのが「インデックス」を表わす Int 型。 a に相当するのが「最長の文字列」を保持する String 型。

CropperCapture[65]

longestWord' :: [String] -> State Int String
longestWord' [x]    = ret x
longestWord' (x:xs) = longestWord' xs `comb` \x' ->
                      if length x < length x'
                      then inc `comb_` ret x'
                      else ret x

inc = \idx -> ((),idx +1) 

longestWord xs = longestWord' xs 0

インデックスを更新する操作を inc 関数で定義している。

CropperCapture[66]

( コード全体は gist: 823793 - GitHub )

 

5. Control.Monad.State を利用する

今度はライブラリに用意されている関数に置き換える。

最初に State モナドを利用するためにモジュールをインポート。

import Control.Monad.State

これを利用して、

longestWord' :: [String] -> State Int String
longestWord' [x] = return x
longestWord' (x:xs) = longestWord' xs >>= \x' ->
                      if length x < length x'
                      then inc >> return x'
                      else return x

inc = modify (+1)

longestWord xs = runState (longestWord' xs) 0

inc 関数は、インデックスの状態に相当する変数を更新していた。このような状態を更新する関数もライブラリに用意されている。

Control.Monad.State.Class

modify :: MonadState s m => (s -> s) -> m

Maps an old state to a new state inside a state monad. The old state is thrown away.

( コード全体は gist: 823796 – GitHub )

 

do 式

モナドは do 式を利用できるので、longestWord’ 関数を以下のように書くことも可能。

longestWord' :: [String] -> State Int String
longestWord' [x]    = return x
longestWord' (x:xs) = do x' <- longestWord' xs
                         if length x < length x'
                            then do inc 
                                    return x'
                            else return x

( コード全体は gist: 823796 - GitHub )

 

6. 更新する変数を増やした場合

最初に定義した Python のコードでは、更新される変数は idx と word だった。上記 Haskell のコードでは、更新される値がインデックスに限定されている。

idx と word が更新されると想定し、より Python で書いたときのコードに似せるなら、

longestWord' word idx []     = (word, idx)
longestWord' word idx (x:xs) = let (x', idx') = longestWord' x (idx+1) xs
                               in if length word < length x'
                                  then (x', idx')
                                  else (word, idx)

longestWord (x:xs) = longestWord' x 0 xs

大雑把なイメージは下図。 longestWord 関数において、longestWord’ 関数の第1・第2引数を与えることが、Python における変数の初期化に相当する。

CropperCapture[69]

先ほどと同じようにオブジェクト指向的に見るなら、

longestWord' x (idx+1) xs

を以下のように頭の中で置き換える。

xs.longestWord’(x, idx+1)

 

State

word, idx を更新される変数と見なし、先ほどと同じく、ライブラリに用意されている State モナドを利用しないで書いてみる。

今回は、更新される変数として word, idx をタプルの要素とし、結果に相当するものは () とする。

関数の型は、

[String] –> State (String, Int) ()

更新される変数 word を計算のつながりの中で参照するためには、状態を結果として取り出す必要がある。そのための関数を get とすると、

get :: State s s
get = \s -> (s, s)

状態を変更するための関数 put も用意しておく。

put :: s -> State s ()
put x = \_ -> ((), x)

最終的に結果は必要なく、状態がわかれば良いので、そのための関数 execState を定義。

execState :: State s a -> s -> s
execState s s0 = snd $ s s0

これらを用いて、

longestWord' :: [String] -> State (String, Int) ()
longestWord' [] = ret ()
longestWord' (x:xs) = get             `comb` \x1@(word, idx) ->
                      put (x, idx+1)  `comb_` 
                      longestWord' xs `comb_` 
                      get             `comb` \x2@(word', idx') ->
                      if length word < length word' then put x2 else put x1
                   
longestWord (x:xs) = (execState $ longestWord' xs) (x, 0)

( コード全体は gist: 823947 – GitHub )

 

Control.Monad.State

Control.Monad.State を利用するなら、

longestWord' [] = return ()
longestWord' (x:xs) = get             >>= \x1@(word, idx) ->
                      put (x, idx+1)  >> 
                      longestWord' xs >> 
                      get             >>= \x2@(word', idx') ->
                      if length word < length word' then put x2 else put x1

longestWord (x:xs) = execState (longestWord' xs) (x, 0)

( コード全体は gist: 824329 - GitHub )

上記を do 式で書き直すと、

longestWord' [] = return ()
longestWord' (x:xs) = do x1@(word, idx) <- get
                         put (x, idx+1) 
                         longestWord' xs
                         x2@(word', idx') <- get
                         if length word < length word' then put x2 else put x1

( コード全体は gist: 824329 – GitHub )

 

7. foldl を使い、畳み込みながら更新

追記(2011.2.19) : 畳込み関数を使うなら、foldl の第2引数に更新する変数に相当する値を与える。

longestWord' (x:xs) = foldl f (x, 0, 0) xs
    where
      f (word, idx, i) w | length word < length w = (w, inc, inc)
                         | otherwise              = (word, idx, inc)
          where 
            inc = i + 1

longestWord xs = let (word, idx, _) = longestWord' xs in (word, idx)

 

State

Control.Monad.State を使うなら、どうなるのだろう? (cf. Haskell の sequence 関数 - foldr をイメージして)

読みやすくするために予め別名を付ける。

type Word  = String  -- 最長の文字列
type Idx   = Int     -- 最長の文字列のインデックス
type Index = Int     -- ループで使うインデックス

これを用いて、畳み込むとき、ループで使うインデックス (Index) が更新されていくと同時に、 (最長の文字列、そのインデックス) という結果が生じると解釈する。

longestWord' :: [String] -> State Index (Word, Idx)
longestWord' (x:xs) = foldl f (return (x, 0)) xs
    where
      f :: State Index (Word, Idx) -> String -> State Index (Word, Idx)
      f s w = s >>= \(word, idx) ->
              (if length word < length w
              then return (w, idx+1)
              else return (word, idx)) >>= \wordIdx ->
              State $ \i -> (wordIdx, i+1)

longestWord xs = let (wordIdx, _) = runState (longestWord' xs) 0 in wordIdx

( コード全体は gist: 834817 - GitHub)

do 式で置き換えるなら、

longestWord' :: [String] -> State Index (Word, Idx)
longestWord' (x:xs) = foldl f (return (x, 0)) xs
    where
      f :: State Index (Word, Idx) -> String -> State Index (Word, Idx)
      f s w = do (word, idx) <- s
                 wordIdx <- if length word < length w
                            then return (w, idx+1)
                            else return (word, idx)
                 State $ \i -> (wordIdx, i+1)

longestWord xs = let (wordIdx, _) = runState (longestWord' xs) 0 in wordIdx

( コード全体は gist: 834817 - GitHub )

//TODO

Haskell の Data.IORef を使い IO モナドの中で変数を更新」につづく

 

参考記事

2011年2月9日水曜日

Haskell で Text.Regex の splitRegex 関数を利用しようとするとリンクエラー

Haskell Platform/2010.2.0.0 において、文字列をリストに分割するため、 Text.Regex モジュールの splitRegex を利用しようとしたらエラー。 OS は Windows 7 64bit 。

Prelude> :m Text.Regex
Prelude Text.Regex> splitRegex (mkRegex " ") "hoge piyo fuga"

これを実行すると、

Loading package array-0.3.0.1 ... linking ... done.
Loading package bytestring-0.9.1.7 ... linking ... done.
Loading package containers-0.3.0.0 ... linking ... done.
Loading package syb-0.1.0.2 ... linking ... done.
Loading package base-3.0.3.2 ... linking ... done.
Loading package mtl-1.1.0.2 ... linking ... done.
Loading package regex-base-0.93.2 ... linking ... done.
Loading package regex-posix-0.94.2 ... linking ... : C:\PROGRA~2\HA
SKEL~1\201020~1.0\lib\extralibs\regex-posix-0.94.2\ghc-6.12.3\HSregex-posix-0.94
.2.o: unknown symbol `_regerror'
: unable to load package `regex-posix-0.94.2'

regex-compat on latest Haskell Platform : Programming Haskell Cafe によると、

For what its worth, Regex-posix worked fine with Platform 2009.2.0.2.
I follow GHC releases rather than Platform ones, so I don't know about
later versions.

このバージョンの Haskell が問題のようだ。

 

regex-posix パッケージを最新にする

[haskell-platform] #137: Linking error when using Text.Regex.Posix によると、

'cabal install regex-posix' can solve this problem,

コマンドラインより、

cabal install regex-posix

インストールされたことを確認するために

ghc-pkg list

しかし、依然としてエラーが表示され実行できない。

 

regex-compat パッケージを最新にする

regex-posix に対するパッケージの依存関係を、

ghc-pkg dot | grep "regex-posix"

により調べると、regex-compat モジュールが regex-posix に依存していることがわかる。 ( grep コマンドは Cygwin を利用)

また、Hoogle で検索すると、splitRegex はパッケージ regex-compat にあると表示される。

試しに、

cabal install regex-compat

により regex-compat もインストールしたら splitRegex を使えるようになった。

 

再びモジュールの依存関係を表示させたら、

"regex-compat-0.93.1" -> "regex-posix-0.94.4"
"regex-posix-0.94.4" -> "array-0.3.0.1"
"regex-posix-0.94.4" -> "base-4.2.0.2"
"regex-posix-0.94.4" -> "bytestring-0.9.1.7"
"regex-posix-0.94.4" -> "containers-0.3.0.0"
"regex-posix-0.94.4" -> "regex-base-0.93.2"
"regex-posix-0.94.2" -> "array-0.3.0.1"
"regex-posix-0.94.2" -> "base-4.2.0.2"
"regex-posix-0.94.2" -> "bytestring-0.9.1.7"
"regex-posix-0.94.2" -> "containers-0.3.0.0"
"regex-posix-0.94.2" -> "regex-base-0.93.2"
"regex-compat-0.93.1" -> "regex-posix-0.94.2"
"haskell-platform-2010.2.0.0" -> "regex-posix-0.94.2"

というようにバージョンがごっちゃになってしまったけれど大丈夫かな。。 (@_@;

 

インストールする順序

HackageDB: regex-posix-0.94.4 よりregex-posix をダウンロードし、

runhaskell Setup configure
runhaskell Setup build
runhaskell Setup install

によりインストールしてもダメだった。

  1. regex-posix をインストール
  2. regex-compat をインストール

の順で行なったときだけ動いてくれた。

2011年2月1日火曜日

USB スピーカーとヘッドホンに対して VSTHost でイコライザーをかける - 仮想的なサウンドデバイスを利用して

0. 目次

PC の音声出力に対してリアルタイムにイコライザーをかける」のつづき

VSTHost のプラグインと設定ファイルをオンラインストレージで管理 につづく

 

1. USBスピーカーとヘッドホンにイコライザーをかけたい

前回、USB スピーカーに対してイコライザーをかけるために、下図の構成にした。 ( ASIO4ALL を使わない場合)

CropperCapture[26]

この設定で PC のフロントにあるイヤホンジャックにヘッドホンを差し込む。

CropperCapture[51]

当然ながら、この状態ではヘッドホンに出力される音声は VSTHost を経由していないため、イコライザーを効かせることができない。

ヘッドホンに対しても VSTHost を経由して、イコライザーをかけたい。

 

2. 仮想的なサウンドデバイスを経由して音声を出力する

a. 仮想的なサウンドデバイスとは

USB スピーカーとヘッドホンから出力される双方の音声を VSTHost に通すためには、仮想的なサウンドデバイスを利用する。

Windowsの最大音量を制限する」 によると、

Windows上で再生されるオーディオをそのままVSTホストへ入力できるようにするには、そのための仮想オーディオドライバが必要である。

前回は、音声の出力先として内蔵のサウンドデバイスに出力した。これをソフトウェア的なものに置き換える必要がある。

CropperCapture[52]

 

b. 仮想的なサウンドデバイスのインストール

仮想的なサウンドデバイスは、サウンド用のアプリケーションに付属している場合がある。

これは純粋な意味でのフリーのものが見つからないのだが(…)、Aimersoft WMA Converterという製品の無料の試用版に付属しているものがある… (同上より)

SnapCrab_NoName_2013-2-27_9-49-4_No-00Aimersoft Music Converter より、Free Trial をダウンロードしてインストール。

これにより「コントロールパネル > サウンド」を確認すると、仮想的なサウンドデバイス

  • WsAudio_DeviceS(1) ~ (5)

の 5 つが追加されたのがわかる。

WsAudio_DeviceS(1) を既定のデバイスに設定。

CropperCapture[55]

 

c. VSTHost の設定

VSTHost のメニューより「Devices > Wave…」を選択する。

  • Input port: ライン WsAudio DevicesS(1) --- 上記で「既定」に設定した仮想的なサウンドデバイス
  • Output Port: スピーカー SoundMAX Integrated --- サウンドカードのヘッドホンの出力に対応したデバイス

( MME, DS のどちらでも聞けた。)

CropperCapture[59]

 

d. 全体の構成

この段階で、以下のような構成となる。

CropperCapture53

前回 VSTHost への入力はサウンドカードの「ステレオミキサー」を利用した。今回は「ライン」を使った。この辺り何がどういう機能を担っていて、使い分けの基準がよくわからない。 (+_+)

水おいしいです^o^: 猿ちぃで仮想ステミキ(仮想サウンドカードを使用してステミキ放送)」によると、

それぞれのサウンドカードはそのサウンドカード内でしか、普通は音のやりとり(再生したり録音したり)ができないよ。別のサウンドカードと音をやりとりするためにはオーディオケーブルをつなぐか、ソフトが必要だよ。

ステレオミキサーは、スピーカーから出る音を受け取って録音する感じだよ。」

仮想サウンドカードの、WsAD_383も、ラインに見えるステレオミキサーだよ…

仮想サウンドカードには、[ステレオミキサー]と表示されていないけれど、ステレオミキサーとして機能するものがあるよ。…

でもステミキ効果が有るのは、同じ名前のスピーカーに対してだけ

上記から推測すると、「サウンドカードというのは音声入出力の機能で、普通は単体で独立して一つのまとまった機能を有している。仮想的なものも同様だけれど、見かけと機能がちょっと違う。」と認識しておけばいいかな。単なる利用者としては。

 

e. 仮想的なサウンドデバイスには色々ある

追記(2013/02/27): 仮想的なサウンドデバイスには、様々な種類がある。以下のサイトに4種紹介されている。

(´・ω・`)「どの仮想サウンドカードを使えば良いのか、よくわかりません。」
(゚ω゚)「ニコ生セッション♪に使うソフトNETDUETTO βに同梱のYamahaのがインストール簡単で良いかも。他のソフトの体験版についてもも今のところ仮想サウンドカード部分は制限が無く使えるみたい。PC少し詳しくて 32BitOSなら、手動インストールになるけどドライバ署名が無いVADplusも普通に使えるしフリーソフトなので良いかも。」
(゚ω゚)「【Yamaha NETDUETTO Driver(WDM)】が最近だとオススメ。ニコ生セッション♪時はアマミキ!は使用しないことに注意。ニコ生セッション♪はあれはあれでステレオミキサーっぽいことができるよ。」

NETDUETTO を試してみたが、自分の環境ではこのサウンドデバイスを既定のデバイスとして指定できなかった。

で紹介されているデバイスは使うことができた。

 

3. ASIO4ALL で音の遅延を最小にする

前回と同じように、音声と映像のズレを最小にするために ASIO4ALL の設定をする。

CropperCapture[54]

VSTHost のメニューより「Devices > Wave…」。

  • Output Port: ASIO: ASIO4ALL v2

CropperCapture[66]

VSTHost のメニューより「Devices > Asio Control Panel…」により、ASIO4ALL の設定ウィンドウを表示し、右下レンチのアイコンをクリックして Advanced Option に切り替える。

 

a. USB スピーカーにイコライザーをかける

USB スピーカーに VSTHost のイコライザーをかけるには、WDM Device List で以下をチェック。

  • WsAudio_DeviceS(1) --- 仮想的なサウンドデバイス
    • In: …
  • USB Audio DAC

ヘッドホンにつながっているサウンドデバイスである SoundMAX Integrated Digital HD Audio のチェックははずす。

CropperCapture[60]

 

b. ヘッドホンにイコライザーをかける

ヘッドホンに VSTHost のイコライザーをかけるには、WDM Device List で以下をチェック。

  • WsAudio_DeviceS(1) --- 仮想的なサウンドデバイス
    • In: …
  • SoundMAX Integrated Digital HD Audio
    • SoundMAX HD Audio O

USB スピーカーにつながっているサウンドデバイスである USB Audio DAC のチェックははずす。

CropperCapture[62]

 

c. ベータ版の利用は慎重に

追記(2013/02/27): Windows 7 32bit をインストールしているノート PC で、 ASIO4ALL 2.11 Beta1 を利用していたら、動画を再生した直後にブルースクリーンが頻発するようになった。

ブルースクリーンに表示されていた内容を見ると、

wsAudioDevice …

とあり、上記の仮想サウンドデバイスに関連しているようだった。

仮想サウンドデバイスは変更せずに、安定版である ASIO4ALL 2.10 – English に戻したら問題なくなった。

 

関連記事