Цветомузыка на WS2812B и ардуино для ПК

Здравствуйте

Мне давно хотелось сделать цветомузыку (далее ЦМУ), но хотелось сделать так, чтобы работы при этом было как можно меньше. Увидел на ali ленту WS2812B и решил вот, это то что надо, ни каких 220В, ни каких тиристоров, симисторов и т.п…

Основные принципы работы данной ЦМУ:
— Обработка звука и формирование цветомузыкальных программ осуществляется моей программой для ПК.
— Управление состоянием светодиодов ленты осуществляет модуль arduino по командам из программы.
— Для воспроизведения музыки может использоваться любой программный плеер, например WinAmp, AIMP, ITUNES, Windows Media и т.п. или аппаратный плеер имеющий линейный выход.

Для управления лентой я написал программу для ПК. Ссылка для скачивания программы. Программа не имеет ограничений и может использоваться в личных целях всеми желающими.

Для минимального комплекта ЦМУ, с непосредственным подключением к USB ПК, нужна лишь светодиодная лента с WS2812B, arduino nano (или аналогичная), три проводника и мини USB кабель для подключения платы arduino к одному из USB портов ПК. В данном варианте количество активных (работающих) светодиодов ограничено 19 по одному на каждую цветовую полосу программы ЦМУ. Ограничение введено для предотвращения перегрузки USB порта.

Скетч модуля arduino при непосредственном подключении ЦМУ к USB порту компьютера:
Дополнительная информация

#include <Adafruit_NeoPixel.h>
 
#define ledPin 13       // светодиод на плате arduino
#define stripPin 2      // выход управления светодиодной лентой
#define stripLed 30     // количество светодиодов в ленте
#define bandPass 19     // число полос ЦМУ (используемых светодиодов)

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(stripLed, stripPin, NEO_GRB + NEO_KHZ800);

const uint32_t PROGMEM
  colorTab[]={
      0xFF0000,0xFF1100,0xFF2200,0xFF3300,0xFF4400,0xFF5500,0xFF6600,0xFF7700,0xFF8800,0xFF9900,0xFFAA00,0xFFBB00,0xFFCC00,0xFFDD00,0xFFEE00,0xFFFF00,  //красный - жёлтый
      0xFFFF00,0xEEFF00,0xDDFF00,0xCCFF00,0xBBFF00,0xAAFF00,0x99FF00,0x88FF00,0x77FF00,0x66FF00,0x55FF00,0x44FF00,0x33FF00,0x22FF00,0x11FF00,0x00FF00,  //жёлтый — зелёный
      0x00FF00,0x00FF11,0x00FF22,0x00FF33,0x00FF44,0x00FF55,0x00FF66,0x00FF77,0x00FF88,0x00FF99,0x00FFAA,0x00FFBB,0x00FFCC,0x00FFDD,0x00FFEE,0x00FFFF,  //зелёный — циан (голубой)
      0x00FFFF,0x00EEFF,0x00DDFF,0x00CCFF,0x00BBFF,0x00AAFF,0x0099FF,0x0088FF,0x0077FF,0x0066FF,0x0055FF,0x0044FF,0x0033FF,0x0022FF,0x0011FF,0x0000FF,  //голубой — синий
      0x0000FF,0x1100FF,0x2200FF,0x3300FF,0x4400FF,0x5500FF,0x6600FF,0x7700FF,0x8800FF,0x9900FF,0xAA00FF,0xBB00FF,0xCC00FF,0xDD00FF,0xEE00FF,0xFF00FF,  //синий — пурпур (маджента)
      0xFF00FF,0xFF00EE,0xFF00DD,0xFF00CC,0xFF00BB,0xFF00AA,0xFF0099,0xFF0088,0xFF0077,0xFF0066,0xFF0055,0xFF0044,0xFF0033,0xFF0022,0xFF0011,0xFF0000}; //маджента — красный

typedef union{
    struct {
      uint8_t b,g,r,w;
    };
    uint32_t dw;
} TColor;

typedef union{
    struct {
      uint8_t b0,b1;
    };
    uint16_t w;
} TWord;

char inStr[64];       // a string to hold incoming data
char rcvString[64];   // a string to hold incoming data
uint8_t inCounter = 0;
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  Serial.begin(115200);
  // reserve 32 bytes for the inputString:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    stringComplete = false;
    compare();
    rcvString[2]=0;
    Serial.println(rcvString);
 }
}

void compare() {
    
    switch (rcvString[0]) {
      case 'r': {
        zmu();
        break;
      }
      case 'c':{
        strip.clear();
        strip.show();
        break;
      }
    }
}


//  SerialEvent
void serialEvent() {
  uint8_t i;
  
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    if (inChar != char(254)) {
     inStr[inCounter++] = inChar;
     if (inChar == char(255)) {
       i=0;
       while (inStr[i]!=char(255)) {
         rcvString[i]=inStr[i];
         i++;
       }
       rcvString[i]=inStr[i];
       stringComplete = true;
       inCounter = 0;          // clear the input string:
     }
    } else inCounter = 0;      // clear the input string: 
  }
}

void zmu() {
  TColor cl;
  TWord akk;
  uint8_t n,i,k,j;

  for(i=0; i<bandPass; i++) {
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
      j = rcvString[i+1];
      akk.w = cl.r * j;
      akk.w = akk.b1 * akk.b1; 
      cl.r = akk.b1;
      akk.w = cl.g * j;
      akk.w = akk.b1 * akk.b1; 
      cl.g = akk.b1;
      akk.w = cl.b * j;
      akk.w = akk.b1 * akk.b1; 
      cl.b = akk.b1;
      cl.dw = strip.Color(cl.r, cl.g, cl.b);
      strip.setPixelColor(i, cl.dw);
  }
  strip.show();
}

Для максимального, беспроводного варианта, дополнительно потребуется ещё одна плата arduino, два радио модуля nRF24L01 с платами адаптеров, блок питания 5В на мощность соответствующую вашей ленте. Оба модуля nRF24L01 подключаются к платам arduino идентично. Подключение осуществляется по типовой схеме к цифровым выводам D9,D10,D11,D12,D13 или другим при соответствующем изменении заголовков конфигурации в скетче. Типовые схемы включения nRF24L01 есть в интернете. Вход управления светодиодной лентой Din (Din на ленте) заведён на цифровой выход D2 платы arduino.


При беспроводном подключении к ПК один из модулей arduino c модулем nRF24L01 подключается к USB порту ПК (при подключении драйвером выполняется преобразование USB<->COM). Указанный модуль принимает по СОМ порту пакеты от программы ЦМУ и через радио модуль nRF24L01 транслирует их по радиоканалу к контроллеру ленты. Радио модуль nRF24L01 контроллера ленты по радио каналу принимает пакеты поступившие от контроллера подключённого к ПК. Модуль arduino контроллера ленты получает принятые пакеты от nRF24L01 и устанавливает светодиоды ленты в требуемое состояние.

Скетч модуля подключаемого к ПК:
Дополнительная информация

#include <SPI.h>        // Подключаем библиотеку для работы с шиной SPI
#include <nRF24L01.h>   // Подключаем файл настроек из библиотеки RF24
#include <RF24.h>       // Подключаем библиотеку для работы с nRF24L01+
RF24    radio(9, 10);   // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов nRF24L01+ (CE, CSN)

char    rfData[32];     // Создаём массив для передачи данных
uint8_t rfCounter = 0;
char    serData[40];   // a string to hold incoming data
uint8_t serCounter = 0;
boolean stringComplete = false;

void setup(){
    Serial.begin(115200);
    radio.begin();                                      // Инициируем работу nRF24L01+
    radio.setChannel(5);                                // Указываем канал передачи данных (от 0 до 127), 5 - значит передача данных осуществляется на частоте 2,405 ГГц (на одном канале может быть только 1 приёмник и до 6 передатчиков)
    radio.setDataRate     (RF24_1MBPS);                 // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек
    radio.setPALevel      (RF24_PA_HIGH);               // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)
    radio.openWritingPipe (0x1234567890LL);             // Открываем трубу с идентификатором 0x1234567890 для передачи данных (на ожном канале может быть открыто до 6 разных труб, которые должны отличаться только последним байтом идентификатора)
}

void loop(){
  uint8_t i;
  
    if (rfCounter>0) {
      radio.write(&rfData[0],32);
      rfCounter=0;
      Serial.write(rfData,32);
    }
}

//  SerialEvent
void serialEvent() {
  uint8_t i;
  
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    if (inChar != char(254)) {
     if (inChar == char(255)) {
       for(i=0; i<32; i++) rfData[i]=serData[i];
       rfCounter = 32;
       serCounter = 0;          // clear the input string:
     }
     else serData[serCounter++] = inChar;
    } else serCounter = 0;      // clear the input string: 
  }
}

Скетч модуля ленты:

#include <SPI.h>                   // Подключаем библиотеку  для работы с шиной SPI
#include <nRF24L01.h>              // Подключаем файл настроек из библиотеки RF24
#include <RF24.h>                  // Подключаем библиотеку  для работы с nRF24L01+
#include <Adafruit_NeoPixel.h>

#define stripPin 2       // выход управления светодиодной лентой
#define stripLed 120     // количество светодиодов в ленте
#define bandPass 19      // полосовых фильтров = цветов = групп светодиодов
#define ledDist stripLed/bandPass  // количество светодиодов на цвет
#define LedtoColor 4  // LedtoColor < или = ledDist - количество активных светодиодов на цвет, если у вас пока нет блока питания который тянет всю ленту (как у меня) 

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(stripLed, stripPin, NEO_GRB + NEO_KHZ800);

RF24      radio(9, 10);    // Создаём объект radio   для работы с библиотекой RF24, указывая номера выводов nRF24L01+ (CE, CSN)

const uint32_t PROGMEM
  colorTab[]={
      0xFF0000,0xFF1100,0xFF2200,0xFF3300,0xFF4400,0xFF5500,0xFF6600,0xFF7700,0xFF8800,0xFF9900,0xFFAA00,0xFFBB00,0xFFCC00,0xFFDD00,0xFFEE00,0xFFFF00,  //красный - жёлтый
      0xFFFF00,0xEEFF00,0xDDFF00,0xCCFF00,0xBBFF00,0xAAFF00,0x99FF00,0x88FF00,0x77FF00,0x66FF00,0x55FF00,0x44FF00,0x33FF00,0x22FF00,0x11FF00,0x00FF00,  //жёлтый — зелёный
      0x00FF00,0x00FF11,0x00FF22,0x00FF33,0x00FF44,0x00FF55,0x00FF66,0x00FF77,0x00FF88,0x00FF99,0x00FFAA,0x00FFBB,0x00FFCC,0x00FFDD,0x00FFEE,0x00FFFF,  //зелёный — циан (голубой)
      0x00FFFF,0x00EEFF,0x00DDFF,0x00CCFF,0x00BBFF,0x00AAFF,0x0099FF,0x0088FF,0x0077FF,0x0066FF,0x0055FF,0x0044FF,0x0033FF,0x0022FF,0x0011FF,0x0000FF,  //голубой — синий
      0x0000FF,0x1100FF,0x2200FF,0x3300FF,0x4400FF,0x5500FF,0x6600FF,0x7700FF,0x8800FF,0x9900FF,0xAA00FF,0xBB00FF,0xCC00FF,0xDD00FF,0xEE00FF,0xFF00FF,  //синий — пурпур (маджента)
      0xFF00FF,0xFF00EE,0xFF00DD,0xFF00CC,0xFF00BB,0xFF00AA,0xFF0099,0xFF0088,0xFF0077,0xFF0066,0xFF0055,0xFF0044,0xFF0033,0xFF0022,0xFF0011,0xFF0000}; //маджента — красный
      
typedef union{
    struct {
      uint8_t b,g,r,w;
    };
    uint32_t dw;
} TColor;

typedef union{
    struct {
      uint8_t b0,b1;
    };
    uint16_t w;
} TWord;      

char rfData[32];           // Буфер команды
uint8_t ledPtr = 0;

void setup(){
    // initialize serial:
    Serial.begin(115200);
    strip.begin();
    strip.show(); // Initialize all pixels to 'off'

    radio.begin();                              // Инициируем работу nRF24L01+
//    radio.setAutoAck(false);

    radio.setChannel(5);                        // Указываем канал приёма данных (от 0 до 127), 5 - значит приём данных осуществляется на частоте 2,405 ГГц (на одном канале может быть только 1 приёмник и до 6 передатчиков)
    radio.setDataRate     (RF24_1MBPS);         // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек
    radio.setPALevel      (RF24_PA_HIGH);       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)
    radio.openReadingPipe (1, 0x1234567890LL);  // Открываем 1 трубу с идентификатором 0x1234567890 для приема данных (на ожном канале может быть открыто до 6 разных труб, которые должны отличаться только последним байтом идентификатора)

    radio.startListening  ();                   // Включаем приемник, начинаем прослушивать открытые трубы
}

void loop(){

    if(radio.available()){      // Если в буфере имеются принятые данные, то получаем номер трубы, по которой они пришли, по ссылке на переменную pipe
      radio.read(&rfData, 32);  // Приём команды
      cmdExecute();       
    }
}

void cmdExecute() {
    
    switch (rfData[0]) {
      case 'r': {
        zmu();
        break;
      }
      case 'c':{
        strip.clear(); strip.show(); break;
      }
    }
}


void zmu() {
  TColor cl;
  TWord akk;
  uint16_t r,g,b;
  uint8_t n,i,k,j;

  for(i=0; i<bandPass; i++) {
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
      j=rfData[i+1];
      akk.w = cl.r * j;
      akk.w = akk.b1 * akk.b1; 
      cl.r = akk.b1;
      akk.w = cl.g * j;
      akk.w = akk.b1 * akk.b1; 
      cl.g = akk.b1;
      akk.w = cl.b * j;
      akk.w = akk.b1 * akk.b1; 
      cl.b = akk.b1;
      cl.dw = strip.Color(cl.r, cl.g, cl.b);
      n=i*ledDist;
      for(k=0; k<LedtoColor; k++) strip.setPixelColor(n+k, cl.dw);
  }
  strip.show();
}

У меня 120 светодиодов в ленте, но используются пока 19*4=76. Мой блок питания не тянет больше. Куплю источник питания мощней зажгу все.

Пока есть только цветомузыка, но к новому году постараюсь добавить какие нибудь дополнительные световые эффекты. Новая программа будет доступна по той же ссылке. Работу цветомузыки вы можете посмотреть на видео в конце статьи.

Для работы программы ЦМУ нужно настроить два подключения:
1. к COM порту ПК, порту к которому подключён модуль arduino;
2. к источнику звука.
Работа начинается после нажатия на кнопку старт.

В простейшем случае в качестве источника звука может выступать микрофон ПК или ноутбука. Недостатком данного метода является влияние на цветовую программу внешних звуков и шума.

Второй вариант получение аудио потока непосредственно с музыкального плеера. Для этого необходимо перехватить аудио поток с программы плеера к выходному звуковому устройству (динамикам ПК или звуковому выходу). Для этого можно использовать драйвер и программу «виртуальный аудио кабель». В интернете есть несколько вариантов «виртуального аудио кабеля» и вы можете выбрать подходящий к вашему оборудованию.
Для моей конфигурации потребовался простой «виртуальный аудио кабель» с одним входом и одним выходом.
Я использую «виртуальный аудио кабель» который вы можете скачать по ссылке.
Установите на ПК программное обеспечение «виртуальный аудио кабель». В настройках звуковых устройств ПК выберите выходное звуковое устройство «виртуальный аудио кабель» и установите для него — использовать по умолчанию.

После данной настройки все аудио потоки со всех программ будут направляться на вход «виртуального аудио кабеля». В программе цветомузыки установите в качестве источника звука (звукового устройства) выход «виртуального аудио кабеля».
Окно программы цветомузыки:

Программа ЦМУ готова к работе.

Мой вариант подключения.
У меня аудио ресивер с airplay и проигрыватель я естественно использую c поддержкой airplay ITUNES. Кроме того ITUNES умеет выводить звук одновременно и на аудио ресивер и на ПК как показано ниже

Звуковой поток поступающий на ПК попадает на устройство по умолчанию, то есть на вход «виртуального аудио кабеля», а его выход служит источником звука в программе цветомузыки.
Если вы пользуетесь другим музыкальным плеером и/или у вас нет усилителя или аудио ресивера с airplay вам понадобится «виртуальный аудио кабель» умеющий коммутировать аудио поток на несколько устройств. Один из выходов вы должны подать на ваше выходное звуковое устройство (выход звуковой карты или динамики ПК), а другой должны указать в качестве источника звука в программе цветомузыки.

Третий вариант потребует наличия или изготовления аудио кабеля. Вы можете использовать линейный вход вашей звуковой карты в качестве источника звука в программе ЦМУ. В этом случае вы можете использовать любой внешний источник звука (аудио плеер, MP3 плеер и т.п. ) имеющий линейный выход.

С «виртуальным аудио кабелем» с разветвителем и вариантом изготовления кабеля вам придётся разбираться самим, мне эти варианты не понадобились. Возможно есть другие варианты организации источника звука для программы ЦМУ.

Профиль для установки светодиодной ленты или другой вариант крепления светодиодной ленты выбирается из ваших желаний.

Примеры работы ЦМУ:




Добавил схемы

Добавил скетч для варианта подключения к USB с внешним источником питания 5В (на большое количество светодиодов > 30).

#include <Adafruit_NeoPixel.h>
 
#define ledPin 13       // светодиод на плате arduino
#define stripPin 2      // выход управления светодиодной лентой
#define stripLed 60     // количество светодиодов в ленте
#define bandPass 19     // число полос ЦМУ (используемых светодиодов)
#define ledDist 3       // Число светодиодов на цвет  bandPass*ledDist=3*19 должно быть меньше  stripLed=60
#define LedtoColor 3    // Число активных светодиодов на цвет должно быть меньше или равно ledDist=3

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(stripLed, stripPin, NEO_GRB + NEO_KHZ800);

const uint32_t PROGMEM
  colorTab[]={
      0xFF0000,0xFF1100,0xFF2200,0xFF3300,0xFF4400,0xFF5500,0xFF6600,0xFF7700,0xFF8800,0xFF9900,0xFFAA00,0xFFBB00,0xFFCC00,0xFFDD00,0xFFEE00,0xFFFF00,  //красный - жёлтый
      0xFFFF00,0xEEFF00,0xDDFF00,0xCCFF00,0xBBFF00,0xAAFF00,0x99FF00,0x88FF00,0x77FF00,0x66FF00,0x55FF00,0x44FF00,0x33FF00,0x22FF00,0x11FF00,0x00FF00,  //жёлтый — зелёный
      0x00FF00,0x00FF11,0x00FF22,0x00FF33,0x00FF44,0x00FF55,0x00FF66,0x00FF77,0x00FF88,0x00FF99,0x00FFAA,0x00FFBB,0x00FFCC,0x00FFDD,0x00FFEE,0x00FFFF,  //зелёный — циан (голубой)
      0x00FFFF,0x00EEFF,0x00DDFF,0x00CCFF,0x00BBFF,0x00AAFF,0x0099FF,0x0088FF,0x0077FF,0x0066FF,0x0055FF,0x0044FF,0x0033FF,0x0022FF,0x0011FF,0x0000FF,  //голубой — синий
      0x0000FF,0x1100FF,0x2200FF,0x3300FF,0x4400FF,0x5500FF,0x6600FF,0x7700FF,0x8800FF,0x9900FF,0xAA00FF,0xBB00FF,0xCC00FF,0xDD00FF,0xEE00FF,0xFF00FF,  //синий — пурпур (маджента)
      0xFF00FF,0xFF00EE,0xFF00DD,0xFF00CC,0xFF00BB,0xFF00AA,0xFF0099,0xFF0088,0xFF0077,0xFF0066,0xFF0055,0xFF0044,0xFF0033,0xFF0022,0xFF0011,0xFF0000}; //маджента — красный

typedef union{
    struct {
      uint8_t b,g,r,w;
    };
    uint32_t dw;
} TColor;

typedef union{
    struct {
      uint8_t b0,b1;
    };
    uint16_t w;
} TWord;

char inStr[64];       // a string to hold incoming data
char rcvString[64];   // a string to hold incoming data
uint8_t inCounter = 0;
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  Serial.begin(115200);
  // reserve 32 bytes for the inputString:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    stringComplete = false;
    compare();
    rcvString[2]=0;
    Serial.println(rcvString);
 }
}

void compare() {
    
    switch (rcvString[0]) {
      case 'r': {
        zmu();
        break;
      }
      case 'c':{
        strip.clear();
        strip.show();
        break;
      }
    }
}


//  SerialEvent
void serialEvent() {
  uint8_t i;
  
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    if (inChar != char(254)) {
     inStr[inCounter++] = inChar;
     if (inChar == char(255)) {
       i=0;
       while (inStr[i]!=char(255)) {
         rcvString[i]=inStr[i];
         i++;
       }
       rcvString[i]=inStr[i];
       stringComplete = true;
       inCounter = 0;          // clear the input string:
     }
    } else inCounter = 0;      // clear the input string: 
  }
}

void zmu() {
  TColor cl;
  TWord akk;
  uint8_t n,i,k,j;

  for(i=0; i<bandPass; i++) {
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
      j = rcvString[i+1];
      akk.w = cl.r * j;
      akk.w = akk.b1 * akk.b1; 
      cl.r = akk.b1;
      akk.w = cl.g * j;
      akk.w = akk.b1 * akk.b1; 
      cl.g = akk.b1;
      akk.w = cl.b * j;
      akk.w = akk.b1 * akk.b1; 
      cl.b = akk.b1;
      cl.dw = strip.Color(cl.r, cl.g, cl.b);
      n=i*ledDist;
      for(k=0; k<LedtoColor; k++) strip.setPixelColor(n+k, cl.dw);
  }
  strip.show();
}


Заключительная версия программы.
Добавить в избранное +153 +303
+
avatar
  • ksiman
  • 21 ноября 2017, 17:49
+41
Сильно не ругайте.
Не очень-то и хотелось :)
+
avatar
  • maxudl
  • 21 ноября 2017, 17:52
+8
Ёмко, талантливо, спасибо.
+
avatar
  • -kan-
  • 21 ноября 2017, 17:53
+4
Молодец. Дешево и сердито:-))
+
avatar
  • DJV
  • 21 ноября 2017, 17:53
+6
Да все восхитительно ;))

За что тут ругать?

Молодец!

*задумался*
+
avatar
  • aspok
  • 21 ноября 2017, 17:55
+14
Хороший обзор. Аж самому сделать руки зачесались. Такое бы да на дискотеку в 80-х… Это тебе не мигающие лампы на стартёрах.
+
avatar
+7
A ку202?
Стоящий обзор. Тоже руки зачесались сделать, к томуже всё имеется и смонтировано.
Я забабахал подсветку в карниз и со смартфона управляю ею, там разные цвета и прочее, надо бобавить микрофон и подправить код.
Обзор хороший,
+
avatar
  • asdfgh
  • 21 ноября 2017, 19:09
+9
А у КУ202 буквы Н в конце не хватает…
+
avatar
  • aspok
  • 21 ноября 2017, 19:30
+12
Неееее. С тиристорамы это уже другой уровень. Со стартёрами от дневных ламп всё гораздо проще. Стартёру на выходы припаивался кондёр на 10мкФ и эта конструкция последовательно в цепь с простой лампой накаливания. Такая хрень конечно к музыке вообще никакого отношения не имела, просто лихорадочно мигала в такт попавшего под напряжение неумелого электрика. Ессесенно таких конструкций, с разным цветом ламп, было несколько. На школьном дискаче прокатывало на ура!
+
avatar
+1
я делал на тиристорах с 40вт лампами и главное — цветными стеклянными колпаками
сейчас нигде такого не найти
+
avatar
  • yualeks
  • 21 ноября 2017, 23:36
+2
Тогда легко было достать стеклянные палочки диаметром 3мм, вот из них я набирал экран.Получались обалденные цветовые переходы а лампы красил цапоном.
+
avatar
+1
так сейчас есть оргстеклянные палочки
правда я первый раз слышу про такой экран
+
avatar
0
В ЮТ или его приложении была статья про разные способы изготовления экранов. Еще один — засыпать битого автомобильного стекла между двух листов оконного стекла. ( в наши дни это проблемно)
+
avatar
  • tedbeer
  • 22 ноября 2017, 16:15
0
Ага! Помню еще рецепт с покрытием стекла клеем с квасцами. После высыхания обещали образование на стекле узора типа морозного.
+
avatar
0
вот про битое стекло помню, только чего проблематичного в наши дни? нет битых стекол что ли?
+
avatar
0
первый раз слышу про такой экран
Один ряд палочек шел вертикально, второй — горизонтально.
+
avatar
0
у меня был подобный экран из оргстекла или поликарбоната, только там рифление было мелкими квадратиками
что-то типа такого с таким же эффектом
cccr.listbb.ru/viewtopic.php?p=3526&sid=3b44042d5e990f84fd49dd5afbb10718#p3526

только это был заводской конструктор
+
avatar
+1


вот такой вот точно было экран и лампочки на 13в с цветными колпаками
экран не впечатлил и его яркость
+
avatar
  • Leoniv
  • 27 ноября 2017, 09:05
+1
Экран — это не то. Это тогда было в диковинку. А сейчас огромный экран есть в каждом доме (телевизор), достаточно сделать цветомузыко с выходом HDMI и можно рисовать что угодно. Но это не то. Настоящая цветомузыка должна иметь отдельные цветные фонари, а не экран или ленту.
+
avatar
0
а смешение цветов в се равно надо делать на экране
так что либо потолок, либо тюль какая на окне или матовое оргстекло с подсветкой в торец

с фонарями сейчас как раз все просто
+
avatar
  • AnnaSun
  • 27 ноября 2017, 20:57
-1
Old School:))))))))))))))))))))

+
avatar
0
что за фонари такие? не из икеи часом?

вот какая штука еще была не выпущена
forum.astrakhan.ru/topic/73205-%D0%B0%D1%83%D0%B4%D0%B8%D0%BE%D1%82%D0%B5%D1%85%D0%BD%D0%B8%D0%BA%D0%B0-%D1%81%D1%81%D1%81%D1%80/?page=2&tab=comments#comment-1470969

дизайн мегакрутой просто
+
avatar
  • kiv69
  • 30 ноября 2017, 10:17
0
Эти палочки шли для изготовления ламп накаливания, сам такие собирал в отходах производства лампового завода.
Поскольку ламповый завод в советские времена этих палочек выкидывал немеряно, все делали цветомузыку из них, изредка встречающиеся конструкции без них вызывали недоумение и мысли о криворукости изготовителя.
Экран получается действительно обалденным, особенно если там 3-4 слоя палочек.
+
avatar
  • NoViY
  • 21 ноября 2017, 17:58
0
Такой проект можно и на поток поставить — главное правильно продажу организовать!
+
avatar
  • DDimann
  • 21 ноября 2017, 18:10
0
Вполне.
+
avatar
  • DimaDSP
  • 21 ноября 2017, 18:10
+1
Благодарю! Очень понравилось!
+
avatar
+1
Елки не хватает. Гирлянда есть.
+
avatar
  • nochkin
  • 21 ноября 2017, 18:35
+1
Я делал нечто похожее для ёлки на Teensy. Только там бегущие огни были. Ленту брал с индивидуальными огнями, она как раз как гирлянда подходит.
+
avatar
  • Kha_
  • 21 ноября 2017, 18:15
+1
Крутотень!
+
avatar
  • mass
  • 21 ноября 2017, 18:17
+1
Крутотень!
Неистово плюсую.
+
avatar
+1
Молодец! Плюс однозначно.
+
avatar
  • heckby
  • 21 ноября 2017, 18:31
+6
+
но хочется такое же только чтоб звук с аудиовыхода брало, никто не видел?
+
avatar
+3
присоеденяюсь.
И чего минусить. не понятно… ( обнулил )
+
avatar
  • Plintus
  • 21 ноября 2017, 19:55
0
На радиокоте, возможно, скоро будет — radiokot.ru/circuit/light/run/83/
+
avatar
  • rx3apf
  • 21 ноября 2017, 20:43
+2
Гляньте «Радиохобби» 4/2008. Но это без WS2812.

На первый взгляд ничего особо сложного все запихать в микроконтроллер нет. Для управления WS2812 вовсе не требуется сожрать практически 100% CPU, как это сейчас обычно делают. Незначительное усложнение (1 корпус 74HC74), и накладные расходы на загрузку ленты сокращаются до этак 10...15% (при 16 MHz тактовой, ATmega). Дальше берем какой-нибудь малозатратную реализацию спектроанализатора и все ограничивается лишь фантазией. И свободным временем, к сожалению…
+
avatar
0
Я делал на 328р инвертированием выхода USART (на одном полевике) и прерываниях (на ассемблере, конечно). В итоге выводил 8-битный цвет (жестко заданная в PM 24-битная палитра на 256 цветов) на 600 светодиодов 50 «кадров» в секунду, и занимало это 49.3% тактов процессора на частоте 16 МГц. Из плюсов — прерывания разрешены и можно было работать с остальными устройствами. Из минусов — были заняты регистры R2-R11, что, скорее всего, не позволяет применять такое решение совместно с каким-либо С компилятором (только асм).
Можно было выводить и 24-битный цвет (даже быстрее получалось), но 1800 байт из 2048 были заняты «экраном», что не оставляло места для какой-либо программы управления этим «экраном». Да и с учетом гаммы 2.2 и баланса белого, там получается по 4 реальных бита на каждый цвет максимум.
+
avatar
  • rx3apf
  • 27 ноября 2017, 23:17
0
Все можно сделать эффективнее. Первоначально я попробовал «склеить» выход USART в режиме SPI (доступный в более свежих кристаллах) и таймер, но возникли некоторые сложности с взаимосинхронизацией (есть неприятная особенность делителя baudrate). Но потом сообразил — сделал просто два одновибратора на 74HC74, на 400 и 800 ns, и их выходы объединил диодным «ИЛИ». Собственно загрузка жрет где-то менее 10% CPU, а вот с палитрой, разворачивая 8-битный код цвет+яркость в 24 бит RGB, немножно больше (поскольку не по таблице, получается накладно). Никаких ограничений по регистрам, прерывания раскрыты большую часть времени, ресурсов должно бы и на FFT хватить.
+
avatar
0
А чем запускаете одновибраторы?
Собственно загрузка жрет где-то менее 10% CPU
Это при каком количестве диодов и какой частоте вывода информации на них?
+
avatar
  • rx3apf
  • 28 ноября 2017, 00:54
+1
Клоком USART/SPI. 400 ns — генерирует всегда, 800 ns — когда передается «1», т.е. он берет данные от выхода USART.

А расходы — посчитал на собственно время загрузки ленты. 300 шт — примерно 9 ms, т.е. из можно обновлять больше 100 раз в секунду. 600 — соответственно вдвое реже. Сейчас глянул код — не, пожалуй слегка приврал, если гнать готовые 24 бита, что скорее 20% (16 MHz тактовой), а перекодировка палитры и еще добавит, так что будет ближе к 30%. Но это если непрерывно грузим цепочку, без пауз.
+
avatar
0
Интересное решение. Да, 50 раз в секунду 600 диодов — это практически в непрерывном режиме, ограничение самого протокола. У меня это занимает 50%, у вас — в два раза меньше.
У меня еще был код параллельного вывода сразу на 5 линий, он как раз занимал менее 20% при 600 диодах, не использовал аппаратных последовательных контроллеров, не требовал вообще никаких внешних активных деталей, но и не был совместим с прерываниями, поэтому практического применения тоже не нашел.
+
avatar
  • sav13
  • 22 ноября 2017, 05:22
0
Берете любой анализатор спектра на ардуине и прикручиваете вместо «баров» спектра цвета в ленте
+
avatar
  • ro70
  • 21 ноября 2017, 18:32
+5
Вот если бы без ПК, вообще было бы красота…
+
avatar
+3
«никаких» пишется слитно.
+
avatar
+3
Класная вещь, если бы она работала от стандартного аудио выхода — цены бы ей не было. ( я бы даже и купил )
два плюса ушло.
+
avatar
+1
Можно и так сделать, я находил скетчи с работой просто от линейного выхода и от микрофона, пробовал делать от микрофона, реакция не понравилась, а от линейного не стал делать, хотел автономную.
+
avatar
  • weds
  • 21 ноября 2017, 18:42
0
а можно глупый вопрос? Сильно ли будут деградировать LEDы в таком режиме в отличии от постоянного включения?
+
avatar
+1
не будут, с чего бы им деградировать?
+
avatar
  • juraspb
  • 21 ноября 2017, 19:15
0
Это нормальный режим работы светодиодов. Яркость каждого из R, G, B светодиодов регулируется с помощью ШИМ, этим задаётся цвет и яркость свечения. При постоянной яркости и цвете скважность постоянна. При изменении яркости или цвета меняется скважность на одном, двух или всех светодиодах и только.
+
avatar
0
неправильный экран все портит, 3 цвета должны светить в одну точку на белом фоне, чтобы смешиваться и образовывать остальные цвета

тут собственно такие светодиоды и не нужны, достаточно мелкасхемы для частотного фильтра и контроллера для шима на 4 канала, хотя мелкасхема раскладывает на 7 каналов и стоит в музцентрах для анализатора спектра
+
avatar
+13
+
avatar
+10
Мне кажется это немного разные режимы цветомузыки, в статье спектр похоже рисуется, тут на тыц-тыц завязано как-то.
+
avatar
+5
Ага, у ТС гораздо красивей, на северное сияние похоже.
+
avatar
  • Rokko
  • 21 ноября 2017, 20:56
0
У Дисколюкса есть похожее. Но цена не радует.
+
avatar
+2
Взгляните повнимательнее на фото выше )
+
avatar
  • Rokko
  • 22 ноября 2017, 16:20
0
На что взглянуть Арсений?
+
avatar
0
Это как бы на базе Discolux и собрано
+
avatar
+6
да оно и так могёт…
+
avatar
+10


самое смотрибельное из всех экранов
+
avatar
0
Давно еще -лет как пять назад находил это видео от дисколюкса, адекватнее цветомузыки не видел, но ценник совсем не радует.
+
avatar
0
дык ручная работа в единичных экземплярах
+
avatar
  • katran
  • 23 ноября 2017, 01:55
+1
и ценик за комплект ??
+
avatar
  • Bald
  • 21 ноября 2017, 19:09
+2
Отлично! Где то видел спектро-анализатор на ардуина. Думал на его основе цветомузыку сделать, но пока только в планах. За это плюс!
+
avatar
  • fps
  • 21 ноября 2017, 19:10
+3
Для управления лентой я написал программу для ПК. Ссылка для скачивания программы. Программа не имеет ограничений и может использоваться в личных целях всеми желающими.
Очень интересно было бы увидеть её исходник, а не только скетчи для ардуинок.
+
avatar
  • SERG27
  • 21 ноября 2017, 19:11
+1
ни каких 220В, ни каких тиристоров, симисторов и т.п…
ну. конечно-
модуль arduino по командам из программы.
куда уж проще… я ох… дорогая редакция. :)
+
avatar
  • paaevv
  • 21 ноября 2017, 19:11
0
Молодчина.
Если можно, схемку подключения всех модулей (Структурную).
Модули уже заказал.
Делаем в школу на Новый год.
Спасибо.
+
avatar
  • juraspb
  • 22 ноября 2017, 12:01
+1
Добавил схемы.
+
avatar
  • muzgaz
  • 21 ноября 2017, 19:13
0
Можно ли применить светодиодную ленту WS2812B из 60 светодиодов, нужно ли править скетч.
+
avatar
  • juraspb
  • 21 ноября 2017, 19:24
0
Если непосредственно к USB порт не потянет.
Для второго варианта
#define stripLed 60 // количество светодиодов в ленте
#define bandPass 19 // полосовых фильтров = цветов = групп светодиодов
#define ledDist stripLed/bandPass // количество светодиодов на цвет
#define LedtoColor ledDist
+
avatar
  • muzgaz
  • 21 ноября 2017, 19:34
0
Спасибо за информацию попробую изменить скетч.
+
avatar
0
У вас же белым цветом она и не горит никогда.
У меня всякие радуги на 288 светиков работали от 1,5 А зарядника от телефона, плюс ещё плисина от этого же питания работала…
+
avatar
  • vismyk
  • 21 ноября 2017, 19:14
+2
Мне медведь все уши оттоптал, но и то мне мерещится, что лента не по-русски висит: высокие частоты вроде слева, а низкие справа. Не по феньшую. ;) Или я что-то путаю?
За песню «Овощевоз» отдельное спасибо! ;)
+
avatar
0
Не по феньшую. ;)
Согласен., но красиво и похоже на настоящую цветомузыку а не световые эффекты под ритм.
Плюсую…
+
avatar
  • Varicap
  • 21 ноября 2017, 21:17
+3
Верно, я тоже заметил некоторе несоответствие.

Инфа из прошлого столетия о соответствии цветов частотам в ЦМУ:
ВЧ — синий
СЧ1 — зеленый
СЧ2- желтый
НЧ — красный
фон (отсутствие сигнала) — белый
+
avatar
  • Brs
  • 21 ноября 2017, 19:18
0
Спасибо, самому тоже захотелось сделать так! Просто и эффектно
+
avatar
  • krasoff
  • 21 ноября 2017, 19:28
0
А если питание внешнее добавить, для первого варианта (от компа) — нужно просто увеличить число 19 до необходимого числа диодов (кратному 19)?
+
avatar
  • juraspb
  • 21 ноября 2017, 21:10
0
Нужно заменить подпрограмму zmu(), взять из второго варианта

void zmu() {
  TColor cl;
  TWord akk;
  uint16_t r,g,b;
  uint8_t n,i,k,j;

  for(i=0; i<bandPass; i++) {
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
      j=rfData[i+1];
      akk.w = cl.r * j;
      akk.w = akk.b1 * akk.b1; 
      cl.r = akk.b1;
      akk.w = cl.g * j;
      akk.w = akk.b1 * akk.b1; 
      cl.g = akk.b1;
      akk.w = cl.b * j;
      akk.w = akk.b1 * akk.b1; 
      cl.b = akk.b1;
      cl.dw = strip.Color(cl.r, cl.g, cl.b);
      n=i*ledDist;
      for(k=0; k<LedtoColor; k++) strip.setPixelColor(n+k, cl.dw);
  }
  strip.show();
}

и добавить количество светодиодов на цвет LedtoColor.
Например 3:
#define ledDist stripLed/bandPass // количество led на цвет для данной ленты
#define LedtoColor 3 // всего светодиодов 3*19=57
LedtoColor должно быть меньше или равно ledDist = stripLed/bandPass
+
avatar
  • juraspb
  • 22 ноября 2017, 09:55
0
8 строчку в листинге zmu()
j=rfData[i+1];
надо заменить на
j=rcvString[i+1];
так как входной массив в первой версии имеет другое имя.
+
avatar
  • dansar
  • 21 ноября 2017, 19:37
0
Использовал VirtualAudioCable, что бы распаралелить звук, идущий на HDMI и наушники. Не понравилось, что идёт небольшая задержка между источником звука и выводом его на выход.
+
avatar
0
А есть ли простая реализация для подобной ленты на ESP, классно было бы просто подсветить окно и запитать от павербанка, а по wifi сделать смену режимов… уверен что есть подобные, но поиски пока не увенчались успехами
+
avatar
0
если не нужно хитрых режимов, то не проще взять простую ргб ленту с контроллером и запитать например от аккума от упса?
+
avatar
0
Автор-молодец, а можно сделать такой расклад:
красный-зеленый-синий-зеленый-красный (типа симметрично, думаю будет красиво)
+
avatar
0
Если симметрию вводить, то надо стерео делать…
+
avatar
  • McCay
  • 21 ноября 2017, 20:47
0
здравствуйте. кто-нибудь знает как проверить работоспособность WS2812B? не подключая к ардуино.
+
avatar
+3
Вот, без ардуин )))
mySKU.me/blog/aliexpress/49938.html
+
avatar
  • ABATAPA
  • 21 ноября 2017, 20:51
0
Хороший троллинг. :) Ну а вдруг?! :)
+
avatar
  • ABATAPA
  • 21 ноября 2017, 20:52
0
Купить там же модуль управления лентами 2812b.
+
avatar
  • ABATAPA
  • 21 ноября 2017, 20:51
+1
Заказал с десяток лотов лент и модулей на проводе sk6812 и 2812b.
Вот такие хороши как гирлянда:
+
avatar
+1
Они какими-то неизолированными выглядят… Я брал 2811 которые микросхемка с диодами в пластиковых колпачках засиликоненых.
+
avatar
  • ABATAPA
  • 21 ноября 2017, 21:12
+1
Такие тоже есть. Они слишком большие.
Для них купил линзы-рассеиватели (менее $2 за 100), ими прикрою. Пайку и обратную сторону можно обработать «Plastik 71».
Зато уже распаяно, похоже на гирлянду и отлично управляется.
+
avatar
+1
Полез искать фотку своих

и нашёл вот какие: aliexpress.com/item/50Pcs-Black-Wire-DC5V-WS2811-with-3pin-JST-connectors-Dream-Color-RGB-Strings-Node-LED-Pixels/32219637999.html

Наверное можно и с прозрачными проводами найти.
+
avatar
  • aspok
  • 21 ноября 2017, 21:46
0
Действительно, можно



+
avatar
  • ABATAPA
  • 21 ноября 2017, 21:57
0
Они слишком большие. Первые у меня, как я уже сказал, есть. Они все одинаковые, как с одного пресса.
+
avatar
  • Hegy
  • 21 ноября 2017, 22:03
0
линзы-рассеиватели

Можно ссылку?
+
avatar
  • ABATAPA
  • 21 ноября 2017, 22:14
+1
Это аукцион eBay.

Ищите «5050 SMD LEDS»
Вот пример:
ebay.com/itm/142286663718
+
avatar
  • chaloc
  • 21 ноября 2017, 22:06
+1
Прозрачную термоусадку нарезать сантиметровыми кусками, надеть на провод и усадить. Дешево, быстро, просто.
Если будет матовая — вместо светорассеивателя будет работать.
+
avatar
  • dimmm84
  • 22 ноября 2017, 00:02
0
Так они и дороже прилично.
+
avatar
  • VladM
  • 21 ноября 2017, 21:36
+7
В моё время для хорошей цветомузыки делались 4 канала — 4-й фоновый горел, когда основные не светились, и не давал уставать глазам от резких вспышек…
+
avatar
  • AnnaSun
  • 21 ноября 2017, 21:38
+4
Я тоже собираю свой вариант, с использованием аутентичных советских материалов:))))))))))
+
avatar
  • AnnaSun
  • 22 ноября 2017, 12:34
+6
:))))))))))))))))))))))))))))))))))))

+
avatar
  • AnnaSun
  • 24 ноября 2017, 14:26
+2
V 2.0 :)))))))))))))))))))))))))))))))

+
avatar
  • 56RUS
  • 21 ноября 2017, 21:50
+1
У ТС потолок шпаклеванный вроде, на натяжном эффект круче был бы наверное.
Прочитал обзор полностью, ни фига не понял но понравилось.
Закинул темку в закладки, руки дойдут скопирую может.
Единственно напрягает привязка к ПК. Обычный аудио вход не помешал бы.
+
avatar
0
за натяжным потолком эффект рассеивания и мягкости цветов был бы гораздо круче.
+
avatar
0
aliexpress.com/item/Hot-Style-18-RGB-LED-Stage-Light-Disco-DJ-Bar-Effect-UP-Lighting-Show-DMX-Strobe/32638684704.html
вот готовое с дмх512 управлением, есть прога dmxcontrol, там есть модуль светомузыки
надо только купить дмх радиомодули или адаптер

вот сравнение
www.youtube.com/watch?v=HqWMQ5E9d4g
+
avatar
+1
мне кажется, или у ТС RGB программируемые диоды используются как простые одноцветные? какой тогда в них смысл? ту же линейку можно было слепить и обычными разноцветными диодами, разделенными на несколько групп…
+
avatar
-1
Автор же сказал, что не хотел усложнять схему делать кучу проводов, ставить транзисторы на каждую группу и т.п. У ардуины то и 57 шим ножек наверное нету…
+
avatar
0
Все что вы написали (транзисторы на каждую группу и т.п.) для ленты WS2812B не требуется — у нее в каждом светодиоде уже встроен собственный ШИМ-контроллер и все это дело управляется по одному единственному проводу. Независимое управление цветом и яркостью каждого светодиода осуществляется с одного цифрового пина ардуины.
+
avatar
  • KaDaBRa
  • 22 ноября 2017, 00:34
0
Но никто не мешает автору доработать алгоритм, и сделать какие угодно цвета. А можете взять и под себя доработать скетч Правда ведь ?:)
+
avatar
0
Собрал вариант номер один (напрямую к USB). Подключил «виртуальный аудио кабель», подключил ленту на 19 диодов
и изменил параметры stripLed:
#define stripLed 19 // количество светодиодов в ленте.

Итог: Не работает как положено моргают все 19 диодов на красный спектр (в ритм басов).
Может автор подскажет- какие еще нужно сделать изменения в программе?
+
avatar
  • juraspb
  • 22 ноября 2017, 10:03
+1
Извините, при переносе потерял строку.
Вставьте строку
cl.dw = strip.Color(cl.r, cl.g, cl.b);
перед
strip.setPixelColor(n+k, cl.dw);
Получится код.

void zmu() {
  TColor cl;
  TWord akk;
  uint8_t n,i,k;

  for(i=0; i<bandPass; i++) {
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
      akk.w = cl.r * rcvString[i+1];
      akk.w = akk.b1 * akk.b1; 
      cl.r = akk.b1;
      akk.w = cl.g * rcvString[i+1];
      akk.w = akk.b1 * akk.b1; 
      cl.g = akk.b1;
      akk.w = cl.b * rcvString[i+1];
      akk.w = akk.b1 * akk.b1; 
      cl.b = akk.b1;
      cl.dw = strip.Color(cl.r, cl.g, cl.b);
      strip.setPixelColor(i, cl.dw);
  }
  strip.show();
}

Основной исходник подправил.
+
avatar
0
Ничего не изменилось работает так же.
Вот Ваш новый код, изменен только > #define stripLed 19.
Проверьте у себя свой код с #define stripLed 19…

#include <Adafruit_NeoPixel.h>
 
#define ledPin 13       // светодиод на плате arduino
#define stripPin 2      // выход управления светодиодной лентой
#define stripLed 19     // количество светодиодов в ленте
#define bandPass 19     // число полос ЦМУ (используемых светодиодов)

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(stripLed, stripPin, NEO_GRB + NEO_KHZ800);

const uint32_t PROGMEM
  colorTab[]={
      0xFF0000,0xFF1100,0xFF2200,0xFF3300,0xFF4400,0xFF5500,0xFF6600,0xFF7700,0xFF8800,0xFF9900,0xFFAA00,0xFFBB00,0xFFCC00,0xFFDD00,0xFFEE00,0xFFFF00,  //красный - жёлтый
      0xFFFF00,0xEEFF00,0xDDFF00,0xCCFF00,0xBBFF00,0xAAFF00,0x99FF00,0x88FF00,0x77FF00,0x66FF00,0x55FF00,0x44FF00,0x33FF00,0x22FF00,0x11FF00,0x00FF00,  //жёлтый — зелёный
      0x00FF00,0x00FF11,0x00FF22,0x00FF33,0x00FF44,0x00FF55,0x00FF66,0x00FF77,0x00FF88,0x00FF99,0x00FFAA,0x00FFBB,0x00FFCC,0x00FFDD,0x00FFEE,0x00FFFF,  //зелёный — циан (голубой)
      0x00FFFF,0x00EEFF,0x00DDFF,0x00CCFF,0x00BBFF,0x00AAFF,0x0099FF,0x0088FF,0x0077FF,0x0066FF,0x0055FF,0x0044FF,0x0033FF,0x0022FF,0x0011FF,0x0000FF,  //голубой — синий
      0x0000FF,0x1100FF,0x2200FF,0x3300FF,0x4400FF,0x5500FF,0x6600FF,0x7700FF,0x8800FF,0x9900FF,0xAA00FF,0xBB00FF,0xCC00FF,0xDD00FF,0xEE00FF,0xFF00FF,  //синий — пурпур (маджента)
      0xFF00FF,0xFF00EE,0xFF00DD,0xFF00CC,0xFF00BB,0xFF00AA,0xFF0099,0xFF0088,0xFF0077,0xFF0066,0xFF0055,0xFF0044,0xFF0033,0xFF0022,0xFF0011,0xFF0000}; //маджента — красный

typedef union{
    struct {
      uint8_t b,g,r,w;
    };
    uint32_t dw;
} TColor;

typedef union{
    struct {
      uint8_t b0,b1;
    };
    uint16_t w;
} TWord;

char inStr[64];       // a string to hold incoming data
char rcvString[64];   // a string to hold incoming data
uint8_t inCounter = 0;
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  Serial.begin(115200);
  // reserve 32 bytes for the inputString:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    stringComplete = false;
    compare();
    rcvString[2]=0;
    Serial.println(rcvString);
 }
}

void compare() {
    
    switch (rcvString[0]) {
      case 'r': {
        zmu();
        break;
      }
      case 'c':{
        strip.clear();
        strip.show();
        break;
      }
    }
}


//  SerialEvent
void serialEvent() {
  uint8_t i;
  
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    if (inChar != char(254)) {
     inStr[inCounter++] = inChar;
     if (inChar == char(255)) {
       i=0;
       while (inStr[i]!=char(255)) {
         rcvString[i]=inStr[i];
         i++;
       }
       rcvString[i]=inStr[i];
       stringComplete = true;
       inCounter = 0;          // clear the input string:
     }
    } else inCounter = 0;      // clear the input string: 
  }
}

void zmu() {
  TColor cl;
  TWord akk;
  uint8_t n,i,k;

  for(i=0; i<bandPass; i++) {
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
      akk.w = cl.r * rcvString[i+1];
      akk.w = akk.b1 * akk.b1; 
      cl.r = akk.b1;
      akk.w = cl.g * rcvString[i+1];
      akk.w = akk.b1 * akk.b1; 
      cl.g = akk.b1;
      akk.w = cl.b * rcvString[i+1];
      akk.w = akk.b1 * akk.b1; 
      cl.b = akk.b1;
      cl.dw = strip.Color(cl.r, cl.g, cl.b);
      strip.setPixelColor(i, cl.dw);
  }
  strip.show();
}

+
avatar
  • juraspb
  • 22 ноября 2017, 15:29
0
У меня работает корректно. Уровень громкости по каналу к которому подключена ЦМУ уменьшите. Вероятно уровень очень высокий.
+
avatar
0
Нет, уровень громкости не влияет…
У меня работает корректно
Проверяли напрямую от USB?
На 19 диодов?
+
avatar
0
Разобрался- мой косяк в монтаже, извините за беспокойство.
Но, с «виртуальным аудио кабелем» не могу разобраться- звук или в динамики, или на светодиоды, одновременно не получается.
+
avatar
  • Fedor
  • 22 ноября 2017, 12:46
0
Круто!
Но все же мне кажется побаловаться несколько раз.
Тут была тема, как делали амбилайт с помощью ардуино на ТВ.
Тоже сделал, но посмотрел пару фильмов и снял.

Плюсанул!
+
avatar
0
А можно сделать автостарт программы в приложении (не автозапуск в винде, а после запуска чтоб не нажимать кнопку Старт)?
+
avatar
  • juraspb
  • 23 ноября 2017, 20:17
+1
В новой программе нет кнопки старт. Смотрите новый обзор. Я сегодня его опубликовал.
+
avatar
  • sepulka
  • 26 ноября 2017, 00:27
0
Огромное спасибо!
Отличная статья!
Как раз под «Новый Год».
Буду делать!
+
avatar
  • loltuz
  • 26 ноября 2017, 00:55
+1
скачал, попробовал:
Прошу прощения за негатив, но опишу как есть:
— гемор с настройкой захвата звука (у меня по цифре идет на ресивер),
— тормознутая программа в которой кстати отсутствует кнопка СЕРНУТЬ
— Нету регулировки чувствительности или яркости, ибо есть сильная зависимость от громкости, а это дико неудобно.

Но это все мелочи, самое главное: музыка и свет живут своей жизнью. На хорошие басовые удары толком нету отклика какой-то группы светодиодов. Вроде все мерцает, но соотнести это с ритмом никак не получается. Запустил генератор синуса, так там на определенных частотах начинает мерцать вся линейка, причем по разному:
21Hz — мерцает где то посередине и в правой части линейки (я то думал слева низкие частоты, справа высокие)
на 50 вообще вся горит в пол накала и ничего не моргает, при этом на 49 и 51 плавно расходится туда-сюда одинаково в режиме двутавр и радуга, короче дальше даже описывать не буду, нету соответствия частотам от слова совсем. И в музыке так же.

До упомянутого DiskoLux как до луны, правда последний стоит как лунный камень.
Да, знаю что заминусите, но какая то фигня а не светомузыка, хотя автор молодец, я и такое не способен создать ;)
+
avatar
  • juraspb
  • 26 ноября 2017, 08:49
+3
В программе есть кнопочка тест(работает до момента старта) по ней прогоняется синус программный от 40 до 22000 Гц. БПФ работает корректно.
Уровень входного сигнала уменьшите. Если у вас сигнал входит в ограничение это даёт резкие фронты с широким спектром. Регулировки усиления в программе нет. Кнопочку свернуть добавлю, но для программы из второй части статьи. Может за счёт большого числа полос нет явно выраженных привязок к инструментам (барабанам) мало светиков на красный. Объедините выходы как вам надо или сделайте разное количество светиков на разные части спектра. Я весь проект написал за четыре дня и дал вам инструмент. Составление цветовых программ естественно займёт намного больше времени. И я надеюсь что если этим будут заниматься несколько человек, читателей муськи, и выкладывать свои удачные цветомузыкальные программы, то каждый подберёт себе такие программы какие нужны ему. Но писать их надо для ардуино что достаточно просто даже для не имеющих профессионального образования в области программирования и спектрального анализа. Я писал статью для тех кто хочет что то аналогичное сделать для себя, но в силу отсутствия знаний и опыта не мог этого сделать. Теперь это будет сделать намного проще.
+
avatar
  • loltuz
  • 26 ноября 2017, 12:04
0
Возможно в целом я немного резковато отозвался :) Тестировал как раз 2 часть программы, там такой копки нету. С уровнем сигнала я по разному экспериментировал, сложно поймать, тем более громкость я на ПК регулирую, прям совсем не удобно :(
Эх, попробую конечно с привязками разобраться, но тяжко будет…
Еще такой вопрос: В программе AmbiBox можно добавлять Плагины, не проще было туда это запихнуть? (Я не программист, по этому не знаю разницы)
+
avatar
  • juraspb
  • 26 ноября 2017, 16:04
+1
У каждой программы свой интерфейс и с ним надо разбираться. Изучать его ради цветомузыки я не готов. Времени на это уйдёт много. Не все интерфейсы хорошо описаны. С какой нибудь мелочью можно убить неделю, а то и месяц пока не поймёшь почему не работает. В отзывах товарищ на MSGEQ7 так завис, а дело может потом оказаться в какой то мелочи. Я пишу на том что хорошо знаю, что бы не терять время на мелочах.
Основная цель всех моих работ заинтересовать моего ребёнка. Смотреть на ютубе Галилео, про машины, про технические новинки и т.п. ему нравится, а что то делать сам не хочет. Надо оторвать его от планшета.
+
avatar
  • juraspb
  • 26 ноября 2017, 20:30
+1
Подправил. Теперь в версии 2 уровень сигнала в цветомузыкальных программах можно ползунком регулировать. И цвет ленты кликом по соотв. цвету индикаторов включается.
+
avatar
0
добрый день, у меня программа CMU пишет «соединение не установлено», порт в настройках стоит верный, скетчи грузятся через ардуино IDE, может подскажите решение. Вариант установки через кабель USB, виртуальный кабель установлен
+
avatar
  • juraspb
  • 30 января 2018, 22:06
+1
Если COM установлен правильно (скетчи грузятся по этому же порту) всё должно работать. Может у вас программа уже запущена? В трее посмотрите.
Версию новую скачайте.
+
avatar
  • juraspb
  • 30 января 2018, 22:10
+2
И про аудио подключение почитайте.

mySKU.me/blog/diy/59692.html
+
avatar
  • sttepir
  • 04 декабря 2018, 06:03
0
Простите, вопрос от начинающего. 12 вольтовую ленту с внешнем питанием можно использовать? 60 диодов / метр. И есть ли ограничение во ко-ву диодов в ленте?
+
avatar
  • juraspb
  • 04 декабря 2018, 19:53
0
Максимальное количество светодиодов 240. Можно включать ленты параллельно. Например 2х240 или 3x240. Мне больше нравится 120. При 240 некоторые динамические программы кажутся слегка затянутыми, пока по всем элементам пробежит.
По вашей ленте, не зная типа ленты, ничего сказать не могу. У меня нет и не было 12В лент, однозначно надо будет что-то городить, минимум согласование.
+
avatar
  • sttepir
  • 06 декабря 2018, 05:22
0
Спасибо за ответ. Лента WS2812b DC12.
+
avatar
  • Emix112
  • 11 декабря 2018, 23:09
0
Не получается переделать эфект уровня звука. Хочется переделать от зеленого- красному и тоже от центра как и с радужной линейкой. Радуга наростающая режет глаза без подсветки фона. Автоуровень уже кто-то сделал или нет? Как его сделать? Без пояснения скетча для меня это оченть трудно. Помогите чем можете. Буду благодарен ) Автор молодец, цветомузыка бомба).
+
avatar
  • juraspb
  • 13 декабря 2018, 00:11
0
Чтобы поменять цвета надо переписать табличку

const uint32_t PROGMEM
  colorTab[]={
      0xFF0000,0xFF1100,0xFF2200,0xFF3300,0xFF4400,0xFF5500,0xFF6600,0xFF7700,0xFF8800,0xFF9900,0xFFAA00,0xFFBB00,0xFFCC00,0xFFDD00,0xFFEE00,0xFFFF00,  //красный - жёлтый
      0xFFFF00,0xEEFF00,0xDDFF00,0xCCFF00,0xBBFF00,0xAAFF00,0x99FF00,0x88FF00,0x77FF00,0x66FF00,0x55FF00,0x44FF00,0x33FF00,0x22FF00,0x11FF00,0x00FF00,  //жёлтый - зелёный
      0x00FF00,0x00FF11,0x00FF22,0x00FF33,0x00FF44,0x00FF55,0x00FF66,0x00FF77,0x00FF88,0x00FF99,0x00FFAA,0x00FFBB,0x00FFCC,0x00FFDD,0x00FFEE,0x00FFFF,  //зелёный - циан (голубой)
      0x00FFFF,0x00EEFF,0x00DDFF,0x00CCFF,0x00BBFF,0x00AAFF,0x0099FF,0x0088FF,0x0077FF,0x0066FF,0x0055FF,0x0044FF,0x0033FF,0x0022FF,0x0011FF,0x0000FF,  //голубой - синий
      0x0000FF,0x1100FF,0x2200FF,0x3300FF,0x4400FF,0x5500FF,0x6600FF,0x7700FF,0x8800FF,0x9900FF,0xAA00FF,0xBB00FF,0xCC00FF,0xDD00FF,0xEE00FF,0xFF00FF,  //синий - пурпур (маджента)
      0xFF00FF,0xFF00EE,0xFF00DD,0xFF00CC,0xFF00BB,0xFF00AA,0xFF0099,0xFF0088,0xFF0077,0xFF0066,0xFF0055,0xFF0044,0xFF0033,0xFF0022,0xFF0011,0xFF0000,  //маджента - красный
      0xFFFFFF,0xEFEFEF,0xDFDFDF,0xCFCFCF,0xBFBFBF,0xAFAFAF,0x9F9F9F,0x8F8F8F,0x7F7F7F,0x6F6F6F,0x5F5F5F,0x4F4F4F,0x3F3F3F,0x2F2F2F,0x1F1F1F,0x0F0F0F,0X000000};

Например:
0xFF0000 R=255(0xFF), G=0, B=0 (0 цвет красный)
0x00FF00 R=0, G=255(0xFF), B=0 (32 цвет зелёный)
0x00FF00 R=0, G=0, B=255(0xFF) (64 цвет синий)
последняя строка градации серого

или в программе радуга

void zmu1() {
  TColor cl;
  TWord akk;
  uint8_t i,k,n,gain;

  for(i=0; i<bandPass; i++) {
      akk.w=readData[i]*brightness;
      gain=akk.b1;
      if (magn[i]<fallspeed) magn[i] = 0;
                        else magn[i] -= fallspeed; 
      if (magn[i]<gain) magn[i]=gain;
                   else gain=magn[i]; 
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
      cl=mulsGain(cl,gain);
      cl.dw = strip.Color(cl.r, cl.g, cl.b);
      n=i*LedtoColor;
      for(k=0; k<LedtoColor; k++) strip.setPixelColor(n+k, cl.dw);
  }
  strip.show();
}

написать новую строку вычисления цвета

      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);

Здесь же можно при уменьшении суммы амплитуд (magn[]) зажигать фоновый цвет, например жёлтый

if (сумма<порога) {
     cl.dw = pgm_read_dword(&colorTab[16]);
     gain = ..... // амплитуда фона
}
else {
      cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
}
cl=mulsGain(cl,gain);
.....


Новый автономный вариант цветомузыки
+
avatar
  • Emix112
  • 13 декабря 2018, 19:15
0
Спасибо) ну как тогда автоуровень звука сделать?
+
avatar
  • juraspb
  • 13 декабря 2018, 22:54
0
Регулировку уровня звука сделать сложнее. Её надо делать в исходнике на Delphi и лучше с использованием аппаратных средств. Проблем будет не меньше чем без АРУ. Я автоматической регулировкой уровня звука не занимался и чтобы её сделать корректно надо хотя бы пару книжек на эту тему прочитать.

Общие принципы понятны:
[регулируемый усилитель] -> [детектор] ->[ НЧ фильтр] -> управление регулируемым усилителем

Вы, если не прослушали композицию ранее, не знаете почему уровень упал. Может это началась новая композиция, а может так автор этой композиции задумал. Исходя из этого и необходимо выбрать параметры блоков системы.
+
avatar
  • Emix112
  • 18 декабря 2018, 01:55
0
Нашёл как решить проблему уровня звука. Плеер AIMP. Заходим настройки эффектов и ставим галочку анализ файла на ленту и звук будет уже сам добавляться или наоборот. Лучше выбрать анализ на альбом. Чтобы музыка не настраевалась вовремя воспроизведения.
+
avatar
  • Emix112
  • 16 декабря 2018, 22:22
0
столкнулся с такой проблемой. пытался передачю даных по юсб перекинуть в другой скеч. получилось но есть одно но. все спектра звука кроме дата ред [0] показания подскакивают вверх без причины. вчем беда почему так происходит. и причем реско и несенхронно. хаотично
+
avatar
  • juraspb
  • 16 декабря 2018, 23:17
0
Я не могу знать что у вас в скетче и что вы перенесли. Придумайте тестовый (программный) сигнал и посмотрите его прохождение.
+
avatar
  • Emix112
  • 17 декабря 2018, 09:21
0
Я вас понял. Вечером скину. Но наперед скажу. Сделал на экране 16 на 2 лсд анализатор спектра на 16 полос и когда плеер выключаеш то большенство полосок прыгают на максимум это на экране еле заметно. Вечером это скеч и скину. И я кстати думал что уровень звука идет например в какомто другом байте например 25 или 26 но нет только спектр от 0 до 19 байта)) Удачного дня всем!)
+
avatar
  • Emix112
  • 17 декабря 2018, 09:33
0
И если можеш скинь то что будет правельней с твоего скетчя вытянуть и вставить в любой другой пример для приема с ком порта.
+
avatar
  • Emix112
  • 17 декабря 2018, 09:46
0
Вот на этой странице скеч 2.8v alexgyver.ru/colormusic/

Я пытался в его скеч перенисти ком порт. Чтобы не ардуино занималась обработкой
звука а пк. Ну и сделать радиопередачю и режимы переключались на ик пульту. Я ему писал но он молчит. Сам передеделал но когда звук молчит полоска моргает и хоть убейся. Время мало до Нового года хочется сделать но мозгов не хватает))) а там и уровень звука атоматический
+
avatar
  • juraspb
  • 17 декабря 2018, 14:49
0
С ардуинкой я завязал. Проект работает и делать из него что то другое это сами.
Сейчас у меня другой проект цветомузыки.
Группа
Видео
+
avatar
  • Emix112
  • 17 декабря 2018, 15:12
0
Понятно.
+
avatar
  • Emix112
  • 17 декабря 2018, 15:49
0
Ну пример скину мож посмотриш че нетак
+
avatar
  • juraspb
  • 17 декабря 2018, 16:10
0
Скинь.
+
avatar
  • Emix112
  • 17 декабря 2018, 19:14
0
// — НАСТРОЙКИ — #define DRIVER_VERSION 0 // 0 — маркировка драйвера кончается на 4АТ, 1 — на 4Т

#define AUTO_GAIN 1 // автонастройка по громкости (экспериментальная функция)
#define VOL_THR 0 // порог тишины (ниже него отображения на матрице не будет)

#define LOW_PASS 0 // нижний порог чувствительности шумов (нет скачков при отсутствии звука)
#define DEF_GAIN 250 // максимальный порог по умолчанию (при GAIN_CONTROL игнорируется)

#define FHT_N 256 // ширина спектра х2
// вручную забитый массив тонов, сначала плавно, потом круче
byte posOffset[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
// — НАСТРОЙКИ — // — ПИНЫ — #define AUDIO_IN 0 // пин, куда подключен звук
#define POT_PIN 7 // пин потенциометра настройки
// — ПИНЫ — // — БИБЛИОТЕКИ — #define LOG_OUT 1
//#include <FHT.h> // преобразование Хартли
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define printByte(args) write(args);
double prevVolts = 100.0;
// — БИБЛИОТЕКИ — #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

// — АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ — // Если кончается на 4Т — это 0х27. Если на 4АТ — 0х3f
#if (DRIVER_VERSION)
LiquidCrystal_I2C lcd(0x27, 16, 2);
#else
LiquidCrystal_I2C lcd(0x3f, 16, 2);
#endif
// — АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ — // — ПОЛОСОЧКИ — byte v1[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111};
byte v2[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111};
byte v3[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111};
byte v4[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111};
byte v5[8] = {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v6[8] = {0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v7[8] = {0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v8[8] = {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
// — ПОЛОСОЧКИ — byte gain = DEF_GAIN; // усиление по умолчанию
unsigned long gainTimer;
byte maxValue, maxValue_f;
float k = 0.1;

uint8_t readData[32];
uint8_t inStr[32];
uint8_t magn[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t inCounter = 0;
boolean inComplete = false;

void setup() {


Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcdChars(); // подхватить коды полосочек

}

void loop() {


uint8_t i;

while (Serial.available()) {
// get the new byte:
uint8_t inChar = (uint8_t)Serial.read();
if (inChar != 253) {
inStr[inCounter++] = inChar;
if (inChar == 254) {
i=0;
while (inStr[i]!=254) {
readData[i]=inStr[i];
i++;
}
readData[i]=inStr[i];
inCounter = 0; // Устанавливаем счётчик принятых символов на начало входного буфера
inComplete = true;
}
} else inCounter = 0; // Устанавливаем счётчик принятых символов на начало входного буфера


}









// если разрешена ручная настройка уровня громкости


for (int pos = 0; pos < 16; pos++) { // для окошек дисплея с 0 по 15
// найти максимум из пачки тонов
if (readData[posOffset[pos]] > maxValue) maxValue = readData[posOffset[pos]]; //fht_log_out

lcd.setCursor(pos, 0);

// преобразовать значение величины спектра в диапазон 0..15 с учётом настроек
int posLevel = map(readData[posOffset[pos]], LOW_PASS, gain, 0, 15);
posLevel = constrain(posLevel, 0, 15);

if (posLevel > 7) { // если значение больше 7 (значит нижний квадратик будет полный)
lcd.printByte(posLevel — 8); // верхний квадратик залить тем что осталось
lcd.setCursor(pos, 1); // перейти на нижний квадратик
lcd.printByte(7); // залить его полностью
} else { // если значение меньше 8
lcd.print(" "); // верхний квадратик пустой
lcd.setCursor(pos, 1); // нижний квадратик
lcd.printByte(posLevel); // залить полосками
}
}

if (AUTO_GAIN) {
maxValue_f = maxValue * k + maxValue_f * (1 — k);
if (millis() — gainTimer > 1500) { // каждые 1500 мс
// если максимальное значение больше порога, взять его как максимум для отображения
if (maxValue_f > VOL_THR) gain = maxValue_f;

// если нет, то взять порог побольше, чтобы шумы вообще не проходили
else gain = 100;
gainTimer = millis();
}
}
}

void lcdChars() {
lcd.createChar(0, v1);
lcd.createChar(1, v2);
lcd.createChar(2, v3);
lcd.createChar(3, v4);
lcd.createChar(4, v5);
lcd.createChar(5, v6);
lcd.createChar(6, v7);
lcd.createChar(7, v8);
}
+
avatar
  • juraspb
  • 18 декабря 2018, 11:33
+1
Комментарий в тексте.


// — НАСТРОЙКИ — #define DRIVER_VERSION 0 // 0 — маркировка драйвера кончается на 4АТ, 1 — на 4Т

#define AUTO_GAIN 1 // автонастройка по громкости (экспериментальная функция)
#define VOL_THR 0 // порог тишины (ниже него отображения на матрице не будет)

#define LOW_PASS 0 // нижний порог чувствительности шумов (нет скачков при отсутствии звука)
#define DEF_GAIN 250 // максимальный порог по умолчанию (при GAIN_CONTROL игнорируется)

#define FHT_N 256 // ширина спектра х2
// вручную забитый массив тонов, сначала плавно, потом круче
byte posOffset[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
// — НАСТРОЙКИ — // — ПИНЫ — #define AUDIO_IN 0 // пин, куда подключен звук
#define POT_PIN 7 // пин потенциометра настройки
// — ПИНЫ — // — БИБЛИОТЕКИ — #define LOG_OUT 1
//#include <FHT.h> // преобразование Хартли
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define printByte(args) write(args);
double prevVolts = 100.0;
// — БИБЛИОТЕКИ — #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

// — АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ — // Если кончается на 4Т — это 0х27. Если на 4АТ — 0х3f
#if (DRIVER_VERSION)
LiquidCrystal_I2C lcd(0x27, 16, 2);
#else
LiquidCrystal_I2C lcd(0x3f, 16, 2);
#endif
// — АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ — // — ПОЛОСОЧКИ — byte v1[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111};
byte v2[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111};
byte v3[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111};
byte v4[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111};
byte v5[8] = {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v6[8] = {0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v7[8] = {0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v8[8] = {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
// — ПОЛОСОЧКИ — byte gain = DEF_GAIN; // усиление по умолчанию
unsigned long gainTimer;
byte maxValue, maxValue_f;
float k = 0.1;

uint8_t readData[32];
uint8_t inStr[32];
uint8_t magn[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t inCounter = 0;
boolean inComplete = false;

void setup() {


Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(«AlexGyver»);
lcd.setCursor(0, 1);
lcd.print(«SpektrumAnalyzer»);
lcdChars(); // подхватить коды полосочек

}

void loop() {


uint8_t i;

while (Serial.available()) {
  // get the new byte:
  uint8_t inChar = (uint8_t)Serial.read();
  if (inChar != 253) {
    inStr[inCounter++] = inChar;
    if (inChar == 254) {
      i=0;
      while (inStr[i]!=254) {
      readData[i]=inStr[i];
      i++;
      }
      readData[i]=inStr[i];
      inCounter = 0; // Устанавливаем счётчик принятых символов на начало входного буфера
      inComplete = true;
    }
  } else inCounter = 0; // Устанавливаем счётчик принятых символов на начало входного буфера
}

  if (inComplete) {
    inComplete=false;
    // Здесь по завершению приёма пакета ПК (в темпе поступления от ПК) выполняем все действия по выводу на LCD, так как повторять их много раз не имеет смысла
    // Я не знаю сколько по времени занимает вывод на LCD но он не должен превышать времени приёма одного байта(или нескольких байт) от ПК, я точно не помню как
    // организован приём данных от UART и есть ли там буферизация, или будут потери данных.
    // Вставьте сюда проверку количества принятых байт и если их число меньше 26 значит были пропущены данные
    // код отправки пакета из ПК для наглядности

procedure TForm1.setBandPass;
var i:Integer;
begin
   SendBuff[0]:=253;   // Сброс счётчика, начало команды
   for i:=0 to nBandPass-1 do
    begin
     if zmuBuf[i]>252 then zmuBuf[i]:=255;
     SendBuff[i+1]:=zmuBuf[i];
    end;
   SendBuff[21]:=prog;
   SendBuff[22]:=param[prog];
   SendBuff[23]:=brightness;
   SendBuff[24]:=0;
   SendBuff[25]:=254;  // Конец передачи команды
   FLink.SendBuffer(SendBuff);
   rcvAnswer;          // Ответ
end;

  // если есть пропуски, значит надо как то по другому организовывать приём данных от UART
  // или по прерываниям, или вставлять проверку принятия байта после каждой операции с LCD 
  // например весь while (Serial.available()) {...} вынести в отдельную функцию и вызывать её
  // в процессе вывода на дисплей 

// если разрешена ручная настройка уровня громкости


for (int pos = 0; pos < 16; pos++) { // для окошек дисплея с 0 по 15
// найти максимум из пачки тонов
if (readData[posOffset[pos]] > maxValue) maxValue = readData[posOffset[pos]]; //fht_log_out

lcd.setCursor(pos, 0);

// преобразовать значение величины спектра в диапазон 0..15 с учётом настроек
int posLevel = map(readData[posOffset[pos]], LOW_PASS, gain, 0, 15);
posLevel = constrain(posLevel, 0, 15);

if (posLevel > 7) { // если значение больше 7 (значит нижний квадратик будет полный)
lcd.printByte(posLevel — 8); // верхний квадратик залить тем что осталось
lcd.setCursor(pos, 1); // перейти на нижний квадратик
lcd.printByte(7); // залить его полностью
} else { // если значение меньше 8
lcd.print(" "); // верхний квадратик пустой
lcd.setCursor(pos, 1); // нижний квадратик
lcd.printByte(posLevel); // залить полосками
}
}

if (AUTO_GAIN) {
maxValue_f = maxValue * k + maxValue_f * (1 — k);
if (millis() — gainTimer > 1500) { // каждые 1500 мс
// если максимальное значение больше порога, взять его как максимум для отображения
if (maxValue_f > VOL_THR) gain = maxValue_f;

// если нет, то взять порог побольше, чтобы шумы вообще не проходили
else gain = 100;
gainTimer = millis();
}
}


    
  }

}

void lcdChars() {
lcd.createChar(0, v1);
lcd.createChar(1, v2);
lcd.createChar(2, v3);
lcd.createChar(3, v4);
lcd.createChar(4, v5);
lcd.createChar(5, v6);
lcd.createChar(6, v7);
lcd.createChar(7, v8);
}
+
avatar
  • Emix112
  • 18 декабря 2018, 13:18
0
Спасибо за помощь.) Удачи в новых проектах!!))
+
avatar
  • Emix112
  • 20 декабря 2018, 09:17
0
Доброго времени суток. Вот ещё программа для выравнивания уровня звука в mp3 файлах MP3 gain. Для цветомузыки )
+
avatar
  • Emix112
  • 04 апреля 2019, 16:24
0
Добрый день. Дайте исходники цму5 или любую версию вашей программы для Delfi… Попробую реализовать регулятор уровня для каждой из полос. В это есть беда что надо на плеере эквалайзер перестраивать чтоб стало мигать как надо. А звук в итоге сильно меняется и слушать уже неприятно. Или может быть вы уже это сделали??
+
avatar
  • juraspb
  • 04 апреля 2019, 21:47
0
Исходники этого проекта с весны прошлого года доступны на Github:
github.com/juraspb/MusicToColor
и я этим проектом с того времени больше не занимаюсь.

Сделал новый проект:
sites.google.com/view/musical-leds
есть группа
vk.com/club171670176
Юрий