For this tutorial, we will need to send live data over USB to the microcontroller. On paper, you can send data between ESP32 and a computer through USB but in real life, people often face problems with ESP32. CP2102 USB to UART Bridge provides a complete plug-and-play interface solution:
1 | https://www.silabs.com/interface/usb-bridges/classic/device.cp2102?tab=specs |
The failproof way is to use Adafruit Metro Mini as a microcontroller board. You can test with your existing microcontrollers, if they fail then you can purchase Adafruit Metro Mini. The method and code I have used for this guide are written by djazz (on GitHub and YouTube) and ana-cc (on GitHub).
I can’t create this thing from scratch since it requires working knowledge of music-related technical things. Here is the video:
In case you want a ready-to-use solution, then you can read our previous guide NeoPixel VU Meter With SP107E LED Music Controller.
---
ana-cc’s Method
You will need this Python script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/python import serial import subprocess ser = serial.Serial('/dev/ttyUSB0', 115200) #point to your arduino as appropriate def read_o(): process=subprocess.Popen(["./pulse_freq.out"],stdout=subprocess.PIPE, universal_newlines=True) for stdout_line in iter(process.stdout.readline, ""): yield stdout_line values_before = [0,0,0,0,0,0,0,0] for item in read_o(): computed_values = [0,0,0,0,0,0,0,0] values_now = item.split(" ") for i in range(0,8): val = abs(int(float(values_now[i]) - float(values_before[i]))) computed_values[i] = val if val < 5 else 5 value = "".join(str(v) for v in computed_values) value += '\n' print (value) ser.write(bytes(value,'utf-8')) values_before = item.split(" ") |
You can save it as pretty_music.py
. You may need to modify the line /dev/ttyUSB0
to match your setup. You’ll need the main processing file written in C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | #include <glib.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <gst/gst.h> static guint spect_bands = 8; #define AUDIOFREQ 20000 /* receive spectral data from element message */ static gboolean message_handler (GstBus * bus, GstMessage * message, gpointer data) { if (message->type == GST_MESSAGE_ELEMENT) { const GstStructure *s = gst_message_get_structure (message); const gchar *name = gst_structure_get_name (s); GstClockTime endtime; if (strcmp (name, "spectrum") == 0) { const GValue *magnitudes; const GValue *phases; const GValue *mag, *phase; gdouble freq; guint i; if (!gst_structure_get_clock_time (s, "endtime", &endtime)) endtime = GST_CLOCK_TIME_NONE; magnitudes = gst_structure_get_value (s, "magnitude"); for (i = 0; i < spect_bands; ++i) { freq = (gdouble) ((AUDIOFREQ / 2) * i + AUDIOFREQ / 4) / spect_bands; mag = gst_value_list_get_value (magnitudes, i); if (mag != NULL) { g_print ("%04.1f ",(g_value_get_float (mag)+80)); } } g_print ("\n"); } } return TRUE; } int main (int argc, char *argv[]) { GstElement *bin; GstElement *src, *audioconvert, *spectrum, *sink; GstBus *bus; GstCaps *caps; GMainLoop *loop; gst_init (&argc, &argv); bin = gst_pipeline_new ("bin"); src = gst_element_factory_make ("pulsesrc", "src"); g_object_set (G_OBJECT (src), "wave", 0, "freq", 6000.0, NULL); audioconvert = gst_element_factory_make ("audioconvert", NULL); g_assert (audioconvert); spectrum = gst_element_factory_make ("spectrum", "spectrum"); g_object_set (G_OBJECT (spectrum), "bands", spect_bands, "threshold", -80, "post-messages", TRUE, "message-phase", TRUE, NULL); sink = gst_element_factory_make ("fakesink", "sink"); g_object_set (G_OBJECT (sink), "sync", TRUE, NULL); g_object_set (G_OBJECT (src), "device", "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor", NULL); gst_bin_add_many (GST_BIN (bin), src, audioconvert, spectrum, sink, NULL); caps = gst_caps_new_simple ("audio/x-raw", "rate", G_TYPE_INT, AUDIOFREQ, NULL); if (!gst_element_link (src, audioconvert) || !gst_element_link_filtered (audioconvert, spectrum, caps) || !gst_element_link (spectrum, sink)) { fprintf (stderr, "can't link elements\n"); exit (1); } gst_caps_unref (caps); bus = gst_element_get_bus (bin); gst_bus_add_watch (bus, message_handler, NULL); gst_object_unref (bus); gst_element_set_state (bin, GST_STATE_PLAYING); /* we need to run a GLib main loop to get the messages */ loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); gst_element_set_state (bin, GST_STATE_NULL); gst_object_unref (bin); return 0; } |
Save this file as pulse_freq.c
. You have to install gstreamer
to get the job done:
1 | apt install gstreamer1.0-pulseaudio libgstreamer1.0-dev python3-serial |
First you need to compile the script:
1 | gcc `pkg-config --cflags --libs glib-2.0` `pkg-config --cflags --libs gstreamer-1.0` pulse_freq.c -o pulse_freq.out |
Then you have to start the Python script and play some music:
1 | python3 pretty_music.py |
This is the code for Arduino:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include <Adafruit_NeoPixel.h> #define PIN 6 Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800); String inString =""; char inChar ='!'; int n; void setup() { strip.begin(); strip.show(); // Initialize all pixels to 'off' Serial.begin(115200); } void loop() { while (Serial.available() > 0) { inChar = Serial.read(); inString += inChar; uint32_t a,off; int r1,r2,r3; a=strip.Color(2,23,45); if (inChar == '\n') { int i=0; for (i=0;i<inString.length()-1;i++){ if (i%2 ==1) { a=strip.Color(45,0,45);} else { r1=random(25); r2=random(25); r3=random(25); a=strip.Color(r1,r2,r3);} n = inString[i] - '0'; mod_col(i, n, a); } strip.show(); inString = ""; } } } void mod_col(int col, int val, uint32_t c) { int i; Serial.println(col); Serial.println(val); Serial.println(c); for (i=0;i<=val;i++) {strip.setPixelColor(col+8 *i,c); } for (i=val;i<=5;i++){ strip.setPixelColor(col+8 * i, strip.Color(0,0,0)); } } void mod_off(uint32_t off) {int i; for (i=0;i<=39;i++) {strip.setPixelColor(i,off);} } |
This is the original link of GitHub: https://github.com/ana-cc/arduino-neopixel-music-visualiser/tree/master

djazz’s Method
The method is almost similar, here is the Github Gist: https://gist.github.com/daniel-j/401d3e7bb481bea55b789c97828fd0d2
In this case, you’ll need to install ffmpeg
(on the command line) and do not need the C file.