Keyes microphone and binary

Hi
I am trying to use a keyes microphone to transform an audio input into binary code.

What I would like to achieve is having this microphone detecting the voice and transforming that into a sequence of 1 and 0 according to the kind if audio signal it receives (that is according to any different words).

Here is the code that I am using

int DO = 4; //Pin for Digital Output - DO
int DA = A0; // Pin for Analog Output - AO
int sensorvalue;
byte incomingByte;
int threshold = 18; //Set minimum threshold for LED lit


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

void loop() {
  sensorvalue = analogRead(DA);  //Read the analog value
  if(sensorvalue>=threshold){
    // read the oldest byte in the serial buffer:
    incomingByte = sensorvalue;
    Serial.println(bitRead(sensorvalue,0));

  } 
  else {
        Serial.println(sensorvalue);
        delay(1000);

      }

}

Now, what I get from this in the serial is a variation from 17 to 20 (that is the analogue signal value).
And when it crosses the 18 I get a sequence of 0 and 1.

However I don;t really understand how is that microphone behaving.
If I speak i
the analogue value doesn't change. it keeps on moving from 17 and 20...
I thought that the value should move from 0 to 1023 according to the voice or audio signal received.

I am probably doing or thinking something wrong or is it maybe the wrong approach?

ANyone any help please?

Cheers!!

I suggest you start by reading and displaying the analog value without the if-statement and without the delay.

The 1 second delay is just going to shut things down for one second, and I don't see what that's doing for you.

You also aren't going to get anything useful from the bit read...

DVDdoug:
I suggest you start by reading and displaying the analog value without the if-statement and without the delay.

The 1 second delay is just going to shut things down for one second, and I don't see what that's doing for you.

You also aren't going to get anything useful from the bit read...

Hi DVDdoug,
I tried what you suggested.
It doesn't change the outcome.
WHat I get without if and without delay is a sequence of the same numbers (analog value) goes from 17 to 18, 19...
If I rotate the integrated potentiometer it changes this value up to 1023, but the variation during time remains of 1 or 2 despite the value I set up.
Also I don't have variation of any sort when I speak into the mic. The analog signal remains pretty much the same.
I used the bitRead to obtain the binary value from the analogValue, but maybe this is not the meaning of it?
Thanks for helping

I gotta' get back to work, but it looks like you are reading bit zero.

If you are not used to binary, you can use the Windows Calculator in Programmer View to convert between binary and decimal. In any case bit-zero (the least significant bit) will be zero if you have a positive number, and it will be 1 if you have a negative number. With audio, that bit should appear random. If you are actually reading zero when there is silence, bit zero will also read zero with silence. (You might have some offset or noise, so "silence may not read zero.)

I still don't get why the variation of the microphone is around 2 digits and not on the entire 1023 spectrum...

DVDdoug:
In any case bit-zero (the least significant bit) will be zero if you have a positive number,

The most significant bit indicates whether a number is positive (=0) or negative (=1).

Pete

It might be me not following what you say, but my problem at the moment is that I don't understand why the analog value of this microphone variates between x and x+2... if x is the sensitivity I give to it.
It seems that it doesn't detect any sound at all...

I don't understand the point of your sketch.
If the sensor value is greater than or equal to the threshold then you print the low order bit of the value.
Otherwise you print the sensor value and delay one second.

If the sensor value stays below the threshold you are simply sampling it once per second.
OTOH if it stays above the threshold you sample and print the low order bit as fast as the processor will allow.

What information does any of that give you?

Pete

el_supremo:
The most significant bit indicates whether a number is positive (=0) or negative (=1).

Pete

Oh crap! You're right! :smiley: :smiley: ...I was in a big rush and I didn't type what my brain was thinking... The LSB in relates to odd or even. (The DAC doesn't read negative values, and since it's only 10-bits you can use either a signed or unsigned 16-bit int and you'll get a positive value.)

I still don't get why the variation of the microphone is around 2 digits and not on the entire 1023 spectrum...

I don't know what's going on either. I don't know how sensitive that thing is... You might not read the entire range unless you are at a rock concert, but you should get some good readings.

Try disconnecting the microphone board from A0, then connect A0 on the Arduino to ground. You should read zero. Then, disconnect it from ground and connect A0 to 5V. You should read 1023.

If that works, your Arduino and your sketch is working and the problem is with the microphone board. If that fails, there's most-likely an error in your sketch (or maybe your Arduino is bad, but that's unlikely).

el_supremo:
I don't understand the point of your sketch.
If the sensor value is greater than or equal to the threshold then you print the low order bit of the value.
Otherwise you print the sensor value and delay one second.

If the sensor value stays below the threshold you are simply sampling it once per second.
OTOH if it stays above the threshold you sample and print the low order bit as fast as the processor will allow.

What information does any of that give you?

Pete

Hi Pete,
my aim is getting a binary sequence out of the audio signal.
I will need a sequence of 0 and 1 to activate respectively 2 servo motors.
The delay is for me to easily read the analog value.
If I comment the line the value doesn't change in time. ANd in fact that's my problem.
As per printing the low order bit, that's probably wrong but then I need to understand how to get a binary value out of the analog signal.

I hope this makes sense?

cheers

DVDdoug:
Oh crap! You're right! :smiley: :smiley: ...I was in a big rush and I didn't type what my brain was thinking... The LSB in relates to odd or even. (The DAC doesn't read negative values, and since it's only 10-bits you can use either a signed or unsigned 16-bit int and you'll get a positive value.)
I don't know what's going on either. I don't know how sensitive that thing is... You might not read the entire range unless you are at a rock concert, but you should get some good readings.

Try disconnecting the microphone board from A0, then connect A0 on the Arduino to ground. You should read zero. Then, disconnect it from ground and connect A0 to 5V. You should read 1023.

If that works, your Arduino and your sketch is working and the problem is with the microphone board. If that fails, there's most-likely an error in your sketch (or maybe your Arduino is bad, but that's unlikely).

Hi,
I tried what you suggested.
I had strange values.
A0 to G is giving me values.
A0 to V is giving me values.
I tried different analog pins
A5 to F is giving me 0 as weel as to V...
I was pretty confused.
Basically I simplified the code a the minimum so at the moment I am just reading the bytes when the sensor detects something over the threshold.

int DO = 4; //Pin for Digital Output - DO
int DA = A5; // Pin for Analog Output - AO
int sensorvalue;
byte incomingByte;
int threshold = 50; //Set minimum threshold for LED lit

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

void loop() {
  sensorvalue = analogRead(DA);  //Read the analog value
  if(sensorvalue>=threshold){
    // read the oldest byte in the serial buffer:
    incomingByte = sensorvalue;
    Serial.println(bitRead(sensorvalue,0));


  } 
  
}

I am getting pretty much what I want, however it is a strange thing as the microphone reacts if I blow on it but nothing happens if I speak...
Any idea?

thanks again

I am getting pretty much what I want, however it is a strange thing as the microphone reacts if I blow on it but nothing happens if I speak...

With a normal voice, the microphone is probably not sensitive enough to reach the threshold of 50.

If you take-out the threshold limit (you can add it back later) you should get a better idea of the readings, and that should also make it easier to adjust the sensitivity pot.

Also, an [u]audio waveform[/u] jumps all over the place. It's negative half of the time and it crosses through zero twice per cycle. A single reading is meaningless... You have to take many readings (quickly) and for what you are trying to do, maybe pick-out the peaks and ignore the rest.

A one second delay means you are reading the waveform at one "random" point in time once per second. Just as a reference point, CD audio is 44.1kHz, which means it's sampled 44,100 times per second... You don't have to sample that fast, or at any known sample rate, but once per second is going to be mostly useless unless you get lucky and "catch" a peak.

serialPrint will slow-down your sketch, but you should get some good numbers.

At the moment, you are not using IncommingByte, but a byte is 8 bits and it won't hold the 10-bit ADC value.
For example 1023 is 11 1111 1111 in binary.
If you throw-away the two top bits you get 1111 1111, which is 255 in decimal.
A value like 11 0000 0000 (decimal 768) would be converted to 0000 0000 (decimal zero).

(You don't need to know much about binary, but everything in a computer or microcontroller is in binary and you should understand that converting a 10-bit value to an 8-bit byte will corrupt the data.)

As per printing the low order bit, that's probably wrong but then I need to understand how to get a binary value out of the analog signal.

What kind of "binary value"? A single bit (or single binary state) of zero or one? Or an 8-bit or 16-bit binary number?

If you just want a one or zero, (reading a one whenever the analog threshold setting of the pot is reached) you should be able to use the digital output from your microphone board into a digital input on the Arduino.

I will need a sequence of 0 and 1 to activate respectively 2 servo motors.

I don't get that, but you'll need to take that one & zero data and then convert that to an angle to be used by a servo library... Sending a "random" sequence of ones & zeros derived from an audio waveform isn't going to work.

You might need to read the audio in a "tight loop" and then briefly break-out of the loop when it's time to send a "message" to the servo.

Hi DVDdoug,
you spent quite a lot of time on this post, thanks a lot. it's very much appreciated.
What you say sounds clear but I need somehow to read more about this and understanding in depth.

I'll try to explain better what's my aim.
I want to speak into the microphone and transforming the input into a binary sequence. To say it in other words I would like to get the way machine read that audio input.

everything in a computer or microcontroller is in binary

.
ADC in Arduino is at 10bits and I missed that. this was very useful indeed

At the moment, you are not using IncommingByte, but a byte is 8 bits and it won't hold the 10-bit ADC value.
For example 1023 is 11 1111 1111 in binary.
If you throw-away the two top bits you get 1111 1111, which is 255 in decimal.
A value like 11 0000 0000 (decimal 768) would be converted to 0000 0000 (decimal zero).

So now here is the code

int DO = 4; //Pin for Digital Output - DO
int DA = A5; // Pin for Analog Output - AO
int sensorvalue;
int threshold = 50; //Set minimum threshold for LED lit

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

void loop() {
  sensorvalue = analogRead(DA);  //Read the analog value
  if(sensorvalue>=threshold){
    Serial.println(bitRead(sensorvalue,0));

  } 
  
}

this way I can get a sequence of 1 and 0 as I want.
I guess this is the bit value of the analogue value?

I don't get that, but you'll need to take that one & zero data and then convert that to an angle to be used by a servo library... Sending a "random" sequence of ones & zeros derived from an audio waveform isn't going to work.

You might need to read the audio in a "tight loop" and then briefly break-out of the loop when it's time to send a "message" to the servo.

About the servo motors, the 1 and 0 will not control the angle but they will just activate either 1 or the other servo.
The angle of the servo will be set in another part of the code and it should be independent.

Also, yes I will need to condition the code so that for each 0 the servo 1 starts and for each 1 the servo 2 starts. These servos must not work at the same time and I ideally I wanted to create a vector to store the binary sequence and then release the single value once at time. But it seems arduino code doesn't like vectors.. so I need ot find another solution.

Anyway, thanks a lot for your help, I played around with the threshold and sensitivity and now at least I get what I needed for the binary sequence!

:slight_smile:

Again, if you read bit-zero from a digitized audio waveform you are going to get a random sequence of ones & zeros, depending on if the instantaneous value is an odd or even number. And if you don't hit the threshold, you won't send anything to the serial monitor.

Are you getting anything? Last time, you said you were getting something when you blow on the mic, but not when you speak. If you're still not getting anything when you speak, did you try taking out the threshold? Or, try lowering the threshold.

I think you are on the wrong track with binary... You CAN make a binary decision (i.e. If signal > X, activate servo 1, else activate servo 2) without using binary numbers. If you want to turn that decision into a binary 1 or 0, you can also do that without bit-reads or any of that bitwise stuff.

Although the microcontroller uses binary internally, C/C++ will automatically convert values to decimal (and characters to ASCII text) so you can to a TON of programming without worrying about binary numbers of bitwise operations.

You might also be on the wrong track with the threshold... Maybe it's just because you've simplified the code (a good thing right now), but right now you are ignoring everything below the threshold. Maybe that's OK for your final program logic, but it could be an issue now. And/or, you may need to change that threshold.

Your microphone board also has a binary (digital) output that turns on when you reach a certain loudness level. I don't know how that works, but I assume it also jumps up & down a lot when you cross the threshold (just because of the nature of sound/audio).

You probably WILL need a delay between servo changes/messages, but you probably don't want a delay between audio readings. That means you'd have to use the delay method from the Blink Without Delay example instead of the delay() function so your sketch doesn't freeze during the delay() time.

To say it in other words I would like to get the way machine read that audio input.

The [u]Audacity website[/u] has a simple introduction to how digital audio is sampled and then reproduced as analog by "connecting the dots". For what you are doing, you don't need to re-convert to analog and I don't think you need to sample at a known-constant rate. But, you probably will benefit from sampling as fast as you can (in a loop with no delay).


I kinda' hate to hit you with this... But for my sound activated lighting effects, I use a [u]Peak Detector Circuit[/u]. It turns the audio signal into a slowly (or slower) changing DC voltage, that's proportional to the peak audio level. I don't remember what timing resistor and capacitor I used (C1 & RL) but it "holds" the loudness for a fraction of a second and I read that voltage about 10 times per second.

I run it from a line-level audio signal, not from a microphone. In your case, the peak detector would go between the microphone board and the Arduino's analog input.

A peak detector circuit is NOT NECESARY. It can all be done in software... Actually, you can do MORE in software.... But the peak detector allows me to simplify the software, and the software can spend it's time doing other things and only sample the volume at about 10 times per second instead of sampling the audio waveform thousands of times per second.

Hi DVDdoug,
At the moment I managed to have the mic working with the voice. so I arranged the threshold and sensitivity so that whenever I speak I get in the Serial a sequence of 1 and 0.
So now, I am not sure what that binary is. Maybe is just a binary translation of the decimal value that I get from the analogue signal? (i.e, if the signal I get is 100,259,129 ETC.. I get the binary conversion of these values.)
It might be good for my purpose, as long as I get a binary sequence out of the audio signal, this is fine.

So, now you think this is the end of the story right? well, it is not!:slight_smile:
I decided I was happy with this first part of the code and I implemented it so that I could control the binary sequence.
In my head the best way is using a vector where I dynamically store the 1 and 0 once converted. Then i can use these 1s and 0s to control my servos like I want.
I prepared a sort of diagram for that here.

and here is the code I prepared for storing the binary sequence. However I get very weird results in the Serial...
I get a sequence of 0000000 and then blocks of numbers.

Can you spot anything odd there?

int DO = 4; //Pin for Digital Output - DO
int DA = A5; // Pin for Analog Output - AO
int sensorvalue;
int threshold = 100; //Set minimum threshold for LED lit
int bitvalue;
int count = 0;
int myBinary[40]; //vector to store the binary sequence 10bits
int arraySize;
boolean shoot;
boolean arrayReady;
int timeSilence = 5000;
int silence;
int bitVal;


void setup() {
  Serial.begin(9600);  
  arraySize = sizeof(myBinary);
  silence = 0;
  arrayReady=false;
}

void loop() {
  sensorvalue = analogRead(DA);  //Read the analog value
  //  bitvalue = (bitRead(sensorvalue,0)); //transforming the analogue value in bit

  //if the voice overcome the threshold put the binary values in my array
  if(sensorvalue>=threshold)
  {

    bitVal = bitRead(sensorvalue,0);
//    Serial.write(bitVal);


    //iterate for the size of array and put all the values in the array
    for (int i=0;i<=arraySize;i++)
    {

      myBinary[count] = bitVal ;    //add the sensorvalue to the array
      count++;
      Serial.println(myBinary[count]);

      //    Serial.println(bitvalue);
      //    Serial.println(sensorvalue);
    }
    silence = millis();
    arrayReady=true;


  } 


  //let's check if there is enough silence to activate the motors.
  if(millis() - silence>=timeSilence && arrayReady){

    for (int i=0;i<=arraySize;i++)
    {
      //      Serial.println(myBinary[count]);
      //      delay(1000);

    }

  }

  //    arrayReady = false;


}

Thanks!!

Adani, I need to tell you I'm not an expert programmer and I'm not the best person to help you with the nitty-gritty details of your program. I've done lots of programming over the years in several different programming languages and I've even written some programs for work. But, I have to constantly refer to my programming books and I write my code in little bits at a time.

Now... Let's back-up a bit... What kind of information are you trying to get from the sound? I'm getting the impression that you are trying to get two states:

1 - Sound is above the threshold.
2 - Sound is below the threshold or silent.

:smiley: I suppose I should have started counting with "state 0", since we are in the digital/programming world.

Then, you want to collect this information, put it into an array, and use it later to control a couple of servos?

So now, I am not sure what that binary is. Maybe is just a binary translation of the decimal value that I get from the analogue signal? (i.e, if the signal I get is 100,259,129 ETC.. I get the binary conversion of these values.)

So... Let's convert these example numbers to binary to see if that gives you anything useful... (I'm using the Windows calculator in programming view).

100 decimal = 1100100 binary
259 decimal = 100000011 binary
129 decimal = 10000001 binary

Or, if we have a type int and we look at all 16-bits, we'd get this:*
0000 0000 0110 0100
0000 0001 0000 0011
0000 0000 1000 0001

Are those numbers (or patterns/sequences) helpful for what you're trying to do?

Note that bit zero (the rightmost bit) corresponds to odd & even. If you bitRead bit zero from those three numbers and stuff it into an array (left to right), you'll get 110.

Is that array at all helpful for what you're trying to do?

 //iterate for the size of array and put all the values in the array
    for (int i=0;i<=arraySize;i++)
    {

      myBinary[count] = bitVal ;    //add the sensorvalue to the array
      count++;
      Serial.println(myBinary[count]);

      //    Serial.println(bitvalue);
      //    Serial.println(sensorvalue);
    }

So... Although I'm still not sure what you're trying to do, I can tell you what you're doing wrong. :wink:

Before going into your for-loop, you read bitVal once. That's going to be 1 or 0, depending on if sensorvalue is odd or even.

Then, your for-loop writes that same bitVal into your array 40 times.

i<=arraySize;

That looks like a small error too... Your 40 element array is counted 0-39 (not 0-40), so I think that should be i < arraySize.


* Totally off-topic:

It's traditional to break binary numbers into 4-bit "nybbles" because it makes it easier to read and it's easier to convert to hexadecimal. It's also very common to use hex when working with binary numbers/patterns because it's a LOT easier to read & write than binary.

It's easy to convert between hex and binary (a LOT easier than converting between decimal and binary) because each group of 4 bytes represents exactly one hex digit.

That means you only have to memorize 16 conversions and you can convert numbers of any size between hex and binary in your head!

You actually only need to memorize 14, since 0 and 1 are the same in hex, decimal, and binary. And some are easy to remember... (such as F = 1111, 5 = 0101, A = 1010, etc.)

Hi DVDdoug,
I finally have time to get back to you.
I read your comments and I found it useful, thanks!
I am proceeding with the code and the circuit now. The mic is working ok and I found a library that behaves like vectors. Or quite...
In fact I suspect my previous problem was that the array wasn't filled properly and this is why I got weird results.
I think it's everything set up now, my only problem is how to access the index of the array using the library. Common way doesn't work.

I will post something on the code section maybe.

anyway, here is the code I am using, pretty straightforward.
but apparently the access to index works in a different way.

for( int i=0;i<queue.count();i++){

println(queue*);*
}
this is the library if you want to have a go!
Arduino Playground - QueueArray Library
Cheers!
:wink:

update can beuseful: module datasheet.
or http://www.mpja.com/download/31072mp.pdf