「TAURI」で「ピアノ音楽」アプリを作ろう

ドの音を再生するだけのサンプル
まずはRustで1音出すだけの実装をしてみます。ピアノの鍵盤は「HTML5+JavaScript+CSS」を使ってWebページをデザインします(後述)。本当は、見た目だけ先に作り、後から音を出すようにプログラミングしても良かったのですが、今回は1音鳴らせるようになればWebページの鍵盤に合わせてそれぞれ音が鳴らせるようになれば良いので、このような順番の解説にしました。
今回のTAURIでは、図4のような「State(ステート)」という機能を使います。この機能は「TAURIコマンド」「TAURIセットアップハンドラ」「Windowイベントハンドラ」からState変数を共有できます。つまりグローバル変数のように、3つの機能からState変数にアクセスできます。なぜこのようなやり方をするかと言うと、Rustはグローバル変数を使わないように推奨されているからだと思われます。
Sound構造体のコーディング
次のように「src」→「sound.rs」ファイルを作成し、コーディングしてサウンドを扱う部分を「Sound」構造体にまとめます。と言っても、今回は「コンストラクタ」の「new」メソッドと、サウンドを再生する「play」メソッドしかありませんが。
図4で見たようにTAURIでステート機能を使うのですが、State変数は「イミュータブル(変更不可)」です。そこで「Mutex型」という機能でラップすれば、「ミュータブル(変更可能)」にデータを死守してくれます。
なお、サウンドの読み込みと再生についての詳細は、kiraクレートを使った第5回の内容が参考になると思います。ただし、今回はMutex型で2つのプロパティをラップしています。
・「src-tauri」→「src」→「sound.rs」サンプルコード//Mutexのクレート
use std::sync::Mutex;
//サウンドクレート
use kira::{
manager::{
AudioManager, AudioManagerSettings,
backend::cpal::CpalBackend,
},
sound::static_sound::{StaticSoundData, StaticSoundSettings},
};
//tauriクレート
use tauri::App;
//サウンド構造体
pub struct Sound {
sound_manager: Mutex<AudioManager>,
sound_data: Mutex<Vec<StaticSoundData>>,
}
//サウンド構造体のメソッド
impl Sound {
//コンストラクタ
pub fn new(
app:&mut App,
path:Vec<String>
) -> Self {
let snd_manager = AudioManager::<CpalBackend>::new(
AudioManagerSettings::default()
).expect("Error");
let mut data = Vec::new();
for p in path {
let resource_path = app.path_resolver()
.resolve_resource(p)
.expect("failed to resolve resource");
let d = StaticSoundData::from_file(
resource_path,
StaticSoundSettings::default()
).unwrap();
data.push(d);
}
Sound {
sound_manager: Mutex::new(snd_manager),
sound_data: Mutex::new(data),
}
}
//サウンド再生
pub fn play(
&self,
index:usize
) {
let mut snd_manager = self.sound_manager.lock().unwrap();
let snd_data = self.sound_data.lock().unwrap();
snd_manager.play(snd_data[index].clone()).expect("Error play");
}
}
【サンプルコードの解説】
Mutex型を扱うクレートとサウンドクレート、TAURIクレートを読み込みます。
Mutex型でラップしたオーディオマネージャー変数とサウンドデータ配列で構成されたSound構造体を宣言します。
「impl Sound」でSound構造体のメソッドを定義します。
コンストラクタの「new」メソッドでサウンドファイルパス配列からサウンドを読み込みます。その際「tauri.conf.json」のリソースで指定した"sounds"フォルダ内のoggファイルのパスを「path_resolver」メソッドの「resolve_resource」メソッドでリソースパスを取得します。
「play」メソッドでサウンドを再生します。その際Mutex型でラップしたオーディオマネージャーとサウンドデータを「lock」メソッドで「ロック」してからそれぞれ使えるようになります。
メインファイルのコーディング
次のように「src」→「main.rs」ファイルをコーディングしたら、ターミナルで「$ cargo-tauri dev」コマンドを実行してください。最初に「ド」の音が1度だけ再生されます。図5のように、まだピアノの鍵盤もなくデフォルトのWebページなのでピアノは弾けません。
ここでステート機能を使います。ステート機能を使わないと、バックエンド内の大部分からアクセスできるState変数が保持できません。
・「src-tauri」→「src」→「main.rs」サンプルコード#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
//TAURIクレート
use tauri::{State,Manager};
//サウンドモジュール
mod sound;
//サウンド再生コマンド
#[tauri::command]
fn playpiano(
note: usize,
snd: State<'_, sound::Sound>,
) {
snd.play(note);
}
//メイン関数
fn main() {
//サウンドデータ
let files = vec![
String::from("sounds/C3.ogg"), //白鍵
String::from("sounds/D3.ogg"),
String::from("sounds/E3.ogg"),
String::from("sounds/F3.ogg"),
String::from("sounds/G3.ogg"),
String::from("sounds/A3.ogg"),
String::from("sounds/B3.ogg"),
String::from("sounds/C4.ogg"),
String::from("sounds/D4.ogg"),
String::from("sounds/E4.ogg"),
String::from("sounds/F4.ogg"),
String::from("sounds/G4.ogg"),
String::from("sounds/A4.ogg"),
String::from("sounds/B4.ogg"),
String::from("sounds/C5.ogg"),
String::from("sounds/D5.ogg"),
String::from("sounds/E5.ogg"),
String::from("sounds/F5.ogg"),
String::from("sounds/G5.ogg"),
String::from("sounds/A5.ogg"),
String::from("sounds/B5.ogg"),
String::from("sounds/Df3.ogg"), //黒鍵
String::from("sounds/Ef3.ogg"),
String::from("sounds/Gf3.ogg"),
String::from("sounds/Af3.ogg"),
String::from("sounds/Bf3.ogg"),
String::from("sounds/Df4.ogg"),
String::from("sounds/Ef4.ogg"),
String::from("sounds/Gf4.ogg"),
String::from("sounds/Af4.ogg"),
String::from("sounds/Bf4.ogg"),
String::from("sounds/Df5.ogg"),
String::from("sounds/Ef5.ogg"),
String::from("sounds/Gf5.ogg"),
String::from("sounds/Af5.ogg"),
String::from("sounds/Bf5.ogg"),
];
//デスクトップアプリのセットアップ
tauri::Builder::default()
.setup(|app| {
let snd = sound::Sound::new(app,files);
snd.play(0);
app.manage(snd);
Ok(())
})
.invoke_handler(tauri::generate_handler![playpiano])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
【サンプルコードの解説】
TAURIクレートのState構造体とManager構造体を読み込みます。
「sound.rs」ファイルを使えるようにするために「mod sound;」でsound.rsファイルをモジュールとして読み込みます。
「playpiano」関数はTAURIコマンド関数で、フロントエンドの同名のメッセージから呼ばれて実行できます。「note」引数はピアノ音のインデックス番号です。「snd」引数はsoundモジュールのSound構造体のState変数で、TAURIのバックエンドの大部分で使いまわせるState変数です。
「main」関数で「files」配列に白鍵7×3オクターブ、続いて黒鍵5×3オクターブの相対パスを指定します。相対パスはリソースのsoundsフォルダ内のoggサウンドファイルを指しています。
TAURIビルダー(「Builder」構造体)のデフォルト(「default」メソッド)のセットアップ(「setup」メソッド)でsound.rsファイルのSound構造体のインスタンスを生成し「snd」変数に代入します。サウンドの0インデックスを再生(playメソッド)します。TAURIマネージャー(「manage」メソッド)でsnd変数をState変数に登録します。「invoke_handler」メソッドで「playpiano」をTAURIコマンド関数にセットしてTAURIを走らせます(「run」メソッド)。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- 「TAURI」にも必要な「Rust」の「クレート」を使う
- 「TAURI」で「画像ビューア」のサンプルアプリを作ろう
- 「Ace」を使って「TAURI」で「テキストエディタ」アプリを作ろう
- 「TAURI」で「簡易RSSリーダー」を開発してみよう
- 「TAURI」で気象庁の「CSVデータ」を解析する
- 「TAURI」でExcelのデータを読み書きしてWebページに表示してみよう
- 「TAURI」の基礎知識を押さえ、簡単なTAURIアプリ開発を体験してみよう
- 「TAURI」と「Rust」の「テスト」機能を試してみよう
- 「TAURI」で「丸アートお絵描き」アプリを作ろう
- 「TAURI」でデータベースを使ってみよう




