Skip to content

Commit

Permalink
added feature of Frequency Vs Energy Plot of real time audio (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
Davda-James authored Jul 13, 2024
1 parent 6027a29 commit b523bf2
Showing 1 changed file with 152 additions and 0 deletions.
152 changes: 152 additions & 0 deletions Frequency-Energy-plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import PySimpleGUI as sg
import pyaudio
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import soundfile as sf
import scipy.fft
import matplotlib.pyplot as plt

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

# pysimpleGUI INIT:
AppFont = "Helvetica"
sg.theme("DarkBlue3")

layout = [
[
sg.Graph(
canvas_size=(600, 600),
graph_bottom_left=(-2, -2),
graph_top_right=(102, 102),
background_color="#809AB6",
key="graph",
tooltip="Frequency vs Energy graph" # Tooltip added
)
],
[sg.Text("Progress:", text_color='white', font=('Helvetica', 15, 'bold')), sg.ProgressBar(4000, orientation="h", size=(20, 20), key="-PROG-")],
[
sg.Button("Listen", font=AppFont, tooltip="Start listening"),
sg.Button("Pause", font=AppFont, disabled=True, tooltip="Pause listening"),
sg.Button("Resume", font=AppFont, disabled=True, tooltip="Resume listening"),
sg.Button("Stop", font=AppFont, disabled=True, tooltip="Stop listening"),
sg.Button("Save", font=AppFont, disabled=True, tooltip="Save the plot"),
sg.Button("Exit", font=AppFont, tooltip="Exit the application"),
],
]

_VARS["window"] = sg.Window("Mic to Frequency vs Energy plot", layout, finalize=True)
graph = _VARS["window"]["graph"]

# 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
pAud = pyaudio.PyAudio()

# FUNCTIONS:

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

def stop():
if _VARS["stream"]:
_VARS["stream"].stop_stream()
_VARS["stream"].close()
_VARS["window"]["-PROG-"].update(0)
_VARS["window"]["Stop"].Update(disabled=True)
_VARS["window"]["Listen"].Update(disabled=False)

def pause():
if _VARS["stream"].is_active():
_VARS["stream"].stop_stream()
_VARS["window"]["Pause"].Update(disabled=True)
_VARS["window"]["Resume"].Update(disabled=False)

def resume():
if not _VARS["stream"].is_active():
_VARS["stream"].start_stream()
_VARS["window"]["Pause"].Update(disabled=False)
_VARS["window"]["Resume"].Update(disabled=True)

def save():
# Ask the user for a directory to save the image file
folder = sg.popup_get_folder('Please select a directory to save the files')
if folder:
# Save the figure as an image file
fig.savefig(f'{folder}/output.png')
sg.popup('Success', f'Image saved as {folder}/output.png')
# Save the recorded audio data to a file
sf.write(f'{folder}/output.wav', _VARS["audioBuffer"], RATE)
sg.popup('Success', f'Audio saved as {folder}/output.wav')

def callback(in_data, frame_count, time_info, status):
_VARS["audioData"] = np.frombuffer(in_data, dtype=np.int16)
_VARS["audioBuffer"] = np.append(_VARS["audioBuffer"], _VARS["audioData"])
return (in_data, pyaudio.paContinue)

def listen():
_VARS["window"]["Stop"].Update(disabled=False)
_VARS["window"]["Listen"].Update(disabled=True)
_VARS["stream"] = pAud.open(
format=pyaudio.paInt16,
channels=1,
rate=RATE,
input=True,
frames_per_buffer=CHUNK,
stream_callback=callback,
)
_VARS["stream"].start_stream()

# INIT:
fig, ax = plt.subplots()
fig_agg = draw_figure(graph.TKCanvas, fig)

# MAIN LOOP
while True:
event, values = _VARS["window"].read(timeout=TIMEOUT)
if event == "Exit":
stop()
pAud.terminate()
break
# for handling the closing of application
if event == sg.WIN_CLOSED :
_VARS["stream"].stop_stream()
_VARS["stream"].close()
pAud.terminate()
break
if event == "Listen":
listen()
_VARS["window"]["Save"].Update(disabled=False)
if event == "Pause":
pause()
if event == "Resume":
resume()
if event == "Stop":
stop()
if event == "Save":
save()

elif _VARS["audioData"].size != 0:
_VARS["window"]["-PROG-"].update(np.amax(_VARS["audioData"]))
yy = scipy.fft.fft(_VARS["audioData"])
xx = np.linspace(0.0, RATE / 2, CHUNK // 2)
ax.clear()

# Calculating the energy
energy = np.abs(yy[:CHUNK // 2]) ** 2

# Plot frequency vs energy
ax.plot(xx, energy, label='Frequency vs Energy')

# Update axis labels
ax.set_ylabel("Energy")
ax.set_xlabel("Frequency [Hz]")

ax.grid(True) # Enable gridlines
ax.legend() # Add a legend
fig_agg.draw() # redraw the figure

0 comments on commit b523bf2

Please sign in to comment.