Advertisement
Guest User

a

a guest
Mar 6th, 2015
221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.97 KB | None | 0 0
  1. script_name = "Jitter"
  2. script_description = "Jitters selected lines."
  3. script_author = "Youka"
  4. script_version = "1.1"
  5. script_modified = "1st October 2012"
  6.  
  7. -- Frame duration in milliseconds
  8. local frame_dur = aegisub.video_size() and (aegisub.ms_from_frame(101)-aegisub.ms_from_frame(1)) / 100 or 41.71
  9.  
  10. --Deep table copy
  11. function table.copy(t1)
  12. local t2 = {}
  13. for i, v in pairs(t1) do
  14. if type(v) == "table" then
  15. t2[i] = table.copy(v)
  16. else
  17. t2[i] = v
  18. end
  19. end
  20. return t2
  21. end
  22.  
  23. --Iterator through frame times
  24. function frames(starts, ends, frame_time)
  25. local cur_start_time = starts
  26. local function next_frame()
  27. if cur_start_time >= ends then
  28. return nil
  29. end
  30. local return_start_time = cur_start_time
  31. local return_end_time = return_start_time + frame_time <= ends and return_start_time + frame_time or ends
  32. cur_start_time = return_end_time
  33. return return_start_time, return_end_time
  34. end
  35. return next_frame
  36. end
  37.  
  38. --Framework
  39. function frame_generator(subs, sel, step, filter)
  40. local function pos_replace(x, y)
  41. local x_add, y_add = filter()
  42. return "\\pos("..(x + x_add)..","..(y + y_add)..")"
  43. end
  44. local add = 0
  45. for _, i in ipairs(sel) do
  46. local sub = subs[i+add]
  47. for s, e in frames(sub.start_time, sub.end_time, frame_dur*step) do
  48. local line = table.copy(sub)
  49. line.start_time = s
  50. line.end_time = e
  51. line.text = line.text:gsub("\\pos%(%s*(%-?[0-9%.]+)%s*,%s*(%-?[0-9%.]+)%s*%)", pos_replace)
  52. subs.insert(i+add, line)
  53. add = add + 1
  54. end
  55. subs.delete(i+add)
  56. add = add - 1
  57. end
  58. end
  59.  
  60. --Random number filter
  61. function random_filter(x1, y1, x2, y2)
  62. local decimal_range = 8
  63. local xa, xb = math.floor( math.min(x1, x2) * decimal_range ), math.floor( math.max(x1, x2) * decimal_range )
  64. local ya, yb = math.floor( math.min(y1, y2) * decimal_range ), math.floor( math.max(y1, y2) * decimal_range )
  65. local function get_random()
  66. return math.random(xa, xb) / decimal_range, math.random(ya, yb) / decimal_range
  67. end
  68. return get_random
  69. end
  70.  
  71. --Random config
  72. local rnd_conf = {
  73. {
  74. class = "label",
  75. x = 0, y = 0, width = 1, height = 1,
  76. label = "X offset:"
  77. },
  78. {
  79. class = "label",
  80. x = 0, y = 1, width = 1, height = 1,
  81. label = "Y offset:"
  82. },
  83. {
  84. class = "label",
  85. x = 2, y = 0, width = 1, height = 1,
  86. label = " - "
  87. },
  88. {
  89. class = "label",
  90. x = 2, y = 1, width = 1, height = 1,
  91. label = " - "
  92. },
  93. {
  94. class = "floatedit", name = "x1",
  95. x = 1, y = 0, width = 1, height = 1,
  96. hint = "Random minimum horizontal offset", value = 0,
  97. step = 1
  98. },
  99. {
  100. class = "floatedit", name = "y1",
  101. x = 1, y = 1, width = 1, height = 1,
  102. hint = "Random minimum vertical offset", value = 0,
  103. step = 1
  104. },
  105. {
  106. class = "floatedit", name = "x2",
  107. x = 3, y = 0, width = 1, height = 1,
  108. hint = "Random maximum horizontal offset", value = 0,
  109. step = 1
  110. },
  111. {
  112. class = "floatedit", name = "y2",
  113. x = 3, y = 1, width = 1, height = 1,
  114. hint = "Random maximum vertical offset", value = 0,
  115. step = 1
  116. }
  117. }
  118.  
  119. --Random GUI
  120. function random_gui(subs, sel, step)
  121. aegisub.progress.title (script_name.." - Random")
  122. local button, conf = aegisub.dialog.display(rnd_conf,{"Run", "Cancel"})
  123. if button == "Run" then
  124. local filter = random_filter(conf.x1, conf.y1, conf.x2, conf.y2)
  125. frame_generator(subs, sel, step, filter)
  126. return true
  127. end
  128. return false
  129. end
  130.  
  131. --Position select filter
  132. function selection_filter(t)
  133. local i = 0
  134. local function get_selection()
  135. i = i+1 <= #t and i+1 or 1
  136. return t[i][1], t[i][2]
  137. end
  138. return get_selection
  139. end
  140.  
  141. --Select config
  142. local function sel_conf()
  143. return {
  144. {
  145. class = "label",
  146. x = 1, y = 0, width = 1, height = 1,
  147. label = "X"
  148. },
  149. {
  150. class = "label",
  151. x = 2, y = 0, width = 1, height = 1,
  152. label = "Y"
  153. },
  154. {
  155. class = "label",
  156. x = 0, y = 1, width = 1, height = 1,
  157. label = "Offset 1"
  158. },
  159. {
  160. class = "floatedit", name = "x1",
  161. x = 1, y = 1, width = 1, height = 1,
  162. hint = "Horizontal offset", value = 0,
  163. step = 1
  164. },
  165. {
  166. class = "floatedit", name = "y1",
  167. x = 2, y = 1, width = 1, height = 1,
  168. hint = "Vertical offset", value = 0,
  169. step = 1
  170. }
  171. }
  172. end
  173.  
  174. --Select GUI
  175. function add_offset(config)
  176. if #config < (2 + 3 * 30) then
  177. local index = (#config - 2) / 3 + 1
  178. table.insert(config, {
  179. class = "label",
  180. x = 0, y = index, width = 1, height = 1,
  181. label = "Offset "..index
  182. })
  183. table.insert(config, {
  184. class = "floatedit", name = "x"..index,
  185. x = 1, y = index, width = 1, height = 1,
  186. hint = "Horizontal offset", value = 0,
  187. step = 1
  188. })
  189. table.insert(config, {
  190. class = "floatedit", name = "y"..index,
  191. x = 2, y = index, width = 1, height = 1,
  192. hint = "Vertical offset", value = 0,
  193. step = 1
  194. })
  195. end
  196. end
  197.  
  198. function remove_offset(config)
  199. if #config > (5) then
  200. for i = 1, 3 do
  201. table.remove(config)
  202. end
  203. end
  204. end
  205.  
  206. function select_gui(subs, sel, step)
  207. aegisub.progress.title (script_name.." - Select")
  208. local config = sel_conf()
  209. local button, tokens
  210. repeat
  211. button, tokens = aegisub.dialog.display(config,{"Run", "Add offset", "Remove offset", "Cancel"})
  212. for _, component in ipairs(config) do
  213. for key, val in pairs(tokens) do
  214. if component.name and key == component.name then
  215. component.value = val
  216. end
  217. end
  218. end
  219. if button == "Add offset" then add_offset(config) end
  220. if button == "Remove offset" then remove_offset(config) end
  221. until button == "Run" or button == "Cancel"
  222. if button == "Run" then
  223. local table_max = 0
  224. for _, _ in pairs(tokens) do
  225. table_max = table_max + 1
  226. end
  227. local positions = {}
  228. for i = 1, table_max/2 do
  229. table.insert(positions, {tokens["x"..i], tokens["y"..i]})
  230. end
  231. local filter = selection_filter(positions)
  232. frame_generator(subs, sel, step, filter)
  233. return true
  234. end
  235. return false
  236. end
  237.  
  238. --Switch config
  239. local switch_conf = {
  240. {
  241. class = "label",
  242. x = 0, y = 0, width = 1, height = 1,
  243. label = "Framesteps:"
  244. },
  245. {
  246. class = "intedit", name = "step",
  247. x = 1, y = 0, width = 1, height = 1,
  248. hint = "How many frames to next position?",
  249. value = 1, min = 1
  250. }
  251. }
  252.  
  253. --Switch GUI
  254. function switch_gui(subs, sel)
  255. aegisub.progress.title (script_name)
  256. aegisub.progress.set(0)
  257. local button, conf = aegisub.dialog.display(switch_conf,{"Random", "Select"})
  258. if button == "Random" then
  259. if random_gui(subs, sel, conf.step) then
  260. aegisub.set_undo_point("\""..script_name.."\"")
  261. end
  262. elseif button == "Select" then
  263. if select_gui(subs, sel, conf.step) then
  264. aegisub.set_undo_point("\""..script_name.."\"")
  265. end
  266. end
  267. end
  268.  
  269. --Test for lines with 0 frames
  270. function test_null_frames(subs, sel)
  271. for i, si in ipairs(sel) do
  272. local sub = subs[si]
  273. if (math.ceil((sub.end_time - sub.start_time) / frame_dur) < 1) then
  274. return false
  275. end
  276. end
  277. return true
  278. end
  279.  
  280. --Register macro in aegisub
  281. aegisub.register_macro(script_name, script_description, switch_gui, test_null_frames)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement