QC

How to do automatic song classification

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.

Easy remote control

Remotely control an LED with ease. Devices and components Arduino Nano 33 BLE with headers Box 525 Resistors precision 1% - 17 values Breadb...