Skip to content

Instantly share code, notes, and snippets.

@miathedev
Created April 10, 2023 06:07
Show Gist options
  • Save miathedev/a3ab0617869f181c3d33573728bd7396 to your computer and use it in GitHub Desktop.
Save miathedev/a3ab0617869f181c3d33573728bd7396 to your computer and use it in GitHub Desktop.
Sound 2 Light using Python Prototype
#This application is a creative project idea
#It captures live audio and maps it realtime to rgb values
#It is a fun way to visualize sound
#But the performance is not good enough to be used as a (actual) visualizer, its really slow
import pyaudio
import numpy as np
import time
import sys
import math
import random
import colorsys
import pygame
from pygame.locals import *
#Initialize pygame
pygame.init()
#screen = pygame.display.set_mode((640, 480))
#Ignore vsync
#screen =pygame.display.set_mode((640, 480), pygame.DOUBLEBUF | pygame.HWSURFACE | )
#Set fps to 60
clock = pygame.time.Clock()
#Set window size to full screen
screen = pygame.display.set_mode((0, 0), pygame.HWSURFACE )
pygame.display.set_caption('Mapify')
pygame.mouse.set_visible(0)
#Initialize pyaudio
p = pyaudio.PyAudio()
#Request from user from which device to capture audio, using pyaudio
device = -1
for i in range(p.get_device_count()):
dev = p.get_device_info_by_index(i)
print((str(i)+': '+dev['name']+' - '+str(dev['maxInputChannels'])+' input channels'))
if dev['maxInputChannels'] > 0:
#Ensure device is activated
if dev['hostApi'] == 0:
print('Default device is ' + str(i))
device = i
break
#if no device is found, exit
if device == -1:
print('No input device found with input channels')
sys.exit()
#Open the stream from device selected
stream = p.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=1024, input_device_index=device)
#Function to get the average volume of the bass frequency range
def get_bass_volume(data):
#Convert data to numpy array
data = np.fromstring(data, dtype=np.int16)
#Get the average volume of the bass frequency range
bass = np.mean(np.abs(data[0:1024]))
return bass
#Function to get the average volume of the mid frequency range
def get_mid_volume(data):
#Convert data to numpy array
data = np.fromstring(data, dtype=np.int16)
#Get the average volume of the mid frequency range
mid = np.mean(np.abs(data[1025:2048]))
return mid
#Function to get the average volume of the treble frequency range
def get_treble_volume(data):
#Convert data to numpy array
data = np.fromstring(data, dtype=np.int16)
#Get the average volume of the treble frequency range
treble = np.mean(np.abs(data[2049:3072]))
return treble
#Function to get the average volume of the high frequency range
def get_high_volume(data):
#Convert data to numpy array
data = np.fromstring(data, dtype=np.int16)
#Get the average volume of the high frequency range
high = np.mean(np.abs(data[3073:4096]))
return high
#Function to get the average volume of the entire frequency range
def get_volume(data):
#Convert data to numpy array
data = np.fromstring(data, dtype=np.int16)
#Get the average volume of the entire frequency range
volume = np.mean(np.abs(data[0:4096]))
return volume
#Continuously loop to capture audio, create fft, and map it to values of bass,mid,treble,high,volume
max_red = 1
max_green = 1
max_blue = 1
max_saturation = 1
max_brightness = 1
running = True
while running:
#Capture audio
data = stream.read(4096)
#Get the average volume of the bass frequency range
bass = get_bass_volume(data)
#Get the average volume of the mid frequency range
mid = get_mid_volume(data)
#Get the average volume of the treble frequency range
treble = get_treble_volume(data)
#Get the average volume of the high frequency range
#high = get_high_volume(data)
#Get the average volume of the entire frequency range
#volume = get_volume(data)
#Map the bass frequency range to the red value
red = bass
#Map the mid frequency range to the green value
green = mid
#Map the treble frequency range to the blue value
blue = treble
#Map the high frequency range to the saturation value
#saturation = high
#Map the entire frequency range to the brightness value
#brightness = volume
#Get and Set the maximum value ever encountered for each value
if red > max_red:
max_red = red
if green > max_green:
max_green = green
if blue > max_blue:
max_blue = blue
#if saturation > max_saturation:
# max_saturation = saturation
#if brightness > max_brightness:
# max_brightness = brightness
#map all values to 0 to 255, set the max value of origin type to maximum value ever encountered
red = int((red / max_red) * 255)
green = int((green / max_green) * 255)
blue = int((blue / max_blue) * 255)
#saturation = int((saturation / max_saturation) * 255)
#brightness = int((brightness / max_brightness) * 255)
#render rgb values to rectangle
screen.fill(color = (0, 0, 0))
#Display all values as bars
pygame.draw.rect(screen, (red, 0, 0), (0, 0, 100, 100))
pygame.draw.rect(screen, (0, green, 0), (100, 0, 100, 100))
pygame.draw.rect(screen, (0, 0, blue), (200, 0, 100, 100))
#pygame.draw.rect(screen, (saturation, saturation, saturation), (300, 0, 100, 100))
#pygame.draw.rect(screen, (brightness, brightness, brightness), (400, 0, 100, 100))
#There is a moving head, it is the color of the current rgb values
#A moving head has x and y coordinates. It moves in a circle
#The x and y coordinates are calculated using the sine and cosine functions
#get screen height
height = pygame.display.get_surface().get_height()
#Calculate the x and y coordinates of the moving head
#When the bass hits, the head moves faster
#pygame get ticks
ticks = float(pygame.time.get_ticks()) / 1000.0
x = 320 + 150 * (math.sin(ticks * 2.0 + float(red) / 200.0))
y = (height / 2) + 150 * (math.cos(ticks * 2.0 + float(red) / 200.0))
#Draw the moving head
pygame.draw.circle(screen, (red, green, blue), (int(x), int(y)), 50)
#Draw fps counter
#pygame get fps
font = pygame.font.Font(None, 36)
text = font.render(str(int(clock.get_fps())), 1, (255, 255, 255))
textpos = text.get_rect()
textpos.centerx = 50
screen.blit(text, textpos)
#Update the screen
pygame.display.flip()
#Loop through the event queue
for event in pygame.event.get():
#Check for KEYDOWN event
if event.type == KEYDOWN:
#If the Esc key has been pressed set running to false to exit the main loop
if event.key == K_ESCAPE:
running = False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment