Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
5th February 2006, 14:43 | #1 | Link |
developer wannabe
Join Date: Nov 2001
Location: Brooklyn, NY
Posts: 1,211
|
Arrays and Loops
I was writing a helper function yesterday and once again came across a situation where it would've been nice to have arrays & loops. After many years of people asking for these kind of features, but no progress aside from "someday, in AVS 3.xx", I assumed it was a hard problem. Turns out it only took a few hours
Code:
# rb-array.avsi -- functions for simulating arrays & loops in Avisynth 2.xx # # Last modified: 2006-02-05 # # Written by Richard Berg and assigned to the public domain. # # Dim # # Create a collection of global variables that can be manipulated similar to an array. You can re-Dim # an existing array, but the contents will be cleared. The type of the "initValue" parameter determines the type # of the array. All Avisynth types are supported. # # PARAMETERS: # "arr" : Name of the array variable. Pass this variable name to Deref and Set. # "size" : Size of the array; 0-based, like C/C++. Dim("foo", 10) creates foo0-foo9. # "initValue" : Each element is initialized to this value. Its type determines the array type. It uses For # internally, so initValue can be parametrized by 'i'. # # USAGE: see example.avs # function Dim(string arr, int size, val initValue) { # create "base" string variable whose value is its name. every Eval in internal array functions # needs this to build the element's name Eval("global " + arr + "=" + chr(34) + arr + chr(34)) # store size so that Length() is O(1) Eval("global " + arr + "Length = " + string(size)) # create each element global DimThunkVal = initValue # thunk requires this in case it's a clip for(0, "<="+string(size), "+1", arr + ".set(i, " + thunk(initValue, "DimThunkVal") + ")") } # DeRef # # Gives you programmatic access to the "arrays" created by Dim # # USAGE: foo.deref(2+2) # ...is semantically equivalent* to foo[2+2] in C/C++ # ...is syntactically equivalent to foo4 in Avisynth # # *exception: the output of deref is NOT an lvalue. If you need to assign something to # an array element, use Set. # function DeRef(string arr, int index) { Eval(arr + string(index)) } # Set # # Allows you to programmatically assign values to the "arrays" created by Dim # # USAGE: foo.set(i, i*2) # ...is semantically equivalent to foo[i] = i*2; in C/C++ # ...is syntactically equivalent to fooI = i*2 in Avisynth # function Set(string arr, int index, val val) { Eval("global " + arr + string(index) + "=" + thunk(val)) } # Thunk # # Makes a generic (untyped) parameter suitable for building Eval strings. # # PARAMETERS: # "clipName" : In order to assign clips to arrays with Eval, the rvalue has to be another Eval # on a clip variable. By default, this variable is the parameter "val," as used # in functions like Set. However, if you are building an Eval string for use with # For, you'll need to set a global variable that can be accessed inside the loop. So # as to not pollute the global namespace, you can create a unique variable name; pass # it as 'clipName' to make Thunk work correctly. # # function Thunk(val val, string "clipName") { clipName = Default(clipName, "val") # string -> escape it # clip -> double-thunk it # everything else -> stringify it return val.IsString() \ ? chr(34) + val + chr(34) \ : val.IsClip() \ ? "Eval(" + chr(34) + clipName + chr(34) + ")" \ : string(val) } # Length # # Returns the length of an "array" created by Dim # function Length(string arr) { try { return Eval(arr + "Length") } catch (err_msg) { Throw("Length: the array " + arr + " was not created by Dim or is corrupt") } } # Length2 # # Returns the length of an "array" that was not created by Dim, or has had elements manipulated directly. O(n) search. # # PARAMETERS: # "startIndex" : Start searching at this index. Default = 0. Note: elements lower than startIndex are # not counted in the length calculation. # function Length2(string arr, int "startIndex") { startIndex = Default(startIndex, 0) # store size in Dim-style global so we don't have to do this again Eval("global " + arr + "Length = " + string(Length2Loop(arr, startIndex))) return arr.length } function Length2Loop(string arr, int index) { try { # note: using deref won't work - after the callstack unwinds, index will be lost Eval(arr + string(index)) return Length2Loop(arr, index + 1) } catch (err_msg) { return index } } # Fill # # Fill an array with values entered as a comma-delimited string literal. # (thanks to James "stickboy" Lin for the idea) # # # USAGE: array.Fill("3, -50, 124") # # PARAMETERS: # "index" : Start writing values at this index. Default is 0. # "string" : If true, fills the array with strings instead of parsing into values. Default is false. # function Fill(string arr, string values, int "index", bool "string") { index = Default(index, 0) string = Default(string, false) offset = FindStr(values, ",") # FindStr returns 0 if not found return (offset == 0) \ ? NOP \ : Eval(""" element = LeftStr(values, offset - 1) element = string ? element : Value(element) arr.Set(index, element) arr.Fill(MidStr(values, offset + 1), index + 1) """) } # For # # A simple for-loop construct for Avisynth 2.xx # # USAGE: for(1, "<=3", "+1", "global x = x*2" ) # ...is semantically equivalent to for(int i=1, i<=3, i=i+1) { x = x*2 } in C/C++ # # Notes: # - with For, the loop variable is always 'i', and the first parameter (its initial value) is always an int. If you # want to use a custom loop variable (so you can nest loops, for instance, or have a floating-point counter) then use For2. # - any script variables you want manipulate inside the loop must be globals # - corollary: you cannot use the implicit 'last' variable. if you want to apply a filter inside the loop, # you must use assignment syntax. Example: for(0, "<=2", "+1", "global clip = clip.FFT3DFilter(sigma=2.5, plane=i)" ) # function For(int i, string cond, string iter, string block) { return Eval("i" + cond) \ ? Eval(""" Eval(block) For(Eval("i" + iter), cond, iter, block) """) \ : NOP } # For2 # # A more generalized for-loop construct for Avisynth 2.xx # # USAGE: for("j=1", "j<=3", "j=j+1", "global x = x*2") # ...is semantically equivalent to for(int j=1, j<=3, j=j+1) { x = x*2 } in C/C++ # # Notes: # - For's guidelines about manipulating globals apply to For2 as well. In addition, the loop variable must # be a global (this is handled for you -- if this hack isn't sufficiently general, use For2Loop directly). # function For2(string init, string cond, string iter, string block) { For2Loop("global " + init, cond, "global " + iter, block) } function For2Loop(string init, string cond, string iter, string block) { Eval(init) return Eval(cond) \ ? Eval(""" Eval(block) For2Loop(iter, cond, iter, block) """) \ : NOP } # For3 # # Same as For, but implemented using For2. Mostly a proof of concept, but there's a practical difference: the # loop variable here is global, so nesting For3's probably does weird things. # function For3(int i, string cond, string iter, string block) { For2("i=" + string(i), "i" + cond, "i=i" + iter, block) } # While # # A simple while-loop construct for Avisynth 2.xx # # USAGE: while(b, "DoSomething()") # ...is semantically equivalent to while(b) { DoSomething() } in C/C++ # # Notes: # - If you put it into an infinite loop, the host app will crash after several seconds. An easy way to do this # is to forget to use 'global' when manipulating variables that affect 'cond' inside the loop. # - I honestly don't think this is a very useful function. Most of the time you want while()-like semantics, you # really want to operate on frames (not clips or other variables), in which case ConditionalFilter is the far # better choice. # function While(string cond, string block) { For2Loop("", cond, "", block) } A simple example.avs: Code:
BlankClip(length=1025, color=color_royalblue) JDL_FadeIO(end=last.framecount) global fade = last # create an array full of 0's, then fill it with the fibonacci sequence Dim("fibArr", 25, 0) for(0, "<=25", "+1", \""" global fade = fade.Subtitle("initial value #" + string(i) + " = " + string(fibArr.deref(i)), y = (i+1) * 18, align = 6) fibArr.set(i, i>=2 \ ? fibArr.deref(i-1) + fibArr.deref(i-2) \ : 1) global fade = fade.Subtitle("Fibonacci #" + string(i) + " = " + string(fibArr.deref(i)), y = i * 18) """) # write a multiplication table global table = fade for2("x=1", "x<=8", "x=x+1", \""" for2("y=1", "y<=8", "y=y+1", \" global table = table.Subtitle(string(x*y), x=x*30 + 180, y=y*20 + 30) ") """) # create an array of clips: each has 1 frame that's a power of 2 in the original clip global j=0 Dim("frameArr", 0, NullClip(fade)) # create empty array; we'll fill it manually for(1, "<=table.FrameCount", "*2", \""" frameArr.set( \ j, table.Trim3(i, length=1) \ .Subtitle("original frame " + string(i), align=8) \ .Subtitle("fibArr length " + string(fibArr.length), align=5) \) global j = j + 1 """) # concatenate the frames from that clip-array into one clip # we'll do it backwards just for fun global powers = NullClip(fade) len = Length("frameArr") # change this to a bogus array name and you'll get an Assert global countdown = frameArr.Length2 - 1 while("countdown>=0", \""" global powers = powers + frameArr.deref(countdown).subtitle("powers frame " + string(countdown), align=8, y = 18) global countdown = countdown-1 """) # detecting the length of frameArr manually (see Length2 call above) is O(N) the first time, so we only want to # do it once; afterward, Length() will work len2 = frameArr.Length return powers.Subtitle("frameArr len: before " + string(len) + ", after " + string(len2), align = 2) FWIW, the function that started it all (FindClosest): Code:
# rb-alignaudio.avsi -- AlignAudio & misc helper functions # # Last modified: 2006-02-05 # # Written by Richard Berg and assigned to the public domain. # # AlignAudio # # Adjusts the length of the audio track to match the video. Uses BestResample if resampling is requested. # # # # PARAMETERS: # "samplerate" : If defined, resample the audio to this rate. If not defined, then the audio samplerate is # set to the standard that's closest to the input. # Function AlignAudio(clip clip, int "samplerate") { Assert(clip.HasAudio && clip.HasVideo, "RB_AlignAudio: clip must have both audio & video") clip = Defined(samplerate) \ ? clip.BestResample(samplerate) \ : clip.AssumeSampleRate( FindClosest(clip.AudioRate, "11025, 22050, 44100, 88200, 12000, 24000, 48000, 96000, 192000") ) return clip.TimeStretch(100. * clip.AudioLength/clip.AudioRate / (clip.FrameCount/clip.FrameRate)) } # BestResample # # Resamples a clip's audio. Intelligently chooses SSRC(fast = true), SSRC(fast = false), or ResampleAudio based on # the guidelines in the Avisynth manual. # # function BestResample(clip clip, int samplerate) { return CanSSRC(clip.AudioRate, samplerate) \ ? WithinFactorOf(2, clip.AudioRate, samplerate) \ ? clip.SSRC(samplerate) \ : clip.SSRC(samplerate, fast=false) \ : clip.ResampleAudio(samplerate) } # Given a list of numbers, returns the one closest to the input # # PARAMETERS: # "input" : number to compare against # "numbers" : comma-delimited list of numbers to search # # function FindClosest(val input, string numbers) { # parse string into array Dim("rates", 0, 0) # empty is ok - we'll fill it manually Fill(rates, numbers) # need Length2 here since we filled manually global g_len = rates.Length2 global g_minDelta = input - rates0 global g_input = input for(1, "<g_len", "+1", \""" global g_minDelta = abs(g_input - rates.deref(i)) < abs(g_minDelta) \ ? g_input - rates.deref(i) \ : g_minDelta """) ret = input - g_minDelta return input.IsInt ? int(ret) : ret } # return true if f is less than the ratio between x & y # Example: WithinFactorOf(10, x, y) == "x is within an order of magnitude of y" # function WithinFactorOf(float f, float x, float y) { ratio = x>y ? x/y : y/x return ratio < f } # Computes the Greatest Common Divisor of two integers # (Euclid's Algorithm) # function GCD(int a, int b) { return (b == 0) \ ? a \ : GCD(b, a % b) } # Returns true if Avisynth's Shibatch sample rate converter function (SSRC) can convert # a clip with samplerate = src to dst, based on the documentation at <http://www.avisynth.org/SSRC> # function CanSSRC(int src, int dst) { fs1 = dst * src / GCD(src, dst) return (fs1 / dst == 1) || (fs1 / dst % 2 == 0) || (fs1 / dst % 3 == 0) } Try it out, let me know what you think. I'm sure there are more features that can be added without much trouble, but I dunno what would be useful. |
5th February 2006, 14:56 | #2 | Link |
Moderator
Join Date: Nov 2001
Location: Netherlands
Posts: 6,364
|
arrays are supported in AVSLib: http://avslib.sourceforge.net/modules/array.html
I will add the stuff above to the documentation, if you haven't already done so |
5th February 2006, 15:32 | #3 | Link |
developer wannabe
Join Date: Nov 2001
Location: Brooklyn, NY
Posts: 1,211
|
Interesting...surprised I never saw AVSLib before. (Maybe I did & forgot). Anyway, my fake arrays should be much faster than their fake arrays & won't have the 512-byte limit. They also don't have any loops Nevertheless, they have a huge collection of array operations that would be nice to have...I'll bet there's an easy way to adapt them, but I'm tired of scripting for now...
|
6th February 2006, 16:34 | #4 | Link |
Registered User
Join Date: Sep 2002
Posts: 88
|
WScript and WSInvoke allow you to use Windows Script (VBScript, JScript and so on) in AviSynth.
These filters are included in a warpsharp plugin. |
19th February 2006, 13:56 | #5 | Link |
developer wannabe
Join Date: Nov 2001
Location: Brooklyn, NY
Posts: 1,211
|
Dunno if anyone actually tried my example.avs, but here's something for scriptmeister Didee. From MCNR_simple2, we simplify:
Code:
bw4 = (frames<4) ? dummy : clp.SrchCmpRp(blocksize,true, 4,chroME,repairME) bw3 = (frames<3) ? dummy : clp.SrchCmpRp(blocksize,true, 3,chroME,repairME) bw2 = (frames<2) ? dummy : clp.SrchCmpRp(blocksize,true, 2,chroME,repairME) bw1 = clp.SrchCmpRp(blocksize,true, 1,chroME,repairME) fw1 = clp.SrchCmpRp(blocksize,false,1,chroME,repairME) fw2 = (frames<2) ? dummy : clp.SrchCmpRp(blocksize,false,2,chroME,repairME) fw3 = (frames<3) ? dummy : clp.SrchCmpRp(blocksize,false,3,chroME,repairME) fw4 = (frames<4) ? dummy : clp.SrchCmpRp(blocksize,false,4,chroME,repairME) frames == 1 ? interleave( bw1,clp,fw1 ) : \ frames == 2 ? interleave( bw2,bw1,clp,fw1,fw2 ) : \ frames == 3 ? interleave( bw3,bw2,bw1,clp,fw1,fw2,fw3 ) : \ interleave( bw4,bw3,bw2,bw1,clp,fw1,fw2,fw3,fw4 ) Code:
Dim("bw", frames, NullClip()) Dim("fw", frames , NullClip()) global inter = "clp" for(1, "<=" + string(frames), "+1", \""" bw.set(i, clp.SrchCmpRp(blocksize,true,i,chroME,repairME)) fw.set(i, clp.SrchCmpRp(blocksize,true,i,chroME,repairME)) global inter = "bw" + string(i) + "," + inter + "," + "fw" + string(i) """) eval( "interleave(" + inter + ")" ) |
18th May 2006, 00:20 | #6 | Link |
Registered User
Join Date: Jan 2005
Location: Praha (not that one in Texas)
Posts: 863
|
Hi Richard,
thanks for these functions. I show you part of my to-be script: Code:
function SmoothDeblockLayer(clip orig,string "dct_type",int "density",float "quant",string "averagingmatrix") { dct_type="DCTFilter" #fixed now global gDensity=density #number of DCT per 8 pix global gOrig=orig global rep=1 #rounding error protection global sc="shiftClip" global avg=sc+"0,"+String(rep) global coma="," global mx=orig.PtrnBlock(3,0,0,255,255) # needed Patterns.avsi (from redeblock thread) global _lut1="x y * 255 /" Dim("DctParams",8,0) Dim("shiftClip",Int(Pow(density,2)),Blackness()) For2("i=7","i>="+String(quant),"i=i-1", \""" DctParams.Set(i,1) """) For2("i=0", "i<gDensity", "i=i+1", \""" For2("j=0", "j<gDensity", "j=j+1", \" shiftClip.Set(i*gDensity+j,(i+j==0) ? gOrig : gOrig.AddBorders(Int(8/gDensity)*i,Int(8/gDensity)*j,16-Int(8/gDensity)*i,16-Int(8/gDensity)*j)) shiftClip.Set(i*gDensity+j,(i+j==0) ? gOrig : shiftClip.DeRef(i*gDensity+j).DCTFilter(DctParams7,DctParams6,DctParams5,DctParams4,DctParams3,DctParams2,DctParams1,DctParams0)) shiftClip.Set(i*gDensity+j,mt_lutxy(shiftClip.DeRef(i*gDensity+j),mx,_lut1,y=3,u=3,v=3)) shiftClip.Set(i*gDensity+j,(i+j==0) ? shiftClip.DeRef(i*gDensity+j) : shiftClip.DeRef(i*gDensity+j).crop(Int(8/gDensity)*i,Int(8/gDensity)*j,Int(8/gDensity)*i-16,Int(8/gDensity)*j-16)) global avg = (i+j==0) ? avg : avg+coma+sc+String(i*gDensity+j)+coma+String(rep) ") """) Eval("Average("+avg+")") } - is it possible to get rid of these artificially added globals in the beginning of the function? - you see that I used variable sc inside the inner loop to pass string because I was not sure how to write qoutation marks inside qoutation marks inside qoutation marks ... - anything else I could do better with your scripts Last edited by redfordxx; 18th May 2006 at 02:02. |
12th August 2017, 17:53 | #9 | Link |
I'm Siri
Join Date: Oct 2012
Location: void
Posts: 2,633
|
Oh, forgot to do some advertizing
Give vaporsynth a shot if u want complex stuff like arrays or loops or conditional statements, it's got Python as the scripting language so u have all that natively with no extra trouble in vaporsynth |
13th August 2017, 03:52 | #10 | Link | |
Registered User
Join Date: Jan 2012
Location: Mesopotamia
Posts: 2,587
|
Quote:
Code:
# rb-array.avsi -- functions for simulating arrays & loops in Avisynth 2.xx # # Last modified: 2017-08-13 # # Written by Richard Berg and assigned to the public domain. # # RBDim # # Create a collection of global variables that can be manipulated similar to an array. You can re-Dim # an existing array, but the contents will be cleared. The type of the "initValue" parameter determines the type # of the array. All Avisynth types are supported. # # PARAMETERS: # "arr" : Name of the array variable. Pass this variable name to Deref and Set. # "size" : Size of the array; 0-based, like C/C++. RBDim("foo", 10) creates foo0-foo9. # "initValue" : Each element is initialized to this value. Its type determines the array type. It uses For # internally, so initValue can be parametrized by 'i'. # # USAGE: see example.avs # function RBDim(string arr, int size, val initValue) { # create "base" string variable whose value is its name. every Eval in internal array functions # needs this to build the element's name Eval("global " + arr + "=" + chr(34) + arr + chr(34)) # store size so that RBLength() is O(1) Eval("global " + arr + "RBLength = " + string(size)) # create each element global DimThunkVal = initValue # thunk requires this in case it's a clip RBFor(0, "<="+string(size), "+1", arr + ".RBSet(i, " + RBThunk(initValue, "DimThunkVal") + ")") } # DeRef # # Gives you programmatic access to the "arrays" created by Dim # # USAGE: foo.DeRef(2+2) # ...is semantically equivalent* to foo[2+2] in C/C++ # ...is syntactically equivalent to foo4 in Avisynth # # *exception: the output of DeRef is NOT an lvalue. If you need to assign something to # an array element, use RBSet. # function DeRef(string arr, int index) { Eval(arr + string(index)) } # RBSet # # Allows you to programmatically assign values to the "arrays" created by Dim # # USAGE: foo.RBSet(i, i*2) # ...is semantically equivalent to foo[i] = i*2; in C/C++ # ...is syntactically equivalent to fooI = i*2 in Avisynth # function RBSet(string arr, int index, val val) { Eval("global " + arr + string(index) + "=" + RBThunk(val)) } # RBThunk # # Makes a generic (untyped) parameter suitable for building Eval strings. # # PARAMETERS: # "clipName" : In order to assign clips to arrays with Eval, the rvalue has to be another Eval # on a clip variable. By default, this variable is the parameter "val," as used # in functions like RBSet. However, if you are building an Eval string for use with # For, you'll need to RBSet a global variable that can be accessed inside the loop. So # as to not pollute the global namespace, you can create a unique variable name; pass # it as 'clipName' to make RBThunk work correctly. # # function RBThunk(val val, string "clipName") { clipName = Default(clipName, "val") # string -> escape it # clip -> double-thunk it # everything else -> stringify it return val.IsString() \ ? chr(34) + val + chr(34) \ : val.IsClip() \ ? "Eval(" + chr(34) + clipName + chr(34) + ")" \ : string(val) } # RBLength # # Returns the length of an "array" created by Dim # function RBLength(string arr) { try { return Eval(arr + "RBLength") } catch (err_msg) { Throw("RBLength: the array " + arr + " was not created by Dim or is corrupt") } } # Length2 # # Returns the length of an "array" that was not created by Dim, or has had elements manipulated directly. O(n) search. # # PARAMETERS: # "startIndex" : Start searching at this index. Default = 0. Note: elements lower than startIndex are # not counted in the length calculation. # function Length2(string arr, int "startIndex") { startIndex = Default(startIndex, 0) # store size in Dim-style global so we don't have to do this again Eval("global " + arr + "RBLength = " + string(Length2Loop(arr, startIndex))) return arr.RBLength } function Length2Loop(string arr, int index) { try { # note: using DeRef won't work - after the callstack unwinds, index will be lost Eval(arr + string(index)) return Length2Loop(arr, index + 1) } catch (err_msg) { return index } } # RBFill # # Fill an array with values entered as a comma-delimited string literal. # (thanks to James "stickboy" Lin for the idea) # # # USAGE: array.RBFill("3, -50, 124") # # PARAMETERS: # "index" : Start writing values at this index. Default is 0. # "string" : If true, fills the array with strings instead of parsing into values. Default is false. # function RBFill(string arr, string values, int "index", bool "string") { index = Default(index, 0) string = Default(string, false) offset = FindStr(values, ",") # FindStr returns 0 if not found return (offset == 0) \ ? NOP \ : Eval(""" element = LeftStr(values, offset - 1) element = string ? element : Value(element) arr.RBSet(index, element) arr.RBFill(MidStr(values, offset + 1), index + 1) """) } # RBFor # # A simple for-loop construct for Avisynth 2.xx # # USAGE: RBFor(1, "<=3", "+1", "global x = x*2" ) # ...is semantically equivalent to RBFor(int i=1, i<=3, i=i+1) { x = x*2 } in C/C++ # # Notes: # - with RBFor, the loop variable is always 'i', and the first parameter (its initial value) is always an int. If you # want to use a custom loop variable (so you can nest loops, for instance, or have a floating-point counter) then use For2. # - any script variables you want manipulate inside the loop must be globals # - corollary: you cannot use the implicit 'last' variable. if you want to apply a filter inside the loop, # you must use assignment syntax. Example: RBFor(0, "<=2", "+1", "global clip = clip.FFT3DFilter(sigma=2.5, plane=i)" ) # function RBFor(int i, string cond, string iter, string block) { return Eval("i" + cond) \ ? Eval(""" Eval(block) RBFor(Eval("i" + iter), cond, iter, block) """) \ : NOP } # For2 # # A more generalized for-loop construct for Avisynth 2.xx # # USAGE: for2("j=1", "j<=3", "j=j+1", "global x = x*2") # ...is semantically equivalent to for2(int j=1, j<=3, j=j+1) { x = x*2 } in C/C++ # # Notes: # - For's guidelines about manipulating globals apply to For2 as well. In addition, the loop variable must # be a global (this is handled for you -- if this hack isn't sufficiently general, use For2Loop directly). # function For2(string init, string cond, string iter, string block) { For2Loop("global " + init, cond, "global " + iter, block) } function For2Loop(string init, string cond, string iter, string block) { Eval(init) return Eval(cond) \ ? Eval(""" Eval(block) For2Loop(iter, cond, iter, block) """) \ : NOP } # For3 # # Same as For, but implemented using For2. Mostly a proof of concept, but there's a practical difference: the # loop variable here is global, so nesting For3's probably does weird things. # function For3(int i, string cond, string iter, string block) { For2("i=" + string(i), "i" + cond, "i=i" + iter, block) } # RBWhile # # A simple while-loop construct for Avisynth 2.xx # # USAGE: RBWhile(b, "DoSomething()") # ...is semantically equivalent to RBWhile(b) { DoSomething() } in C/C++ # # Notes: # - If you put it into an infinite loop, the host app will crash after several seconds. An easy way to do this # is to forget to use 'global' when manipulating variables that affect 'cond' inside the loop. # - I honestly don't think this is a very useful function. Most of the time you want While()-like semantics, you # really want to operate on frames (not clips or other variables), in which case ConditionalFilter is the far # better choice. # function RBWhile(string cond, string block) { For2Loop("", cond, "", block) } example.avs Code:
BlankClip(length=1025, color=$4169e1) JDL_FadeIO(end=last.framecount) global fade = last # create an array full of 0's, then fill it with the fibonacci sequence RBDim("fibArr", 25, 0) RBfor(0, "<=25", "+1", \""" global fade = fade.Subtitle("initial value #" + string(i) + " = " + string(fibArr.deref(i)), y = (i+1) * 18, align = 6) fibArr.RBset(i, i>=2 \ ? fibArr.deref(i-1) + fibArr.deref(i-2) \ : 1) global fade = fade.Subtitle("Fibonacci #" + string(i) + " = " + string(fibArr.deref(i)), y = i * 18) """) # write a multiplication table global table = fade for2("x=1", "x<=8", "x=x+1", \""" for2("y=1", "y<=8", "y=y+1", \" global table = table.Subtitle(string(x*y), x=x*30 + 180, y=y*20 + 30) ") """) # create an array of clips: each has 1 frame that's a power of 2 in the original clip global j=0 RBDim("frameArr", 0, NullClip(fade)) # create empty array; we'll fill it manually RBfor(1, "<=table.FrameCount", "*2", \""" frameArr.RBset( \ j, table.Trim3(i, length=1) \ .Subtitle("original frame " + string(i), align=8) \ .Subtitle("fibArr length " + string(fibArr.RBlength), align=5) \) global j = j + 1 """) # concatenate the frames from that clip-array into one clip # we'll do it backwards just for fun global powers = NullClip(fade) len = RBLength("frameArr") # change this to a bogus array name and you'll get an Assert global countdown = frameArr.Length2 - 1 RBwhile("countdown>=0", \""" global powers = powers + frameArr.deref(countdown).subtitle("powers frame " + string(countdown), align=8, y = 18) global countdown = countdown-1 """) # detecting the length of frameArr manually (see Length2 call above) is O(N) the first time, so we only want to # do it once; afterward, Length() will work len2 = frameArr.RBLength return powers.Subtitle("frameArr len: before " + string(len) + ", after " + string(len2), align = 2) Code:
# rb-alignaudio.avsi -- AlignAudio & misc helper functions # # Last modified: 2017-08-13 # # Written by Richard Berg and assigned to the public domain. # # AlignAudio # # Adjusts the length of the audio track to match the video. Uses BestResample if resampling is requested. # # # # PARAMETERS: # "samplerate" : If defined, resample the audio to this rate. If not defined, then the audio samplerate is # set to the standard that's closest to the input. # Function AlignAudio(clip clip, int "samplerate") { Assert(clip.HasAudio && clip.HasVideo, "RB_AlignAudio: clip must have both audio & video") clip = Defined(samplerate) \ ? clip.BestResample(samplerate) \ : clip.AssumeSampleRate( FindClosest(clip.AudioRate, "11025, 22050, 44100, 88200, 12000, 24000, 48000, 96000, 192000") ) return clip.TimeStretch(100. * clip.AudioLength/clip.AudioRate / (clip.FrameCount/clip.FrameRate)) } # BestResample # # Resamples a clip's audio. Intelligently chooses SSRC(fast = true), SSRC(fast = false), or ResampleAudio based on # the guidelines in the Avisynth manual. # # function BestResample(clip clip, int samplerate) { return CanSSRC(clip.AudioRate, samplerate) \ ? WithinFactorOf(2, clip.AudioRate, samplerate) \ ? clip.SSRC(samplerate) \ : clip.SSRC(samplerate, fast=false) \ : clip.ResampleAudio(samplerate) } # Given a list of numbers, returns the one closest to the input # # PARAMETERS: # "input" : number to compare against # "numbers" : comma-delimited list of numbers to search # # function FindClosest(val input, string numbers) { # parse string into array RBDim("rates", 0, 0) # empty is ok - we'll fill it manually RBFill(rates, numbers) # need Length2 here since we filled manually global g_len = rates.Length2 global g_minDelta = input - rates0 global g_input = input for(1, "<g_len", "+1", \""" global g_minDelta = abs(g_input - rates.deref(i)) < abs(g_minDelta) \ ? g_input - rates.deref(i) \ : g_minDelta """) ret = input - g_minDelta return input.IsInt ? int(ret) : ret } # return true if f is less than the ratio between x & y # Example: WithinFactorOf(10, x, y) == "x is within an order of magnitude of y" # function WithinFactorOf(float f, float x, float y) { ratio = x>y ? x/y : y/x return ratio < f } # Computes the Greatest Common Divisor of two integers # (Euclid's Algorithm) # function GCD(int a, int b) { return (b == 0) \ ? a \ : GCD(b, a % b) } # Returns true if Avisynth's Shibatch sample rate converter function (SSRC) can convert # a clip with samplerate = src to dst, based on the documentation at <http://www.avisynth.org/SSRC> # function CanSSRC(int src, int dst) { fs1 = dst * src / GCD(src, dst) return (fs1 / dst == 1) || (fs1 / dst % 2 == 0) || (fs1 / dst % 3 == 0) }
__________________
See My Avisynth Stuff Last edited by real.finder; 13th August 2017 at 04:42. |
|
13th August 2017, 06:42 | #11 | Link |
Retried Guesser
Join Date: Jun 2012
Posts: 1,373
|
I see you have renamed the functions to avoid a name collision. I agree with that. Avisynth+ reserves for and while which are keywords in GScript, but with different syntax.
RBLength calls Throw("...") which does not exist; replace with Assert(false, "...") The test script has some oddities too, like JDL_FadeIO (replace with FadeIO(30)) and NullClip (replace with BlankClip) While the resulting script runs, the output is just a black screen with the message frameArr len: before 0, after 11. It's probably not running correctly. |
13th August 2017, 09:44 | #12 | Link | |
Registered User
Join Date: Jan 2012
Location: Mesopotamia
Posts: 2,587
|
Quote:
maybe later I will did more check for this especially if I need Arrays and Loops in future and since pinterf care about Arrays and did added it before in avs+ but remove it cuz it causing compatibility problems with 2.5 plugins, maybe this Thread by Richard Berg will give him some ideas
__________________
See My Avisynth Stuff |
|
Thread Tools | Search this Thread |
Display Modes | |
|
|