ConditionalReader

From Avisynth wiki
(Difference between revisions)
Jump to: navigation, search
m (added category)
(formatting, links, phrasing)
Line 1: Line 1:
{{Template:FuncDef|ConditionalReader(clip ''clip'', string ''filename'', string ''variablename'' [, bool ''show''])}}
+
Import information from a text file and assign a per-frame value to a script variable.
  
ConditionalReader allows you to import information from a text file, with different values for each frame - or a range of frames.
+
== Syntax and Parameters ==
 +
<div style="max-width:62em" >
 +
{{FuncDef
 +
|ConditionalReader(clip ''clip'', string ''filename'', string ''variablename'' [, bool ''show'' ] )
 +
}}
  
== Parameters ==
+
:{{Par2|clip|clip|}}
 +
::Source clip. Not touched, unless you specify {{FuncArg|show}}=true.
 +
 
 +
:{{Par2|filename|string|}}
 +
::Path to the file with the per-frame values you want to set. See [[#File format|File format]] below.
 +
 
 +
:{{Par2|variablename|string|}}
 +
::Name of the variable you want the {{FuncArg|filename}} values assigned to.
 +
 
 +
:{{Par2|show|bool|false}}
 +
::If ''true'', show the {{FuncArg|variablename}} value at the current frame (as determined by the file values) as a text overlay.
 +
</div>
  
{| border="1"
 
|-
 
| '''Parameter'''
 
| '''Description'''
 
| '''Default'''
 
|-
 
| clip
 
| The input clip. It is not touched, unless you specify show=true.
 
| not optional
 
|-
 
| filename
 
| The file with the variables you want to set.
 
| not optional
 
|-
 
| variablename
 
| The name of the variable you want the information inserted into.
 
| not optional
 
|-
 
| show
 
| When set to true, the value given at this frame will be overlayed on the image.
 
| false
 
|}<br>
 
  
 
== File format ==
 
== File format ==
 +
<div style="max-width:62em" >
 +
*The file is plain text. It is not case sensitive. Each line stands alone. There are several different line types, as explained below.
 +
 +
*The file may begin with one or more optional {{BoldColor|blue|100|''comment''}} lines:
 +
<div {{ListItemContinue}} >
 +
Any line is ignored if the first non-whitespace character is '<tt>#</tt>' (hash), '<tt>;</tt>' (semicolon) or '<tt>%</tt>' (percent).
 +
</div>
 +
<div {{BoxWidthIndent|24|4}} >
 +
#this line is a comment
 +
;so is this line
 +
      %and this one too.
 +
</div>
 +
 +
*The first non-{{BoldColor|blue|100|''comment''}} line must be a {{BoldColor|blue|100|''type''}} line, being one of the following:
 +
:: <code>TYPE int</code>
 +
::: (''ints'' are the digits 0-9, optionally preceded with a '+' or '-' sign)
 +
:: <code>TYPE float</code>
 +
::: (like ''int'' but containing a '.' decimal separator, and optionally followed by an 'e' or 'E' character plus an ''int'' exponent)
 +
:: <code>TYPE bool</code>
 +
::: ('true' or 'false')
 +
:: <code>TYPE string</code> (from v2.60)
 +
::: (any sequence of characters representing text)
 +
:The {{BoldColor|blue|100|''type''}} line defines the {{BoldColor|blue|100|''data''}} type to be parsed from this file and assigned to the variable {{FuncArg|variablename}}. You must have one, and only one, {{BoldColor|blue|100|''type''}} line per file, and it must come before any other lines, except for optional comments.
 +
 +
*The {{BoldColor|blue|100|''header''}} comes next, and consists of the following lines in any order:
 +
 +
::Optional {{BoldColor|blue|100|''default''}} line:
 +
:::<code>DEFAULT <value></code>
 +
:::This specifies the default value to be assigned to the script variable if there is no {{BoldColor|blue|100|''data''}} line defining a value for a given frame. If you do not define a default, you must be sure to specify a setting for all frames; or you will get unexpected results.
 +
 +
::Optional {{BoldColor|blue|100|''offset''}} line:
 +
:::<code>OFFSET <value></code> (from v2.60)
 +
:::When specified, this will add an offset to all frame numbers in the {{BoldColor|blue|100|''data''}} lines below.
 +
 +
::Optional {{BoldColor|blue|100|''comment''}} and empty line(s)
 +
 +
*Next come the {{BoldColor|blue|100|''data''}} line(s), which set the per-frame value(s) to be assigned to the script variable. There are three styles:
  
The ConditionalReader input file format can be [[wikipedia:Backus–Naur_Form|summarized]] as follows; see below for further explanation:
+
::''Single-frame'' data line:
 +
:::<code><framenumber> <value></code>
 +
:::Set ''value'' for frame ''framenumber'' only.
 +
 
 +
::''Range'' data line:
 +
:::<code>R <startframe> <endframe> <value></code>
 +
:::Apply ''value'' to a range of frames.
 +
:::Note that both ''startframe'' and ''endframe'' are included.
 +
 
 +
::''Interpolated'' data line:
 +
:::<code>I <startframe> <endframe> <startvalue> <stopvalue></code>
 +
:::Interpolate between two ''values'' over a range of frames. This only works on ''int'' and ''float'' types.
 +
:::Note that both ''startframe'' and ''endframe'' are included.
 +
 
 +
:''Values'' must be valid for the defined {{BoldColor|blue|100|''type''}}, as defined above, or file parsing will fail and an error will be raised.
 +
 
 +
 
 +
To sum up the file format in approximate [[wikipedia:Backus–Naur_Form|BNF]]-style:
 +
<div {{BoxWidthIndent|58|1}} >
 
  input_file:
 
  input_file:
 
     comment_line*  /* asterisk means zero or more */
 
     comment_line*  /* asterisk means zero or more */
Line 57: Line 105:
 
   | WS* 'I' WS <int startframe> WS <int endframe> WS <type startvalue> WS <type endvalue>
 
   | WS* 'I' WS <int startframe> WS <int endframe> WS <type startvalue> WS <type endvalue>
 
  )
 
  )
 +
</div>
 +
</div>
  
 
The file is plain text. All separation is done by spaces, and newline indicates a new data set. It is '''not''' case sensitive!
 
 
''' TYPE (int | float | bool | string) ''' <br>
 
You can only have one type of data in each file. Currently it is possible to have ''float'', ''int'', ''bool'' or (from v2.60) ''string'' values. You specify this by using the '''TYPE''' keyword. You should always start out by specifying the type of data, as nothing is saved until this keyword has been found.  It is not possible to change type once it has been set!
 
 
''' DEFAULT <value> ''' <br>
 
This specifies the default value of all frames. You should do this right after specifying the type, as it overwrites all defined frames. You can omit this setting, you you must be sure to specify a setting for all frames, as it will lead to unexpected results otherwise.
 
 
''' OFFSET <value> ''' (from v2.60)<br>
 
When specified, this will offset all framenumbers by a constant offset. This is done for all framenumbers which are set after this keyword.
 
 
''' <framenumber> <value> ''' <br>
 
This will set the value only for frame <framenumber>.
 
 
''' R <startframe> <endframe> <value> ''' <br>
 
This will apply a value to a range of frames. You should note that both start AND end-frame are included.
 
 
''' I <startframe> <endframe> <startvalue> <stopvalue> ''' <br>
 
This will interpolate between two values over a range of frames. This only works on int and float values. You should note that both start AND end-frame are included.
 
 
''' White space ''' <br>
 
Leading white space (spaces and tabs) is ignored up the first non-whitespace character, and then it is used to separate elements on the line.
 
 
''' Comments ''' <br>
 
Any line is a comment and ignored by ConditionalReader if the first non-whitespace character is '''#''' (hash), ''';''' (semicolon) or '''%''' (percent).
 
#this line is a comment
 
;so is this line
 
      %and this one too.
 
TYPE String
 
# No default
 
 
1 dog
 
2 cat
 
3 etc...
 
 
== Types ==
 
 
As mentioned, the types can be either ''float'', ''int'', ''bool'' or (from v2.60) ''string''.
 
 
''Int'' numbers is a number optionally preceded with a sign.
 
 
''Float'' is a decimal number containing a decimal point, optionally preceded by a sign and optionally followed by the e or E character and a decimal number. Valid entries are -732.103 or 7.12e4.
 
 
''Bool'' can either be ''true'' or ''false''.
 
 
''String'' is a sequence of characters representing text.
 
  
 
== Examples ==
 
== Examples ==
 
+
<div style="max-width:62em" >
=== Basic usage ===
+
===== ''Basic usage'' =====
 
+
:Example file ''File.txt:''
File.txt:
+
<div {{BoxWidthIndent|24|3}} >
 
+
 
  Type float
 
  Type float
 
  Default 3.45567
 
  Default 3.45567
Line 118: Line 120:
 
  2 -671.454
 
  2 -671.454
 
  72 -671.454
 
  72 -671.454
 +
</div>
  
The file above will return float values. It will by default return 3.45567.  However frames 45 to 300 it will return 76.5654. And frame 2 and 72 will return -671.454.  
+
:The file above will return values of type ''float''. It will return <tt>3.45567</tt> by default, but at frames 45-300 it will return <tt>76.5654</tt>, and at frames 2 and 72 it will return <tt>-671.454</tt>.  
  
As you might notice - later changes overrule settings done earlier in the file. This is illustrated by frame '72' - even though it is inside the range of 45-300, the later value will be returned. On the other hand - if the range was specified AFTER '72 -671.454' - it would return 76.5654.
+
:Later lines in the file overrule earlier ones. This is illustrated by the '72' line: even though frame 72 is inside the range of 45-300, frame 72 will use the value <tt>-671.454</tt>, not <tt>76.5654</tt>. If the 'R' line had been placed ''after'' the '72' line, the range value would have had priority.
  
A script to invoke this file could be:
+
:A script to invoke this file could be:
 
+
<div {{BoxWidthIndent|36|3}} >
  ColorBars(512,512)
+
  [[ColorBars]](512,512)
  Trim(0,500)
+
  [[Trim]](0,500)
  ScriptClip("subtitle(string(myvar))")
+
  [[ScriptClip]]("subtitle(string(myvar))")
 
  ConditionalReader("file.txt", "myvar", false)
 
  ConditionalReader("file.txt", "myvar", false)
 +
</div>
  
This will put the values into the variable called "myvar", which is used by [[Subtitle]], invoked by [[ScriptClip]] to display the conditional value.
+
:This will put the values into the variable called <tt>myvar</tt>, which is displayed with [[Subtitle]]. Subtitle must be invoked by [[ScriptClip]] to display the conditional value.
 
+
=== Adjusting Overlay ===
+
  
'''AviSynth script:'''
+
===== ''Adjusting Overlay'' =====
  ColorBars(512,256)
+
:Script:
  a1 = Trim(0,600)
+
<div {{BoxWidthIndent|52|2}} >
  a2 = MessageClip("Text clip")
+
  [[ColorBars]](512,256)
  Overlay(a1,a2, y = 100, x = 110, mode="subtract", opacity=0, pc_range=true)
+
  a1 = [[Trim]](0,600)
 +
  a2 = [[MessageClip]]("Text clip")
 +
  [[Overlay]](a1,a2, y = 100, x = 110, mode="subtract", opacity=0, pc_range=true)
 
  ConditionalReader("opacity.txt", "ol_opacity_offset", false)
 
  ConditionalReader("opacity.txt", "ol_opacity_offset", false)
 
  ConditionalReader("xoffset.txt", "ol_x_offset", false)
 
  ConditionalReader("xoffset.txt", "ol_x_offset", false)
 +
</div>
  
'''xoffset.txt:'''
+
:File ''xoffset.txt:''
 +
<div {{BoxWidthIndent|24|2}} >
 
  Type int
 
  Type int
 
  Default -50
 
  Default -50
Line 149: Line 155:
 
  R 50 250 100
 
  R 50 250 100
 
  I 250 275 100 250
 
  I 250 275 100 250
 +
</div>
  
'''opacity.txt:'''
+
:File ''opacity.txt:''
 +
<div {{BoxWidthIndent|24|2}} >
 
  Type float
 
  Type float
 
  Default 0.0
 
  Default 0.0
Line 157: Line 165:
 
  R 50 250 1.0
 
  R 50 250 1.0
 
  I 250 275 1.0 0.0
 
  I 250 275 1.0 0.0
 +
</div>
  
Basically it defines keyframes for an x-offset and the opacity. Frame 25->50 the opacity is scaled from 0.0 to 1.0, while the text is moving from left to right. The text is then kept steady from frame 50 to 250, whereafter it moves further to the right, while fading out. It is easier to watch the clip above than completely describe what it does.
+
:Basically this example defines ''keyframes'' for an [[Overlay]] x-offset and opacity. For frames 25-50 the opacity is scaled from 0.0 to 1.0, while the text is moving from left to right. The text is then kept steady from frame 50-250, and thereafter it moves further to the right while fading out. It is easier to watch the clip above than completely describe what it does.
  
=== Complicated ApplyRange ===
+
===== ''Complicated ApplyRange'' =====
 
+
:As you may have noticed, using a large number of [[ApplyRange]] calls in a script can lead to resource issues. Using '''ConditionalReader''' together with [[ConditionalFilter]] can lead to an efficient solution:
As you may have noticed using a large number of [[ApplyRange]]() calls in a script can lead to resource issue. Using ConditionalReader together with [[ConditionalFilter]] can lead to an efficient solution:
+
 
+
File.txt:
+
  
 +
:File ''File.txt:''
 +
<div {{BoxWidthIndent|24|3}} >
 
  Type Bool
 
  Type Bool
 
  Default False
 
  Default False
Line 175: Line 183:
 
  210 False
 
  210 False
 
  315 True
 
  315 True
 +
</div>
  
The file above will return boolean values. It will by default return False. However frames 2, 45 to 60, 72, 200 to 220 and 315 except for 210 it will return True. As you might notice, later changes overrule settings done earlier in the file. This is illustrated by frame '210' - even though it is inside the range of 200-220, the later value, False, will be returned.
+
:The file above will return boolean values. It will by default return False. However frames 2, 45 to 60, 72, 200 to 220 and 315 except for 210 it will return True. As you might notice, later changes overrule settings done earlier in the file. This is illustrated by frame '210' - even though it is inside the range of 200-220, the later value, False, will be returned.
  
A script to make use of this file could be:
+
:A script to make use of this file could be:
 
+
<div {{BoxWidthIndent|42|3}} >
  Colorbars(512,512)
+
  [[ColorBars]](512,512)
  Trim(0,500)
+
  [[Trim]](0,500)
 
  A = Last
 
  A = Last
  FlipHorizontal() # Add a complex filter chain
+
  [[FlipHorizontal]] # Add a complex filter chain
 
  B = Last
 
  B = Last
 
  ConditionalFilter(A, B, "MyVar", "==", "False", false)
 
  ConditionalFilter(A, B, "MyVar", "==", "False", false)
 
  ConditionalReader("File.txt", "MyVar", false)
 
  ConditionalReader("File.txt", "MyVar", false)
 +
</div>
  
This will put the values into the variable called "MyVar", which is used by [[ConditionalFilter]] to select between the unprocessed and flipped version of the source.
+
:This will put the values into the variable called <tt>MyVar</tt>, which is used by [[ConditionalFilter]] to select between the unprocessed and flipped version of the source.
 
+
'''Note!''' The ConditionalReader() line comes '''after''' any use of "MyVar" in your script.
+
 
+
=== Returning Strings ===
+
  
ConditionalReader cannot return strings prior to v2.60, but one solution is to create a list of variables with corresponding string assignments, and eval the indexed solution. For example:
+
:'''Note!''' The '''ConditionalReader''' line comes ''after'' any use of <tt>MyVar</tt> in the script.
  
  import("strings.txt")
+
===== ''Returning Strings'' =====
  ScriptClip("""subtitle(Eval("n"+string(mystringindex)))""")
+
:'''ConditionalReader''' cannot return strings prior to v2.60, but one solution is to create a list of variables with corresponding string assignments, and [[Internal functions/Eval|Eval]] the indexed solution.  For example:
 +
<div {{BoxWidthIndent|42|3}} >
 +
  [[Import]]("strings.txt")
 +
  [[ScriptClip]]("""subtitle([[Internal functions/Eval|Eval]]("n"+string(mystringindex)))""")
 
  ConditionalReader("range_string.txt", "mystringindex")
 
  ConditionalReader("range_string.txt", "mystringindex")
 +
</div>
  
range_string.txt
+
:File ''strings.txt''
 +
<div {{BoxWidthIndent|24|3}} >
 +
n0=""
 +
n1="Intro"
 +
n2="Main"
 +
n3="Credits"
 +
</div>
  
 +
:File ''range_string.txt''
 +
<div {{BoxWidthIndent|24|3}} >
 
  Type int
 
  Type int
 
  Default 0
 
  Default 0
Line 208: Line 226:
 
  R 1005 3000 2
 
  R 1005 3000 2
 
  R 3200 3800 3
 
  R 3200 3800 3
 +
</div>
  
strings.txt
+
:Obviously ''strings.txt'' does not need to be a separate file, but this solution is sometimes appropriate in e.g., multilingual applications:
n0=""
+
<div {{BoxWidthIndent|24|3}} >
n1="Intro"
+
n2="Main"
+
n3="Credits"
+
 
+
Obviously strings.txt does not need to be a separate file, but this solution is sometimes appropriate in some multilingual applications, e.g.
+
 
  language="spanish"  
 
  language="spanish"  
  import(language + "_strings.txt")
+
  [[Import]](language + "_strings.txt")
 +
</div>
 +
</div>
 +
 
  
'''Changelog:'''
+
== Changelog ==
  
 
{|border=1 cellspacing=1 cellpadding=4
 
{|border=1 cellspacing=1 cellpadding=4

Revision as of 15:07, 24 February 2016

Import information from a text file and assign a per-frame value to a script variable.

Contents

Syntax and Parameters

ConditionalReader(clip clip, string filename, string variablename [, bool show ] )

clip  clip =
Source clip. Not touched, unless you specify show=true.
string  filename =
Path to the file with the per-frame values you want to set. See File format below.
string  variablename =
Name of the variable you want the filename values assigned to.
bool  show = false
If true, show the variablename value at the current frame (as determined by the file values) as a text overlay.


File format

  • The file is plain text. It is not case sensitive. Each line stands alone. There are several different line types, as explained below.
  • The file may begin with one or more optional comment lines:

Any line is ignored if the first non-whitespace character is '#' (hash), ';' (semicolon) or '%' (percent).

#this line is a comment
;so is this line
     %and this one too.
  • The first non-comment line must be a type line, being one of the following:
TYPE int
(ints are the digits 0-9, optionally preceded with a '+' or '-' sign)
TYPE float
(like int but containing a '.' decimal separator, and optionally followed by an 'e' or 'E' character plus an int exponent)
TYPE bool
('true' or 'false')
TYPE string (from v2.60)
(any sequence of characters representing text)
The type line defines the data type to be parsed from this file and assigned to the variable variablename. You must have one, and only one, type line per file, and it must come before any other lines, except for optional comments.
  • The header comes next, and consists of the following lines in any order:
Optional default line:
DEFAULT <value>
This specifies the default value to be assigned to the script variable if there is no data line defining a value for a given frame. If you do not define a default, you must be sure to specify a setting for all frames; or you will get unexpected results.
Optional offset line:
OFFSET <value> (from v2.60)
When specified, this will add an offset to all frame numbers in the data lines below.
Optional comment and empty line(s)
  • Next come the data line(s), which set the per-frame value(s) to be assigned to the script variable. There are three styles:
Single-frame data line:
<framenumber> <value>
Set value for frame framenumber only.
Range data line:
R <startframe> <endframe> <value>
Apply value to a range of frames.
Note that both startframe and endframe are included.
Interpolated data line:
I <startframe> <endframe> <startvalue> <stopvalue>
Interpolate between two values over a range of frames. This only works on int and float types.
Note that both startframe and endframe are included.
Values must be valid for the defined type, as defined above, or file parsing will fail and an error will be raised.


To sum up the file format in approximate BNF-style:

input_file:
    comment_line*   /* asterisk means zero or more */
    WS* 'TYPE' WS ( 'int' | 'float' | 'bool' | 'string' ) /* choose one */
    header
    data_line+      /* plus sign means one or more */

comment_line:
    WS* ( '#' | ';' | '%' ) <ignore any characters to end of line>

WS: 
    ( ' ' | '\t' )+ /* WS = one or more spaces or tabs */

header:             /* header = zero or more of the following in any order */
(
    WS* 'DEFAULT' WS <type value>       /* legal value for TYPE */
  | WS* 'OFFSET' WS <int offset_value>
  | WS*
  | comment_line
)*

data_line:          /* data = one or more of the following in any order */
(
    WS* <int framenumber> WS <type value>
  | WS* 'R' WS <int startframe> WS <int endframe> WS <type value>
  | WS* 'I' WS <int startframe> WS <int endframe> WS <type startvalue> WS <type endvalue>
)


Examples

Basic usage
Example file File.txt:
Type float
Default 3.45567

R 45 300 76.5654
2 -671.454
72 -671.454
The file above will return values of type float. It will return 3.45567 by default, but at frames 45-300 it will return 76.5654, and at frames 2 and 72 it will return -671.454.
Later lines in the file overrule earlier ones. This is illustrated by the '72' line: even though frame 72 is inside the range of 45-300, frame 72 will use the value -671.454, not 76.5654. If the 'R' line had been placed after the '72' line, the range value would have had priority.
A script to invoke this file could be:
ColorBars(512,512)
Trim(0,500)
ScriptClip("subtitle(string(myvar))")
ConditionalReader("file.txt", "myvar", false)
This will put the values into the variable called myvar, which is displayed with Subtitle. Subtitle must be invoked by ScriptClip to display the conditional value.
Adjusting Overlay
Script:
ColorBars(512,256)
a1 = Trim(0,600)
a2 = MessageClip("Text clip")
Overlay(a1,a2, y = 100, x = 110, mode="subtract", opacity=0, pc_range=true)
ConditionalReader("opacity.txt", "ol_opacity_offset", false)
ConditionalReader("xoffset.txt", "ol_x_offset", false)
File xoffset.txt:
Type int
Default -50

I 25 50 -50 100
R 50 250 100
I 250 275 100 250
File opacity.txt:
Type float
Default 0.0

I 25 50 0.0 1.0
R 50 250 1.0
I 250 275 1.0 0.0
Basically this example defines keyframes for an Overlay x-offset and opacity. For frames 25-50 the opacity is scaled from 0.0 to 1.0, while the text is moving from left to right. The text is then kept steady from frame 50-250, and thereafter it moves further to the right while fading out. It is easier to watch the clip above than completely describe what it does.
Complicated ApplyRange
As you may have noticed, using a large number of ApplyRange calls in a script can lead to resource issues. Using ConditionalReader together with ConditionalFilter can lead to an efficient solution:
File File.txt:
Type Bool
Default False

2 True
R 45 60 True
72 True
R 200 220 True
210 False
315 True
The file above will return boolean values. It will by default return False. However frames 2, 45 to 60, 72, 200 to 220 and 315 except for 210 it will return True. As you might notice, later changes overrule settings done earlier in the file. This is illustrated by frame '210' - even though it is inside the range of 200-220, the later value, False, will be returned.
A script to make use of this file could be:
ColorBars(512,512)
Trim(0,500)
A = Last
FlipHorizontal # Add a complex filter chain
B = Last
ConditionalFilter(A, B, "MyVar", "==", "False", false)
ConditionalReader("File.txt", "MyVar", false)
This will put the values into the variable called MyVar, which is used by ConditionalFilter to select between the unprocessed and flipped version of the source.
Note! The ConditionalReader line comes after any use of MyVar in the script.
Returning Strings
ConditionalReader cannot return strings prior to v2.60, but one solution is to create a list of variables with corresponding string assignments, and Eval the indexed solution. For example:
Import("strings.txt")
ScriptClip("""subtitle(Eval("n"+string(mystringindex)))""")
ConditionalReader("range_string.txt", "mystringindex")
File strings.txt
n0=""
n1="Intro"
n2="Main"
n3="Credits"
File range_string.txt
Type int
Default 0

R 10 1000 1
R 1005 3000 2
R 3200 3800 3
Obviously strings.txt does not need to be a separate file, but this solution is sometimes appropriate in e.g., multilingual applications:
language="spanish" 
Import(language + "_strings.txt")


Changelog

v2.60 Added OFFSET, Added Type=string.
Personal tools