ジンジャー研究室

長めのつぶやき。難しいことは書きません。

Electron と Go で音を鳴らしてみた話

SoundEngine とか Audacity みたいな波形編集ソフトを作りたいと思った時に、本当はデスクトップアプリが作りたいんだけど Web 技術の方が慣れてるから(ここでの Web 技術は HTML や JavaScript など)という理由で、わざわざローカルでサーバーを起動してブラウザで WebAudio API を利用するアプリを作ったりしてしていた。でもユーザー体験は確実に悪いので、まずそれが嫌になった。面倒がらずに Electron を使おう。

もう一つ、 WebAudio API はとても良く出来ているのだがレイヤーが高すぎて細かいことができなかったり、パフォーマンスを求めるときは AudioWorklet を使わないといけないのが面倒だった。 AudioWorklet は既存のノードの拡張として使うのが行儀が良いのだろうけど、最近は他の言語で書かれたアプリケーションを丸ごとドーンと wasm に変換して、 WebAudio API は単にオーディオバッファをやり取りするインターフェースとして使う事例が増えていそう。その流れなら WebAudio API は一旦脇に置いてパフォーマンスの良い言語で自由に書いてみようかと。

というわけで、使い慣れた Web 技術で GUI を書きつつ音声処理はパフォーマンスを出すために Electron + Go という組み合わせを採用するに至った。特に Web サービスを作るという動機はないので AudioWorklet や wasm も使わずに両者は IPC で繋ぐことにする。

┌───────────── Electron ─────────────┐
┌────────────┐           ┌───────────┐           ┌───────┐
│ ui         │<-- IPC -->│ core      │<-- IPC -->│ audio │<---- MIDI
│ (TS/React) │           │ (TS/Node) │           │ (Go)  │<---> File
└────────────┘           └───────────┘           └───────┘

サーバーを立てて WebSocket 使うよりパフォーマンス出てるんじゃないかな、多分。プロトコルはシンプルにスペース区切りの文字列を双方向にやり取りすることにする。

{url-encoded} {url-encoded} {url-encoded} ...
{url-encoded} {url-encoded} {url-encoded} ...
...

ここで一番検証したかったのは UI 操作や描画がスムーズかということだったんだけど、ここは何事もなく普通にサクサク動いた。トラブルのひとつやふたつあるかと思ったけど。ボタンを押したらすぐに音が鳴るし、波形も 60fps で描画できた。ということは、これから任意のデスクトップアプリの GUI を Web 技術で作りたくなった場合はこの構成が使えるということなので嬉しい。

今回は上の検証が主な目的でアプリとして作るものはあまり決めていなかったので、最初は波形編集ソフトを作る予定だったのが気づいたらシンセを作っていた。でもシンセを作るなら VST とかで作らないと実際に DAW で使えないよね、ということで一旦この構成での制作は打ち切りにして C++ (JUCE) に移行中。

途中まで作ったもの。 github.com

ちなみに Go のライブラリは hajimehoshi/oto を使わせてもらってます。BGM 制作で参加させてもらっている Odencat 製のゲームなどで実績があります。 github.com