--
-- V4XE.V.E.C.エディター

--
-- プラグインマニフェスト関数.
--
function manifest()
    myManifest = {
        name          = "V4X E.V.E.C.Editor",
        comment       = "VOCALOIDEditorでE.V.E.C.を操作します",
        author        = "きょん☆さん",
        pluginID      = "{2db83a7b-e261-4182-a39b-63510f23684b}",
        pluginVersion = "1.0.1.0",
        apiVersion    = "3.0.0.1"
    }
    
    return myManifest
end

-- ノートイベント配列.
noteListEX = {}
phtbl = {"a", "i", "M", "e", "o", "N\\", "N", "J", "m'", "n", "m", "N'"}
cidL = {"BEKF82G3FDXLTEBD", "BELH8285FDYNTEDD", "BLLN57S9CKYTPLCB", "BMKKD8S6MLXP2MCC"}
cidRin = {"BLECA76YHKRGXLB7","BDHEBZG2KCWKYDC5","BKKP765AEHXWSKDB"}
cidLen = {"BKFFF663PHSL4KB6","BMGD88HZFLTHTMC7","BKPLC6S7LH3RZKC8"}
cidM = {"BCNFCY43LB2LZCD4", "BFPL93T7GE3RWFC9", "BKGHF6Y5PHTN4KD6", "BHNME578NG2S3HD8", "BDGE8ZB2FCTKTDBA"}
-- 設定ファイルの保存場所
dirf = os.getenv("APPDATA").."\\VOCALOIDJOBP\\"
-- 設定ファイルディレクトリがない場合は作成
os.execute("CMD /C \"MKDIR %appdata%\\VOCALOIDJOBP\\ > NUL 2>&1")

--- split関数
function split(str, del)
  p, nrep = str:gsub("%s*"..del.."%s*", "")
  return { str:match((("%s*(.-)%s*"..del.."%s*"):rep(nrep).."(.*)")) }
end

--
-- スクリプトのエントリポイント関数.
--
function main(processParam, envParam)
	-- 実行時に渡されたパラメータを取得する.
	local beginPosTick = processParam.beginPosTick	-- 選択範囲の始点時刻（ローカルTick）.
	local endPosTick   = processParam.endPosTick	-- 選択範囲の終点時刻（ローカルTick）.
	local songPosTick  = processParam.songPosTick	-- カレントソングポジション時刻（ローカルTick）.

	-- 実行時に渡された実行環境パラメータを取得する.
	local scriptDir  = envParam.scriptDir	-- Luaスクリプトが配置されているディレクトリパス（末尾にデリミタ "\" を含む）.
	local scriptName = envParam.scriptName	-- Luaスクリプトのファイル名.
	local tempDir    = envParam.tempDir		-- Luaプラグインが利用可能なテンポラリディレクトリパス（末尾にデリミタ "\" を含む）.

	-- MusicalパートのバーチャルSinger情報を取得 musicalSinger.compID
	local musicalSinger = {}
	retCode, musicalSinger = VSGetMusicalPartSinger()
	libr = ""
	for i = 1, 4 do
		if cidL[i] == musicalSinger.compID then
			libr = "LukaV4X"
		end
	end

	for i = 1, 5 do
		if cidM[i] == musicalSinger.compID then
			libr = "MikuV4X"
		end
	end

	for i = 1, 3 do
		if cidRin[i] == musicalSinger.compID then
			libr = "RinV4X"
		end
	end
	for i = 1, 3 do
		if cidLen[i] == musicalSinger.compID then
			libr = "LenV4X"
		end
	end

--	if libr == "" then
--		VSMessageBox("ライブラリを変更してください。", 0)
--		return 0
--	end

	local preset = {}
	--設定ファイルの読み込み
	df = 1
	file = io.open(dirf.."V4X_EVEC10.dat", "r")
	if file then
		for idz = 0, 10 do
			preset[idz] = file:read()
			if preset[idz] == nil then
				df = 0
			end
     	end
     end
	if(file == nil) then
		df = 0
	end
	--設定ファイルがない場合のデフォルト値
	if df == 0 then
		preset[0] = "なし,Whisper,Soft,Husky,Native,Power1,Power2,Cute,Dark,Falsetto"
		preset[1] = "なし,Breath-Short,Breath-Long"
		preset[2] = "なし,×２,×３,×４"
		preset[3] = ""
		preset[4] = 45
		preset[5] = 60
		preset[6] = 1
		preset[7] = 1
		--ミクβ・リン・レン用Preset
		preset[8] = "なし,Soft,Power"
		--リン・レンアクセントPreset
		preset[9] = "なし,Accent,×２,×３,×４"
		--ミク発音拡張
		preset[10] = "なし,Mild／Soft,Accent／Strong"
	end

	-- パラメータ入力ダイアログのウィンドウタイトルを設定する.
	VSDlgSetDialogTitle(libr.." E.V.E.C.エディター")

	-- ダイアログにフィールドを追加する.
	local field = {}
	field.name       = "ColorType"
	field.caption    = "Voice Color"
	if libr == "MikuV4X" or libr == "RinV4X" or libr == "LenV4X" then
		field.initialVal = preset[8]
	end
	if libr == "LukaV4X" or libr == "" then
		field.initialVal = preset[0]
	end
	field.type = 4
	dlgStatus  = VSDlgAddField(field)

	field.name       = "ReleaseType"
	field.caption    = "Voice Release"
	field.initialVal = preset[1]
	field.type = 4
	dlgStatus  = VSDlgAddField(field)

	if  libr == "MikuV4X" or libr == "" then
		field.name       = "AccentType"
		field.caption    = "発音拡張"
		field.initialVal = preset[10]
		field.type = 4
		dlgStatus  = VSDlgAddField(field)
	end

	field.name = "phetbl"
	if  libr == "RinV4X" or libr == "LenV4X" then
		field.caption    = "発音拡張・子音拡張"
		field.initialVal = preset[9]
	else
		field.caption    = "子音拡張"
		field.initialVal = preset[2]
	end
	field.type = 4
	dlgStatus  = VSDlgAddField(field)

	field.name       = "Cly"
	field.caption = "Color・Release部分lyric"
	field.initialVal = preset[3]
	field.type       = 3
	dlgStatus = VSDlgAddField(field)

	field.name       = "Vlen"
	field.caption    = "先頭ノート長さ（45）通常はこのまま"
	field.initialVal = preset[4]
	field.type       = 0
	dlgStatus = VSDlgAddField(field)

	field.name       = "Rlen"
	field.caption    = "Release長さ（60）通常はこのまま"
	field.initialVal = preset[5]
	field.type       = 0
	dlgStatus = VSDlgAddField(field)

	field.name       = "PHPro"
	field.caption    = "Color・Releaseの発音記号をプロテクト"
	field.initialVal = preset[6]
	field.type       = 1
	dlgStatus = VSDlgAddField(field)

	field.name       = "prsn"
	field.caption    = "この設定値をデフォルトにする"
	field.initialVal = preset[7]
	field.type       = 1
	dlgStatus = VSDlgAddField(field)

	-- ダイアログから入力値を取得する.
	dlgStatus = VSDlgDoModal()
	if  (dlgStatus ~= 1) then
		return 0
	end

	-- ダイアログから入力値を取得する.
	dlgStatus, ColorType = VSDlgGetStringValue("ColorType")
	dlgStatus, ReleaseType = VSDlgGetStringValue("ReleaseType")
	if libr == "MikuV4X" or libr == "" then
		dlgStatus, AccentType = VSDlgGetStringValue("AccentType")
	end
	dlgStatus, phetbl = VSDlgGetStringValue("phetbl")
	dlgStatus, Cly = VSDlgGetStringValue("Cly")
	dlgStatus, Vlen = VSDlgGetIntValue("Vlen")
	dlgStatus, Rlen = VSDlgGetIntValue("Rlen")
	dlgStatus, PHPro = VSDlgGetBoolValue("PHPro")
	dlgStatus, prsn = VSDlgGetBoolValue("prsn")

	if libr == "LukaV4X" or libr == "" then
		if ColorType == "なし" then
			preset[0] = "なし,Whisper,Soft,Husky,Native,Power1,Power2,Cute,Dark,Falsetto"
			colorex = ""
		end
		if ColorType == "Whisper" then
			preset[0] = "Whisper,なし,Soft,Husky,Native,Power1,Power2,Cute,Dark,Falsetto"
			colorex = "#1"
		end
		if ColorType == "Soft" then
			preset[0] = "Soft,なし,Whisper,Husky,Native,Power1,Power2,Cute,Dark,Falsetto"
			colorex = "#2"
		end
		if ColorType == "Husky" then
			preset[0] = "Husky,なし,Whisper,Soft,Native,Power1,Power2,Cute,Dark,Falsetto"
			colorex = "#3"
		end
		if ColorType == "Native" then
			preset[0] = "Native,なし,Whisper,Soft,Husky,Power1,Power2,Cute,Dark,Falsetto"
			colorex = "#4"
		end

		if ColorType == "Power1" then
			preset[0] = "Power1,なし,Whisper,Soft,Husky,Native,Power2,Cute,Dark,Falsetto"
			colorex = "#5"
		end
		if ColorType == "Power2" then
			preset[0] = "Power2,なし,Whisper,Soft,Husky,Native,Power1,Cute,Dark,Falsetto"
			colorex = "#6"
		end
		if ColorType == "Cute" then
			preset[0] = "Cute,なし,Whisper,Soft,Husky,Native,Power1,Power2,Dark,Falsetto"
			colorex = "#+"
		end
		if ColorType == "Dark" then
			preset[0] = "Dark,なし,Whisper,Soft,Husky,Native,Power1,Power2,Cute,Falsetto"
			colorex = "#-"
		end
		if ColorType == "Falsetto" then
			preset[0] = ",Falsetto,なし,Whisper,Soft,Husky,Native,Power1,Power2,Cute,Dark"
			colorex = "#F"
		end
	elseif libr == "MikuV4X" or libr == "RinV4X" or libr == "LenV4X" then
		if ColorType == "なし" then
			preset[8] = "なし,Soft,Power"
			colorex = ""
		end
		if ColorType == "Soft" then
			preset[8] = "Soft,なし,Power"
			colorex = "#2"
		end
		if ColorType == "Power" then
			preset[8] = "Power,なし,Soft"
			colorex = "#6"
		end
	end

	if ReleaseType == "なし" then
		preset[1] = "なし,Breath-Short,Breath-Long"
		Relex = ""
	end
	if ReleaseType == "Breath-Short" then
		preset[1] = "Breath-Short,Breath-Long,なし"
		rtype = "BS"
		Relex = "*#1"
	end
	if ReleaseType == "Breath-Long" then
		preset[1] = "Breath-Long,なし,Breath-Short"
		rtype = "BL"
		Relex = "*#2"
	end

	if  libr == "RinV4X" or libr == "LenV4X" then
		if phetbl == "なし" then
			preset[9] = "なし,Accent,×２,×３,×４"
			phex = 1
		end

		if phetbl == "Accent" then
			preset[9] = "Accent,なし,×２,×３,×４"
			phex = 2
		end

		if phetbl == "×２" then
			preset[9] = "×２,なし,Accent,×３,×４"
			phex = 3
		end

		if phetbl == "×３" then
			preset[9] = "×３,なし,Accent,×２,×４"
			phex = 4
		end

		if phetbl == "×４" then
			preset[9] = "×４,なし,Accent,×２,×３"
			phex = 5
		end
	end

	if  libr ~= "RinV4X" and libr ~= "LenV4X" then
		if phetbl == "なし" then
			preset[2] = "なし,×２,×３,×４"
			phex = 1
		end

		if phetbl == "×２" then
			preset[2] = "×２,なし,×３,×４"
			phex = 2
		end

		if phetbl == "×３" then
			preset[2] = "×３,なし,×２,×４"
			phex = 3
		end

		if phetbl == "×４" then
			preset[2] = "×４,なし,×２,×３"
			phex = 4
		end
	end
	atp = ""
	if  libr == "MikuV4X" or libr == "" then
		if AccentType == "なし" then
			preset[10] = "なし,Mild／Soft,Accent／Strong"
		end

		if AccentType == "Mild／Soft" then
			preset[10] = "Mild／Soft,なし,Accent／Strong"
			atp = "#2"
		end

		if AccentType == "Accent／Strong" then
			preset[10] = "Accent／Strong,なし,Mild／Soft"
			atp = "#6"
		end
	end
	if (colorex == "") and (Relex == "") and (phex == 1) and (atp == "") then
		VSMessageBox("Voice colore・Voice Release・子音拡張のいずれかをを指定してください。", 0)
		return 0
	end

	preset[3] =	Cly
	preset[4] = Vlen
	preset[5] = Rlen
	preset[6] = PHPro
	preset[7] = prsn

	-- 終了コード.
	local endStatus = 0

	-- 変数・定数の定義
	local noteListEX = {}
	local note     = {}
	local noteCount
	local retCode
	local idx

	-- ノートを取得してノートイベント配列へ格納します.
	VSSeekToBeginNote()
	idx = 1
	retCode, note = VSGetNextNoteEx()
	while (retCode == 1) do
		-- 取得したノートを配列へ格納する.
		noteListEX[idx] = note
		retCode, note = VSGetNextNoteEx()
		idx = idx + 1
	end

	-- 読み込んだノートの総数.
	noteCount = table.getn(noteListEX)
	if (noteCount == 0) then
		VSMessageBox("読み込んだノートがありません。", 0)
		return 0
	end

	-- 選択音符を判定
	local startNote = noteCount + 1	-- 最初の選択音符
	local endNote = 0		-- 最後の選択音符
	local noteStartPos		-- 音符の開始時刻
	local noteEndPos		-- 音符の終了時刻

	for idx = 1, noteCount do
		noteStartPos = noteListEX[idx].posTick
		noteEndPos   = noteListEX[idx].posTick + noteListEX[idx].durTick
		-- 音符が選択範囲内に入っていた場合
		if ( (beginPosTick <= noteStartPos) and (noteEndPos <= endPosTick) ) then
			if (idx < startNote ) then
				startNote = idx
			end
			if (idx > endNote) then
				endNote = idx
			end
		end
	end

	-- ノートが選択されていない場合
	if (endNote == 0) then
		VSMessageBox("ノートが選択されていません。", 0)
		return 0
	end

	--複数ノート選択に制限をかける（暫定）
	if endNote - startNote > 0 then
		local BoxStatus
		BoxStatus = VSMessageBox("複数のノートが選択されています。\nよろしいですか？",4)
		if( BoxStatus == 7 ) then
			return 0
		end
	end

	-- 処理ループ.
	for idx =  startNote, endNote do
		local updNote = {}
		updNote = noteListEX[idx]
		erf = 0
		durTickm = updNote.durTick
		posTickm = updNote.posTick
		vibratoTypem = updNote.vibratoType
		lenmax = 30 + Rlen
		if (colorex == "") and (Relex ~= "") then
			lenmax = 30 + Vlen
		end
		if (colorex ~= "") and (Relex ~= "") then
			lenmax = 30 + Vlen + Rlen
		end
		if (colorex == "") and (Relex == "") then
			lenmax = 0
		end
		if durTickm < lenmax then
			erf = 1
		end
		local phfl = 0
		phoneV = ""
		for i = 1, 12 do
			if phtbl[i] == updNote.phonemes then
				phoneC = updNote.phonemes
				phfl = 1
			end
		end
		if phfl == 0 then
			phoneCV = split(updNote.phonemes, " ")
			phoneC = phoneCV[1]
			phoneV = phoneCV[2]
			if (phoneV == nil) then
				phoneV = ""
			end
			if (phoneC.." "..phoneV) ~= updNote.phonemes then
				erf = 1
			end
		end

		for i = 1, 5 do
			if phtbl[i] == phoneV then
			phfl = 2
			end
		end

		if phfl == 0 then
			erf = 1
		end

		if phfl == 1 then
			phoneV = phoneC
		end

		--ノートの処理
		if (erf == 0) or ((colorex == "") and (Relex ~= "")) then
			if colorex ~= "" then
				updNote.durTick = Vlen
				updNote.vibratoType = 0
			end
			if (colorex == "") and (Relex ~= "") then
				updNote.durTick = updNote.durTick - Rlen
			end
			if ((phex > 1) and (phfl ~= 1)) or ((atp ~= "") and (phfl ~= 1)) then
				updNote.phonemes = phoneC
				if (phex > 1) and (phfl ~= 1) then
					for i = 2,phex do
						updNote.phonemes = updNote.phonemes.." "..phoneC
					end
				end
				if atp ~= "" then
					updNote.phonemes = updNote.phonemes.." "..phoneC..atp
				end
				updNote.phonemes = updNote.phonemes.." "..phoneV
			end
			retCode = VSUpdateNoteEx(updNote);
			if (retCode ~= 1) then
				VSMessageBox("更新エラー", 0)
				return 0
			end
			--ノートColorの処理
			if (colorex ~= "") then
				local newNoteA = {}
				newNoteA = noteListEX[idx]
				newNoteA.durTick = durTickm - Vlen
				if  Relex ~= "" then
					newNoteA.durTick = newNoteA.durTick - Rlen
				end
				newNoteA.phLock = 0
				if PHPro == 1 then
					newNoteA.phLock = 1
				end
				newNoteA.posTick = newNoteA.posTick + Vlen
				newNoteA.lyric = Cly
				if Cly == "" then
					newNoteA.lyric = ColorType
				end
				newNoteA.phonemes = phoneV..colorex
				newNoteA.vibratoType = vibratoTypem
				retCode = VSInsertNoteEx(newNoteA)
				if(retCode ~= 1) then
					VSMessageBox("更新エラー", 0)
					return 0
				end
			end
			--ノートReleaseの処理
			if Relex ~= "" then
				local newNoteB = {}
				newNoteB = noteListEX[idx]
				newNoteB.phLock = 0
				if PHPro == 1 then
					newNoteB.phLock = 1
				end
				newNoteB.vibratoType = 0
				newNoteB.durTick = Rlen
				newNoteB.posTick = posTickm + durTickm - Rlen
				newNoteB.lyric = Cly
				if Cly == "" then
					newNoteB.lyric = rtype
				end
				newNoteB.phonemes = Relex
				retCode = VSInsertNoteEx(newNoteB)
				if(retCode ~= 1) then
					VSMessageBox("更新エラー", 0)
					return 0
				end
			end
		end
	-- 設定ファイル保存
	if (prsn == 1) then
		f = io.open(dirf.."V4X_EVEC10.dat", "w")
		for idz = 0, 10 do
			if f ~=  nil then
				f:write(preset[idz] .. "\n")
			end
		end
		if f == nil then
				VSMessageBox("設定ファイルを保存できませんでした。", 0)
		end
		if f ~=  nil then
			f:close()
		end
	end
end
	return 0
end
