FileSystemWatcherによるファイル監視 powershell版

FileSystemWatcherによるファイル監視 – powershell版

基本的に手段は3つあります

1. 同期メソッドによる監視
2. 非同期イベントによる監視
3. バックグラウンドでの監視

この時、共通して最低限必要となるプロパティは3つあり、

NotifyFilterプロパティ、
Pathプロパティ、
Filterプロパティ

上記を指定することで、ファイル種別とイベントを選択できるかと思います

1. WaitForChangedメソッドによる監視

 ファイル監視の振り分けも含め、基本構造だけ組んでみました。
メソッドにイベントが発生すると、ウェイトが外れコンソールへ出力します。

$wait= New-Object System.IO.FileSystemWatcher

$wait.NotifyFilter= [IO.NotifyFilters]::LastWrite -bor [IO.NotifyFilters]::FileName
$wait.Path= “C:\必要なパス”
$wait.Filter= “*.txt”

[string]$chk_time= “”
[int]$i= 0
$chk= { # ScriptBlock
    $chk_time= (Get-Item (Join-Path $wait.Path $f.Name)).LastWriteTime.ToString(‘yy/MM/dd HH:mm:ss’)
    echo (“time: “+ $chk_time)
}

echo “ファイル監視開始”

while(1){

    $f= $wait.WaitForChanged([IO.WatcherChangeTypes]::All) # method

    Write-Host (“`r`n”+ ‘no. ‘+ $i)
    $i++

    echo (“change type: “+ $f.ChangeType)
    # echo (“time out: “+ $f.TimedOut)

    switch($f.ChangeType){
    Created{
        echo (“name: “+ $f.Name)
        & $chk
    }
    Deleted{
        echo (“name: “+ $f.Name)
        echo (“time: “+ (Get-Date).ToString(‘yy/MM/dd HH:mm:ss’))
    }
    Changed{
        echo (“name: “+ $f.Name)
        & $chk
    }
    Renamed{
        echo (“old name: “+ $f.OldName)
        echo (“name: “+ $f.Name)
        & $chk
    }

    } #sw
} #

1. WaitForChangedメソッドによる監視
2. Add_Changedイベントハンドラによる監視
3. Register-ObjectEventによるバックグラウンド監視

広告

Add_Changed イベントハンドラによるファイル監視

2. Add_Changedイベントハンドラによる監視

— LastWriteの二度読み問題の解決について

 FileSystemWatcherではファイルの書き込みがなされた時、
LastWriteを選択しているとイベント通知が発生するのですが、
この時、何故か通知が二度、発行されるという問題があります。

これを迂回するため、いろいろ試したのですが、
イベント発生時のファイル書き込み時間を取得、照合することで、
二度目のスクリプトブロック呼出しを回避するという返し技 ?を使うことで凌ぎました。

(ちなみに同期メソッドでは、EnableRaisingEventsプロパティが解除後、
自動的に$falseに戻るらしく、再読み込みは発生しません)

Add-Type -AssemblyName System.Windows.Forms | Out-Null

$frm= New-Object System.Windows.Forms.Form
$frm.WindowState = [Windows.Forms.FormWindowState]::Minimized
# $frm.ShowInTaskbar = $false

$wait= New-Object System.IO.FileSystemWatcher
$wait.SynchronizingObject= $frm

# $wait.InternalBufferSize= 8192 # [4096-8192-65535]
# $wait.IncludeSubdirectories = $false

$wait.NotifyFilter= [IO.NotifyFilters]::LastWrite
$wait.Path= “C:\必要なパス”
$wait.Filter= “*.txt”

[string]$lated_time= “”
[string]$chk_time= “”
[int]$i= 0

$wait.Add_Changed({ # Event

    $lated_time= (Get-Item $_.FullPath).LastWriteTime.ToString(‘yy/MM/dd HH:mm:ss’)

    if($lated_time -ne $chk_time){ # ここで二度目をキャンセル

        Write-Host (“`r`n”+ ‘no. ‘+ $i)
        $i++

        write-host (“change type: “+ $_.ChangeType)
        write-host (“full path: “+ $_.FullPath)
        write-host (“name: “+ $_.Name)
        write-host (“time: “+ $lated_time)

        $chk_time= $lated_time
    }
})

write-host “ファイル監視開始”
$wait.EnableRaisingEvents= $true # 開始
$frm.ShowDialog()

1. WaitForChangedメソッドによる監視
2. Add_Changedイベントハンドラによる監視
3. Register-ObjectEventによるバックグラウンド監視

Register-ObjectEventによるバックグラウンドファイル監視

3. Register-ObjectEventによるバックグラウンド監視

 イベントハンドラとの違いは、自動変数$Event.TimeGeneratedから、イベント発生時の時間を取得する点です。
Register-ObjectEventでは、多くの自動変数が発行されるので、
これを利用するのが最良と思われます。

$wait= New-Object System.IO.FileSystemWatcher

$wait.NotifyFilter= [IO.NotifyFilters]::LastWrite
$wait.Path= “C:\必要なパス”
$wait.Filter= “*.txt”

#バックグランドで稼働

Register-ObjectEvent -InputObject $wait -SourceIdentifier “mml_wch” -EventName “Changed” -Action{

    if($i -eq $null){ # 初期化

        [int]$i= 0
    }

    $t= $Event.TimeGenerated # 見やすくするため
    $f= $Event.SourceEventArgs

    [string]$lated_time= $t.ToString(‘yy/MM/dd HH:mm:ss.f’)

    if($lated_time -ne $chk_time){ # 出力

        Write-Host (“`r`n”+ ‘no. ‘+ $i)
        $i++

        write-host (“change type: “+ $f.ChangeType)
        write-host (“full path: “+ $f.FullPath)
        write-host (“name: “+ $f.Name)
        write-host (“time: “+ $lated_time)

        [string]$chk_time= $lated_time
    }
}

#確認する場合

Get-EventSubscriber

#削除する場合

# Unregister-Event -SourceIdentifier “mml_wch”

# 自動変数リスト ——–

     write-host (‘$Event: ‘+ $Event)
     # System.Management.Automation.PSEventArgs

     write-host (‘$EventSubscriber: ‘+ $EventSubscriber)
     # System.Management.Automation.PSEventSubscriber

     write-host (‘$Sender: ‘+ $Sender)
     # System.IO.FileSystemWatcher

     write-host (‘$SourceEventArgs: ‘+ $SourceEventArgs)
     # なし

     write-host (‘$SourceArgs: ‘+ $SourceArgs)
     # なし

     write-host (‘$Event.SourceArgs: ‘+ $Event.SourceArgs)
     # System.IO.FileSystemWatcher System.IO.FileSystemEventArgs

     write-host (‘$Event.SourceEventArgs: ‘+ $Event.SourceEventArgs)
     # System.IO.FileSystemEventArgs

# ——–

1. WaitForChangedメソッドによる監視
2. Add_Changedイベントハンドラによる監視
3. Register-ObjectEventによるバックグラウンド監視

古典調律の計算

古典調律の計算

 まず、セントと周波数の関係を計算式で表します。
 

□ 平均律eの周波数の計算の仕方

 eは、aから700セント(半音で7つ上)なので

a: 440 Hz
e: 440* 2^(700/1200)= 659.25511382573985947168352209311 Hz

win付属の電卓であれば、2 [x^y] ( 700 / 1200 ) * 440 と計算します

平均律と純正律
http://homepage1.nifty.com/musica/enharmonic.htm

 

 次に、古典調律の計算式を、順に書き記します。

□ ピタゴラス音律eのセント値の求め方

 aから3倍音が1oct上のeなので

a: 0 cent
e: 1200* log(440 *3/2 /440)/log2= 701.95500086538741774448673273738 cent

win付属の電卓では、( 3 / 2 ) [log] / 2 [log] * 1200 と計算します

Windows付属の電卓 – 関数電卓のlogについて – 数学 解決済 | 教えて!goo
http://oshiete.goo.ne.jp/qa/698762.html

 

□ ミーントーン(中全音律)のセント値の求め方

 1/4シントニックコンマ狭めるので、

a: 0 cent
e: 1200* log(440 *5^(1/4) /440)/log2= 696.57842846620870436109582884682 cent

win付属の電卓では、5 [x^y] ( 1 / 4 ) = [log] / 2 [log] * 1200 と計算。(途中に [=] を入れて、経過を出します)

ミーントーン – 中全音律 – Wikipedia
https://ja.wikipedia.org/wiki/%E4%B8%AD%E5%85%A8%E9%9F%B3%E5%BE%8B

 

□ キルンベルガー第3調律法のセント値

 基準ピッチが442Hzで計算、面倒になってきた、ここからgoogle計算機の力を借ります。
1200* log(442 *5^(1/4) /440) /log2 と入力して割り出しました

g: 1200* log(442 *(1/5^(2/4)) *2 *2 /440)/log2= 1 014.69456
d: 1200* log(442 *(1/5^(1/4)) *2 /440)/log2= 511.272987
a: 1200* log(442 /440) /log2= 7.85141504 cent
e: 1200* log(442 *5^(1/4) /440) /log2= 704.429844
b: 1200* log(442 *5^(1/4) *3/2 /2 /440) /log2= 206.384844

キルンベルガー第3法 – Wikipedia
https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%AB%E3%83%B3%E3%83%99%E3%83%AB%E3%82%AC%E3%83%BC%E7%AC%AC3%E6%B3%95

 

□ 聴感上の計算できない難しさについて

 調律の関係上、オクターブは整数倍関係が成り立つが、実際には必ずしも一致していない

例えば、弦楽器はインハーモニシティを考慮しなければならない。
ピアノの調律はレイルスバックデータに基づいて行うことが多いらしい。
中域はセントにずれはないが、低い音は、より低いセントへ、高い音は、より高いセントで、鳴らす必要がある

これは中域において倍音が、基音周波数の2倍値に比べ、わずかに高く出るため、1oct上の音が、それ以下であれば、不自然に聞こえるからではないか、と考えられる

インハーモニシティ現象について。 – 吹奏楽の講師で、チューバなどの… – Yahoo!知恵袋
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14128213414

なぜに調律は奥深い?|新堂隼人、ピアノ製作者のブログ in ドイツ
http://www.ameblo.jp/klavierbauer/entry-10585527453.html

PowerShellによるMMLファイル監視 – 非同期版

PowerShellによるMMLファイル監視 – 非同期版

 windows上のppmckやnsd.Libで使用するスクリプト非同期版です。
PowerShellによりmmlファイルの更新チェック機能を提供します。

もし、同期版の説明が必要であるならば、同期版を参考にして下さい。ライセンスについてもこちらで表示しています。

mmlファイルドロップで監視を始める点は同期版と同じですが、
できるだけバッチファイルを使用しない版で、総パワーシェル仕様です。
PowerShell2.0以降に対応します

 必要なのは、前回と同じく4つのスクリプトです。 powershellを呼び出すバッチファイル、mmlファイルのパスチェッカ、監視スクリプト本体、コンパイラとプレイヤーを呼び出すスクリプトです。
それとppmckのみ、set_envs.bat,mknsf.batをPowerShellスクリプトに置き変えたものを用意しました。

このうちのふたつ、powershellを呼び出すバッチファイルDrop.batと、mmlファイルパスチェッカchk_mml.ps1は、同期版とまったく同じものを使います。 このため非同期版は、監視スクリプトからの説明とします。

 それと、全てのスクリプトが入れてあるmml_watch.zipも置きました。 よろしければダウンロードしてみて下さい

注: mml_watchは、ver3bにアップデートしたため当該ファイルは、圧縮ファイル内の旧版ver1となります

 


 

□ mml_watch.ps1 – 非同期処理のファイル監視スクリプト 
 では非同期処理のファイル監視スクリプト、mml_watch.ps1から説明を始めます。

 基本的に挙動は同期版と同じですが、主にファイル変更の判定をイベントハンドラでしている点、try catchを使用している点に違いがあります。

エラーcatch時には、pauseの代わりとなるRead-Host “—” | Out-Nullでスクロールを止めるようにしています。 あと、$Argsをわざわざ$Args_pathにコピーしているのは、再ループ時に$Argsが書き換えられるためです

mml_watch.ps1

— ppmck,nsd共通

$ErrorActionPreference = “Stop”
try{

$Args_path = $Args # $Args overwrite after

.\nsf_trans.ps1 $Args_path[0] # Command

while(1){

    Add-Type -AssemblyName System.Windows.Forms | Out-Null
    $m = New-Object System.Windows.Forms.Form
    $m.WindowState = [System.Windows.Forms.FormWindowState]::Minimized
    $m.ShowInTaskbar = $false

    $w = New-Object System.IO.FileSystemWatcher
    $w.Path = $Args_path[1]
    $w.Filter = $Args_path[2]
    $w.NotifyFilter = [System.IO.NotifyFilters]::LastWrite
    $w.SynchronizingObject = $m

    $w.add_Changed({ # イベント

        Write-Host ($_.Name+ ” MODIFY`r`n”)

        .\nsf_trans.ps1 $Args_path[0] # Command

        $w.EnableRaisingEvents = $false # 終了
        $m.Dispose()
    })

    Write-Host “”
    Write-Host “Setting up watches.”
    Write-Host “Watches established.`r`n”

    $w.EnableRaisingEvents = $true # 開始
    [void]$m.ShowDialog()

} #
}
catch [Exception]{ #err_all
    Write-Host $_.exception
    Read-Host “続けるにはENTERキーを押して下さい” | Out-Null
}

 注: こちらは旧版の説明です。好ましくない点があり、参考にならないかもしれません。非同期イベントハンドラについては、 Add_Changed イベントハンドラによるファイル監視 を参照することをお勧めします。

 

参考url

 


 

□ nsf_trans.ps1 – mmlコンパイラとプレイヤーを呼び出すスクリプト 
 mmlコンパイラとプレイヤーを呼び出すスクリプトnsf_trans.ps1です。
空白のあるファイルパスに対応しています

 パワーシェルはパスの扱いで、いくつかの注意点があったのでそれを説明します。
PowerShellスクリプト間やシェルのコマンドに送るのであれば、パラメータをオブジェクトとして送っているらしく、ファイルパス名を ” で挟む必要ありません。
これとは違い、実行ファイルのnsc、nsfplay,VirtuaNSFへファイル名を送る時には文字列としているようです。 このため、”`””このようにダブルバックスラッシュをエスケープしたものをつかって、ファイルパス名を囲って対応しました

 & $exe_nsc -n -e $mml | Write-Hostについて。
$exe_nsc= “..\bin\nsc.exe”として実行ファイルを変数オブジェクト化した場合、単に$exe_nscと書き込んだだけでは、コマンドとして認識しません。 コマンド化したい場合は、実行演算子&をつけます。
また、nscのパラメータ -n -eは、オブジェクト内に入れると、上手く実行できないので外に置いてます。
そして次にくる$mmlは上記のとおり、”`””で囲った文字列として送り出しています。
最後の | Write-Hostはコンソール出力するためのものです。 そのままだと、mml_watch.ps1で呼び込んだフォームオブジェクト側に出力されるためか、コンソール側にnscから出力がきません。 パイプを経由して、nscの出力をコンソールへ読み込んでいます。

 function化について。
function err_chk($ErrLev)としたのは、メッセージ出力をできるだけ上へ置くためです。このほうが、最終的に何を行うのか把握しやすかったりします

 なお、前回と同じく、プレイヤー呼び出す当スクリプトでは、2行だけ環境に合わせて修正をする必要があります。
$exe_path に記述した、プレイヤーまでのファイルパスを的確に記述して下さい。
nsfplay,VirtuaNSFの両プレイヤーは、$exe_pathに記述したコメント記号 # の付け外しによって、選択される形となります

nsf_trans.ps1

— ppmck,nsd共通

cd (Split-Path -Parent $MyInvocation.MyCommand.Path)

#$exe_player= “..\..\nsfplay\nsfplay.exe”
$exe_player= “..\..\VirtuaNSF\VirtuaNSF.exe”

$exe_nsc= “..\bin\nsc.exe”

function err_chk($ErrLev){

    Write-Host “”
    Write-Host (“exitcode :”+ $ErrLev)

    if($ErrLev -ne 0){
        Write-Host “”
        Write-Host “// NSFfile: failure !//”
    }else{

        start $exe_player $nsf
    }
} #func

$nsf= “`””+ $Args[0]+ “.nsf`”” # esc[`”]
$mml= “`””+ $Args[0]+ “.mml`””

if((Test-Path .\mck_script\mknsf.ps1) -eq $true){ # ppmck chk

    .\mck_script\mknsf.ps1 $Args[0] | Write-Host # Command
}else{

    & $exe_nsc -n -e $mml | Write-Host # Command
}

err_chk($LASTEXITCODE)

参考url

 以上の3つのスクリプトをbinと同階層になるように、mck\mml_watch_hi, nsd\mml_watch_hi のような、単一フォルダに全て入れて下さい。
次に、ppmckのみ必要になるスクリプト、mknsf.ps1について説明します

 


 

□ mknsf.ps1 – set_envs.batとmknsf.batをPowerShellで再記述 
 set_envs.batとmknsf.batをPowerShellで書き直したmknsf.ps1を準備します。

このスクリプトはppmckのみに使用します。
以下のフォルダmck\mml_watch_hi\mck_scriptに置いて下さい。
このスクリプト.\mck_script\mknsf.ps1の有無により、上位スクリプトnsf_trans.ps1がppmck,nsd.Libを切り換えています

 簡単ではありますが、順に内容の説明をします。
$Env:は環境変数のセットです。DOSのsetコマンドと同義です。
move -force はパラメータを付けて移動上書きをしています。
DOSのMOVE /Yと同じです。
最後の行の、exit $LASTEXITCODEは、上位スクリプトに
エラーレベルを返すことを意味してます

mknsf.ps1

— ppmck

$Env:PPMCK_BASEDIR = “..”
$Env:NES_INCLUDE = $Env:PPMCK_BASEDIR+ “\nes_include”
$Env:DMC_INCLUDE = [System.IO.Path]::GetDirectoryName($Args[0])

$exe_ppmckc= $Env:PPMCK_BASEDIR+ “\bin\ppmckc.exe”
$exe_nesasm= $Env:PPMCK_BASEDIR+ “\bin\nesasm.exe”

$mml= “`””+ $Args[0]+ “.mml`””
$nsf= $Args[0]+ “.nsf” # shell only

if((Test-Path .\effect.h) -eq $true){ del .\effect.h }
& $exe_ppmckc -i $mml # Command

if($? -eq $true){

    if((Test-Path .\ppmck.nes) -eq $true){ del .\ppmck.nes }
    & $exe_nesasm -s -raw ppmck.asm # Command

    if($? -eq $true){

        move -force .\ppmck.nes $nsf
    }
}

exit $LASTEXITCODE

参考url

 これで必要なスクリプトが揃いました。 ここからは、監視スクリプトのテストをします。

 


 

□ nsf_trans.ps1 – 変換スクリプトのテスト 
 変換スクリプトのテスト手順です。

まず、mck\mml_watch_hi と、nsd\mml_watch_hi のフォルダにそれぞれに対応したsample.mml などを置きます。

各フォルダ上でコマンドプロンプトを立ち上げ、長いワンライナーで申し訳ありませんが、以下のコマンドを打って、順に確認してください。 ファイル名であるsampleを引数として、パワーシェルスクリプトをRemoteSignedポリシーで実行するというコマンドです

> powershell -ExecutionPolicy RemoteSigned -File nsf_trans.ps1 sample

 無事nsfファイルが出力され、滞りなくプレイヤーから再生されたら、テストはokです。

  うまくコンパイルできないケースについて。

・スクリプトの置く場所が間違っている可能性があります。
 binのあるフォルダ階層と同じ、1階層下へ置き直してみて下さい。

・ないし、ppmck, nsd.Libの切り換えミスも考えられるので、mck_scriptフォルダ、
 mknsf.ps1の有無を確認します。

・nsd.Libから、../../bin/nsd.bin: No such file or directory などと返される場合は、
 MMLの記述を、#Code “../bin/nsd.bin”のように変更をお願いします。
 binと同じ階層、1階層下であるスクリプトのディレクトリがカレントとなっているためです。

・プレイヤーが起動しないのであれば、nsf_trans.ps1に書き込んだ
 プレイヤーパスの記述が間違っているかもしれません

 もし、ここまでうまくいっているようなら、残りのテストは一つのみです。

 

□ Drop.bat – 監視スクリプトの起動テスト 
 監視スクリプトの起動テストを行います。

Drop.batにsample.mml をドロップすると
コマンドプロンプトが立ち上がりファイル監視を始めるはずです。
エディタなどでsample.mml を開き、a>cf など入力して再保存すれば、即座に反映すると思います。

 なお、Ctrl+C での終了はできないので、監視をやめたい時はウィンドウを閉じて下さい

 最後にワンポイントです。Drop.batのショートカットをつくっておくと、ちょっとだけ幸せになれるかもしれません、

 

□ 所感として 
 パス取得において、少しだけ気になったこと。

 ppmckは、1階層下のmck\songsで運用することを前提に構成されているようなのですが、nsd.Libには、もともとsongsフォルダらしきものがないので、各々の環境はまちまちのようです。

もし、nsd.Libで見受けられる2階層下側で運用する場合は、パスを適切に修正すれば一応動くとは思います。
nsd.Libでは、nsf_trans.ps1の$exe_nsc= “..\bin\nsc.exe”、
ppmckであれば、mknsf.ps1の$Env:PPMCK_BASEDIR = “..”、が直すべき部分になると思います

 ただ、階層が深くなるとその分、mmlファイルやスクリプト側のパス記述が増えることもあり、実行ファイルとスクリプトは、できるなら直近に置くのがベストな気がしてます。
mck\mml_watch_hi やnsd\watch_hi のような1階層下のフォルダに、スクリプトをアサインしたのはこの様な理由のためです。

パス取得で苦心したためか、できるだけ仕様が統一されているとありがたいなあとなんとなく思った次第です
 


 
□ 謝辞 
 参考リンクという形ばかりではありますが、今回のPowerShellをつくるにあたり、多くのサンプルと解説を参考にさせていただきました。 この場を借りてお礼を申し上げます

PowerShellによるMMLファイル監視 – 同期版

PowerShellによるMMLファイル監視 – 同期版

 windows上のppmckやnsd.Libで使用するPowerShellスクリプトをつくりました。
PowerShellを使ったmmlファイル更新チェッカとして機能するものです。

ppmckとnsd.Libの著作権については、以下のとおりです

— ppmck
ライセンス形態–GPLライセンス?で運用、以下は著作権表示となります。

nesasm: NES assembler J.H.Van Ornum,David Michel,Dave Shadoff,Charles Doty様
mck: NES Sound Driver Izumi様
mckc: mck用mmlコンバータ Manbow-J様
pmck/pmckc: mck/mckc拡張版 boukichi様
ppmck: mck/mckc改良版 h7様

— nsd.Lib
ライセンス形態–FreeBSDライセンス(2条項BSD)著作権はS.W.様となります

 mmlファイルをドロップすると監視を始め、mmlファイルがエディタで保存されたら、
即時にコンパイルしてプレイヤーで再生までを自動化するスクリプトです。
linuxでのmmlファイル監視をwindowsでもできたら..と思いつつ組みました。

確認はXPのみ。以降のOSでも多分問題なく動くはずです

 ファイル監視に、PowerShellを使います。
win 7以降では、標準でインストール済みのものです。このPowerShellスクリプトをふたつつくります。それとふたつバッチファイルが必要です。
ひとつは、PowerShellを呼び出すバッチファイル、もう一つはコンパイラとプレイヤーへ送出するためのものです。
及びppmckのバッチファイル、set_envs.batと、mknsf.batを空白パスに対応したものを用意しました

もし試して頂けるのであれば、全てのスクリプトがあるmml_watch.zipを置きました。よろしければ、ダウンロードしてみて下さい

注: mml_watchは、ver3bにアップデートしたため当該ファイルは、圧縮ファイル内の旧版ver1となります

 なおこの監視スクリプトは、バッチファイルを主体として組んだものとなってます。
もし、パワーシェル仕様の非同期処理版にも興味があるならば非同期版を見てみて下さい

 

□ vistaXP – PowerShellのインストール 
 ではまず手始めとして、vistaXPであれば、PowerShellを入れなければ何もできません。

パワーシェルは、更新ファイルを入手することでインストールできます。
実行環境はPowerShell 2.0から動くので、XPsp3向け2.0のリンクを貼りますが、適時自分の環境に合わせて選択してください

 ここからは本題の、4つのスクリプトを順に載せていきます。
Powershellを使ったファイル監視スクリプトの説明及び、その使用法です

 


 

□ Drop.bat – PowerShellを呼び出すバッチ 
 PowerShellを呼び出すバッチファイルDrop.batをまず用意します。
拡張子ps1は、ファイルドロップができないのとポリシーの設定があるため、このバッチファイルから呼び出します。

フィルドロップのケースでは、プロファイルフォルダにカレントが残るので、
まず、cd /d %~dp0を打ち、スクリプト自身のフォルダにカレントディレクトリを移動、
PowerShellを走らせるため、プロセスのみポリシーに実行権限を付与する、という内容を行ってます

Drop.bat

— ppmck,nsd共通

@rem Drop.bat
@echo on

cd /d %~dp0
powershell -ExecutionPolicy RemoteSigned -File .\chk_mml.ps1 “%~f1”

参考url

 


 

□ chk_mml.ps1 – PowerShellによるファイルパスチェック 
 PowerShellによるファイルパスチェックスクリプトchk_mml.ps1を用意します。
ファイルの存在を確認し、必要となるパス情報をここで集めてます

chk_mml.ps1

— ppmck,nsd共通

function err_out($num){
    switch($num){
    1{ echo “//パラメータ数があわない//`r`n” }
    2{ echo “//ファイル指定がない//`r`n” }
    3{ echo (“//”+ $f+ “ファイルが見つからない//`r`n”) }
    } #sw
    Read-Host “続けるにはENTERキーを押して下さい” | Out-Null
} #func

if($args.Length -ne 1){ # args chk
    err_out 1
}else{

    if($Args[0] -eq “”){ # path chk
        err_out 2
    }else{

        $p= [System.IO.Path]::GetDirectoryName($Args[0])
        $n= [System.IO.Path]::GetFileNameWithoutExtension($Args[0])
        $f= $n+ “.mml”

        echo “”
        echo (“Path :”+ $p)
        echo (“File :”+ $f+ “`r`n”)

        if((Test-Path ($p+ “\”+ $f)) -eq $false){ # file chk
            err_out 3
        }else{

            .$dpn= $p+ “\”+ $n
            .\mml_watch.ps1 $dpn $p $f
        }
    }
}

参考url

 


 

□ mml_watch.ps1 – PowerShellの監視スクリプト 
 PowerShellの監視スクリプトmml_watch.ps1を用意します。同期処理版です

必要となるパス情報を受け付けたら後、繰り返しファイル変更を監視し、随時バッチファイルを実行する、という内容です

mml_watch.ps1

— ppmck,nsd共通

$Args_path = $Args

$w = New-Object System.IO.FileSystemWatcher
$w.Path = $Args_path[1]
$w.Filter = $Args_path[2]
$w.NotifyFilter = [System.IO.NotifyFilters]::LastWrite

while(1){
    .\nsf_trans.bat $Args_path[0] # Command

    echo “”
    echo “Setting up watches.”
    echo “Watches established.`r`n”

    $changeResult = $w.WaitForChanged([System.IO.WatcherChangeTypes]::Changed)
    echo ($changeResult.Name+ ” MODIFY`r`n”)

} #

 注: 同期メソッドについては、 WaitForChangedメソッドによる監視 も参考にしてみて下さい。

参考url

 


 

□ nsf_trans.bat – mmlコンパイラとプレイヤーを呼び出す変換バッチ 
 mmlコンパイラとプレイヤーを呼び出す変換バッチファイルnsf_trans.batを用意します。if elseだとうまくエラーレベルが取得できなかったため、ラベルとgoto文での記述となってます。

 コンパイラを呼出し後、別プロセスでプレイヤーを演奏するという中身のため、
当バッチファイルのみ、2行だけ環境に合わせて、プレイヤーパスを記述し直す必要があります。

このため、set exe_pathに記述してある、プレイヤーのパスを的確に指定して下さい。
空白のあるファイルパスにも対応します。ただしsetコマンドの仕様上、= 以降は、不必要な空白を入れないように気をつけて下さい。

相対パス指定であれば、スクリプトのあるフォルダを起点とします。
Forコマンドで絶対パスに変換されるとき、スクリプトのあるディレクトリが起点になるためです。

凡例にある..\はカレントディレクトリから一つ上へあがるという意味なので..\..\VirtuaNSF\VirtuaNSFであれば、2つ上の階層へあがりVirtuaNSFフォルダにあるVirtuaNSFを呼び出すことを表しています
再生プレイヤーとしてnsfplayとVirtuaNSFを記載しましたので、
@remの付け外しにより、どちらかを選択して下さい

nsf_trans.bat

— ppmck,nsd共通

@rem nsf_trans.bat
@echo off

cd /d %~dp0

@rem set exe_player=”..\..\nsfplay\nsfplay.exe”
set exe_player=”..\..\VirtuaNSF\VirtuaNSF.exe”

set exe_nsc=”..\bin\nsc.exe”

if not exist .\mck_script\mknsf.bat goto nsd

call .\mck_script\mknsf.bat %1
goto mck
:nsd

for %%I in (%exe_nsc%) do set nsc_path=%%~dpI
cd %nsc_path%

for %%I in (%exe_nsc%) do set nsc_name=%%~nxI
%nsc_name% -n -e “%~1.mml”
:mck

echo.
echo errorlevel :%errorlevel%
if errorlevel 1 goto err

for %%I in (%exe_player%) do set ply_path=%%~dpI
cd %ply_path%

for %%I in (%exe_player%) do set ply_name=%%~nxI
start %ply_name% “%~1.nsf”

goto fin
:err

echo.
echo // NSFfile: failure !//
:fin

参考url

 以上、4つのスクリプトを、ppmck,nsd.Libのbinと同じ階層となる、mck\mml_watch, nsd\mml_watch のような単一フォルダに全て入れます。
次に、ppmckのみ必要になる、修正済みバッチファイルを説明します。

 


 

□ mknsf.bat – set_envs.batとmknsf.batを単体化 
 set_envs.batとmknsf.batを単体化し、mmlファイルパス上に空白があっても、稼働できるようにしたものです。このバッチファイルmknsf.batを、mck\mml_watch\mck_script下に置きます。

 ppmck,nsd.Libを切り換えは、先ほど説明した上位スクリプトnsf_trans.batにより、
このバッチファイル.\mck_script\mknsf.batの有無をチェックすることで判断しています。このため、ppmck側のmck\mml_watchのみに、置く必要があります

 まず、set_envs.bat側の修正点を説明します。
DMC_INCLUDEを有効にし、mmlファイルのあるパスを、この環境変数に代入するようにしました。
DMC_INCLUDEはこの後、mmlファイルに書かれた相対パスが組み込まれると思われ、ファイルパス名を ” で挟まず、最後の \ を取り去ることでdmcが読み込めるようになりました

 続いてmknsf.bat側の修正点です。
空白のあるパス対策にダブルバックスラッシュでファイルパスを囲った点、ファイル移動を追加した点と、errorlevelを返すように変更した点が主な修正ポイントです。
このファイルの最後に書かれた、exit /b %errorlevel%は、上位スクリプトにエラーレベルの出力を返すことを意味します

mknsf.bat

— ppmck

@rem set_envs.bat ———————

set PPMCK_BASEDIR=..
set NES_INCLUDE=%PPMCK_BASEDIR%\nes_include

set DMC_INCLUDE=%~dp1
set DMC_INCLUDE=%DMC_INCLUDE:~0,-1%

@rem mknsf.bat ————————

if not exist .\effect.h goto compile
del .\effect.h
:compile

%PPMCK_BASEDIR%\bin\ppmckc -i “%~1.mml”

if not exist .\effect.h goto err
if not exist .\ppmck.nes goto assemble
del .\ppmck.nes
:assemble

%PPMCK_BASEDIR%\bin\nesasm -s -raw ppmck.asm

if not exist .\ppmck.nes goto err

move /y .\ppmck.nes “%~1.nsf”
:err

exit /b %errorlevel%

参考url

 これで全ての準備が整いました。ここからは、監視スクリプトを順にテストします。

 


 

□ nsf_trans.bat – 変換バッチファイルのテスト 
 変換バッチファイルのテストをまず行います。

まず、mck\mml_watch と、nsd\mml_watch のフォルダに、それぞれに対応したsample.mml を置きます。
各フォルダ上でコマンドプロンプトを立ち上げ、以下のワンライナーを打って、順に確認してみて下さい

 > nsf_trans.bat sample

 無事nsfファイルが出力され、滞りなくプレイヤーが再生したらテストは終了です。
 もし、コンパイルされないのであれば、以下のケースをチェックしてみてください。

・スクリプトを置く場所が間違っている、つまりbinが置いてあるフォルダと同じ階層にmml_watchフォルダがないため、mmlコンパイラが呼び出せない。

・もしく、ppmckに必要な.\mck_script\mknsf.batがないため認識できない、
 逆に.\mck_script\mknsf.batがあるため、nsd.Libと認識できないなどの理由も考えられます。mck_scriptフォルダ、mknsf.batの存在を確認してみて下さい。

・nsd.Libから、../../nsd.bin: No such file or directory などと返される場合は、
 MMLの記述を、#Code “../bin/nsd.bin”のように変更してください。カレントからの相対パスとして見えるようになります。

・プレイヤーが自動起動しないのであれば、恐らくnsf_trans.batのプレイヤーパスの記述が間違っている可能性があります

  ここまでの手順が無事、終わったなら残りはわずかです。

 

□ Drop.bat – 監視スクリプトの起動 
 監視スクリプトの起動テストをします。

Drop.batにsample.mml をドロップしてみて下さい。
コマンドプロンプトが立ち上がりファイル監視を始めると思います。
エディタなどでsample.mml を開き、a>cf などとmmlを入力して再保存すれば、即座に反映するはずです。
監視をやめたい時はウィンドウを閉じるのみでokです

 ちなみに、mml_watchフォルダ上で起動したコマンドプロンプト上でも、
>drop sample とコマンドすることで、同様の監視が始まります。

もしどうしても、コマンドプロンプト上で終了処理したいのであれば、まずCtrl+C の後、再度、sample.mml をエディタで保存してみて下さい。
すると、シェルのwaitが外れてバッチ ジョブを終了しますか (Y/N)?と返してきます

 最後に使用する上でのワンポイントです。 Drop.batのショートカットをつくっておくと良いかもしれません。このショートカットにドロップするだけでも、ファイル監視が始められるからです

 

□ 注意点として 
 現在わかっている注意点をふたつばかり上げておきます。

 空白が入るパスであっても試聴ができ、運用も可能ではありますが、nsd.Libのヘルプを見る限りでは、厳密にはファイルパスに空白を入れないことを推奨しているようです。
空白が入りずらくなるよう、コンパイラとプレイヤーの近くにmmlファイルを置いて運用するのが望ましいと思います

 また、非力なマシンの場合のみですが、nsdとNSFPlayの組合せにおいて、演奏をかけたまま即時MMLコンパイルするつかの間、再生しているプレイヤーからノイズのようなぶちぶち音が出ることがわかってます。
この症状が出るケースでは、瞬間的にCPUの処理能力を使いきったとも考えられるため、もし気になるようであれば、NSFPlayの再生周波数を一時的に下げるなどの対処によって改善してみて下さい

FONTCONFIG WARNING エラーへの対応

Fontconfig warning エラーへの対応

 knoppixで、コンソール上からGUIアプリケーション呼び出しをすると、
Fontconfig warning のエラーが以下のように返される

Fontconfig warning: “/etc/fonts/conf.d/50-user.conf”, line 9: reading configurations from ~/.fonts.conf is deprecated.

Fontconfig warning: “/etc/fonts/conf.d/69-language-selector-ja-jp.conf”, line 126: Having multiple values in isn’t supported and may not work as expected



 それぞれの修正点を順に説明します。

/// 50-user.confのwarning対策

 ~/.fonts.conf is deprecated.と返しているため、
ファイルの場所を移動させます。

移動先の確認のため、環境変数 XDG_CONFIG_HOME のチェックします。

$ printenv | more
XDG_CONFIG_HOME=/home/knoppix/.config

この移動先に必要となる fontconfig ディレクトリを生成します。

$ cd /home/knoppix/.config
$ mkdir fontconfig

.fonts.conf ファイルを新しく用意したディレクトリに移動します。

元の場所
/home/knoppix/.fonts.conf
移動先
/home/knoppix/.config/fontconfig/.fonts.conf

ついでに、フォント表示がひどくならないよう、
ビットマップフォントを抑制する目的で、以下を .fonts.conf 内に追加しておきます。

  <match target="font" >
      <edit mode="assign" name="embeddedbitmap">
          <bool>false</bool>
      </edit>
  </match>

 この後、 設定から ルックアンドフィールを設定の フォントタブを選択して、
ヒンディングのスタイルを微小などに変更すると綺麗なフォント表示になります。


/// 69-language-selector-ja-jp.confのwarning対策

 Having multiple values in <test> isn’t supported
複数記述が問題になっています。

/etc/fonts/conf.avail/69-language-selector-ja-jp.conf
上記ファイルをルート権限を使い、エディタなどで開きます。

このような記述になっている部分があるはずなので、

  <match target="font">
      <test name="family" compare="contains">
          <string>IPA Pゴシック</string>
          <string>IPA P明朝</string>
          ...
          ...

これを以下のように修正していけば上手くいくと思います。

  <match target="font">
      <test name="family" compare="contains">
          <string>IPA Pゴシック</string>
      </test>
      <test name="family" compare="contains">
          <string>IPA P明朝</string>
      </test>
      ...
      ...


/// 参考url