日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

    歡迎訪問 生活随笔!

    生活随笔

    當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

    编程问答

    【Aegisub相关】卡拉OK模板执行环境和顺序

    發(fā)布時間:2023/12/14 编程问答 32 豆豆
    生活随笔 收集整理的這篇文章主要介紹了 【Aegisub相关】卡拉OK模板执行环境和顺序 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

    本頁描述了許多有關(guān) 卡拉OK模板執(zhí)行器(kara-templater) 的工作方式,并且會解釋為什么許多東西起作用,而另一些不起作用。

    大多數(shù)的細(xì)節(jié)你在卡拉OK模板執(zhí)行器中是不需要用到的,但是如果你在某些腳本中看到了你不理解的行為,那么本頁面可能會解釋它。

    注:Aegisub的代碼執(zhí)行環(huán)境具體實現(xiàn)對應(yīng)的源碼文件是kara-templater.lua,在這個文件中的第292行——function apply_templates(meta, styles, subs, templates)

    function apply_templates(meta, styles, subs, templates)的具體代碼如下:

    -- Apply the templates function apply_templates(meta, styles, subs, templates)-- the environment the templates will run inlocal tenv = {meta = meta,-- put in some standard libsstring = string,math = math,_G = _G}tenv.tenv = tenv-- Define helper functions in tenvtenv.retime = function(mode, addstart, addend)local line, syl = tenv.line, tenv.syllocal newstart, newend = line.start_time, line.end_timeaddstart = addstart or 0addend = addend or 0if mode == "syl" thennewstart = line.start_time + syl.start_time + addstartnewend = line.start_time + syl.end_time + addendelseif mode == "presyl" thennewstart = line.start_time + syl.start_time + addstartnewend = line.start_time + syl.start_time + addendelseif mode == "postsyl" thennewstart = line.start_time + syl.end_time + addstartnewend = line.start_time + syl.end_time + addendelseif mode == "line" thennewstart = line.start_time + addstartnewend = line.end_time + addendelseif mode == "preline" thennewstart = line.start_time + addstartnewend = line.start_time + addendelseif mode == "postline" thennewstart = line.end_time + addstartnewend = line.end_time + addendelseif mode == "start2syl" thennewstart = line.start_time + addstartnewend = line.start_time + syl.start_time + addendelseif mode == "syl2end" thennewstart = line.start_time + syl.end_time + addstartnewend = line.end_time + addendelseif mode == "set" or mode == "abs" thennewstart = addstartnewend = addendelseif mode == "sylpct" thennewstart = line.start_time + syl.start_time + addstart*syl.duration/100newend = line.start_time + syl.start_time + addend*syl.duration/100-- wishlist: something for fade-over effects,-- "time between previous line and this" and-- "time between this line and next"endline.start_time = newstartline.end_time = newendline.duration = newend - newstartreturn ""endtenv.fxgroup = {}tenv.relayer = function(layer)tenv.line.layer = layerreturn ""endtenv.restyle = function(style)tenv.line.style = styletenv.line.styleref = styles[style]return ""endtenv.maxloop = function(newmaxj)tenv.maxj = newmaxjreturn ""endtenv.maxloops = tenv.maxlooptenv.loopctl = function(newj, newmaxj)tenv.j = newjtenv.maxj = newmaxjreturn ""endtenv.recall = {}setmetatable(tenv.recall, {decorators = {},__call = function(tab, name, default)local decorator = getmetatable(tab).decorators[name]if decorator thenname = decorator(tostring(name))endaegisub.debug.out(5, "Recalling '%s'\n", name)return tab[name] or defaultend,decorator_line = function(name)return string.format("_%s_%s", tostring(tenv.orgline), name)end,decorator_syl = function(name)return string.format("_%s_%s", tostring(tenv.syl), name)end,decorator_basesyl = function(name)return string.format("_%s_%s", tostring(tenv.basesyl), name)end})tenv.remember = function(name, value, decorator)getmetatable(tenv.recall).decorators[name] = decoratorif decorator thenname = decorator(tostring(name))endaegisub.debug.out(5, "Remembering '%s' as '%s'\n", name, tostring(value))tenv.recall[name] = valuereturn valueendtenv.remember_line = function(name, value)return tenv.remember(name, value, getmetatable(tenv.recall).decorator_line)endtenv.remember_syl = function(name, value)return tenv.remember(name, value, getmetatable(tenv.recall).decorator_syl)endtenv.remember_basesyl = function(name, value)return tenv.remember(name, value, getmetatable(tenv.recall).decorator_basesyl)endtenv.remember_if = function(name, value, condition, decorator)if condition thenreturn tenv.remember(name, value, decorator)endreturn valueend-- run all run-once code snippetsfor k, t in pairs(templates.once) doassert(t.code, "WTF, a 'once' template without code?")run_code_template(t, tenv)end-- start processing lineslocal i, n = 0, #subswhile i < n doaegisub.progress.set(i/n*100)i = i + 1local l = subs[i]if l.class == "dialogue" and ((l.effect == "" and not l.comment) or l.effect:match("[Kk]araoke")) thenl.i = il.comment = falsekaraskel.preproc_line(subs, meta, styles, l)if apply_line(meta, styles, subs, l, templates, tenv) then-- Some templates were applied to this line, make a karaoke timing line of itl.comment = truel.effect = "karaoke"subs[i] = lend endend end

    概念

    有些術(shù)語和概念在本頁全篇中都有使用。這些名稱和腳本中使用的相似或者完全相同。(譯者注:在使用時需要保留英文,故翻譯內(nèi)容保留重要英文)
    tenv:template environment(模板環(huán)境)的縮寫, 或者 代碼執(zhí)行環(huán)境。
    varctx:variable context(內(nèi)聯(lián)變量環(huán)境), 內(nèi)聯(lián)變量存儲在的實際區(qū)域。
    template:卡拉OK模板執(zhí)行器(kara-templater)中最基本的 “執(zhí)行單元(execution unit)” , 事實上一個模板就是一個迷你程序,這個程序由 卡拉OK模板執(zhí)行器 編譯并執(zhí)行。
    code template:以Lua代碼塊方式行使功能的模板,但是一般情況下不會直接輸出字幕對象。(用 code 關(guān)鍵字聲明)
    output template:會產(chǎn)生字幕行(字幕對象)的一類模板,一般以打好K值的行作為輸入。(用 template 關(guān)鍵字聲明)
    code line:字幕文件中的一行,該行定義了一個code模板(code 模板)。
    template line:字幕文件中的一行,該行定義了一個輸出模板(output template), 或者整個輸出模板中的一部分。 (一個 line 類輸出模板可以對應(yīng)多個模板行)
    class(類):一個類指的是一種類型的模板。有四種基本的模板類, once, line, syl and furi, 第一個類只對code模板有用。
    modifier(修飾語):修飾語會影響模板作用的方式和作用的順序。
    template text 或 text:模板的"文本" 部分,可以是code模板中的 Lua 代碼,或者是輸出模板中的模板代碼。 line 類輸出模板還有一個 pre-line text 。

    啟動(Start-up)

    卡拉OK模板執(zhí)行器(后文均簡稱模板應(yīng)用器)做的第一件事是使用 卡拉OK框架(karaskel) 來收集一些基礎(chǔ)的字幕文件信息。這個過程中總是會伴隨著傳遞 真(true)值給 generate_furigana (生成假名標(biāo)注),它屬于karaskel.collect_head 函數(shù),這意味著 假名標(biāo)注(furigana) 的樣式會被生成,除非它們早就存在。

    然后模板應(yīng)用器會收集文件中的所有模板行(template line)信息。

    收集,解析并編譯模板

    文件中的每一行都會被檢查是否是一行模板,例如,被打上注釋并且特效欄(Effect field)填寫著 code 或者 template 的行會被作為模板行。

    細(xì)節(jié)在這里并不重要。你要知道的是 特效欄關(guān)鍵字后的修飾語會作為一個參數(shù)起作用。

    當(dāng)遇到一個 line 類的模板行時,模板應(yīng)用器首先會檢查是否有其他和這行具有一樣模板名稱的行。如果沒有,則會以該名稱新建一行,并按照給定的修飾語進(jìn)行初始化。如果已經(jīng)存在這樣的行, 該模板行中的文本會被加入到當(dāng)前模板行中統(tǒng)一成一個新模板行 。最終應(yīng)用的修飾語決定于后一個模板行的修飾語,而非當(dāng)前行。應(yīng)用模板的過程中,修飾語沒有辦法從模板中移除。特殊的是 pre-line 模板行的文本會被添加到 pre-line text (被置于所有代碼的最前面)。

    不同類的模板會被分別放置到各自的 “bucket” 中,所以 line 和 syl 模板不會被一起保存。(應(yīng)用模板后不會產(chǎn)生同類合并效果)

    清除(Clean-up)

    在所有模板信息都被收集后。所有不需要的行會被從字幕文件中刪除,最常見的情況是,第二次應(yīng)用同一個模板時第一次生成的 fx(在Effect欄) 行會先被清除。

    初始化 tenv

    在開始實際應(yīng)用模板之前的最后一項工作就是初始化運行環(huán)境。基本上,在所有的模板運行之前,都會被放置到 tenv。詳見 代碼執(zhí)行環(huán)境 ("基本上"是指除了 line, orgline, syl 和 basesyl.)

    運行 once 模板

    所有的 once 類模板會被首先執(zhí)行。這個過程中沒有什么激動人心的事情發(fā)生,發(fā)生的僅僅是一些額外的文件被添加到了 tenv。

    循環(huán)訪問(Iterate through)卡拉OK行

    字幕文件中的每個非模板行都會被瀏覽并且按順序應(yīng)用上模板。

    如果一行的注釋已經(jīng)打勾,但是特效欄沒有寫著Karaoke,那么應(yīng)用模板時這行會被跳過。
    如果一行沒被打上注釋,并且特效欄寫著除了Karaoke或者空白以外的文本,它也會被跳過。
    模板應(yīng)用器會試圖匹配所有非模板行。
    如果通過了以上幾點,剩下的每一行都會以三個步驟被應(yīng)用上模板。

    首先,所有的 line 類模板會試圖匹配非模板行然后再逐一在karaoke行上運行。下面會給出"模板匹配行的順序"的概念。

    接下來,所有行內(nèi)的音節(jié)會按順序被瀏覽,所有的 syl 類模板最終會被應(yīng)用在每個音節(jié)上。

    最后,會過一遍所有注音假名的音節(jié),來嘗試將所有 furi 類模板匹配相應(yīng)行,然后在注音假名上應(yīng)用模板。

    值得注意的是,音節(jié)和注音假名音節(jié)是會被解析并儲存的音節(jié),而不是用multi時的虛擬音節(jié),或是用char時的虛擬音節(jié),并且不是一個組合。

    Example 假設(shè)有三個 syl 類模板: A, B 和 C.A 是一個規(guī)則的模板,不帶有 multi 或者 char 修飾語。 B 模板含有 multi 修飾語,但是不含有 char 修飾語。 C 含有 char 和 multi 修飾語。 現(xiàn)在這三個模板會被應(yīng)用到一行中,這行含有兩個音節(jié)(syllable)。以下是過程:音節(jié)1 被選出 模板A匹配到這行,音節(jié)1被匹配。 模板A被應(yīng)用到音節(jié)1。 模板B匹配到這行,音節(jié)1被匹配。 音節(jié)1被分解為多音節(jié)標(biāo)注的虛擬音節(jié)1.1 和 1.2 模板B被應(yīng)用到虛擬音節(jié)1.1。 模板B被應(yīng)用到虛擬音節(jié)1.2。 模板C匹配到這行。 音節(jié)1被分解為以字符為單位的虛擬音節(jié)1.a 和 1.b 音節(jié) 1.a 和 1.b 被進(jìn)一步分解為 1.a1, 1.a2, 1.b1 和 1.b2。 模板C被應(yīng)用到虛擬音節(jié) 1.a1。 模板C被應(yīng)用到虛擬音節(jié) 1.a2。 模板C被應(yīng)用到虛擬音節(jié) 1.b1。 模板C被應(yīng)用到虛擬音節(jié) 1.b2。 音節(jié)2 被選出 進(jìn)行和上面相似的過程。 想知道更多有關(guān) 多音節(jié)標(biāo)注 和 以字符為單位的虛擬音節(jié)的內(nèi)容,請看下面。

    如果任何一個模板在以上三個步驟中匹配到了“打好K值的行”,執(zhí)行過模板后這樣的行就會被打上注釋,并且特效欄會顯示 karaoke 。

    模板匹配行

    模板的匹配總是以行為單位,而不是音節(jié)或其他單位。

    如果模板含有 fxgroup 修飾語,那么名字和 fxgroup 名相同的行會被無視。
    如果模板含有 all 修飾語,它會匹配任何行。
    如果模板和某行有一樣的樣式,它會匹配到這行。(這是最常見的情況)
    其他情況下模板不會匹配到行。

    應(yīng)用 line 類模板

    待編寫(原文如此)

    應(yīng)用 syl 和 furi 類模板

    待編寫(原文如此)

    過程描述

    (這部分內(nèi)容的具體代碼可以在Aegisub安裝目錄下的automation/autoload/kara-templater.lua中讀到)

    卡拉OK模板執(zhí)行器執(zhí)行的主要過程: 1. 收集頭部信息1. 找到所有的頭部信息,基本有播放分辨率(X/Y)。2. 找到所有的樣式。3. 生成對應(yīng)樣式的假名標(biāo)注樣式。 2. 收集模板并刪除已存在的 "fx" 行l(wèi)ines。 3. 初始化 tenv1. 添加 "string", "math""_G" 標(biāo)記2. 添加 "tenv"自引用3. 添加 "retime" 函數(shù)4. 添加空的 "fxgroup"4. 運行每一個"code once" 模板 5. 對于字幕文件中每個待處理的對話行:a. 如果特效欄以 "code""template"開始:1. 跳過行b. 否則:1. 如果特效欄不是空的,也不是 "karaoke":a. 跳過行2. 如果特效欄是空的,并且該行被打上注釋:a. 跳過行3.karaskel(卡拉OK框架)預(yù)處理行4. 初始化 varctx(內(nèi)聯(lián)變量環(huán)境)5. 重置 tenv1."orgline" 作為輸入2."line", "syl""basesyl" 置空6. 對于每個 "line" 模板:如果樣式匹配或者作用范圍是"all":循環(huán)過程("template.loops")多次:1."tenv.j" 為循環(huán)計數(shù)器2. a. 如果模板是 code 行:1."tenv.line" 為輸入行2. 運行 code 代碼b. 否則:1. 產(chǎn)生輸出行作為輸入行的副本2."tenv.line" t為輸出行3. 初始化 輸出行層(output line Layer)為模板層(template Layer)4. 初始化 輸出行文本為空5. 如果模板含有 pre-line:1. 運行 pre-line 模板2. 在輸出結(jié)果上附加文本6. a. 如果模板匹配到規(guī)則的行:對于輸入行中的每個音節(jié):1."tenv.syl" 為音節(jié)2. 為音節(jié)更新 varctx 3. 運行 line 模板4. 在輸出結(jié)果上附加文本5. 如果未設(shè)置 "notext" :a. 如果設(shè)置 "keeptags" :1. 在輸出文本上附上 "syl.text" b. 否則:1. 在輸出文本上附上 "syl.text_stripped"(剝離原標(biāo)簽的文本)b. 否則:a. 如果設(shè)置了 "keeptags" :1. 在輸出文本上附上 "syl.text" b. 否則1. 在輸出文本上附上 "syl.text_stripped"7. 把輸出行的特效欄填上 "fx"8. 把輸出行整合到字幕文件中7. 對于行中每個主要的音節(jié):對于每個 "syl" 模板:如果樣式匹配或者作用范圍是"all":如果模板不是在一個無效的fxgroup中:1."tenv.syl" 為音節(jié)2. 為音節(jié)更新 varctx 3. 如果音節(jié)的inlinefx(內(nèi)聯(lián)特效)沒有匹配到對應(yīng)的模板:1. 跳過音節(jié)4. 如果模板設(shè)置了 "noblank" 并且這個音節(jié)是個空格:1. 跳過音節(jié)5. 如果模板有"char"修飾:1. 建立 "charsyl" 作為音節(jié)的副本2."tenv.basesyl"(基礎(chǔ)音節(jié))為當(dāng)前的"tenv.syl"3."tenv.syl""charsyl"(字符音節(jié))4. 對于音節(jié)中每個 Unicode 編碼的字符:1."charsyl"計算虛擬音節(jié)數(shù) 2."字符音節(jié)"更新 varctx 3. 對虛擬音節(jié)繼續(xù)進(jìn)行音節(jié)的處理過程 (5.b.7.6.)6. 如果模板有"multi"修飾:1. 建立 "hlsyl"(音節(jié)) 作為音節(jié)的副本2. 除非 "tenv.basesyl" 早就存在,否則置為 "hlsyl"3."tenv.syl""hlsyl"4. 對于音節(jié)上每個標(biāo)記:1."hlsyl"計算虛擬音節(jié)數(shù)2."標(biāo)記音節(jié)"更新 varctx 3. 對虛擬音節(jié)繼續(xù)進(jìn)行音節(jié)的處理過程 (5.b.7.7.)7. a. 如果模板是 code 行:1."tenv.line" 為輸入行2. 運行 code 代碼b. 否則:1."tenv.line" 為輸入行2. 運行 code 代碼循環(huán)過程("template.loops")多次:1."tenv.j" 為循環(huán)計數(shù)器2. 創(chuàng)建輸出行3. 置輸出行的樣式為虛擬音節(jié)樣式4. 置輸出行層為模板層5."tenv.line" 為輸出行6. 運行模板7. 置輸出行文本為結(jié)果8. a. 如果設(shè)置了 "keeptags" :1. 在輸出文本上附上 "syl.text"b. 如果未設(shè)置 "keeptags" :1. 在輸出行文本上附上 "syl.text_stripped"c. 其他情況下什么都不會發(fā)生9. 置輸出行的特效欄內(nèi)容為"fx"10. 把輸出行整合到字幕文件中8. 對于行中的每個假名部分:和音節(jié)處理方式相同 (5.b.7.)9. 如果有非 code 模板應(yīng)用到行:1. 把輸入行置為注釋2. 置輸入行的特效欄文本為 "karaoke"3. 存儲修飾過的輸入行到字幕文件運行 code 行: 1. 編譯行文本為 Lua 函數(shù) 2. 如果編譯失敗, 報告錯誤 3. 置已編譯的函數(shù)的環(huán)境到 tenv 4. 循環(huán)過程("template.loops")多次::1."tenv.j" 為循環(huán)計數(shù)器2. 運行已編譯的函數(shù)3. 如果發(fā)生錯誤,報告它運行一行單獨的模板: 1. 置結(jié)果文本為模板 2. 如果存在 varctx:對于結(jié)果文本中的每個屬于 "$([a-zA-Z_]+)" 的字符:1. 將捕獲到的文本轉(zhuǎn)化為小寫2. a. 如果捕獲到的名稱在 varctx中:1. 替換結(jié)果文本中的這部分為 varctx中的值b. 否則:1. 警告2. 保持原文本不變 3. 對于結(jié)果文本中匹配到 "!(.-)!" 的情況:1. 附加 "結(jié)果 " 到捕獲的代碼中2. 按照Lua函數(shù)的方式編譯 捕獲到的代碼3. 如果編譯失敗,報告錯誤4. 置已編譯的函數(shù)的環(huán)境到 tenv 中5. 運行已編譯的函數(shù)a. 如果已編譯的函數(shù)產(chǎn)生了錯誤:1. 報告錯誤2. 在結(jié)果文本中保留了匹配到的內(nèi)容b. 否則:1. 用函數(shù)運行的結(jié)果替換掉匹配到的內(nèi)容

    總結(jié)

    以上是生活随笔為你收集整理的【Aegisub相关】卡拉OK模板执行环境和顺序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。