Automatically and easily detect songs with built-in artificial intelligence
Devices and components
Arduino® UNO R4 Wi-Fi
Microphone MAX4466
Software and tools
Arduino IDE
NanoEdge AI Studio
Project description
Step 1: Setup
Step 2: Collect microphone data
Step 3: Create the classification model
Step 4: Add the model into our Arduino code
Step 5: Use the LED matrix to display the detected song
Step 1: Setup
OUT (mic) to A0 (card)
GND to one of the GNDs on the board
VCC at 3.3 V
Tools > Boards > Arduino Renesas UNO R4 Boards > Arduino UNO R4 WIFI
If you can't find it, click Tools > Boards > Boards Manager..., search for UNO R4 and install the package.
Step 2: Recording data with a microphone
Set the AMP_PIN to A0 because our microphone uses the A0 pin to send data
We define a buffer called neai_buffer to store the collected value
In our case, the buffer is of size 1024 (SENSOR_SAMPLE)
We initialize the serial number in setup()
We create a get_microphone_data() to collect data buffers from the microphone. We only get 1/32 values
We print the buffer to send it via serial.
/* Defines ----------------------------------------------------------*/
#define SENSOR_SAMPLES 1024 //buffer size
#define AXIS 1 //microphone is 1 axis
#define DOWNSAMPLE 32 //microphone as a very high data rate, we downsample it
/* Prototypes ----------------------------------------------------------*/
void get_microphone_data(); //function to collect buffer of sound
/* Global variables ----------------------------------------------------------*/
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer
int const AMP_PIN = A0; // Preamp output pin connected to A0
/* Setup function ----------------------------------------------------------*/
void setup() {
Serial.begin(115200);
delay(10);
}
/* Infinite loop ----------------------------------------------------------*/
void loop() {
get_microphone_data();
}
/* Functions declaration ----------------------------------------------------------*/
void get_microphone_data()
{
static uint16_t temp = 0; //stock values
int sub = 0; //increment to downsample
//while the buffer is not full
while (neai_ptr < SENSOR_SAMPLES) {
//we only get a value every DOWNSAMPLE (32 in this case)
if (sub > DOWNSAMPLE) {
/* Fill neai buffer with new accel data */
neai_buffer[neai_ptr] = analogRead(AMP_PIN);
/* Increment neai pointer */
neai_ptr++;
sub = 0; //reset increment
}
else {
//we read the sample even if we don't use it
//else it is instantaneous and we don't downsample
temp = analogRead(AMP_PIN);
}
sub ++;
}
//print the buffer values to send them via serial
for (uint16_t i = 0; i < SENSOR_SAMPLES; i++) {
Serial.print(neai_buffer[i]);
Serial.print(" ");
}
Serial.print("\n");
neai_ptr = 0; //reset the beginning position
}
Step 3: Classification Model
Open NanoEdge
Create a class N classification project
Select Arduino R4 WIFI board as target (other boards are compatible)
Select 1-axis microphone as sensor
Click Next
Click ADD SIGNAL
then FROM SERIAL (USB)
Start the music first (on a phone for example)
Then click START/STOP to collect data (make sure the correct COM port is selected)
Collect the pads while playing the song at least twice. Avoid empty buffers (take a break if you need to)
Click CONTINUE then IMPORT
Rename the file if you wish
repeat for each song
Click NEW BENCHMARK
Select the entire song and click START
/* Defines ----------------------------------------------------------*/
#define SENSOR_SAMPLES 2048 //buffer size
#define DOWNSAMPLE 64 //microphone as a very high data rate, we downsample it
Click INIATILIZE EMULATOR
Click SERIAL (USB)
Click START/STOP while playing a song
Step 4: Classification integration
Open the .zip obtained, there is an Arduino folder containing another zip
Import the library into the Arduino IDE: Sketch > Include Library > Add Library .ZIP... and select the .zip in the Arduino folder
The library
Some NanoEdge variants
Initializing the library in setup
Classification after collection of sound data
The output class
/* Libraries ----------------------------------------------------------*/
#include "NanoEdgeAI.h"
#include "knowledge.h"
/* Defines ----------------------------------------------------------*/
#define SENSOR_SAMPLES 1024 //buffer size
#define AXIS 1 //microphone is 1 axis
#define DOWNSAMPLE 32 //microphone as a very high data rate, we downsample it
/* Prototypes ----------------------------------------------------------*/
void get_microphone_data(); //function to collect buffer of sound
/* Global variables ----------------------------------------------------------*/
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer
int const AMP_PIN = A0; // Preamp output pin connected to A0
/* NEAI PART*/
uint8_t neai_code = 0; //initialization code
uint16_t id_class = 0; // Point to id class (see argument of neai_classification fct)
float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities
const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name
"unknown",
"song1",
"song2",
};
/* Setup function ----------------------------------------------------------*/
void setup() {
Serial.begin(115200);
delay(10);
/* Initialize NanoEdgeAI AI */
neai_code = neai_classification_init(knowledge);
if (neai_code != NEAI_OK) {
Serial.print("Not supported board.\n");
}
}
/* Infinite loop ----------------------------------------------------------*/
void loop() {
get_microphone_data();
neai_classification(neai_buffer, output_class_buffer, &id_class);
/* DISPLAY THE SONG NAME */
Serial.println(id_class);
}
/* Functions declaration ----------------------------------------------------------*/
void get_microphone_data()
{
static uint16_t temp = 0; //stock values
int sub = 0; //increment to downsample
//while the buffer is not full
while (neai_ptr < SENSOR_SAMPLES) {
//we only get a value every DOWNSAMPLE (32 in this case)
if (sub > DOWNSAMPLE) {
/* Fill neai buffer with new accel data */
neai_buffer[neai_ptr] = analogRead(AMP_PIN);
/* Increment neai pointer */
neai_ptr++;
sub = 0; //reset increment
}
else {
//we read the sample even if we don't use it
//else it is instantaneous and we don't downsample
temp = analogRead(AMP_PIN);
}
sub ++;
}
neai_ptr = 0; //reset the beginning position
}
/* Infinite loop ----------------------------------------------------------*/
void loop() {
get_microphone_data();
neai_classification(neai_buffer, output_class_buffer, &id_class);
/* DISPLAY THE SONG NAME */
switch(id_class){
case 1:
Serial.println("your song 1");
break;
case 2:
Serial.println("your song 1");
break;
//continue if you have more songs
default:
Serial.println("default");
break;
}
}
in document/arduino/libraries/nanoedge/src/NanoEdgeAI.h (commented at the end of the file)
const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name
"unknown",
"magic fs32",
"cheriecoco fs32",
"zouglou fs32",
"gaou fs32",
"ambiance fs32",
};
Step 5: Use the LED matrix to print the song name
Sketch > Include Library, we need to include the following libraries:
ArduinoGraphics
Arduino_LED_Matrix
Change the *id2 class as in the previous step
In the loop(), edit the switch to display what you want
switch(id_class){
case 1:
strcpy (text, " song1 ");
break;
case 2:
strcpy (text, " song2 ");
break;
default:
strcpy (text, " check switch in code ");
break;
}
Code_with_matrix_display
The final code
1/* Libraries ----------------------------------------------------------*/
2#include "ArduinoGraphics.h"
3#include "Arduino_LED_Matrix.h"
4#include "NanoEdgeAI.h"
5#include "knowledge.h"
6
7/* Defines ----------------------------------------------------------*/
8#define SENSOR_SAMPLES 1024 //buffer size
9#define AXIS 1 //microphone is 1 axis
10#define DOWNSAMPLE 32 //microphone as a very high data rate, we downsample it
11
12
13/* Prototypes ----------------------------------------------------------*/
14void get_microphone_data(); //function to collect buffer of sound
15
16/* Global variables ----------------------------------------------------------*/
17static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
18static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer
19int const AMP_PIN = A0; // Preamp output pin connected to A0
20
21/* NEAI PART*/
22uint8_t neai_code = 0; //initialization code
23uint16_t id_class = 0; // Point to id class (see argument of neai_classification fct)
24float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities
25const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name
26 "unknown",
27 "up",
28 "down",
29};
30
31/* Declare matrix to display */
32byte frame[8][12] = {
33 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
34 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
35 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
36 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
37 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
38 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
39 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
40 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
41};
42
43char text[30];
44
45
46/* Objects ----------------------------------------------------------*/
47ArduinoLEDMatrix matrix;
48
49
50/* Setup function ----------------------------------------------------------*/
51void setup() {
52 Serial.begin(115200);
53 delay(10);
54 matrix.begin();
55
56 /* Initialize NanoEdgeAI AI */
57 neai_code = neai_classification_init(knowledge);
58 if (neai_code != NEAI_OK) {
59 Serial.print("Not supported board.\n");
60 }
61}
62
63/* Infinite loop ----------------------------------------------------------*/
64void loop() {
65 get_microphone_data();
66 neai_classification(neai_buffer, output_class_buffer, &id_class);
67 /* DISPLAY THE SONG NAME */
68 switch(id_class){
69 case 1:
70 strcpy (text, " song1 ");
71 break;
72 case 2:
73 strcpy (text, " song2 ");
74 break;
75 default:
76 strcpy (text, " check switch in code ");
77 break;
78 }
79
80 Serial.println(id_class);
81 matrix.beginDraw();
82 matrix.stroke(0xFFFFFFFF);
83 matrix.textScrollSpeed(50);
84 matrix.textFont(Font_5x7);
85 matrix.beginText(0, 1, 0xFFFFFF);
86 matrix.println(text);
87 matrix.endText(SCROLL_LEFT);
88 matrix.endDraw();
89}
90
91
92/* Functions declaration ----------------------------------------------------------*/
93void get_microphone_data()
94{
95 static uint16_t temp = 0; //stock values
96 int sub = 0; //increment to downsample
97 //while the buffer is not full
98 while (neai_ptr < SENSOR_SAMPLES) {
99 //we only get a value every DOWNSAMPLE (32 in this case)
100 if (sub > DOWNSAMPLE) {
101 /* Fill neai buffer with new accel data */
102 neai_buffer[neai_ptr] = analogRead(AMP_PIN);
103 /* Increment neai pointer */
104 neai_ptr++;
105 sub = 0; //reset increment
106 }
107 else {
108 //we read the sample even if we don't use it
109 //else it is instantaneous and we don't downsample
110 temp = analogRead(AMP_PIN);
111 }
112 sub ++;
113 }
114 neai_ptr = 0; //reset the beginning position
115}
Downloadable files
Code_with_matrix_display
The final code
arduino_demo_shazam_matrix.ino
Note: Content and images are from: https://projecthub.arduino.cc/, with some modifications.
If you want it removed due to copyright reasons, please leave a comment. Thank you.
I want to share this article more widely so that everyone knows about Arduino and your project.