Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

Python: PyQt5のQPushButtonで作る簡易ピアノ鍵盤

PyQt5の練習がてら、ピアノ鍵盤(もどき)を作ってみました。

タプル型の引数keysetで鍵盤の数を変えられます。

ハマったところ:

  • 参考にしたドキュメント:Qt 5.15
  • buttonClicked に引数を渡すなら、partial()が便利
  • PythonはQtの情報が少ないので、他の言語(e.g. C++)でのQtの例を探したほうがよさそう ※synthesizerはバックエンド開発用の引数なので、無視してください。

f:id:Kurene:20191115091710p:plain

'''
License: MIT
'''
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QHBoxLayout, QMessageBox
import sys
from functools import partial

class MyWidget(QWidget):
    pitch_class = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
    pitch_freq_di = {pn+str(k): 440*2**(((12*k+idx)-48)/12)
                     for idx, pn in enumerate(pitch_class)\
                     for k in range(0, 9)}
    def __init__(self, synthesizer=None, keyset=(51, 64)):
        super().__init__()
        self.synthesizer = synthesizer
        self.keyset = keyset
        self.init_ui() 
        self.show()
        
    def __make_bt(self, name):
        bt = QPushButton(name)
        if "#" in name:
            bt.setStyleSheet("background-color: #999999")
        else:
            bt.setStyleSheet("background-color: #ffffff")
        bt.setContentsMargins(0,0,0,0)
        freq = MyWidget.pitch_freq_di[name]
        bt.clicked.connect(partial(self.buttonClicked, freq)) 
        bt.setMaximumWidth(50)
        bt.setMaximumHeight(300)
        print(f"{name}\t{freq}")
        return bt
        
    def init_ui(self):
        self.setStyleSheet("background-color: #eeeeee")
        self.setWindowTitle('Synthesizer')

        keys = QHBoxLayout()
        for n in range(self.keyset[0], self.keyset[1]):
            name = MyWidget.pitch_class[n%12] + str(n//12)
            keys.addWidget(self.__make_bt(name))
        self.setLayout(keys)

        self.setGeometry(300, 300, 720, 160) # x, y, width, height

          
    def buttonClicked(self, freq):
        sender = self.sender()
        if self.synthesizer is not None:
            self.synthesizer.request(freq, type)

            
    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Message',  "Are you sure to quit?", QMessageBox.Yes, QMessageBox.No)

        if reply == QMessageBox.Yes:
            if self.synthesizer is not None:
                self.synthesizer.terminate()
            event.accept()
        else:
            event.ignore()          

            
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyWidget()
    sys.exit(app.exec_())

補足

これをベースにシンセサイザもどきを作りました

www.wizard-notes.com