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は、ver2bにアップデートしたため当該ファイルは、圧縮ファイル内の旧版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
}

参考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は、ver2bにアップデートしたため当該ファイルは、圧縮ファイル内の旧版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”)

} #

参考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の再生周波数を一時的に下げるなどの対処によって改善してみて下さい