091117_2114_TinkeringTu6.png

Tinkering Tuesday – Playmobil Stage – Audio Spectrum Analysis from WAV input with simple logic, FHT and MSGEQ7

Past posts of this series:

Tinkering Tuesday – Playmobil Stage – Einführung

Tinkering Tuesday – Playmobil Stage – Introduction

Tinkering Tuesday – Playmobil Stage – Playmobil parts

Tinkering Tuesday – Playmobil Stage – LED Stage Lights

Tinkering Tuesday – Playmobil Stage – Disco Ball with stepper motor

Tinkering Tuesday – Playmobil Stage – LED Rings
Tinkering Tuesday – Playmobil Stage – Audio Output from microSD with Arduino


This post will be about different possibilities to do sound input analysis (or spectrum analysis) with the Arduino. The source of sound will be my Arduino audio output from the last post for now. But I plan on using a sound sensor board additionally for the final build. The audio output from my last post is a little bit special because it uses PWM. „Normal“ audio is more of a sine wave. To not have any side effects I will do my testing with a second Arduino (nano in my case)

But lets start using the PWM output directly:

Sound input analysis on PWM signals

I made a direct connection from the PWM output of my audio output Arduino to A0 of the input Arduino:

New is only the Arduino nano, connecting A0 and GND.

With this we can use a simple input analysis, based on the code at http://blog.yavilevich.com/2016/08/arduino-sound-level-meter-and-spectrum-analyzer/ (which is by the way a great post for the theory also).

//based on: http://blog.yavilevich.com/2016/08/arduino-sound-level-meter-and-spectrum-analyzer/
#define MicSamples (1024*2)
#define MicPin A0

// measure basic properties of the input signal
// determine if analog or digital, determine range and average.
void MeasureAnalog()
{
long signalAvg = 0, signalMax = 0, signalMin = 1024, t0 = millis();
for (int i = 0; i < MicSamples; i++)
{
int k = analogRead(MicPin);
signalMin = min(signalMin, k);
signalMax = max(signalMax, k);
signalAvg += k;
}
signalAvg /= MicSamples;

// print
Serial.print("Time: " + String(millis() - t0));
Serial.print(" Min: " + String(signalMin));
Serial.print(" Max: " + String(signalMax));
Serial.print(" Avg: " + String(signalAvg));
Serial.print(" Span: " + String(signalMax - signalMin));
Serial.print(", " + String(signalMax - signalAvg));
Serial.print(", " + String(signalAvg - signalMin));
Serial.println("");

}
void setup() {
Serial.begin(115200);
}

void loop() {
MeasureAnalog();
}

As a result I got some readings. First you see the basic noise (without the output Arduino connected), then the plugin noise of the output Arduino and finally the sound playing.

--Basic noise
Time: 229 Min: 0 Max: 8 Avg: 2 Span: 8, 6, 2
Time: 229 Min: 0 Max: 7 Avg: 2 Span: 7, 5, 2
Time: 230 Min: 0 Max: 8 Avg: 2 Span: 8, 6, 2
Time: 229 Min: 0 Max: 8 Avg: 2 Span: 8, 6, 2
--PlugIn
Time: 229 Min: 0 Max: 221 Avg: 89 Span: 221, 132, 89
Time: 229 Min: 0 Max: 180 Avg: 108 Span: 180, 72, 108
Time: 229 Min: 28 Max: 88 Avg: 52 Span: 60, 36, 24
--Playing Sound
Time: 230 Min: 0 Max: 1023 Avg: 24 Span: 1023, 999, 24
Time: 229 Min: 0 Max: 1023 Avg: 327 Span: 1023, 696, 327
Time: 230 Min: 0 Max: 1023 Avg: 332 Span: 1023, 691, 332
Time: 229 Min: 0 Max: 1023 Avg: 327 Span: 1023, 696, 327
Time: 229 Min: 0 Max: 1023 Avg: 331 Span: 1023, 692, 331
Time: 230 Min: 0 Max: 1023 Avg: 323 Span: 1023, 700, 323
Time: 229 Min: 0 Max: 1023 Avg: 327 Span: 1023, 696, 327
Time: 230 Min: 0 Max: 1023 Avg: 326 Span: 1023, 697, 326
Time: 229 Min: 0 Max: 1023 Avg: 325 Span: 1023, 698, 325
Time: 229 Min: 0 Max: 1023 Avg: 325 Span: 1023, 698, 325

Having a closer look at the readings shows what could already be expected. Values ranging from 0 to 1023, the averages varying a bit. It is PWM, so fully on (1023) or fully off (0). That can be verified by a pure analog read:

#define MicPin A0

void setup() {
Serial.begin(115200);

}

void loop() {
Serial.println(analogRead(MicPin));
}
1023
0
0
1023
0
0
195
1
0
524
0
7
1023
0
988
0
7
1023
0
62
0
574
0
1023
0
0
0
902
0
1023

I don’t know quite the theory why the „in-between-values“ are there but they are. But mostly you can see 0 and 1023.

There is an advanced function to analyse audio on the arduino and it is called the Arduino FHT library. For more information about that please have a look at http://wiki.openmusiclabs.com/wiki/ArduinoFHT. There is also the full theory.

The following sketch is a modified example code and is producing serial output:

/*
fht_adc.pde
guest openmusiclabs.com 9.5.12
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.  there is a pure data patch for
visualizing the data.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 256 // set to 256 point fht

#include <FHT.h> // include the library

void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
while(1) { // reduces jitter
cli();  // UDRE interrupt slows this way down on arduino1.0
long t0 = micros();
for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fht_input[i] = k; // put real data into bins
}
long dt = micros() - t0;
fht_window(); // window the data for better frequency response
fht_reorder(); // reorder the data before doing the fht
fht_run(); // process the data in the fht
fht_mag_log(); // take the output of the fht
//    sei();
//    Serial.write(255); // send a start byte
//    Serial.write(fht_log_out, FHT_N/2); // send out the data
// print as text
for (int i = 0; i < FHT_N / 2; i++)
{
Serial.print(fht_input[i]);
Serial.print(',');
}
long sample_rate = FHT_N * 1000000l / dt;
Serial.print(dt);
Serial.print(',');
Serial.println(sample_rate);
}
}

The result can be seen in the following screenshot:

Puh, that’s a lot of numbers. As a plot in excel this is the result:

Using digital to analog conversion (DAC) to convert PWM back to analog signal

Searching for some solutions I stumbled upon the DAC from http://www.instructables.com/id/Analog-Output-Convert-PWM-to-Voltage/

This is using a capacitor and a resistor to smoothen the PWM signal back into a voltage level. It is also known as a low pass filter (if you exchange the resistor and the capacitor you get a high pass filter as I read in the comments…).

The following schematic shows the enhanced connection:

R1=3,9k, C=100nF (0,1uF)

The output from the basic input readings look much better now:

Time: 230 Min: 155 Max: 547 Avg: 347 Span: 392, 200, 192
Time: 229 Min: 174 Max: 562 Avg: 347 Span: 388, 215, 173
Time: 230 Min: 150 Max: 545 Avg: 347 Span: 395, 198, 197
Time: 229 Min: 175 Max: 528 Avg: 347 Span: 353, 181, 172
Time: 229 Min: 163 Max: 513 Avg: 347 Span: 350, 166, 184
Time: 229 Min: 149 Max: 511 Avg: 347 Span: 362, 164, 198
Time: 230 Min: 180 Max: 539 Avg: 347 Span: 359, 192, 167
Time: 230 Min: 202 Max: 504 Avg: 347 Span: 302, 157, 145
Time: 229 Min: 161 Max: 540 Avg: 347 Span: 379, 193, 186
Time: 230 Min: 147 Max: 582 Avg: 347 Span: 435, 235, 200
Time: 229 Min: 118 Max: 546 Avg: 349 Span: 428, 197, 231
Time: 229 Min: 59 Max: 610 Avg: 347 Span: 551, 263, 288
Time: 230 Min: 187 Max: 553 Avg: 347 Span: 366, 206, 160
Time: 229 Min: 179 Max: 603 Avg: 348 Span: 424, 255, 169
Time: 230 Min: 186 Max: 569 Avg: 347 Span: 383, 222, 161
Time: 229 Min: 175 Max: 502 Avg: 347 Span: 327, 155, 172
Time: 229 Min: 191 Max: 497 Avg: 347 Span: 306, 150, 156
Time: 231 Min: 170 Max: 494 Avg: 347 Span: 324, 147, 177
Time: 229 Min: 203 Max: 517 Avg: 347 Span: 314, 170, 144
Time: 230 Min: 218 Max: 532 Avg: 347 Span: 314, 185, 129
Time: 229 Min: 189 Max: 514 Avg: 347 Span: 325, 167, 158
Time: 230 Min: 201 Max: 484 Avg: 347 Span: 283, 137, 146
Time: 229 Min: 117 Max: 532 Avg: 347 Span: 415, 185, 230

This can also be observed in the pure readings:

245
253
310
368
424
398
382
370
390
405
402
386
400
399
387
345
308
292
320
338
337
313
317
335
353
371
348
290
280
279
263
232
221
247
319

I have to admit in the FHT output I don’t see much difference:

Connecting some LEDs I modified the sketch to light the LEDs up based on some thresholds.

//based on: http://blog.yavilevich.com/2016/08/arduino-sound-level-meter-and-spectrum-analyzer/
#define MicSamples (1024*2)
#define MicPin A0
#define LEDRedPin 11
#define LEDGreenPin 9
#define LEDBluePin 10

// measure basic properties of the input signal
// determine if analog or digital, determine range and average.
void MeasureAnalog()
{
long signalAvg = 0, signalMax = 0, signalMin = 1024, t0 = millis();
for (int i = 0; i < MicSamples; i++) { int k = analogRead(MicPin); signalMin = min(signalMin, k); signalMax = max(signalMax, k); signalAvg += k; } signalAvg /= MicSamples; // print Serial.print("Time: " + String(millis() - t0)); Serial.print(" Min: " + String(signalMin)); Serial.print(" Max: " + String(signalMax)); Serial.print(" Avg: " + String(signalAvg)); Serial.print(" Span: " + String(signalMax - signalMin)); Serial.print(", " + String(signalMax - signalAvg)); Serial.print(", " + String(signalAvg - signalMin)); Serial.println(""); if(signalMax - signalMin > 450){
analogWrite(LEDRedPin, 255);
} else {
analogWrite(LEDRedPin, 0);
}
if(signalMax - signalMin > 400){
analogWrite(LEDGreenPin, 255);
} else {
analogWrite(LEDGreenPin, 0);
}
if(signalMax - signalMin > 500){
analogWrite(LEDBluePin, 255);
} else {
analogWrite(LEDBluePin, 0);
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LEDRedPin, OUTPUT);
pinMode(LEDBluePin, OUTPUT);
pinMode(LEDGreenPin, OUTPUT);
}

void loop() {
MeasureAnalog();
}

It is currently based on the intro, so it is not really an optimal solution for the whole song and for other songs. I will have to see how to configure the threshholds best. Maybe they have to adopt to the levels of the prior readings.

MSGEQ7

Then I connected the MSGEQ7 according to the schematic shown at http://nuewire.com/info-archive/msgeq7-by-j-skoba/. Using the very same Arduino sketch from there I got a lot of zeros for my input with some readings in different frequencies in between. What I also recognized was that the direct PWM output from the other Arduino was giving at least some results (not for the intro of the test song but from the chorus onwards. I have no clue why this is…). When I used the DAC / low pass filter shown above, I got no readings at all. I had no 200ohm resistor and used a 220ohm but should this result in such a difference? I don’t think so. I also tried connecting an MP3 player directly to the MSGEQ7 but also got no results.

Abb: Wiring with DAC – R2=200k, C2=33pF, C3=100nF, C4=10nF, C5=100nF

Abb: Wiring without DAC – R2=200k, C2=33pF, C3=100nF, C4=10nF, C5=100nF

I found a MSGEQ7 Demo app at https://forum.arduino.cc/index.php?topic=425799.0. Adopted to my setup:

/*
MSGEQ7 Demo app
Look for the breakout board on www.whizoo.com

This code runs on an Arduino Duemilanove, but will run on other Arduino models.

Connections:
- GND to GND on MSGEQ7 breakout board, and LED's
- 5V to VDD on MSGEQ7 breakout board
- A0 to OUT on MSGEQ7 breakout board
- D2 to STROBE on MSGEQ7 breakout board
- D3 to RESET on MSGEQ7 breakout board
- D9 to LED 0 (indicator for frequency band 0)
- D10 to LED 1 (indicator for frequency band 1)
- D11 to LED 2 (indicator for frequency band 2)
- no pin to LED 3 (indicator for frequency band 3)
- no pin to LED 4 (indicator for frequency band 4)
- no pin to LED 5 (indicator for frequency band 5)

*/

// Hardware-specific defines
#define MSGEQ7_STROBE_PIN      2
#define MSGEQ7_RESET_PIN       3
#define MSGEQ7_ANALOG_PIN      A0

#define NUM_FREQUENCY_BANDS    3

// Duemilanove only has 6 PWM outputs, so the last LED won't respond properly.  Your
// board may have more PWM outputs.  Typically you only want to monitor the lowest
// frequency bands because that is where the beat is.
int led[NUM_FREQUENCY_BANDS] = {9, 10, 11};

// There is a concept of "persistence of vision" with LED's.  The LED has to be on long enough
// for the eye to recognise that it is on.  When a high volume is received on a frequency band,
// The LED is turned on (at a high PWM value) and then gradually faded until the next beat in
// that frequency.
int ledPWMValue[NUM_FREQUENCY_BANDS] = {0, 0, 0};

void setup() {
// Set the LED pins as outputs
for (int i=0; i<NUM_FREQUENCY_BANDS; i++)
pinMode(led[i], OUTPUT);

// Set up the MSGEQ7 IC
pinMode(MSGEQ7_ANALOG_PIN, INPUT);
pinMode(MSGEQ7_STROBE_PIN, OUTPUT);
pinMode(MSGEQ7_RESET_PIN, OUTPUT);
digitalWrite(MSGEQ7_RESET_PIN, LOW);
digitalWrite(MSGEQ7_STROBE_PIN, HIGH);
Serial.begin(9600);
}

// This loop executes around 100 times per second
void loop() {
int frequencyBandVolume;

// Toggle the RESET pin of the MSGEQ7 to start reading from the lowest frequency band
digitalWrite(MSGEQ7_RESET_PIN, HIGH);
digitalWrite(MSGEQ7_RESET_PIN, LOW);

// Read the volume in every frequency band from the MSGEQ7
for (int i=0; i<NUM_FREQUENCY_BANDS; i++) { digitalWrite(MSGEQ7_STROBE_PIN, LOW); // delayMicroseconds(20); // Allow the output to settle frequencyBandVolume = analogRead(MSGEQ7_ANALOG_PIN); digitalWrite(MSGEQ7_STROBE_PIN, HIGH); Serial.print(frequencyBandVolume); Serial.print(" "); if (i == NUM_FREQUENCY_BANDS-1) { Serial.println(""); } // The read value is 10-bit (0 to 1024). PWM needs a value from 0 to 255, so divide by 4 frequencyBandVolume = frequencyBandVolume >> 2;

// Fade the current LED value for this band
ledPWMValue[i] = ledPWMValue[i] > 7? ledPWMValue[i] - 7 : 0;

// Don't show the lower values
if ((frequencyBandVolume > 70) && (frequencyBandVolume < 100)){ // If the new volume is greater than that currently being showed then show the higher volume if (frequencyBandVolume > ledPWMValue[i])
ledPWMValue[i] = frequencyBandVolume;
}

if (frequencyBandVolume > 220) {
// If the new volume is greater than that currently being showed then show the higher volume
if (frequencyBandVolume > ledPWMValue[i])
ledPWMValue[i] = frequencyBandVolume;
}

// Set the LED PWM value to the frequency band's volume
analogWrite(led[i],  ledPWMValue[i]);
}

// Wait before executing this loop again
//delay(2);
}

With some LEDs connected (there will be another post regarding the LEDs) you can see the result for the chorus in the video below:

I don’t have so much time to tinker more with the MSGEQ7 right now, so I will just go with a simple input solution I guess. At least I will take the fading of the LEDs from the MSGEQ7 Demo app. But one more note: http://www.eetimes.com/author.asp?doc_id=1323030 recommends to also use 100nF instead of the 10nF capacitor. Perhaps that might be something worth to try. The site has also the wiring for stereo input.

Doing it all on one Arduino

For my tests I used two separate Arduinos. But of course I would really like to reduce this down to one Arduino. So I connected the output of the DAC directly to the A0 pin of the Arduino UNO and combined the two sketches:

// ---------------------------------------------------------------------------------
// DO NOT USE CLASS-10 CARDS on this project - they're too fast to operate using SPI
// ---------------------------------------------------------------------------------

#include <SD.h>
#include <TMRpcm.h>
TMRpcm tmrpcm;

File root;
File entry;
#define MicSamples (1024^2)
#define MicPin A0
#define LEDRedPin 11
#define LEDGreenPin 9
#define LEDBluePin 10

// ---------------------------------------------------------------------------------
// set chipSelect to '10' if using the $2 SD card module or '4' if using the
// Ethernet shield's microSD card instead.
const int chipSelect = 10;
// ---------------------------------------------------------------------------------

const int oldCard = SPI_HALF_SPEED;
const int newCard = SPI_QUARTER_SPEED;

// ---------------------------------------------------------------------------------
// set cardType to 'oldCard' if using an old SD card (more than a few years old) or
// to 'newCard' if using a newly-purchase Class-4 card.
int cardType = newCard;
// ---------------------------------------------------------------------------------

int wasPlaying = 0;
int inSwitch = 7;
int finished = 0;
int start = 0;
int pauseOn = 0;
unsigned long timeDiff = 0;
unsigned long timePress = 0;
int analogMeasureCounter = 0;
int analogMeasureValue = 0;
long signalAvg = 0, signalMax = 0, signalMin = 1024, t0 = millis();

void setup() {
Serial.begin(9600);
Serial.print("\nInitializing SD card...");
pinMode(chipSelect, OUTPUT);
if (!SD.begin(chipSelect,cardType)) {
Serial.println("failed!");
return;
}
Serial.println("done.");

tmrpcm.speakerPin = 9;

pinMode(inSwitch,INPUT_PULLUP);
digitalWrite(inSwitch,HIGH);

root = SD.open("/");
}

void loop(void) {
if(!tmrpcm.isPlaying() && wasPlaying == 1) {
tmrpcm.stopPlayback();
playNext();
}
MeasureAnalog();
if (millis() - timeDiff > 50) { // check switch every 100ms
timeDiff = millis(); // get current millisecond count

if(digitalRead(inSwitch) == LOW) {

if(start==0) {
start=1;
playNext();
delay(200);

} else {

timePress = millis();
while(digitalRead(inSwitch)==LOW) {
delay(50);
}
if (millis() - timePress < 1000 && start == 1) { tmrpcm.pause(); if (pauseOn == 0) { pauseOn = 1; } else { pauseOn = 0; } } if (millis() - timePress > 1000 && start == 1) {
if (pauseOn == 1) {pauseOn = 0; tmrpcm.pause();}
tmrpcm.stopPlayback();
timePress = millis();
if (finished == 0) {
playNext();
} else {
finished = 0;
Serial.println("Restarting.");
root.rewindDirectory();
playNext();
}
}
}
}
}
}

void playNext() {
entry = root.openNextFile();
if (entry) {
entry.close();
tmrpcm.play(entry.name());
Serial.print("Playing ");
Serial.print(entry.name());
wasPlaying = 1;
} else {
if (wasPlaying == 1) {
Serial.println("Completed playback.");
wasPlaying = 0;
finished = 1;
start = 0;
root.rewindDirectory();
}
}
}
void MeasureAnalog()
{
if (analogMeasureCounter == MicSamples) {
signalAvg /= MicSamples;

// print
Serial.print("Time: " + String(millis() - t0));
Serial.print(" Min: " + String(signalMin));
Serial.print(" Max: " + String(signalMax));
Serial.print(" Avg: " + String(signalAvg));
Serial.print(" Span: " + String(signalMax - signalMin));
Serial.print(", " + String(signalMax - signalAvg));
Serial.print(", " + String(signalAvg - signalMin));
Serial.println("");

//    if(signalMax - signalMin > 450){
//      analogWrite(LEDRedPin, 255);
//    } else {
//      analogWrite(LEDRedPin, 0);
//    }
//    if(signalMax - signalMin > 400){
//      analogWrite(LEDGreenPin, 255);
//    } else {
//      analogWrite(LEDGreenPin, 0);
//    }
//    if(signalMax - signalMin > 500){
//      analogWrite(LEDBluePin, 255);
//    } else {
//      analogWrite(LEDBluePin, 0);
//    }
t0 = millis();
analogMeasureCounter = 0;
} else {
//Serial.println( analogRead(MicPin));
analogMeasureValue = analogRead(MicPin);
//signalMin = min(signalMin, analogMeasureValue);
//signalMax = max(signalMax, analogMeasureValue);
signalAvg += analogMeasureValue;
analogMeasureCounter++;
}

}

That resulted in very slow readings. Instead of every 230 milliseconds I got a reading every 2-4 seconds. Also reducing the number of MicSamples down to 512 resulted in the following output:

Time: 1197 Min: 1024 Max: 0 Avg: 234 Span: -1024, -234, -790
Time: 1274 Min: 1024 Max: 0 Avg: 236 Span: -1024, -236, -788
Time: 1235 Min: 1024 Max: 0 Avg: 233 Span: -1024, -233, -791
Time: 1275 Min: 1024 Max: 0 Avg: 236 Span: -1024, -236, -788
Time: 1196 Min: 1024 Max: 0 Avg: 231 Span: -1024, -231, -793
Time: 1258 Min: 1024 Max: 0 Avg: 231 Span: -1024, -231, -793
Time: 1274 Min: 1024 Max: 0 Avg: 238 Span: -1024, -238, -786

So still over a second. That is not usable for sound reactive lights. It would lag very much behind.

I also got to remove the calculation of min and max values because the dynamic memory was giving a warning and the playback did not start anymore.

TMRpcm versions

I used the version of TMRpcm that came with the Auduino. It doesn’t include volume adjustment yet and so I wanted to upgrade to the most recent version of the library from https://github.com/TMRh20/TMRpcm/wiki. Unfortunately I was not able to get that one running. I tried the basic examples and also my above used codes but it was refusing to playback anything. I have no clue why.

In the end I will just continue with the current setup of two Arduinos (perhaps I might exchange the one that is doing the audio playback with an Arduino nano and try the recent version again. But for now I don’t want to reconnect all the cables. I will go for some PCB design soon and solder everything together. That will make rewiring everything easier.

More to read

Fading RGB FHT: http://shin-ajaran.blogspot.de/2014/11/arduino-spectrum-analyzer-for-music-to.html

PWM to Voltage: http://www.instructables.com/id/Arduino-RC-Circuit-PWM-to-analog-DC/

Wiring of the MSGEQ7 http://nuewire.com/info-archive/msgeq7-by-j-skoba/

Matching Instructable: http://www.instructables.com/id/Extreme-Nightlight-Color-Organ/

MSGEQ7 forum post with TestCode https://forum.arduino.cc/index.php?topic=425799.0

MSGEQ7 Datasheet: https://www.sparkfun.com/datasheets/Components/General/MSGEQ7.pdf

MSGEQ7 Tutorial http://tronixstuff.com/2013/01/31/tutorial-arduino-and-the-msgeq7-spectrum-analyzer/

MSGEQ7 Tutorial https://www.baldengineer.com/msgeq7-simple-spectrum-analyzer.html

Mic Amp: http://www.redcircuits.com/Page38.htm

AnalogIn Basic analysis, theory: http://blog.yavilevich.com/2016/08/arduino-sound-level-meter-and-spectrum-analyzer/

FFT for Arduino: http://wiki.openmusiclabs.com/wiki/ArduinoFFT

FHT for Arduino: http://wiki.openmusiclabs.com/wiki/ArduinoFHT

Arduino, FHT, RGB Led, sound to lighting: https://gist.github.com/teos0009/6e54aff7e3d236d17ac4

Schreib einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *