Sound Responsive Laser (help?)

I'm pretty deep into a project using an Arduino to analyze an ambient audio source and translate it into a beat responsive laser.
Currently I have a micro servo moving the mirror for the laser, and a small microphone with preamp from SparkFun providing the audio input.

The setup looks like so:

I have a video of how it responds right now.

WARNING: The audio is VERY loud in this clip, be sure to turn down your speakers or something so I don't make your ears bleed. Sorry!

This is the code I am using:

#include <Servo.h>

int val = 0;
int envelope = 0;
int envScale = 1;
int toggle = 0;
int sendCount = 0;

Servo servo;

void setup() {
servo.attach(3);
servo.write(25);
}

void loop() {
  val = analogRead(A0) - 300;
  val = abs(val);
  if (val > envelope) {
    envelope = val;
    envScale = 1;
  }
  else {
    envelope = envelope - envScale;
    envScale++;
  }
  
  if (envelope > 280 && sendCount > 35 && toggle > 0) {
    servo.write(random(35, 47));
    sendCount = 0;
    toggle = 0;
  }
  
  if (envelope > 280 && sendCount > 35 && toggle < 1) {
    servo.write(random(23, 35));
    sendCount = 0;
    toggle = 1;
  }
  
  sendCount++;
 
  delay(10);
}

It does not work as well as I had hoped.

I believe it is one of two things, or maybe both.

First possibility:

The microphone sucks. I am using this microphone: SparkFun Electret Microphone Breakout - BOB-12758 - SparkFun Electronics

I didn't realize this before purchasing it, but it seems the microphone is only responsive down to 100hz and I believe the low pass I put on the input is about 120hz. Probably works, but could be better for hearing a kick drum.

Additionally, it doesn't have much headroom, which I am not sure how to fix. If the music gets to loud, the input clips, which sucks for a party or something, so I definitely need to replace it with something that has more headroom, and is perhaps more accurate.

Second possibility:

The code sucks.

I know a lot more about music than I do about coding (right now anyways). I know that it at minimum needs to follow the envelope of the signal, because the microphone I have doesn't measure the SPL, it just gives the raw waveform.

Any ideas?
Thanks in advance!

  • Justin

I haven't really analyzed your code, so I won't try to help with the nitty-gritty details....

If the music gets to loud, the input clips, which sucks for a party or something....

If the mic-amplifier circuit is clipping, there are a couple of things you can try. This might be tricky with the surface mount components, but you can reduce the gain of the amplifier by reducing the value of the feedback resistor (U5), or by adding a resistor (or pot) in parallel with the feedback resistor.

Or, you might be able to reduce the sound level "mechanically" by sticking a piece of cotton (or something) in front of the mic. This might also work as a (acoustic) low-pass filter.

...so I definitely need to replace it with something that has more headroom, and is perhaps more accurate.

Since you are sending an AC signal (biased at ~2.5V) into the ADC, and you are only concerned with the loudness, you can double your dynamic range by using a rectifier circuit or a [u]Peak Detector[/u] and some amplification in order to make your signal-range useful from 0V to 5V. (You'd need a precision rectifier made with an op-amp, or the ~0.5V diode drop will block low-level signals.)

I did a couple of other things to increase the dynamic range of my sound-controlled lighting. (Im not running off a microphone. I'm running off a volume-controlled line-level signal, which also varies a lot depending on the volume setting.)

I take a reading once per second, and save the value in a 20-second "rotating buffer" array. From that array I could find the 20-second moving-average and a maximum (not necessarily the maximum... just the maximum of the readings in the array). Then, I can use the average or maximum as an internal software reference. For example, one of my lighting effects simply turns the lights on if the signal is greater than average, and off when it's less than average. That gives an effect that "flickers" to the music. There is always lots of "action", since the light is on half the time and off half the time, and it automatically adjusts with the volume.

Another trick I use is to automatically switch between the 1.1V and 5V ADC references. When the maximum value in the 20-second array is below 150, I switch to the 1.1V reference (if not done already). If the maximum value in the array is above 200, I switch to the 5V reference (if not done already). Of course whenever I change the reference, I have to scale up or down the values in the array and adjust my "software" references.

You said you have a low-pass filter. Another thing you can do is make an "loudness envelope" filter, that's essentially a bandpass filter tuned around the beat-frequency (maybe 2 to 5Hz). You can do that in hardware if you use a rectifier or peak detector to get a varying DC voltage that follows the loudness. Or, you could do it in software. In software, you might not need a proper bandpass filter... Just something that "likes" signals that look-like beats, or that ignores signals that are too fast or too slow. In my design, I simply put-in a delay so that it doesn't look for a beat/peak unless about 1/4 second has passed since the last beat. The decay time on my peak detector is somewhere around 1/10th to 1/3 of a second, so that helps somewhat in following the loudness/beat too.

I have far too much to say about sound controlled lighting effects, since it's how I make a lot of my money.

In my experience, the EASIEST, and the best at the same time is to use a dedicated chip to do the heavy lifting on the audio processing. I have hundreds of the MSGEQ7 chip, and there are easily purchased shields for the Arduino that can make it absurdly easy to integrate them into any project. spark fun sells one called the Spectrum Analyzer shield. One of those and some very simple code (more simple than yours) can help you do just about anything and you can have the added benefit of being able to trivially base your laser movements on any of 7 bands of audio. This helps for making the project bass or kick responsive. If you search for the msgeq7 on this forum you'll find lots of information, or if you want you can message me, and I'll happily share all the code you like.

If you wanted to connect your device to a PC you could use PROCESSING with the MINIM module to do even more!

If I wanted to perfectly convert a kick drum to an event, it would definitely be nice to have a mic that goes down to 40Hz. This doesn't mean it can't be done with a lesser mic, but in much electronic music the kick is a very high Q KAPOW at fairly low frequencies. (A lot of the Deadmau5 and Dadda Life stuff is centered in the 46Hz ballpark.) On the other hand other tunes in electronic music land give the low end to the bass and the kick is quite a bit higher (100Hz+ sometimes). So absolute perfection may be tough.

If you are going to stick with a mic, it makes sense to get it out of the box even if you just drill a little hole.

I'm not sure if you have the coding options, but an expander under 120Hz would be nice. (A compressor with a ratio of < 1:1 will increase the transients relatively to the RMS-style bass instruments and make it easier to trigger your laser based on the kick.)

Brandon