Monday, January 28, 2013

Testing the Sound Switcher board with an Arduino

So after completing my Sound Switcher board (and updating it) I wanted to use it with a microcontroller. I have a couple of aux cables lying around and some headphones to hear what is coming out of the board. Using headphones though is not ideal as it will hurt my ears after some time, as writing and testing the Arduino sketch is going to take some time. Last night I found a self powered speaker so I will use that instead (it was only $5 so worth it, and even some decent sound coming from it). Here it is:

Self Powered mini speaker
Yes, it does look like a microphone but it is actually a small speaker. It's quite ingenious, I took it apart and looked at it (forgot to take pictures) and the cool part is that it charges using the same 3.5mm input. Not
ideal if you want to listen to it and charge it at the same time but still, quite portable.

So back to the testing. Well the most important part is to have everything ready. I am using a cheap mp4 player as one of the input and my phone as the other. Because I am short of a some male-to-female header jumper cables I am using a breadboard and some tricky use of header pins ( I do have some male-male and female-female header jumper cables). Here is the full setup:

The full testing setup
And a close up of the interesting parts. Ignore the Attiny85 in the picture, I will be using that at a later time.

Test setup closeup
After fiddling around and having some problems with the setup I managed to make a sketch that works. It works for me at least, this is not guaranteed to work for everyone unless the resistors values are exactly the same. That being said the code should be easy to understand and modifications should only be needed for the global variables that define my observed reading of the nominal values coming from the monitor pin.

Here is the sketch.

The code is rather simple but I will go over the major parts of it.

The 2 functions at the end are just for switching between the 2 sources; ListenToPhone() and ListenToSound(). That being said, you should notice that at no time will there be no input selected. This is to ensure that the value being read fluctuates as little as possible. If there is no input selected than the sensorValue would be 0 (or below 2 taking into account stray currents).

//selectable source
int phonePin = 6;
//always on source
int soundPin = 7;

These are my control pins for each channel, 6 left side and 7 right side.

int sensorPin = A1;

I am only monitoring the left side so I only have one input pin setup, analog pin 1.

int qvalue = 45;

This variable holds the nominal value of the reading. So the sensing value will be something like this:
  • 0 (less than 2 to be exact) when there is not input or the monitored input is not selected
  • around 52 when there is only the selectable input and there is no sound coming through it
  • around 45 when there are 2 sources and there is no sound coming through the selectable input
This is a value that needs to change according to the sources and to the specific board that has been built. For example if I set my phone to less than have the maximum volume than the value would be somewhere around 48. The best combination of this and the delta value needs to be found.

int delta = 2;

This variable is very important, this will give you false positives if it is too low and will dismiss some sounds from the input if it is too high and you will end up not hearing the beginning of the selectable input. 2 is a value that works for me; from what I saw the variance is somewhere around 1,2 and rarely 3. I want to make sure I don't miss anything that is why I set it to 2.

int IncomingSound = 0;
int LastHigh = 99;
int MaxSilence = 20;

IncomingSound is used to signal that there should be sound comming from the selectable input. It is used as a boolean values so only 0 and 1 for this variable. LastHigh is counting the number of ticks (the number of time the loop() function has been called) since the last sensor reading was considered as positive (sound was coming from that input). MaxSilance keeps the number of ticks to keep the selectable input selected before going back to the default sound source when there has been no more positives sensor readings. The loop() function has a delay of 100 milliseconds so a value of 20 for the MaxSilence would give you approximately 2 seconds of silence before going back to the default source.

Looking at the loop() function, it basically does the following:
  • checks to see if the acceptable period of silence has passed so that it may mark it as no sound coming from the selectable input;
  • keeps the LastHigh variable to a maximum value of 100;
  • reads the monitoring pin;
  • mark as a high value if the sensor read more than 2 (meaning there is some input) and the reading deviates from the normal reading (qvalue) by more than the delta: the modulus of (qvalue - sensorValue) >= delta;
  • and last, based on the boolean value of IncomingSound set the correct input source.
The monitoring of the input only works because of the way sound is transmitted through the wires. Sound is transmitted as a variation of values. No sound means a constant value (in our case qvalue). When sound is emitted the value fluctuates creating a wave like pattern. This should help with the visualization part. Because nothing is perfect (not the wires and not the connectors, not to mention that IRL there are losses at every level) we need to have a minimum variation before we call it a sound, this is what delta is used for.

I left in the debug code that outputs to the serial port the values read so that it will be easier to note down the values you get when you have no sources, one source, 2 sources and different volume levels.

Have fun with this and try to improve my sloppy work!

No comments:

Post a Comment