#はじめに
Qiita記事初投稿のディーノです。どうもこんにちは。
突然なんですが、みなさんUTAUってご存知でしょうか。
簡単に説明すると、いわゆるボカロのフリー版みたいなもので、誰でも無料で歌唱合成ができてしまうとんでもツールです。
そんなVOCALOID Editor殺しかと思われるUTAUですが、UTAU本体のみでは機能に乏しかったり、UXが良くなかったりなどの問題があります。
そのためUTAUでは、ユーザーが簡単に機能を追加できるようにプラグインを挿す(?)ことができます。
この記事ではそんなUTAUプラグインを作っていきます。
ちなみに自分はプログラミング歴1年未満の超初心者です。
使える言語は未だCとRustの二択なので、できることもそれなりに限られています。
今回使うのはRustオンリーです。
また以降はRustとUTAUを使用したことがあることを前提に進めていきます。
#UTAUプラグインを作るための予備知識
さぁいざプラグイン作るぞと意気込んでも、やっぱり何からすればいいのか分かりません。ということで、UTAU プラグイン 作り方
でググります。
その結果参考になった記事をば。
「UTAUユーザー互助会」は事細かく説明されている感じがするので、コーディングをしながら分からなかったところをピンポイントで調べると良さそうな気がしました。
逆に「プラグイン製作のススメ」は言語こそ違いますが、一連の流れが掴めるので自分は真っ先に見ました。動画であることも情報が入りやすくてありがたいです。
そして極めつけに「半音上げプラグイン大会の振り返り」でサンプルコードを見れば多分流れは掴めそうです。
ということで、自分なりのUTAUプラグイン処理の大まかな流れをば。
- UTAUからTMPファイルのパスをプログラムの引数として受け取る。
- TMPファイルからノートの各パラメータ(長さ、歌詞、音程、etc)を抽出する。
- 抽出したパラメータに任意の処理を実行する。
- 変更を加えた各パラメータをTMPファイルに書き込む。
こんな感じでしょうか。
とすると、1に関してはstd::env
でどうにかなるとして、少なくとも2、3、4についての関数を作る必要がありそうです。
#UTAU API for Rust的なのを自作する
では早速作っていきましょう。
とはいっても、上のようなことをするとなると、それなりに処理が複雑になりそうです。
自分の脳みそは然程マルチスレッドではないので、ここで本命からクレートを分けようと思います。
今後複数回UTAUプラグインをRustで作りたいと思ったときにも、外部クレートがあるとなれば便利ですからね。
ということでできたものがこちらです。
exampleはこんな感じ。
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を見ただけでお粗末なコードだと思われるかもしれませんが、そこはどうかご了承ください。
動けばよかろうなのです。
それはさておき、コードの説明をしましょう。
use utau_rs::*;
今回作ったクレートであるutau_rs
以下のモジュール全てをスコープへ持ち込みます。
丁寧なクレートならちゃんとモジュール名を書くと思いますが、今回はcrates.ioにあげるわけでもないので、これでいいことにします。
let mut uta_sections=UtaSections::default();
UtaSections
オブジェクトを生成します。
UtaSections
オブジェクトはdefault
トレイトを実装しているので、new()
とかread()
とかをする必要はありません。
しかしnew()
もread()
もpub
で定義しているので、
let mut uta_sections=UtaSections::new().unwrap();
uta_sections.read().unwrap();
とすることもできます。ケースバイケースで使っていただければと思います。
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(音程)を一つ増加させることができます。
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の公開リポジトリとして保存しているので、自分のプロジェクトで使う際には
[dependencies]
utau_rs = {git = "https://github.com/dino3616/utau_rs", branch = "main"}
という記述を追加してください。
今後クレートの仕様が変わるようなアップデートはしない予定ではいますが、もしそのような場合には今度こそちゃんとcrates.ioにあげてバージョン管理をするようにします。
#おわりに
今回はUTAUプラグインのおおまかな流れとUTAU API for Rustを自作するところまで進めました。
次回は今回作成したAPIをもとにCUIでのプラグイン作成をしようと思います。
またね。