--
-- Voice Color変更

--
-- プラグインマニフェスト関数.
--
function manifest()
    myManifest = {
        name          = "EVEC Change",
        comment       = "Voice Colorを変更します",
        author        = "きょん☆さん",
        pluginID      = "{2431f540-3021-4476-a24a-fc53ea2110ac}",
        pluginVersion = "1.0.1.0",
        apiVersion    = "3.0.0.1"
    }
    
    return myManifest
end

-- ノートイベント配列.
noteListEX = {}
coltbl = {"#1", "#2", "#3", "#4", "#5", "#6", "#+", "#-", "#F"}
phtbl = {"a", "i", "M", "e", "o", "N\\", "N", "J", "m'", "n", "m", "N'"}
lrybl = {"あ", "い", "う", "え", "お", "ん", "ん", "ん", "ん", "ん", "ん", "ん"}
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.."EVEC_Change10.dat", "r")
	if file then
		for idz = 0, 4 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] = ""
		preset[2] = 1
		preset[3] = 1
		--ミクβ・リン・レン用Preset
		preset[4] = "なし,Soft,Power,削除,母音に戻す"
	end

	-- パラメータ入力ダイアログのウィンドウタイトルを設定する.
	VSDlgSetDialogTitle(libr.." Voice Color変更")

	-- ダイアログにフィールドを追加する.
	local field = {}
	field.name       = "ColorType"
	field.caption    = "Voice Color"
	if libr == "MikuV4X" or libr == "RinV4X" or libr == "LenV4X" then
		field.initialVal = preset[4]
	end
	if libr == "LukaV4X" or libr == "" then
		field.initialVal = preset[0]
	end
	field.type = 4
	dlgStatus  = VSDlgAddField(field)

	field.name       = "Cly"
	field.caption    = "Color・Release部分lyric"
	field.initialVal = preset[1]
	field.type       = 3
	dlgStatus = VSDlgAddField(field)

	field.name       = "PHPro"
	field.caption    = "Voice Colorノートをプロテクトする"
	field.initialVal = preset[2]
	field.type       = 1
	dlgStatus = VSDlgAddField(field)

	field.name       = "prsn"
	field.caption    = "この設定値をデフォルトにする"
	field.initialVal = preset[3]
	field.type       = 1
	dlgStatus = VSDlgAddField(field)

	-- ダイアログから入力値を取得する.
	dlgStatus = VSDlgDoModal()
	if  (dlgStatus ~= 1) then
		return 0
	end

	-- ダイアログから入力値を取得する.
	dlgStatus, ColorType = VSDlgGetStringValue("ColorType")
	dlgStatus, Cly = VSDlgGetStringValue("Cly")
	dlgStatus, PHPro = VSDlgGetBoolValue("PHPro")
	dlgStatus, prsn = VSDlgGetBoolValue("prsn")

	if libr == "LukaV4X" or libr == "" then
		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
		if ColorType == "削除" then
			preset[0] = "削除,Whisper,Soft,Husky,Native,Power1,Power2,Cute,Dark,Falsetto,母音に戻す"
			colorex = ""
		end

		if ColorType == "母音に戻す" then
			preset[0] = "母音に戻す,Whisper,Soft,Husky,Native,Power1,Power2,Cute,Dark,Falsetto,削除"
			colorex = ""
		end
	elseif libr == "MikuV4X" or libr == "RinV4X" or libr == "LenV4X" then
		if ColorType == "なし" then
			preset[4] = "なし,Soft,Power,削除,母音に戻す"
			colorex = ""
		end
		if ColorType == "Soft" then
			preset[4] = "Soft,なし,Power,削除,母音に戻す"
			colorex = "#2"
		end
		if ColorType == "Power" then
			preset[4] = "Power,なし,Soft,削除,母音に戻す"
			colorex = "#6"
		end
		if ColorType == "削除" then
			preset[0] = "削除,なし,Soft,Power,母音に戻す"
			colorex = ""
		end
		if ColorType == "母音に戻す" then
			preset[0] = "母音に戻す,なし,Soft,Power,削除"
			colorex = ""
		end
	end
	preset[1] =	Cly
	preset[2] = 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
		VSMessageBox("ノートが選択されていないか、複数選択されています", 0)
		return 0
	end

	-- 処理
	local updNote = {}
	local updNotem = {}
	updNote = noteListEX[startNote]
	updNotem = noteListEX[startNote-1]
	if (updNotem == nil) and colorex ~= "" then
		phoneV = "a"
		VSMessageBox("手前ノートが無いのでaを代用します", 0)
	end

	--一つ前のノートの母音を取得する
	if (updNotem ~= nil) and colorex ~= "" then
		phoneCV = split(updNotem.phonemes, " ")
		leng = #phoneCV
		phoneC = phoneCV[1]
		phoneV = phoneCV[leng]
		if phoneV == nil then
			for i = 1, 12 do
				if phtbl[i] == updNotem.phonemes then
					phoneV = updNotem.phonemes
				end
			end
		end
	end
	erro = 0
	if (phoneV == "" or phoneV == nil) and (colorex ~= "") then
		phoneV = "a"
		VSMessageBox("手前ノートの母音が取得できなかったのでaを代用します", 0)
	end
	for i = 1, 12 do
		if phtbl[i] == phoneV then
			erro = 1
		end
	end
	if erro == 0 and colorex ~= "" then
		phoneV = "a"
		VSMessageBox("手前ノートの母音が取得できなかったのでaを代用します", 0)
	end
	--ノート変更処理
	if colorex ~= "" then
		updNote.phonemes = phoneV..colorex
		updNote.lyric = Cly
		if Cly == "" then
			updNote.lyric = ColorType
		end
		updNote.lyric = ColorType
		if PHPro == 1 then
			updNote.phLock = 1
		end
		retCode = VSUpdateNoteEx(updNote);
		if (retCode ~= 1) then
			VSMessageBox("変更できませんでした", 0)
			return 0
		end
	end

	-- Voice Color削除処理
	if (colorex == "") and (ColorType ~= "母音に戻す") then
		cn = string.sub(updNote.phonemes, -2)
		erro = 1
		for i = 1 , 9 do
			if coltbl[i] == cn then
				erro = 0
			end
		end
		if (erro == 1) or (updNotem == nil) then
			VSMessageBox("結合できませんでした。", 0)
			return 0
		end
		updNotem.durTick = updNotem.durTick + updNote.durTick
		updNotem.vibratoType = updNote.vibratoType
		updNotem.vibratoLength = updNote.vibratoLength
		retCode = VSRemoveNote(updNote);
		if (retCode ~= 1) then
			VSMessageBox("変更できませんでした", 0)
			return 1
		end
		retCode = VSUpdateNoteEx(updNotem);
		if (retCode ~= 1) then
			VSMessageBox("変更できませんでした", 0)
			return 0
		end
	end
	-- 母音に戻す処理
	if ColorType == "母音に戻す" then
		phA = ""
		lryA = ""
		phlen = string.len(updNote.phonemes)
		phB = string.sub(updNote.phonemes, -2)
		for i = 1, 9 do
			if phB == coltbl[i] then
				phA = string.sub(updNote.phonemes, 1, phlen - 2)
			end
		end
		if (phA == "") then
			VSMessageBox("母音に変更できませんでした", 0)
			return 0
		end
		if phA ~= "" then
			for i = 1, 12 do
				if phA == phtbl[i] then
					lryA = lrybl[i]
				end
			end
			if (lryA == "") then
				lryA = "-"
			end
		end
		updNote.phonemes = phA
		updNote.lyric = lryA
		updNote.phLock = 0
		retCode = VSUpdateNoteEx(updNote);
		if (retCode ~= 1) then
			VSMessageBox("変更できませんでした", 0)
			return 0
		end
	end
	if (prsn == 1) then
		f = io.open(dirf.."EVEC_Change10.dat", "w")
		for idz = 0, 4 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
	return 0
end
