#!/bin/sh
# the next line restarts using wish \
exec wish "$0" "$@"

#
# UTAU用音声ファイルセットの各音節の内容を解析してUTAU用原音設定を自動的に作るスクリプト
#
#
# 解析結果のファイルは先頭行の音声ファイルセットのあるディレクトリ名を削除すればoto.iniとして使用可能
#
#
# 先行発声、オーバーラップはUTAU作者のブログに書かれている内容を参考に設定。
# 「きゃ」「しゃ」などは先頭の1文字目と同じ行として設定している。
# ただしブログに記述のない「ざ行」は「さ行」、「ら行」は「な行」「ま行」と同じに設定。
#

set VIRSION "1.10+oremo3"					;# このスクリプトのバージョン
set INITFILE {[file rootname $FULLPATH]_init.tcl}	;# 初期化ファイルのファイル名。デイレクトリの区切り記号には"/"を使うこと。$FULLPATHを指定すると現在実行しているファイルのフルパスのファイル名になる(直接実行している場合はスクリプトのファイル名、starpack化している場合は.exeファイルの名前。ただしファイル名は'""'ではなく'{}'で囲み、後でsubustで評価させる)。

set OUTFILE {$dirValue/analyzeresult.ini}		;# 解析結果の保存先。デイレクトリの区切り記号には"/"を使うこと。ファイル名に"$[]{}"の文字がある場合はその文字の直前に"\"を入れること。$dirValueを指定すると選択したディレクトリになる(ただしファイル名は'""'ではなく'{}'で囲むこと)。
set DISDIRNAME 0					;# 1で解析結果の先頭に原音ファイルのあるディレクトリ名を記録しない

set DISPVER 0						;# 1でバージョンを表示する
set DISPFILE 1						;# 1で処理したファイル名を表示する
set ENFILTER 1						;# 1で解析時にフィルタを使用する
set FILTERDELAY 0					;# 1でフィルタの遅延を考慮する
set OUTFORM ""						;# ""で出力桁数の制限なしで出力する。

set RELTRIMLEVEL1 0.025					;# 無音と判断する最大音量からの倍率(音の開始時)
set RELTRIMLEVEL2 0.05					;# 無音と判断する最大音量からの倍率(音の終了時)
set RELTRIMLEVEL3 0.4					;# 音の開始時のノイズと判断する最大音量からの倍率(f0を検出したのに音が小さい場合はノイズとみなす。「んが」などと発音した場合の「ん」部分を削る)
set MINTRIMLEVEL1 30					;# 無音と判断する基準値の最低値(音の開始時)
set MINTRIMLEVEL2 60					;# 無音と判断する基準値の最低値(音の終了時)
set MINTRIMLEVEL3 120					;# 音の開始時のノイズと判断する基準値の最低値
set PROBLEVEL1 0.95					;# 母音と判断するf0の自己相関係数
set PROBLEVEL3 0.75					;# 音の開始時のノイズと判断するf0の自己相関係数
set FILTERDMINTRIMCOEFF 0.75				;# フィルタを使用した場合に判断値に掛ける係数
set FILTERDPROBLEVEL 0.25				;# フィルタを使用した場合に母音と判断するf0の自己相関係数

set tap2 44 						;# (タップ数-1)/2の値。この値の倍の値がフィルタの次数。フィルタ長はこの値の倍+1。
set fs 44100						;# サンプリング周波数
set fc1 1000						;# バンドパスフィルタの低い側の遮断周波数。ローパスフィルタにしたい場合はfc1の値を0にする
set fc2 22050						;# バンドパスフィルタの高い側の遮断周波数。ハイパスフィルタにしたい場合はfc2の値をfs/2にする

set MAXPITCH 400					;# Pitch検出の最大周波数
set MINPITCH 60						;# Pitch検出の最小周波数
set FRAMEINTERVAL 0.01					;# Frame間隔 (秒)

;# 音の開始時のノイズを判断しない音
set DISTRIM3TYPE "な,に,ぬ,ね,の,ま,み,む,め,も,ら,り,る,れ,ろ,ナ,ニ,ヌ,ネ,ノ,マ,ミ,ム,メ,モ,ラ,リ,ル,レ,ロ"
;# 子音部の音量が小さい音で子音部の先頭を削られると発音が変わる音
set LOWPWRTYPE "さ,し,す,せ,そ,ち,つ,は,ひ,ふ,へ,ほ,サ,シ,ス,セ,ソ,チ,ツ,ハ,ヒ,フ,ヘ,ホ"
# set LOWPWRTYPE "さ,し,す,せ,そ,ち,つ,は,ひ,ふ,へ,ほ,ざ,じ,ず,ぜ,ぞ"	;# 子音部の音量が小さい音で子音部の先頭を削られると発音が変わる音

set LOWPWRCOEFF 0.5						;# 子音部の音量が小さい音に対して判断値に掛ける係数

;# 先行発声・オーバラップ共に設定しない
set TYPE1 "あ,い,う,え,お,を,ん,ア,イ,ウ,エ,オ,ヲ,ン"
;# 頭にブランクを残してその分先行発声を設定
set TYPE2 "か,き,く,け,こ,た,て,と,てぃ,とぅ,が,ぎ,ぐ,げ,ご,だ,で,ど,ば,び,ぶ,べ,ぼ,ぱ,ぴ,ぷ,ぺ,ぽ,カ,キ,ク,ケ,コ,タ,テ,ト,ティ,トゥ,ガ,ギ,グ,ゲ,ゴ,ダ,デ,ド,バ,ビ,ブ,ベ,ボ,パ,ピ,プ,ペ,ポ"
;# 先行発声の値は子音部分の真ん中より右寄りに設定。オーバーラップは先行発声から左に50msec位に設定
set TYPE3 "さ,し,す,せ,そ,ざ,じ,ず,づ,ぜ,ぞ,サ,シ,ス,セ,ソ,ザ,ジ,ズ,ヅ,ゼ,ゾ"
;# 先行発声は値は子音部分の真ん中より右。オーバーラップは設定しない。
set TYPE4 "つ,つぁ,つぃ,つぇ,つぉ,ち,ちゃ,ちゅ,ちぇ,ちょ,ツ,ツァ,ツィ,ツェ,ツォ,チ,チャ,チュ,チェ,チョ"
;# 先行発声は値は頭から20〜25msec程度のところに設定。オーバーラップは頭の立ち上がり分くらい。
set TYPE5 "な,に,ぬ,ね,の,ま,み,む,め,も,や,ゆ,よ,いぇ,ら,り,る,れ,ろ,わ,ナ,ニ,ヌ,ネ,ノ,マ,ミ,ム,メ,モ,ヤ,ユ,ヨ,イェ,ラ,リ,ル,レ,ロ,ワ"
;# 先行発声の値は子音部分の真ん中より右寄り、サ行よりも母音部の頭に接近にさせて設定。オーバーラップは先行発声から左に50msec位に設定
set TYPE6 "は,ひ,へ,ほ,ふ,ふぁ,ふぃ,ふぇ,ふぉ,ハ,ヒ,ヘ,ホ,フ,ファ,フィ,フェ,フォ"
           


set TYPE2ADDBLANK 0.02					;# TYPE2で頭にブランクを残してその分先行発声を設定する場合のブランクを残す秒数
set TYPE3SENKORATE 0.6					;# TYPE3で検出した子音部の先行発声に割り当てる割合
set TYPE3OVERLAP 0.05					;# TYPE3で設定するオーバーラップから先行発声までの秒数の最大値
set TYPE4SENKORATE 0.6					;# TYPE4で検出した子音部の先行発声に割り当てる割合
set TYPE5SENKO 0.02					;# TYPE5で設定する先行発声の秒数
set TYPE5OVERLAP 0.01					;# TYPE5で設定するオーバーラップの秒数
set TYPE6SENKORATE 0.8					;# TYPE6で検出した子音部の先行発声に割り当てる割合
set TYPE6OVERLAP 0.05					;# TYPE6で設定するオーバーラップから先行発声までの秒数の最大値

set startscript {}					;# 解析処理開始前に1回だけ実行させるTclスクリプト
set repeatscript {}					;# 各wavファイルの処理前に毎回実行させるTclスクリプト
set endscript {}					;# すべてのファイルの解析処理終了時に1回だけ実行させるTclスクリプト

set aliaslist {}					;#aliasを指定する。ファイル名とaliasを1組にして並べる。ファイル名は大文字・小文字を区別する。(.wavと.WAVは別物として扱うので注意)

set DEBUG 0						;# 1でデバッグ用にパラメータを出力 


set trim3enable 0					;# 1で音の開始時のノイズを回避する係数を使用する

proc makeflt {tap2 fs fc1 fc2} {

	set fs [expr double($fs)]
	set fc1 [expr double($fc1)]
	set fc2 [expr double($fc2)]

	set pi [expr 2.0 * asin(1.0)] ;# πの値

	set work1 [expr $fc2/$fs-$fc1/$fs]
	set coeff_list [expr 2.0*$work1]

	for {set cnt 1} {$cnt <= $tap2} {incr cnt} {
		set work2 [expr $pi*$cnt]
		set coeff [expr 2.0*$work1*cos($work2*[expr $fc1/$fs+$fc2/$fs])*sin($work2*$work1)/($work2*$work1)]

		set coeff_list [linsert $coeff_list 0 $coeff]
		set coeff_list [linsert $coeff_list end $coeff]
	}

#	puts "coeff = $coeff_list"

	set flt [snack::filter iir -impulse $coeff_list]

	return $flt

}


package require snack 
snack::sound s 

set batch 1   ;# 1=バッチ的に処理させる。

if {[info exists ::starkit::topdir]} {
  set FULLPATH [info nameofexecutable]
} else {
  set FULLPATH $argv0
}
if {$batch == 0} {
  if {[info exists ::starkit::topdir]} {
	  set dirValue [file dirname $::starkit::topdir]
  } else {
	  set dirValue [pwd]
  }
}

set INITFILE [file rootname $FULLPATH]_init.tcl
if {[file exists $INITFILE]==1} {
	source $INITFILE
}

#-------------------------------------------
# 引数チェック
# memo: *.tcl -- -option とするのが無難。--がないとwishのオプションと思われる様子
if {$argc != 2} {
  puts "usage: $argv0 dirname outfile"
  puts "usage: $argv0 -f paramFile"
  puts "         paramFile: 1行目=dirname、2行目=outfile"
  exit
}
if {[lindex $argv 0] == "-f"} {
  set paramFile [lindex $argv 1]
  regsub -all -- {(\r|\n)} $paramFile "" paramFile
  if [catch {open $paramFile r} in] {
    tk_messageBox -message "error: $paramFileを読み込めません。" \
      -title "エラー" -icon warning
    exit
  }
  if [catch {gets $in} dirValue] {
    tk_messageBox -message "error: $paramFile読み込み失敗。" \
      -title "エラー" -icon warning
    exit
  }
  if [catch {gets $in} OUTFILE] {
    tk_messageBox -message "error: $paramFile読み込み失敗。" \
      -title "エラー" -icon warning
    exit
  }
  close $in
} else {
  set dirValue [lindex $argv 0]
  set OUTFILE  [lindex $argv 1]
  regsub -all -- {(\r|\n)} $OUTFILE "" OUTFILE
}

#if {![file isdirectory "$dirValue"]} {
#  puts "error: $dirValue is not directory"
#  exit
#}
#if {![file isdirectory [file dirname "$OUTFILE"]]} {
#  puts "error: can not open $OUTFILE"
#  exit
#}

#cd "$dirValue"


set flt [makeflt $tap2 $fs $fc1 $fc2]

set fdelay [expr 1000.0*$tap2/$fs]
set stopflag 0

set FONT {{MS ゴシック} 10 normal}

frame .f1
button .f1.b1 -text "ディレクトリ選択" -font $FONT -command {
  set dirValue [tk_chooseDirectory -initialdir "$dirValue" -title "原音ディレクトリ選択"]
	if {"$dirValue" ne ""} {
		# cd "$dirValue"
		.f1.l1 configure -text "ディレクトリ: $dirValue"
	}
}
label .f1.l1 -text "ディレクトリ: $dirValue" -font $FONT
;#button .b2 -text "開始" -font $FONT -command "analyze"
button .b2 -text "--" -font $FONT 
frame .f2
text .f2.t0 -state disabled -yscrollcommand {.f2.s0 set}
scrollbar .f2.s0 -command {.f2.t0 yview}

pack .f1 -side top
pack .b2 -side top
pack .f1.l1 -side left -ipadx 10
pack .f1.b1 -side left
pack .f2 -expand 1 -fill both
pack .f2.t0 -side left -expand 1 -fill both
pack .f2.s0 -side right -fill y

if {$DISPVER==1} {
	.f2.t0 configure -state normal
	.f2.t0 insert end "Version:$VIRSION\n"
	.f2.t0 configure -state disabled
}
wm title . "パラメータの自動推定($argv0 ver.$VIRSION)"

#set coeff [makeflt2 $tap2 $fs $fc1 $fc2]
#.f2.t0 configure -state normal ; .f2.t0 insert end "coeff=$coeff\n" ; .f2.t0 configure -state disabled 

proc analyze {} {
	global FONT dirValue flt stopflag fdelay
	global OUTFILE DISDIRNAME DISPFILE ENFILTER FILTERDELAY OUTFORM
	global RELTRIMLEVEL1 RELTRIMLEVEL2 RELTRIMLEVEL3 MINTRIMLEVEL1 MINTRIMLEVEL2 MINTRIMLEVEL3
	global PROBLEVEL1 PROBLEVEL3 FILTERDMINTRIMCOEFF FILTERDPROBLEVEL
	global MAXPITCH MINPITCH FRAMEINTERVAL
	global DISTRIM3TYPE LOWPWRTYPE LOWPWRCOEFF
	global TYPE1 TYPE2 TYPE3 TYPE4 TYPE5 TYPE6
	global TYPE2ADDBLANK TYPE3SENKORATE TYPE3OVERLAP TYPE4SENKORATE
	global TYPE5SENKO TYPE5OVERLAP TYPE6SENKORATE TYPE6OVERLAP
	global startscript repeatscript endscript
	global aliaslist DEBUG trim3enable
  global batch

	set MINTRIMLEVEL1 [expr double($MINTRIMLEVEL1)]
	set MINTRIMLEVEL2 [expr double($MINTRIMLEVEL2)]
	set MINTRIMLEVEL3 [expr double($MINTRIMLEVEL3)]
	set MAXPITCH [expr int($MAXPITCH)]			;# 整数でないとpitch解析でエラーになる
	set MINPITCH [expr int($MINPITCH)]			;# 整数でないとpitch解析でエラーになる
	set FRAMEINTERVAL [expr double($FRAMEINTERVAL)]
	set LOWPWRCOEFF [expr double($LOWPWRCOEFF)]

	.f2.t0 configure -state normal
	.f2.t0 delete 1.0 end
	.f2.t0 configure -state disabled

	.f1.b1 configure -state disable
	.b2 configure -text "処理中"
#	destroy .b2
#	button .b3 -text "処理中" -font $FONT -command "stop"
#	pack .b3

	if {$startscript ne {}} {eval $startscript}

	if {[file exists "$OUTFILE"]==1} {
		if {[tk_messageBox -message "$OUTFILE はすでに存在しています。\n上書きしてもよろしいですか？" -type okcancel -title "上書き確認" -icon warning] ne "ok"} {
			.f1.b1 configure -state normal
			.b2 configure -text "開始"
      exit    ;#return
		}
	}

  .f2.t0 configure -state normal
	set OUTFILID [open "$OUTFILE" "w"]

	if {$DISDIRNAME!=1} {puts $OUTFILID "$dirValue"}

	if {[catch {glob -directory "$dirValue" *.wav} fid] } {
		tk_messageBox -message ".wavファイルの検索でエラーが発生しました。\n$fid" -type ok -title "処理中止" -icon info
		.f1.b1 configure -state normal
		.b2 configure -text "開始"
		return
	}
#.f2.t0 configure -state normal ; .f2.t0 insert end "executable=[info nameofexecutable]\nscript=[info script]\ntopdir=$::starkit::topdir\n" ; .f2.t0 configure -state disabled 

	array set aliasarray $aliaslist
	set errnum 0
	set warnnum 0

  initProgressWindow "now estimating..."  ;# 経過窓を作る
  set cnt 0
  set wavNum [llength [glob -nocomplain -directory "$dirValue" *.wav]]

	foreach wavfile [glob -nocomplain -directory "$dirValue" *.wav] {
		if {$repeatscript ne {}} {eval $repeatscript}

		if {$DISPFILE==1} {
			.f2.t0 configure -state normal
			.f2.t0 insert end "$wavfile\n"
			.f2.t0 configure -state disabled
		}

		s read $wavfile 
		s convert -frequency 44100 -channels mono -format Lin16 

		set WORKF0 [s pitch -method esps -framelength $FRAMEINTERVAL -maxpitch $MAXPITCH -minpitch $MINPITCH]

		s filter $flt -continuedrain 0

		if {$ENFILTER==1} {
			set WORKFILF0 [s pitch -method esps -framelength $FRAMEINTERVAL -maxpitch $MAXPITCH -minpitch $MINPITCH]
		}
#		s write [file rootname $wavfile]_flt.wav 
		set fname [file tail [file rootname $wavfile]]
		set lowpwr 0
		for {set i 0} {$i<=[expr [string length $fname]-1]} {incr i} {
			set str [string range $fname 0 [expr [string length $fname]-$i-1]]		;# $fnameを後ろから一文字ずつ減らしていって一致するかチェック
			if {[string first ",$str," ",$DISTRIM3TYPE,"]!=-1} {set trim3enable 0}	;# 探す文字の前後に","をつけて文字の区切りとともに一致をチェックする
			if {[string first ",$str," ",$LOWPWRTYPE,"]!=-1} {set lowpwr 1}	;# 探す文字の前後に","をつけて文字の区切りとともに一致をチェックする
		}

#		if {$ENFILTER==1} {
#			set pitlinenum [llength $WORKFILF0]
#	.f2.t0 configure -state normal ; .f2.t0 insert end "WORKFILF0=$WORKFILF0\n" ; .f2.t0 configure -state disabled 
#			if {[string first "expected integer but got" "$WORKFILF0"]!=-1} {
#				incr errnum
#				.f2.t0 configure -state normal
#				.f2.t0 insert end "ERROR snackの解析が正常に行われていない : $wavfile\n"
#				.f2.t0 configure -state disabled
#			}
#		}
		set pitlinenum [llength $WORKF0]
#	.f2.t0 configure -state normal ; .f2.t0 insert end "WORKF0=$WORKF0\n" ; .f2.t0 configure -state disabled 
#		if {[string first "expected integer but got" "$WORKF0"]!=-1} {
#			incr errnum
#			.f2.t0 configure -state normal
#			.f2.t0 insert end "ERROR snackの解析が正常に行われていない : $wavfile\n"
#			.f2.t0 configure -state disabled
#		}

		set problevel $PROBLEVEL1
		set maxrms 0.0
		set maxrmsnum 0
#	.f2.t0 configure -state normal ; .f2.t0 insert end "problevel=$problevel\n" ; .f2.t0 configure -state disabled 

		for {set i 0} {$i<=[expr $pitlinenum-1]} {incr i} {
			set f0 [lindex $WORKF0 $i 0]
			set f0enable [lindex $WORKF0 $i 1]
			set f0rms [lindex $WORKF0 $i 2]
			set f0prob [lindex $WORKF0 $i 3]
#	.f2.t0 configure -state normal ; .f2.t0 insert end "f0=$f0 ,f0enable=$f0enable ,f0rms=$f0rms ,f0prob=$f0prob\n" ; .f2.t0 configure -state disabled 
			if {$f0enable==1 && $f0prob>$problevel && $f0rms>=$maxrms} {	;# f0の自己相関係数がproblevel以上あった位置を記録
				set maxrms $f0rms
				set maxrmsnum $i
			}
		}
# if {$DEBUG==1} { .f2.t0 configure -state normal ; .f2.t0 insert end "maxrms=$maxrms ,maxrmsnum=$maxrmsnum ,f0rms=$f0rms\n" ; .f2.t0 configure -state disabled }

		if {$ENFILTER==1} {
			set startlevel [expr $maxrms*$RELTRIMLEVEL1*$FILTERDMINTRIMCOEFF] 
			if {$startlevel<$MINTRIMLEVEL1} {set startlevel $MINTRIMLEVEL1}
			set endlevel [expr $maxrms*$RELTRIMLEVEL2]
			if {$endlevel<$MINTRIMLEVEL2} {set endlevel $MINTRIMLEVEL2}
			set problevel $FILTERDPROBLEVEL
		} else {
			set startlevel [expr $maxrms*$RELTRIMLEVEL1]
			if {$startlevel<$MINTRIMLEVEL1} {set startlevel $MINTRIMLEVEL1}
			set endlevel [expr $maxrms*$RELTRIMLEVEL2]
			if {$endlevel<$MINTRIMLEVEL2} {set endlevel $MINTRIMLEVEL2}
			if {$trim3enable==1} {
				set startlevel [expr $maxrms*$RELTRIMLEVEL3]
				if {$startlevel<$MINTRIMLEVEL3} {set startlevel $MINTRIMLEVEL3}
				set problevel $PROBLEVEL3
			}
		}
#	.f2.t0 configure -state normal ; .f2.t0 insert end "startlevel=$startlevel ,endlevel=$endlevel ,problevel=$problevel\n" ; .f2.t0 configure -state disabled 

		if {$lowpwr==1} {set startlevel [expr $startlevel*$LOWPWRCOEFF]}
		if {$DEBUG==1} { .f2.t0 configure -state normal ; .f2.t0 insert end "maxrms=$maxrms ,maxrmsnum=$maxrmsnum ,f0rms=$f0rms ,startlevel=$startlevel ,endlevel=$endlevel\n" ; .f2.t0 configure -state disabled }
		set offsetnum -1
		set pwrend -2
		set shiinnum -1
		set pitend -1
		set pitlinenum [llength $WORKF0]
		for {set i 0} {$i<=[expr $pitlinenum-1]} {incr i} {
			set f0 [lindex $WORKF0 $i 0]
			set f0enable [lindex $WORKF0 $i 1]
			set f0rms [lindex $WORKF0 $i 2]
			set f0prob [lindex $WORKF0 $i 3]
			if {$ENFILTER==1} {
					set f0fil [lindex $WORKFILF0 $i 0]
					set f0filenable [lindex $WORKFILF0 $i 1]
					set f0filrms [lindex $WORKFILF0 $i 2]
					set f0filprob [lindex $WORKFILF0 $i 3]
#	.f2.t0 configure -state normal ; .f2.t0 insert end "f0fil=$f0fil ,f0filenable=$f0filenable ,f0filrms=$f0filrms ,f0filprob=$f0filprob\n" ; .f2.t0 configure -state disabled 
			}

			if {$ENFILTER==1} {
				if {$f0filrms>$startlevel && $offsetnum==-1} {set offsetnum [expr $i+1]}	;# 一旦TRIMLEVELを上回ったら以降はオフセットには含めない
#	.f2.t0 configure -state normal ; .f2.t0 insert end "f0filrms=$f0filrms\n" ; .f2.t0 configure -state disabled 
				if {$f0filenable==1 && $f0filprob>$problevel && $shiinnum==-1} {set shiinnum $i}	;# f0の自己相関係数がproblevel以上あった位置を記録
			} else {
				if {$f0rms>$startlevel && $offsetnum==-1} {set offsetnum [expr $i+1]}	;# 一旦TRIMLEVELを上回ったら以降はオフセットには含めない
				if {$f0enable==1 && $f0prob>$problevel && $shiinnum==-1} {set shiinnum $i}	;# f0の自己相関係数がproblevel以上あった位置を記録
			}

			if {$ENFILTER==1} {
				if {$f0enable==0 && $f0filenable==0 && $pitend==-1 && $shiinnum>=0} {set pitend $i}	;# shiinnum設定後にf0が検出できなくなった位置を記録
			} else {
				if {$f0enable==0 && $pitend==-1 && $shiinnum>=0} {set pitend $i}	;# shiinnum設定後にf0が検出できなくなった位置を記録
			}

			if {$f0rms>$endlevel && $i>$maxrmsnum && $pwrend==-2 && $offsetnum!=-1} {set pwrend -1}	;# endlevelを上回るまで音の終了の記録をしない
			if {$f0rms<$endlevel && $pwrend==-1} {set pwrend $i}	;# 一旦startlevelを上回った以降でendlevelを下回ったら音の終了とみなす
		}
		if {$DEBUG==1} { .f2.t0 configure -state normal ; .f2.t0 insert end "pwrend=$pwrend ,pitend=$pitend ,shiinnum=$shiinnum ,offsetnum=$offsetnum\n" ; .f2.t0 configure -state disabled }
		if {$offsetnum<0} {set offsetnum 0}
		if {$pwrend==-1} {set pwrend [expr $pitlinenum-1]}
		if {$pwrend<-1} {
			set offsetnum [expr $pitlinenum-1]
			set pwrend [expr $pitlinenum-1]
		}
		if {$pitend<0} {set pitend [expr $pitlinenum-1]}
		if {$pitend>$pwrend} {set pitend $pwrend}
		if {$shiinnum<$offsetnum} {
			if {$ENFILTER==1} {set shiinnum $offsetnum} else {set offsetnum $shiinnum}
		}
		if {[expr ($pitend-$shiinnum)/4.0]>[expr 0.05/$FRAMEINTERVAL]} {
			set shiin [expr $shiinnum-$offsetnum+($pitend-$shiinnum)/4.0]	;# 子音部に母音部の1/4を追加する
		} else {
			set shiin [expr $shiinnum-$offsetnum+0.05/$FRAMEINTERVAL]	;# 子音部に最小50msの母音を追加する
		}
		if {$shiin<0} {set shiin 0}

		set blank [expr $pitlinenum+3.0-$pitend+($pitend-$shiinnum)/4.0]	;# 母音部の1/4を切り捨てる。ピッチ解析では実際の長さより30ms分くらい短い所で終了するのでその分は大きくする

		set fname [file tail [file rootname $wavfile]]
		set type 0
		for {set i 0} {$i<=[expr [string length $fname]-1]} {incr i} {
			set str [string range $fname 0 [expr [string length $fname]-$i-1]]	;# $fnameを後ろから一文字ずつ減らしていって一致するかチェック
			if {[string first ",$str," ",$TYPE1,"]!=-1} {set type 1 ; break}	;# 探す文字の前後に","をつけて文字の区切りとともに一致をチェックする
			if {[string first ",$str," ",$TYPE2,"]!=-1} {set type 2 ; break}
			if {[string first ",$str," ",$TYPE3,"]!=-1} {set type 3 ; break}
			if {[string first ",$str," ",$TYPE4,"]!=-1} {set type 4 ; break}
			if {[string first ",$str," ",$TYPE5,"]!=-1} {set type 5 ; break}
			if {[string first ",$str," ",$TYPE6,"]!=-1} {set type 6 ; break}
		}
#	.f2.t0 configure -state normal ; .f2.t0 insert end "type=$type\n" ; .f2.t0 configure -state disabled 

		if {$type==1} {
			set senkou 0
			set overlap 0
		} elseif {$type==2} {
			set senkou [expr $TYPE2ADDBLANK/$FRAMEINTERVAL]
#	.f2.t0 configure -state normal ; .f2.t0 insert end "offsetnum=$offsetnum ,senkou=$senkou\n" ; .f2.t0 configure -state disabled 
			if {$offsetnum>$senkou} {
				set offsetnum [expr $offsetnum-$senkou]
				set overlap 0
			} else {
				set senkou $offsetnum
				set offsetnum 0
				set overlap 0
			}
		} elseif {$type==3} {
			set senkou [expr ($shiinnum-$offsetnum)*$TYPE3SENKORATE]
			if {$senkou>[expr $TYPE3OVERLAP/$FRAMEINTERVAL]} {
				set overlap [expr $senkou-$TYPE3OVERLAP/$FRAMEINTERVAL]
			} else {
				set overlap 0
			}
#	.f2.t0 configure -state normal ; .f2.t0 insert end "senkou=$senkou ,overlap=$overlap\n" ; .f2.t0 configure -state disabled 
		} elseif {$type==4} {
			set senkou [expr ($shiinnum-$offsetnum)*$TYPE4SENKORATE]
			set overlap 0
		} elseif {$type==5} {
			set senkou [expr $TYPE5SENKO/$FRAMEINTERVAL]
			set overlap [expr $TYPE5OVERLAP/$FRAMEINTERVAL]
		} elseif {$type==6} {
			set senkou [expr ($shiinnum-$offsetnum)*$TYPE6SENKORATE]
			if {$senkou>[expr $TYPE6OVERLAP/$FRAMEINTERVAL]} {
				set overlap [expr $senkou-$TYPE6OVERLAP/$FRAMEINTERVAL]
			} else {
				set overlap 0
			}
		} else {
			set senkou 0
			set overlap 0
			incr warnnum
			.f2.t0 configure -state normal
			.f2.t0 insert end "WARNING 対応する音節がない : $wavfile\n"
			.f2.t0 configure -state disabled
		}

		if {$offsetnum<0 || $shiinnum<0 || [expr $pitlinenum+3]<=[expr $blank+$shiin+$offsetnum]} {
			incr errnum
			.f2.t0 configure -state normal
			.f2.t0 insert end "ERROR in $wavfile ,offsetnum=$offsetnum ,shiinnum=$shiinnum ,pitlinenum=$pitlinenum ,blank=$blank ,shiin=$shiin ,pwrend=$pwrend ,pitend=$pitend\n"
			.f2.t0 configure -state disabled
		}

#		set alias [info exists aliasarray([file tail $wavfile])?$aliasarray([file tail $wavfile]):""]
		if {[info exists aliasarray([file tail $wavfile])]} {
			set alias $aliasarray([file tail $wavfile])
		} else {
			set alias ""
		}

		set offset [expr $offsetnum*$FRAMEINTERVAL*1000.0]
		set shiin [expr $shiin*$FRAMEINTERVAL*1000.0]
		set blank [expr $blank*$FRAMEINTERVAL*1000.0]
		set senkou [expr $senkou*$FRAMEINTERVAL*1000.0]
		set overlap [expr $overlap*$FRAMEINTERVAL*1000.0]

		if {$ENFILTER==1 && $FILTERDELAY==1} {
			if {$OUTFORM eq ""} {
				puts $OUTFILID "[file tail $wavfile]=$alias,[expr $offset>$fdelay?$offset-$fdelay:0],[expr $shiin>$fdelay?$shiin-$fdelay:0],[expr $blank+$fdelay],[expr $senkou>$fdelay?$senkou-$fdelay:0],[expr $overlap>$fdelay?$overlap-$fdelay:0]"
			} else {
				puts $OUTFILID [format $OUTFORM [file tail $wavfile] $alias [expr $offset>$fdelay?$offset-$fdelay:0] [expr $shiin>$fdelay?$shiin-$fdelay:0] [expr $blank+$fdelay] [expr $senkou>$fdelay?$senkou-$fdelay:0] [expr $overlap>$fdelay?$overlap-$fdelay:0] ]
			}
		} else {
			if {$OUTFORM eq ""} {
				puts $OUTFILID "[file tail $wavfile]=$alias,$offset,$shiin,$blank,$senkou,$overlap"
			} else {
				puts $OUTFILID [format $OUTFORM [file tail $wavfile] $alias $offset $shiin $blank $senkou $overlap ]
			}
		}

		if {$stopflag != 0} {
			set stopflag 0
			break
		}

    updateProgressWindow [expr 100 * $cnt / $wavNum]
    incr cnt
	}

  deleteProgressWindow

	close $OUTFILID

	if {$endscript ne {}} {eval $endscript}

	if {$errnum!=0 || $warnnum!=0} {
		tk_messageBox -message "エラー/ワーニングがありました。\nエラー:$errnum\nワーニング:$warnnum" -type ok -title "エラー数" -icon info
	}

  if {$batch} exit

	.f1.b1 configure -state normal
	.b2 configure -text "開始"
#	destroy .b3
#	button .b2 -text "開始" -font $FONT -command "analize"
#	pack .b2

}


proc stop {} {
	global stopflag

	set stopflag 1

}

#---------------------------------------------------
# プログレスバーを初期化して表示する
#
proc initProgressWindow {{title "now processing..."}} {
  global prgWindow v
  if [isExist $prgWindow] return

  set topg [split [wm geometry .] "x+"]
  set x [expr [lindex $topg 2] + [lindex $topg 0] / 2 - 100]
  set y [expr [lindex $topg 3] + [lindex $topg 1] / 2 - 5]

  toplevel $prgWindow
  wm title $prgWindow $title
  wm attributes $prgWindow -toolwindow 1
  wm attributes $prgWindow -topmost 1
  bind $prgWindow <Escape> "destroy $prgWindow"
  wm geometry $prgWindow "+$x+$y"

  set v(pregress) 0

  ttk::progressbar $prgWindow.p -length 200 -variable v(progress) -mode determinate
  pack $prgWindow.p

  focus .progress
}

#---------------------------------------------------
# プログレスバーを更新する。進捗状況は$progress(0〜100)で指定する)
#
proc updateProgressWindow {progress} {
  global v prgWindow

  set v(progress) $progress
  focus $prgWindow
  update
}

#---------------------------------------------------
# プログレスバーを消去する
#
proc deleteProgressWindow {} {
  global prgWindow
  destroy $prgWindow
}

#---------------------------------------------------
#   指定した窓が起動済みかチェック。起動済みならフォーカスする。
#
proc isExist {w} {
  if [winfo exists $w] {
    focus $w
    return 1
  } else {
    return 0
  }
}



set v(pregress) 0
set prgWindow .progress

if {$batch} analyze

