Skip to content

Language New Features

Nekopanda edited this page Apr 28, 2018 · 18 revisions

AviSynth Neo 新言語仕様

第一級オブジェクトとしての関数を導入!関数型プログラミング言語へ!!

基本

関数オブジェクトの基本

a = function(int x, int y){
    return x + y
}
MessageClip(String(a)) # Function
b = a
MessageClip(String(b)) # Function
MessageClip(String(a == b)) # true

引数にとったり

function MyFunc(func f) {
    return f(2, 3)
}
a = MyFunc(function(x, y) {
    return x + y
})
MessageClip(String(a)) # 5

戻り値で返したり

function MyFunc() {
    return function(x, y) {
        return x + y
    }
}
a = MyFunc()(2, 3)
MessageClip(String(a)) # 5

仮引数の前に '[]' でその時点での変数をキャプチャ

function MyFunc() {
    x = 2
    y = 3
    return function[x, y]() {
        return x + y
    }
}
a = MyFunc()()
MessageClip(String(a)) # 5

仕様詳細

関数オブジェクトは新しい構文で定義された関数です。

function[](){ ... }

これまでの通常の関数定義と比べて名前のない関数のような形になっています。[]はオプションでなくても構いません。

普通の関数形式で定義された関数は関数オブジェクトではありません(互換性維持のため)。

function MyFunc() { return 123 }
a = MyFunc
MessageClip(String(a)) # 123 (Not Function)

同様に組み込み関数やプラグイン関数も、関数オブジェクトではありません。

a = Invert # Error: I don't know what 'Invert' means.

関数オブジェクトでない関数は、func関数を使えば関数オブジェクト化できます。

a = func(Invert)
Version().a() # Invert a clip

値の型に、新しく'func'が加わりました。

function MyFunc(func x, func y, int z) {
    return x() + y() + z
}
a = MyFunc(function(){1},function(){2},3)
MessageClip(String(a)) # 6 (= 1 + 2 + 3)

関数オブジェクトを判定するIsFunction関数が追加されています。

a = function(){}
MessageClip(String(IsFunction(a))) # true

GRunTと比較

ScriptClipを書きやすくするプラグインGRunTとNeoを比較してみましょう。

GRunTの紹介ページにある以下のコード

function bracket_luma(clip c, float th1, float th2) {
    Assert(0 <= th1 && th1 < th2 && th2 <= 255, "Invalid thresholds!")
    ScriptClip(c, """
       avl = AverageLuma()
       avl <= th1 ? last.BlankClip() : avl >= th2 ? last.BlankClip(color=color_white) : last
    """, args="th1,th2", local=true)
}

GRunTの良さをアピールするためのサンプルですが、Neoだと以下のように書けます。

function bracket_luma(clip c, float th1, float th2) {
    Assert(0 <= th1 && th1 < th2 && th2 <= 255, "Invalid thresholds!")
    ScriptClip(c, function[th1,th2]() {
       avl = AverageLuma()
       avl <= th1 ? last.BlankClip() : avl >= th2 ? last.BlankClip(color=color_white) : last
    })
}

GRunTと比べて以下のような違いがあります。

  • 処理の内容を文字列で渡す必要がない
  • 使う変数は専用の構文で書けるので、記述量が減っている

組み込み関数の関数入力対応

処理の内容をスクリプトの文字列で渡していた関数は、関数を渡せるバージョンが追加されました。

ScriptClip

ScriptClip(clip clip, func filter [, bool show, bool after_frame] )

例)

Version()
ScriptClip(function[](clip c) {
    c.Subtitle(String(current_frame))
})

ConditionalFilter

ConditionalFilter(clip testclip, clip source1, clip source2, func condition [, bool show] )

例)

a = Version()
b = a.Invert()
ConditionalFilter(a, a, b, function[](clip c) {
    current_frame < 30 # if true return a else b
})

ConditionalSelect

ConditionalSelect(clip testclip, func get_index, clip source0 [, clip source1...] [, bool show] )

例)

Version()
ConditionalSelect(function[](clip c) {
    current_frame / 100
}, subtitle("0"), subtitle("1"), subtitle("2"))

WriteFile系

WriteFile(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append, bool flush])

WriteFileIf(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append, bool flush])

WriteFileStart(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append])

WriteFileEnd(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append])

例)

Version().ConvertToY()
WriteFile("out.txt", function() {
    string(current_frame) + ": " + string(YPlaneMedian())
})

エスケープ処理される文字列のサポート

eプリフィックスが付いた文字列 e"..." は、バックスラッシュによるエスケープ処理が有効になります。

例)

Version().ConvertToY()
WriteFileStart("out.txt", function() {
    e"foo\tbar\nhoge\thoge"
})