【Rust】UTAUプラグインを作ってみる話。(1/3) ～API作成編～

#はじめに
Qiita記事初投稿のディーノです。どうもこんにちは。
突然なんですが、みなさん[UTAU](http://utau-synth.com)ってご存知でしょうか。
簡単に説明すると、いわゆるボカロのフリー版みたいなもので、誰でも無料で歌唱合成ができてしまうとんでもツールです。

そんなVOCALOID Editor殺しかと思われるUTAUですが、UTAU本体のみでは機能に乏しかったり、UXが良くなかったりなどの問題があります。
そのためUTAUでは、ユーザーが簡単に機能を追加できるようにプラグインを挿す(？)ことができます。
この記事ではそんなUTAUプラグインを作っていきます。

ちなみに自分はプログラミング歴1年未満の超初心者です。
使える言語は未だCとRustの二択なので、できることもそれなりに限られています。
今回使うのはRustオンリーです。
また以降はRustとUTAUを使用したことがあることを前提に進めていきます。

#UTAUプラグインを作るための予備知識
さぁいざプラグイン作るぞと意気込んでも、やっぱり何からすればいいのか分かりません。ということで、`UTAU プラグイン 作り方`でググります。
その結果参考になった記事をば。

https://w.atwiki.jp/utaou/pages/64.html#id_0fb814c5

https://www.nicovideo.jp/watch/sm26807902

https://shinta0806be.ldblog.jp/archives/9116719.html

「UTAUユーザー互助会」は事細かく説明されている感じがするので、コーディングをしながら分からなかったところをピンポイントで調べると良さそうな気がしました。
逆に「プラグイン製作のススメ」は言語こそ違いますが、一連の流れが掴めるので自分は真っ先に見ました。動画であることも情報が入りやすくてありがたいです。
そして極めつけに「半音上げプラグイン大会の振り返り」でサンプルコードを見れば多分流れは掴めそうです。

ということで、自分なりのUTAUプラグイン処理の大まかな流れをば。

1. UTAUからTMPファイルのパスをプログラムの引数として受け取る。
1. TMPファイルからノートの各パラメータ(長さ、歌詞、音程、etc)を抽出する。
1. 抽出したパラメータに任意の処理を実行する。
1. 変更を加えた各パラメータをTMPファイルに書き込む。

こんな感じでしょうか。
とすると、1に関しては`std::env`でどうにかなるとして、少なくとも2、3、4についての関数を作る必要がありそうです。

#UTAU API for Rust的なのを自作する
では早速作っていきましょう。
とはいっても、上のようなことをするとなると、それなりに処理が複雑になりそうです。
自分の脳みそは然程マルチスレッドではないので、ここで本命からクレートを分けようと思います。
今後複数回UTAUプラグインをRustで作りたいと思ったときにも、外部クレートがあるとなれば便利ですからね。

ということでできたものがこちらです。

https://github.com/dino3616/utau_rs

exampleはこんな感じ。

```Rust:src/main.rs
use utau_rs::*;

fn main(){
    half_upper();
}

fn half_upper(){
    //オブジェクトの生成(TMPファイルの読み込み・各パラメータの抽出)
    let mut uta_sections=UtaSections::default();

    //セクションごとの処理
    for section in uta_sections.sections.iter_mut(){
        section.note_num+=1;
    }

    //TMPファイルへの書き込み
    if let Err(err)=uta_sections.write(){
        panic!("Error：{}\n",err);
    }
}
```

老練のRustaceanならexampleを見ただけでお粗末なコードだと思われるかもしれませんが、そこはどうかご了承ください。
動けばよかろうなのです。

それはさておき、コードの説明をしましょう。

***

```Rust:
use utau_rs::*;
```

今回作ったクレートである`utau_rs`以下のモジュール全てをスコープへ持ち込みます。
丁寧なクレートならちゃんとモジュール名を書くと思いますが、今回は[crates.io](https://crates.io)にあげるわけでもないので、これでいいことにします。

***

```Rust:
let mut uta_sections=UtaSections::default();
```

`UtaSections`オブジェクトを生成します。
`UtaSections`オブジェクトは`default`トレイトを実装しているので、`new()`とか`read()`とかをする必要はありません。
しかし`new()`も`read()`も`pub`で定義しているので、

```Rust:
let mut uta_sections=UtaSections::new().unwrap();
uta_sections.read().unwrap();
```

とすることもできます。ケースバイケースで使っていただければと思います。

***

```Rust:
for section in uta_sections.sections.iter_mut(){
    section.note_num+=1;
}
```

`UtaSections`型のメンバ変数である`sections`を`.iter_mut()`で可変なイテレータとし、それを`for in`構文で回します。
ここで、`sections`は`Vec<UtaData>`型なので、そのイテレータの各要素となる`section`は`UtaData`型になります。
この型はメンバにLengthやLyrics等TMPファイルの情報を格納した変数を持ちます。
また、ただ回すだけなら追加するメソッドは必要ないのですが、`section.note_num+=1;`をする必要があるため`.iter_mut()`を付け加えます。
これにより、各セクション(各ノート)のNoteNum(音程)を一つ増加させることができます。

***

```Rust:
if let Err(err)=uta_sections.write(){
    panic!("Error：{}\n",err);
}
```

uta_sectionsに格納されている情報をTMPファイルに書き込みます。
ちなみに`if let Err(err)=uta_sections.write(){}`という他言語ではあまり見かけない(~~と自分が勝手に思っている~~)構文ですが、これは`uta_sections.write()`が`Err(err)`を返したときにのみ`{}`の処理が実行されるというものです。

さて、ここまでで最低限のクッションとなるクレートが出来上がりました。
これは先述の通りcrates.ioではなく[GitHub](https://github.com/dino3616/utau_rs)の公開リポジトリとして保存しているので、自分のプロジェクトで使う際には

```Rust:Cargo.toml
[dependencies]
utau_rs = {git = "https://github.com/dino3616/utau_rs", branch = "main"}
```

という記述を追加してください。
今後クレートの仕様が変わるようなアップデートはしない予定ではいますが、もしそのような場合には今度こそちゃんとcrates.ioにあげてバージョン管理をするようにします。

#おわりに
今回はUTAUプラグインのおおまかな流れとUTAU API for Rustを自作するところまで進めました。
[次回](https://qiita.com/dino3616/items/f6fa4460002915e4577a)は今回作成したAPIをもとにCUIでのプラグイン作成をしようと思います。

またね。