Урок 19. LED панель + Микрофон. Светомузыка
-
Цель урока
Привет! Сегодня мы научимся зажигать многоцветные светодиодные панели (только в M5 FIRE), полагаясь на составляющие частоты звукового сигнала, полученные со встроенного (только в M5 FIRE) микрофона.
Рисунок 1
Этот урок научит: подключать и использовать на практике сторонние библиотеки для работы с быстрым преобразованием Фурье (FFT) и светодиодами SK6818.
Краткая справка
Цветомузыка - вид искусства, основанный на способности человека ассоциировать звуковые ощущения со световыми восприятиями; такое явление в неврологии получило название синестезия. Светомузыка как искусство, представляет собой производную от музыки и является её неотъемлемой частью. Её назначение — раскрытие сущности музыки посредством зрительных восприятий. Основной целью светомузыки как искусства — это изучение способности человека испытывать ощущения, навязываемые световыми образами при сопровождении музыки.
Любители музыки уже давно подметили, что музыкальные инструменты звучат намного громче и отчетливее в хорошо освещённом помещении, чем в затемнённом. Поэтому при исполнении серьёзной музыки свет в зале обычно не гасят.
Впервые связь между слухом и зрением очень убедительно показал русский физик и русский физиолог академик П. П. Лазарев.
Подробно на Wiki: https://ru.wikipedia.org/wiki/Светомузыка
Перечень компонентов для урока
- PC/MAC;
- M5STACK FIRE;
- кабель USB-C из стандартного набора.
Начнём!
Шаг 1. Установка библиотеки для работы с LED BAR
Переходим по ссылке Библиотека LED BAR в разделе Downloads и скачиваем пример с файлами библиотек (рис. 2).
Рисунок 2
Далее извлекаем архив в новую папку sketch и удаляем файл demo1.ino (рис. 3).
Рисунок 3
Шаг 2. Установка библиотеки FFT
Переходим по ссылке Библиотека Arduino FFT в разделе Downloads и скачиваем пример с файлами библиотек (рис. 4).
Рисунок 4
Далее извлекаем содержимое и копируем папку в C:\Users\USER_NAME\Documents\Arduino\libraries с новым именем arduinoFFT вместо arduinoFFT-master (рис. 5).
Рисунок 5
Отлично! С библиотеками всё :)
Шаг 3. Пишем скетч
Создадим в Arduino IDE новый скетч и сохраним его в той папке, где лежат файлы библиотеки из шага 1 (рис. 6).
Рисунок 6
Сразу подключим необходимые библиотеки и создадим необходимые переменные:
#include <M5Stack.h> #include "arduinoFFT.h" #include "esp32_digital_led_lib.h" arduinoFFT FFT = arduinoFFT(); #define SAMPLES 256 //Must be a power of 2 #define SAMPLING_FREQUENCY 10000 //Hz, must be 10000 or less due to ADC conversion time. Determines maximum frequency that can be analysed by the FFT. #define amplitude 50 unsigned int sampling_period_us; unsigned long microseconds; byte peak[] = {0,0,0,0,0,0,0}; double vReal[SAMPLES]; double vImag[SAMPLES]; unsigned long newTime, oldTime; strand_t m_sLeds = {.rmtChannel = 0, .gpioNum = 15, .ledType = LED_WS2812B_V3, .brightLimit = 32, .numPixels = 10, .pixels = nullptr, ._stateVars = nullptr};
Для упрощенного обращения к LED BAR предлагаю использовать следующую функцию void ledBar(int R, int G, int B, int M). Где int R, int G, int B - яркость КРАСНОГО, ЗЕЛЕНОГО и СИНЕГО - соответственно (от 0 до 255); int M - режим: от 0 до 9 - номер светодиода, 10 - все светодиоды из левой панели, 11 - все светодиоды из правой панели, 12 - все светодиоды.
Светодиоды расположены по часовой стрелке (рис. 7).
Рисунок 7
Рисунок 7.1
void ledBar(int R, int G, int B, int M) { if ((M < 0) || (M > 13)) return; if (M == 11) // right { for (int i = 0; i < 5; i++) { m_sLeds.pixels[i] = pixelFromRGBW(R, G, B, 0); } } else if (M == 10) // left { for (int i = 5; i < 10; i++) { m_sLeds.pixels[i] = pixelFromRGBW(R, G, B, 0); } } else if (M == 12) // all { for (int i = 0; i < 10; i++) { m_sLeds.pixels[i] = pixelFromRGBW(R, G, B, 0); } } else { m_sLeds.pixels[M] = pixelFromRGBW(R, G, B, 0); } digitalLeds_updatePixels(&m_sLeds); }
Основная часть. Не забывайте про void dacWrite(25, 0); чтобы динамик не издавал странных звуков и треска.
void setup(){ M5.begin(); pinMode(25, OUTPUT); pinMode(34, INPUT); sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY)); pinMode(15, OUTPUT); digitalWrite (15, LOW); if (digitalLeds_initStrands(&m_sLeds, 1)) { Serial.println("Can't init LED driver()."); } digitalLeds_resetPixels(&m_sLeds); }
Обратите внимание на pinMode(34, INPUT) - это аналоговый вход, к которому подключён встроенный микрофон (рис. 8) через усилитель, поэтому настроим его на INPUT.
Рисунок 8
void loop() { for (int i = 0; i < SAMPLES; i++) { newTime = micros() - oldTime; oldTime = newTime; vReal[i] = analogRead(34); // A conversion takes about 1mS on an ESP8266 vImag[i] = 0; while (micros() < (newTime + sampling_period_us)); // do nothing to wait } FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); dacWrite(25, 0); for (int i = 2; i < (SAMPLES/2); i++){ // Don't use sample 0 and only first SAMPLES/2 are usable. Each array eleement represents a frequency and its value the amplitude. if (vReal[i] > 200) { // Add a crude noise filter, 4 x amplitude or more if (i<=5 ) displayBand(0,(int)vReal[i]/amplitude); // 125Hz if (i >5 && i<=12 ) displayBand(1,(int)vReal[i]/amplitude); // 250Hz if (i >12 && i<=32 ) displayBand(2,(int)vReal[i]/amplitude); // 500Hz if (i >32 && i<=62 ) displayBand(3,(int)vReal[i]/amplitude); // 1000Hz if (i >62 && i<=105 ) displayBand(4,(int)vReal[i]/amplitude); // 2000Hz if (i >105 && i<=120 ) displayBand(5,(int)vReal[i]/amplitude); // 4000Hz if (i >120 && i<=146 ) displayBand(6,(int)vReal[i]/amplitude); // 8000Hz } } }
Зажигать светодиоды будем с помощью функции void displayBand(int band, int dsize). Где band - частота в сигнале; dsize - количество частоты в сигнале. Можете смело тут экспериментировать и добиваться лучших вспышек.
void displayBand(int band, int dsize){ if (band > 1) dsize += 100; if (dsize >= 150) { ledBar(0, 0, 0, 12); if (band == 0) { if (dsize >= 300) { ledBar(255, 0, 0, 0); ledBar(255, 0, 0, 1); } } else if (band == 1) { if (dsize >= 180) { ledBar(255, 255, 0, 3); ledBar(255, 255, 0, 4); } } else if (band == 2) { if (dsize >= 170) { ledBar(0, 255, 0, 5); ledBar(0, 255, 0, 6); } } else { ledBar(0, 0, 255, 8); ledBar(0, 0, 255, 9); } } }
Завершающий шаг
На этом всё :)
Downloads
- Библиотека LED BAR (GitHub): https://github.com/MartyMacGyver/ESP32-Digital-RGB-LED-Drivers/tree/master/arduino-esp32/demo1
- Библиотека Arduino FFT (GitHub): https://github.com/kosme/arduinoFFT