forked from mia/Aegisub
6dcb5ff4a8
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.
314 lines
12 KiB
Text
314 lines
12 KiB
Text
--[[
|
|
Copyright (c) 2005, Niels Martin Hansen
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
* Neither the name of the Aegisub Group nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
]]
|
|
|
|
-- Aegisub Automation include file
|
|
-- This file is meant as a support file for the various karaoke skeleton
|
|
-- scripts, to avoid including unneeded code
|
|
|
|
include("utils.auto3")
|
|
|
|
-- karaskel
|
|
-- This is a gloabl table defining various parameters, controlling what the
|
|
-- skeleton will do. Not all parameters are defined in this base.
|
|
karaskel = {
|
|
-- Does this script need positioning information?
|
|
engage_positioning = false,
|
|
-- Syllable precalc parameters
|
|
precalc_start_progress = 0, -- progress precalc starts at
|
|
precalc_end_progress = 50, -- and where it ends at
|
|
-- Does this script use furigana information? (has no effect without positioning)
|
|
engage_furigana = false,
|
|
-- Furigana parameters
|
|
furigana_scale = 0.4, -- relative size of furigana
|
|
-- Default effect-name for inline effects (read manual)
|
|
inline_fx_default = "regular",
|
|
-- Set this to the name of the style used for out-of-line effect specifications, if any (read manual on this!)
|
|
ool_fx_style = false,
|
|
-- Show tracing messages?
|
|
engage_trace = true
|
|
}
|
|
|
|
function karaskel.warning(s)
|
|
aegisub.output_debug("WARNING! " .. s)
|
|
end
|
|
|
|
function karaskel.trace(s)
|
|
if karaskel.engage_trace then
|
|
aegisub.output_debug(s)
|
|
else
|
|
-- A little optimisation
|
|
karaskel.trace = function() end
|
|
end
|
|
end
|
|
|
|
-- precalc_syllable_data
|
|
-- Adds various extra fields to the line and syllable tables
|
|
-- See the implementation and/or Aegisub help file for more information
|
|
function karaskel.precalc_syllable_data(meta, styles, lines)
|
|
karaskel.trace("precalc_syllable_data")
|
|
aegisub.set_status("Preparing syllable-data")
|
|
|
|
-- Fix missing resolution data
|
|
if meta.res_x == 0 and meta_res_y == 0 then
|
|
meta.res_x = 384
|
|
meta.res_y = 288
|
|
elseif meta.res_x == 0 then
|
|
-- This is braindead, but it's how TextSub does things...
|
|
if meta.res_y == 1024 then
|
|
meta.res_x = 1280
|
|
else
|
|
meta.res_x = meta.res_y / 3 * 4
|
|
end
|
|
elseif meta.res_y == 0 then
|
|
-- As if 1280x960 didn't exist
|
|
if meta.res_x == 1280 then
|
|
meta.res_y = 1024
|
|
else
|
|
meta.res_y = meta.res_x * 3 / 4
|
|
end
|
|
end
|
|
|
|
for i = 0, lines.n-1 do
|
|
karaskel.trace("precalc_syllable_data:2:"..i)
|
|
aegisub.report_progress(karaskel.precalc_start_progress + i/lines.n*(karaskel.precalc_end_progress-karaskel.precalc_start_progress))
|
|
local line, style = lines[i]
|
|
-- Index number of the line
|
|
line.i = i
|
|
-- Linked list-style access
|
|
line.prev = lines[i-1]
|
|
line.next = lines[i+1]
|
|
karaskel.trace("precalc_syllable_data:3:")
|
|
if line.kind == "dialogue" or line.kind == "comment" then
|
|
karaskel.trace("precalc_syllable_data:4:")
|
|
local style = styles[line.style]
|
|
if not style then
|
|
-- ok, so the named style does not exist... well there MUST be at least ONE style (assume this)
|
|
-- pick the first one
|
|
style = styles[0]
|
|
karaskel.warning(string.format("You have a line using a style named \"%s\", but that style does not exist! Using the first defined style (\"%s\") instead.", line.style, style.name))
|
|
end
|
|
if karaskel.engage_furigana then
|
|
karaskel.split_furigana_data(line)
|
|
line.text_stripped = ""
|
|
for k = 0, line.karaoke.n-1 do
|
|
line.text_stripped = line.text_stripped .. line.karaoke[k].text_stripped
|
|
end
|
|
end
|
|
-- This should make things more predictable
|
|
line.text_stripped = trim(line.text_stripped)
|
|
if karaskel.engage_positioning then
|
|
-- Line dimensions
|
|
line.width, line.height, line.ascent, line.extlead = aegisub.text_extents(style, line.text_stripped)
|
|
karaskel.trace(string.format("precalc_syllable_data:5: text_stripped='%s', width=%d", line.text_stripped, line.width))
|
|
-- Line position
|
|
line.centerleft = math.floor((meta.res_x - line.width) / 2)
|
|
line.centerright = meta.res_x - line.centerleft
|
|
end
|
|
-- Line duration, in miliseconds
|
|
line.duration = (line.end_time - line.start_time) * 10
|
|
-- Style reference
|
|
line.styleref = style
|
|
karaskel.trace("precalc_syllable_data:6:")
|
|
-- Process the syllables
|
|
local curtime = 0
|
|
local sumtext = ""
|
|
local inline_fx = karaskel.inline_fx_default
|
|
for j = 0, line.karaoke.n-1 do
|
|
karaskel.trace("precalc_syllable_data:7::"..j)
|
|
local syl = line.karaoke[j]
|
|
-- Syllable index
|
|
syl.i = j
|
|
-- Check for inline-effect
|
|
karaskel.trace("testing for inline_fx in: " .. syl.text)
|
|
local a, b, new_inline_fx = string.find(syl.text, "{%\\?%-(.*)}")
|
|
if new_inline_fx then
|
|
karaskel.trace("caught new inline_fx: " .. new_inline_fx)
|
|
inline_fx = new_inline_fx
|
|
end
|
|
syl.inline_fx = inline_fx
|
|
-- Do positioning calculations, if applicable
|
|
sumtext = sumtext .. syl.text_stripped
|
|
karaskel.trace("new sumtext = " .. sumtext)
|
|
if karaskel.engage_positioning then
|
|
-- Summed text dimensions
|
|
local sumwidth = aegisub.text_extents(style, sumtext)
|
|
karaskel.trace("sumwidth = " .. sumwidth)
|
|
-- Strip some spaces
|
|
local tmp1, tmp2, prespc, syltxt, postspc = string.find(syl.text_stripped, "^([ \t]*)(.-)([ \t]*)$")
|
|
-- Pre/post space dimensions
|
|
local prespc_width = aegisub.text_extents(style, prespc)
|
|
local postspc_width = aegisub.text_extents(style, postspc)
|
|
karaskel.trace("space capture lengths = " .. string.len(prespc) .. ", " .. string.len(syltxt) .. ", " .. string.len(postspc))
|
|
karaskel.trace("space widths = " .. prespc_width .. ", " .. postspc_width)
|
|
-- Syllable dimensions
|
|
syl.width, syl.height, syl.ascent, syl.extlead = aegisub.text_extents(style, syltxt)
|
|
karaskel.trace("syllable text, width = " .. syltxt .. ", " .. syl.width)
|
|
karaskel.trace("precalc_syllable_data:8::")
|
|
-- Syllable positioning
|
|
syl.right = sumwidth - postspc_width
|
|
syl.left = sumwidth - syl.width + prespc_width
|
|
syl.center = math.floor(syl.left + (syl.right - syl.left) / 2)
|
|
karaskel.trace("syllable left, center, right = " .. syl.left .. ", " .. syl.center .. ", " .. syl.right)
|
|
if syl.furigana then
|
|
karaskel.calc_furigana_sizes(line, syl)
|
|
end
|
|
end
|
|
-- Start and end times in miliseconds
|
|
syl.start_time = curtime
|
|
syl.end_time = curtime + syl.duration*10
|
|
curtime = syl.end_time
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Rebuild the entire karaoke data list, splitting out and adding furigana data
|
|
-- This also does joining of syllables with "#" as text
|
|
-- (Joining of furigana syllables with # as text seems useless for now, so it's not done.)
|
|
function karaskel.split_furigana_data(line)
|
|
if line.kind ~= "dialogue" then
|
|
karaskel.trace("skipping line, not dialogue")
|
|
return
|
|
end
|
|
karaskel.trace("split_furigana_data:1")
|
|
line.furigana = {n=0}
|
|
local newkara = {n=0}
|
|
local curtime = 0
|
|
for i = 0, line.karaoke.n-1 do
|
|
karaskel.trace("split_furigana_data:2:"..i)
|
|
local syl = line.karaoke[i]
|
|
local a, b, maintext, furitext = string.find(syl.text_stripped, "^(.*)|(.*)$")
|
|
if not maintext then
|
|
maintext = syl.text_stripped
|
|
end
|
|
karaskel.trace("split_furigana_data:3:"..i..":"..maintext)
|
|
local highlight = { duration = syl.duration, start_time = curtime*10, end_time = curtime*10+syl.duration*10 }
|
|
curtime = curtime + syl.duration
|
|
if maintext == "#" then
|
|
karaskel.trace("split_furigana_data:4:"..i..":a")
|
|
-- repeat character
|
|
newkara[newkara.n-1].duration = newkara[newkara.n-1].duration + syl.duration
|
|
syl = newkara[newkara.n-1]
|
|
else
|
|
karaskel.trace("split_furigana_data:4:"..i..":b")
|
|
syl.furigana = {n=0, text=""} -- essentially a list of syllables in the syllable :o
|
|
syl.highlights = {n=0}
|
|
syl.text_stripped = maintext
|
|
newkara[newkara.n] = syl
|
|
newkara.n = newkara.n + 1
|
|
end
|
|
karaskel.trace("split_furigana_data:5:"..i)
|
|
syl.highlights[syl.highlights.n] = highlight
|
|
syl.highlights.n = syl.highlights.n + 1
|
|
if a then
|
|
karaskel.trace("split_furigana_data:6:"..i)
|
|
local furi = { text = furitext, duration = highlight.duration, start_time = highlight.start_time, end_time = highlight.end_time }
|
|
syl.furigana[syl.furigana.n] = furi
|
|
syl.furigana.n = syl.furigana.n + 1
|
|
syl.furigana.text = syl.furigana.text .. furitext
|
|
end
|
|
end
|
|
line.karaoke = newkara
|
|
end
|
|
|
|
function karaskel.calc_furigana_sizes(line, syl)
|
|
-- assume the sizes for the main syllable itself has been calculated already
|
|
local ls = line.styleref
|
|
local style = { -- only copy what's needed for text_extents
|
|
fontname = ls.fontname,
|
|
fontsize = ls.fontsize * karaskel.furigana_scale,
|
|
bold = ls.bold,
|
|
italic = ls.italic,
|
|
underline = ls.underline,
|
|
strikeout = ls.strikeout,
|
|
scale_x = ls.scale_x,
|
|
scale_y = ls.scale_y,
|
|
spacing = ls.spacing,
|
|
encoding = ls.encoding
|
|
}
|
|
syl.furigana.width, syl.furigana.height = aegisub.text_extents(style, syl.furigana.text)
|
|
syl.furigana.scale = syl.width / syl.furigana.width * 100
|
|
syl.furigana.fontsize = style.fontsize
|
|
if syl.furigana.scale > 100 then
|
|
syl.furigana.scale = 100
|
|
else
|
|
syl.furigana.width = syl.width
|
|
end
|
|
style.scale_x = style.scale_x * syl.furigana.scale / 100
|
|
local left = syl.left + (syl.width - syl.furigana.width)/2
|
|
for i = 0, syl.furigana.n-1 do
|
|
local f = syl.furigana[i]
|
|
f.width, f.height = aegisub.text_extents(style, f.text)
|
|
f.left = left
|
|
f.center = f.left + f.width/2
|
|
f.right = f.left + f.width
|
|
left = f.right
|
|
end
|
|
end
|
|
|
|
-- Everything else is done in the process_lines function
|
|
function karaskel.process_lines(meta, styles, lines, config)
|
|
karaskel.trace("new skeleton")
|
|
karaskel.trace("skel_process_lines")
|
|
-- Do a little pre-calculation for each line and syllable
|
|
karaskel.precalc_syllable_data(meta, styles, lines)
|
|
karaskel.trace("skel_process_lines:2")
|
|
-- A var for the new output
|
|
local result = {n=0}
|
|
local ool_fx = {}
|
|
aegisub.set_status("Running main-processing")
|
|
-- Now do the usual processing
|
|
for i = 0, lines.n-1 do
|
|
karaskel.trace("skel_process_lines:3:"..i)
|
|
aegisub.report_progress(50+i/lines.n*50)
|
|
if (lines[i].kind == "dialogue" or lines[i].kind == "comment") and lines[i].style == karaskel.ool_fx_style then
|
|
karaskel.trace("skel_process_lines: parsing ool fx: " .. lines[i].text)
|
|
local fx = {}
|
|
fx.head, fx.tail = string.headtail(lines[i].text)
|
|
karaskel.trace("--- head: '" .. fx.head .. "'")
|
|
karaskel.trace("--- tail: '" .. fx.tail .. "'")
|
|
fx.line = lines[i]
|
|
fx.start_time, fx.end_time = fx.line.start_time, fx.line.end_time
|
|
ool_fx[fx.head] = fx
|
|
else
|
|
-- Get replacement lines
|
|
lines[i].ool_fx = ool_fx
|
|
repl = do_line(meta, styles, config, lines[i])
|
|
karaskel.trace("skel_process_lines:4:"..i..":"..repl.n)
|
|
-- Append to result table
|
|
for j = 1, repl.n do
|
|
result.n = result.n + 1
|
|
result[result.n] = repl[j]
|
|
end
|
|
end
|
|
end
|
|
-- Done, return the stuff
|
|
return result
|
|
end
|
|
process_lines = karaskel.process_lines
|