auto_rec_rename.jsをバッチファイルに埋め込む

前の関連記事:SoX(Sound eXchange)で音声感知録音:その2


jsファイルはバッチファイルと違ってコマンドウィンドウからではcscript.exeの引数で指定して起動しないといけません。一定の長さより短い音声ファイルを削除するバッチファイルも作るのでそれにauto_rec_rename.jsも埋め込んでしまいます。

一定の長さより短い音声ファイルを削除するバッチファイルsht_f_del.bat

rem 長さが一定秒以下の音声ファイルを削除する
@echo off
rem sox.exeへのパスの設定。(Windows7 64bitの場合)
path %PATH%;C:\Program Files (x86)\sox-14-4-2
set AUDIODRIVER=waveaudio
rem 削除するファイルの秒数の設定(秒)。
set SEC=3
rem 削除対象ファイルの拡張子の設定。
set EXT=mp3
rem 削除対象ファイルのあるフォルダの設定。
set FLDR=%CD%\sox_data\renamed
echo 長さ%SEC%秒以下の%EXT%ファイルを%FLDR%から削除しています。
cd %FLDR%
setlocal enabledelayedexpansion
for %%f in ("*.%EXT%") do (
  for /F "tokens=1 delims=." %%t in ('sox --i -D %%f') do set T=%%t
  if !T! LEQ %SEC% del /q %%f
)
endlocal
これをsht_f_del.batとして実行すると削除対象ファイルのあるフォルダの設定で設定されたフォルダにある長さ3秒より短いmp3ファイルが削除されます。

長さの測定できないmp3ファイルも削除してくれます。

sox WARN mp3-util: MAD lost sync

このエラーがたくさんでてきますが動作に支障はないようです。

16行目のdoのあとの入れ子の丸括弧は^でエスケープしなくても問題ありませんでした。

SoX(Sound eXchange)で音声感知録音:その2のauto_rec.batのfor分のinの中の入れ子の丸括弧はエスケープが必要でしたが、doの中の丸括弧はエスケープする必要はないようです。(それがわからなくて次の記事で苦労しました。)

vadエフェクトで話し声の検出ができるかと期待しましたが物音との鑑別はできませんでした。

sht_f_del.batにauto_rec_rename.jsを埋め込む


バッチファイル:JScriptを埋め込んでDOSコマンドと変数をやりとりするでやったようにsht_f_del.batにauto_rec_rename.jsを埋め込んでしまいます。
@if(0)==(0) ECHO OFF
rem sox.exeへのパスの設定。(WindowsXPの場合)
path %PATH%;C:\Program Files\sox-14-4-2
set AUDIODRIVER=waveaudio
rem 処理対象ファイルの拡張子の設定。
set EXT=mp3
rem データディレクトリ名。
set DATA_DIR=sox_data
rem 改名後のデータをいれるディレクトリ名。
set RENAMED_DIR=renamed
rem この秒数より短い長さの音声ファイルは削除する(秒)。
set SEC=3
rem 削除対象ファイルのあるフォルダの生成。
set FLDR=%CD%\%DATA_DIR%\%RENAMED_DIR%
echo %DATA_DIR%フォルダにある%EXT%ファイルを改名して%RENAMED_DIR%フォルダに移動させています。
cscript.exe //nologo //E:JScript "%~f0"
echo %SEC%秒より短い%EXT%ファイルを削除しています。
cd %FLDR%
setlocal enabledelayedexpansion
for %%f in ("*.%EXT%") do (
  for /F "tokens=1 delims=." %%t in ('sox --i -D %%f') do set T=%%t
  if !T! LEQ %SEC% del /q %%f
)
endlocal
GOTO :EOF
@end
var sh = new ActiveXObject("WScript.Shell");
var ext = sh.ExpandEnvironmentStrings("%EXT%");//改名対象拡張子。
var data_dir = sh.ExpandEnvironmentStrings("%DATA_DIR%");//データディレクトリ名。
var renamed_dir = sh.ExpandEnvironmentStrings("%RENAMED_DIR%");//改名後のデータをいれるディレクトリ名。
var fso = new ActiveXObject("Scripting.FileSystemObject");
var s_path = String(WScript.ScriptFullName).replace(WScript.ScriptName, "");//このスクリプトがあるフォルダのパスを取得。
var fldr = fso.GetFolder(s_path + data_dir); //データフォルダオブジェクトの取得。
var fc = new Enumerator(fldr.Files); //ファイルコレクションをEnumeratorオブジェクトにして取得。
var f, new_name;
var f_arr = [];//処理対象ファイルオブジェクトを格納する配列。
//RegExpオブジェクトを作成。
var re = new RegExp("^(\\d{4})(\\d{2})(\\d{2})_(\\d{2})(\\d{2})(\\d{2})_(\\d+)_(\\d+)\\." + ext + "$");
renamed_dir = s_path + data_dir + "\\" + renamed_dir;//改名後のデータを入れるディレクトリのフルパス。
if (!fso.FolderExists(renamed_dir)){
    fso.CreateFolder(renamed_dir);//改名後のデータをいれるディレクトリがないときは作成する。
}
//ファイルコレクションの各ファイルに対して。
for (; !fc.atEnd() ; fc.moveNext()) {
    f = fc.item(); //ファイルオブジェクトの取得。
    //ファイル名の判別
    if (re.test(f.Name)) {
        f_arr.push(f);//処理対象となるファイルオブジェクトを配列に格納。ファイル名昇順に取得できているはず。
    } else {
        f.Delete();//処理対象とならないファイルは削除。
    }
}
for (var i = 0; i < f_arr.length - 1 ; i++) {
    f = f_arr[i];//配列からファイルオブジェクトを取得。最終要素は処理しない。
    new_name = new_fname(re.exec(f.Name));//正規表現結果配列からファイル名を取得。
    try {
        f.Move(renamed_dir + "\\" + new_name[0] + "." + ext)//「年月日_時分-年月日_時分」と改名して移動。
    } catch (e) {
        f.Move(renamed_dir + "\\" + new_name[1] + "." + ext)//「年月日_時分秒-年月日_時分秒」と改名して移動。
    } 
}
//正規表現結果配列から新しいファイル名を返す関数。戻り値は配列[年月日_時分-年月日_時分, 年月日_時分秒-年月日_時分秒]。
function new_fname(r) {
    //ファイル名から記録開始日時のDateオブジェクトを得る。1月を0として開始。
    var start_dt = new Date(r[1], r[2] - 1, r[3], r[4], r[5], r[6]);
    var int_sec = r[7] * 1000; //記録区間長(ミリ秒)
    var int_cnt = r[8]; //記録区間番号
    var start_ms = start_dt.getTime() + int_sec * (int_cnt - 1); //区間開始日時経過ミリ秒
    //経過ミリ秒を数字羅列に変換
    var end_n = date_num(start_ms + int_sec);//区間開始日時。
    var start_n = date_num(start_ms);//区間終了日時。
    var hhmm = start_n[0] + "-" + end_n[0];//新しいファイル名年月日_時分-年月日_時分。
    var hhmmss = start_n[0] + start_n[1] + "-" + end_n[0] + end_n[1];//新しいファイル名年月日_時分秒-年月日_時分秒。
    return [hhmm, hhmmss];
    //経過ミリ秒を年月日の数字羅列に変換する関数。戻り値は配列[年月日_時分, 秒]。
    function date_num(ms) {
        var dt = new Date();//Dateオブジェクトの生成。
        dt.setTime(ms);//経過ミリ秒からDateオブジェクトを取得。
        return [dt.getFullYear() + fm(dt.getMonth() + 1) + fm(dt.getDate()) + "_" + fm(dt.getHours()) + fm(dt.getMinutes()), fm(dt.getSeconds())];
        function fm(m) {
            return ("0" + m).slice(-2);//固定長2桁を返す。
        }
    }
}
バッチファイルとして起動して16行目で自分自身を今度はWSH JScriptファイルとして呼び出しています。

WSH JScriptファイルとして読み込まれたときは@if ステートメントにより@if(0)がfalseと判定されて@endまでは無視されます。

ということで27行目からWSH JScriptとして実行されることになります。

バッチファイルで設定した環境変数を28行目、29行目、30行目でWSH JScriptに引き渡しています。

WSH JScriptの部分が終了すると17行目からまたバッチファイルが始まって25行目で終了します。

長さをチェックしたファイルを他のフォルダに移動させる処理を組み込む

@if(0)==(0) ECHO OFF
rem sox.exeへのパスの設定。(WindowsXPの場合)
path %PATH%;C:\Program Files\sox-14-4-2
set AUDIODRIVER=waveaudio
rem 処理対象ファイルの拡張子の設定。
set EXT=mp3
rem データディレクトリ名。
set DATA_DIR=sox_data
rem 改名後のデータをいれるディレクトリ名。
set RENAMED_DIR=renamed
rem 処理後のファイルの移動先ディレクトリ名。
set EXTRACTED_DIR=extracted
rem この秒数より短い長さの音声ファイルは削除する(秒)。
set SEC=3
rem 削除対象ファイルのあるディレクトリフルパスの生成。
set FLDR=%CD%\%DATA_DIR%\%RENAMED_DIR%
rem 短いファイルを削除後残ったファイルの移動先ディレクトリのフルパス。
set EXTRACTED=%CD%\%DATA_DIR%\%EXTRACTED_DIR%
if not exist "%EXTRACTED%" (mkdir "%EXTRACTED%")
echo %DATA_DIR%フォルダにある%EXT%ファイルを改名して%RENAMED_DIR%フォルダに移動させています。
cscript.exe //nologo //E:JScript "%~f0"
echo %SEC%秒より短い%EXT%ファイルを削除しています。
cd %FLDR%
setlocal enabledelayedexpansion
for %%f in ("*.%EXT%") do (
  for /F "tokens=1 delims=." %%t in ('sox --i -D %%f') do set T=%%t
  if !T! LEQ %SEC% del /q %%f
)
endlocal
move /Y *.%EXT% "%EXTRACTED%"
GOTO :EOF
@end
var sh = new ActiveXObject("WScript.Shell");
var ext = sh.ExpandEnvironmentStrings("%EXT%");//改名対象拡張子。
var data_dir = sh.ExpandEnvironmentStrings("%DATA_DIR%");//データディレクトリ名。
var renamed_dir = sh.ExpandEnvironmentStrings("%RENAMED_DIR%");//改名後のデータをいれるディレクトリ名。
var fso = new ActiveXObject("Scripting.FileSystemObject");
var s_path = String(WScript.ScriptFullName).replace(WScript.ScriptName, "");//このスクリプトがあるフォルダのパスを取得。
var fldr = fso.GetFolder(s_path + data_dir); //データフォルダオブジェクトの取得。
var fc = new Enumerator(fldr.Files); //ファイルコレクションをEnumeratorオブジェクトにして取得。
var f, new_name;
var f_arr = [];//処理対象ファイルオブジェクトを格納する配列。
//RegExpオブジェクトを作成。
var re = new RegExp("^(\\d{4})(\\d{2})(\\d{2})_(\\d{2})(\\d{2})(\\d{2})_(\\d+)_(\\d+)\\." + ext + "$");
renamed_dir = s_path + data_dir + "\\" + renamed_dir;//改名後のデータを入れるディレクトリのフルパス。
if (!fso.FolderExists(renamed_dir)){
    fso.CreateFolder(renamed_dir);//改名後のデータをいれるディレクトリがないときは作成する。
}
//ファイルコレクションの各ファイルに対して。
for (; !fc.atEnd() ; fc.moveNext()) {
    f = fc.item(); //ファイルオブジェクトの取得。
    //ファイル名の判別
    if (re.test(f.Name)) {
        f_arr.push(f);//処理対象となるファイルオブジェクトを配列に格納。ファイル名昇順に取得できているはず。
    } else {
        f.Delete();//処理対象とならないファイルは削除。
    }
}
for (var i = 0; i < f_arr.length - 1 ; i++) {
    f = f_arr[i];//配列からファイルオブジェクトを取得。最終要素は処理しない。
    new_name = new_fname(re.exec(f.Name));//正規表現結果配列からファイル名を取得。
    try {
        f.Move(renamed_dir + "\\" + new_name[0] + "." + ext)//「年月日_時分-年月日_時分」と改名して移動。
    } catch (e) {
        f.Move(renamed_dir + "\\" + new_name[1] + "." + ext)//「年月日_時分秒-年月日_時分秒」と改名して移動。
    } 
}
//正規表現結果配列から新しいファイル名を返す関数。戻り値は配列[年月日_時分-年月日_時分, 年月日_時分秒-年月日_時分秒]。
function new_fname(r) {
    //ファイル名から記録開始日時のDateオブジェクトを得る。1月を0として開始。
    var start_dt = new Date(r[1], r[2] - 1, r[3], r[4], r[5], r[6]);
    var int_sec = r[7] * 1000; //記録区間長(ミリ秒)
    var int_cnt = r[8]; //記録区間番号
    var start_ms = start_dt.getTime() + int_sec * (int_cnt - 1); //区間開始日時経過ミリ秒
    //経過ミリ秒を数字羅列に変換
    var end_n = date_num(start_ms + int_sec);//区間開始日時。
    var start_n = date_num(start_ms);//区間終了日時。
    var hhmm = start_n[0] + "-" + end_n[0];//新しいファイル名年月日_時分-年月日_時分。
    var hhmmss = start_n[0] + start_n[1] + "-" + end_n[0] + end_n[1];//新しいファイル名年月日_時分秒-年月日_時分秒。
    return [hhmm, hhmmss];
    //経過ミリ秒を年月日の数字羅列に変換する関数。戻り値は配列[年月日_時分, 秒]。
    function date_num(ms) {
        var dt = new Date();//Dateオブジェクトの生成。
        dt.setTime(ms);//経過ミリ秒からDateオブジェクトを取得。
        return [dt.getFullYear() + fm(dt.getMonth() + 1) + fm(dt.getDate()) + "_" + fm(dt.getHours()) + fm(dt.getMinutes()), fm(dt.getSeconds())];
        function fm(m) {
            return ("0" + m).slice(-2);//固定長2桁を返す。
        }
    }
}
音声ファイルの長さのチェックは時間かかるのでチェック済みのファイルは別フォルダ、今回はデータフォルダの下層のextractedというフォルダに移動させてチェックは1回だけさせるようにしました。

12行目でフォルダ名の設定をしています。

18行目と19行目でその存在確認と作成を行っています。

次の関連記事:SoXで音声感知録音:その3 自動録音環境構築まとめ

PR

0 件のコメント:

コメントを投稿