User defined script functions

From Avisynth wiki
Revision as of 10:41, 20 January 2021 by Pinterf (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

Definition and Structure

You can define and call your own (user defined) functions in AviSynth scripts. These are independent blocks of script code that are executed each time a call to the function is made in the script. They can return any clip or variable type. An example of a simple user defined script function (here a custom filter, ie a function returning a clip) immediately follows:

function MuteRange(clip c, int fstart, int fend)
{
    before = c.Trim(0, -fstart)
    current = c.Trim(fstart, fend) 
    after = c.Trim(fend + 1, 0)
    audio = Dissolve(before, current.BlankClip, after, 3)
    return AudioDub(c, audio)
}

User defined script functions start with the keyword function, followed by the function name. The name of a script function follows the same naming rules as script variables.

Immediately after the name, the function's argument list follows. The list (which can be empty) consists of (expected argument's type - argument's name) pairs. Argument type may be any of those supported by the scripting language.

function MuteRange(clip c, int fstart, int fend)

Then comes the function body, ie the code that is executed each time the function is called. The arguments are accessed within the function body by their names. The function body is contained within an opening and closing brace pair { ... }.

{
    before = c.Trim(0, -fstart)
    current = c.Trim(fstart, fend) 
    after = c.Trim(fend + 1, 0)
    audio = Dissolve(before, current.BlankClip, after, 3)
    return AudioDub(c, audio)
}

For simplicity, this code assumes the function will only be called with fstart>0 and fend<c.Framecount-1. A more complete version would also handle the special cases fstart=0 and fend=c.Framecount-1.

At the end of the function body, a return statement is placed, which sets the return value.

    return AudioDub(c, audio)

As a shorthand, a bare expression as the final statement is treated as if the keyword return was present. Thus, we could also have written simply

    AudioDub(c, audio)

It should be noted that unlike other languages, where multiple return statements are allowed inside the function body, AviSynth functions contain a single return statement. This is because the language does not support loops or branching in the normal sense, although there are ways around this – see Control structures for more.

Facts about user defined script functions

  • Functions can take up to sixty arguments and the return value can be of any type supported by the scripting language (clip, int, float, bool, string, AVS+array).
  • Although not recommended practice, an argument type may be omitted, and will default to val, the generic type.
  • If the function expects a video clip as its first argument, and that argument is not supplied, then the clip in the special Last variable will be used.
  • Functions support named arguments. Simply enclose an argument's name inside double quotes to make it a named argument. Note that after doing so the following apply:
    1. All subsequent arguments in the argument list must be named also.
    2. A named argument is an optional argument, that is, it need not be supplied by the caller.
    3. When a function is called, any optional argument which has not been provided is set to a value which has the void ('undefined') type. This does not mean that its value is random garbage - simply that its type is neither clip, int, float, bool or string and so it has no usable value.
    4. AVS+ Except: calling with missing parameters a parameter 'val_array' yields a zero sized array. The array parameter will always be defined but the size will be zero.
    5. AVS+ Array type parameters can be be given with the usual comma separated way. Arrays other than val_array are allowed to pass with the bracket syntax. E.g. [1.0, 3.0, 3.14] for a float_array.
    6. Normally, you should use the Defined function to test if an optional argument has an explicit value, or the Default function, which combines the Defined test with the setting of a default value if appropriate. AVS+ a val_array (array of anything) is always defined and has the size of zero.
    7. A void ('undefined') value can be passed on to another function as one of its optional arguments. This is useful when you want to write a wrapper function that calls another function, preserving the same defaults.
  • AVS+ As mentioned, Avisynth traditionally was always using arrays for internal and plugin function definitions. Array (zero or more of anything) is marked as type specifier ".*". Integer array is marked "i*", array of string is "s*" in the function definition. Arrays are used for example in "Select" or "GeneralConvolution" or "StackHorizontal". Avisynth+ (since v3.6) was just extended their use on script level.
  • AVS+ Rules for arrays.
    • val_array: array of anything; zero or more element. Can occur at the last position of the parameter list. Being an untyped array element can be another array. Untyped arrays can contain variables or any type (int, string, etc.., arrays) in arbitrary depth. The reason, why val_array is allowed only at the very last parameter is because parameters at this place can be simply given as a comma separated syntax. (This syntax is used internally in classic Avisynth as well when getting a parameter list into an array.) Because of this simple syntax, when not providing any parameters in the function call for val_array, Avisynth thinks that a zero-sized array is passed. One would argue that by providing a [] (empty array) would help, but no, it creates an array which has a single empty array element.
    • bool_array, int_array, string_array, float_array, clip_array, func_array: simple 1D arrays of the specified type. When called from script, typed array values must be passed with the bracketed syntax e.g. [1, 2, 3] when provided directly, or passing an existing array type variable. Exception: Avisynth recognizes a fixed-type array when providing it in a comma separated way instead of the [] style in two cases. Case #1: parameter is the very last one. Case #2: the parameters values are followed by a differently typed value. Avisynth can recognize the end of the comma separatedly given array only by encountering a different type.
  • If a function body has no (explicit or implicit) return, a void value (ie a value of the 'undefined' type) is returned.
  • Functions always produce a new value and never modify an existing one. What that means is that all arguments to a function are passed "by value" and not "by reference"; in order to alter a variable's value in AviSynth script language you must assign to it a new value.
  • Functions can call other functions, including themselves. The latter is known as recursion and is a very useful technique for creating functions that can accomplish complex tasks. See Control structures for more.
  • Local function variables mask global ones with the same name inside the function body. For example, if you define in a function a local variable myvar by assigning to it a value, then you cannot read the global myvar anymore inside this function.
  • The above is also true for arguments, since from the perspective of a function arguments are initialized local variables.
  • Each function has its own local version of the special variable Last. On entry to a function, Last is set to a void ('undefined') value.

Array examples

AVS+

Parameters that are "arrays" in the function definition, can be be given with the usual comma separated way.

"zero or more of anything" parameters can only occur at the very end or the parameter list because the parameters can begiven in a flattened way (like in classic Avisynth where there had been no [] array syntax).

Avisynth parser engine is not able to distinguish between not-given or zero-sized arrays parameters. Avisynth was always working with simple 1D arrays which are used for example in Apply, Format, Animate, etc. If the parameters at the given place were not provided, the array size was 0. But the variable was always existing.

Note 1: int_array and the other fixed-type arrays are type checked. They are only 1D arrays.

Note 2: "val_array" (array of anything) type is special. The parser has not even any clue what type of parameters should it expect. So when you pass a direct array for that (like in the "Dedicated val_array" example) it will take as a distinct value and will put it as a subarray of the given "n" variable. In r_val(20, "Dedicated val_array", [1,2,3]) n will be an array of size 1, containing the [1,2,3] array in its 0th element

This is because arrays can contain anything, even different type of subarrays or other types in an infinite depth.

BlankClip(width=1024,pixel_type="yv12")
 
r(0, "Dedicated int_array", [1,2,3])
r_val(20, "Dedicated val_array", [1,2,3])
r_val(40, "Dedicated val_array", [1,2,3],["hello","leo",2])
r(60, "Classic int_array", 1,2,3)
r_val(80, "Classic val_array", 1,2,3)
r(100, "Nothing =classic int_array (zero sized)")
r(120, "Nothing =classic val_array (zero sized)")
 
function r(clip c, int y, string s, int_array "n")
{
  x=0
  if(ArraySize(n) == 3) {
    return Subtitle(c, x=x, y=y, Format("{}: Array length={},[0]={},[1]={},[2]={}",s, ArraySize(n),n[0],n[1],n[2]))
  } else {
    if(ArraySize(n) == 1) {
      return Subtitle(c, x=x, y=y, Format("{}: Array length={}, n[0] length={},[0,0]={},[0,1]={},[0,2]={}", s, ArraySize(n),ArraySize(n[0]),n[0,0],n[0,1],n[0,2]))
    } else if(ArraySize(n) == 2) {
      return Subtitle(c, x=x, y=y, Format("{}: Array length={}, n[0] length={},n[1] length={},[0,0]={},[0,1]={},[0,2]={},[1,0]={},[1,1]={},[1,2]={}", \
       s, ArraySize(n),ArraySize(n[0]),ArraySize(n[1]),n[0,0],n[0,1],n[0,2],n[1,0],n[1,1],n[1,2]))
    } else { 
      return Subtitle(c, x=x, y=y, Format("{}: Array length={}",s, ArraySize(n)))
    }
  }
}
 
function r_val(clip c, int y, string s, val_array "n")
{
  x=0
  if(ArraySize(n) == 3) {
    return Subtitle(c, x=x, y=y, Format("{}: Array length={},[0]={},[1]={},[2]={}",s, ArraySize(n),n[0],n[1],n[2]))
  } else {
    if(ArraySize(n) == 1) {
      return Subtitle(c, x=x, y=y, Format("{}: Array length={}, n[0] length={},[0,0]={},[0,1]={},[0,2]={}", s, ArraySize(n),ArraySize(n[0]),n[0,0],n[0,1],n[0,2]))
    } else if(ArraySize(n) == 2) {
      return Subtitle(c, x=x, y=y, Format("{}: Array length={}, n[0] length={},n[1] length={},[0,0]={},[0,1]={},[0,2]={},[1,0]={},[1,1]={},[1,2]={}", \
       s, ArraySize(n),ArraySize(n[0]),ArraySize(n[1]),n[0,0],n[0,1],n[0,2],n[1,0],n[1,1],n[1,2]))
    } else { 
      return Subtitle(c, x=x, y=y, Format("{}: Array length={}",s, ArraySize(n)))
    }
  }
}

Related Links

  • Shared functions – an ever growing collection of shared script functions created by the members of the AviSynth community.
  • Category:Scripts – even more scripts.

TODO

http://www.avisynth.org/ExportingSingleImage
http://www.avisynth.org/HowToApplyFilterToManySingleFrames
Perhaps make decent functions from the last two?

Back to AviSynth Syntax.

Personal tools