Многоканальная цветомузыка. Методы обработки сигнала

hypersash
Offline
Зарегистрирован: 07.12.2011

Всем доброго времени суток!

Задался целью сваять годную цветомузыку, на основе УНО (328). Хочеться все сделать качественно и красиво, а для этого как ни крути надо ФФТ использовать, но никак не воткну как она работает. Поэтому пока сделано относительно громкости входящего сигнала, но, сами понимаете, это не комильфо =) Прошу помощи с ффт, ткните носом куда нужно, очень уж охота сделать по уму =)

Тут две версии моего говнокода светомузыки для ргб ленты, лазерного проэктора и строба.

Вариант 1

int MicPin = 0;          // audio in

int redPin = 5;          
int greenPin = 6;
int bluePin = 3;

int MicValue = 0;       //значение аудиосигнала
int correction = 370 //коррекция по громкости для разных устройств
void setup() {
  Serial.begin(9600); 
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);

  analogWrite(redPin, 0);      
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 0);
}

void loop() {

  MicValue = analogRead(MicPin)+correction;
 
 
  Serial.println(MicValue);     // это для отладки

  if (MicValue > 500) {   
    analogWrite(bluePin,255);
   analogWrite(redPin, 0); 
    delay(15);            
    }
  
  if (MicValue > 540) {      
    analogWrite(bluePin,0);
    analogWrite(greenPin, 255);
    delay(15);            
    }
  
  if (MicValue > 560) {     
    analogWrite(greenPin,0);
    analogWrite(redPin, 255);
    delay(15);              
    }

analogWrite(greenPin, 0);    //все гасим для стобо-эффекта
analogWrite(redPin, 0);
analogWrite(bluePin,0);
delay(5);                 // увеличивает период темноты - лучший стробо-эффект

}

Видео первого варианта - см ниже (от модератора)

Вариант 2 

int MicPin = 0;          // пин входа
int input = 0;

int redPin = 5;           
int greenPin = 6;
int bluePin = 3;
int laserPin = 11;
int stroboPin = 2;

int MicValue = 0;        // значение аудиосигнала
int correction = 360;
void setup() {
  Serial.begin(9600);  
  pinMode(MicPin, INPUT);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(laserPin, OUTPUT);
  pinMode(stroboPin, OUTPUT);
                                // ЭТО ДЛЯ ПРОСТОЙ ПРОВЕРКИ, ВСЕ ЛИ КАНАЛЫ РАБОТАЮТ!
analogWrite(11, 0);
 analogWrite(redPin, 255);
 analogWrite(10, 200);
  delay(500);
 analogWrite(redPin, 0);
  analogWrite(10, 0);
delay(200);
  analogWrite(greenPin, 255);
   analogWrite(10, 200);
  delay(500);
  analogWrite(greenPin, 0);
    analogWrite(10, 0);
  delay(200);
  analogWrite(bluePin, 255);
   analogWrite(10, 200);
  delay(500);
  analogWrite(bluePin, 0);
    analogWrite(10, 0);
  delay(200);
  analogWrite(laserPin, 150);
   analogWrite(10, 200);
   delay(500);
    analogWrite(laserPin, 0);
   analogWrite(10, 0);
     delay(200);
  digitalWrite(stroboPin, HIGH);
   analogWrite(10, 200);
   delay(500);
    digitalWrite(stroboPin, LOW);
   analogWrite(10, 0);
}
                             // конец теста
                            // 10й пин - пьезопищалка
void loop() 
{
  MicValue = analogRead(MicPin)+correction;  
   Serial.println(MicValue); // для отладки
if (MicValue > 610)
{
     digitalWrite(stroboPin, HIGH);
     delay(3);
 } 
 else
   {
     digitalWrite(stroboPin, LOW);
     delay(5);
 } 

 if (MicValue > 450 && MicValue <490)
 { 
   analogWrite(bluePin,255);
   delay(10);
 }
   else
   {
    analogWrite(bluePin,0);
    delay(10);
 }
 if (MicValue > 480 && MicValue <520)
 { 
   analogWrite(greenPin,255);
   delay(10);
 }
   else
   {
    analogWrite(greenPin,0);
    delay(10);
 }
 delay(10);
 if (MicValue > 510 && MicValue <600)
 { 
   analogWrite(redPin,255);
   delay(10);
 }
   else
   {
    analogWrite(redPin,0);
    delay(10);
 }
if (MicValue < 400)
{
     analogWrite(laserPin, 255);
 } 
 else
   {
     analogWrite(laserPin, 0);
     delay(5);
 } 
}
 

 

hypersash
Offline
Зарегистрирован: 07.12.2011

Ссылка на ютуб из первого поста - http://youtu.be/s92hXKmjHiw

Тут нельзя редактировать сообщения? ^_^

---------

Понял, только шапку нельзя менять =)

Совсем забыл, кто может подсказать как сделать автокоррекцию входящего сигнала, что-бы не надо было настраивать на разные уровни громкости (ноут и телефон, например). БЛАГОДАРСТВУЮ ЗАРАНЕЕ =)

Alexander
Offline
Зарегистрирован: 25.04.2010

hypersash
Offline
Зарегистрирован: 07.12.2011

Alexander,  спасибо =)

Что кто может подсказать по поводу ФФТ и автокоррекции громкости?

hypersash
Offline
Зарегистрирован: 07.12.2011

Сорри, не пинайте, но ап! =)

leshak
Offline
Зарегистрирован: 29.09.2011

То есть как-то "не пинайте"? :) А как же еще развлекатся?

А если серъезней, то если "все молчат", значит возможные варианты
1. Тема не интерестна
2. Никто не знает ответа
3. Никто не понял что вы хотите

Как видим, ни одни пункт не лечится простым "ап".

С вариантом  (2) - вы врядли что-то сделаете, а вот (3) - можете посидеть и подумать, "как бы спросить по другому" (интересней/понятней).

Ну например попытатся объяснить что вы понимаете под "автокоррекцией громкости".
 

leshak
Offline
Зарегистрирован: 29.09.2011

Возможно что-то вот типа такого вам подойдет:

#define MIC_PIN A0


int maxRawValue=300; // начальное значение диапазано
int minRawValue=700;

void loop(){
  int rawValue=analogRead(MIC_PIN);
  // уточняем диапазон
  if(rawValue>maxRawValue)maxRawValue=rawValue;
  if(rawValue<minRawValue)minRawValue=rawValue;
  
  // приводым "сырое значение" к какому-то нашему "условному диапазон" от 0 до 1000
  
  int micValue=map(rawValue, minRawValue,maxRawValue,0,1000);
  
  // тут идет ваша остальная логика. micValue будет в диапазоне от 0 до 1000
  // 0 - значит "самое тихое что когда-либо было", 1000 - самый громкий звук что мы слышали
  
}

 

leshak
Offline
Зарегистрирован: 29.09.2011

Кстати, вам вашем варианте

  pinMode(MicPin, INPUT);

включит на вход не аналогвый пин, а цифровой. 

Кстати2,  по умолчанию все пины и так включены на вход, так что делать pinMode(...,INPUT) - не обазательно.

hypersash
Offline
Зарегистрирован: 07.12.2011

Всем снова доброго времени суток! Спасибо за пример автокоррекции, пока еще не пробывал, не хватает времени =)

 

leshak пишет:

Кстати, вам вашем варианте

  pinMode(MicPin, INPUT);

включит на вход не аналогвый пин, а цифровой. 

Кстати2,  по умолчанию все пины и так включены на вход, так что делать pinMode(...,INPUT) - не обазательно.

Простите, но вы ошибаетесь, он работает как аналоговый вход, тут все в порядке, через серийник все видно =)

 

Раз уж с ФФТ ничего не выходит, подскажите пожалуйста чем можно было-бы заменить delay() в моем коде, для более своевременного реагирования на бит. Пробовал с millis(), по образцу стандартного примера, но видимо не так я одарен в коде =) Заранее благодарю!

 

int MicPin = 0;           // пин аудиовхода

int redPin = 5;          
int greenPin = 6;
int bluePin = 3;
int laserPin = 11;
int stroboPin = 2;

int MicValue = 0;       
int correction = 390;
void setup() 
{
  Serial.begin(9600);  
  pinMode(MicPin, INPUT);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(laserPin, OUTPUT);
  pinMode(stroboPin, OUTPUT);
}

void loop() 
{
  MicValue = analogRead(MicPin)+correction;  //входящий сигнал + ручная коррекция громкости

  Serial.println(MicValue);

if (MicValue > 610)
{
     digitalWrite(stroboPin, LOW);
     analogWrite(greenPin,0);
     analogWrite(bluePin,0);
     analogWrite(redPin,0);
     delay(3);
            // стробоскопным 10Вт диодом временно управляет реле, поэтому 5 или 0, впринципе и транзистором также можно управлять, только резистор подобрать
 } 
 else
   {
     digitalWrite(stroboPin, HIGH);
     delay(8);
 } 

 if (MicValue > 450 && MicValue <490)
 { 
   analogWrite(bluePin,255);
   delay(10);
 }
   else
   {
    analogWrite(bluePin,0);
    delay(3);
 }
 if (MicValue > 480 && MicValue <520)
 { 
   analogWrite(greenPin,255);
   delay(15);
 }
   else
   {
    analogWrite(greenPin,0);
    delay(3);
 }
 delay(10);
 if (MicValue > 510 && MicValue <600)
 { 
   analogWrite(redPin,255);
   delay(10);
 }
   else
   {
    analogWrite(redPin,0);
    delay(3);
 }
if (MicValue > 400)
   {
     digitalWrite(laserPin, LOW);
     delay(5);
 } 
 else
 {
   digitalWrite(laserPin, HIGH);
   delay(10);
 }

 

leshak
Offline
Зарегистрирован: 29.09.2011

>чем можно было-бы заменить delay()

функцией millis(). После прочтения примеров из документации. В шапке сайта линк "Програмирование", потом смотрим в правую колонку, там есть раздел "примеры", ищем пример который вроде подходит по смыслу. Пытаемся понять принцип его работы. Так же поиск по форуму может помоч.

 

Zhyravlev_AS
Offline
Зарегистрирован: 03.04.2013

Вот что у меня есть:

#include <fix_fft.h>
#define AUDIOPIN 5
 
char im[128], data[128];
int i=0, val;
 
void setup() {
  Serial.begin(9600);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val/4 -128;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=1; i<64;i++){
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
      // здесь i это канал от 1 до 64, каждый канал принимает значение от 0 до 15 насколько я сам это понял.
    }
}
leshak
Offline
Зарегистрирован: 29.09.2011

 

hypersash пишет:

Всем снова доброго времени суток! Спасибо за пример автокоррекции, пока еще не пробывал, не хватает времени =)

А зачем тогда "поехали дальше" если этот этап не прошли?

hypersash пишет:

leshak пишет:

 

Кстати, вам вашем варианте

  pinMode(MicPin, INPUT);

включит на вход не аналогвый пин, а цифровой. 

Кстати2,  по умолчанию все пины и так включены на вход, так что делать pinMode(...,INPUT) - не обазательно.

Простите, но вы ошибаетесь, он работает как аналоговый вход, тут все в порядке, через серийник все видно =)

Спорим на биткоины что ошибаетесь вы? Я же не сказал "работать не будет", я сказал что "делает оно не то что вы думаете". К счастью эти ошибочные танцевальные движения - не приводят к неработоспособности в этом конкретном скетче. Но если вы не разберетесь с этим вопре рано или поздно вы таким образом либо словите глюк, либо когда перепутаете какому именно пиноу вы настраиваете режим при настройке на Output, - упалите ногу.

Итак: У вас есть два пина. D0 и A0. Оба уже включены на INPUT. И вообщем-то не требует инкаких настроек. Но вы захотели все-таки еще раз, явно указать. Это ничего не меняет, но является нормальной практикой. Для читабельности кода - вполне полезно. Но... pinMode вы сделали для D0, а не A0!!! И "ничего не поломалось", только потому что они уже оба были включены на INPUT.

Далее, вы пытаетесь делать analogRead с цифрового входа. Но... к счастью вы не первый кто так делают, поэтому те кто писал функцию analogRead - уже предусмотрели это. И внутри себя она имеет "защиту от дурака", если есть скормили цифровой пин, она сама, внутри поправляет его на аналоговый. Только поэтому у вас и работает. Но вот это "логика поправления" - не документирована, следовательно, хоть и маловероятно но в будущих версиях - ее могут убрать. Или появятся новые платы, в которых просто по номеру будет не просто понять про какой же пин идет речь (и сделать "поправку" станет не возможным).

hypersash пишет:

Вот что у меня есть:

И где тут видно попытки применить millis()? Даже delay() что-бы понять что вы хотите - и то нет.

hypersash
Offline
Зарегистрирован: 07.12.2011

Zhyravlev_AS пишет:

Вот что у меня есть:

#include <fix_fft.h>
#define AUDIOPIN 5
 
char im[128], data[128];
int i=0, val;
 
void setup() {
  Serial.begin(9600);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val/4 -128;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=1; i<64;i++){
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
      // здесь i это канал от 1 до 64, каждый канал принимает значение от 0 до 15 насколько я сам это понял.
    }
}

Вот это какраз и есть то, что я не смог понять в ффт. i понятное дело перебирает каналы, с 1 по 63, а вот как поймать значение нужного канала? Например значение канала 1, 25, 50, 60? Мне-то по сути 3-5 каналов и нужно, правда широких. Допустим первый до 500Гц (низ), второй от 500Гц до 1500Гц , третий от 1500 до 3000Гц и т.п..
Покажите пожалуйсто пример с одним каналом и выводом его в серийник, мне хочеться разобраться как оно работает, а тогда я уже смогу подогнать все под свои нужды =) Естественно результатом поделюсь, думаю не мне одному такое интересно =) Заранее благодарю!

Уважаемый leshak, пробывал как вы советовали, тоже правда не до конца воткнул как работает этот алгоритм. Все время 0 после обработки. И пофиг ему что на входе =(

#define MIC_PIN A0


int maxRawValue=300; // начальное значение диапазано
int minRawValue=700;

void loop(){
  int rawValue=analogRead(MIC_PIN);
  // уточняем диапазон
  if(rawValue>maxRawValue)maxRawValue=rawValue;
  if(rawValue<minRawValue)minRawValue=rawValue;
  
  // приводым "сырое значение" к какому-то нашему "условному диапазон" от 0 до 1000
  
  int micValue=map(rawValue, minRawValue,maxRawValue,0,1000);
  
  // тут идет ваша остальная логика. micValue будет в диапазоне от 0 до 1000
  // 0 - значит "самое тихое что когда-либо было", 1000 - самый громкий звук что мы слышали
  
}

 

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

Тема умерла?

Прикрутил к Arduino три RGB ленты через TLC5940NT

Сейчас думаю, какие эффекты зашить, в том числе и от звука.

С преобразованием фурье на три канала кто-то разобрался?

Или проще заюзать три аналоговых порта с частотными фильтрами?

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

http://yadi.sk/d/cyD8GFReCbbh4

качайте библиотеку. рабочая проверял

это спектр если пальцем дотронутся до входа ардуины на которой проверял

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

jeka_tm пишет:

http://yadi.sk/d/cyD8GFReCbbh4

качайте библиотеку. рабочая проверял

Не нашел описание на библиотеку.

Как задать частотные полосы для фильтра?

std
Offline
Зарегистрирован: 05.01.2012
jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

sav13 пишет:

jeka_tm пишет:

http://yadi.sk/d/cyD8GFReCbbh4

качайте библиотеку. рабочая проверял

Не нашел описание на библиотеку.

Как задать частотные полосы для фильтра?

честно сказать незнаю. я просто проверил рабочая или нет

hypersash
Offline
Зарегистрирован: 07.12.2011

К коду Zhyravlev_AS, попробывал на скорую руку выловить три канала из 64, правда у меня почему-то значения канала колеблються от 0 до 3. Пока работает так-себе, но вроде частоты смутненько проклевываються) Со временем еще поковыряюсь в этом направлении, может кому еще поможет =)

Код:

#include <fix_fft.h>
#define AUDIOPIN 0
 
char im[128], data[128];
int i=0, val;
int out = 0;
int br = 0;

int redPin = 5;          // pins that the LED are attached to  
int greenPin = 6;
int bluePin = 3;
 
void setup() {
  Serial.begin(9600);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val/4 -128;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=1; i<64;i++){
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
     
   if (i == 21) {
   out = data[i];
   Serial.print("low - ");
   Serial.println(out);
   Serial.println(val);
   if (out == 0)
     {analogWrite(redPin,0);}
   if (out == 1)
     {analogWrite(redPin,100);}
   if (out == 2)
     {analogWrite(redPin,200);}
   if (out > 3)
     {analogWrite(redPin,255);}}
   
if (i == 42) {
   out = data[i];
   Serial.print("mid - ");
   Serial.println(out);
   Serial.println(val);
   if (out == 0)
     {analogWrite(bluePin,0);}
   if (out == 1)
     {analogWrite(bluePin,100);}
   if (out == 2)
     {analogWrite(bluePin,200);}
   if (out > 3)
     {analogWrite(bluePin,255);}}
   
if (i == 60) {
   out = data[i];
   Serial.print("hi - ");
   Serial.println(out);
   Serial.println(val);
   if (out == 0)
     {analogWrite(greenPin,0);}
   if (out == 1)
     {analogWrite(greenPin,100);}
   if (out == 2)
     {analogWrite(greenPin,200);}
   if (out > 3)
     {analogWrite(greenPin,255);}}
  }
}

Вывод в серийник (тут попались 0 и 1 значения на каналах, но бывает еще проскакивает 2 и изредка даже 3):

low - 1
0
mid - 1
0
hi - 1
0
low - 1
0
mid - 0
0
hi - 1
0
low - 1
3
mid - 1
3
hi - 1
3
low - 1
16
mid - 0
16
hi - 1
16
low - 1
23
mid - 1
23
hi - 1
23
low - 1
0
mid - 1
0
hi - 1
0
low - 1
0
mid - 1
0
hi - 1
0
low - 1
78
mid - 1
78
hi - 1
78
low - 1
0
mid - 1
0
hi - 1
0
low - 0
0
mid - 1
0
hi - 1
0
low - 1
0
mid - 0
0
hi - 1
0
low - 1
0
mid - 1
0
hi - 1
0
low - 1
85
mid - 0
85
hi - 1
85
low - 0
118
mid - 1
118
hi - 0
118
low - 0
0
mid - 1
0
hi - 0
0
low - 0
0
mid - 1
0
hi - 1
0
low - 0
0
mid - 1
0
hi - 0
0
low - 1
76
mid - 1
76
hi - 1
76
low - 1
0
mid - 0
0
hi - 0
0
low - 1
2
mid - 1
2
hi - 1
2
low - 1
0
mid - 1
0
hi - 1
0
low - 1
87
mid - 1
87
hi - 1
87
low - 1
129
mid - 1
129
hi - 1
129
low - 1
0
mid - 0
0
hi - 1
0
low - 1
5
mid - 1
5
hi - 1
5
low - 0
0
mid - 0
0
hi - 1
0
low - 1
0
mid - 0
0
hi - 1
0
low - 0
0
mid - 0
0
hi - 1
0
low - 1
14
mid - 1
14
hi - 1
14
low - 0
11
mid - 1
11
hi - 1
11
low - 1
0
mid - 1
0
hi - 1
0
low - 1
0
mid - 1
0
hi - 1
0
low - 1
0
mid - 1
0
hi - 1
0
low - 0
0
mid - 0
0
hi - 1
0

И на закусочку видео, как оно работает...

https://youtu.be/6JAfFBUcNUw

hypersash
Offline
Зарегистрирован: 07.12.2011

Может у более опытных форумчан есть мнение - в том ли направлении я мучаюсь? :)

Logik
Offline
Зарегистрирован: 05.08.2014

hypersash пишет:
Может у более опытных форумчан есть мнение - в том ли направлении я мучаюсь? :)

Есть мнение. Перед строкой 19 вставить delayMicroseconds(200);

hypersash
Offline
Зарегистрирован: 07.12.2011

Logik пишет:

Есть мнение. Перед строкой 19 вставить delayMicroseconds(200);

Попробывал - ситуацию не изменило.

Вобщем есть идея суммировать значения каналов с 1 по 21, с 22 по 41, с 42 по 63, и эти три суммы и использывать как нч/сч/вч. 

Вопрос в том, что я не знаю, как написать такие циклы =( Попробывал пару вариантов, не бейте, самому стыдно =)

Вариант 1 (циклично бегает по цветам, не особо реагируя на сигнал):

#include <fix_fft.h>
#define AUDIOPIN 0
 
char im[128], data[128];
int i=0, val;
int outlow = 0;
int outmid = 0;
int outhi = 0;

int redPin = 5;          // pins that the LED are attached to  
int greenPin = 6;
int bluePin = 3;
 
void setup() {
  Serial.begin(19200);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val/4 -128;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=1; i<64;i++){
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
      // здесь i это канал от 1 до 64, каждый канал принимает значение от 0 до 15 насколько я сам это понял.
   if (i > 0 && i < 22)
   {outlow = outlow + data[i];}
   Serial.print("low - ");
   Serial.println(outlow);
   Serial.println(val);
   analogWrite(redPin, outlow * 5);
   if (i > 22 && i < 42)
   {outmid = outmid + data[i];}
   Serial.print("mid - ");
   Serial.println(outmid);
   Serial.println(val);
   analogWrite(bluePin, outmid * 5);
   if (i > 42 && i < 63)
   {outhi = outhi + data[i];}
   Serial.print("hi  - ");
   Serial.println(outhi);
   Serial.println(val);
   analogWrite(greenPin, outhi * 5);
}
 outlow = 0;
 outmid = 0;
 outhi = 0;  }

Вариант 2 (вообще не работает, тут я понял, что не врубаюсь в циклы):

#include <fix_fft.h>
#define AUDIOPIN 0
 
char im[128], data[128];
int i=0, val;
int outlow = 0;
int outmid = 0;
int outhi = 0;

int redPin = 5;          // pins that the LED are attached to  
int greenPin = 6;
int bluePin = 3;
 
void setup() {
  Serial.begin(19200);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val/4 -128;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=1; i<64;i++){
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
      // здесь i это канал от 1 до 64, каждый канал принимает значение от 0 до 15 насколько я сам это понял.
   
   do
   {outlow = outlow + data[i];} while (i<22);
   
   Serial.print("low - ");
   Serial.println(outlow);
   Serial.println(val);
   analogWrite(redPin, outlow * 5);
   
   do
   {outmid = outmid + data[i];} while (i<42);
   
   Serial.print("mid - ");
   Serial.println(outmid);
   Serial.println(val);
   analogWrite(bluePin, outmid * 5);

   do
   {outhi = outhi + data[i];} while (i<63);
   
   Serial.print("hi  - ");
   Serial.println(outhi);
   Serial.println(val);
   analogWrite(greenPin, outhi * 5);

}
 outlow = 0;
 outmid = 0;
 outhi = 0;  }

 

Logik
Offline
Зарегистрирован: 05.08.2014

Ну незнаю даже.

Либу дернул тут https://github.com/Robmaister/LEDMusicVisualizer.

Скетч взял Ваш, поправил как советовал, номер пина да вывод поудобней сделал, получил такой 

#include <fix_fft.h>
#define AUDIOPIN A2
 
char im[128], data[128];
int i=0, val;
int outlow = 0;
int outmid = 0;
int outhi = 0;

int redPin = 5;          // pins that the LED are attached to  
int greenPin = 6;
int bluePin = 3;
 
void setup() {
  Serial.begin(19200);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      delayMicroseconds(200);
      data[i] = val/4 -128;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
    

    
  for (i=0; i<10;i++)
  {
          Serial.print((byte)(sqrt(data[i] * data[i]+im[i]*im[i])));
      Serial.print("\t");

  }
  Serial.println();

 }

Ткнул пальцем во вход, он у меня 50Гц ;) Получил при тыкании такое

21	1	1	1	0	1	1	1	0	1	
22	1	1	0	1	1	1	0	1	0	
21	1	0	1	1	1	1	1	1	1	
22	1	1	1	0	1	1	1	1	1	
21	0	0	1	1	0	1	0	0	0	
21	0	1	1	0	1	1	1	1	0	
21	0	0	1	0	1	0	1	0	0	
21	1	1	1	1	1	1	1	0	1	
25	2	8	4	2	1	6	3	1	2	
22	4	17	1	2	3	7	2	1	1	
21	1	12	2	2	1	5	4	2	2	
22	2	12	3	1	2	5	3	1	1	
23	0	14	0	0	0	5	4	0	1	
19	1	14	2	1	1	5	4	2	2	
22	2	14	1	1	4	5	2	3	2	
22	3	13	1	1	2	6	4	2	2	
19	1	13	2	0	1	6	4	1	1	
23	2	13	1	1	2	5	2	1	1	
23	1	13	1	2	3	7	5	2	3	
19	1	11	2	2	2	8	2	2	1	
22	4	15	0	1	3	8	2	1	1	
21	0	13	2	1	2	9	3	1	1	
22	1	12	2	2	4	9	1	2	0	
26	3	16	1	2	3	9	1	0	1	
21	1	12	2	2	2	8	3	0	2	
23	1	14	2	2	1	8	3	2	3	
22	2	14	0	1	1	6	4	0	2	
20	2	12	2	1	0	6	3	2	2	
20	2	13	1	2	1	8	5	2	3	
23	1	13	2	1	1	7	5	2	4	
19	1	13	3	1	1	6	5	1	1	
21	3	14	0	1	1	6	5	1	2	
21	2	12	2	2	2	7	3	3	2	
22	1	1	0	0	1	1	1	1	1	
21	1	1	1	1	1	1	1	1	1	
22	1	1	1	1	1	1	1	0	1	
21	1	0	1	1	1	1	1	0	1	
22	1	1	1	1	1	1	1	0	1	
21	1	0	1	0	1	0	1	0	1	
22	1	0	1	0	1	0	1	0	1	
22	1	1	1	0	1	1	1	0	1	
22	0	0	1	0	0	0	1	1	0	

На правду похоже в общем.

hypersash
Offline
Зарегистрирован: 07.12.2011

Logik, только что затестил Вашу версию, единственная разница "for (i=0; i<3;i++)", если там 10, вывод серийника не меняеться, кстати.

Бод-рэйт пробывал разный, в скетче и мониторе порта он одинаковый

На выходе серийника либо пустота, либо каша, если потеребить пальцами или вставить/вынуть штекер в комп:

	

	$	
	!	
	 	
		
	"	
	'	
	)	
	3	
	+	
		
	#	
	-	
	1	
		
	0	
	/	
(		
	4	
	0	
	5	
	$	
	)	
	.	
	.	
!	"	
	1	
	2	
		
	2	
	-	
	0	
	,	
	5	
	.	
	1	
	-	
	(	
	&	
	%	
	%	
	#	
	"	
	#	
	)	
	)	
	&	
	 	
	(	
	(	
	'	
	&	
		
	
	
		
		
		,	
	)	
	&	
&	&	
		
	.	
	1	
	3	
	2	
	3	
	?	
	!	
	3	
	4	
		
		4	
	2	
	)	

В чем может быть косяк?

Кстати компилирую и заливаю все на 0023, на 1.6.8 ругаеться сильно на библиотеку ффт, не удалось подружить..

Logik
Offline
Зарегистрирован: 05.08.2014

Различия я перечислил. Номер ввода у Вас 10, он не аналоговый, delayMicroseconds(200) и вывод. Каша в выводе от отсутствия приведения к байту. Внимательней сравнивайте, или загрузите мой, проверте и затем поправте вывод как в вашем.

hypersash
Offline
Зарегистрирован: 07.12.2011

На всякий случай есть еще вариант полу-рабочий, однако уже заметнее разделение по частотам))

Еще заметил, что входящий сигнал делиться на 4 и из него вычитаетсья 128, убрал это, стало гораздо лучше:

for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val/4-128;
      im[i] = 0;

Код:

#include <fix_fft.h>
#define AUDIOPIN 0
 
char im[128], data[128];
int i=0, val;
int out = 0;

int redPin = 5;          // pins that the LED are attached to  
int greenPin = 6;
int bluePin = 3;
 
void setup() {
  Serial.begin(19200);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=1; i<64;i++){
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
     
   if (i == 2) {
   out = data[i];
   Serial.print("low - ");
   Serial.println(out);
   Serial.println(val);
   if (out <= 6)
     {analogWrite(redPin,0);}
   if (out >= 8)
     {analogWrite(redPin,255);}}
   
if (i == 30) {
   out = data[i];
   Serial.print("mid - ");
   Serial.println(out);
   Serial.println(val);
   if (out <= 2)
     {analogWrite(bluePin,0);}
   if (out >= 4)
     {analogWrite(bluePin,255);}}
   
if (i == 58) {
   out = data[i];
   Serial.print("hi - ");
   Serial.println(out);
   Serial.println(val);
   if (out <= 3)
     {analogWrite(greenPin,0);}
   if (out >= 5)
     {analogWrite(greenPin,255);}}
  }
}

Вывод в серийник при динамичной музыке:

low - 8
23
mid - 1
23
hi - 3
23
low - 15
181
mid - 2
181
hi - 2
181
low - 4
0
mid - 2
0
hi - 1
0
low - 2
185
mid - 4
185
hi - 3
185
low - 8
26
mid - 3
26
hi - 5
26
low - 2
0
mid - 5
0
hi - 9
0
low - 7
0
mid - 9
0
hi - 3
0
low - 2
0
mid - 5
0
hi - 4
0
low - 1
0
mid - 1
0
hi - 2
0
low - 5
104
mid - 4
104
hi - 7
104
low - 3
74
mid - 2
74
hi - 2
74

Видео:

https://youtu.be/GVfffSM_Mjc

hypersash
Offline
Зарегистрирован: 07.12.2011

Logik пишет:

Различия я перечислил. Номер ввода у Вас 10, он не аналоговый, delayMicroseconds(200) и вывод. Каша в выводе от отсутствия приведения к байту. Внимательней сравнивайте, или загрузите мой, проверте и затем поправте вывод как в вашем.

Ввод во всех скетчах у меня А0, тоесть нулевой аналоговый, или я что-то упустил?

Вот код, я его тупо скопировал с Вашего поста, изменив только порт и количество циклов:

#include <fix_fft.h>
#define AUDIOPIN 0
 
char im[128], data[128];
int i=0, val;
int out = 0;

int redPin = 5;          // pins that the LED are attached to  
int greenPin = 6;
int bluePin = 3;
 
void setup() {
  Serial.begin(19200);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      delayMicroseconds(200);
      data[i] = val/4-128;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=1; i<3;i++){
      Serial.print((byte)(sqrt(data[i] * data[i]+im[i]*im[i])));
      Serial.print("\t");}

  
  Serial.println();

 }

 

Logik
Offline
Зарегистрирован: 05.08.2014

Точно, не 10 пин у Вас, а 0-й. #define AUDIOPIN 0

но и это тоже не А0, не аналоговый.

hypersash
Offline
Зарегистрирован: 07.12.2011

Logik пишет:

Точно, не 10 пин у Вас, а 0-й. #define AUDIOPIN 0

но и это тоже не А0, не аналоговый.

Окей, сделал #define AUDIOPIN A0

Как я и думал - причина не в этом, хотя порт и так читал (выдавал) данные 0-1023

Еще варианты? =) У меня уже идеи заканчиваються, почему идентичный код не хочет работать, еще и таким образом...

Ради хохмы сейчас перекину на A2, как у Вас =)

------------------------------------------------------------------------------

UPD Естественно смена порта ничего не дала - вывод серийника все такая-же каша или пустота при подключенном компе

Logik
Offline
Зарегистрирован: 05.08.2014

каша при Serial.print((byte)(sqrt(data[i] * data[i]+im[i]*im[i]))); ?

hypersash
Offline
Зарегистрирован: 07.12.2011

Logik пишет:

каша при Serial.print((byte)(sqrt(data[i] * data[i]+im[i]*im[i]))); ?

Ну да, я же говорю, я скопировал код из Вашего поста, все в точности так, своего ничего не добавлял...

Logik
Offline
Зарегистрирован: 05.08.2014

И скорости обмена скетча и монитора согласованы? Либу брали где? Хотя на кашу это не влияет. Там выше ссылка на github. Я запускал под ИДЕ 1.0.6.

hypersash
Offline
Зарегистрирован: 07.12.2011

Ладно, вечером поэксперементирую еще.

У меня другой вопрос - допустим изначальный код, который из примера спектроанализатора, рисует 64 столбика и делит диапазон частот на эти 64 столбика (интервала) (кстати с каким диапазоном он работает? 0-20000Гц?). Если мы меняем количество столбиков, допустим, на 3, он перерассчитывает всю анализируюмую полосу под 3 интервала?

Оригинальный код:

#include <TVout.h>
#include <fix_fft.h>
TVout TV;
char im[128], data[128], lastpass[64];
char x=32, ylim=90;
int i=0,val;
void setup()
    {                                          
    TV.begin(_NTSC,128,96);                              //  Initialize TV output, 128x96.
    TV.print_str(2,2,"  Realtime Arduino");             //  TVout lib uses x,y for print
    TV.print_str(2,11,"  Spectrum Analyzer");         //  statements.  8x8 default font.
    analogReference(DEFAULT);                          //  Use default (5v) aref voltage. 
    for (int z=0; z<64; z++) {lastpass[z]=80;};       //  fill the lastpass[] array with dummy data
    };
void loop()
    {
    for (i=0; i < 128; i++){                                     // We don't go for clean timing here, it's
      val = analogRead(0);                                      // better to get somewhat dirty data fast
      data[i] = val/4 -128;                                       // than to get data that's lab-accurate
      im[i] = 0;                                                       // but too slow, for this application.
      };

    fix_fft(data,im,7,0);
    
    for (i=1; i< 64;i++){                                          // In the current design, 60Hz and noise
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);  // in general are a problem.  Future designs
      TV.draw_line(i+x,lastpass[i],i+x,ylim,0);          // and code may fix this, but for now, I
      TV.draw_line(i+x,ylim,i+x,ylim-data[i],1);        // skip displaying the 0-500hz band completely.
      lastpass[i]=ylim-data[i];                                   // if you insist, initialize the loop with 0
      };                                                                    // rather than 1.
    };

Пример под 3 интервала:

#include <TVout.h>
#include <fix_fft.h>
TVout TV;
char im[128], data[128], lastpass[64];
char x=32, ylim=90;
int i=0,val;
void setup()
    {                                          
    TV.begin(_NTSC,128,96);                              //  Initialize TV output, 128x96.
    TV.print_str(2,2,"  Realtime Arduino");             //  TVout lib uses x,y for print
    TV.print_str(2,11,"  Spectrum Analyzer");         //  statements.  8x8 default font.
    analogReference(DEFAULT);                          //  Use default (5v) aref voltage. 
    for (int z=0; z<64; z++) {lastpass[z]=80;};       //  fill the lastpass[] array with dummy data
    };
void loop()
    {
    for (i=0; i < 128; i++){                                     // We don't go for clean timing here, it's
      val = analogRead(0);                                      // better to get somewhat dirty data fast
      data[i] = val/4 -128;                                       // than to get data that's lab-accurate
      im[i] = 0;                                                       // but too slow, for this application.
      };

    fix_fft(data,im,7,0);
    
    for (i=1; i< 3;i++){                                          // In the current design, 60Hz and noise
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);  // in general are a problem.  Future designs
      TV.draw_line(i+x,lastpass[i],i+x,ylim,0);          // and code may fix this, but for now, I
      TV.draw_line(i+x,ylim,i+x,ylim-data[i],1);        // skip displaying the 0-500hz band completely.
      lastpass[i]=ylim-data[i];                                   // if you insist, initialize the loop with 0
      };                                                                    // rather than 1.
    };

 

hypersash
Offline
Зарегистрирован: 07.12.2011

Всем доброго времени суток! Вобщем пока работает, не известно как, но работает =) Дальше буду пробывать реализовать плавное вкл/выкл каждого цвета, чтоб не мельтешила так...

Код:

#include <fix_fft.h>
#define AUDIOPIN 0
 
char im[128], data[128];
int i=0, val;
int out = 0;
int br = 0;

int redPin = 5;          // pins that the LED are attached to  
int greenPin = 6;
int bluePin = 3;
 
void setup() {
  Serial.begin(19200);
  analogWrite(redPin,0);                 // just test connections
      analogWrite(greenPin,0);
        analogWrite(bluePin,0);
        delay(500);
  analogWrite(redPin,255);
  delay(500);
  analogWrite(redPin,0);
  analogWrite(greenPin,255);
  delay(500);
  analogWrite(greenPin,0);
  analogWrite(bluePin,255);
  delay(500);
  analogWrite(bluePin,0);
}
 
void loop() {
    for (i=0; i < 128; i++){
      val = analogRead(AUDIOPIN);
      data[i] = val;
      im[i] = 0;
    }

    fix_fft(data,im,7,0);
     
    for (i=0; i<3;i++){
      data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
     
   if (i == 0) {
   out = data[i];
   Serial.print("low - ");
   Serial.println(out);
   Serial.println(val);
   if (out <= 9)
     {analogWrite(redPin,0);}
   if (out >= 13)
     {analogWrite(redPin,out*10);}}
   
if (i == 1) {
   out = data[i];
   Serial.print("mid - ");
   Serial.println(out);
   Serial.println(val);
   if (out <= 5)
     {analogWrite(bluePin,0);}
   if (out >= 10)
     {analogWrite(bluePin,out*10);}}
   
if (i == 2) {
   out = data[i];
   Serial.print("hi  - ");
   Serial.println(out);
   Serial.println(val);
   if (out <= 4)
     {analogWrite(greenPin,0);}
   if (out >= 8)
     {analogWrite(greenPin,out*10);}}
  }
}

Видео:

https://youtu.be/2cp0oxr5q2U

liur
Offline
Зарегистрирован: 12.10.2016

Всем здравствуйте! Тоже захотелось сделать цветомузыку, всё собрал, всё работает. Спасибо за код!  Но как было написано выше, нехватает плавности. Когда долго смотришь, глаза устают. Сам не силён программировании, пытался разобраться, но пока ничего не нашел. Может кто разобрался и сможет подсказать как сделать или где почитать, как сделать?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Коль тему приподняли, а ответа не было - отвечу.

hypersash пишет:

У меня другой вопрос - допустим изначальный код, который из примера спектроанализатора, рисует 64 столбика и делит диапазон частот на эти 64 столбика (интервала) (кстати с каким диапазоном он работает? 0-20000Гц?).

Это зависит от частоты дискретизации, с которой заполнен массив данных.

Если исхождить из параметров АЦП Атмеги, то примерно 0-4500. Интервалы равные в Герцах, т.е. полосы примерно по 70 Гц.

Цитата:

Если мы меняем количество столбиков, допустим, на 3, он перерассчитывает всю анализируюмую полосу под 3 интервала?

"Он" - это кто? FFT посчитал 64 значения, Вы выбрали из них только 3 нижних, т.е. полосы 0-70Гц, 70-140Гц и 140-210Гц, остальные не использовали.

popUP
Offline
Зарегистрирован: 09.10.2014

Пытаюсь повторить

выдает ошибку

D:\ARDUINO\Sketch\libraries\fix_FFT\fix_fft.cpp:51:7: error: 'prog_int8_t' does not name a type

 
 const prog_int8_t Sinewave[N_WAVE-N_WAVE/4] PROGMEM = {
 
       ^
 
In file included from D:\ARDUINO\Sketch\libraries\fix_FFT\fix_fft.cpp:1:0:
 
D:\ARDUINO\Sketch\libraries\fix_FFT\fix_fft.cpp: In function 'int fix_fft(char*, char*, int, int)':
 
D:\ARDUINO\Sketch\libraries\fix_FFT\fix_fft.cpp:200:38: error: 'Sinewave' was not declared in this scope
 
             wr =  pgm_read_word_near(Sinewave + j+N_WAVE/4);
 
                                      ^
 
D:\ARDUINO\Sketch\libraries\fix_FFT\fix_fft.cpp:210:38: error: 'Sinewave' was not declared in this scope
 
             wi = -pgm_read_word_near(Sinewave + j);
 
                                      ^
 
exit status 1
Ошибка компиляции для платы Arduino Nano.