From c41afbe547b8567dabf973c932463875516c6ec4 Mon Sep 17 00:00:00 2001 From: Priyaanshucodez <141406744+Priyaanshucodez@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:38:33 +0530 Subject: [PATCH 1/4] Update Intensity-vs-Frequency-and-time.py --- Intensity-vs-Frequency-and-time.py | 291 +++++++++++------------------ 1 file changed, 110 insertions(+), 181 deletions(-) diff --git a/Intensity-vs-Frequency-and-time.py b/Intensity-vs-Frequency-and-time.py index 1877d13..b85bd53 100644 --- a/Intensity-vs-Frequency-and-time.py +++ b/Intensity-vs-Frequency-and-time.py @@ -1,190 +1,119 @@ -import PySimpleGUI as sg +import kivy +from kivy.app import App +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.label import Label +from kivy.uix.button import Button +from kivy.uix.progressbar import ProgressBar +from kivy.clock import Clock +from kivy.graphics import Color, Rectangle +from kivy.core.window import Window import pyaudio import numpy as np -import scipy.fft -import matplotlib.pyplot as plt -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import subprocess -"""Realtime Sound Intensity vs Frequency heatmap""" +class SoundScapeApp(App): + def build(self): + self.stream = None + self.audioData = np.array([]) + self.current_visualizer_process = None -# VARS CONSTS: -_VARS = {"window": False, "stream": False, "audioData": np.array([]), "current_visualizer_process": None} - -# pysimpleGUI INIT: -AppFont = "Any 16" -sg.theme("DarkBlue3") + layout = BoxLayout(orientation='vertical', padding=20, spacing=20) + + self.graph = BoxLayout() + self.graph.canvas.add(Color(0.5, 0.5, 0.5, 1)) + self.graph.canvas.add(Rectangle(size=(500, 500))) -# Heatmap plot: -layout = [ - - [ - sg.Graph( - canvas_size=(500, 500), - graph_bottom_left=(-2, -2), - graph_top_right=(102, 102), - background_color="#809AB6", - key="graph", + self.progress_bar = ProgressBar(max=4000, size_hint=(1, None), height=20) + + btn_layout = BoxLayout(size_hint=(1, None), height=50) + self.listen_btn = Button(text="Listen", on_press=self.listen) + self.stop_btn = Button(text="Stop", on_press=self.stop, disabled=True) + self.exit_btn = Button(text="Exit", on_press=self.stop) + + btn_layout.add_widget(self.listen_btn) + btn_layout.add_widget(self.stop_btn) + btn_layout.add_widget(self.exit_btn) + + layout.add_widget(Label(text="Mic to Sound Intensity vs Frequency heatmap", font_size=24, size_hint=(1, 0.1))) + layout.add_widget(self.graph) + layout.add_widget(self.progress_bar) + layout.add_widget(btn_layout) + + Clock.schedule_interval(self.update, 0.1) + return layout + + def listen(self, instance): + self.stop_btn.disabled = False + self.listen_btn.disabled = True + + self.stream = pAud.open( + format=pyaudio.paInt16, + channels=1, + rate=RATE, + input=True, + frames_per_buffer=CHUNK, + stream_callback=self.callback, ) - ], - [sg.ProgressBar(4000, orientation="h", size=(20, 20), key="-PROG-")], - [ - sg.Button("Listen", font=AppFont), - sg.Button("Stop", font=AppFont, disabled=True), - sg.Button("Exit", font=AppFont), - ], -] -_VARS["window"] = sg.Window("Mic to Sound Intensity vs Frequency heatmap", 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() - -# PySimpleGUI plots: -def drawHeatMapWithLabels(intensity_data): - graph.erase() # Clear previous heatmap - rows, cols = intensity_data.shape - - # Draw labels for frequency axis - for row in range(rows): - graph.DrawText(f"{row * (RATE / 2) / rows:.0f} Hz", (105, 100 - row * 100 / rows)) - - # Draw labels for time axis - for col in range(cols): - graph.DrawText(f"{col * INTERVAL:.1f} sec", (col * 100 / cols, -5)) - - # Draw heatmap - for row in range(rows): - for col in range(cols): - intensity = intensity_data[row, col] - color = getHeatMapColor(intensity) - x1 = col * 100 / cols - y1 = 100 - (row + 1) * 100 / rows - x2 = x1 + 100 / cols - y2 = y1 + 100 / rows - graph.DrawRectangle((x1, y1), (x2, y2), line_color=color, fill_color=color) - -# pyaudio stream: -def stop(): - if _VARS["stream"]: - _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) - -# callback: -def callback(in_data, frame_count, time_info, status): - _VARS["audioData"] = 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["stream"] = pAud.open( - format=pyaudio.paInt16, - channels=1, - rate=RATE, - input=True, - frames_per_buffer=CHUNK, - stream_callback=callback, - ) - _VARS["stream"].start_stream() - -def close_current_visualizer(): - if _VARS["current_visualizer_process"] and _VARS["current_visualizer_process"].poll() is None: - _VARS["current_visualizer_process"].kill() - -# INIT: - -def initHeatMap(graph, rate, interval, rows, cols): - - # Clear previous drawing - - graph.erase() - - #Initial setup for the heatmap - - for row in range(rows): - - graph.DrawText(f"{row * (rate / 2) / rows:.0f} Hz", (105, 100 - row * 100 / rows)) - - - - # Draw labels for time axis - - for col in range(cols): - - graph.DrawText(f"{col * interval:.1f} sec", (col * 100 / cols, -5)) - - - -# Call the initHeatMap function to initialize the heatmap - -rows = 10 # Number of rows in the heatmap - -cols = 10 # Number of columns in the heatmap - -initHeatMap(graph, RATE, INTERVAL, rows, cols) - -# Function to get heatmap color -def getHeatMapColor(intensity, threshold=0.0, cmap=None): - # Default color map - if cmap is None: - cmap = ["#0000ff", "#00ff00", "#ffff00", "#ff0000"] # Blue to Red gradient - - # Determining color based on intensity and thresholds - if np.isnan(intensity): - return "#808080" # Gray color for NaN values - else: - # Normalizing intensity to fit within the colormap range - intensity_norm = np.log1p(intensity) / 20 # Logarithmic scale for better visualization + self.stream.start_stream() + + def stop(self, instance): + if self.stream: + self.stream.stop_stream() + self.stream.close() + self.stream = None + self.progress_bar.value = 0 + self.stop_btn.disabled = True + self.listen_btn.disabled = False + if self.current_visualizer_process: + self.current_visualizer_process.kill() + self.current_visualizer_process = None + App.get_running_app().stop() + + def callback(self, in_data, frame_count, time_info, status): + self.audioData = np.frombuffer(in_data, dtype=np.int16) + return (in_data, pyaudio.paContinue) + + def update(self, dt): + if self.audioData.size != 0: + self.progress_bar.value = np.amax(self.audioData) + intensity_data = self.compute_intensity_data(self.audioData) + self.draw_heatmap(intensity_data) + + def compute_intensity_data(self, audio_data, window_size=1024, hop_size=512): + num_frames = len(audio_data) // hop_size + intensity_data = np.zeros((num_frames, window_size // 2)) + + for i in range(num_frames): + frame = audio_data[i * hop_size: (i + 1) * hop_size] + intensity_data[i, :] = np.abs(np.fft.fft(frame)[:window_size // 2]) + return intensity_data + + def draw_heatmap(self, intensity_data): + self.graph.canvas.clear() + rows, cols = intensity_data.shape + for row in range(rows): + for col in range(cols): + intensity = intensity_data[row, col] + color = self.get_heatmap_color(intensity) + x1 = col * 500 / cols + y1 = 500 - (row + 1) * 500 / rows + x2 = x1 + 500 / cols + y2 = y1 + 500 / rows + with self.graph.canvas: + Color(*color) + Rectangle(pos=(x1, y1), size=(x2 - x1, y2 - y1)) + + def get_heatmap_color(self, intensity, threshold=0.0): + cmap = [(0, 0, 1, 1), (0, 1, 0, 1), (1, 1, 0, 1), (1, 0, 0, 1)] + if np.isnan(intensity): + return (0.5, 0.5, 0.5, 1) + intensity_norm = np.log1p(intensity) / 20 color_index = min(int(intensity_norm * len(cmap)), len(cmap) - 1) return cmap[color_index] - -def compute_intensity_data(audio_data, window_size=1024, hop_size=512): - num_frames = len(audio_data) // hop_size - intensity_data = np.zeros((num_frames, window_size // 2)) - - for i in range(num_frames): - frame = audio_data[i * hop_size: (i + 1) * hop_size] - intensity_data[i, :] = np.abs(np.fft.fft(frame)[:window_size // 2]) # Magnitude spectrum - return intensity_data - -# MAIN LOOP -while True: - event, values = _VARS["window"].read(timeout=TIMEOUT) - if event in (sg.WIN_CLOSED, "Exit"): - close_current_visualizer() - 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() - if event == "Stop": - stop() - - # Along with the global audioData variable, this - # bit updates the waveform plot - elif _VARS["audioData"].size != 0: - # Update volume meter - _VARS["window"]["-PROG-"].update(np.amax(_VARS["audioData"])) - - # Compute intensity data for heatmap - intensity_data = compute_intensity_data(_VARS["audioData"]) - - # Draw heatmap - drawHeatMapWithLabels(intensity_data) - -_VARS["window"].close() +if __name__=='__main__': + CHUNK=1024 + RATE=44100 + INTERVAL=1 + TIMEOUT=10 + pAud = pyaudio.PyAudio() + SoundScapeApp().run() From 388837d830d0d7a20de9f8e5c36e35d8ad5e1983 Mon Sep 17 00:00:00 2001 From: Priyaanshucodez <141406744+Priyaanshucodez@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:39:24 +0530 Subject: [PATCH 2/4] Update Spectrogram.py --- Spectrogram.py | 248 +++++++++++++++++++++++-------------------------- 1 file changed, 115 insertions(+), 133 deletions(-) diff --git a/Spectrogram.py b/Spectrogram.py index 59744f5..39e8f57 100644 --- a/Spectrogram.py +++ b/Spectrogram.py @@ -1,91 +1,37 @@ -import PySimpleGUI as sg import pyaudio import numpy as np import scipy.signal import matplotlib.pyplot as plt -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg -import subprocess - - - -""" RealTime Audio Spectrogram plot """ - -# VARS CONSTS: -_VARS = {"window": False, "stream": False, "audioData": np.array([]), "current_visualizer_process": None} - -# pysimpleGUI INIT: -AppFont = "Any 16" -sg.theme("DarkBlue3") - -menu_layout = [ - ['Run Visualizers', ['Amplitude-Frequency-Visualizer', 'Waveform', 'Spectrogram', 'Intensity-vs-Frequency-and-time']], -] - -layout = [ - [sg.Menu(menu_layout)], - [ - sg.Graph( - canvas_size=(500, 500), - graph_bottom_left=(-2, -2), - graph_top_right=(102, 102), - background_color="#809AB6", - key="graph", - ) - ], - [sg.ProgressBar(4000, orientation="h", size=(20, 20), key="-PROG-")], - [ - sg.Button("Listen", font=AppFont), - sg.Button("Stop", font=AppFont, disabled=True), - sg.Button("Save", font=AppFont, disabled=True), - sg.Button("Exit", font=AppFont), - ], -] -_VARS["window"] = sg.Window("Mic to spectrogram plot + Max Level", 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 +from kivy.app import App +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.button import Button +from kivy.uix.label import Label +from kivy.uix.progressbar import ProgressBar +from kivy.uix.popup import Popup +from kivy.graphics.texture import Texture +from kivy.uix.image import Image +from kivy.clock import Clock +from kivy.uix.filechooser import FileChooserIconView +import io + +# Global Variables +_VARS = {"stream": None, "audioData": np.array([])} +CHUNK = 1024 +RATE = 44100 pAud = pyaudio.PyAudio() +# Check if audio input is available try: pAud.get_device_info_by_index(0) -except pyaudio.CoreError as e: +except pyaudio.PyAudioError 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"]: - _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"]["Save"].Update(disabled=True) - -# callback: def callback(in_data, frame_count, time_info, status): _VARS["audioData"] = 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"]["Save"].Update(disabled=False) _VARS["stream"] = pAud.open( format=pyaudio.paInt16, channels=1, @@ -96,74 +42,110 @@ def listen(): ) _VARS["stream"].start_stream() -def close_current_visualizer(): - if _VARS["current_visualizer_process"] and _VARS["current_visualizer_process"].poll() is None: - _VARS["current_visualizer_process"].kill() +def stop(): + if _VARS["stream"]: + _VARS["stream"].stop_stream() + _VARS["stream"].close() + _VARS["stream"] = None + +class SpectrogramApp(App): + def build(self): + self.title = "Mic to Spectrogram Plot + Max Level" + self.layout = BoxLayout(orientation='vertical') -def save_spectrogram(): - file_path = sg.popup_get_file('Save as', save_as=True, no_window=True, file_types=(("PNG Files", "*.png"), ("All Files", "*.*"))) - if file_path: - fig.savefig(file_path) - sg.popup("File saved!", title="Success") + self.image = Image() + self.layout.add_widget(self.image) -# 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 + self.progress = ProgressBar(max=4000) + self.layout.add_widget(self.progress) + self.button_layout = BoxLayout(size_hint_y=0.2) + + self.listen_button = Button(text="Listen") + self.listen_button.bind(on_press=self.on_listen) + self.button_layout.add_widget(self.listen_button) -# MAIN LOOP -while True: - event, values = _VARS["window"].read(timeout=TIMEOUT) - if event in (sg.WIN_CLOSED, "Exit"): - close_current_visualizer() - stop() - pAud.terminate() - break + self.stop_button = Button(text="Stop", disabled=True) + self.stop_button.bind(on_press=self.on_stop) + self.button_layout.add_widget(self.stop_button) - if event == "Listen": + self.save_button = Button(text="Save", disabled=True) + self.save_button.bind(on_press=self.on_save) + self.button_layout.add_widget(self.save_button) + + self.exit_button = Button(text="Exit") + self.exit_button.bind(on_press=self.on_exit) + self.button_layout.add_widget(self.exit_button) + + self.layout.add_widget(self.button_layout) + self.event = None + + return self.layout + + def on_listen(self, instance): listen() + self.listen_button.disabled = True + self.stop_button.disabled = False + self.save_button.disabled = False + self.event = Clock.schedule_interval(self.update, 0.1) - if event == "Stop": + def on_stop(self, instance): stop() + self.listen_button.disabled = False + self.stop_button.disabled = True + self.save_button.disabled = True + if self.event: + self.event.cancel() + self.event = None + + def on_save(self, instance): + content = BoxLayout(orientation='vertical') + filechooser = FileChooserIconView() + content.add_widget(filechooser) + save_button = Button(text="Save", size_hint_y=0.2) + content.add_widget(save_button) + popup = Popup(title="Save as", content=content, size_hint=(0.9, 0.9)) + + def save(instance): + if filechooser.selection: + file_path = filechooser.selection[0] + self.save_figure(file_path) + popup.dismiss() + + save_button.bind(on_press=save) + popup.open() + + def on_exit(self, instance): + stop() + pAud.terminate() + App.get_running_app().stop() - if event == "Save": - save_spectrogram() - - if event == 'Amplitude-Frequency-Visualizer': - close_current_visualizer() - _VARS["current_visualizer_process"] = subprocess.Popen(['python', 'Amplitude-Frequency-Visualizer.py']) - _VARS["window"].close() - break - if event == 'Waveform': - close_current_visualizer() - _VARS["current_visualizer_process"] = subprocess.Popen(['python', 'Waveform.py']) - _VARS["window"].close() - break - if event == 'Spectogram': - close_current_visualizer() - _VARS["current_visualizer_process"] = subprocess.Popen(['python', 'Spectogram.py']) - _VARS["window"].close() - break - if event == 'Intensity-vs-Frequency-and-time': - close_current_visualizer() - _VARS["current_visualizer_process"] = subprocess.Popen(['python', 'Intensity-vs-Frequency-and-time.py']) - _VARS["window"].close() - break - - # 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 + def save_figure(self, file_path): + fig, ax = plt.subplots() 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 - -_VARS["window"].close() + ax.pcolormesh(t, f, Sxx, shading="gouraud") + ax.set_ylabel("Frequency [Hz]") + ax.set_xlabel("Time [sec]") + plt.savefig(file_path) + plt.close(fig) + + def update(self, dt): + if _VARS["audioData"].size != 0: + self.progress.value = np.amax(_VARS["audioData"]) + f, t, Sxx = scipy.signal.spectrogram(_VARS["audioData"], fs=RATE) + fig, ax = plt.subplots() + ax.pcolormesh(t, f, Sxx, shading="gouraud") + ax.set_ylabel("Frequency [Hz]") + ax.set_xlabel("Time [sec]") + buf = io.BytesIO() + fig.savefig(buf, format='png') + buf.seek(0) + img = plt.imread(buf, format='png') + buf.close() + texture = Texture.create(size=(img.shape[1], img.shape[0]), colorfmt='rgb') + texture.blit_buffer(img.tobytes(), colorfmt='rgb', bufferfmt='ubyte') + self.image.texture = texture + plt.close(fig) + +if __name__ == "__main__": + SpectrogramApp().run() From 849cd42a592f3037de2168afe07b7ecea7fa6647 Mon Sep 17 00:00:00 2001 From: Priyaanshucodez <141406744+Priyaanshucodez@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:40:24 +0530 Subject: [PATCH 3/4] Update Waveform.py --- Waveform.py | 241 ++++++++++++++++++++++++---------------------------- 1 file changed, 110 insertions(+), 131 deletions(-) diff --git a/Waveform.py b/Waveform.py index 1ee4ebc..ec20770 100644 --- a/Waveform.py +++ b/Waveform.py @@ -1,135 +1,114 @@ -import PySimpleGUI as sg -import pyaudio import numpy as np -import subprocess - -""" RealTime Audio Waveform plot """ -# VARS CONSTS: -_VARS = {"window": False, "stream": False, "audioData": np.array([]), "current_visualizer_process": None} - -# PySimpleGUI INIT: -AppFont = "Any 16" -sg.theme("DarkBlue3") - - -layout = [ - [ - sg.Graph( - canvas_size=(500, 500), - graph_bottom_left=(-2, -2), - graph_top_right=(102, 102), - background_color="#809AB6", - key="graph", - ) - ], - [sg.ProgressBar(4000, orientation="h", size=(20, 20), key="-PROG-")], - [ - sg.Button("Listen", font=AppFont), - sg.Button("Stop", font=AppFont, disabled=True), - sg.Button("Exit", font=AppFont), - ], -] -_VARS["window"] = sg.Window("Mic to waveform plot + Max Level", 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() - -try: - pAud.get_device_info_by_index(0) -except pyaudio.CoreError as e: - print(f"Error initializing PyAudio: {e}") - pAud = None - -# PySimpleGUI plots: -def drawAxis(dataRangeMin=0, dataRangeMax=100): - - # Y Axis - - graph.DrawLine((0, 50), (100, 50)) - - # X Axis - - graph.DrawLine((0, dataRangeMin), (0, dataRangeMax)) - -# pyaudio stream: -def stop(): - if _VARS["stream"]: - _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) - -# callback: -def callback(in_data, frame_count, time_info, status): - _VARS["audioData"] = 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["stream"] = pAud.open( - format=pyaudio.paInt16, - channels=1, - rate=RATE, - input=True, - frames_per_buffer=CHUNK, - stream_callback=callback, - ) - _VARS["stream"].start_stream() - -def close_current_visualizer(): - if _VARS["current_visualizer_process"] and _VARS["current_visualizer_process"].poll() is None: - _VARS["current_visualizer_process"].terminate() - _VARS["current_visualizer_process"].wait() - _VARS["current_visualizer_process"] = None - -# INIT: -drawAxis() - -# MAIN LOOP -while True: +import pyaudio +from kivy.app import App +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.button import Button +from kivy.uix.widget import Widget +from kivy.clock import Clock +from kivy.graphics import Line, Color + +# Constants +CHUNK = 1024 +RATE = 44100 + +class WaveformWidget(Widget): + def __init__(self, **kwargs): + super(WaveformWidget, self).__init__(**kwargs) + self.points = [] + + def update(self, data): + self.canvas.clear() + with self.canvas: + Color(1, 0, 0) + self.points = [] + for i in range(len(data)): + self.points.append((self.width * i / len(data), self.height / 2 + data[i] / 32768 * self.height / 2)) + Line(points=self.points) + +class AudioVisualizerApp(App): - event, values = _VARS["window"].read(timeout=TIMEOUT) - if event in (sg.WIN_CLOSED, "Exit"): - close_current_visualizer() - stop() - pAud.terminate() - break - - if event == "Listen": - listen() - - if event == "Stop": - stop() - - - # Along with the global audioData variable, this bit updates the waveform plot - elif _VARS["audioData"].size != 0: - # Update volume meter - _VARS["window"]["-PROG-"].update(np.amax(_VARS["audioData"])) - # Redraw plot - graph.erase() - drawAxis() - + def build(self): + # Initialize PyAudio + self.pAud = pyaudio.PyAudio() + try: + self.pAud.get_device_info_by_index(0) + except pyaudio.PyAudioError as e: + print(f"Error initializing PyAudio: {e}") + self.pAud = None - # Here we go through the points in the audioData object and draw them - - # Note that we are rescaling ( dividing by 100 ) and centering (+50) - - # try different values to get a feel for what they do. - for x in range(CHUNK): - graph.DrawCircle( - (x, (_VARS["audioData"][x] / 100) + 50), - 0.4, - line_color="blue", - fill_color="blue", - ) + # Main layout + self.layout = BoxLayout(orientation='vertical', padding=10, spacing=10) + + # Waveform widget + self.waveform = WaveformWidget() + + # Buttons + self.listen_button = Button(text='Listen', size_hint=(None, None), size=(100, 50)) + self.listen_button.bind(on_press=self.listen) + + self.stop_button = Button(text='Stop', size_hint=(None, None), size=(100, 50), disabled=True) + self.stop_button.bind(on_press=self.stop) + + self.exit_button = Button(text='Exit', size_hint=(None, None), size=(100, 50)) + self.exit_button.bind(on_press=self.close_app) + + self.button_layout = BoxLayout(size_hint=(1, None), height=50, spacing=10) + self.button_layout.add_widget(self.listen_button) + self.button_layout.add_widget(self.stop_button) + self.button_layout.add_widget(self.exit_button) + + self.layout.add_widget(self.waveform) + self.layout.add_widget(self.button_layout) + + Clock.schedule_interval(self.update_plot, 1.0 / 30.0) # Update plot every 1/30th of a second + + return self.layout + + def update_plot(self, dt): + if hasattr(self, 'audioData') and self.audioData.size != 0: + self.waveform.update(self.audioData) + + def listen(self, instance): + self.stop_button.disabled = False + self.listen_button.disabled = True + if self.pAud: + try: + self.stream = self.pAud.open( + format=pyaudio.paInt16, + channels=1, + rate=RATE, + input=True, + frames_per_buffer=CHUNK, + stream_callback=self.callback, + ) + self.stream.start_stream() + except pyaudio.PyAudioError as e: + print(f"Error opening stream: {e}") + self.listen_button.disabled = False + self.stop_button.disabled = True + + def stop(self, instance=None): + if hasattr(self, 'stream'): + self.stream.stop_stream() + self.stream.close() + del self.stream + self.stop_button.disabled = True + self.listen_button.disabled = False + + def callback(self, in_data, frame_count, time_info, status): + self.audioData = np.frombuffer(in_data, dtype=np.int16) + return (in_data, pyaudio.paContinue) + + def close_app(self, instance): + self.stop() + if self.pAud: + self.pAud.terminate() + App.get_running_app().stop() + + def run_visualizer(self, visualizer): + self.stop() + subprocess.Popen(['python', visualizer]) + self.close_app(None) -_VARS["window"].close() +if __name__ == '__main__': + AudioVisualizerApp().run() From 1d91611a543e65b9769e80f911f26dcb8493fe6b Mon Sep 17 00:00:00 2001 From: Priyaanshucodez <141406744+Priyaanshucodez@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:50:21 +0530 Subject: [PATCH 4/4] Update mainLanding.py --- mainLanding.py | 179 ++++++++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 76 deletions(-) diff --git a/mainLanding.py b/mainLanding.py index 6b2e9cf..e9792d8 100644 --- a/mainLanding.py +++ b/mainLanding.py @@ -1,79 +1,106 @@ -import PySimpleGUI as sg +from kivy.app import App +from kivy.uix.label import Label +from kivy.uix.button import Button +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.textinput import TextInput +from kivy.uix.popup import Popup +from kivy.clock import Clock +from kivy.utils import get_color_from_hex import subprocess -import os - -# Create the layout for the landing page -AppFont = "Helvetica 16" - -# Function to create the main layout -def create_layout(): - return [ - [sg.Text("Welcome to SoundScape", font=("Helvetica", 24), justification="center", pad=(0, 20), expand_x=True)], - [sg.Text("Explore various audio visualizers", font=("Helvetica", 14), justification="center", pad=(0, 10), expand_x=True)], - [sg.Multiline("SoundScape is an innovative application designed to transform audio data into stunning visualizations. " - "Choose from a variety of visualizers to unleash the power of audio visualizations!.", - font=("Helvetica", 14), justification="center", size=(60, 2), no_scrollbar=True, disabled=True, pad=(20, 20), - background_color="#e1f5fe", text_color="#006064", expand_x=True, expand_y=True)], - [sg.Button("Amplitude-Frequency Visualizer", pad=(10, 10), key="Amplitude-Frequency Visualizer"), - sg.Button("Waveform", pad=(10, 10), key="Waveform"), - sg.Button("Spectrogram", pad=(10, 10), key="Spectrogram"), - sg.Button("Intensity vs Frequency and Time", pad=(10, 10), key="Intensity vs Frequency and Time")], - [sg.Button("Change Theme", pad=(10, 20), key="Change Theme", button_color=("white", "green"))], - [sg.Button("Exit", size=(80,2), pad=(10, 10), key="Exit", button_color=("white", "red"), font=("Helvetica", 12), tooltip="Exit the application")], - - ] - -# Create the main window with the initial layout -layout = create_layout() -window = sg.Window("Welcome to SoundScape ", layout, finalize=True, element_justification="center", resizable=False, size=(800, 600)) - -def close_current_visualizer(process): - if process and process.poll() is None: - process.kill() - process.wait() - -# new function made for changing the theme -def change_theme(): - print("Changing theme...") - current_theme = sg.theme_list() - current_theme_index = current_theme.index(sg.theme()) - next_theme_index = (current_theme_index + 1) % len(current_theme) - sg.theme(current_theme[next_theme_index]) - - global window - layout = create_layout() # layout chanfing - window.close() - window = sg.Window("Welcome to SoundScape ", layout, finalize=True, element_justification="center", resizable=False, size=(800, 600)) - - print("Theme changed to:", current_theme[next_theme_index]) - -# Main loop -current_visualizer_process = None -while True: - event, values = window.read() - - if event in (sg.WIN_CLOSED, "Exit"): - close_current_visualizer(current_visualizer_process) - break - - if event == "Change Theme": - change_theme() - - visualizer_scripts = { - "Amplitude-Frequency Visualizer": "Amplitude-Frequency-Visualizer.py", - "Waveform": "Waveform.py", - "Spectrogram": "Spectogram.py", - "Intensity vs Frequency and Time": "Intensity-vs-Frequency-and-Time.py" - } - - if event in visualizer_scripts: - script_path = visualizer_scripts[event] - if os.path.exists(script_path): - close_current_visualizer(current_visualizer_process) - current_visualizer_process = subprocess.Popen(['python', script_path]) - window.close() - break +import os + +class SoundScapeApp(App): + def build(self): + self.current_visualizer_process = None + + # Define the initial layout + layout = BoxLayout(orientation='vertical', padding=20, spacing=20) + + title = Label(text="Welcome to SoundScape", font_size=24, size_hint=(1, 0.2)) + subtitle = Label(text="Explore various audio visualizers", font_size=18, size_hint=(1, 0.1)) + + description = TextInput( + text=("SoundScape is an innovative application designed to transform audio data into stunning visualizations. " + "Choose from a variety of visualizers to unleash the power of audio visualizations!"), + readonly=True, + background_color=get_color_from_hex("#e1f5fe"), + foreground_color=get_color_from_hex("#006064"), + font_size=16, + size_hint=(1, 0.3), + ) + + button_layout = BoxLayout(orientation='horizontal', size_hint=(1, 0.2), spacing=10) + button_layout.add_widget(Button(text="Amplitude-Frequency Visualizer", on_press=self.launch_visualizer)) + button_layout.add_widget(Button(text="Waveform", on_press=self.launch_visualizer)) + button_layout.add_widget(Button(text="Spectrogram", on_press=self.launch_visualizer)) + button_layout.add_widget(Button(text="Intensity vs Frequency and Time", on_press=self.launch_visualizer)) + + theme_button = Button(text="Change Theme", size_hint=(1, 0.1), background_color=(0, 1, 0, 1)) + theme_button.bind(on_press=self.change_theme) + + exit_button = Button(text="Exit", size_hint=(1, 0.1), background_color=(1, 0, 0, 1)) + exit_button.bind(on_press=self.stop) + + layout.add_widget(title) + layout.add_widget(subtitle) + layout.add_widget(description) + layout.add_widget(button_layout) + layout.add_widget(theme_button) + layout.add_widget(exit_button) + + self.layout = layout + self.theme_index = 0 + return layout + + def close_current_visualizer(self): + if self.current_visualizer_process and self.current_visualizer_process.poll() is None: + self.current_visualizer_process.kill() + self.current_visualizer_process.wait() + + def change_theme(self, instance): + themes = [ + {"bg_color": [1, 1, 1, 1], "fg_color": [0, 0, 0, 1]}, # Light theme + {"bg_color": [0, 0, 0, 1], "fg_color": [1, 1, 1, 1]}, # Dark theme + ] + self.theme_index = (self.theme_index + 1) % len(themes) + theme = themes[self.theme_index] + + self.layout.canvas.before.clear() + with self.layout.canvas.before: + from kivy.graphics import Color, Rectangle + Color(*theme["bg_color"]) + self.bg_rect = Rectangle(size=self.layout.size, pos=self.layout.pos) + self.layout.bind(size=self._update_rect, pos=self._update_rect) + + for child in self.layout.children: + if isinstance(child, Label): + child.color = theme["fg_color"] + if isinstance(child, Button): + child.background_color = theme["bg_color"] + child.color = theme["fg_color"] + + def _update_rect(self, instance, value): + self.bg_rect.pos = instance.pos + self.bg_rect.size = instance.size + + def launch_visualizer(self, instance): + visualizer_scripts = { + "Amplitude-Frequency Visualizer": "Amplitude-Frequency-Visualizer.py", + "Waveform": "Waveform.py", + "Spectrogram": "Spectogram.py", + "Intensity vs Frequency and Time": "Intensity-vs-Frequency-and-Time.py" + } + + script_name = instance.text + script_path = visualizer_scripts.get(script_name) + + if script_path and os.path.exists(script_path): + self.close_current_visualizer() + self.current_visualizer_process = subprocess.Popen(['python', script_path]) else: - sg.popup_error(f"Script '{script_path}' not found!", title="File Not Found") + popup = Popup(title="File Not Found", content=Label(text=f"Script '{script_path}' not found!"), size_hint=(None, None), size=(400, 200)) + popup.open() + +if __name__ == '__main__': + SoundScapeApp().run() -window.close() \ No newline at end of file