Вопрос или проблема
Мне нужно изменить код, найденный в сети, чтобы изменить цвета в зависимости от музыкального ритма, не меняя цвета при разговорном голосе.
Приведенный код
import numpy
import struct
import sys
import pyaudio
import time
PWM = False # Установите False, если не хотите использовать ШИМ
PYG = True # Установите True для использования pygame для визуального отображения
if PWM:
import RPi.GPIO as IO
if PYG:
import pygame
CHANNELS = 2
RATE = 44100
FORMAT = pyaudio.paInt16
nFFT = 512
BUF_SIZE = 4 * nFFT
ofr, ofg, ofb = 0, 0, 0 # Смещения (калибровка шума)
sv1, sv2, sv3 = 0, 0, 0
# Размер окна
sx, sy = 800, 400
pri = False
if PWM:
prr, pgg, pbb = 9, 10, 11 # Номера выводов для r, g, b соответственно
IO.setmode(IO.BCM)
IO.setup(prr, IO.OUT)
IO.setup(pgg, IO.OUT)
IO.setup(pbb, IO.OUT)
pr = IO.PWM(prr, 100)
pg = IO.PWM(pgg, 100)
pb = IO.PWM(pbb, 100)
pr.start(sv1)
pg.start(sv2)
pb.start(sv3)
if PYG:
pygame.init()
screen = pygame.display.set_mode((sx, sy))
pygame.mouse.set_visible(0)
pygame.display.set_caption('Дисплей RGB LED, реагирующий на звук')
p = pyaudio.PyAudio()
# Функция для перечисления аудиоустройств
def list_devices():
for i in range(p.get_device_count()):
info = p.get_device_info_by_index(i)
print(f"Устройство {i}: {info['name']}")
# Определите индекс выходного устройства динамиков и установите его здесь
output_device_index = None # Установите это после определения устройства динамиков
# Перечисление всех доступных устройств
list_devices()
# Установите входное устройство на систему вывода (ваши динамики)
stream = p.open(
format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
input_device_index=output_device_index, # Установите индекс вывода вашего динамика здесь
frames_per_buffer=BUF_SIZE
)
def restartP(): # Перезапустите pyaudio в случае ошибок/исключений
global p, stream, CHANNELS, RATE, FORMAT, nFFT, BUF_SIZE, output_device_index
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=BUF_SIZE, input_device_index=output_device_index)
def scale(va, fromin, fromax, tomin, tomax):
return numpy.interp(va, [fromin, fromax], [tomin, tomax])
def constrain(val, i, j):
if val < i:
return i
if val > j:
return j
return int(val)
def getF(MAX_y, ret):
global PWM, PYG, pri, ofr, ofg, ofb, stream, sv1, sv2, sv3
if PWM:
global pr, pg, pb
try:
N = int(max(stream.get_read_available() / nFFT, 1) * nFFT) # Убедитесь, что N - целое число
data = stream.read(N)
except IOError as e:
time.sleep(2)
restartP()
return ""
y = numpy.array(struct.unpack("%dh" % (N * CHANNELS), data)) / MAX_y
y_L = y[::2]
y_R = y[1::2]
Y_L = numpy.fft.fft(y_L, nFFT)
Y_R = numpy.fft.fft(y_R, nFFT)
Y = abs(numpy.hstack((Y_L[-nFFT // 2:-1], Y_R[:nFFT // 2])))
v1, v2, v3 = 0, 0, 0
c01, c02 = 255 - 4, 256 + 4
c11, c12 = c01 - 20, c02 + 20
c21, c22 = 0, 511
for i in range(c01, c02):
v1 += Y[i]
for i in list(range(c11, c01)) + list(range(c02, c12)):
v2 += Y[i]
for i in list(range(c21, c11)) + list(range(c12, c22)):
v3 += Y[i]
if ret:
return (v1, v2, v3)
else:
v1 -= ofr
v2 -= ofg
v3 -= ofb
constr = 1000
scl_fac = (6, 4.5, 7)
iv1, iv2, iv3 = constrain(int(scl_fac[0] * v1), 0, constr), constrain(int(scl_fac[1] * v2), 0, constr), constrain(int(scl_fac[2] * v3), 0, constr)
sv1, sv2, sv3 = scale(iv1, 0, constr, 0, 255), scale(iv2, 0, constr, 0, 255), scale(iv3, 0, constr, 0, 255)
if PWM:
pr.ChangeDutyCycle(scale(sv1, 0, 255, 0, 100))
pg.ChangeDutyCycle(scale(sv2, 0, 255, 0, 100))
pb.ChangeDutyCycle(scale(sv3, 0, 255, 0, 100))
if PYG:
color = (int(sv1), int(sv2), int(sv3)) # Создание цвета RGB из масштабируемых значений
screen.fill(color) # Закрасить окно текущим цветом
pygame.display.flip() # Обновить дисплей
if pri:
if sv1 != 0 or sv2 != 0 or sv3 != 0:
print(sv1, "\t", sv2, "\t", sv3)
def rgb():
calib = 300
global ofr, ofg, ofb, p, stream, sv1, sv2, sv3
if PWM:
global pr, pg, pb
MAX_y = 2.0 ** (p.get_sample_size(FORMAT) * 8 - 1)
try:
for _ in range(0, 10):
ofrr, ofgg, ofbb = getF(MAX_y, True)
tofr, tofg, tofb = 0, 0, 0
for _ in range(0, calib):
ofrr, ofgg, ofbb = getF(MAX_y, True)
tofr += ofrr
tofg += ofgg
tofb += ofbb
ofr = (tofr / calib) * 3
ofg = (tofg / calib) * 3
ofb = (tofb / calib) * 3
if pri:
print("калибровка завершена", ofr, ofg, ofb)
sv1, sv2, sv3 = 100, 100, 100
if PWM:
pr.ChangeDutyCycle(sv1)
pg.ChangeDutyCycle(sv2)
pb.ChangeDutyCycle(sv3)
time.sleep(0.3)
sv1, sv2, sv3 = 0, 0, 0
if PWM:
pr.ChangeDutyCycle(sv1)
pg.ChangeDutyCycle(sv2)
pb.ChangeDutyCycle(sv3)
while True:
getF(MAX_y, False)
except KeyboardInterrupt:
print("выход")
sys.exit()
stream.stop_stream()
stream.close()
p.terminate()
rgb()
Заранее спасибо за помощь
Ответ или решение
Для реализации цветовой реакции на музыку при помощи кода, предложенного вами, необходимо внести изменения, которые позволят отслеживать и изменять цвета только в зависимости от ритма музыкальных битов, игнорируя при этом речь. Это требует применения методов анализа аудиосигнала, таких как преобразование Фурье, для выделения частотных компонентов, характерных для музыки.
Шаги для достижения цели
1. Модификация функции getF
Для того чтобы определять биты музыки, вам необходимо изменить функцию getF
, в которой обрабатываются аудиоданные. Основная задача заключается в том, чтобы распознавать наиболее значимые пики в спектре частот, которые присутствуют в музыке:
def getF(MAX_y, ret):
global stream, sv1, sv2, sv3
try:
N = int(max(stream.get_read_available() / nFFT, 1) * nFFT)
data = stream.read(N)
except IOError as e:
time.sleep(2)
restartP()
return ""
y = numpy.array(struct.unpack("%dh" % (N * CHANNELS), data)) / MAX_y
y_L, y_R = y[::2], y[1::2]
Y_L = numpy.fft.fft(y_L, nFFT)
Y_R = numpy.fft.fft(y_R, nFFT)
Y = abs(numpy.hstack((Y_L[-nFFT // 2:-1], Y_R[:nFFT // 2])))
# Добавлено: Определение диапазона частот для битов
V = numpy.mean(Y[50:100]) # Частоты низкого диапазона для басов
# Проверка, превышает ли V порог
threshold = 10 # Настройте порог в зависимости от уровня громкости
if V > threshold:
sv1, sv2, sv3 = 255, 0, 0 # Красный цвет при обнаружении бита
else:
sv1, sv2, sv3 = 0, 0, 255 # Синий цвет при отсутствии битов
if PYG:
color = (int(sv1), int(sv2), int(sv3))
screen.fill(color)
pygame.display.flip()
2. Установка порога чувствительности
В вышеуказанном коде используется простой механизм определения, есть ли речевой вход или выброс, который, скорее всего, связан с битами. Для более точного идентифицирования ритма музыки вы можете провести эксперименты с диапазоном частот и порогом:
- Настройте диапазоны: Экспериментально подберите диапазоны частот для подсчета среднего значения, фокусируясь на базовых тонах вашей музыки.
- Подобрав порог: Установите порог чувствительности, чтобы избежать случайных срабатываний от фоновых шумов.
3. Завершение
Убедитесь, что после этих изменений программа будет реагировать только на биты музыки. Проверяйте поведение программы в реальных сценариях с разными видами музыкальных треков. При необходимости, продолжайте вносить изменения на основе получаемых результатов.
Эта модификация гарантирует сохранение реакции на музыку, в то время как звуки речи будут проигнорированы. Также рекомендуется протестировать итоговый код на различных устройствах, чтобы убедиться в его совместимости и стабильности.
Просим вас учесть, что работа с аудиоданными требует опытной настройки и иногда может потребовать дополнительных библиотек (например, для обработки аудиосигналов). Настройка системы также имеет большое значение для точности ваших визуальных выходов.