Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Spectogram.py #82

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 65 additions & 74 deletions Spectogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import scipy.signal
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import threading
import queue

""" RealTime Audio Spectrogram plot """
# Global variables
_VARS = {"window": None, "stream": None, "audioData": np.array([])}
audio_buffer = queue.Queue(maxsize=10) # Buffer for audio data
stop_event = threading.Event() # Event to signal stopping of the audio stream

# VARS CONSTS:
_VARS = {"window": False, "stream": False, "audioData": np.array([])}

# pysimpleGUI INIT:
# PySimpleGUI initialization
AppFont = "Any 16"
sg.theme("DarkBlue3")
layout = [
Expand All @@ -30,54 +32,35 @@
sg.Button("Exit", font=AppFont),
],
]
_VARS["window"] = sg.Window(
"Mic to spectrogram plot + Max Level", layout, finalize=True
)

graph = _VARS["window"]["graph"]
_VARS["window"] = sg.Window("Mic to spectrogram plot + Max Level", layout, finalize=True)

# INIT vars:
CHUNK = 1024 # Samples: 1024, 512, 256, 128
RATE = 44100 # Equivalent to Human Hearing at 40 kHz
INTERVAL = 1 # Sampling Interval in Seconds -> Interval to listen
TIMEOUT = 10 # In ms for the event loop
# PyAudio initialization
pAud = pyaudio.PyAudio()
CHUNK = 1024
RATE = 44100
INTERVAL = 1
TIMEOUT = 100 # Adjusted timeout value

try:
pAud.get_device_info_by_index(0)
except pyaudio.CoreError as e:
print(f"Error initializing PyAudio: {e}")
pAud = None
# FUNCTIONS:


# PySimpleGUI plots:
def draw_figure(canvas, figure):
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
figure_canvas_agg.draw()
figure_canvas_agg.get_tk_widget().pack(side="top", fill="both", expand=1)
return figure_canvas_agg


# pyaudio stream:
def stop():
if _VARS["stream"]:
if _VARS["stream"] is not None and _VARS["stream"].is_active():
stop_event.set() # Signal the audio processing thread to stop
_VARS["stream"].stop_stream()
_VARS["stream"].close()
_VARS["stream"] = None
_VARS["window"]["-PROG-"].update(0)
_VARS["window"]["Stop"].Update(disabled=True)
_VARS["window"]["Listen"].Update(disabled=False)
_VARS["window"]["Stop"].update(disabled=True)
_VARS["window"]["Listen"].update(disabled=False)
stop_event.clear() # Reset the event for the next use


# callback:
def callback(in_data, frame_count, time_info, status):
_VARS["audioData"] = np.frombuffer(in_data, dtype=np.int16)
if stop_event.is_set():
return (in_data, pyaudio.paComplete)
audio_buffer.put(np.frombuffer(in_data, dtype=np.int16))
return (in_data, pyaudio.paContinue)


def listen():
_VARS["window"]["Stop"].Update(disabled=False)
_VARS["window"]["Listen"].Update(disabled=True)
_VARS["window"]["Stop"].update(disabled=False)
_VARS["window"]["Listen"].update(disabled=True)
_VARS["stream"] = pAud.open(
format=pyaudio.paInt16,
channels=1,
Expand All @@ -88,36 +71,44 @@ def listen():
)
_VARS["stream"].start_stream()


# INIT:
fig, ax = plt.subplots() # create a figure and an axis object
fig_agg = draw_figure(graph.TKCanvas, fig) # draw the figure on the graph

# MAIN LOOP
while True:
event, values = _VARS["window"].read(timeout=TIMEOUT)
if event == sg.WIN_CLOSED or event == "Exit":
stop()
pAud.terminate()
break
if event == "Listen":
listen()
if event == "Stop":
stop()

# Along with the global audioData variable, this
# bit updates the spectrogram plot

elif _VARS["audioData"].size != 0:
# Update volume meter
_VARS["window"]["-PROG-"].update(np.amax(_VARS["audioData"]))
# Compute spectrogram
f, t, Sxx = scipy.signal.spectrogram(_VARS["audioData"], fs=RATE)
# Plot spectrogram
ax.clear() # clear the previous plot
ax.pcolormesh(
t, f, Sxx, shading="gouraud"
) # plot the spectrogram as a colored mesh
ax.set_ylabel("Frequency [Hz]") # set the y-axis label
ax.set_xlabel("Time [sec]") # set the x-axis label
fig_agg.draw() # redraw the figure
def audio_processing(ax, fig_agg):
while not stop_event.is_set():
try:
audio_data = audio_buffer.get(timeout=1)
if audio_data.size != 0:
_VARS["window"]["-PROG-"].update(np.amax(audio_data))
f, t, Sxx = scipy.signal.spectrogram(audio_data, fs=RATE)
ax.clear()
ax.pcolormesh(t, f, Sxx, shading="gouraud")
ax.set_ylabel("Frequency [Hz]")
ax.set_xlabel("Time [sec]")
fig_agg.draw()
except queue.Empty:
continue

def main():
# Initialization
fig, ax = plt.subplots()
fig_agg = FigureCanvasTkAgg(fig, _VARS["window"]["graph"].TKCanvas)
fig_agg.draw()
fig_agg.get_tk_widget().pack(side="top", fill="both", expand=1)

# Multithreading for audio processing
audio_thread = threading.Thread(target=audio_processing, args=(ax, fig_agg))
audio_thread.daemon = True
audio_thread.start()

# Event loop
while True:
event, values = _VARS["window"].read(timeout=TIMEOUT)
if event == sg.WINDOW_CLOSED or event == "Exit":
stop()
pAud.terminate()
break
elif event == "Listen":
listen()
elif event == "Stop":
stop()

if __name__ == "__main__":
main()