Advertisement
FichteFoll

Angel Beats! Insert 4 FX

Apr 5th, 2011
343
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.14 KB | None | 0 0
  1. -- This script is made by FichteFoll for Akatsuki-subs
  2. -- You can see this FX in Angel Beats episode 05 (BD version)
  3.  
  4. --[[
  5.     Remarks
  6. ]]
  7.  
  8. include("karaskel.lua")
  9.  
  10. script_name = "AB ins4 FX"
  11. script_description = "some effects"
  12. script_author = "FichteFoll"
  13. script_version = 1.0
  14.  
  15. -- ############################# handler funcs ##############################
  16.  
  17. function macro_script_handler(subs)
  18.     aegisub.progress.title(script_name);
  19.     script_handler(subs)
  20.     aegisub.set_undo_point("\""..script_name.."\"")
  21. end
  22.  
  23. function script_handler(subs)
  24.     aegisub.progress.task("Getting header data...")
  25.     generate_styles(subs)
  26.     local meta, styles = karaskel.collect_head(subs, false)
  27.  
  28.     undo_fx(subs)
  29.  
  30.     aegisub.progress.task("Applying effect...")
  31.     local i, maxi = 1, #subs
  32.     for i = 1, maxi do
  33.         if aegisub.progress.is_cancelled() then error("User cancelled") end
  34.         aegisub.progress.task(string.format("Applying effect (%d/%d)...", i, maxi))
  35.         aegisub.progress.set((i-1)/maxi*100)
  36.         local l = subs[i]
  37.  
  38.         if (l.class == "dialogue" and not l.comment) or (l.class == "dialogue" and l.comment and l.effect == "karaoke") then
  39.             do_fx(subs, meta, styles, l)
  40.             l.comment = true
  41.             l.effect = "karaoke"
  42.             subs[i] = l
  43.         end
  44.  
  45.         i = i + 1
  46.     end
  47.  
  48.     aegisub.progress.task("Finished!")
  49.     aegisub.progress.set(100)
  50. end
  51.  
  52.  
  53. function undo_macro_script_handler(subs)
  54.     aegisub.progress.title("Undo "..script_name);
  55.     undo_fx(subs)
  56.     aegisub.set_undo_point("\"Undo "..script_name.."\"")
  57. end
  58.  
  59. -- ############################# fx funcs ############################## -- action begins here
  60. local li = 0
  61. local sub_start, kanji_start = false, false
  62.  
  63. function do_fx(subs, meta, styles, baseline)
  64.     local line = table.copy(baseline)
  65.     li = li + 1
  66.  
  67.     -- variables
  68.     local fade_min, fade_max, fadein_accel = 700, 2000, 3
  69.     local _line = {
  70.                 fadein = {
  71.                     mindur = fade_min,
  72.                     maxdur = fade_max,
  73.                     accel = fadein_accel;
  74.                 },
  75.                 fadeout = {
  76.                     mindur = fade_min,
  77.                     maxdur = fade_max,
  78.                     accel = 1.0/fadein_accel;
  79.                 },
  80.                 color = {},
  81.                 alpha = {};
  82.             }
  83.     local _syl = {
  84.                 hl = {
  85.                     fadein = {
  86.                         dur = 50,
  87.                         accel = 0.4;
  88.                     };
  89.                     fadeout = {
  90.                         mindur = 800,
  91.                         multi = 1.5,
  92.                         ymulti = 3,
  93.                         movemulti = 6.0;
  94.                     };
  95.                 };
  96.                 start_off = 0,
  97.                 end_off = 0,
  98.                 noblank = {n = 0};
  99.             }
  100.  
  101.     for i, c, a in colors_from_style(styles[line.style]) do
  102.         _line.color[i] = c
  103.         _line.alpha[i] = a
  104.     end
  105.  
  106.     -- generate positions
  107.     if not kanji_start and line.style:find("kanji") then
  108.         kanji_start = true
  109.         li = 1
  110.     end
  111.     if not sub_start and line.style:find("english") then
  112.         sub_start = true
  113.         li = 1
  114.     end
  115.  
  116.     if (line.actor:find("overlay") and line.actor:find("start")) then li = li-1 end
  117.     local left = (li % 2 == 0)
  118.  
  119.     if not (line.style == "ins4_romaji" or line.style == "ins4_romaji-blue") then
  120.         if line.style:find("english") and not line.actor:find("bg") then left = not left; end
  121.  
  122.         if left then
  123.             line.style = line.style.."-left"
  124.         else
  125.             line.style = line.style.."-right"
  126.         end
  127.         if line.style:find("english") and not line.actor:find("bg") then left = not left; end -- reverse change to let syllables fly into the same direction
  128.     end
  129.  
  130.     local si = 0
  131.  
  132.     if (line.style:find("ins4_romaji") or line.style:find("ins4_kanji") or line.style:find("ins4_english")) then
  133.  
  134.         -- generate syls for non-karaoke part
  135.         if line.style:find("ins4_english") then
  136.             local ltext, ltext_stripped = "", strip_comments(line.text)
  137.             for word in ltext_stripped:words() do -- to generate positions for each word
  138.                 _syl.noblank.n = _syl.noblank.n + 1
  139.                 _syl.noblank[_syl.noblank.n] = string.format("{\\k1}%s ", word)
  140.                 ltext = string.format("%s{\\k1}%s ", ltext, word)
  141.             end
  142.             line.text = ltext
  143.         end
  144.  
  145.         -- karaoke
  146.         karaskel.preproc_line(subs, meta, styles, line)
  147.         line.effect = "fx" -- affects all copies from line
  148.         line.layer = 2
  149.  
  150.         for i = 1, line.kara.n do
  151.             local syl = line.kara[i]
  152.             if (syl.duration > 0 and syl.text_stripped ~= '' and syl.text_stripped ~= ' ') then
  153.                 _syl.noblank.n = _syl.noblank.n + 1
  154.                 _syl.noblank[_syl.noblank.n] = syl
  155.             end
  156.         end
  157.  
  158.  
  159.         -- For every syl
  160.         for i = 1, line.kara.n do
  161.             local syl = line.kara[i]
  162.  
  163.             if (syl.duration > 0 and syl.text_stripped ~= '' and syl.text_stripped ~= ' ') then
  164.                 si = si + 1
  165.                 local l
  166.  
  167.                 -- fade-in
  168.                 l = table.copy(line)
  169.                 local maxmovex, maxmovey = line.styleref.fontsize*3, -line.styleref.fontsize*3
  170.                 local minmovex, minmovey = line.styleref.fontsize, -line.styleref.fontsize
  171.                 if left then maxmovex = maxmovex * -1; minmovex = minmovex * -1; end
  172.  
  173.                 if not line.actor:find("start") then
  174.                     local temp, colnum = "{\\an5\\move(%%f,%%f,%%f,%%f)}{\\alpha&HFF&\\t(%f,\\1a%s\\3a%s\\4a%s)}{\\frx%%f\\fry%%f\\frz%%f\\t(\\frx0\\fry0\\frz0)}{\\c%s}%s", 2
  175.                     if line.style:find("ins4_english") then colnum = 1 end
  176.  
  177.                     temp = string.format(temp, _line.fadein.accel, _line.alpha[colnum], _line.alpha[3], _line.alpha[4], _line.color[colnum], syl.text_stripped)
  178.                     l.text = string.format(temp, line.left+syl.center + math.random()*(maxmovex-minmovex)+minmovex, line.middle + math.random()*(maxmovey-minmovey)+minmovey, line.left+syl.center, line.middle,
  179.                             math.random(-360,360), math.random(-360,360), math.random(-70,70))
  180.  
  181.                     l.start_time = line.start_time - math.random(_line.fadein.mindur, _line.fadein.maxdur)
  182.                     l.end_time = line.start_time
  183.                     subs.append(l)
  184.                 end
  185.  
  186.                 -- fade-out
  187.                 if not line.actor:find("end") then
  188.                     l = table.copy(line)
  189.                     minmovex = minmovex * -1; maxmovex = maxmovex * -1;
  190.                     minmovey = minmovey * -1; maxmovey = maxmovey * -1;
  191.  
  192.                     local temp = string.format("{\\an5\\move(%%f,%%f,%%f,%%f)}{\\t(%f,\\alpha&HFF&)}{\\t(\\frx%%f\\fry%%f\\frz%%f}%s", _line.fadein.accel, syl.text_stripped)
  193.                     l.text = string.format(temp, line.left+syl.center, line.middle,
  194.                             line.left+syl.center + math.random()*(maxmovex-minmovex)+minmovex, line.middle + math.random()*(maxmovey-minmovey)+minmovey,
  195.                             math.random(-360,360), math.random(-360,360), math.random(-70,70))
  196.  
  197.                     l.start_time = line.end_time
  198.                     l.end_time = line.end_time + math.random(_line.fadein.mindur, _line.fadein.maxdur)
  199.                     subs.append(l)
  200.                 end
  201.             end
  202.         end
  203.  
  204.         -- Highlight effect
  205.         local show, hide, temp = tonumber(line.actor:match("start:(%d+)")), tonumber(line.actor:match("end:(%d+)")), ""
  206.         if show and show > 0 then temp = string.format("{\\alpha&HFF&\\t(%d,%d,\\alpha&H00&)}", show, show) end
  207.         if hide and hide > 0 then temp = string.format("{\\t(%d,%d,\\alpha&HFF&)}", hide, hide) end
  208.  
  209.         if (line.style:find("ins4_romaji") or line.style:find("ins4_kanji")) then
  210.             l = table.copy(line)
  211.             l.text = string.format("{\\an5\\pos(%f,%f)}%s%s", line.center, line.middle, temp, line.text)
  212.             subs.append(l)
  213.         elseif line.style:find("ins4_english") then
  214.             l = table.copy(line)
  215.             l.text = string.format("{\\an5\\pos(%f,%f)}%s%s", line.center, line.middle, temp, baseline.text)
  216.             subs.append(l)
  217.         end
  218. --~         local l = table.copy(line)
  219. --~         if (line.style:find("ins4_romaji") or line.style:find("ins4_kanji")) then
  220. --~             subs.append(l)
  221. --~         end
  222.     end
  223. end
  224.  
  225. -- Collect and generate styles
  226. function generate_styles(subs)
  227.     local styles = {n = 0}
  228.     local toinsert = {}
  229.     local first_style_line, last_style_line = nil, nil
  230.  
  231.     -- First pass: collect all existing styles
  232.     for i = 1, #subs do
  233.         if aegisub.progress.is_cancelled() then error("User cancelled") end
  234.         local l = subs[i]
  235.         l.i = i
  236.  
  237.         if l.class == "style" and l.section == "[V4+ Styles]" then
  238.             if not first_style_line then first_style_line = i end
  239.             -- Store styles into the style table
  240.             styles.n = styles.n + 1
  241.             styles[styles.n] = l
  242.             styles[l.name] = l
  243.             l.margin_v = l.margin_t -- convenience
  244.  
  245.             -- Generate top-left and -right styles for all
  246.             if l.name:find("^ins4_") and (not l.name:find("-left$") and not l.name:find("-right$")) then
  247.                 local fxs = table.copy(l)
  248.                 fxs.align = 7
  249.                 fxs.name = fxs.name .. "-left"
  250.                 table.insert(toinsert, fxs) -- queue to insert in file
  251.  
  252.                 fxs = table.copy(l)
  253.                 fxs.align = 9
  254.                 fxs.name = fxs.name .. "-right"
  255.                 table.insert(toinsert, fxs) -- queue to insert in file
  256.             end
  257.  
  258.         elseif first_style_line and not last_style_line then
  259.             last_style_line = i
  260.         end
  261.     end
  262.  
  263.     -- Second pass: insert all toinsert styles that don't already exist
  264.     for i = 1, #toinsert do
  265.         if not styles[toinsert[i].name] then
  266.             -- Insert into styles table
  267.             styles.n = styles.n + 1
  268.             styles[styles.n] = toinsert[i]
  269.             styles[toinsert[i].name] = toinsert[i]
  270.             -- And subtitle file
  271.             subs[-(last_style_line)] = toinsert[i]
  272.         else
  273.             subs[styles[toinsert[i].name].i] = toinsert[i]
  274.         end
  275.     end
  276. end
  277.  
  278. function undo_fx(subs)
  279.     aegisub.progress.task("Unapplying effect...")
  280.  
  281.     local i, ai, maxi, maxai = 1, 1, #subs, #subs
  282.     while i <= maxi do
  283.         aegisub.progress.task(string.format("Unapplying effect (%d/%d)...", ai, maxai))
  284.         aegisub.progress.set((ai-1)/maxai*100)
  285.         local l = subs[i]
  286.         if (l.class == "dialogue" and not l.comment and l.effect == "fx") then
  287.             subs.delete(i)
  288.             maxi = maxi - 1
  289.         else
  290.             if (l.class == "dialogue" and l.comment and l.effect == "karaoke") then
  291.                 l.comment = false
  292.                 l.effect = ''
  293.                 subs[i] = l
  294.             end
  295.             i = i + 1
  296.         end
  297.     end
  298. end
  299.  
  300. -- ############################### helping funcs ##############################
  301.  
  302. function colors_from_style(style)
  303.     local i = 0
  304.     function enum_colors_from_style()
  305.         i = i + 1
  306.         if (i > 4) then
  307.             return nil
  308.         end
  309.  
  310.         return i, color_from_style(style["color"..tostring(i)]), alpha_from_style(style["color"..tostring(i)])
  311.     end
  312.  
  313.     return enum_colors_from_style, nil, nil
  314. end
  315.  
  316. function strip_comments(str)
  317.     return str:gsub("{.-}", "")
  318. end
  319.  
  320. -- ############################### validation funcs ##############################
  321.  
  322. function macro_validation(subs)
  323.     for i = 1, #subs do
  324.         local l = subs[i]
  325.         if (l.class == "dialogue" and not l.comment) or (l.class == "dialogue" and l.comment and l.effect == "karaoke") then
  326.             return true
  327.         end
  328.     end
  329.  
  330.     return false
  331. end
  332.  
  333. aegisub.register_filter(script_name, "", 2000, script_handler)
  334. aegisub.register_macro(script_name, "processing script as templater", macro_script_handler, macro_validation)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement