Synthesizer V Pro(琴葉茜・葵)でAIきりたんを真似るスクリプト
投稿:2020-08-15
前回のスクリプト作成で当初の目標だった「AIきりたんのように歌う」というのが失敗に終わり、とりあえずピッチをシフトするスクリプトを作りました。
Synthesizer V Proのスクリプトを作った
AIきりたんは音声合成をする際にbapファイル、f0ファイル、mgcファイルも生成します。 f0はピッチ、mgcは声量が含まれているようです。 f0ファイルをSynthesizerV Proのピッチベンド、mgcファイルをラウドネスに設定すればAIきりたんのように歌ってくれるのではないかと考えました。
真似をするスクリプトを作りました。
-- AIきりたんの真似
local plugin_name = "AIきりたんの真似(Lua)"
local timeout = 100
function getClientInfo()
return {
name = plugin_name,
category = "AIきりたん",
author = "lemorin_jp",
versionNumber = 1,
minEditorVersion = 0
}
end
function main()
-- ダイアログの内容
local myForm = {
title = plugin_name,
message = "ファイルのフルパス(Windowsは漢字NG)",
buttons = "OkCancel",
widgets = {
{
name = "f0file",
type = "TextBox",
label = "f0",
default = "sample.f0"
},
{
name = "mgcfile",
type = "TextBox",
label = "mgc",
default = "sample.mgc"
},
}
}
-- ダイアログ表示(モーダル)
local is_valid = false
while not is_valid do
local result = SV:showCustomDialog(myForm)
if not result.status then break end
-- Okならダイアログの設定をグローバル変数へ
f0file = result.answers.f0file
mgcfile = result.answers.mgcfile
is_valid = validate(f0file, mgcfile)
if is_valid then break end
myForm.widgets[1].default = f0file
myForm.widgets[2].default = mgcfile
end
if is_valid then
-- 後でkiritanを開始
SV:setTimeout(timeout, kiritan)
else
-- スクリプト終了
SV:finish()
end
end
function validate(f0, mgc)
if not string.match(f0, "^[:\\%a]+%.f0$") then
SV:showMessageBox(plugin_name, "f0ファイルではありません\n" .. f0)
return false
end
local fh = io.open(f0, "rb")
if not fh then
SV:showMessageBox(plugin_name, "f0ファイルを開けません\n" .. f0)
return false
end
fh:close()
if not string.match(mgc, "^[:\\%a]+%.mgc$") then
SV:showMessageBox(plugin_name, "mgcファイルではありません\n" .. mgc)
return false
end
fh = io.open(mgc, "rb")
if not fh then
SV:showMessageBox(plugin_name, "mgcファイルを開けません\n" .. mgcfile)
return false
end
fh:close()
return true
end
function kiritan()
track = SV:getMainEditor():getCurrentTrack()
-- トラックを検証
local notegroup = track:getGroupReference(1):getTarget()
local numnote = notegroup:getNumNotes()
if numnote < 2 then
SV:showMessageBox(plugin_name, "トラックに音符がありません")
-- スクリプト終了
SV:finish()
return
end
-- トラックの歌声をリセット
track:getGroupReference(1):setVoice({
tF0Left = 0,
tF0Right = 0,
dF0Left = 0,
dF0Right = 0,
tF0VbrStart = 0,
tF0VbrLeft = 0,
tF0VbrRight = 0,
dF0Vbr = 0,
fF0Vbr = 0,
paramLoudness = 0,
paramTension = 0,
paramBreathiness = 0,
paramGender = 0
})
-- トラックのノートのパラメータをリセット
local i
for i = 1, numnote do
notegroup:getNote(i):setAttributes({
tF0Offset = 0,
tF0Left = 0,
tF0Right = 0,
dF0Left = 0,
dF0Right = 0,
tF0VbrStart = 0,
tF0VbrLeft = 0,
tF0VbrRight = 0,
dF0Vbr = 0,
pF0Vbr = 0,
fF0Vbr = 0,
tNoteOffset = 0
})
end
piano_roll = SV:getMainEditor():getNavigation()
-- 後でf0startを開始
SV:setTimeout(timeout, f0start)
end
function f0start()
trackAutomation = track:getGroupReference(1):getTarget():getParameter("Pitch Deviation")
trackAutomation:removeAll()
projectTimeAxis = SV:getProject():getTimeAxis()
trackNoteGroup = track:getGroupReference(1):getTarget()
numNote = trackNoteGroup:getNumNotes()
curFreq = SV:pitch2Freq(trackNoteGroup:getNote(1):getPitch())
nextIndex = 2
nextNote = trackNoteGroup:getNote(nextIndex)
blickNext = nextNote:getOnset()
blickLast = nextNote:getEnd()
nextFreq = SV:pitch2Freq(nextNote:getPitch())
msPos = 0
fh = io.open(f0file, "rb")
dbl = fh:read(8)
-- 後でf0progressを開始
SV:setTimeout(timeout, f0process)
end
function f0process()
-- 処理範囲を表示
disp_scroll(msPos)
-- 適当に5ms×100個分を処理
local i
for i = 1, 100 do
if not dbl then
break
end
local blick = projectTimeAxis:getBlickFromSeconds(msPos / 1000)
if blickNext <= blick then
curFreq = nextFreq
if nextIndex <= numNote then
nextNote = trackNoteGroup:getNote(nextIndex)
nextIndex = nextIndex + 1
blickNext = nextNote:getOnset()
blickLast = nextNote:getEnd()
nextFreq = SV:pitch2Freq(nextNote:getPitch())
elseif blickLast < blick then
dbl = nil
break
end
end
local f0 = string.unpack("<d", dbl)
if 0 ~= f0 then
trackAutomation:add(blick, 1200 * math.log(f0 / curFreq, 2.0))
else
trackAutomation:add(blick, 0)
end
dbl = fh:read(8)
msPos = msPos + 5
end
-- 未処理の時間がある?
if dbl then
-- 処理継続
SV:setTimeout(timeout, f0process)
else
-- 後でf0endを開始
SV:setTimeout(timeout, f0end)
end
end
function f0end()
fh:close()
-- 簡略化
trackAutomation:simplify(0, track:getDuration())
SV:showMessageBox(plugin_name, "ピッチベンドを更新しました")
-- 後でmgcstartを開始
SV:setTimeout(timeout, mgcstart)
end
function mgcstart()
trackAutomation = track:getGroupReference(1):getTarget():getParameter("loudness")
trackAutomation:removeAll()
fh = io.open(mgcfile, "rb")
is_end, mgc = read_mgc(fh)
msPos = 0
-- 後でmgcprocessを開始
SV:setTimeout(timeout, mgcprocess)
end
function mgcprocess()
-- 処理範囲を表示
disp_scroll(msPos)
-- 適当に5ms×100個分を処理
local i
for i = 1, 100 do
if 1 == is_end then
break
end
local blick = projectTimeAxis:getBlickFromSeconds(msPos / 1000)
mgc = (7 + mgc) / (48 - 7) * 48
if mgc < -48 then
mgc = -48
elseif 12 < mgc then
mgc = 12
end
trackAutomation:add(blick, mgc)
is_end, mgc = read_mgc(fh)
msPos = msPos + 5
end
-- 未処理の時間がある?
if 1 ~= is_end then
-- 処理継続
SV:setTimeout(timeout, mgcprocess)
else
-- 後でmgcendを開始
SV:setTimeout(timeout, mgcend)
end
end
function mgcend()
fh:close()
-- 簡略化
trackAutomation:simplify(0, track:getDuration())
SV:showMessageBox(plugin_name, "ラウドネスを更新しました")
-- トラックの先頭に戻る
disp_scroll(0)
-- 後でkiritanendを開始
SV:setTimeout(timeout, kiritanend)
end
function kiritanend()
-- スクリプト終了
SV:finish()
end
function read_mgc(fh)
local mgc = 0
local is_end = 0
local dbl = fh:read(8)
if not dbl then
is_end = 1
else
mgc = string.unpack("<d", dbl)
end
fh:read(8 * 59)
return is_end, mgc
end
function disp_scroll(msPos)
local disp_blick = projectTimeAxis:getBlickFromSeconds(msPos / 1000)
local range = piano_roll:getTimeViewRange()
if disp_blick < range[1] or range[2] < disp_blick then
piano_roll:setTimeLeft(disp_blick)
end
end
AIきりたんと同じ歌があるトラックを選択してから
メニュー「スクリプト|AIきりたん|AIきりたん(Lua)」を選択するとf0とmgcを指定するダイアログが表示されます。
それぞれフルパスで指定してください。
Windowsはパスにアルファベットを使ってください、漢字を使えません。
ボタン「確定」をクリックすると、トラックの歌声およびノートのプロパティをリセットして平坦な歌声にします。
続いてピッチベンドを設定、それからラウドネスを設定します。
設定には時間がかかるので、ピアノロールの設定している小節をスクロールしながら進めます。
ピアノロールのパラメータ(ピッチベンドとラウドネス)を表示させておくと、設定処理の経過が分かります。
表示されるダイアログ
AIきりたんのように歌う琴葉茜・葵さんです。
元の動画はこちらです。