式(Expressions)¶
NODE タブの FX 欄と Expression SIG Node で使う、小さな式言語のリファレンスです。
どの規格にも準拠しない独自の言語で(実装:crates/lemonade-core/src/expr.rs)、演算子は C、関数名は GLSL に合わせています。値はすべて float の 1 種類です。
trig(0) > 0.5 ? 1 : x * phase
mix(x1, x2, smoothstep(0.2, 0.8, low))
mod(floor(beats / 4), 2) == 0 ? v : 0
演算子¶
上ほど優先度が低い順です。
| 優先度 | 演算子 | 備考 |
|---|---|---|
| 1 | a ? b : c |
右結合(a ? b : c ? d : e と書ける) |
| 2 | \|\| |
短絡評価。結果は 1 か 0 |
| 3 | && |
短絡評価。結果は 1 か 0 |
| 4 | == != |
float をそのまま比較 |
| 5 | < <= > >= |
|
| 6 | + - |
左結合 |
| 7 | * / % |
左結合。% は C と同じで、結果の符号は左辺に従う |
| 8 | 単項 - + ! |
!x は x が 0 なら 1、それ以外は 0 |
( ) でグループ化できます。真偽値は 1 と 0 で、0 以外は真として扱います。
変数¶
どこでも使える値(エンジンの値)¶
| 名前 | 内容 |
|---|---|
time |
起動からの秒数 |
dt |
前フレームからの秒数 |
bpm |
テンポ |
phase |
拍内の位置 0..1 |
beat |
拍ごとのパルス(拍の頭で 1、0 に向かって減衰) |
beats |
累計拍数(連続値。小数部が phase) |
level |
全体の音量 0..1 |
onset |
アタックの強さ |
sub low mid high |
帯域ごとのレベル 0..1 |
pi |
3.14159… |
パラメタの FX 欄だけで使える値¶
| 名前 | 内容 |
|---|---|
x |
接続されているワイヤーを combine(mul / add / min / max / avg)した値。未接続ならスライダーの値 |
x1〜x4 |
各ワイヤーの値。未接続なら 0 |
v |
スライダーで設定した元の値 |
Expression Node の中だけで使える値¶
| 名前 | 内容 |
|---|---|
a b c d |
Node の入力ポートの値。未接続なら 0 |
関数¶
| 関数 | 内容 |
|---|---|
sin(x) cos(x) tan(x) |
ラジアン |
abs(x) sign(x) |
sign(0) は 0 |
floor(x) ceil(x) round(x) fract(x) |
fract(x) = x - floor(x) |
sqrt(x) |
負の値は 0 として計算 |
pow(a, b) |
|
min(a, b) max(a, b) |
|
mod(a, b) |
GLSL と同じで、結果の符号は b に従う(mod(-1, 4) = 3) |
step(edge, x) |
x >= edge なら 1、それ以外は 0 |
clamp(x, lo, hi) |
|
mix(a, b, t) |
a + (b - a) * t |
smoothstep(e0, e1, x) |
引数の順番は GLSL と同じ |
hash(x) |
x から決まる疑似乱数 0..1(同じ x なら同じ値) |
trig(i) |
トリガーパッドの値。0 始まりなので、パッド 1〜4 は trig(0)〜trig(3) |
band(i) |
帯域 0..3(0 = sub, 1 = low, 2 = mid, 3 = high) |
hit(i) |
帯域 i(0 = sub, 1 = low, 2 = mid, 3 = high)のアタックがしきい値(AUDIO タブ)を超えた瞬間に 1、減衰して 0 |
fft(i) |
FFT のビン 0..63(対数間隔) |
trig band fft はインデックスの小数点以下を切り捨て、範囲外のインデックスでは 0 を返します。
構文(EBNF)¶
式の文法です(ISO 14977 の EBNF:, は連接、| は選択、[ ] は省略可、{ } は 0 回以上の繰り返し)。
expr.rs の再帰下降パーサー(ternary → 優先順位法の binary → unary → primary)と同じ構造で、上の演算子表の優先度・結合性はこの規則から決まります。
expression = ternary ;
ternary = or , [ "?" , ternary , ":" , ternary ] ; (* 右結合 *)
or = and , { "||" , and } ; (* 以下はすべて左結合 *)
and = equality , { "&&" , equality } ;
equality = comparison , { ( "==" | "!=" ) , comparison } ;
comparison = additive , { ( "<" | "<=" | ">" | ">=" ) , additive } ;
additive = multiplicative , { ( "+" | "-" ) , multiplicative } ;
multiplicative = unary , { ( "*" | "/" | "%" ) , unary } ;
unary = ( "-" | "+" | "!" ) , unary
| primary ;
primary = number
| call
| name
| "(" , ternary , ")" ;
call = name , "(" , [ ternary , { "," , ternary } ] , ")" ;
字句(トークン)の規則:
number = digit , { digit | "." }
| "." , digit , { digit | "." } ; (* 全体が 10 進の小数として読めること *)
name = ( letter | "_" ) , { letter | digit | "_" } ;
letter = "A" | … | "Z" | "a" | … | "z" ; (* ASCII のみ *)
digit = "0" | … | "9" ;
- 空白(スペース・タブ・改行)はトークンの間で無視されます。
sin (x)もsin(x)と同じです。 - 2 文字の演算子(
||&&==!=<=>=)は 2 文字のまとまりとして先に読まれます。|、&、=単独は使えません。 numberは数字と.を続く限り読んでから数値にするので、1.2.3はエラーです。1.は 1 と同じです。nameの直後に(があれば関数呼び出し(call)です。関数名は下の関数表のもので、引数の数が合わないとエラーになります。- それ以外の
nameは、その場所だけで使える値(FX 欄のxx1..x4v、Expression Node のa..dなど)、エンジンの値の順に探し、どちらにもなければエラーです。 - 式全体が空、または
expressionの後に余りのトークンがあるとエラーです。 - 比較も左結合なので、
a < b < cは(a < b) < c(0 か 1 と c の比較)になります。 - 単項演算子は二項演算子より強く結びつきます。
-x * yは(-x) * y、!a == bは(!a) == bです。
C / GLSL と違うところ¶
- 数値は
1、0.5、.5の形だけです。1e3のような指数表記、16 進数、true/falseは使えません。 - 代入、ビット演算、
vec2などのベクトル型、コメントはありません。 - 名前は大文字と小文字を区別します。
エラーと結果の扱い¶
- 知らない名前、引数の数の誤り、構文エラーは、書いた時点で NODE タブにエラー位置付きで表示されます。その間、パラメタはスライダーの値を使います(Expression Node は 0 を出力)。
- 0 除算などで結果が NaN や無限大になった場合は 0 になります。
- パラメタに入る値は、最後にそのパラメタの範囲に clamp されます。int のパラメタは四捨五入、bool のパラメタは 0 以外なら true になります。
例¶
| やりたいこと | 式 | 備考 |
|---|---|---|
| パッド 1 でフラッシュ | trig(0) > 0.5 ? 1 : 0.2 |
|
| キックでフラッシュ | v + hit(1) |
low 帯域のヒット |
| 拍に合わせてパルス | v + beat * 0.5 |
|
| 低音で量を変える | mix(v, 1, low) |
|
| 2 拍で 1 回転 | fract(beats / 2) * 360 - 180 |
Transform rotate など |
| ワイヤーの値をスケール | x * 32 |
LFO (0..1) → Blur radius |
| LFO をパッドでゲート | x1 * x2 |
LFO → wire 1、Trigger → wire 2(IN ×2 の mul と同じ) |
| 2 本のワイヤーをクロスフェード | mix(x1, x2, x3) |
wire 3 がフェーダー |
| 1 小節おきにオン | mod(floor(beats / 4), 2) == 0 ? v : 0 |
|
| 拍ごとにランダム | hash(floor(beats)) |
テキストのテンプレート¶
文字列のパラメタ(Text の text、Image / Video の file、font file など)の FX 欄と、STR の Format Node では、上の式を {…} に埋め込んだテンプレートを書きます(実装:crates/lemonade-core/src/template.rs)。
/clips/{floor(beats) % 4:.0}.mp4
{v} · {bpm:.0} BPM
{x1}/{x2}-{floor(beats) % 4:02}.png
{…}の外はそのまま文字として出力されます。{{と}}は{と}1 文字になります。{名前}が文字列の変数ならその文字列が入ります。- FX 欄:
x(つないだ STR ワイヤーを順に連結したもの。未接続ならパラメタの値)、x1..x4(各ワイヤー。未接続は空文字)、v(パラメタの値) - Format Node:
s1、s2 - それ以外は数値の式として評価されます。使える名前は、エンジンの値と関数、Format Node では入力の
a..dです。 - 最後の
:の後に書式を付けられます。空白を入れずに書いてください(a ? b : cの:と区別するためです)。
| 書式 | 意味 | 例(値 7.456) |
|---|---|---|
.2 |
小数 2 桁 | 7.46 |
03 |
3 文字になるまで先頭を 0 で埋める | 7.456(小数点以下は既定のまま) |
05.1 |
0 埋めで 5 文字、小数 1 桁 | 007.5 |
4 |
4 文字になるまで先頭を空白で埋める | 7.456 |
| なし | 必要な桁だけ | 7.456 |
- IN のワイヤーだけで FX 欄が空なら、つないだ文字列を順に連結したものがそのまま値になります。
- テンプレートのエラーは NODE タブに表示されます。その間は連結したワイヤー(なければパラメタの値)が使われます。
- 例:Image の
fileを File List のpathにつなぐと、indexを拍で進めるだけでスライドショーになります。Video のfileを拍ごとに変えると、そのたびにデコーダーを起動し直します。1 拍に 1 回程度にしてください。
テンプレートの構文¶
template = { literal | "{{" | "}}" | "}" | hole } ;
literal = character - ( "{" | "}" ) , { character - ( "{" | "}" ) } ;
hole = "{" , body , "}" ; (* body に { と } は書けない *)
body = text-name
| expression , [ ":" , format ] ;
format = [ digits ] , [ "." , digits ] ; (* 空でないこと。数字と . だけ *)
digits = digit , { digit } ;
{{は{、}}は}、対になっていない}はそのまま}1 文字になります。閉じていない{と、穴の中の{はエラーです。bodyを前後の空白を除いて比べ、文字列の変数の名前(x、x1..x4、v、s1、s2など)と一致すればtext-nameです。- それ以外は、最後の
:で分け、後ろがformatとして読めればそれが書式、読めなければ(空白を含む、など)body全体をexpressionとして読みます。そのため{a ? b : c}はそのまま三項演算子になります。 逆に、三項演算子の最後の項が数字だけのときは:の後に空白を入れてください({a ? b : 2})。{a ? b :2}だと2が書式と読まれ、a ? bが不完全な式としてエラーになります。 formatの幅が0で始まると 0 埋め、それ以外は空白で埋めます。