ugsのマニュアル v1.0.0
作成日:2021.04.04
用語の定義は「[用語名]とは、」から始まるので、文書内検索する際に役立ててください。
▼目次
- ugsとは
- 全体の形式
- ログ
- 正規表現
- コメント
- Script
- Rule
- 文字列
- 数値
- 真偽値
- 演算子
- ustのプロパティ
- 音符のプロパティ
- 変数
- 予約語
- 引数
- 式
- 代入
- 音符の挿入・削除
- デバッグ用出力
- 条件分岐
- その他注意事項など
- ヒント
- 文法以外の話題
ugsとは
ugsとは、UST Generator Script の略称です。そのまま拡張子名にもなっています。 今のところはプラグインとしては使えませんが、簡易的なUTAUのプラグインを作れるプログラミング言語です。
全体の形式
ugsの文字コードは UTF-8 である必要があります。一方、出力されるustの文字コードは Shift JIS です。
各行の初めと終わりの空白は無視されます。すなわちインデントの形式は自由です。
空行も無視されます。
演算子と値の間など、多くのプログラミング言語と同様に適宜空白を入れることができます。
コメントと空白以外の文字がある行は以下のものいずれかがちょうど1つだけある必要があります。
ログ
ugsの実行によりログが出力されます。
エラーとは、 "Error:" から始まるメッセージのことで、そのエラーが発生したファイルと行番号、エラーの要因が書かれています。その情報を見てugsのデバッグをする必要があります。必要に応じてprint文を使うのがよいでしょう。
但しメッセージに "internal error" を含む場合は、ソフトウェアのバグなので、示されたugsファイルの中身とメッセージとともに作者に文句を言ってください。
エラーがなければustが生成され、"正常にustを生成できました。"というメッセージが出力されます。この場合でも警告や情報が出力されることがあります。
警告とは、 "Warning:" から始まるメッセージのことで、一応動作するが非推奨なコードや意図しない動作をしていることが予想される場合に出力されます。
情報とは、 "Info:" から始まるメッセージのことで、デバッグ用出力やエラーに付随する情報が書かれています。
なおメッセージの意味がわかりにくいと感じた場合、作者に文句を言うと改善される可能性があります。
正規表現
JavaScriptの正規表現と同じです。 文字列strを正規表現とみなすとは、JavaScript上で
new RegExp(str, 'u')
とするということです
(uフラグは文字列をUnicodeのコードポイントの連続として扱う、すなわち漢字や絵文字もしっかり1文字として扱うことを表すものです)。
コメント
コメントとは、"//" 以降行末までのことで、存在しないものとして解釈されます。
Script
Script文とは、"Script:"、Script名 の順で並んだもののことです。間の空白は任意です。
Script名とは、resources/script フォルダからの相対パスから拡張子 .ugs を除いたもののことです。
例)resources/script/hoge/fuga.ugs のscript名は hoge/fuga
Script内とは、Script文とそれ以降はじめて記述されているScript文またはRule文かファイル末尾の間にある文のことです。
Script内が1度実行された後、Script名で示されたscriptを呼び出して実行します。そのscriptの処理がすべて終わったら呼び出し元に戻り、次のScript文かRule文から実行を再開します。
script呼び出しの前に実行した文で引数が定義されていた場合、引数名から"#"を除いた名前のグローバル変数が引数の値で定義されている状態で呼び出し先の処理が始まります。
script呼び出しにおいて自己参照、循環参照は検出してエラーにします。
Rule
Rule文とは、"Rule:"、パターン の順で並んだもののことです。間の空白は任意です。
パターンとは、"/" から始まり、"/"がエスケープされた正規表現、"/" を任意回繰り返したもののことです。
パターンの長さとは、パターンに含まれるエスケープされていない"/"の数から1引いた数のことです。
パターンの末尾にオプション("h", "t", "r")を1つまでつけることができます。但しパターンの長さが0のときは "h" と "t" のいずれか一方をつける必要があります。
パターン内の "${[ustのプロパティまたは変数]}" は、ustのプロパティまたは変数の値に置換されます。この置換は先頭の"$"がエスケープされているかを確認せずに行います。
この仕様は例えば \${3} が "$$$" にマッチするのを妨げません。
Rule内とは、Rule文とそれ以降はじめて記述されているScript文またはRule文かファイル末尾の間にある文のことです。
オプションがない場合の挙動は次の通りです。
- 音符を先頭から順に見ていき、2.-3. を繰り返す。
- 見ている音符の歌詞(Lyric)がパターンの1つ目の正規表現にマッチするかを調べる。マッチするならば、その次の音符の歌詞がパターンの2つ目の正規表現にマッチするかを調べる。同様のことをパターンの長さだけ行う。 この手順中、次の音符がない場合はマッチしなかったとみなす。
- 2.でマッチしなかった正規表現がない場合はパターン内を実行する。このとき今見ている音符がindex0に対応する。
"h"(head)オプションがついている場合は、1.が「先頭の音符において 2.-3. を行う。」となります。
"t"(tail)オプションがついている場合は、1.が「後ろから数えて(パターンの長さ)番目の音符において 2.-3. を行う。」となります。言い換えると「パターン最後の正規表現が最後の音符の歌詞に対応するような位置で 2.-3. を行う」ということです。
"r"(reverse)オプションがついている場合は、1.が「音符を末尾から逆順にみていき、2.-3. を繰り返す。」となります。
文字列
文字列とは、対応する引用符('や")で囲われたもののことです。 ''内に単一引用符、 ""内に二重引用符を含めることはできません。もし両方を含む文字列を使いたい場合は文字列連結演算子(&)を使用してください。 数値や真偽値の形式と合致する文字列はそれぞれ数値, 真偽値としても扱われます。
数値
整数であっても内部的にはすべて浮動小数点数として扱われます。
固定小数点表記(3.14など)と指数表記(4.41e4など)に対応しています。
指数表記のeはEも許容され、指数部が非負ならその直後に+を付けることも可能です。
例)1E+2 は 1e2 に等しい
小数を表すとき、整数部が0の場合はそれを省略することが可能です。
例).25 は 0.25 に等しい
その一方で、小数部が0の場合にそれを省略することはできません。
例)1.0 を 1. とはかけない(1 とかくことは当然できる)
これは 1.e2 が 100 のことを指すのか indexが1の音符のプロパティe2 のことを指すのかが曖昧にならないようにするための仕様です。
プログラム中にかかれた負の数は単項の - と非負数の並びとして扱われます。
無限大(Inf)や非数(NaN)は扱えません。
真偽値
真偽値とは、true あるいは false のことです。
演算子
算術演算子
加減乗除の演算のために それぞれ +, -, *, / が使えます。 演算は浮動小数点数として行われ、0割りなどによって無限大や非数になった場合はエラーとなります。 単項の +, - も使えますが、2つ以上並べるとエラーになります。
文字列連結演算子
& は2つの文字列を並べた順で連結します。 すべての値は文字列として扱われるので、例えば 1 & 3 とかくことができて評価結果は 13 となります。
比較演算子
>=, >, <=, < は数値の大小比較をします。両辺が数値として解釈できない場合はエラーになります。
==, != は両辺が数値であるならば数値比較、そうでないなら文字列比較になります。
例)"1e2" == "100" は true
=~, !~ は左辺の文字列が右辺の正規表現にマッチする(しない)かを評価します。正規表現は文字列として表されます。
例)=~ や !~ の右辺にある "[あいうえお]" は あ,い,う,え,お のうち1つ以上を含む文字列とマッチする正規表現と解釈される
論理演算子
and(&&), xor(^), or(||), not(!) がキーワード、記号ともに使えます。 not(!) を2つ以上並べるとエラーになります。
三項演算子
A ? B : C の評価値は Aの評価値が "true" ならBの評価値、"false" ならCの評価値になります。このときBとCのうち評価値を使わないほうは計算されません。またAの評価値が真偽値でないならばエラーとなります。
A ~ B -> C の評価値は Bの評価値を正規表現とみなし、JavaScriptでいうところの
[Aの評価値].replace(new RegExp([Bの評価値], 'u'), [Cの評価値])
になります。
代入演算子
= は左辺の変数に右辺の評価値を代入します。但し左辺が Flags プロパティである場合、例外的な挙動をします(ustのプロパティ、音符のプロパティの該当する箇所を参照のこと)。
+=, -=, *=, /=, &= は左辺の変数の値と右辺の評価値の演算結果を左辺の変数に代入します。
例)A += B は A = A + (B) と等価
:= は左辺の変数が定義されていなければ右辺の評価値を代入します。scriptが受け取る予定の引数のデフォルト値を記述することができます(= を使うと渡された引数を上書きしてしまう)。
演算子の優先順位
優先順位が高いものから順に以下の通りです。
- 単項演算子(+,-,not)
- 乗除算(*,/)
- 加減算(+,-)
- 文字列連結演算子(&)
- 数値の大小比較演算子(>=,>,<=,<)
- 上記以外の比較演算子(==,!=,=~,!~)
- and(&&)
- xor(^)
- or(||)
- 三項演算子
- 代入演算子
演算子の結合
単項演算子、三項演算子、代入演算子は右結合、その他は左結合です。
ustのプロパティ
ustのプロパティとは、"$"にプロパティ名が続くもののことです。
ここでのプロパティ名の形式は、ラテン文字([A-Za-z])で始まり、その後にラテン文字と数字([0-9])とアンダーバー(_)が任意の数が続く(ugsの文法要素ではなく一般的な意味の方の)文字列です。
デフォルトではすべてのプロパティが未定義です。
定義されたプロパティはustの[#SETTING]セクションに [プロパティ名]=[プロパティの値] の形で書き込まれます。プロパティ名はustファイルをテキストエディタで開くなどして確認してください。
$Flags には以下のような特別な記法があったり、代入時に例外的な挙動をしたりします。
- $Flags.[フラグ名] とかくことで、特定のフラグの値を参照・代入できます。
- $Flags.[フラグ名] には真偽値を代入できます。true を代入した場合、数字指定なしのフラグとして扱われます。false を代入した場合、そのフラグは指定されていないものとして扱われます。
- $Flags に文字列を代入することで、フラグを一括で設定できます。このとき記述されなかったフラグの値は消えずにそのまま残ります。
フラグ名から始まり、フラグ名と整数が交互に連結された文字列のみが代入できます。
フラグ名の区切りに整数が来ることが想定されているので、数字指定なしのフラグを同時に2つ設定できません。
例)"NW" は フラグNとフラグW ではなく フラグNW として扱われる - $Flags の各フラグの数値はustに出力するときに整数に丸められます。
音符のプロパティ
Rule内でのみ使えます。
音符のプロパティとは、index、"."、プロパティ名の順に並んだもののことです。間に空白があってはいけません。
indexは0以上Ruleのパターンの長さ未満の整数であり、indexで指定される音符(パターンの先頭から0,1,2,...)のプロパティを操作することを示します。
ここでのプロパティ名の形式は、ラテン文字([A-Za-z])で始まり、その後にラテン文字と数字([0-9])とアンダーバー(_)が任意の数が続く(ugsの文法要素ではなく一般的な意味の方の)文字列です。さらに頭に"$"がついたものもプロパティ名として扱われます。
デフォルト値は Length = 480(四分音符)、NoteNum = 60(C4)、Lyricは与えられた値、その他は未定義です。
定義されたプロパティはustの対応する音符のセクションに [プロパティ名]=[プロパティの値] の形で書き込まれます。プロパティ名はustファイルをテキストエディタで開くなどして確認してください。
Flags はustのプロパティ $Flags と同様の記法や代入時の例外的な挙動があります。それに加えて以下の例外的な挙動があります。
- Flags や Flags.[フラグ名] の値を参照しようとしたときにそれが定義されていなかった場合、代わりにustのプロパティ($Flags や $Flags.[フラグ名])の値を参照します。
Envelope には以下のような特別な記法があったり、代入時に例外的な挙動をしたりします。
- Envelope.[要素名] とかくことで、特定の要素の値を参照・代入できます。 要素名は p1, p2, p3, p4, p5, v1, v2, v3, v4, v5 のいずれかです。
- Envelope には "p1,p2,p3,v1,v2,v3,v4,%,p4,p5,v5" の形の文字列が代入できます(要素名には数値が入る)。v4 以降の途中のコンマ(,)の直前("%"を除く)で打ち切った文字列も代入可能です。これらはustの書式と同様の仕様です。
- Envelope が定義されていない状態で Envelope 自身やその要素のいずれかに代入・参照しようとすると、Envelope に "0,5,35,0,100,100,0,%,0,10,100" が代入されていたものとして扱われます。
変数
変数とは、ラテン文字([A-Za-z])で始まり、ラテン文字と数字([0-9])とアンダーバー(_)のみで構成される(ugsの文法要素ではなく一般的な意味の方の)文字列のうち、予約語でないもののことです。
大文字から始まるものはグローバル変数であり、再代入されない限り1つのugsファイルを通して同じ値を持ちます。異なるugsに値を持ち越したい場合はScriptの引数を活用してください。
小文字から始まるものはローカル変数っぽいものであり、Rule文やScript文を通過するたびにリセットされます。同じRule文によるループ間で変数の値が持ち越されるので、:= を活用することで何かができる余地があります。
一度も代入されていない変数の値を読もうとするとエラーになります。また再代入は可能です。
予約語
予約語とは、以下に列挙されているもののことで、現在あるいは将来においてugsの重要な機能を表す語として利用されている、あるいはされる可能性があるので変数名としては使えません。
Rule, Script, Plugin, Exec, Version,
insert, delete, print, if, else, end, true, false, and, or, not, xor,
break, continue, for, while, undefined, return, function
引数
Script内でのみ使えます。
引数とは、"#"にグローバル変数と同じ形式の文字列が続くもののことです。
一度も代入されていない引数の値を読もうとするとエラーになります。また再代入は可能です。
式
式とは、代入演算子以外の演算子、文字列、数値、真偽値、変数(プロパティや引数を含む)、優先順位を表すための丸括弧 の組み合わせのうち正しい並びをしているもののことです。
これら0個の並びも式であり、空文字列("")と等価です。
式の構成要素の前後には任意の数の空白を入れることができます。
式の評価値とは、式の記述通りに演算した結果得られる文字列のことです。数値や真偽値も文字列になりますが、文字列の項にある通りそれはそれぞれ数値や真偽値としても扱われます。
代入
代入文とは、プロパティまたは変数、代入演算子、式 の順で並んだもののことです。それぞれの間の空白は任意です。 代入文の作用については、代入演算子の項を参照してください。
音符の挿入・削除
Rule内でのみ使えます。
音符の挿入
insert文とは、"insert"、1つ以上の空白、index、任意の数の空白、":"、任意の数の空白、式 の順で並んだもののことです。
insert文内の式の評価値は挿入する音符の歌詞を表します。
insert文には対応する "end" が存在し、それらの間の行に記述されるプロパティ設定文で挿入される音符のプロパティを設定できます。
プロパティ設定文とは、プロパティ名、":"、式 の順で並んだものであり、それぞれの間の空白は任意です。
同じプロパティ名が2度以上設定された場合は、より後の行に出てきたものの式の評価値が採用されます。Lyricを設定した場合はinsert文で表した歌詞を上書きします。
indexは0以上パターンの長さ以下の整数であり、indexで指定される位置(パターンの先頭の音符の直前が0, 以降音符の間と末尾に順に番号がふられる)への音符の挿入を予約します。
挿入の予約後も index が指定する位置は変わりません。
同じ位置に挿入の予約をした場合、後に予約されたものほど後ろになります。
挿入が実際に行われるのは、予約が行われた1ループが終了したときです。
音符の削除
delete文とは、"delete"、1つ以上の空白、index の順で並んだもののことです。
indexは0以上Ruleのパターンの長さ未満の整数であり、delete文はindexで指定される音符(パターンの先頭から0,1,2,...)の削除を予約します。
削除の予約後も index が指定する位置は変わらず、その音符のプロパティにもアクセスできます。
すでに削除の予約がされている音符を再び削除しようとしてもエラーにはなりませんが警告が出ます。
削除が実際に行われるのは、予約が行われた1ループが終了したときです。
挿入・削除による影響
挿入や削除が行われたか否かに関わらず、次にパターンマッチするか調べる位置は 直前に調べた音符(削除されていた場合はそうでなかった場合の位置)の次になります。
例)[A B C D] と並んでいて Bの位置でのループ時にBが削除されてAとBの間にE, BとCの間にFが挿入されて音符の並びが[A E F C D]になった場合、次に調べる位置はFになります。
上記の仕様のため生じる恐れがある音符の挿入による無限ループは、同じRuleのパターンマッチが既定の回数(現在は30000、将来的に既定で10000を下回らないことを保証する)を超えて行われたらエラーとすることで防止されています。
デバッグ用出力
print文とは、"print"、式 の順で並んだもののことです。但し式の先頭が変数をなす文字の場合、"print"と式の間に1つ以上の空白が必要です。そうでない場合、間の空白は任意です。
この仕様により、print "hello" を print("hello") とかくことができます。
print文は "Info: [ファイル名]:L[行数]: print: [式の評価値]" の形のログを出力します。
条件分岐
if文とは、"if"、式 の順で並んだもののことです。但し式の先頭が変数をなす文字の場合、"if"と式の間に1つ以上の空白が必要です。そうでない場合、間の空白は任意です。
この仕様により、if cond を if(cond) とかくことができます。
if文には対応する "end" が存在します。また対応する "else" が高々1つ存在します。
if文内の式の評価値は "true" か "false" のいずれかでなければなりません。
これが "true" かつ 対応する "else" が存在する場合、"else" までの文が実行され、そこから対応する "end" までの文は実行されません。
これが "false" かつ 対応する "else" が存在する場合、"else" までの文は実行されず、そこから対応する "end" までの文が実行されます。
対応する "else" が存在しない場合、"true" である場合に限り対応する "end" までの文が実行されます。
else-if文とは、"else"、1つ以上の空白、if文 の順で並んだもののことです。
else-if文は
else
if式
...
end // elseと同じif文に対応する
と等価です。
その他注意事項など
現状の実装では "end" の数が足りない場合でも、Rule文やScript文の直前では対応する "end" を必要とするものは "end" を与えられたとみなされます。しかしこの挙動を用いるのは非推奨であり、将来的にはエラーとなる予定です。
ヒント
歌詞の先頭(末尾)も休符の直後(直前)と同じ処理をしたい
歌詞の先頭(末尾)に休符(R)をあらかじめ入れておけばコードをより簡潔にできます。番兵と呼ばれるテクニックです。
例)
Rule: /h
insert 0: "R"
end
Rule: /t
insert 0: "R"
end
呼び出したScriptから返り値を受け取りたい
末尾にダミーの音符を挿入して、その音符のプロパティに値を詰め込めば実現できます。
例)呼び出し先(example1)
Rule: /t
insert 0: "return" // 歌詞に情報を乗せてもよい
hoge: "fuga"
end
呼び出し元
Script: example1
Rule: /.*/t
ReturnValue = 0.hoge
// 値を受け取った後にダミーの音符を削除するのを忘れずに
delete 0
一部の音符だけScriptの処理をするようにしたい
呼び出し元で音符に適当なプロパティに目印となる値を代入しておけば実現できます。目印となる値を複数用意することで、複数の処理を使い分けることもできます。
例)呼び出し先(example2)
Rule: /.*/
if 0.$marker == "long"
// 何らかの処理
else if 0.$marker == "short"
// 何らかの処理
end
// $から始まる音符のプロパティはプラグインの独自エントリとして使用できる
// 現状不要なプロパティを未定義に戻す方法がないのでとりあえず空文字列を代入しておくことにする
0.$marker = ""
呼び出し元
Rule: /.*/
if 0.Length >= 960
0.$marker = "long"
else if 0.Length < 240
0.$marker = "short"
else
0.$marker = ""
end
Script: example2
文法以外の話題
ugsの例
resources/script に連続音用の歌詞にする renzoku.ugs, 母音結合させる autocomb.ugs があります。
resources/script/preset に作者がHANASU動画を作るときに使っているデ4用のプリセットがあります。メインはそこから呼び出している resources/script/charcter 内のugsです。
プログラミングが面倒な人へ
HANASU仕様のデ4のプリセットを同梱しているので、UTAUのダウンロードページからデ4の原音、ここから拡張ピッチエディタを落としてくれば、HANASUライフが簡単に始められます!
ugsを使えば作れる(かもしれない)もののリスト
トークソフト
条件分岐を頑張って書けば、漢字交じりの文章からピッチを書いた状態のustファイルを生成できるかもしれません。現実的にはよく使う感嘆詞や固有名詞のピッチ(PBW,PBY,PBS,PBM)をustからコピペして用意しておくくらいだと思います(異なるテンポだとピッチがずれることに注意)。
電卓
歌詞を書くべきところに数式を書くと計算してログに答えを返すものを想定しています。括弧なしなら比較的簡単に作れます。括弧ありでも工夫すれば作れます。
エディタ
(今のところ)構文ハイライトなどの機能をもつ専用のエディタや既存のエディタの拡張機能は存在しません。
但し作者はVisual Studio Codeを使用しているので、それでugsを快適に書くための拡張機能が作られる可能性が(0に非常に近い確率ながら)あります。