Analog music input detection

Hello all,
i want to build up a small project to auto-start my sound receiver in case active music signal is detected by the arduino.
Therefore i want to connect a 3.5 mm AUX input (for example by an Y-connector and cutting the wirres) the a Arduino UNO (1st step of the project). As soon as an active sound signal is detected (only ON or OFF) the Arduino should start the receiver (by Infrared or Relay - 2nd step of the project).
I read that the music signal is DC so its not super easy to detect something.
Therefore i am asking for help. Do i have to add something like a diode or capacitor?
Also will i get trouble with noise on the audio channel going to the receiver?

Thank you for your help :slight_smile:

Music signal is usually between 20Hz and 20KHz. For you to determine that what your arduino is getting is indeed music, I think what you have to look out for is the frequency or formants. They tell you where the energy in the sound is concentrated. That way you may have a pretty good guess that it's music. I'm not sure how you will go about that, when I did some sound project in the past, I used autocorrelation. It's highly mathematical and I'm not sure how arduino can handle it. Read about it and give it a shot.
Edit:
The 20Hz to 20KHz is off course dependent on the music sampling rate but I think it a roughly good guess

Hi olaideagbolade,
thank you for your answer.
The intention is not to identify whether the signal is music or not (sorry for confusion), the intention is to detect whether there is signal itself on the channel or not.
I would just assume that this is music.

I found this post in the forum:

I will try to follow this setup:
Audio Bias.jpg

Do you think this will do the job?

Do you think this will do the job?

Yes, that should work fine. You might have to experiment with the +/-8 value. Use the serial monitor to monitor the analog values with and without signal (like the Analog Read Serial Example, but you can leave-out the delay).

I read that the music signal is DC so its not super easy to detect something

It's AC (I think you knew that) so it's positive half the time and negative half the time and it crosses-through zero twice per cycle. The Arduino can't read negative voltages. That's why you need the bias. In fact it can be damaged by negative voltages and/or you can "damage" (distort) the audio.

That also means the readings will "look random" but your software can look for peak readings above some threshold. Of course, this is easier if the signal is not volume-controlled.

(for example by an Y-connector and cutting the wires)

I's "more professional" if you buy a connector and plug-in you Y-adapter without cutting it. Or, you can put two connectors on your Arduino and make a "pass-through" connection.

Also will i get trouble with noise on the audio channel going to the receiver?

You should be OK because the Arduino input (and the recommended 100K resistors) are high-impedance compared to the audio output. But audio circuits do tend to be noise-sensitive and our ears have a wide dynamic range so we can hear a tiny amount of noise.

P.S.
Don't short the left & right signals together. The easiest solution is to choose one or the other.

Hello DVDdoug, thank you for your detailed answer.
I tried the setup today.
With my smartphone it more or less worked, i was able to detect higher amplitudes on the signal as soon there is music playing. However with really low volume the deviation in amplitude was really small.
The real use-case for the setup is an amazon alexa echo.
Unfortunatelly with this device it worked a lot worse. The noice on the signal is higher and i really have to turn up the volume to ~80% to see a difference in the signal.

I tried to improve it with making the abs() of the signal and a maximum value detection over time:

int analogPin = A0; 
int val = 0; 
int timer = 0;
int maxi = 0;

void setup() {
  Serial.begin(9600); 
}

void loop() {
  val = analogRead(analogPin) - 511; 

  if (val<0){  
    val = -val;
  }

  if (maxi<val) {
    maxi = val;
  }

  delay(10);
  timer = timer + 1;

  if (timer>50){  
    Serial.println(maxi); 
    maxi = 0;
    timer = 0;
  }

}

I am ending up with the image attached.
From 0-50 there was low volume music.
From 50-100 it was mute.
From 100-200 there was high volume music.

Is there maybe an easier way to detect if the amazon echo dot is playing music? :frowning:

I tried a little bit more.
I took some pictures and marked the music parts with red lines.

1st picture:
The strange thing is that with my smartphone its just working fine, even with low volumen (see first pircture).

2nd picture:
When i plug in the amazon alexa dot at the beginning also a very low amplitude is measured (~3), when i turn on loud music it also works (2nd picture). However when i stop the music its not going back to the initial amplitude, but staying at a higher amplitude even when there is no music (~25).

3rd picture:
When i replug the device and play quite music its not working, its just staying at ~25 amplitude even if there is no music (3rd picture).

4th picture:
However when i replug the device during measurement the amplitude is going back to ~3 when there is no music. And ~25 when there is quite music (4th picture).

So i thing this is really strange. I dont understand why the amplitude is not going back to the initial amplitude (~3) after stopping the music. Only when i replug the device to the line-in its going back to this low amplitude.
Does someone have an idea? :frowning:

edit: Also it doesnt seem to go back to "sleep" after a certain amount of time. Still on an amplitude of ~25 after 30 min without any sound or music.
Would it maybe be easier to use a digital audio signal as an input? Something like optical audio signal (Toslink)?

Maybe your hardware setup is borked. Please post a clear wiring diagram or schematic, and image of the actual hardware if you can.

You might, if you are not getting anywhere, use a microphone module such as a Adafruit Electret Microphone Amplifier - MAX9814 with auto gain control.

You can set the gain programmaticlly through a GPIO pin. If the sound level detected by A:D conversion is too low or non existent then change to gain. I use 2 to detect sound in a room, with the gain of the microphone changing with changing conditions.

The module are fast and do not persist the data.

Hello aarg,
sure i attached pictures of the circuit.
Always possible that there are mistakes in it.

Edit:
Hello Idahowalker, i do understand your point.
However the microphone will not detect any music if the stereo receiver is still off.
And to switch it on i have to detect that there is music on the line-in channel.
So i think this will not work.

The circuit and wiring look okay, although I can’t see the Arduino pins very well. Looking at your chart, I wonder if you have an input level problem. If the input sensitivity is too high, it will amplify noise when there is no music. For troubleshooting, it would be better to examine each and every analog input value rather than process them, then report via serial as you are doing. That forces you to guess what is going on. If your sensitivity (input gain) is too high, then you will also see the signal “clipping” or squaring off at the maximum + and - values.

Similarly, if the input signal is too low, it might get swamped by noise. So verifying the input signal level directly is an important part of troubleshooting this. You have to set aside the normal purposes of your sketch, and just write code to only troubleshoot. Look directly at raw values.

Another possible problem is ground loops between the source and the device. The ground connection is shared, but might be also connected differently back through your source and Arduino power source (e.g. PC) if it is also grounded. In some cases, that can create a “battle of grounds” that introduces noise.

Let’s start with something simple. What value do you read on A0 when there is no input at all?

Hello aarg,
thank you alot for your detailed answer!
The wires are just going to 5V, GND and A0 on the Arduino.
I do agree on tackling the problem step by step :slight_smile:
So i checked the analog input value of A0 without any wire in it: Shacking between 350 to 364. Also checked A1: Between 320 to 344.
With the wire connected to A0, but no device connected to the audio line-in plug: 510 to 511.

Connecting the audio line-in plug to my phone without music: 508 to 513.
Playing low volume music on the phone: 507 to 514.
Playing high volume music on the phone: 498 to 530.
Stopping the music again on the phone: 508 to 513.

Connecting the audio line-in plug to Amazon Alexa without music: 508 to 513.
Playing low volume music on Amazon Alexa: 496 to 528.
Playing high volume music on Amazon Alexa: 450 to 550.
Stopping the music again on Amazon Alexa: 495 to 530.

I think the last part is strange. Why is the amplitude still so high after stopping the music on Amazon Alexa?
The Arduino is powered by a USB port of the PC.
phone by battery.
Amazon Alexa by a power socket, however on the same power strip like the PC.

Those numbers are way too "low" (too near 512). Something in the input chain is open, a plug, a cable or something like using the wrong wires on the plug cable. Or you don't have the ground connected properly. With that circuit and line level audio coming in, you should see at least differences in the 100-200 range. You need to try a more reliable signal source. Also are you sure about the value of the "220nF" cap? What are the part markings? If the capacitor value is too small, it might cause this problem.

By the way, it's not cool to run the signal in to the Arduino without a limiting resistor in series with the capacitor. Should be at least 1k ohms.

Your A0 readings clearly shows that what you are getting on your arduino is some sort of random readings that is not reflecting what is coming from the source.
My first guess is that the voltage level coming from your source is too low probably in order of millivolts which may be why you're getting just random readings.
If the setup still doesn't work and you're sure you did everything correctly, then it's time to change it. Use an op-amp, get the offset right and you should get something reliable. I picked this circuit off this link https://www.hackster.io/babuvaka/a-simple-arduino-based-leds-dance-to-audio-input-b48cce. While I haven't proved it, I think it will provide a good guidance. You may need to do some tweaking though.

I tried to improve it with making the abs() of the signal and a maximum value detection over time:

What you are not doing is reducing that maximum level reading so it is like a ratchet, once you reach a maximum level that is it, it stays at that maximum level, irrespective of your input signal.

You want to reduce the maximum level every so often. Use the millis timer to see if this reduction time has passed and then decrement the max value.

aarg:
Those numbers are way too "low" (too near 512). Something in the input chain is open, a plug, a cable or something like using the wrong wires on the plug cable. Or you don't have the ground connected properly. With that circuit and line level audio coming in, you should see at least differences in the 100-200 range. You need to try a more reliable signal source. Also are you sure about the value of the "220nF" cap? What are the part markings? If the capacitor value is too small, it might cause this problem.

By the way, it's not cool to run the signal in to the Arduino without a limiting resistor in series with the capacitor. Should be at least 1k ohms.

Hello aarg, thank you for the input!
Of course always possible that something is wrong with the wiring. I am a beginner so that would not supprise me :wink:
I am just wondering that the signal amplitude should be that much higher when there is sound on the line.
Because like DVDdoug wrote in the #3 post: We are searching for a 512 +/- 8 threshold to detect active sound on the line. This is a very narrow threshold i think.
Can you give me a hint how to check if the ground is fine? Dont know how to make sure that the signal source (Amazon Alexa) and Arduino are using the same ground because they are powered by different sources (Power socket and USB from PC).
I checked the capacitor, its written 224 on it. Bought it here in the local electric store, they told me its 0.22uF.
Can you tell me exactly where to put the 1k ohm resistor? Do you mean like this:
audio_1.gif
I will get a oscilloscope from the office over the weekend an measure the signal source :slight_smile:

olaideagbolade:
I picked this circuit off this link https://www.hackster.io/babuvaka/a-simple-arduino-based-leds-dance-to-audio-input-b48cce. While I haven't proved it, I think it will provide a good guidance. You may need to do some tweaking though.

Thank you for the input and diagram. However this project is using a microphone as an input. I am using a line-in 3.5 mm plug cable. Not sure if this diagram can be applied to this input source?

Grumpy_Mike:
What you are not doing is reducing that maximum level reading so it is like a ratchet, once you reach a maximum level that is it, it stays at that maximum level, irrespective of your input signal.

You want to reduce the maximum level every so often. Use the millis timer to see if this reduction time has passed and then decrement the max value.

Sorry i dont really understand what you mean.
I will try to explain what i tried to do in the code above:
Every ~10ms i am reading a new analog input value (val), if its negative i am calculating the absolute value, so that all values of val are positve.
Than i am checking ~0.5s for the highest absolute val (maxi).
After ~0.5s i am displaying the highest value of the last ~0.5s and re-set the maximum (maxi = 0) and timer (timer=0). After this the monitoring of highest value is restarted.
Do i have a wrong understanding of this?

I dont understand why the amplitude is not going back to the initial amplitude (~3) after stopping the music. Only when i replug the device to the line-in its going back to this low amplitude.

That would seem to suggest that your capacitor is very leaky or has a short on it. Try replacing the 100K resistors with 10K ones.

This code:-

val = analogRead(analogPin) - 511;

  if (val<0){  
    val = -val;
  }

Should be:-

val = abs(analogRead(analogPin) - 511)