Loading...
Pages: [1] 2   Go Down
Author Topic: The "Beat/Music Detection" code you have always wanted  (Read 16251 times)
0 Members and 1 Guest are viewing this topic.
Norfolk, VA
Offline Offline
Newbie
*
Karma: 1
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is my first Arduino project, it is still a work in progress.  I finished the basic core of the code and saw there was a good demand for something like this and nothing good out there, so here it is.  It should be VERY easy to adapt this to any project that involves music activated features.  I created a chopped down version of my code to show the basic concept, I'll also include the code for my testing display at the bottom.

I used two LM386 chips to filter and amplify bass and treble out of a signal that I tapped out of a 3.5mm audio extension cable, if more detail on that is desired let me know.  I feed the output of the 386's to analog inputs and the Arduino outputs digital I/O power to my LEDs.  The color LEDs show bass while the two 7-segment LEDs display high pitch treble.

Also if anyone knows where I could still find some GE g-35 color effects lights or could recommend some other LEDs ready for serial communication that would be great, thanks.


I gave up on embedding the youtube video so I just put the url and then... magic.

The most basic code that will work, it won't do anything per say, but it knows what your bass is up to.
Quote
/*  Bass Detection Basic
-Perform actions based on bass

     Created by: Matthew Kachur
*/

int tic = 0;
int Bass = 0;
int Bmin = 0;
int Bmax = 0;

void setup() {
  pinMode(A0, INPUT);
}

void loop() {
  //Loop counter, and auto correcting
  ++tic;
  if (tic > 200) {  //determines rate of correction
    ++Bmin;
    --Bmax;
    tic = 0;
  }
  
  //Order of calculations is important!!
  Bmin = min(Bmin, Bass);
  
  Bass = analogRead(A0) - Bmin;
  
  Bmax = max(Bmax, Bass);
  
  //Series of if statements to control actions
  //according to bass level
  if (Bass > 0.5 * Bmax) {
    //Do something
    if (Bass > 0.7 * Bmax) {
      //Do something more
      if (Bass > 0.9 * Bmax) {
        //Do something Crazy!
      }
    }
  }
}


Pictures of my breadboarding skills, the microphone was not used for anything, I'm finishing up code designed for use with a mic soon.




The code running on my board.
Quote
/*  Musical Light Show
-Lights up LEDs based on music input; can be easily
adapted to do any action along with music

     Created by: Matthew Kachur
*/

int tic = 0;
int Bass = 0;
int Treb = 0;
int Bdelay = 0;
int Tdelay = 0;
int Bmin = 0;
int Tmin = 0;
int Bmax = 0;
int Tmax = 0;

void setup() {
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
}

void loop() {
  //Light delays, loop counter, and auto correcting
  ++Bdelay;
  ++Tdelay;
  ++tic;
  if (tic > 200) {  //rate of music level correction
    ++Bmin;
    ++Tmin;
    --Bmax;
    --Tmax;
    tic = 0;
  }
  
  //Order of calculations is important!!
  Bmin = min(Bmin, Bass);
  Tmin = min(Tmin, Treb);
  
  Bass = analogRead(A0) - Bmin;
  Treb = analogRead(A1) - Tmin;
  
  Bmax = max(Bmax, Bass);
  Tmax = max(Tmax, Treb);
  
  //Series of if statements to control actions
  //according to bass level
  if (Bass > 0.5 * Bmax) {
    digitalWrite(2, HIGH);
    if (Bass > 0.6 * Bmax) {
      digitalWrite(3, HIGH);
      if (Bass > 0.7 * Bmax) {
        digitalWrite(4, HIGH);
        if (Bass > 0.8 * Bmax) {
          digitalWrite(5, HIGH);
          if (Bass > 0.85 * Bmax) {
            digitalWrite(6, HIGH);
            if (Bass > 0.9 * Bmax) {
              digitalWrite(7, HIGH);
              if (Bass > 0.95 * Bmax) {
                digitalWrite(8, HIGH);
                if (Bass > 0.99 * Bmax) {
                  digitalWrite(9, HIGH);
                }
              }
            }
          }
        }
      }
    }
  }
  //Bass lights refresh rate
  if (Bdelay > 20) {
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    Bdelay = 0;
  }
  
  //Determines if a high pitch instrument twankled and lights up LEDs
  if (Treb > 0.7 * Tmax) {
    digitalWrite(11, HIGH);
    if (Treb > 0.9 * Tmax) {
      digitalWrite(12, HIGH);
    }
  }
  //Trebele lights refresh rate
  if (Tdelay > 30) {
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    Tdelay = 0;
  }
}

« Last Edit: January 27, 2011, 05:25:25 pm by Arduinoid » Logged

All that is necessary for the triumph of evil is that good men do not debug.

Ky.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
The answer is 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice work. smiley
A ruff schematic of the input side would be nice. I guess my electronic skills need work smiley-confuse I have been trying to get audio from LM386’s into my nano and have had some trouble.
Thanks,
BEAN
Logged

No one knows what the question really is

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, we are new in the forum, so hi everybody!
We are doing a project with an arduino and sound detection. So we would like to know which is the maximum frequency of data adquisition by the analogic input.
After doing some experiments we have scored 8333 Hz. Is that correct?
Thank you!
Logged

Ky.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
The answer is 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for taking the time to post the schematic. It addressed the problem I was having. Just means I have to keep working at it
Thanks again,
BEAN
Logged

No one knows what the question really is

Norfolk, VA
Offline Offline
Newbie
*
Karma: 1
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You're welcome Bean.  And now for the microphone specific code.

I used a cheap electret microphone for my testing because most people, including myself, will use them for sound responsive projects, if you have a high quality microphone you can probably use the original code I posted.  This code is designed to make any project bounce, blink, or explode to music(or other noise) for the lowest cost and with minimal effort.

I used the exact same filter and amplifier circuit from before, I just put the microphone output to the audio connection instead of the 3.5mm cable audio signal.  The louder the music the better but it works at surprisingly low levels.  This code might not be as clear as the last one so let me know if there are any confusing parts.  It still auto corrects for volume and even has a built in feature to get your project dancing back on beat as fast as possible even if someone lights off some firecrackers right next to your microphone.

I had to search how to hook up an electret microphone so to save anyone some trouble I'll explain how I did it.  The legs that looks like it has multiple internal connections going to it goes to ground only.  The other leg gets one resistor(2.2k) to power(3.3V) AND a capacitor(.047uF) and resistor(10k) in series going to ground, the capacitor connects to the microphone leg.  The output of the microphone is taken from the shared leg between the capacitor and resistor in series.  I don't remember exactly why I chose the values I did, but I remember it wasn't very important, so anything close should work, if you know why to choose the values then yours will work even better.



... I forgot the code.
Quote
/*  Musical Light Show for microphones(cheap ones)

-Lights up LEDs based on music input; can be easily
 adapted to do any action along with music
 
-Specially designed for inexpensive microphones, perfect
 for your next music sensitive costume or artwork!
 
      Created by: Matthew Kachur
*/

int tic = 0;
int Bass = 0;
int Treb = 0;
int Bdelay = 0;
int Tdelay = 0;
int Bmin = 0;
int Tmin = 0;
int Bmax = 0;
int Tmax = 0;
int B = 0;
int T = 0;
int Brange = 0;
int Trange = 0;
int Hmic = 0;
int Lmic = 0;

void setup() {
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  //Light delays, loop counter, and auto correcting
  ++Bdelay;
  ++Tdelay;
  ++tic;
  
  if (tic > 1000) {  //rate of music level correction
    ++Bmin;
    ++Tmin;
    --Bmax;
    --Tmax;
    tic = 0;
    Serial.println(analogRead(A1));
  }
  
  //Order of calculations is important!!
  Bmin = min(Bmin, Bass);
  Tmin = min(Tmin, Treb);
  
  Bass = analogRead(A0) - Bmin;
  Treb = analogRead(A1) - Tmin;
  
  Bmax = max(Bmax, Bass);
  Tmax = max(Tmax, Treb);
  
  //puts you back in range after a loud noise or anti-noise? is picked up
  if (Hmic > 10000 || Lmic > 10000) {
    Bmax = (analogRead(A0) / 2) + 10;
    Bmin = (analogRead(A0) / 2) - 5;
    Tmax = (analogRead(A1) / 2) + 10;
    Tmin = (analogRead(A1) / 2) - 5;
    Hmic = 0;
    Lmic = 0;
  }
  
  //makes up for small changes in microphone output at low volumes
  Brange = Bmax - Bmin;
  B = Bass - Bmin;
  Trange = Tmax - Tmin;
  T = Treb - Tmin;
  
  //Series of if statements to control actions
  //according to bass level
  if (B > 0.5 * Brange) {
    digitalWrite(2, HIGH);
    if (B > 0.6 * Brange) {
      digitalWrite(3, HIGH);
      if (B > 0.7 * Brange) {
        digitalWrite(4, HIGH);
        Lmic = 0;
        if (B > 0.8 * Brange) {
          digitalWrite(5, HIGH);
          if (B > 0.85 * Brange) {
            digitalWrite(6, HIGH);
            if (B > 0.9 * Brange) {
              digitalWrite(7, HIGH);
              ++Hmic;
              if (B > 0.95 * Brange) {
                digitalWrite(8, HIGH);
                if (B > 0.99 * Brange) {
                  digitalWrite(9, HIGH);
                }
              }
            }
          }
        }
      }
    }
  }
  if (B < 0.5 * Brange) {
    Hmic = 0;
    ++Lmic;
  }
  //Bass lights refresh rate
  if (Bdelay > 20) {
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    Bdelay = 0;
  }
  
  //Determines if a high pitch instrument twankled and lights up LEDs
  if (T > 0.75 * Trange) {
    digitalWrite(11, HIGH);
    if (T > 0.9 * Trange) {
      digitalWrite(12, HIGH);
    }
  }
  //Trebele lights refresh rate
  if (Tdelay > 30) {
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    Tdelay = 0;
  }
}
« Last Edit: January 27, 2011, 09:59:13 pm by Arduinoid » Logged

All that is necessary for the triumph of evil is that good men do not debug.

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
do you know if i could do the same thing --> control led lights using a playlist of say 3 songs in max/msp and then sending it to arduino to change the led colors?
Logged

North Yorkshire, UK
Offline Offline
Faraday Member
**
Karma: 104
Posts: 5531
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Unfortunately not actually beat detection, I was kinda hoping for some true 'beat detection' code which is extremely difficult.

Nice work none the less smiley

Mowcius
Logged

Norfolk, VA
Offline Offline
Newbie
*
Karma: 1
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
do you know if i could do the same thing --> control led lights using a playlist of say 3 songs in max/msp and then sending it to arduino to change the led colors?
I'm not familiar with max/msp, I just got Arduino 2 weeks ago.  Any analog signal will work with this program regardless of the source.  To get bass isolated you would still need to create a filter before the signal is put into the Arduino since the code only performs actions based on amplitude and doesn't do any filtering.  I looked up max/msp and plan to mess with it in the near future so if you still have trouble I may be of more assistance later.

Unfortunately not actually beat detection, I was kinda hoping for some true 'beat detection' code which is extremely difficult.
Yes, but I couldn't think of any good reason to actually detect the beat pattern of music, if you want to play different songs or very dynamic music a program that detected beats would not be very useful.  This program allows for rapid change in music intensity and rhythm and will still perform actions based on the bass hits as long as you have a halfway decent filter. 

I can add a few lines of code to estimate BPM if you were looking for something like that.  If you have an awesome project idea that requires being able to estimate the upcoming beats in music before they are played then you can let me know and maybe it will inspire me to take up the coding challenge, for the projects I have in mind though this is all I need.
Logged

All that is necessary for the triumph of evil is that good men do not debug.

North Yorkshire, UK
Offline Offline
Faraday Member
**
Karma: 104
Posts: 5531
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I can add a few lines of code to estimate BPM if you were looking for something like that.
The main issue is that the estimated BMP changes during the song. Hmm - Perhaps the whole song can be analysed and then the bpm worked out after it has finished. That sounds like an interesting project to me smiley

I'm using an rMP3 board for my audio stuff (which will analyse the frequencies of the audio you are playing - so you can do visualisers) so I can also easily tell when the song has finished. Unfortunately my projects meter is already full so I don't think I want to try this right at the mo  smiley-razz

Btw, Rogue Robotics are currently doing a compo where you can win an rMP3 - see http://arduino.cc/forum/index.php/topic,50016.0.html

Mowcius
Logged

Norfolk, VA
Offline Offline
Newbie
*
Karma: 1
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I did a little research into measuring tempo, aka BPM, and found it to be a very non exact science.  Depending on what note being played in a song determines the beat varies.  You could make a filter to focus on the note for a particular song that defines the beat but that note and therefore the frequency the filter is looking at would need to change for different songs.  Using the the low pass filter for bass seems to work for giving you a general idea of the tempo of most songs.

I wrote some code to calculate the BPM though I still haven't thought of a good use for it, putting extra 7-segment displays to use is the best thing I thought of.  It is not accurate until 60 seconds of music has played, it is beats per minute after all, and it tracks accurately after that.  Music does change tempo during a single song so having a single BPM would still just be an average.  Anyways, here's some more code to look at for anyone interested.

Quote
/*  Bass Detection Basic with BPM
-Perform actions based on bass
-calculates a running average BPM
 
      Created by: Matthew Kachur
*/

int tic = 0;
int Bass = 0;
int Bmin = 0;
int Bmax = 0;
int Beat = 0;
int BeatTot = 0;
int BPS = 0;
int BPMray[60];
int BPM = 0;
int BPMt = 0;
long pmil = 0;

void setup() {
  pinMode(A0, INPUT);
}

void loop() {
  //Loop counter, and auto correcting
  ++tic;
  if (tic > 200) {  //determines rate of correction
    ++Bmin;
    --Bmax;
    tic = 0;
  }
  if (millis() - pmil >= 1000) {
    pmil = millis();
    ++BPMt;
    BeatTot -= BPMray[BPMt];
    BPMray[BPMt] = BPS;
    BeatTot += BPMray[BPMt];
    BPM = BeatTot/60;
    BPS = 0;
    if (BPMt >= 60){
      BPMt = 0;
    }
  }
  
  //Order of calculations is important!!
  Bmin = min(Bmin, Bass);
  
  Bass = analogRead(A0) - Bmin;
  
  Bmax = max(Bmax, Bass);
  
  //Series of if statements to control actions
  //according to bass level
  if (Bass > 0.5 * Bmax) {
    //Do something
    if (Bass > 0.7 * Bmax) {
      Beat = 1;
      //Do something more
      if (Bass > 0.9 * Bmax) {
        //Do something Crazy!
      }
    }
  }
  if (Bass < 0.5 * Bmax && Beat == 1) {
    Beat = 0;
    ++BPS;
  }
}
Logged

All that is necessary for the triumph of evil is that good men do not debug.

North Yorkshire, UK
Offline Offline
Faraday Member
**
Karma: 104
Posts: 5531
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I did a little research into measuring tempo, aka BPM, and found it to be a very non exact science.
Indeed - that's the issue smiley-grin
Logged

Offline Offline
Newbie
*
Karma: 2
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey very cool! And nice video smiley

I'm new to the Arduino world - and have been working on the exact same type of project (the implementation is a bit different, however). Here's my video:



You can see some pictures of the shield I built (and more instructions to follow) here:
http://majordecibel.blogspot.com/
« Last Edit: February 10, 2011, 01:11:16 pm by majordecibel » Logged

+++ Check out The MajorDecibel Project Review, a third party project review site spotlighting electronics projects, parts, news, and resources. If you are interested in getting some exposure for your project please contact me +++

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey Arduinoid, did you ever get around to scribbling down the schematic for this circuit?
Would love to include it in my current project.

Thanks
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
Is it possible that you can post schematics?
I like your project to do some christmas lights-
Thanks
Bye
Michael
Venezuela
Logged

Brazil
Offline Offline
God Member
*****
Karma: 1
Posts: 615
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Great project! (oh, over 1000 views?!)  smiley-eek

Wk
Logged


Pages: [1] 2   Go Up
Print
 
Jump to: