我正在尝试为我创建的终端应用程序创建一个 GUI,该应用程序监听您的麦克风以确定您在吉他上演奏的音符。我想使用 PyQt5,这是我第一次使用它(或者特别是任何 GUI 框架)。
我可以很好地创建 UI,但是我用于由 QTimer 调用的笔记检测的主要功能使应用程序非常缓慢且无响应。我认为我在如何设置方面做得非常错误,但我自己找不到最好的方法。
这是我的代码:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWidgets import QGridLayout, QLabel
from PyQt5.QtGui import QFont
from PyQt5.QtCore import QTimer, QTime, Qt
import pyaudio
import numpy as np
from aubio import pitch
from helpers import pitch2note
# set up globals
CHUNK = 1024
FORMAT = pyaudio.paFloat32
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5000
tolerance = 0.8
downsample = 1
win_s = 4096 // downsample # fft size
hop_s = 1024 // downsample # hop size
pitch_o = pitch("yinfft", win_s, hop_s, RATE)
pitch_o.set_unit("Hz")
pitch_o.set_silence(-40)
pitch_o.set_tolerance(tolerance)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setupUI()
def setupUI(self):
# UI design is very much in progress
# not final but it shouldn't matter for this case
self.setGeometry(100, 100, 800, 400)
self.noteLabel = QLabel('Note played:')
layout = QGridLayout()
font = QFont('Arial', 60, QFont.Bold)
self.note = QLabel() # the variable I will modify later
self.note.setAlignment(Qt.AlignCenter)
# setting font to the label
self.note.setFont(font)
# adding widgets to the layout
layout.addWidget(self.noteLabel, 1, 0)
layout.addWidget(self.note, 1, 1)
# setting the layout to main window
self.setLayout(layout)
# creating a timer object
timer = QTimer(self)
# adding action to timer
# this is what might be wrong
timer.timeout.connect(self.getNote)
# update the timer every 33ms (30fps?)
# or is it too much?
timer.start(33)
def getNote(self):
# main function handling note detection
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
frames = []
notes_list = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
buffer = stream.read(CHUNK)
frames.append(buffer)
signal = np.frombuffer(buffer, dtype=np.float32)
pitch_of_note = pitch_o(signal)[0]
if pitch_of_note != 0:
note_played = pitch2note(pitch_of_note)
notes_list.append(note_played[:-1])
# we append only note and not number (eg. E and not E2)
if len(notes_list) == 10:
# We listen for 10 signals and then select the most frequent note in the list
# This is because when you pluck a note the frequency can deviate as you pluck it strongly
most_likely_note = max(notes_list, key=notes_list.count)
stream.stop_stream()
stream.close()
p.terminate()
self.label.setText(most_likely_note)
return most_likely_note
# create pyqt5 app
App = QApplication(sys.argv)
# create the instance of our Window
window = Window()
# showing all the widgets
window.show()
# start the app
App.exit(App.exec_())
这是帮助文件:
from math import log2
A4 = 440
C0 = A4*pow(2, -4.75)
NOTE_NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
def pitch2note(freq):
h = round(12*log2(freq/C0))
octave = h // 12
n = h % 12
return NOTE_NAMES[n] + str(octave)