Skip to contentSkip to main navigation Skip to footer

Матрица-анализатор громкости

Задача


  • Сделать реакцию ленты на звук как в вирусном видео (см. внизу страницы)
21.11.2021 – исправил схему, добавил комментариев в код

Базовые уроки


Подключение


  • Лента подключается к внешнему питанию и пину D2
  • В данной схеме Arduino питается от внешнего источника, подключение к USB необязательно
  • Микрофон к питанию и аналоговому пину (А0)
  • Пин Gain микрофона задаёт усиление звука (значения также написаны на модуле):
    • Никуда не подключен (float) – 60dB (максимум)
    • GND – 50dB
    • VCC – 40dB

 

Библиотеки


Программа


Примечание: можно настроить нижний порог шумов, добавив строчку sound.setTrsh(величина) в блок setup(). По умолчанию порог задан 40, его можно увеличить, чтобы снизить чувствительность системы к шумам.

Версия с шумом
// вывод гармонического шума, наложенного на громкость

#define STRIP_PIN 2     // пин ленты
#define SOUND_PIN A0    // пин звука

#define SHOW_MAX 1          // 1/0 - показывать плавающие точки максимума
#define COLOR_MULT -15      // шаг изменения цветовой палитры столбика
#define COLOR_STEP 3        // шаг движения палитры столбика (по времени)
#define COLON_SIZE 50       // высота матрицы
#define COLON_AMOUNT 12     // ширина матрицы

#define COLOR_DEBTH 3
#include <microLED.h>
microLED < COLON_SIZE * COLON_AMOUNT, STRIP_PIN, -1, LED_WS2812, ORDER_GRB, CLI_AVER > strip;

#include <FastLED.h>

#include "VolAnalyzer.h"
VolAnalyzer sound(SOUND_PIN);

byte volume[COLON_AMOUNT];
int maxs[COLON_AMOUNT];
byte colorCount = 0;
int16_t noise;

void setup() {
  strip.setBrightness(200);     // яркость ленты
  sound.setVolMax(100);
  sound.setVolK(30);
}

void loop() {
  if (sound.tick()) {   // если анализ звука завершён (~10мс)
    strip.clear();      // чистим ленту

    for (int i = 0; i < COLON_AMOUNT; i++) {
      // домножаем шум на громкость
      // также я домножил на 2, чтобы шум был более амплитудным
      int val = inoise8(noise - i * 100) * 2 * sound.getVol() / 100;
      
      // ограничиваем и масштабируем до половины высоты столбика
      val = constrain(val, 0, 255);
      val = map(val, 0, 255, 0, COLON_SIZE / 2);
      volume[i] = val;
    }

    noise += 90;    // двигаем шум (скорость бокового движения картинки)
    colorCount += COLOR_STEP;   // двигаем цвет
    
    // двигаем точки максимумов
    for (int i = 0; i < COLON_AMOUNT; i++) {
      if (maxs[i] < volume[i] * 10) maxs[i] = (volume[i] - 1) * 10;
      else maxs[i] -= 2;
      if (maxs[i] < 0) maxs[i] = 0;
    }
    
    // выводим
    for (int col = 0; col < COLON_AMOUNT; col++) {      // по столбикам
      for (int i = 0; i < volume[col]; i++) {           // для текущей громкости
        mData color = mWheel8(colorCount + i * COLOR_MULT);
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 + i] = color;      // вверх от центра
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 - 1 - i] = color;  // вниз от центра
      }
      
      // отображаем точки максимумов, если включены и больше 0
      if (SHOW_MAX && maxs[col] > 0) {
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 + maxs[col] / 10] = mGreen;      // вверх от центра
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 - 1 - maxs[col] / 10] = mGreen;  // вниз от центра
      }
    }
    
    // обновляем ленту
    strip.show();
  }
}
Версия с формой волны
// матрица. Вывод формы волны

#define STRIP_PIN 2     // пин ленты
#define SOUND_PIN A0    // пин звука

#define COLOR_MULT -15      // шаг изменения цветовой палитры столбика
#define COLOR_STEP 3        // шаг движения палитры столбика (по времени)
#define COLON_SIZE 50       // высота матрицы
#define COLON_AMOUNT 12     // ширина матрицы

#define COLOR_DEBTH 3       // глубина цвета (понизь, если не хватает памяти)
#include <microLED.h>
microLED < COLON_SIZE * COLON_AMOUNT, STRIP_PIN, -1, LED_WS2812, ORDER_GRB, CLI_AVER > strip;

#include "VolAnalyzer.h"
VolAnalyzer sound(SOUND_PIN);

byte volume[COLON_AMOUNT];
byte colorCount = 0;

void setup() {
  strip.setBrightness(100);     // яркость ленты
  sound.setVolMax(COLON_SIZE / 2 + 1);
}

void loop() {
  if (sound.tick()) {   // если анализ звука завершён (~10мс)
    strip.clear();  // чистим ленту
    
    // перематываем массив громкости вправо
    for (int i = COLON_AMOUNT - 1; i > 0; i--) volume[i] = volume[i - 1];
    volume[0] = sound.getVol();     // новое значение громкости на освободившееся место

    colorCount += COLOR_STEP;   // двигаем цвет

    for (int col = 0; col < COLON_AMOUNT; col++) {      // для каждого столбика
      for (int i = 0; i < volume[col]; i++) {           // для его текущей громкости
        mData color = mWheel8(colorCount + i * COLOR_MULT);             // цвет со смещением по радуге
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 + i] = color;      // вверх от центра
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 - 1 - i] = color;  // вниз от центра
      }
    }
    // выводим
    strip.show();
  }
}
Анализ спектра

У меня данный скетч перестал работать по непонятным причинам =)

#define STRIP_PIN 2     // пин ленты
#define SOUND_PIN A0    // пин звука

#define FREQ_NOISE 35
#define FREQ_DIV 20

#define COLOR_MULT -15
#define COLOR_STEP 2
#define COLON_SIZE 16
#define COLON_AMOUNT 16

#define COLOR_DEBTH 3
#include <microLED.h>
microLED < COLON_SIZE * COLON_AMOUNT, STRIP_PIN, -1, LED_WS2812, ORDER_GRB, CLI_AVER > strip;

#define LOG_OUT 1
#define FHT_N 128
#include <FHT.h>

int volume[COLON_AMOUNT];
int maxs[COLON_AMOUNT];
byte colorCount = 0;

void setup() {
  analogReference(EXTERNAL);
  strip.setBrightness(100);
  ADCSRA &= bit(7);
  ADCSRA |= 0b110;  //110 8 кгц, 101 19 кгц
}

void loop() {
  static uint32_t tmr;
  if (millis() - tmr >= 20) {
    tmr = millis();
    for (int i = 0; i < FHT_N; i++) {
      fht_input[i] = analogRead(SOUND_PIN);
      //delayMicroseconds(50);
    }
    fht_window();
    fht_reorder();
    fht_run();
    fht_mag_log();

    int maxv = 0;
    static int maxvf;
    int vals[COLON_AMOUNT];
    int wholes = (FHT_N / 2 - 2) / COLON_AMOUNT;

    for (int i = 0; i < FHT_N / 2; i++) {
      if (fht_log_out[i] < FREQ_NOISE) fht_log_out[i] = 0;
      else fht_log_out[i] -= FREQ_NOISE;
      fht_log_out[i] += (long)fht_log_out[i] * i / FREQ_DIV;
    }

    for (int col = 0; col < COLON_AMOUNT; col++) {
      vals[col] = 0;
      for (int i = 0; i < wholes; i++) {
        int val = fht_log_out[col * wholes + i + 2];
        vals[col] += val;
      }
      vals[col] *= 100;
      if (maxv < vals[col]) maxv = vals[col];
    }

    if (maxvf < maxv) maxvf += (maxv - maxvf) / 20;
    else maxvf += (maxv - maxvf) / 200;

    for (int i = 0; i < COLON_AMOUNT; i++) {
      vals[i] = constrain(vals[i], 0, maxvf);
      if (volume[i] < vals[i]) volume[i] = vals[i];
      else volume[i] += (vals[i] - volume[i]) / 10;
      vals[i] = map(volume[i], 0, maxvf, 0, COLON_AMOUNT / 2);
    }

    strip.clear();

    colorCount += COLOR_STEP;
    /*for (int i = 0; i < COLON_AMOUNT; i++) {
      if (maxs[i] < vals[i] * 10) maxs[i] = vals[i] * 10;
      else maxs[i] -= 3;
      if (maxs[i] < 0) maxs[i] = 0;
      }*/

    for (int col = 0; col < COLON_AMOUNT; col++) {
      for (int i = 0; i < vals[col]; i++) {
        mData color = mWheel8(colorCount + i * COLOR_MULT);
        //mData color = mGreen;
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 + i] = color;
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 - 1 - i] = color;
      }

      /*if (maxs[col] > 0) {
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 + maxs[col] / 10] = mRed;
        strip.leds[COLON_SIZE * col + COLON_SIZE / 2 - 1 - maxs[col] / 10] = mRed;
        }*/
    }
    strip.show();
  }
}

Видео


Полезный пример?

Похожие примеры
20 Комментариев
  • Заметил, что если использовать китайский блок питания 5 v 3 а то шумы присутствуют и не помогает даже перемычка с GAIN на VCC ,но при использовании другого блока питания 5 в 2 а(не китай) то шумы пропали, почему так я так и не понял.

  • Скетч с волной завелся с первого раза, только теперь нужно решить проблему с шумами

  • В скетче вижу, что использованы 2 ленты по 5 м. 50 x 12 матрица.
    Как эти 2 ленты подключаются? Вряд ли последовательно – ведь дорожки не выдержат большой ток.
    Тогда как подключение выглядит?

    • большой ток пойдёт при включении всех светодиодов белым цветом. В этом примере они не горят все вместе, и делают это цветом. Что ещё в 3 раза понижает ток потребления

  • думаю можно вместо микрофона подключить источник звука? Не будет ли в источник идти помехи с ардуинки? Питание развязано с источником, но будет распараллелено с усилителем. И куда можно выложить творения? Я меня всё вокруг Электросамоката)

  • Я повторил проект с формой волны, где точки максимум показываются. Но возникла проблема: при полной тишине у меня “бежит волна”. Если начинаю издавать резкие звуки, то волна утихает и потом начинает воспроизводить мои “шумы”.
    Собственно и вопрос: как при полной тишине сделать так, чтобы матрица не светилась, а реагировала только на звуки и шумы?

    • В общем-то, выспался и ещё более внимательно перечитал инструкцию. Вся проблема оказалась в том, что я разъём микрофона “Gain” подключил на “GND”, что снизило чувствительность микрофона до -50dB и этого оказалось недостаточно.
      У кого будет такая же проблема с шумом, то подключать надо только на “VCC”, иначе волны будут постоянно.

  • Пробовал сделать проект , собрал а прошить ардуино не смог . Постоянно выдает In file included from C:\Users\roadt\AppData\Local\Temp\arduino_modified_sketch_429027\sketch_dec20a.ino:16:0:
    C:\Users\roadt\Documents\Arduino\libraries\FastLED/FastLED.h:14:21: note: #pragma message: FastLED version 3.003.003
    # pragma message “FastLED version 3.003.003”
    , Может кто то подскажет что не так ?

  • а почему перестал работать Анализ спектра????????

    сегодня забрал с почты микрофон с али, думал успею к нг – а тут такая подстава(

  • Алексей привет.
    Так же решил сделать как у тебя с волной. Подскажи пожалуйста, посмотрел видео несколько раз (честно раз 10 уже). Вопрос такой:
    1)если сделать высоту не 50, а к примеру 25
    и длина будет не 12, а тогда 24. Идея сделать ее длинной. Как будет играть волна тогда? хотелось чтобы спектр по высоте был короче? или он сам подгонят по высоте ленты?
    2)Как греется лента? мысли закрепить ее на клеем от пистолета на жидкие обои? не будет ли сильно греться чтобы не было (не дай бог) – пожара?
    3)Я обратил внимание (пересматривая) что через 300 светодиодов у тебя начинается новая лента. Как соединять тогда. последовательно или параллельно. последовательно я понял, А вот параллельно не понимаю как подать сигнал (последовательный или параллельный)

    спасибо за ответы.

Оставить комментарий

Ваш адрес email не будет опубликован.