Posts: 18
Threads: 3
Joined: Jul 2018
Jul-11-2018, 04:18 AM
(This post was last modified: Jul-11-2018, 04:18 AM by mekha.)
(Jul-10-2018, 04:26 PM)Alfalfa Wrote: (Jul-07-2018, 02:44 AM)mekha Wrote: It does looping forever until I terminate the graphs window, then they stop.
But if I want to assign this Qtimer to show some frequency data as Label Text in my QtDesigner window, then how I can do that?
I'm not sure to understand, are you asking about how to use the QTimer to refresh the text of a QLabel?
If so, simply add something like
self.ui.yourLabel.setText("frequency data") into the function connected to your timer..
The purpose of QtDesigner is to organize your widget, but the dynamic content is rather set by using python.
I'm sorry if I confused you, I'm trying my best to tell you since English isn't my primary language
I see... I'll try it if it is can show the freq data as I hope so
But can you take a look of this code for me, I have a problem with this freq analyzer recorder. My question is why in the middle of recording data it's stopped and if I tried to close the data (every single time) there'll be a warning and it said to me that the .py file still running (but the weird is, there's actually no updates at all or any more progress of the data itself, totally stop)
import pyaudio
import os
import struct
import numpy as np
import time
from time import sleep
CHUNK = 2**14 #2**15 #4096
WIDTH = 2
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
dt = 1.0/RATE
### frequencies of the strings for the violin (tunned in A), in Hz
f4 = 195.998 ## G3
f3 = 293.665 ## D4
f2 = 440.000 ## A4
f1 = 659.255 ## E5
n = CHUNK
freqs = np.fft.rfftfreq(n, d = dt)
def Frequency_of_position(position):
""" Returns the frequency (Hz) of the note in from its position (halftones)
relative to A4 in an equal tempered scale. Ex: 0 -> 440 Hz (A4),
12 -> 880 Hz (A5)."""
return 440.0*(2**(1.0/12.0))**position
def Position_to_note(position):
"A A# B C C# D D# E F F# G G#"
SCALE = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
LETTER = SCALE[position % 12]
NUMBER = str(int((position+57) / 12))
return LETTER+NUMBER
pos = np.array(range(-36,48))
vnote_freqs = np.vectorize(Frequency_of_position)
note_freqs = vnote_freqs(pos)
def get_frequency( spectrum ):
return freqs[np.argmax(spectrum)]
class Freq_analysis(object):
def __init__(self):
self.pa = pyaudio.PyAudio()
self.stream = self.open_mic_stream()
def stop(self):
self.stream.close()
def open_mic_stream( self ):
device_index = self.find_input_device()
stream = self.pa.open( format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
input_device_index = device_index,
frames_per_buffer = CHUNK)
return stream
def find_input_device(self):
device_index = None
for i in range( self.pa.get_device_count() ):
devinfo = self.pa.get_device_info_by_index(i)
print( "Device %d: %s"%(i,devinfo["name"]) )
for keyword in ["mic","input"]:
if keyword in devinfo["name"].lower():
print( "Found an input: device %d - %s"% (i,devinfo["name"]) )
device_index = i
return device_index
if device_index == None:
print( "No preferred input found; using default input device." )
return device_index
def PrintFreq(self, S2):
dominant = get_frequency( S2 )
dist = np.abs(note_freqs-dominant)
closest_pos = pos[np.argmin(dist)]
closest_note = Position_to_note(closest_pos)
print(dominant, "(",closest_note, "=",Frequency_of_position(closest_pos),")")
def listen(self):
try:
block = self.stream.read(CHUNK)
except IOError:
# An error occurred.
print( "Error recording.")
return
indata = np.array(struct.unpack("%dh"%(len(block)/2),block))
n = indata.size
freqs = np.fft.rfftfreq(n, d = dt)
data_rfft = np.fft.rfft(indata)
S2 = np.abs(data_rfft)**2
#self.PrintFreq(block)
#self.update_fig(block)
self.PrintFreq(S2)
if __name__ == "__main__":
Tuner = Freq_analysis()
for i in range(100):
Tuner.listen() And yes, this is the freq data I want to showed in my QT Window since it's running on the back, so if I can injected the label to show the result of this freq recorder I'm truly happy
Posts: 18
Threads: 3
Joined: Jul 2018
(Jul-04-2018, 10:30 AM)DeaD_EyE Wrote: I have no clue about music.
Based on this Article and this Example with matplotlib, I wrote an example.
from itertools import product
import matplotlib.pyplot as plt
def calc_freq_from_midi(m):
if m < 0 or m > 127:
raise ValueError('m must be between 0 and 127.')
notes = ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B')
octaves = range(-1, 10)
notes = product(octaves, notes)
notes = [note + str(band) for band, note in notes]
freq = 440 * 2 ** ((m - 69)/12)
return freq, notes[m]
labels = [calc_freq_from_midi(m) for m in range(128)]
x_ticks, x_labels = zip(*labels) # it's a transpose
frequencies = [110.0, 220.0, 440.0] # A2, A3, A4
magnitude = [2, 3, 4]
plt.title('Spectrum')
plt.xlabel('Notes')
plt.ylabel('Magnitude')
plt.xticks(x_ticks, x_labels, rotation='vertical')
plt.plot(frequencies, magnitude, 'o')
plt.legend(['Signal'])
plt.show() Just check if the notes are correct.
It should plot A2, A3 and A4 as blue dots.
I guess you can also print two different xticks.
Just explore the matplotlib examples.
If you don't use matplotlib inside of QT, you have to adapt it to the plotting framework you use.
(Jul-10-2018, 04:26 PM)Alfalfa Wrote: (Jul-07-2018, 02:44 AM)mekha Wrote: It does looping forever until I terminate the graphs window, then they stop.
But if I want to assign this Qtimer to show some frequency data as Label Text in my QtDesigner window, then how I can do that?
I'm not sure to understand, are you asking about how to use the QTimer to refresh the text of a QLabel?
If so, simply add something like
self.ui.yourLabel.setText("frequency data") into the function connected to your timer..
The purpose of QtDesigner is to organize your widget, but the dynamic content is rather set by using python.
When I calling a class inside the freq.py inside the go.py, the QtWindow (the graphs and others) couldn't showed up it keep loading and the freq analyzer keep running on the back giving results of it's recorder
the updated go.py
from PyQt4 import QtGui,QtCore
import sys
import ui_main
import StrSetting
import numpy as np
import pyqtgraph
import SWHear
import freq
from freq import Freq_analysis
class SoundApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
def __init__(self, parent=None):
pyqtgraph.setConfigOption('background', 'w') #before loading widget
super(SoundApp, self).__init__(parent)
self.setupUi(self)
self.grFFT.plotItem.showGrid(True, True, 0.7)
self.grPCM.plotItem.showGrid(True, True, 0.7)
self.maxFFT=0
self.maxPCM=0
self.ear = SWHear.SWHear(rate=44100,updatesPerSecond=20)
self.ear.stream_start()
def update(self):
if not self.ear.data is None and not self.ear.fft is None:
pcmMax=np.max(np.abs(self.ear.data))
if pcmMax>self.maxPCM:
self.maxPCM=pcmMax
self.grPCM.plotItem.setRange(yRange=[-pcmMax,pcmMax])
if np.max(self.ear.fft)>self.maxFFT:
self.maxFFT=np.max(np.abs(self.ear.fft))
#self.grFFT.plotItem.setRange(yRange=[0,self.maxFFT])
self.grFFT.plotItem.setRange(yRange=[0,1])
self.pbLevel.setValue(1000*pcmMax/self.maxPCM)
pen=pyqtgraph.mkPen(color='b')
self.grPCM.plot(self.ear.datax,self.ear.data,pen=pen,clear=True)
pen=pyqtgraph.mkPen(color='r')
self.grFFT.plot(self.ear.fftx,self.ear.fft/self.maxFFT,pen=pen,clear=True)
QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat
if __name__=="__main__":
app = QtGui.QApplication(sys.argv)
form = SoundApp()
form.show()
form.update() #start with something
Tuner = Freq_analysis()
for i in range(1000):
Tuner.listen()
app.exec_()
print("DONE") and this is the freq.py
import pyaudio
import os
import struct
import numpy as np
import time
from time import sleep
CHUNK = 2**14 #2**15 #4096
WIDTH = 2
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
dt = 1.0/RATE
### frequencies of the strings for the violin (tunned in A), in Hz
f4 = 195.998 ## G3
f3 = 293.665 ## D4
f2 = 440.000 ## A4
f1 = 659.255 ## E5
n = CHUNK
freqs = np.fft.rfftfreq(n, d = dt)
def Frequency_of_position(position):
""" Returns the frequency (Hz) of the note in from its position (halftones)
relative to A4 in an equal tempered scale. Ex: 0 -> 440 Hz (A4),
12 -> 880 Hz (A5)."""
return 440.0*(2**(1.0/12.0))**position
def Position_to_note(position):
"A A# B C C# D D# E F F# G G#"
SCALE = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
LETTER = SCALE[position % 12]
NUMBER = str(int((position+57) / 12))
return LETTER+NUMBER
pos = np.array(range(-36,48))
vnote_freqs = np.vectorize(Frequency_of_position)
note_freqs = vnote_freqs(pos)
def get_frequency( spectrum ):
return freqs[np.argmax(spectrum)]
class Freq_analysis(object):
def __init__(self):
self.pa = pyaudio.PyAudio()
self.stream = self.open_mic_stream()
def stop(self):
self.stream.close()
def open_mic_stream( self ):
device_index = self.find_input_device()
stream = self.pa.open( format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
input_device_index = device_index,
frames_per_buffer = CHUNK)
return stream
def find_input_device(self):
device_index = None
for i in range( self.pa.get_device_count() ):
devinfo = self.pa.get_device_info_by_index(i)
print( "Device %d: %s"%(i,devinfo["name"]) )
for keyword in ["mic","input"]:
if keyword in devinfo["name"].lower():
print( "Found an input: device %d - %s"% (i,devinfo["name"]) )
device_index = i
return device_index
if device_index == None:
print( "No preferred input found; using default input device." )
return device_index
def PrintFreq(self, S2):
dominant = get_frequency( S2 )
dist = np.abs(note_freqs-dominant)
closest_pos = pos[np.argmin(dist)]
closest_note = Position_to_note(closest_pos)
print(dominant, "(",closest_note, "=",Frequency_of_position(closest_pos),")")
def listen(self):
try:
block = self.stream.read(CHUNK)
except IOError:
# An error occurred.
print( "Error recording.")
return
indata = np.array(struct.unpack("%dh"%(len(block)/2),block))
n = indata.size
freqs = np.fft.rfftfreq(n, d = dt)
data_rfft = np.fft.rfft(indata)
S2 = np.abs(data_rfft)**2
#self.PrintFreq(block)
#self.update_fig(block)
self.PrintFreq(S2)
if __name__ == "__main__":
Tuner = Freq_analysis()
for i in range(100):
Tuner.listen()
Posts: 164
Threads: 22
Joined: Feb 2017
I'm glad to help you get on the right track, but unfortunately I do not have the time to go over your code. So your problem is that you are trying to have a long running code in parallel with your GUI? In that case, instead of QTimer your need to put the long running code in a separate thread, or else the GUI will becomes unresponsive.
Then the right way to send data back from the worker thread to the gui thread is by using signals and slots. To get you started, have a look at this example: https://gitlab.com/snippets/1732597
In your case, the frequency analysis would go into the function run() (class WorkerThread), the result would be sent through the signal/slot mechanism, and the label would be set into the function signalExample() of the gui thread (class Main). Hope that helps.
Posts: 18
Threads: 3
Joined: Jul 2018
(Jul-12-2018, 09:38 PM)Alfalfa Wrote: I'm glad to help you get on the right track, but unfortunately I do not have the time to go over your code. So your problem is that you are trying to have a long running code in parallel with your GUI? In that case, instead of QTimer your need to put the long running code in a separate thread, or else the GUI will becomes unresponsive.
Then the right way to send data back from the worker thread to the gui thread is by using signals and slots. To get you started, have a look at this example: https://gitlab.com/snippets/1732597
In your case, the frequency analysis would go into the function run() (class WorkerThread), the result would be sent through the signal/slot mechanism, and the label would be set into the function signalExample() of the gui thread (class Main). Hope that helps.
I've checked the post you linked but it's for Python 3x and using PyQt5, and I'm using Python 2.7 and PyQt4...
So what I can confirmed for the progress I've been making from my last post is, when I said it's error not showing the graphs window and etc but only the python running box...
It's actually happened that way because when I combined the freq analyzer with my graph sound visualizer and when I run the overall code both the freq analyzer and sound visualizer (it's on the go.py)
from PyQt4 import QtGui,QtCore
import sys
import ui_main
import StrSetting
import numpy as np
import pyqtgraph
import SWHear
import freq
from freq import Freq_analysis
class SoundApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
def __init__(self, parent=None):
pyqtgraph.setConfigOption('background', 'w') #before loading widget
super(SoundApp, self).__init__(parent)
self.setupUi(self)
self.grFFT.plotItem.showGrid(True, True, 0.7)
self.grPCM.plotItem.showGrid(True, True, 0.7)
self.maxFFT=0
self.maxPCM=0
self.ear = SWHear.SWHear(rate=44100,updatesPerSecond=20)
self.ear.stream_start()
def update(self):
if not self.ear.data is None and not self.ear.fft is None:
pcmMax=np.max(np.abs(self.ear.data))
if pcmMax>self.maxPCM:
self.maxPCM=pcmMax
self.grPCM.plotItem.setRange(yRange=[-pcmMax,pcmMax])
if np.max(self.ear.fft)>self.maxFFT:
self.maxFFT=np.max(np.abs(self.ear.fft))
#self.grFFT.plotItem.setRange(yRange=[0,self.maxFFT])
self.grFFT.plotItem.setRange(yRange=[0,1])
self.pbLevel.setValue(1000*pcmMax/self.maxPCM)
pen=pyqtgraph.mkPen(color='b')
self.grPCM.plot(self.ear.datax,self.ear.data,pen=pen,clear=True)
pen=pyqtgraph.mkPen(color='r')
self.grFFT.plot(self.ear.fftx,self.ear.fft/self.maxFFT,pen=pen,clear=True)
QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat
if __name__=="__main__":
app = QtGui.QApplication(sys.argv)
form = SoundApp()
form.show()
form.update() #start with something
Tuner = Freq_analysis()
for i in range(100):
Tuner.listen()
app.exec_()
print("DONE") so what I want to pointed is, the freq analyzer is had to be runned 1st and finishing it's recording and later the sound visualizer came in (so the sound visualizer window keeps loading whie the freq give it's results)
what can I do to make the both running in the same time??
Posts: 164
Threads: 22
Joined: Feb 2017
You have to use a QThread for your freq analyzer, then emit a signal to update the gui. For PyQt4 it would be something like this:
import sys
import time
from PyQt4 import QtGui, QtCore
class WorkerThread(QtCore.QObject):
updateFreq = QtCore.pyqtSignal(int)
def __init__(self):
super().__init__()
@QtCore.pyqtSlot()
def run(self):
freq = 0
while True:
freq += 1
self.updateFreq.emit(freq)
time.sleep(5)
class Main(QtGui.QMainWindow):
def __init__(self):
super().__init__()
self.worker = WorkerThread()
self.workerThread = QtCore.QThread() # Move the Worker object to the Thread object
self.workerThread.started.connect(self.worker.run) # Init worker run() at startup
self.worker.moveToThread(self.workerThread)
self.worker.updateFreq.connect(self.updateFreq) # Connect your signals/slots
self.workerThread.start()
def updateFreq(self, freq):
#self.ui.freqLabel.setText(str(freq) + " Hz")
print(freq)
if __name__== '__main__':
app = QtGui.QApplication([])
gui = Main()
sys.exit(app.exec_())
Posts: 18
Threads: 3
Joined: Jul 2018
Jul-16-2018, 01:59 PM
(This post was last modified: Jul-16-2018, 01:59 PM by mekha.)
(Jul-16-2018, 12:45 PM)Alfalfa Wrote: You have to use a QThread for your freq analyzer, then emit a signal to update the gui. For PyQt4 it would be something like this:
import sys
import time
from PyQt4 import QtGui, QtCore
class WorkerThread(QtCore.QObject):
updateFreq = QtCore.pyqtSignal(int)
def __init__(self):
super().__init__()
@QtCore.pyqtSlot()
def run(self):
freq = 0
while True:
freq += 1
self.updateFreq.emit(freq)
time.sleep(5)
class Main(QtGui.QMainWindow):
def __init__(self):
super().__init__()
self.worker = WorkerThread()
self.workerThread = QtCore.QThread() # Move the Worker object to the Thread object
self.workerThread.started.connect(self.worker.run) # Init worker run() at startup
self.worker.moveToThread(self.workerThread)
self.worker.updateFreq.connect(self.updateFreq) # Connect your signals/slots
self.workerThread.start()
def updateFreq(self, freq):
#self.ui.freqLabel.setText(str(freq) + " Hz")
print(freq)
if __name__== '__main__':
app = QtGui.QApplication([])
gui = Main()
sys.exit(app.exec_())
Ah thank you very much!
I'll try to run a test now
EDIT:
so I've try to run it to see what it does... so got an error (of course it'll but...)
Traceback (most recent call last):
File "C:/Users/user/Desktop/Python sound recog/qt_audio_monitor/TEST/QthreadFreq.py", line 35, in <module>
gui = Main()
File "C:/Users/user/Desktop/Python sound recog/qt_audio_monitor/TEST/QthreadFreq.py", line 21, in __init__
super().__init__()
TypeError: super() takes at least 1 argument (0 given) What's this super() do anyway? sorry if I asking you a lot
Posts: 164
Threads: 22
Joined: Feb 2017
Jul-16-2018, 04:35 PM
(This post was last modified: Jul-16-2018, 04:35 PM by Alfalfa.)
I forgot that python2 need arguments to init super. Simply replace it with:
super(ClassName, self).__init__()
so for the example above:
super(WorkerThread, self).__init__()
super(Main, self).__init__()
I don't know what it does exactly but it is mandatory. Btw, as you are developping a new app, maybe you should consider going for the lastest versions, as PyQt4 is quite old. You'll less likely need to port your code again in the future. If you need help to get started I've posted several examples for PyQt5 on gitlab: https://gitlab.com/users/william.belanger/snippets
Posts: 18
Threads: 3
Joined: Jul 2018
Jul-18-2018, 12:47 AM
(This post was last modified: Jul-18-2018, 12:47 AM by mekha.)
(Jul-16-2018, 04:35 PM)Alfalfa Wrote: I forgot that python2 need arguments to init super. Simply replace it with:
super(ClassName, self).__init__()
so for the example above:
super(WorkerThread, self).__init__()
super(Main, self).__init__()
I don't know what it does exactly but it is mandatory. Btw, as you are developping a new app, maybe you should consider going for the lastest versions, as PyQt4 is quite old. You'll less likely need to port your code again in the future. If you need help to get started I've posted several examples for PyQt5 on gitlab: https://gitlab.com/users/william.belanger/snippets
Thank you very much!
But if I porting it right now, I guess no... because I need to get this app right 1st then I'll consider to porting it when all done. My deadline is getting closer and the app still unable to give what I need
|