Aegisub/automation/demos/auto3/7-advanced-effect.lua
Niels Martin Hansen 6dcb5ff4a8 Runtime errors in auto3 scripts no longer kill the program but are reported properly instead.
Apparently Lua 5.1 has changed the semantics of table.insert so it's incompatible with the way used in all Auto3 demo scripts etc. Now it's overridden in utils.auto3 and all instances of it in sample scripts etc. replaced with code having the expected behaviour.

Originally committed to SVN as r926.
2007-02-06 12:30:17 +00:00

201 lines
7.8 KiB
Lua

-- Aegisub Automation demonstration script
-- Original written by Niels Martin Hansen
-- Given into the public domain
-- But still, please don't use the effect generated by this script
-- (unchanged) for your own works.
-- Note that many of the techniques used in this script are heavily deprecated, much of the processing done
-- is also done by the karaskel scripts.
-- In fact, this can almost be viewed as an example of how *not* to do things...
-- Since this script assumes some rather specific things about the ASS input, it might not be very useful at first.
-- The original ASS file this was written for is available upon request.
include("utils.lua")
name = "Advanced karaoke effect"
description = "An advanced karaoke effect, making heavy use of both line-copying and per-syllable text placement. Also demonstrates how to treat lines differently, based on their style, and syllables differently based on the timing tag used."
version, kind, configuration = 3, 'basic_ass', {}
function process_lines(meta, styles, lines, config)
local output = { n=0 }
math.randomseed(5922) -- just to make sure it's initialised the same every time
for curline = 0, lines.n-1 do
aegisub.report_progress(curline/lines.n*100)
local lin = lines[curline]
if lin.kind == "dialogue" and lin.style == "op romaji" then
doromaji(lin, output, styles["op romaji"], 30)
elseif lin.kind == "dialogue" and lin.style == "op kanji" then
-- Just one of these lines should be uncommented.
-- This script was written before configuration worked, otherwise it would use configuration
-- to select which of the two effects to use for "op kanji" style lines.
--doromaji(lin, output, styles["op kanji"], 20)
dokanji(lin, output, styles["op kanji"])
else
-- Unknown lines are copied verbatim
output.n = output.n + 1
output[output.n] = lin
end
end
return output
end
function doromaji(lin, output, sty, linetop)
aegisub.set_status(lin.text_stripped)
--local linetop = 50
-- prepare syllable data
local linewidth = 0
local syltime = 0
local syls = {n=0}
for i = 1, lin.karaoke.n-1 do
local syl = lin.karaoke[i]
syl.width, syl.height, syl.descent, syl.extlead = aegisub.text_extents(sty, syl.text_stripped)
syl.left = linewidth
syl.start_time = syltime
syl.end_time = syltime + syl.duration
syltime = syltime + syl.duration
if syl.kind == "kf" and (syl.text == " " or syl.text == " ") then
-- The font this effect was made to work with has too wide spaces, so make those half width
syl.width = math.floor(syl.width / 2)
syl.kind = "space"
elseif syl.kind == "kf" then
syl.kind = "deco"
elseif syl.kind == "k" then
syl.kind = "reg"
elseif syl.kind == "ko" then
syl.kind = "dance"
else
syl.kind = "ignore"
end
if syl.text == "#" then
syls[syls.n-1].duration = syls[syls.n-1].duration + syl.duration
syls[syls.n-1].end_time = syls[syls.n-1].end_time + syl.duration
else
linewidth = linewidth + syl.width
syls[syls.n] = syl
syls.n = syls.n + 1
end
end
local lineofs = math.floor((640 - linewidth) / 2)
for i = 0, syls.n-1 do
local syl = syls[i], copy_line(lin)
if syl.kind == "space" then
-- Spaces are skipped. Since the width of them is already incorporated in the position calculations
-- for the following syllables, they can safely be stripped from output, without losing the spaces.
elseif syl.kind == "ignore" then
-- These are actually syllable kinds we don't know what to do about. They are not included in the output.
else
local startx, starty, shakex, shakey, enterangle
-- angle to enter from
enterangle = math.rad((180 / lin.karaoke.n) * i - 90)
-- position to enter from (350 pixels from (320, 50))
startx = math.sin(enterangle)*350 + 320
starty = linetop - math.cos(enterangle)*350
if syl.kind == "reg" then
shakex = (syl.left+lineofs) + math.random(-5, 5)
shakey = linetop + math.random(-5, 5)
elseif syl.kind == "deco" then
shakex, shakey = syl.left+lineofs, linetop
elseif syl.kind == "dance" then
shakex = (syl.left+lineofs) + math.random(-5, 5)
shakey = linetop + math.random(-5, 5)
end
-- origin for rotation
local orgx = syl.left + lineofs + syl.width/2
local orgy = linetop + syl.height/2
-- entry effect
local enterlin = copy_line(lin)
enterlin.start_time = lin.start_time - 40
enterlin.end_time = lin.start_time
enterlin.text = string.format("{\\move(%d,%d,%d,%d)\\fr%d\\t(\\fr0)\\an7}%s", startx, starty, shakex, shakey, -math.deg(enterangle), syl.text)
output.n = output.n + 1
output[output.n] = enterlin
-- main highlight effect
local newlin = copy_line(lin)
local hilistart, hilimid, hiliend = syl.start_time*10, (syl.start_time+syl.duration/2)*10, (syl.start_time+syl.duration)*10
newlin.text = string.format("\\move(%d,%d,%d,%d,%d,%d)\\an7}%s", shakex, shakey, syl.left+lineofs, linetop, hilistart, hiliend, syl.text)
newlin.layer = 1
if syl.kind == "dance" then
local fx = string.format("\\org(%d,%d)\\t(%d,%d,\\fr30)\\t(%d,%d,\\fr-30)\\t(%d,%d,\\3c&H0000ff&)\\t(%d,%d,\\3c&H000080&)\\t(%d,%d,\\fr0)", orgx, orgy, hilistart, hilistart+20, hilistart+20, hiliend, hilistart, hilimid, hilimid, hiliend, hiliend, hiliend+syl.duration*10)
newlin.text = fx .. newlin.text
else
local fx = string.format("\\t(%d,%d,\\3c&H0000ff&)\\t(%d,%d,\\3c&H000080&)", hilistart, hilimid, hilimid, hiliend)
newlin.text = fx .. newlin.text
end
local bord = copy_line(newlin)
bord.layer = 0
bord.text = "{" .. bord.text
newlin.text = "{\\bord0" .. newlin.text
output.n = output.n + 2
output[output.n-1] = bord
output[output.n] = newlin
-- leave effect
-- cut the line over in two, lower half "drops down", upper just fades away
local tophalf = copy_line(lin)
tophalf.start_time = lin.end_time
tophalf.end_time = lin.end_time + 100
tophalf.text = string.format("\\3c&H000080&\\fad(0,700)\\pos(%d,%d)\\an7}%s", syl.left+lineofs, linetop, syl.text_stripped)
local bottomhalf = copy_line(tophalf)
tophalf.text = string.format("{\\t(0,200,\\1c&H000080&)\\clip(0,0,640,%d)%s", linetop+syl.height/2, tophalf.text)
bottomhalf.text = string.format("{\\org(%d,%d)\\clip(0,%d,640,480)\\t(0,200,\\1c&H000080&)\\t(200,1000,1.2,\\frx90\\clip(0,%d,640,480)%s", 320, linetop+syl.height, linetop+syl.height/2, linetop+syl.height, bottomhalf.text)
output.n = output.n + 2
output[output.n-1] = tophalf
output[output.n] = bottomhalf
end
end
end
function dokanji(lin, output, sty)
aegisub.set_status(lin.text_stripped)
local fontname = "@HGSHigemoji"
local lineheight = 0
local syltime = 0
local syls = {n=0}
for i = 1, lin.karaoke.n-1 do
local syl = lin.karaoke[i]
syl.height, syl.width, syl.descent, syl.extlead = aegisub.text_extents(sty, syl.text_stripped)
syl.start_time = syltime
syl.end_time = syltime + syl.duration
syltime = syltime + syl.duration
if syl.text == "#" then
syls[syls.n-1].duration = syls[syls.n-1].duration + syl.duration
syls[syls.n-1].end_time = syls[syls.n-1].end_time + syl.duration
--elseif syl.text == "" then
-- skip
else
lineheight = lineheight + syl.height
syls[syls.n] = syl
syls.n = syls.n + 1
end
end
for i = 0, syls.n-1 do
local syl = syls[i]
local top = 170
for j = 0, 8 do
if i+j >= syls.n then
break
end
local newlin = copy_line(lin)
newlin.start_time = lin.start_time + syl.start_time
newlin.end_time = newlin.start_time + syl.duration
local startalpha, targetalpha
if j == 0 then
startalpha = 0
targetalpha = 255
else
startalpha = j * 255 / 8
targetalpha = (j-1) * 255 / 8
end
newlin.text = string.format("{\\fn%s\\an7\\fr-90\\move(%d,%d,%d,%d)\\1a&H%2x&\\3a&H%2x&\\t(\\1a&H%2x&\\3a&H%2x&)}%s", fontname, 620, top, 620, top-syl.height, startalpha, startalpha, targetalpha, targetalpha, syls[i+j].text)
top = top + syls[i+j].height
output.n = output.n + 1
output[output.n] = newlin
end
end
end