質問編集履歴

2

回答を踏まえ改善しましたがうまくいかず内容を変更しました。

2021/11/11 02:31

投稿

lteru
lteru

スコア6

test CHANGED
@@ -1 +1 @@
1
- threadを用いたアプリすぐに落ちてまう
1
+ threadがうまく機能ない
test CHANGED
@@ -10,21 +10,107 @@
10
10
 
11
11
 
12
12
 
13
+
14
+
15
+
16
+
13
- ### 発生ている問題
17
+ ### たこと
18
+
19
+
20
+
14
-
21
+ 並列処理について調べたところ、threadを用いることで実現できそうだったため、reset_sinwaveを別スレッドで実行しようと考えました。
22
+
23
+
24
+
15
- 下記のコーでは音の出力後にサイン波がプロットされしまいます
25
+ ~~ここでスレッに通知を送るためにstart_fragを用意し、キーが押された際フラグがTrueになり、サイン波がプロットされるようにしました~~
26
+
27
+ スレッドに通知を送るために、play_fragを用意し、キーが押された際にフラグがTrueになり、音声が出力されるようにしましたが、音声が出力されません。
28
+
29
+
16
30
 
17
31
 
18
32
 
19
33
  ```Python
20
34
 
21
-
35
+ #=== アプリケーションの定義
36
+
37
+ class Synth_application(tk.Frame):
38
+
39
+ def __init__(self, master=None):
40
+
41
+
42
+
43
+ self.thread2 = threading.Thread(target=self.play)
44
+
45
+ self.thread2.start()
46
+
47
+
48
+
49
+ self.play_flag = False
50
+
51
+
52
+
53
+ def press_key(self, event):
54
+
55
+ global freq
56
+
57
+ self.key = event.keysym
58
+
59
+ if self.key == 'a':
60
+
61
+ freq = FREQ_SCALE['ド/C4']
62
+
63
+ self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
64
+
65
+ self.play_flag = True
66
+
67
+ elif self.key == 's':
68
+
69
+ freq = FREQ_SCALE['レ/D4']
70
+
71
+ self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
72
+
73
+ self.play_flag = True
74
+
75
+
76
+
77
+
78
+
79
+ # ストリームに渡して再生 パターン②
80
+
81
+ def play(self):
82
+
83
+ if self.play_flag == True:
84
+
85
+ self.stream.write(self.sin_t.astype(np.float32).tobytes())
86
+
87
+ self.play_flag = False
88
+
89
+
90
+
91
+
92
+
93
+ ```
94
+
95
+
96
+
97
+ ### ソースコード
98
+
99
+ 下記で音の出力とグラフのプロットを同時にできると考えましたが、~~コードを実行してもすぐにカーネルが落ちてしまいます。何が足りないでしょうか。~~音声が流れません。
100
+
101
+
102
+
103
+ ```Python
104
+
105
+
106
+
107
+ # ライブラリのインポート
22
108
 
23
109
  import tkinter as tk
24
110
 
25
- import numpy as np
111
+ import numpy as np # sin波
26
-
112
+
27
- import pyaudio
113
+ import pyaudio # メモリ上の音楽を再生
28
114
 
29
115
  import matplotlib.pyplot as plt
30
116
 
@@ -34,7 +120,11 @@
34
120
 
35
121
 
36
122
 
37
-
123
+ import threading
124
+
125
+
126
+
127
+ #=== アプリケーションの定義
38
128
 
39
129
  class Synth_application(tk.Frame):
40
130
 
@@ -42,17 +132,33 @@
42
132
 
43
133
  def __init__(self, master=None):
44
134
 
135
+ # メインウィンドウの設定
136
+
45
- super().__init__(master)
137
+ super().__init__(master) # 親クラス(Application)の __init__ メソッドを実行
46
138
 
47
139
  self.master = master
48
140
 
49
- self.master.geometry('{}x{}'.format(750, 570))
141
+ self.master.title('Synth_Application')
142
+
50
-
143
+ self.master.resizable(width=False,height=False) #ウィンドウ幅の固定
144
+
145
+
146
+
147
+ # sin波の初期値設定
148
+
51
- self.start_up()
149
+ self.start_up()
150
+
151
+
152
+
153
+ # ウィジットをつくる
52
154
 
53
155
  self.create_widgets()
54
156
 
157
+
158
+
159
+ # pyaudioの開始
160
+
55
- self.p = pyaudio.PyAudio()
161
+ self.p = pyaudio.PyAudio()
56
162
 
57
163
  self.stream = self.p.open(format=pyaudio.paFloat32,
58
164
 
@@ -68,171 +174,185 @@
68
174
 
69
175
  self.master.protocol("WM_DELETE_WINDOW", self.quit_app)
70
176
 
177
+
178
+
71
-
179
+ self.thread2 = threading.Thread(target=self.play)
180
+
181
+ self.thread2.start()
182
+
183
+
184
+
185
+
72
186
 
73
187
  #=== 初期値
74
188
 
75
189
  def start_up(self, gain=0.25, rate=44100, chunk_size=1024):
76
190
 
191
+ global freq # 初期値のためにglobal変数が必要
192
+
193
+
194
+
195
+ freq = 261.26
196
+
197
+ self.DURATION = {
198
+
199
+ 'L4': (60 / 100 * 4) / 4, # 四分音符
200
+
201
+ }
202
+
203
+ self.duration = self.DURATION['L4']
204
+
205
+ self.bpm = 100
206
+
207
+
208
+
209
+ self.gain = gain
210
+
211
+ self.rate = rate
212
+
213
+ self.chunk_size = chunk_size
214
+
215
+
216
+
217
+ self.start_pos = 0
218
+
219
+ self.end_pos = self.start_pos + self.duration * self.rate
220
+
221
+
222
+
223
+ self.t = np.arange(self.start_pos, self.end_pos) / self.rate
224
+
225
+ self.sin_t = self.gain * np.sin(2 * np.pi * 0 * self.t)
226
+
227
+
228
+
229
+ self.quitting_flag = False
230
+
231
+ self.play_flag = False
232
+
233
+
234
+
235
+ #=== ウィジットの定義
236
+
237
+ def create_widgets(self):
238
+
239
+ #=== ウィジェット:LabelFrameウィジットをつくる
240
+
241
+ self.chunk_labelFrame = tk.LabelFrame(self.master, text="WaveForm", fg='white', bg='#444', relief=tk.FLAT)
242
+
243
+ self.chunk_labelFrame.grid(column=0, row=0)
244
+
245
+ self.chunk_innerBox = tk.Frame(self.chunk_labelFrame)
246
+
247
+ self.chunk_innerBox.grid(column=0, row=0)
248
+
249
+
250
+
251
+ #=== Figureインスタンスをつくる
252
+
253
+ fig = Figure(figsize=(2,2), dpi=100, tight_layout=True, facecolor='#F0F0F0')
254
+
255
+ axes_wave = fig.add_subplot(1, 1, 1)
256
+
257
+ axes_wave.set_ylim([-(self.gain + 0.05), (self.gain + 0.05)])
258
+
259
+ self.line_wave, = axes_wave.plot(self.sin_t[:500])
260
+
261
+
262
+
263
+ self.canvas = FigureCanvasTkAgg(fig, master=self.chunk_innerBox)
264
+
265
+ self.canvas.get_tk_widget().pack(padx=10, pady=10)
266
+
267
+ self.canvas.get_tk_widget().bind('<Any-KeyPress>', self.press_key)
268
+
269
+
270
+
271
+
272
+
273
+ # sin波の作成
274
+
275
+ def create_sinwave(self, duration, freq):
276
+
277
+ self.duration = duration
278
+
279
+ self.freq = freq
280
+
281
+
282
+
283
+ self.start_pos = self.end_pos
284
+
285
+ self.end_pos = self.start_pos + duration * self.rate
286
+
287
+ self.t = np.arange(self.start_pos, self.end_pos) / self.rate
288
+
289
+ self.sin_t = self.gain * np.sin(2 * np.pi * freq * self.t)
290
+
291
+
292
+
293
+ def press_key(self, event):
294
+
77
295
  global freq
78
296
 
79
297
 
80
298
 
81
- freq = 261.26
82
-
83
- self.DURATION = {
84
-
85
- 'L4': (60 / 100 * 4) / 4,
86
-
87
- 'L8': (60 / 100 * 4) / 8,
88
-
89
- }
90
-
91
- self.duration = self.DURATION['L4']
92
-
93
- self.bpm = 100 # New
94
-
95
-
96
-
97
- self.gain = gain
98
-
99
- self.rate = rate
100
-
101
- self.chunk_size = chunk_size
102
-
103
-
104
-
105
- self.t = np.arange(0, self.duration * self.rate) / self.rate
106
-
107
- self.sin_t = np.sin(2 * np.pi * 0 * self.t)
108
-
109
-
110
-
111
- #=== ウィジットの定義
112
-
113
- def create_widgets(self):
114
-
115
- self.canvas_frame = tk.Frame(self.master, width=700, height=250, bg="#000080")
116
-
117
- self.canvas_frame.grid(column=0, row=0)
118
-
119
- self.canvas_frame.grid_propagate(0)
120
-
121
- self.canvas_frame.grid_anchor(tk.CENTER)
122
-
123
-
124
-
125
- self.option_frame = tk.Frame(self.master, width=700, height=320, bd = 5, relief = tk.GROOVE) # New
126
-
127
- self.option_frame.grid(column=0, row=1)
128
-
129
- self.option_frame.grid_propagate(0)
130
-
131
- self.option_frame.grid_anchor(tk.CENTER)
132
-
133
-
134
-
135
- self.chunk_labelFrame = tk.LabelFrame(self.canvas_frame, text="WaveForm", fg='white', bg='#444', relief=tk.FLAT)
136
-
137
- self.chunk_labelFrame.grid(column=0, row=0)
138
-
139
- self.chunk_innerBox = tk.Frame(self.chunk_labelFrame)
140
-
141
- self.chunk_innerBox.grid(column=0, row=0)
142
-
143
-
144
-
145
- fig = Figure(figsize=(6.5,2), dpi=100, tight_layout=True, facecolor='#F0F0F0')
146
-
147
-
148
-
149
- axes_wave = fig.add_subplot(1, 1, 1)
150
-
151
- axes_wave.set_title('Sin_wave')
152
-
153
- axes_wave.set_xlabel('t', fontsize=8)
154
-
155
- axes_wave.set_ylabel('sin_t', fontsize=8)
156
-
157
- axes_wave.set_ylim([-(self.gain + 0.05), (self.gain + 0.05)])
158
-
159
-
160
-
161
- self.line_wave, = axes_wave.plot(self.sin_t[:500])
162
-
163
-
164
-
165
- self.canvas = FigureCanvasTkAgg(fig, master=self.chunk_innerBox)
166
-
167
- self.canvas.get_tk_widget().pack(padx=10, pady=10)
168
-
169
- self.canvas.get_tk_widget().bind('<Any-KeyPress>', self.press_key)
170
-
171
-
172
-
173
- # sin波の作成
174
-
175
- def create_sinwave(self, duration, freq):
176
-
177
- self.duration = duration
178
-
179
- self.freq = freq
180
-
181
-
182
-
183
- self.t = np.arange(0, duration * self.rate) / self.rate
184
-
185
- self.sin_t = np.sin(2 * np.pi * freq * self.t)
186
-
187
-
188
-
189
- def press_key(self, event):
190
-
191
- global freq
192
-
193
-
194
-
195
299
  self.key = event.keysym
196
300
 
197
301
  if self.key == 'a':
198
302
 
199
303
  freq = FREQ_SCALE['ド/C4']
200
304
 
201
- self.create_sinwave(self.duration, freq)
305
+ self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
202
-
306
+
203
- self.play()
307
+ self.play_flag = True
204
308
 
205
309
  elif self.key == 's':
206
310
 
207
311
  freq = FREQ_SCALE['レ/D4']
208
312
 
209
- self.create_sinwave(self.duration, freq)
313
+ self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
210
-
314
+
211
- self.play()
315
+ self.play_flag = True
212
316
 
213
317
  elif self.key == 'd':
214
318
 
215
319
  freq = FREQ_SCALE['ミ/E4']
216
320
 
217
- self.create_sinwave(self.duration, freq)
321
+ self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
218
-
322
+
219
- self.play()
323
+ self.play_flag = True
220
-
221
-
324
+
325
+
222
326
 
223
327
  self.reset_sinwave()
224
328
 
225
329
 
226
330
 
331
+
332
+
333
+ # ストリームに渡して再生
334
+
335
+ # def play(self):
336
+
337
+ # self.stream.write(self.sin_t.astype(np.float32).tobytes())
338
+
339
+
340
+
341
+ # ストリームに渡して再生 パターン②
342
+
227
343
  def play(self):
228
344
 
345
+ if self.play_flag == True:
346
+
229
- self.stream.write(self.sin_t.astype(np.float32).tobytes())
347
+ self.stream.write(self.sin_t.astype(np.float32).tobytes())
348
+
349
+ self.play_flag = False
230
350
 
231
351
 
232
352
 
233
353
  def reset_sinwave(self):
234
354
 
235
- self.line_wave.set_ydata(self.sin_t[:500])
355
+ self.line_wave.set_ydata(self.sin_t[:500]) # グラフのy軸をアップデート
236
356
 
237
357
  self.canvas.draw()
238
358
 
@@ -246,7 +366,11 @@
246
366
 
247
367
 
248
368
 
369
+
370
+
371
+ # パラメータ
372
+
249
- FREQ_SCALE = {
373
+ FREQ_SCALE = { # 周波数f0のスケール
250
374
 
251
375
  'ド/C4': 261.626,
252
376
 
@@ -264,344 +388,4 @@
264
388
 
265
389
  app.mainloop()
266
390
 
267
-
268
-
269
391
  ```
270
-
271
-
272
-
273
- ### 試したこと
274
-
275
-
276
-
277
- 並列処理について調べたところ、threadを用いることで実現できそうだったため、reset_sinwaveを別スレッドで実行しようと考えました。
278
-
279
-
280
-
281
- ここでスレッドに通知を送るために、start_fragを用意し、キーが押された際にフラグがTrueになり、サイン波がプロットされるようにしました。
282
-
283
-
284
-
285
-
286
-
287
- ```Python
288
-
289
- def start_up(self, gain=0.25, rate=44100, chunk_size=1024):
290
-
291
-    …
292
-
293
- #==== 追加 ===#
294
-
295
- self.start_flag = False
296
-
297
- self.quitting_flag = False
298
-
299
-
300
-
301
-
302
-
303
- #==== 追加 ===#
304
-
305
- def reset_sinwave(self):
306
-
307
- while not self.quitting_flag:
308
-
309
- if self.start_flag:
310
-
311
- self.line_wave.set_ydata(self.sin_t[:500])
312
-
313
- self.canvas.draw()
314
-
315
- ```
316
-
317
-
318
-
319
- ### ソースコード
320
-
321
- 下記で音の出力とグラフのプロットを同時にできると考えましたが、コードを実行してもすぐにカーネルが落ちてしまいます。何が足りないでしょうか。
322
-
323
-
324
-
325
- ```Python
326
-
327
-
328
-
329
- import tkinter as tk
330
-
331
- import numpy as np
332
-
333
- import pyaudio
334
-
335
- import matplotlib.pyplot as plt
336
-
337
- from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
338
-
339
- from matplotlib.figure import Figure
340
-
341
- import threading
342
-
343
-
344
-
345
-
346
-
347
- class Synth_application(tk.Frame):
348
-
349
- def __init__(self, master=None):
350
-
351
- super().__init__(master)
352
-
353
- self.master = master
354
-
355
- self.master.geometry('{}x{}'.format(700, 570, startX, startY))
356
-
357
- self.start_up() # 初期値
358
-
359
- self.create_widgets()
360
-
361
- self.p = pyaudio.PyAudio()
362
-
363
- self.stream = self.p.open(format=pyaudio.paFloat32,
364
-
365
- channels=1,
366
-
367
- rate=self.rate,
368
-
369
- frames_per_buffer=self.chunk_size,
370
-
371
- output=True)
372
-
373
-
374
-
375
- self.master.protocol("WM_DELETE_WINDOW", self.quit_app)
376
-
377
-
378
-
379
- #==== 追加 ===#
380
-
381
- self.thread1 = threading.Thread(target=self.reset_sinwave)
382
-
383
- self.thread1.start()
384
-
385
-
386
-
387
-
388
-
389
- #=== 初期値
390
-
391
- def start_up(self, gain=0.25, rate=44100, chunk_size=1024):
392
-
393
- global freq
394
-
395
-
396
-
397
- freq = 261.26
398
-
399
- self.DURATION = {
400
-
401
- 'L4': (60 / 100 * 4) / 4,
402
-
403
- 'L8': (60 / 100 * 4) / 8,
404
-
405
- }
406
-
407
- self.duration = self.DURATION['L4']
408
-
409
- self.bpm = 100
410
-
411
-
412
-
413
- self.gain = gain
414
-
415
- self.rate = rate
416
-
417
- self.chunk_size = chunk_size
418
-
419
-
420
-
421
- self.t = np.arange(0, self.duration * self.rate) / self.rate
422
-
423
- self.sin_t = np.sin(2 * np.pi * 0 * self.t)
424
-
425
-
426
-
427
- #==== 追加 ===#
428
-
429
- self.start_flag = False
430
-
431
- self.quitting_flag = False
432
-
433
-
434
-
435
- #=== ウィジットの定義
436
-
437
- def create_widgets(self):
438
-
439
- self.canvas_frame = tk.Frame(self.master, width=700, height=250, bg="#000080")
440
-
441
- self.canvas_frame.grid(column=0, row=0)
442
-
443
- self.canvas_frame.grid_propagate(0)
444
-
445
- self.canvas_frame.grid_anchor(tk.CENTER)
446
-
447
-
448
-
449
- self.option_frame = tk.Frame(self.master, width=700, height=320, bd = 5, relief = tk.GROOVE)
450
-
451
- self.option_frame.grid(column=0, row=1)
452
-
453
- self.option_frame.grid_propagate(0)
454
-
455
- self.option_frame.grid_anchor(tk.CENTER)
456
-
457
-
458
-
459
- self.chunk_labelFrame = tk.LabelFrame(self.canvas_frame, text="WaveForm", fg='white', bg='#444', relief=tk.FLAT)
460
-
461
- self.chunk_labelFrame.grid(column=0, row=0)
462
-
463
- self.chunk_innerBox = tk.Frame(self.chunk_labelFrame)
464
-
465
- self.chunk_innerBox.grid(column=0, row=0)
466
-
467
-
468
-
469
- fig = Figure(figsize=(6.5,2), dpi=100, tight_layout=True, facecolor='#F0F0F0')
470
-
471
-
472
-
473
- axes_wave = fig.add_subplot(1, 1, 1)
474
-
475
- axes_wave.set_title('Sin_wave')
476
-
477
- axes_wave.set_xlabel('t', fontsize=8)
478
-
479
- axes_wave.set_ylabel('sin_t', fontsize=8)
480
-
481
- axes_wave.set_ylim([-(self.gain + 0.05), (self.gain + 0.05)])
482
-
483
-
484
-
485
- self.line_wave, = axes_wave.plot(self.sin_t[:500])
486
-
487
-
488
-
489
- self.canvas = FigureCanvasTkAgg(fig, master=self.chunk_innerBox)
490
-
491
- self.canvas.get_tk_widget().pack(padx=10, pady=10)
492
-
493
- self.canvas.get_tk_widget().bind('<Any-KeyPress>', self.press_key)
494
-
495
-
496
-
497
- # sin波の作成
498
-
499
- def create_sinwave(self, duration, freq):
500
-
501
- self.duration = duration
502
-
503
- self.freq = freq
504
-
505
-
506
-
507
- self.t = np.arange(0, duration * self.rate) / self.rate
508
-
509
- self.sin_t = np.sin(2 * np.pi * freq * self.t)
510
-
511
-
512
-
513
- def press_key(self, event):
514
-
515
- global freq
516
-
517
-
518
-
519
- self.key = event.keysym
520
-
521
- if self.key == 'a':
522
-
523
- freq = FREQ_SCALE['ド/C4']
524
-
525
- self.create_sinwave(self.duration, freq)
526
-
527
- self.play()
528
-
529
- elif self.key == 's':
530
-
531
- freq = FREQ_SCALE['レ/D4']
532
-
533
- self.create_sinwave(self.duration, freq)
534
-
535
- self.play()
536
-
537
- elif self.key == 'd':
538
-
539
- freq = FREQ_SCALE['ミ/E4']
540
-
541
- self.create_sinwave(self.duration, freq)
542
-
543
- self.play()
544
-
545
-
546
-
547
- self.start_flag = True
548
-
549
-
550
-
551
- def play(self):
552
-
553
- self.stream.write(self.sin_t.astype(np.float32).tobytes())
554
-
555
-
556
-
557
- #==== 追加 ===#
558
-
559
- def reset_sinwave(self):
560
-
561
- while not self.quitting_flag:
562
-
563
- if self.start_flag:
564
-
565
- self.line_wave.set_ydata(self.sin_t[:500]) # グラフのy軸をアップデート
566
-
567
- self.canvas.draw()
568
-
569
-
570
-
571
- #==== 追加 ===#
572
-
573
- def quit_app(self):
574
-
575
- self.stream.close()
576
-
577
-
578
-
579
- self.quitting_flag = True
580
-
581
- self.thread1.join()
582
-
583
- self.master.destroy()
584
-
585
-
586
-
587
-
588
-
589
- FREQ_SCALE = {
590
-
591
- 'ド/C4': 261.626,
592
-
593
- 'レ/D4': 293.665,
594
-
595
- 'ミ/E4': 329.628,
596
-
597
- }
598
-
599
-
600
-
601
- root = tk.Tk()
602
-
603
- app = Synth_application(master=root)
604
-
605
- app.mainloop()
606
-
607
- ```

1

書式を改善しました

2021/11/11 02:31

投稿

lteru
lteru

スコア6

test CHANGED
File without changes
test CHANGED
@@ -16,15 +16,321 @@
16
16
 
17
17
 
18
18
 
19
+ ```Python
20
+
21
+
22
+
23
+ import tkinter as tk
24
+
25
+ import numpy as np
26
+
27
+ import pyaudio
28
+
29
+ import matplotlib.pyplot as plt
30
+
31
+ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
32
+
33
+ from matplotlib.figure import Figure
34
+
35
+
36
+
37
+
38
+
39
+ class Synth_application(tk.Frame):
40
+
41
+ #=== 初期設定
42
+
43
+ def __init__(self, master=None):
44
+
45
+ super().__init__(master)
46
+
47
+ self.master = master
48
+
49
+ self.master.geometry('{}x{}'.format(750, 570))
50
+
51
+ self.start_up()
52
+
53
+ self.create_widgets()
54
+
55
+ self.p = pyaudio.PyAudio()
56
+
57
+ self.stream = self.p.open(format=pyaudio.paFloat32,
58
+
59
+ channels=1,
60
+
61
+ rate=self.rate,
62
+
63
+ frames_per_buffer=self.chunk_size,
64
+
65
+ output=True)
66
+
67
+
68
+
69
+ self.master.protocol("WM_DELETE_WINDOW", self.quit_app)
70
+
71
+
72
+
73
+ #=== 初期値
74
+
75
+ def start_up(self, gain=0.25, rate=44100, chunk_size=1024):
76
+
77
+ global freq
78
+
79
+
80
+
81
+ freq = 261.26
82
+
83
+ self.DURATION = {
84
+
85
+ 'L4': (60 / 100 * 4) / 4,
86
+
87
+ 'L8': (60 / 100 * 4) / 8,
88
+
89
+ }
90
+
91
+ self.duration = self.DURATION['L4']
92
+
93
+ self.bpm = 100 # New
94
+
95
+
96
+
97
+ self.gain = gain
98
+
99
+ self.rate = rate
100
+
101
+ self.chunk_size = chunk_size
102
+
103
+
104
+
105
+ self.t = np.arange(0, self.duration * self.rate) / self.rate
106
+
107
+ self.sin_t = np.sin(2 * np.pi * 0 * self.t)
108
+
109
+
110
+
111
+ #=== ウィジットの定義
112
+
113
+ def create_widgets(self):
114
+
115
+ self.canvas_frame = tk.Frame(self.master, width=700, height=250, bg="#000080")
116
+
117
+ self.canvas_frame.grid(column=0, row=0)
118
+
119
+ self.canvas_frame.grid_propagate(0)
120
+
121
+ self.canvas_frame.grid_anchor(tk.CENTER)
122
+
123
+
124
+
125
+ self.option_frame = tk.Frame(self.master, width=700, height=320, bd = 5, relief = tk.GROOVE) # New
126
+
127
+ self.option_frame.grid(column=0, row=1)
128
+
129
+ self.option_frame.grid_propagate(0)
130
+
131
+ self.option_frame.grid_anchor(tk.CENTER)
132
+
133
+
134
+
135
+ self.chunk_labelFrame = tk.LabelFrame(self.canvas_frame, text="WaveForm", fg='white', bg='#444', relief=tk.FLAT)
136
+
137
+ self.chunk_labelFrame.grid(column=0, row=0)
138
+
139
+ self.chunk_innerBox = tk.Frame(self.chunk_labelFrame)
140
+
141
+ self.chunk_innerBox.grid(column=0, row=0)
142
+
143
+
144
+
145
+ fig = Figure(figsize=(6.5,2), dpi=100, tight_layout=True, facecolor='#F0F0F0')
146
+
147
+
148
+
149
+ axes_wave = fig.add_subplot(1, 1, 1)
150
+
151
+ axes_wave.set_title('Sin_wave')
152
+
153
+ axes_wave.set_xlabel('t', fontsize=8)
154
+
155
+ axes_wave.set_ylabel('sin_t', fontsize=8)
156
+
157
+ axes_wave.set_ylim([-(self.gain + 0.05), (self.gain + 0.05)])
158
+
159
+
160
+
161
+ self.line_wave, = axes_wave.plot(self.sin_t[:500])
162
+
163
+
164
+
165
+ self.canvas = FigureCanvasTkAgg(fig, master=self.chunk_innerBox)
166
+
167
+ self.canvas.get_tk_widget().pack(padx=10, pady=10)
168
+
169
+ self.canvas.get_tk_widget().bind('<Any-KeyPress>', self.press_key)
170
+
171
+
172
+
173
+ # sin波の作成
174
+
175
+ def create_sinwave(self, duration, freq):
176
+
177
+ self.duration = duration
178
+
179
+ self.freq = freq
180
+
181
+
182
+
183
+ self.t = np.arange(0, duration * self.rate) / self.rate
184
+
185
+ self.sin_t = np.sin(2 * np.pi * freq * self.t)
186
+
187
+
188
+
189
+ def press_key(self, event):
190
+
191
+ global freq
192
+
193
+
194
+
195
+ self.key = event.keysym
196
+
197
+ if self.key == 'a':
198
+
199
+ freq = FREQ_SCALE['ド/C4']
200
+
201
+ self.create_sinwave(self.duration, freq)
202
+
203
+ self.play()
204
+
205
+ elif self.key == 's':
206
+
207
+ freq = FREQ_SCALE['レ/D4']
208
+
209
+ self.create_sinwave(self.duration, freq)
210
+
211
+ self.play()
212
+
213
+ elif self.key == 'd':
214
+
215
+ freq = FREQ_SCALE['ミ/E4']
216
+
217
+ self.create_sinwave(self.duration, freq)
218
+
219
+ self.play()
220
+
221
+
222
+
223
+ self.reset_sinwave()
224
+
225
+
226
+
227
+ def play(self):
228
+
229
+ self.stream.write(self.sin_t.astype(np.float32).tobytes())
230
+
231
+
232
+
233
+ def reset_sinwave(self):
234
+
235
+ self.line_wave.set_ydata(self.sin_t[:500])
236
+
237
+ self.canvas.draw()
238
+
239
+
240
+
241
+ def quit_app(self):
242
+
243
+ self.stream.close()
244
+
245
+ self.master.destroy()
246
+
247
+
248
+
249
+ FREQ_SCALE = {
250
+
251
+ 'ド/C4': 261.626,
252
+
253
+ 'レ/D4': 293.665,
254
+
255
+ 'ミ/E4': 329.628,
256
+
257
+ }
258
+
259
+
260
+
261
+ root = tk.Tk()
262
+
263
+ app = Synth_application(master=root)
264
+
265
+ app.mainloop()
266
+
267
+
268
+
19
269
  ```
20
270
 
271
+
272
+
273
+ ### 試したこと
274
+
275
+
276
+
277
+ 並列処理について調べたところ、threadを用いることで実現できそうだったため、reset_sinwaveを別スレッドで実行しようと考えました。
278
+
279
+
280
+
281
+ ここでスレッドに通知を送るために、start_fragを用意し、キーが押された際にフラグがTrueになり、サイン波がプロットされるようにしました。
282
+
283
+
284
+
285
+
286
+
287
+ ```Python
288
+
289
+ def start_up(self, gain=0.25, rate=44100, chunk_size=1024):
290
+
291
+    …
292
+
21
- # ライブラリのインポート
293
+ #==== 追加 ===#
294
+
295
+ self.start_flag = False
296
+
297
+ self.quitting_flag = False
298
+
299
+
300
+
301
+
302
+
303
+ #==== 追加 ===#
304
+
305
+ def reset_sinwave(self):
306
+
307
+ while not self.quitting_flag:
308
+
309
+ if self.start_flag:
310
+
311
+ self.line_wave.set_ydata(self.sin_t[:500])
312
+
313
+ self.canvas.draw()
314
+
315
+ ```
316
+
317
+
318
+
319
+ ### ソースコード
320
+
321
+ 下記で音の出力とグラフのプロットを同時にできると考えましたが、コードを実行してもすぐにカーネルが落ちてしまいます。何が足りないでしょうか。
322
+
323
+
324
+
325
+ ```Python
326
+
327
+
22
328
 
23
329
  import tkinter as tk
24
330
 
25
- import numpy as np # sin波
331
+ import numpy as np
26
-
332
+
27
- import pyaudio # メモリ上の音楽を再生
333
+ import pyaudio
28
334
 
29
335
  import matplotlib.pyplot as plt
30
336
 
@@ -32,66 +338,28 @@
32
338
 
33
339
  from matplotlib.figure import Figure
34
340
 
35
-
36
-
37
-
38
-
39
- #=== アプリケーションの定義
341
+ import threading
342
+
343
+
344
+
345
+
40
346
 
41
347
  class Synth_application(tk.Frame):
42
348
 
43
- #=== 初期設定
44
-
45
349
  def __init__(self, master=None):
46
350
 
47
- #=== メインウィンドウの設定
48
-
49
- super().__init__(master) # 親クラス(Application)の __init__ メソッドを実行
351
+ super().__init__(master)
50
352
 
51
353
  self.master = master
52
354
 
53
- self.master.title('Synth_Application')
54
-
55
- self.master.resizable(width=False,height=False) #ウィンドウ幅の固定
56
-
57
-
58
-
59
- #=== オプション:メインウィンドウを画面ん中央に表示させる
60
-
61
- winWidth = 700 # メインウィンドウの幅を定義
62
-
63
- winHeight = 570 # メインウィンドウの高さを定義
64
-
65
- screenWidth = self.master.winfo_screenwidth() # 使用しているモニターの横幅を取得
66
-
67
- screenHeight = self.master.winfo_screenheight() # 使用しているモニターの縦幅を取得
68
-
69
- startX = int((screenWidth / 2) - (winWidth / 2))
70
-
71
- startY = int((screenHeight / 2) - (winHeight / 2))
72
-
73
- self.master.geometry('{}x{}+{}+{}'.format(winWidth, winHeight, startX, startY)) # f-strings 700px × 570pxの画面が左上(縦Xpx、横Ypx)
355
+ self.master.geometry('{}x{}'.format(700, 570, startX, startY))
74
-
75
-
76
-
77
- #=== sin波の初期値設定 → def start_up
78
356
 
79
357
  self.start_up() # 初期値
80
358
 
81
-
82
-
83
- #=== ウィジットをつくる → def create_widgets
84
-
85
- self.create_widgets()
359
+ self.create_widgets()
86
-
87
-
88
-
89
- #=== pyaudioの開始
90
360
 
91
361
  self.p = pyaudio.PyAudio()
92
362
 
93
- #==== 移動 ===#
94
-
95
363
  self.stream = self.p.open(format=pyaudio.paFloat32,
96
364
 
97
365
  channels=1,
@@ -104,10 +372,16 @@
104
372
 
105
373
 
106
374
 
107
- #==== 追加:終了したときの処理 → def quite_app===#
108
-
109
375
  self.master.protocol("WM_DELETE_WINDOW", self.quit_app)
110
376
 
377
+
378
+
379
+ #==== 追加 ===#
380
+
381
+ self.thread1 = threading.Thread(target=self.reset_sinwave)
382
+
383
+ self.thread1.start()
384
+
111
385
 
112
386
 
113
387
 
@@ -116,7 +390,7 @@
116
390
 
117
391
  def start_up(self, gain=0.25, rate=44100, chunk_size=1024):
118
392
 
119
- global freq # 初期値のためにglobal変数が必要
393
+ global freq
120
394
 
121
395
 
122
396
 
@@ -124,35 +398,37 @@
124
398
 
125
399
  self.DURATION = {
126
400
 
127
- 'L1': (60 / 100 * 4), # 全音符
128
-
129
- 'L2': (60 / 100 * 4) / 2, # 二分音符
130
-
131
- 'L4': (60 / 100 * 4) / 4, # 四分音符
401
+ 'L4': (60 / 100 * 4) / 4,
132
-
402
+
133
- 'L8': (60 / 100 * 4) / 8, # 八分音符
403
+ 'L8': (60 / 100 * 4) / 8,
134
404
 
135
405
  }
136
406
 
137
407
  self.duration = self.DURATION['L4']
138
408
 
139
- self.bpm = 100 # New
409
+ self.bpm = 100
140
-
141
-
142
-
410
+
411
+
412
+
143
- self.gain = gain # "A"
413
+ self.gain = gain
144
-
414
+
145
- self.rate = rate # サンプリング周波数"fs":44100
415
+ self.rate = rate
146
-
416
+
147
- self.chunk_size = chunk_size # 音源から1回読み込むときのデータサイズ。1024(=2の10乗) とする場合が多い
417
+ self.chunk_size = chunk_size
148
418
 
149
419
 
150
420
 
151
421
  self.t = np.arange(0, self.duration * self.rate) / self.rate
152
422
 
153
- self.envRange = np.ones(int(self.duration * self.rate)) # 1字配列
154
-
155
- self.sin_t = self.gain * np.sin(2 * np.pi * 0 * self.t)
423
+ self.sin_t = np.sin(2 * np.pi * 0 * self.t)
424
+
425
+
426
+
427
+ #==== 追加 ===#
428
+
429
+ self.start_flag = False
430
+
431
+ self.quitting_flag = False
156
432
 
157
433
 
158
434
 
@@ -160,19 +436,17 @@
160
436
 
161
437
  def create_widgets(self):
162
438
 
163
- #=== フレームをつくる
164
-
165
439
  self.canvas_frame = tk.Frame(self.master, width=700, height=250, bg="#000080")
166
440
 
167
- self.canvas_frame.grid(column=0, row=0) # 1行1列に配置
441
+ self.canvas_frame.grid(column=0, row=0)
168
-
442
+
169
- self.canvas_frame.grid_propagate(0) # フレーム幅の固定
443
+ self.canvas_frame.grid_propagate(0)
170
-
444
+
171
- self.canvas_frame.grid_anchor(tk.CENTER) # gridを中央に表示するには、grid()で配置する要素の親要素にgrid_anchor(tkinter.CENTER)を使う
445
+ self.canvas_frame.grid_anchor(tk.CENTER)
172
-
173
-
174
-
446
+
447
+
448
+
175
- self.option_frame = tk.Frame(self.master, width=700, height=320, bd = 5, relief = tk.GROOVE) # New
449
+ self.option_frame = tk.Frame(self.master, width=700, height=320, bd = 5, relief = tk.GROOVE)
176
450
 
177
451
  self.option_frame.grid(column=0, row=1)
178
452
 
@@ -182,8 +456,6 @@
182
456
 
183
457
 
184
458
 
185
- #=== ウィジェット:LabelFrameウィジットをつくる
186
-
187
459
  self.chunk_labelFrame = tk.LabelFrame(self.canvas_frame, text="WaveForm", fg='white', bg='#444', relief=tk.FLAT)
188
460
 
189
461
  self.chunk_labelFrame.grid(column=0, row=0)
@@ -194,53 +466,33 @@
194
466
 
195
467
 
196
468
 
197
- #=== Figureインスタンスをつくる
198
-
199
- fig = Figure(figsize=(6.5,2), dpi=100, tight_layout=True, facecolor='#F0F0F0') ## 650 x 200のFigureインスタンスを作成, tight_layoutでオブジェクトの配置を自動調整
469
+ fig = Figure(figsize=(6.5,2), dpi=100, tight_layout=True, facecolor='#F0F0F0')
200
-
201
-
202
-
203
- axes_envRange = fig.add_subplot(1, 2, 1) # 1行2列の最初(1,1)に表示
470
+
204
-
205
- axes_envRange.set_title('envRange')
471
+
206
-
207
- axes_envRange.set_xlabel('t', fontsize=8) # ラベルのオプション
472
+
208
-
209
- axes_envRange.set_ylabel('envRange', fontsize=8) # ラベルのオプション
210
-
211
-
212
-
213
- axes_wave = fig.add_subplot(1, 2, 2) # 1行2列の2番目(1,2)に表示
473
+ axes_wave = fig.add_subplot(1, 1, 1)
214
474
 
215
475
  axes_wave.set_title('Sin_wave')
216
476
 
217
- axes_wave.set_xlabel('t', fontsize=8) # ラベルのオプション
477
+ axes_wave.set_xlabel('t', fontsize=8)
218
-
478
+
219
- axes_wave.set_ylabel('sin_t', fontsize=8) # ラベルのオプション
479
+ axes_wave.set_ylabel('sin_t', fontsize=8)
220
480
 
221
481
  axes_wave.set_ylim([-(self.gain + 0.05), (self.gain + 0.05)])
222
482
 
223
483
 
224
484
 
225
- self.line_envRange, = axes_envRange.plot(self.t, self.envRange)
226
-
227
485
  self.line_wave, = axes_wave.plot(self.sin_t[:500])
228
486
 
229
487
 
230
488
 
231
- #=== ウィジェット:FigureCanvasTkAggを宣言し、LabelFrameウィジェット上に配置する
232
-
233
489
  self.canvas = FigureCanvasTkAgg(fig, master=self.chunk_innerBox)
234
490
 
235
491
  self.canvas.get_tk_widget().pack(padx=10, pady=10)
236
492
 
237
- self.canvas.get_tk_widget().bind('<Any-KeyPress>', self.press_key) # イベントハンドラと連動
493
+ self.canvas.get_tk_widget().bind('<Any-KeyPress>', self.press_key)
238
-
239
-
240
-
241
-
242
-
243
-
494
+
495
+
244
496
 
245
497
  # sin波の作成
246
498
 
@@ -252,19 +504,15 @@
252
504
 
253
505
 
254
506
 
255
- # 指定周波数のsin波を指定秒数生成
256
-
257
507
  self.t = np.arange(0, duration * self.rate) / self.rate
258
508
 
259
- self.envRange = np.ones(int(duration * self.rate)) # 1字配列
260
-
261
- self.sin_t = self.gain * np.sin(2 * np.pi * freq * self.t)
509
+ self.sin_t = np.sin(2 * np.pi * freq * self.t)
262
510
 
263
511
 
264
512
 
265
513
  def press_key(self, event):
266
514
 
267
- global freq # 初期値として、create_sinwave(FREQ_SCALE['ド/C4'])のために必要
515
+ global freq
268
516
 
269
517
 
270
518
 
@@ -274,7 +522,7 @@
274
522
 
275
523
  freq = FREQ_SCALE['ド/C4']
276
524
 
277
- self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
525
+ self.create_sinwave(self.duration, freq)
278
526
 
279
527
  self.play()
280
528
 
@@ -282,7 +530,7 @@
282
530
 
283
531
  freq = FREQ_SCALE['レ/D4']
284
532
 
285
- self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
533
+ self.create_sinwave(self.duration, freq)
286
534
 
287
535
  self.play()
288
536
 
@@ -290,17 +538,15 @@
290
538
 
291
539
  freq = FREQ_SCALE['ミ/E4']
292
540
 
293
- self.create_sinwave(self.duration, freq) # def create_sinwave()に渡す
541
+ self.create_sinwave(self.duration, freq)
294
542
 
295
543
  self.play()
296
544
 
297
545
 
298
546
 
299
- self.reset_sinwave()
547
+ self.start_flag = True
300
-
301
-
302
-
303
- # ストリームに渡して再生
548
+
549
+
304
550
 
305
551
  def play(self):
306
552
 
@@ -312,29 +558,35 @@
312
558
 
313
559
  def reset_sinwave(self):
314
560
 
561
+ while not self.quitting_flag:
562
+
563
+ if self.start_flag:
564
+
315
- self.line_wave.set_ydata(self.sin_t[:500]) # グラフのy軸をアップデート
565
+ self.line_wave.set_ydata(self.sin_t[:500]) # グラフのy軸をアップデート
316
-
566
+
317
- self.canvas.draw()
567
+ self.canvas.draw()
318
568
 
319
569
 
320
570
 
321
571
  #==== 追加 ===#
322
572
 
323
- # 終了ボタンが押された時の処理
324
-
325
573
  def quit_app(self):
326
574
 
327
575
  self.stream.close()
328
576
 
577
+
578
+
579
+ self.quitting_flag = True
580
+
581
+ self.thread1.join()
582
+
329
- self.master.destroy()
583
+ self.master.destroy()
330
-
331
-
332
-
333
-
334
-
335
- # パラメータ
584
+
336
-
585
+
586
+
587
+
588
+
337
- FREQ_SCALE = { # 周波数f0のスケール
589
+ FREQ_SCALE = {
338
590
 
339
591
  'ド/C4': 261.626,
340
592
 
@@ -352,40 +604,4 @@
352
604
 
353
605
  app.mainloop()
354
606
 
355
-
356
-
357
607
  ```
358
-
359
-
360
-
361
- ### 試したこと
362
-
363
-
364
-
365
- 並列処理について調べたところ、threadを用いることで実現できると考えました。
366
-
367
- そこで、start_frag
368
-
369
-
370
-
371
-
372
-
373
- ### 該当のソースコード
374
-
375
-
376
-
377
- ```Python
378
-
379
-
380
-
381
- ```
382
-
383
-
384
-
385
-
386
-
387
- ### 補足情報(FW/ツールのバージョンなど)
388
-
389
-
390
-
391
- ここにより詳細な情報を記載してください。