
環境
・macOS Big Sur ver. 12.6 (21G115)
・MacBook Air M1, 2020 メモリ 8GB
・go1.18.3 darwin/arm64
やっていること
Go WebAssemblyでブラウザ上でGoを実行する その2 Go側からJavascriptを操作する
この二つのサイトを組み合わせて,一つ目のサイトにおけるsrc/webassembly.goを,二つ目のサイトの440Hzでsin波を鳴らしているものに変更させ,Go言語からJavaSciptでWeb Audio APIを制御してシンセサイザーを鳴らそうとしています.
それぞれ単体では実行することに成功しました.
WebAssembly.go
Go
1package main 2 3import ( 4 "syscall/js" 5) 6 7func main() { 8 // グローバルオブジェクト(window)を取得します 9 window := js.Global() 10 11 // document オブジェクトを取得します 12 document := window.Get("document") 13 14 // bodyを取得します 15 body := document.Get("body") 16 17 // h1 のDOMを作成します 18 h1 := document.Call("createElement", "h1") 19 h1.Set("innerHTML", "Hello Webassembly!") 20 21 // h1をbodyに追加します 22 body.Call("appendChild", h1) 23 24 // プログラムが終了しないように待機します 25 select {} 26 27}
sin波を生成するJavaScript
JavaScript
1// デフォルト設定でAudioContextを取得 2let ctx = new AudioContext() 3// 基本的な音を発するオシレータのAudioNodeをコンテキストの中に作成 4// 周波数は440Hz、波形はサイン波 5let osc = new OscillatorNode(ctx) 6osc.frequency = 440 7osc.type = "sine" 8// オシレータノードの出力をコンテキストのスピーカーに接続 9osc.connect(ctx.destination) 10// オシレータの処理を開始 11osc.start()
上のJavaScriptを自分で書き換えてみたもの
Go
1package main 2 3import ( 4 "syscall/js" 5) 6 7func main() { 8 // グローバルオブジェクト(window)を取得します 9 window := js.Global() 10 11 // document オブジェクトを取得します 12 document := window.Get("document") 13 14 // bodyを取得します 15 body := document.Get("body") 16 17 ctx := js.Global().Get("AudioContext").New() 18 osc := js.Global().Get("OscillatorNode").New(ctx) 19 js.Global().Set("osc.frequency", 440) 20 js.Global().Set("osc.type", "sine") 21 js.Global().Get("document").Call("osc.connect", ctx.destination) 22 osc = js.Global().Get("document").Call("start") 23 body.Call("appendChild", osc) 24 25 26 27 // プログラムが終了しないように待機します 28 select {} 29 30}
しかしこの状態でビルドを行うと.
terminal
1MacBook-Air src % GOOS=js GOARCH=wasm go build -o ../docs/build.wasm 2# sound_wav 3./webassembly.go:21:54: ctx.destination undefined (type js.Value has no field or method destination)
のようになってしまい,成功しません.
https://zenn.dev/nobonobo/books/85e605893d44ebe7dd3f/viewer/b5ac64d9135e123e367a
このサイトや
ドキュメントの
https://pkg.go.dev/syscall/js
を読んではみたのですが,二つ目の引数はどのようにすればいいのかわかりませんでした.
教えてほしいこと
エラー部分の二つ目の引数の適切な入れ方.
追記
フィールド名にドットを使ってはいけない,フィールドはjs.Valueのものを使って取得する,とのご指摘を受けたので,考えた範囲で修正いたしました.
webassembly.go
Go
1package main 2 3import ( 4 "syscall/js" 5) 6 7func main() { 8 // グローバルオブジェクト(window)を取得します 9 window := js.Global() 10 11 // document オブジェクトを取得します 12 document := window.Get("document") 13 14 // bodyを取得します 15 body := document.Get("body") 16 17 ctx := js.Global().Get("AudioContext").New() 18 osc := js.Global().Get("OscillatorNode").New(ctx) 19 osc.Set("frequency", 440) 20 osc.Set("type", "sine") 21 osc.Call("connect", ctx.Get("destination")) 22 osc.Call("start") 23 body.Call("appendChild", osc) 24 25 26 27 // プログラムが終了しないように待機します 28 select {} 29 30}
ビルドとmain.goの実行まではエラーが出ることなく進んだのですが,ブラウザで対象の場所に行っても音は鳴りませんでした.
ブラウザ上でコンソールを確認してみると以下のようなエラー文が出ていました.
console
1The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu 2syscall/js.valueNew @ wasm_exec.js:383 3Promise.then (async) 4(anonymous) @ (index):7 5 6wasm_exec.js:349 The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu 7syscall/js.valueCall @ wasm_exec.js:349 8Promise.then (async) 9(anonymous) @ (index):7 10wasm_exec.js:22 panic: JavaScript error: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'. 11wasm_exec.js:22 12wasm_exec.js:22 goroutine 1 [running]: 13wasm_exec.js:22 syscall/js.Value.Call({{}, 0x7ff800010000000a, 0x410028}, {0x114ef, 0xb}, {0x438f68, 0x1, 0x1}) 14wasm_exec.js:22 /usr/local/go/src/syscall/js/js.go:389 +0x31 15wasm_exec.js:22 main.main() 16wasm_exec.js:22 /Users/usrname/Go/make_sound/01/src/sound_wav/src/webassembly.go:23 +0xd 17 18wasm_exec.js:101 exit code: 2 19exit @ wasm_exec.js:101 20Promise.then (async) 21(anonymous) @ (index):7
最初のエラーについて調べてみたのですが
https://www.wizard-notes.com/entry/javascript/web-audio-api-chrome-user-interaction
のようなサイトを見るに,音を自動再生するのがchromeでは禁止されているのでnew AudioContextをしようというものとなっていました.
しかし,一応上のコードではインスタンスの作成はしていますし,Goを経由しない時には音が出せていたので,コードの構成上の問題ではなく,インスタンスの作り方が間違っているということなのでしょうか.
回答1件
あなたの回答
tips
プレビュー