PDA

View Full Version : Loop structeres (for/while/repeat) in avisynth scripts ?


Poutnik
17th November 2005, 23:05
I did my best to find out if there is a way to do conditional loops,
common in most coding languages...

but in the end I have to ask:

Is there a way to do it by more clever way than repeat the code more than enough ?
Maybe it is against Avisynth design, script processing or parsing..., or I am comletely blind...

stickboy
18th November 2005, 04:04
Use recursion.

http://forum.doom9.org/showthread.php?t=100659

Poutnik
18th November 2005, 09:11
thank, you. I really did the search, but I missed it somehow....

gzarkadas
18th November 2005, 23:01
See my attached files at the thread: http://forum.doom9.org/showthread.php?t=101669 for a way to implement a for loop (near the last post of the thread).

You can also try the following functions (released under the GNU GPL version 2.0 or any later version published by the FSF), but do it at your own risk; I have not actually tested them, thus I consider them alpha version. However I would be glad to get back feedback whether they actually work or not. Read carefully the comments.
# Executes the statement 'func'('args') while the bool global variable with
# name 'condition_global' has the value true.
# 'func' must return a string containing the argument list of its invokation
# at the next loop; when the termination of the loop is desired 'func' must
# execute the following statement:
# dummy = Eval("global " + condition_global + "=false")
# Inspection of 'condition_global''s value is done *before* invoking 'func'.
# Thus, 'func' may not be called at all.
# NOTE:
# If 'func' does *not* modify 'condition_global' (to false) for some 'args',
# the function yields an infinite loop !!!
#
Function DoWhile(string condition_global, string func, string args)
{
new_args = Eval(condition_global) \
? Eval(func + "(" + args + ")") \
: args
# do not store Eval results; func may have changed condition_global's value!
return Eval(condition_global) \
? DoWhile(condition_global, func, new_args) \
: new_args
}

# Executes the statement 'func'('args') while the bool global variable with
# name 'condition_global' has the value false.
# 'func' must return a string containing the argument list of its invokation
# at the next loop; when the termination of the loop is desired 'func' must
# execute the following statement:
# dummy = Eval("global " + condition_global + "=true")
# Inspection of 'condition_global''s value is done *after* invoking 'func'.
# Thus, 'func' will be called at least one time.
# NOTE:
# If 'func' does *not* modify 'condition_global' (to true) for some 'args',
# the function yields an infinite loop !!!
#
Function DoUntil(string condition_global, string func, string args)
{
# ensure 'func' will be called at least once
new_args = Eval(func + "(" + args + ")")
return Eval(condition_global) \
? new_args \
: DoUntil(condition_global, func, new_args) \
}


I must emphasize that since looping is not natively supported by the Avisynth script language, in order to achieve such loops you will almost always have to pack the loop body into a function, use globals for communicating data and make tricks with Eval().

For most simple loops I would recommend the array implementation of AVSLib and the running of functions on int counter ranges such as in the example below (use your values instead of the variables):
global a_var = AVISource(filename)

global clp1 = AVISource(preset1)
global clp2 = AVISource(preset2)

# The loop body

# if start,stop,step are not ints, use float as the type of the first argument
# arg1, arg2[, arg3,...] are arguments that do not change during the loop
# if not needed, delete them from the list
#
Function myLoopBody(int i, clip arg1, clip arg2, int arg3)
{
# if need to modify a var outside the block from within the loop
#it must be global
global a_var = a_var + arg1.Trim(i, -10) + arg2.Trim(arg3, -i)

#.....other code....

# retval may either be something meaningfull such for example the frames
# processed or a clip that will be used by ArrayOpFunc below or
# a dummy value if all the functionality of the loop is implemented by globals
# modification; in the later case better use an int value to preserve memory
return retval
}

# the loop counter
counter = ArrayRange(start, stop, step)

# the loop execution
# here we use clp1 as arg1, clp2 as arg2 and 4 as arg3
#
looparray = counter.ArrayOpFunc("myLoopBody", "clp1,clp2,4")

#.....other code....


With Avisynth 2.5.6 and the 1.0.1 patch of AVSLib arrays of any practical size can be supported.
But you must be economical in what you put inside the loop, because you can easily hit the maximum process allowed memory limit, particularly if you use the Overlay() filter.

HunJozsef
18th August 2011, 11:06
Hi Everyone,
This is an old thread, still I think that my contribution has its place in here. I wanted to code the easy creation of peak-hold images from a part of a video, for which I needed looping in the AviSynth script. I was inspired by the AviSynth Wiki (http://avisynth.org/mediawiki/Block_statements) and I created a bare simple for-next looping implementation. It does not need any additional components, just the plain AviSynth intall (mine is ver. 2.58 currently).

I share it with you below. No warranty, try it on your own risk. GPL 3.0 license, if you want legal stuff. However, I am neither a lawyer, nor a programmer, so please let me know if I have done something wrong. I just hope this code helps and might prevents one from reinventing the wheel :-) Comments are welcome.
Save the following code as "ForNext.avs":

# Usage:
# Import this file in the beginning of your avs script e.g. Import("ForNext.avs")

# Version 1.0; (original version) 2011.08.11. Jozsef Bor, MTA GGKI, Hungary
# Based on the idea in the AviSynth Wiki http://avisynth.org/mediawiki/Block_statements
# License: GNU GPL version 3.0 or any later version published by the FSF. No warranty, use at your own risk.

# Usage:
# some_string_variable = ForNext(var_string, from_indx, to_indx, by_value, loop_string)
# Eval(some_string_variable)
#
# function 'ForNext' returns a string containig the repeated content of 'loop_string' with different values of 'var_string'
# example1:
#
# result = ""
# block = ForNext("${i}", 1,3,1, """result = result + String(${i})""")
#
# after this, variable 'block' contains the string:
# """
# result = result + String(1)
# result = result + String(2)
# result = result + String(3)"""
# If the command Eval(block) is then given, the variable 'result' will hold the string "123"
# Note that according to the Avisynth grammar, 'loop_string' can contain more lines of commands
# as long as they are enclosed between triple quotas
# example2:
#
# result = ""
# block = ForNext("${i}", 1,3,1, """result = result + String(${i})
# result = result + String(${i}*${i})""")
#
# after evaluation, this will end in the string "112439" in the variable 'result'

function ForNext(var_string, from_indx, to_indx, by_value, loop_string)
{
result = ""
from_indx <= to_indx ? Eval( "result = result + LineBreak() + Subst_string(var_string,String(from_indx),loop_string)") : NOP
(from_indx+by_value) <= to_indx ? Eval( "result = result + ForNext(var_string, (from_indx+by_value), to_indx, by_value, loop_string)") : NOP
return result
}



# Usage:
# some_string_variable = Subst_string(what_str, bywhat_str, inwhat_str)
#
# Substitutes every instances of what_str in inwhat_str by bywhat_str
# example1: Subst_string("aa", "bb", "1aa1a1aa111") returns "1bb1a1bb111"
# example2: Subst_string("aa", "ba", "aaa") returns "baa"

function Subst_string(what_str, bywhat_str, inwhat_str)
{
inwhat_length = StrLen(inwhat_str)
what_length = StrLen(what_str)
result = inwhat_str
position = FindStr(inwhat_str,what_str)
position == 0 ? NOP : Eval("result = LeftStr(inwhat_str, position-1) + bywhat_str + Subst_string(what_str, bywhat_str, MidStr(inwhat_str, position+what_length, inwhat_length))")
return result
}



# When there are too many "s, one can use this function to insert """ in strings

function TripleQuotas()
{
result = MidStr(""" " """,2,1) + MidStr(""" " """,2,1) + MidStr(""" " """,2,1)
return result
}



# "a"+LineBreak()+"b" puts b in a new line in Avisynth (note that "a\nb" does not work in Avisynth)

function LineBreak()
{
result = """
"""
return result
}