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

Added comments to clarify code #167

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
197 changes: 82 additions & 115 deletions Amplitude-Frequency-Visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
from kivy.clock import Clock
from kivy.graphics.texture import Texture

import pyaudio
import numpy as np
import soundfile as sf
import scipy.fft
import matplotlib.pyplot as plt
import os
import traceback
import pyaudio # Import PyAudio for audio input
import numpy as np # Import NumPy for numerical operations
import soundfile as sf # Import SoundFile for audio file handling
import scipy.fft # Import SciPy for FFT operations
import matplotlib.pyplot as plt # Import Matplotlib for plotting
import os # Import OS for file system operations
import traceback # Import traceback for error handling

# VARS CONSTS:
_VARS = {
Expand All @@ -27,40 +27,40 @@
}

# INIT vars:
CHUNK = 1024
RATE = 44100
INTERVAL = 1
TIMEOUT = 0.1
pAud = pyaudio.PyAudio()
CHUNK = 1024 # Number of audio frames per buffer
RATE = 44100 # Sampling rate (samples per second)
INTERVAL = 1 # Interval for updates
TIMEOUT = 0.1 # Timeout for updates
pAud = pyaudio.PyAudio() # Initialize PyAudio

def stop(instance=None):
if _VARS["stream"]:
_VARS["stream"].stop_stream()
_VARS["stream"].close()
_VARS["stream"] = None
progress_bar.value = 0
btn_stop.disabled = True
btn_listen.disabled = False
btn_pause.disabled = True
btn_resume.disabled = True
btn_save.disabled = True
_VARS["stream"].stop_stream() # Stop the audio stream
_VARS["stream"].close() # Close the audio stream
_VARS["stream"] = None # Reset the stream variable
progress_bar.value = 0 # Reset the progress bar
btn_stop.disabled = True # Disable the stop button
btn_listen.disabled = False # Enable the listen button
btn_pause.disabled = True # Disable the pause button
btn_resume.disabled = True # Disable the resume button
btn_save.disabled = True # Disable the save button

def pause(instance=None):
if _VARS["stream"] and _VARS["stream"].is_active():
_VARS["stream"].stop_stream()
btn_pause.disabled = True
btn_resume.disabled = False
_VARS["stream"].stop_stream() # Stop the audio stream
btn_pause.disabled = True # Disable the pause button
btn_resume.disabled = False # Enable the resume button

def resume(instance=None):
if _VARS["stream"] and not _VARS["stream"].is_active():
_VARS["stream"].start_stream()
btn_pause.disabled = False
btn_resume.disabled = True
_VARS["stream"].start_stream() # Start the audio stream
btn_pause.disabled = False # Enable the pause button
btn_resume.disabled = True # Disable the resume button

def save(instance=None):
folder = 'saved_files'
folder = 'saved_files' # Define the folder to save files
if not os.path.exists(folder):
os.makedirs(folder)
os.makedirs(folder) # Create the folder if it doesn't exist
try:
# Save the figure as an image file
fig.savefig(f'{folder}/output.png')
Expand All @@ -74,146 +74,113 @@ def save(instance=None):

def callback(in_data, frame_count, time_info, status):
try:
_VARS["audioData"] = np.frombuffer(in_data, dtype=np.int16)
_VARS["audioBuffer"] = np.append(_VARS["audioBuffer"], _VARS["audioData"])
_VARS["audioData"] = np.frombuffer(in_data, dtype=np.int16) # Convert audio data to NumPy array
_VARS["audioBuffer"] = np.append(_VARS["audioBuffer"], _VARS["audioData"]) # Append audio data to buffer
except Exception as e:
print("Error in callback:", e)
traceback.print_exc()
return (in_data, pyaudio.paContinue)
return (in_data, pyaudio.paContinue) # Continue the audio stream

def listen(instance=None):
try:
btn_stop.disabled = False
btn_listen.disabled = True
btn_pause.disabled = False
btn_stop.disabled = False # Enable the stop button
btn_listen.disabled = True # Disable the listen button
btn_pause.disabled = False # Enable the pause button
_VARS["stream"] = pAud.open(
format=pyaudio.paInt16,
channels=1,
rate=RATE,
input=True,
frames_per_buffer=CHUNK,
stream_callback=callback,
format=pyaudio.paInt16, # 16-bit audio format
channels=1, # Mono audio
rate=RATE, # Sampling rate
input=True, # Input stream
frames_per_buffer=CHUNK, # Buffer size
stream_callback=callback, # Callback function for audio data
)
_VARS["stream"].start_stream()
_VARS["stream"].start_stream() # Start the audio stream
except Exception as e:
popup_message('Error', f"Error: {e}")

def popup_message(title, message):
popup = Popup(title=title, content=Label(text=message), size_hint=(0.8, 0.8))
popup.open()
popup = Popup(title=title, content=Label(text=message), size_hint=(0.8, 0.8)) # Create a popup window
popup.open() # Open the popup window

class MicVisualizerApp(App):
def build(self):
global progress_bar, btn_listen, btn_pause, btn_resume, btn_stop, btn_save, fig, ax, canvas_img

tab_panel = TabbedPanel(do_default_tab=False)
tab_panel = TabbedPanel(do_default_tab=False) # Create a tab panel

# Listening tab
listening_tab = TabbedPanelItem(text='Listening')
listening_layout = BoxLayout(orientation='vertical')

btn_listen = Button(text='Listen', on_press=listen)
btn_pause = Button(text='Pause', on_press=pause, disabled=True)
btn_resume = Button(text='Resume', on_press=resume, disabled=True)
btn_stop = Button(text='Stop', on_press=stop, disabled=True)
btn_save = Button(text='Save', on_press=save, disabled=True)
btn_exit = Button(text='Exit', on_press=self.stop)
btn_listen = Button(text='Listen', on_press=listen) # Listen button
btn_pause = Button(text='Pause', on_press=pause, disabled=True) # Pause button
btn_resume = Button(text='Resume', on_press=resume, disabled=True) # Resume button
btn_stop = Button(text='Stop', on_press=stop, disabled=True) # Stop button
btn_save = Button(text='Save', on_press=save, disabled=True) # Save button
btn_exit = Button(text='Exit', on_press=self.stop) # Exit button

progress_bar = ProgressBar(max=4000)
progress_bar = ProgressBar(max=4000) # Progress bar

button_layout = BoxLayout(size_hint_y=None, height=50)
button_layout = BoxLayout(size_hint_y=None, height=50) # Button layout
button_layout.add_widget(btn_listen)
button_layout.add_widget(btn_pause)
button_layout.add_widget(btn_resume)
button_layout.add_widget(btn_stop)
button_layout.add_widget(btn_save)
button_layout.add_widget(btn_exit)

listening_layout.add_widget(Label(text='Progress:', size_hint_y=None, height=50))
listening_layout.add_widget(progress_bar)
listening_layout.add_widget(button_layout)
listening_layout.add_widget(Label(text='Progress:', size_hint_y=None, height=50)) # Progress label
listening_layout.add_widget(progress_bar) # Add progress bar to layout
listening_layout.add_widget(button_layout) # Add button layout to listening layout

listening_tab.add_widget(listening_layout)
tab_panel.add_widget(listening_tab)
listening_tab.add_widget(listening_layout) # Add listening layout to tab
tab_panel.add_widget(listening_tab) # Add listening tab to tab panel

# Visualization tab
visualization_tab = TabbedPanelItem(text='Visualization')
visualization_layout = BoxLayout(orientation='vertical')

fig, ax = plt.subplots()
canvas_img = Image()
visualization_layout.add_widget(canvas_img)
fig, ax = plt.subplots() # Create a Matplotlib figure and axes
canvas_img = Image() # Image widget for displaying the plot
visualization_layout.add_widget(canvas_img) # Add image widget to layout

visualization_tab.add_widget(visualization_layout)
tab_panel.add_widget(visualization_tab)
visualization_tab.add_widget(visualization_layout) # Add visualization layout to tab
tab_panel.add_widget(visualization_tab) # Add visualization tab to tab panel

# Settings tab
settings_tab = TabbedPanelItem(text='Settings')
settings_layout = BoxLayout(orientation='vertical')

rate_label = Label(text='Sample Rate:')
self.rate_input = TextInput(text=str(RATE), multiline=False)
chunk_label = Label(text='Chunk Size:')
self.chunk_input = TextInput(text=str(CHUNK), multiline=False)
rate_label = Label(text='Sample Rate:') # Sample rate label
self.rate_input = TextInput(text=str(RATE), multiline=False) # Sample rate input
chunk_label = Label(text='Chunk Size:') # Chunk size label
self.chunk_input = TextInput(text=str(CHUNK), multiline=False) # Chunk size input

apply_button = Button(text='Apply', on_press=self.apply_settings)
settings_layout.add_widget(rate_label)
settings_layout.add_widget(self.rate_input)
settings_layout.add_widget(chunk_label)
settings_layout.add_widget(self.chunk_input)
settings_layout.add_widget(apply_button)
apply_button = Button(text='Apply', on_press=self.apply_settings) # Apply button
settings_layout.add_widget(rate_label) # Add sample rate label to layout
settings_layout.add_widget(self.rate_input) # Add sample rate input to layout
settings_layout.add_widget(chunk_label) # Add chunk size label to layout
settings_layout.add_widget(self.chunk_input) # Add chunk size input to layout
settings_layout.add_widget(apply_button) # Add apply button to layout

settings_tab.add_widget(settings_layout)
tab_panel.add_widget(settings_tab)
settings_tab.add_widget(settings_layout) # Add settings layout to tab
tab_panel.add_widget(settings_tab) # Add settings tab to tab panel

Clock.schedule_interval(self.update_plot, TIMEOUT)
Clock.schedule_interval(self.update_plot, TIMEOUT) # Schedule the update plot function

return tab_panel
return tab_panel # Return the tab panel

def apply_settings(self, instance):
global RATE, CHUNK
try:
RATE = int(self.rate_input.text)
CHUNK = int(self.chunk_input.text)
RATE = int(self.rate_input.text) # Update the sample rate
CHUNK = int(self.chunk_input.text) # Update the chunk size
popup_message('Settings Applied', 'Sample Rate and Chunk Size updated.')
except ValueError:
popup_message('Invalid Input', 'Please enter valid integer values.')

def update_plot(self, dt):
if _VARS["audioData"].size != 0:
progress_bar.value = np.amax(_VARS["audioData"])
yf = scipy.fft.fft(_VARS["audioData"])
xf = np.linspace(0.0, RATE / 2, CHUNK // 2)
ax.clear()
ax.plot(
xf, 2.0 / CHUNK * np.abs(yf[: CHUNK // 2]), label='Frequency Spectrum'
)
ax.set_title("Frequency Spectrum")
ax.set_ylabel("Amplitude")
ax.set_xlabel("Frequency [Hz]")
ax.grid(True)
ax.legend()

self.update_canvas()

def update_canvas(self):
fig.canvas.draw()
width, height = fig.canvas.get_width_height()
buf = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
buf = buf.reshape(height, width, 3)

texture = Texture.create(size=(width, height))
texture.blit_buffer(buf.tostring(), colorfmt='rgb', bufferfmt='ubyte')
texture.flip_vertical()

canvas_img.texture = texture

def on_stop(self):
stop(None)
if _VARS["current_visualizer_process"]:
close_current_visualizer()
pAud.terminate()

if __name__ == '__main__':
app = MicVisualizerApp()
app.run()
progress_bar.value = np.amax(_VARS["audioData"]) # Update the progress bar value
yf = scipy.fft.fft(_VARS["audioData"]) # Perform FFT on the audio data
xf = np.linspace(0.0, RATE / 2
Loading