2006-02-23 22:56:46 +01:00
--[[
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.lua " )
-- 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 = false
}
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 " )
2006-02-24 22:35:36 +01:00
-- 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...
2006-03-12 21:32:25 +01:00
if meta.res_y == 1024 then
2006-02-24 22:35:36 +01:00
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
2006-02-23 22:56:46 +01:00
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
2006-02-24 22:35:36 +01:00
-- ok, so the named style does not exist... well there MUST be at least ONE style (assume this)
2006-02-23 22:56:46 +01:00
-- 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
2006-02-24 00:26:32 +01:00
line.text_stripped = line.text_stripped .. line.karaoke [ k ] . text_stripped
2006-02-23 22:56:46 +01:00
end
end
2006-02-24 22:35:36 +01:00
-- This should make things more predictable
line.text_stripped = trim ( line.text_stripped )
2006-02-23 22:56:46 +01:00
if karaskel.engage_positioning then
-- Line dimensions
line.width , line.height , line.ascent , line.extlead = aegisub.text_extents ( style , line.text_stripped )
2006-02-24 22:35:36 +01:00
karaskel.trace ( string.format ( " precalc_syllable_data:5: text_stripped='%s', width=%d " , line.text_stripped , line.width ) )
2006-02-23 22:56:46 +01:00
-- 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
2006-02-24 00:26:32 +01:00
local curtime = 0
local sumtext = " "
2006-02-23 22:56:46 +01:00
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
2006-02-24 00:26:32 +01:00
sumtext = sumtext .. syl.text_stripped
2006-03-12 21:32:25 +01:00
karaskel.trace ( " new sumtext = " .. sumtext )
2006-02-23 22:56:46 +01:00
if karaskel.engage_positioning then
2006-02-24 00:26:32 +01:00
-- Summed text dimensions
local sumwidth = aegisub.text_extents ( style , sumtext )
2006-03-12 21:32:25 +01:00
karaskel.trace ( " sumwidth = " .. sumwidth )
2006-02-24 22:35:36 +01:00
-- Strip some spaces
2006-03-12 21:32:25 +01:00
local tmp1 , tmp2 , prespc , syltxt , postspc = string.find ( syl.text_stripped , " ^([ \t ]*)(.-)([ \t ]*)$ " )
2006-02-24 22:35:36 +01:00
-- Pre/post space dimensions
local prespc_width = aegisub.text_extents ( style , prespc )
local postspc_width = aegisub.text_extents ( style , postspc )
2006-03-12 21:32:25 +01:00
karaskel.trace ( " space capture lengths = " .. string.len ( prespc ) .. " , " .. string.len ( syltxt ) .. " , " .. string.len ( postspc ) )
karaskel.trace ( " space widths = " .. prespc_width .. " , " .. postspc_width )
2006-02-23 22:56:46 +01:00
-- Syllable dimensions
2006-02-24 22:35:36 +01:00
syl.width , syl.height , syl.ascent , syl.extlead = aegisub.text_extents ( style , syltxt )
2006-03-12 21:32:25 +01:00
karaskel.trace ( " syllable text, width = " .. syltxt .. " , " .. syl.width )
2006-02-23 22:56:46 +01:00
karaskel.trace ( " precalc_syllable_data:8:: " )
-- Syllable positioning
2006-02-24 22:35:36 +01:00
syl.right = sumwidth - postspc_width
syl.left = sumwidth - syl.width + prespc_width
syl.center = math.floor ( syl.left + ( syl.right - syl.left ) / 2 )
2006-03-12 21:32:25 +01:00
karaskel.trace ( " syllable left, center, right = " .. syl.left .. " , " .. syl.center .. " , " .. syl.right )
2006-02-23 22:56:46 +01:00
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
local fx = { }
fx.head , fx.tail = string.headtail ( lines [ i ] )
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 )
-- Append to result table
for j = 1 , repl.n do
table.insert ( result , repl [ j ] )
end
ool_fx = { }
end
end
-- Done, return the stuff
return result
end
process_lines = karaskel.process_lines