質問編集履歴

3

編集

2022/11/01 07:05

投稿

aaaa____
aaaa____

スコア26

test CHANGED
File without changes
test CHANGED
@@ -6,6 +6,15 @@
6
6
  ### 最終的に目指していること
7
7
  https://www.amazon.co.jp/dp/4873118220?tag=note0e2a-22&linkCode=ogi&th=1&psc=1
8
8
  この本で作っているMonkeyという言語に,組み込み関数としてplay関数を作り,```play(60)```のようにMIDIノートナンバーを引数としてその音を鳴らすことができるようにする.
9
+
10
+ まず,Live Codingという,即興で音楽をコーディングによって作るものに使用する言語の設計を考えていまして,そのための基盤(Monkey言語と呼ばれる参考書を見ながら作る対話型独自言語)を質問本文に記載した参考書にしたがってGo言語で作成いたしました.
11
+ https://interpreterbook.com/waiig_code_1.4.zip
12
+ その言語に対して,組み込み関数(例えばlen("aiueo");と入力したら5と返してくるようなlen関数のようなもの)として,MIDIノートナンバーを引数として,その音をWebAudioAPIを用いて鳴らすplay()関数を付け加えようと考えています.
13
+ 文字数の都合上,細かい実装した手順などは本文に記載させていただいた記事に任させていただこうとおもうのですが,現状,音を鳴らす機能がない(与えられてMIDIノートナンバーをそのまま返すだけ)play()組み込み関数の追加はすることが出来ました.そのあとに,命令としてplay(60);としたら60の音が鳴るように評価の部分を変更しようとしたのですが,方法が分からない,といったことになっております.
14
+
15
+ ブラウザ上で操作するのではなく,あくまでもコーディングとしてターミナル上で命令を記述し,ブラウザではボタンを押すだけでコーディングしたように音が鳴るようにしたいと考えております.
16
+
17
+
9
18
 
10
19
 
11
20
  ### 今できていること

2

編集

2022/11/01 07:01

投稿

aaaa____
aaaa____

スコア26

test CHANGED
File without changes
test CHANGED
@@ -80,3 +80,135 @@
80
80
  このサイトにあるように,ブラウザに値を打ち込んでやる方法を取るしかないのでしょうか.
81
81
 
82
82
 
83
+ ### 追記
84
+ 一つ上のサイトを参考に,以下のようにして,ブラウザにテキストボックスとボタンを配置しそのMIDIノートなんばーの音を鳴らすことは出来ましたが,これは少し趣旨とは異なってしまいます.
85
+
86
+ ##### index.html
87
+ ```html
88
+ <html>
89
+ <head>
90
+ <meta charset="utf-8"/>
91
+ <script src="wasm_exec.js"></script>
92
+ <script>
93
+ const go = new Go();
94
+ WebAssembly.instantiateStreaming(fetch("build.wasm"), go.importObject).then((result) => {
95
+ go.run(result.instance);
96
+ });
97
+ </script>
98
+ </head>
99
+ <body>
100
+ <input type="text" id="noteNum" />
101
+ <button onClick="play('noteNum');" id="playButton">play</button>
102
+ </body>
103
+ </html>
104
+ ```
105
+
106
+ ##### webassembly.go
107
+ ```go
108
+ package main
109
+
110
+ import (
111
+ "syscall/js"
112
+ "time"
113
+ "math/rand"
114
+ "math"
115
+ "fmt"
116
+ "strconv"
117
+ )
118
+
119
+ func num_to_freq (notenum int) float64{
120
+ // 基準音から何音高い/低いかを計算する
121
+ from_concert_a := notenum - 69
122
+ // 周波数を実際に計算する
123
+ // 十二平均律では2音の最小の周波数差は`2^(1/12)`となる
124
+ freq := math.Pow(2, float64(from_concert_a) / 12) * 440;
125
+ return freq;
126
+ }
127
+
128
+ func registerCallbacks() {
129
+ js.Global().Set("play", js.FuncOf(play))
130
+ }
131
+
132
+ func textToStr(v js.Value) string {
133
+ return js.Global().Get("document").Call("getElementById", v.String()).Get("value").String()
134
+ }
135
+
136
+ func play(this js.Value, args []js.Value) interface{} {
137
+ value := textToStr(args[0])
138
+
139
+ noteNum, _ := strconv.Atoi(value)
140
+ ctx := js.Global().Get("AudioContext").New()
141
+ osc := js.Global().Get("OscillatorNode").New(ctx)
142
+ gain := js.Global().Get("GainNode").New(ctx)
143
+ gain.Get("gain").Set("value", 0)
144
+
145
+ bpm := 120.0
146
+ note_length := 60.0 / bpm
147
+
148
+ osc.Call("connect", gain)
149
+ gain.Call("connect", ctx.Get("destination"))
150
+ osc.Call("start")
151
+
152
+ for n := 0; n < 60; n++{
153
+ start_t := float64(n) * note_length
154
+ end_t := start_t + 1.0
155
+ osc.Get("frequency").Call("setValueAtTime", num_to_freq(noteNum), ctx.Get("currentTime").Float()+start_t)
156
+ gain.Get("gain").Call("setValueAtTime", 0.3, ctx.Get("currentTime").Float()+start_t)
157
+ gain.Get("gain").Call("setValueAtTime", 0., ctx.Get("currentTime").Float()+end_t)
158
+ }
159
+ osc.Set("type", "sawtooth")
160
+ return nil
161
+ }
162
+
163
+ func main() {
164
+
165
+ registerCallbacks()
166
+
167
+ // グローバルオブジェクト(window)を取得します
168
+ window := js.Global()
169
+
170
+ // document オブジェクトを取得します
171
+ document := window.Get("document")
172
+
173
+ // bodyを取得します
174
+ body := document.Get("body")
175
+
176
+ // ボタンのDOMを作成し、Clickイベントを設定します
177
+ btn := document.Call("createElement", "button")
178
+ btn.Set("textContent", "music start!")
179
+ btn.Call("addEventListener", "click", js.FuncOf(func(js.Value, []js.Value) interface{} {
180
+ ctx := js.Global().Get("AudioContext").New()
181
+ osc := js.Global().Get("OscillatorNode").New(ctx)
182
+ gain := js.Global().Get("GainNode").New(ctx)
183
+ gain.Get("gain").Set("value", 0)
184
+
185
+ bpm := 120.0
186
+ note_length := 60.0 / bpm
187
+
188
+ osc.Call("connect", gain)
189
+ gain.Call("connect", ctx.Get("destination"))
190
+ osc.Call("start")
191
+
192
+ rand.Seed(time.Now().UnixNano())
193
+
194
+ for n := 0; n < 120; n++{
195
+ randNote := rand.Intn(20) + 55
196
+ fmt.Println(randNote)
197
+ start_t := float64(n) * note_length
198
+ end_t := start_t + 1.0
199
+ osc.Get("frequency").Call("setValueAtTime", num_to_freq(randNote), ctx.Get("currentTime").Float()+start_t)
200
+ gain.Get("gain").Call("setValueAtTime", 0.3, ctx.Get("currentTime").Float()+start_t)
201
+ gain.Get("gain").Call("setValueAtTime", 0., ctx.Get("currentTime").Float()+end_t)
202
+ }
203
+ osc.Set("type", "sawtooth")
204
+ return nil
205
+ }))
206
+ // ボタンをbodyに追加します
207
+ body.Call("appendChild", btn)
208
+
209
+ // プログラムが終了しないように待機します
210
+ select {}
211
+
212
+ }
213
+ ```
214
+

1

編集

2022/11/01 01:31

投稿

aaaa____
aaaa____

スコア26

test CHANGED
File without changes
test CHANGED
@@ -75,3 +75,8 @@
75
75
  }
76
76
  ```
77
77
 
78
+ ### 調べてでてきたもの
79
+ https://ludwig125.hatenablog.com/entry/2022/03/06/080759
80
+ このサイトにあるように,ブラウザに値を打ち込んでやる方法を取るしかないのでしょうか.
81
+
82
+