Python でキーボードピアノを作る方法について、スクリプトをまとめ、公開しておきます。
マウスクリックだけでなく、パソコンのキーからも演奏ができます。
以下の環境で動作を確認しています。
環境:
・ Windows 10 パソコン(Anaconda、Python 3、pygame インストール済み)
※ Python と pygame は必須です。pygame をインストールしていない場合は、下記の関連リンクを参照してみてください。
背景 ~ パソコンをキーボードピアノ代わりにする!
Windows パソコンで Python 経由で MIDI 音源が自由に扱えるようになると、ちょっとした音楽を簡単に作成できるようになり、パソコンや Python の活用の幅が格段に広がります。
ということで、Python でキーボードピアノを作るスクリプトをまとめ、公開しておくことにします。
設定のしかた
① パソコンにフォルダを作成し、keyboard_piano1.py というテキストファイルを作成してください。
例: C:\user\keyboard_piano\
② ①のフォルダ内に keyboard_piano1.py という名前でテキストファイルを作成し、下記のスクリプトをコピー&ペーストして保存してください。
例: C:\user\keyboard_piano\keyboard_piano1.py
キーボードピアノの使い方:パソコンのキーで鍵盤代わり
③ コマンドプロンプト(または、Anaconda Prompt)を起動して、以下のコマンドを実行してください。キーボードピアノの GUI が起動します。
python C:\user\keyboard_piano\keyboard_piano1.py
※ 鍵盤をクリックすると音が鳴ります。PC のキーボードのキーを押しても音が鳴ります。
※ ピアノの白鍵と黒鍵の位置関係にほぼ対応するよう、パソコンのキーを割りつけています。
パソコンのキーボードのキーをいくつか押してみてください。
音の大きさの調整
音量は「volume」欄の「+」、「-」ボタンをクリックして調整してください。
数値を直接入力しても設定できます。
MIDI の楽器を設定する
楽器を設定・変更するには、ソフトウェアの画面 GUI 上、「instrument」欄の「+」、「-」ボタンをクリックしてみてください。
楽器の種類は、以下の表を参照してください。
設定している数値が instrument 番号に対応しています。簡単のため、下記のリストは抜粋としていますが、表に示した前後の数値を入れると、類似の楽器が設定できると思います。なお、数値はテキストボックスに直接半角数値で入力できますが、設定を反映させるため、「+」「-」ボタンで値を前後させてみてください。
instrument 番号 | 楽器 |
001 | Acoustic Grand Piano グランドピアノ |
007 | Harpsichord ハープシコード |
013 | Marimba マリンバ/木琴 |
017 | Drawbar Organ 電気オルガン |
022 | Accordion アコーディオン |
023 | Harmonica ハーモニカ |
025 | Acoustic Guitar アコースティックギター |
033 | Acoustic Bass アコースティックベース |
041 | Violin バイオリン |
043 | Chello チェロ |
053 | Choir Aahs 合唱(アー) |
057 | Trumpet トランペット |
061 | French Horn フレンチホルン |
065 | Soprano Sax ソプラノサックス |
069 | Oboe オーボエ |
072 | Clarinet クラリネット |
073 | Piccolo ピッコロ |
074 | Flute フルート |
078 | Shakuhachi 尺八 |
081 | Lead 1 シンセサイザー |
107 | Shamisen 三味線 |
108 | Koto 琴 |
113 | Tinkle Bell ティンカベル |
117 | Taiko Drum 和太鼓 |
123 | Seashore 海辺 |
124 | Bird Tweet 鳥のさえずり |
127 | Applause 拍手 |
好きな楽器で音階をつけて自由に演奏できます。
※ MIDI は社団法人音楽電子事業協会(AMEI)の登録商標です。
まとめ
Python のキーボードピアノのサンプルスクリプトをまとめました。
これで、任意の音源も扱えるようになりました。
なお、スクリプトの解説については、以下の「ドレミファソラシドを鳴らすサンプル」を参照してください。
プログラムが長くなりすぎたため詳細は省略しますが、MIDI 音源を鳴らすポイントの部分はこのリンク先と同等です。
他に、カノン進行、Just the Tow of Us 進行など、任意のコード進行を演奏するスクリプトなどについてもまとめています。
音楽関連のプログラミングなど、もし関心があるようでしたら、参考にしてみてください。
関連リンク
・ ドレミファソラシドを鳴らすサンプル【pygame】
・ Python で Just the Two of Us 進行 【pygame】
・ 【tkinter】 テキストボックスとボタンを使う方法 コピペ用サンプル
・ PC の音声を録音する方法
・ Anaconda 環境で Pygame をインストールする手順【Python】
・ Pygame をインストールする手順
サンプルスクリプト keyboard_piano1.py
import tkinter as tk1
import threading as th1
import time as tm1
import pygame.midi
class tone_thread1( th1.Thread ):
def __init__( self ):
super( tone_thread1, self ).__init__()
def run( self ):
tone1()
def tone1():
global n1
global vol1
out1.note_on( n1, vol1 )
tm1.sleep( 2.0 )
out1.note_off( n1, vol1 )
def btn1( n0 ):
global n1
n1 = n0 - 25 + 60
thr1 = tone_thread1()
thr1.start()
def key1( event ):
global n1
c1 = event.char
n0 = 0
if c1 == 'a':
n0 = 60
elif c1 == 'w':
n0 = 61
elif c1 == 's':
n0 = 62
elif c1 == 'e':
n0 = 63
elif c1 == 'd':
n0 = 64
elif c1 == 'f':
n0 = 65
elif c1 == 'y':
n0 = 66
elif c1 == 'g':
n0 = 67
elif c1 == 'y':
n0 = 68
elif c1 == 'h':
n0 = 69
elif c1 == 'u':
n0 = 70
elif c1 == 'j':
n0 = 71
elif c1 == 'k':
n0 = 72
elif c1 == 'o':
n0 = 73
elif c1 == 'l':
n0 = 74
elif c1 == 'p':
n0 = 75
elif c1 == ';':
n0 = 76
elif c1 == ':':
n0 = 77
elif c1 == '[':
n0 = 78
elif c1 == ']':
n0 = 79
if n0 > 0:
n1 = n0
thr1 = tone_thread1()
thr1.start()
def inst1( n1 ):
global ins1
global chn1
ins0 = textbox1.get()
if ins0.isdigit():
ins0 = int( ins0 )
else:
ins0 = 1
if n1 > 0:
ins0 = ins0 + 1
else:
ins0 = ins0 - 1
if ins0 < 1: ins0 = 1 elif ins0 > 128:
ins0 = 128
ins1 = ins0 - 1
textbox1.delete(0, tk1.END)
textbox1.insert(0, str(ins0) )
btn_inst1.focus_set()
out1.set_instrument(ins1, chn1)
def volu1( n1 ):
global vol1
vol0 = textbox2.get()
if vol0.isdigit():
vol0 = int( vol0 )
else:
vol0 = 127
if n1 > 0:
vol0 = vol0 + 1
else:
vol0 = vol0 - 1
if vol0 < 0: vol0 = 0 elif vol0 > 127:
vol0 = 127
vol1 = vol0
textbox2.delete(0, tk1.END)
textbox2.insert(0, str(vol1) )
btn_inst3.focus_set()
root = tk1.Tk()
root.title('midi_piano v0.2')
root.geometry("910x140")
root["bg"] = "#202020"
root.bind( "", key1 )
btn01 = tk1.Button(root, text='', bg='white', command=lambda:btn1(1))
btn01.place(x=20, y=30, height=100, width=30)
btn02 = tk1.Button(root, text='', bg='white', command=lambda:btn1(3))
btn02.place(x=50, y=30, height=100, width=30)
btn03 = tk1.Button(root, text='', bg='white', command=lambda:btn1(5))
btn03.place(x=80, y=30, height=100, width=30)
btn04 = tk1.Button(root, text='', bg='white', command=lambda:btn1(6))
btn04.place(x=110, y=30, height=100, width=30)
btn05 = tk1.Button(root, text='', bg='white', command=lambda:btn1(8))
btn05.place(x=140, y=30, height=100, width=30)
btn06 = tk1.Button(root, text='', bg='white', command=lambda:btn1(10))
btn06.place(x=170, y=30, height=100, width=30)
btn07 = tk1.Button(root, text='', bg='white', command=lambda:btn1(12))
btn07.place(x=200, y=30, height=100, width=30)
btn08 = tk1.Button(root, text='', bg='white', command=lambda:btn1(13))
btn08.place(x=230, y=30, height=100, width=30)
btn09 = tk1.Button(root, text='', bg='white', command=lambda:btn1(15))
btn09.place(x=260, y=30, height=100, width=30)
btn10 = tk1.Button(root, text='', bg='white', command=lambda:btn1(17))
btn10.place(x=290, y=30, height=100, width=30)
btn11 = tk1.Button(root, text='', bg='white', command=lambda:btn1(18))
btn11.place(x=320, y=30, height=100, width=30)
btn12 = tk1.Button(root, text='', bg='white', command=lambda:btn1(20))
btn12.place(x=350, y=30, height=100, width=30)
btn13 = tk1.Button(root, text='', bg='white', command=lambda:btn1(22))
btn13.place(x=380, y=30, height=100, width=30)
btn14 = tk1.Button(root, text='', bg='white', command=lambda:btn1(24))
btn14.place(x=410, y=30, height=100, width=30)
btn15 = tk1.Button(root, text='', bg='white', command=lambda:btn1(25))
btn15.place(x=440, y=30, height=100, width=30)
btn16 = tk1.Button(root, text='', bg='white', command=lambda:btn1(27))
btn16.place(x=470, y=30, height=100, width=30)
btn17 = tk1.Button(root, text='', bg='white', command=lambda:btn1(29))
btn17.place(x=500, y=30, height=100, width=30)
btn18 = tk1.Button(root, text='', bg='white', command=lambda:btn1(30))
btn18.place(x=530, y=30, height=100, width=30)
btn19 = tk1.Button(root, text='', bg='white', command=lambda:btn1(32))
btn19.place(x=560, y=30, height=100, width=30)
btn20 = tk1.Button(root, text='', bg='white', command=lambda:btn1(34))
btn20.place(x=590, y=30, height=100, width=30)
btn21 = tk1.Button(root, text='', bg='white', command=lambda:btn1(36))
btn21.place(x=620, y=30, height=100, width=30)
btn22 = tk1.Button(root, text='', bg='white', command=lambda:btn1(37))
btn22.place(x=650, y=30, height=100, width=30)
btn23 = tk1.Button(root, text='', bg='white', command=lambda:btn1(39))
btn23.place(x=680, y=30, height=100, width=30)
btn24 = tk1.Button(root, text='', bg='white', command=lambda:btn1(41))
btn24.place(x=710, y=30, height=100, width=30)
btn25 = tk1.Button(root, text='', bg='white', command=lambda:btn1(42))
btn25.place(x=740, y=30, height=100, width=30)
btn26 = tk1.Button(root, text='', bg='white', command=lambda:btn1(44))
btn26.place(x=770, y=30, height=100, width=30)
btn27 = tk1.Button(root, text='', bg='white', command=lambda:btn1(46))
btn27.place(x=800, y=30, height=100, width=30)
btn28 = tk1.Button(root, text='', bg='white', command=lambda:btn1(48))
btn28.place(x=830, y=30, height=100, width=30)
btn29 = tk1.Button(root, text='', bg='white', command=lambda:btn1(49))
btn29.place(x=860, y=30, height=100, width=30)
btn51 = tk1.Button(root, bg='black', command=lambda:btn1(2))
btn51.place(x=40, y=30, height=60, width=20)
btn52 = tk1.Button(root, bg='black', command=lambda:btn1(4))
btn52.place(x=70, y=30, height=60, width=20)
btn53 = tk1.Button(root, bg='black', command=lambda:btn1(7))
btn53.place(x=130, y=30, height=60, width=20)
btn54 = tk1.Button(root, bg='black', command=lambda:btn1(9))
btn54.place(x=160, y=30, height=60, width=20)
btn55 = tk1.Button(root, bg='black', command=lambda:btn1(11))
btn55.place(x=190, y=30, height=60, width=20)
btn56 = tk1.Button(root, bg='black', command=lambda:btn1(14))
btn56.place(x=250, y=30, height=60, width=20)
btn57 = tk1.Button(root, bg='black', command=lambda:btn1(16))
btn57.place(x=280, y=30, height=60, width=20)
btn58 = tk1.Button(root, bg='black', command=lambda:btn1(19))
btn58.place(x=340, y=30, height=60, width=20)
btn59 = tk1.Button(root, bg='black', command=lambda:btn1(21))
btn59.place(x=370, y=30, height=60, width=20)
btn60 = tk1.Button(root, bg='black', command=lambda:btn1(23))
btn60.place(x=400, y=30, height=60, width=20)
btn61 = tk1.Button(root, bg='black', command=lambda:btn1(26))
btn61.place(x=460, y=30, height=60, width=20)
btn62 = tk1.Button(root, bg='black', command=lambda:btn1(28))
btn62.place(x=490, y=30, height=60, width=20)
btn63 = tk1.Button(root, bg='black', command=lambda:btn1(31))
btn63.place(x=550, y=30, height=60, width=20)
btn64 = tk1.Button(root, bg='black', command=lambda:btn1(33))
btn64.place(x=580, y=30, height=60, width=20)
btn65 = tk1.Button(root, bg='black', command=lambda:btn1(35))
btn65.place(x=610, y=30, height=60, width=20)
btn66 = tk1.Button(root, bg='black', command=lambda:btn1(38))
btn66.place(x=670, y=30, height=60, width=20)
btn67 = tk1.Button(root, bg='black', command=lambda:btn1(40))
btn67.place(x=700, y=30, height=60, width=20)
btn68 = tk1.Button(root, bg='black', command=lambda:btn1(43))
btn68.place(x=760, y=30, height=60, width=20)
btn69 = tk1.Button(root, bg='black', command=lambda:btn1(45))
btn69.place(x=790, y=30, height=60, width=20)
btn70 = tk1.Button(root, bg='black', command=lambda:btn1(47))
btn70.place(x=820, y=30, height=60, width=20)
label1 = tk1.Label(text='instrument :')
label1.place(x=310, y=5, height=20, width=80)
label1["bg"] = "#202020"
label1["foreground"] = "#FFFFFF"
textbox1 = tk1.Entry( master=root )
textbox1.place( x=390, y=5, height=20, width=30)
btn_inst1 = tk1.Button(root, text='-', command=lambda:inst1(-1))
btn_inst1.place(x=420, y=5, height=20, width=20)
btn_inst1["bg"] = "#444444"
btn_inst1["foreground"] = "#FFFFFF"
btn_inst2 = tk1.Button(root, text='+', command=lambda:inst1(1))
btn_inst2.place(x=440, y=5, height=20, width=20)
btn_inst2["bg"] = "#444444"
btn_inst2["foreground"] = "#FFFFFF"
label2 = tk1.Label(text='volume :')
label2["bg"] = "#202020"
label2["foreground"] = "#FFFFFF"
label2.place(x=510, y=5, height=20, width=70)
textbox2 = tk1.Entry( master=root )
textbox2.place( x=580, y=5, height=20, width=30)
btn_inst3 = tk1.Button(root, text='-', command=lambda:volu1(-1))
btn_inst3.place(x=610, y=5, height=20, width=20)
btn_inst3["bg"] = "#444444"
btn_inst3["foreground"] = "#FFFFFF"
btn_inst4 = tk1.Button(root, text='+', command=lambda:volu1(1))
btn_inst4.place(x=630, y=5, height=20, width=20)
btn_inst4["bg"] = "#444444"
btn_inst4["foreground"] = "#FFFFFF"
ins1 = 1
vol1 = 127
oct1 = 0
chn1 = 0
n1 = 60
pygame.midi.init()
out1 = pygame.midi.Output(0)
out1.set_instrument(ins1, chn1)
textbox1.insert(0, ins1)
textbox2.insert(0, vol1)
root.mainloop()
out1.close()
pygame.midi.quit()