Skip to content

Commit

Permalink
Merge branch 'main' into power_spectral_density
Browse files Browse the repository at this point in the history
  • Loading branch information
dinxsh authored Jul 26, 2024
2 parents 48308d8 + afd7365 commit 722424c
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 2 deletions.
71 changes: 71 additions & 0 deletions Chroma-Feature-Visualizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import numpy as np
import librosa
import librosa.display
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import pyaudio
import threading

FRAME_SIZE = 2048
HOP_SIZE = 512
SR = 22050
BUFFER_SIZE = 10

p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32, channels=1, rate=SR, input=True, frames_per_buffer=HOP_SIZE)

# Initialize the plot
fig, ax = plt.subplots()
chroma_data = np.zeros((12, BUFFER_SIZE))
img = ax.imshow(chroma_data, aspect='auto', cmap='inferno', origin='lower')
fig.colorbar(img, ax=ax)
ax.set_title('Chroma Feature Visualizer')
ax.set_xlabel('Time')
ax.set_ylabel('Pitch Class')

is_paused = False

# Function to update the plot
def update(frame):
global chroma_data, is_paused
if not is_paused:
data = np.frombuffer(stream.read(HOP_SIZE), dtype=np.float32)
chroma = librosa.feature.chroma_stft(y=data, sr=SR, n_fft=FRAME_SIZE, hop_length=HOP_SIZE)
chroma_db = librosa.amplitude_to_db(chroma, ref=np.max)
chroma_data = np.roll(chroma_data, -1, axis=1)
chroma_data[:, -1] = np.mean(chroma_db, axis=1)
img.set_data(chroma_data)
return [img]

# Function to toggle pause/resume
def toggle_pause(event):
global is_paused
is_paused = not is_paused

# Adding a button to pause/resume
ax_pause = plt.axes([0.81, 0.01, 0.1, 0.075])
btn_pause = plt.Button(ax_pause, 'Pause/Resume')
btn_pause.on_clicked(toggle_pause)

# Function to adjust color map
def change_colormap(event):
current_cmap = img.get_cmap().name
new_cmap = 'inferno' if current_cmap == 'viridis' else 'viridis'
img.set_cmap(new_cmap)
fig.canvas.draw()

# Adding a button to change color map
ax_colormap = plt.axes([0.61, 0.01, 0.15, 0.075])
btn_colormap = plt.Button(ax_colormap, 'Change Color Map')
btn_colormap.on_clicked(change_colormap)

# Create an animation
ani = FuncAnimation(fig, update, frames=BUFFER_SIZE, blit=True, interval=50)

# Start the plot
plt.show()

# Close the stream when done
stream.stop_stream()
stream.close()
p.terminate()
124 changes: 124 additions & 0 deletions Lissajous-Curves-Visualizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import numpy as np
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
import random
import subprocess

# Constants
CHUNK = 1024
RATE = 44100

class LissajousWidget(Widget):
def __init__(self, **kwargs):
super(LissajousWidget, self).__init__(**kwargs)
self.points = []
self.offset_x = self.width / 2
self.offset_y = self.height / 2

def update(self, data, a=5, b=4, delta=np.pi / 2):
self.canvas.clear()
with self.canvas:
Color(1, 0, 0)
t = np.linspace(0, 2 * np.pi, 1000)
amplitude = np.max(data) / 32768.0 * 2 # Increase size by scaling amplitude
x = np.sin(a * t + delta) * amplitude * self.width / 2 + self.width / 2 + self.offset_x
y = np.sin(b * t) * amplitude * self.height / 2 + self.height / 2 + self.offset_y
self.points = list(zip(x, y))
flattened_points = [coord for point in self.points for coord in point]
Line(points=flattened_points, width=1.5)

# Randomly move the curves over the screen
self.offset_x = random.uniform(-self.width / 2, self.width / 2)
self.offset_y = random.uniform(-self.height / 2, self.height / 2)

class AudioVisualizerApp(App):
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

# Main layout
self.layout = BoxLayout(orientation='vertical', padding=10, spacing=10)

# Lissajous widget
self.lissajous_widget = LissajousWidget()

# 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.lissajous_widget)
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.lissajous_widget.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)

if __name__ == '__main__':
AudioVisualizerApp().run()
8 changes: 6 additions & 2 deletions mainLanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ def build(self):
"Waveform",
"Spectrogram",
"Intensity vs Frequency and Time",
"Depth-Perspective Visualizer"
"Depth-Perspective Visualizer",
"Chroma-Feature Visualizer"
"Lissajous-Curves Visualizer"
]
for visualizer in visualizers:
button = Button(
Expand Down Expand Up @@ -144,7 +146,9 @@ def launch_visualizer(self, instance):
"Waveform": "Waveform.py",
"Spectrogram": "Spectrogram.py",
"Intensity vs Frequency and Time": "Intensity-vs-Frequency-and-Time.py",
"Depth-Perspective Visualizer": "Depth-Perspective-Visualizer.py"
"Depth-Perspective Visualizer": "Depth-Perspective-Visualizer.py",
"Chroma-Feature Visualizer": "Chroma-Feature-Visualizer.py"
"Lissajous-Curves Visualizer": "Lissajous-Curves-Visualizer.py"
}

script_name = instance.text
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ PyAudio
PySimpleGUI
sounddevice
soundfile
librosa

0 comments on commit 722424c

Please sign in to comment.