Upgrade to Pro — share decks privately, control downloads, hide ads and more …

個人開発のWeb アプリに WASM を導入してみての振り返り @ Osaki.rs#4

Avatar for kokeiro kokeiro
February 27, 2025
110

個人開発のWeb アプリに WASM を導入してみての振り返り @ Osaki.rs#4

Avatar for kokeiro

kokeiro

February 27, 2025

Transcript

  1. 自己紹介 2 • kokeiro ◦ 都内でエンジニアをやっています ▪ これまではネットワークやサーバーを中心に扱ってきましたが 昨年末から Web

    ( + 機械学習) を触り始めました ◦ Rust に興味をもったきっかけ ▪ チーム内に静的型付け言語至上主義なプロがおり 巷でよく聞く Rust ってどんなもんなんだろうかと思った Web も Rust も WASM も初心者ですが よろしくおねがいします!!
  2. 作成したアプリ 3 • https://okokebot.github.io/scale-out/ ◦ ギターでどこを抑えるべきか可視化するシンプルなアプリ ◦ Root と Scale

    を選択すると、抑えるべき場所とその音階 (音符) が表示される ◦ 表示される音符をクリックするとその音がでます ※ ド = C, レ = D, ミ = E, ファ = F, ソ = G, ラ = A, シ = B ラ (440 Hz)
  3. • フロントエンド ◦ react x Next.js v15.1 • Rust (WebAssembly)

    ◦ wasm-bindgen v0.2.100 ◦ web-audio-api (js) を呼び出し I'll generate an image that creatively combines elements of both Rust (represented by the Ferris crab) and Next.js (represented by its logo). 使った技術 4 これらの画像をあなたの想像で 合成してみてください。
  4. WebAssembly 用のファイル生成 5 use web_sys::{AudioContext, OscillatorNode, GainNode}; #[wasm_bindgen] pub struct

    WasmAudio { context: AudioContext, // 音の処理を管理 oscillator: OscillatorNode, // 音量調整 gain: GainNode, // 音量調整 } #[wasm_bindgen] impl WasmAudio { // 実装 ... // 周波数指定 pub fn set_frequency(&self, freq: f32) { 略 } // 音量指定 pub fn set_volume(&self, volume: f32) { 略 } ... // 指定した音量で開始し、一定時間をかけてゼロに減衰 pub fn set_volume_with_fadeout( &self, volume: f32, duration: f32 ) { 一定時間後にボリュームをゼロにして音が止まる設定 } ... } web-audio-api による音の生成 wasm と js のエクスポート ... export class WasmAudio { ... set_frequency(freq) { // 周波数指定 wasm.wasmaudio_set_frequency(this.__wbg_ptr, freq); } set_volume(volume) { // 音量指定 wasm.wasmaudio_set_volume(this.__wbg_ptr, volume); } ... // 指定した音量で開始し、一定時間をかけてゼロに減衰 set_volume_with_fadeout(volume, duration) { wasm.wasmaudio_set_volume_with_fadeout(this.__wbg_ptr, volume, duration); } ... } TS 用 型定義 .wasm +
  5. アプリへの組み込み 6 wasm をインポートして使用 import init, { WasmAudio } from

    "@/../public/wasm/wasm_audio_api.js"; import type { WasmAudio as WasmAudioType } from "@/../src/types/wasm/wasm_audio_api"; export class SoundGenerator { // wasm をラップしたクラス wasmAudio: WasmAudioType; private constructor(wasmAudio: WasmAudioType) { this.wasmAudio = wasmAudio; } static async create(): Promise<SoundGenerator> { // 初期化に必要な処理とエラーハンドリングをカプセル化し た try { const response = await fetch("wasm/wasm_audio_api_bg.wasm"); // バイナリを GET しにいく if (!response.ok) { throw new Error(`Failed to fetch WASM file: ${response.statusText}`); } const wasmArrayBuffer = await response.arrayBuffer(); // バイナリを格納 await init({ wasmArrayBuffer }); // バイナリから wasm を初期化 const wasmAudio = new WasmAudio(); return new SoundGenerator(wasmAudio); } catch (error) { // 略: 初期化できなかったときのエラーハンドリング } } playSound(frequency: number) { // 周波数を設定して、音を出す this.wasmAudio.set_frequency(frequency); this.wasmAudio.set_volume_with_fadeout(1.0, 0.5); this.wasmAudio.start(); } }
  6. ハマったところ 7 • 音符ひとつひとつで wasm を初期化したら... ◦ The AudioContext encountered

    an error from the audio device or the WebAudio renderer. ◦ RuntimeError: memory access out of bounds ⚪ ✖ wasm instance wasm instance wasm instance wasm instance … … wasm instance … すべての音符で、 1つの wasmAudio のインスタンスを使うことで解決
  7. (まだまだ詰めは甘いが) WASM を Web アプリに組み込むことができた まとめ 10 ◾ ChatGPT での解答精度は

      Rust だと良いとは言えない ・型エラー、コンパイルエラーが  発生するコードを出してくる ◾ デバッグが難しい ◾ 自分で使うアプリだと   モチベが続く ◾ 型のある開発、ありがたい Pain Good 継続的に Rust を学んでいこうと思います