Alexandre
Alexandre

Reputation: 3170

cpp raw audio to analog values

A microphone or a sound generate different current. I would like to extract this information from a raw audio file.

I get the raw data from the microphone with the following command:

arecord -t raw -f cd

Now I would like to analyse the raw data in order to extract the signal from 0V to 5V. But I have no idea about how to proceed.

I tried a bit but it is absolutely not successful, I think I am very far from the solution.

#define BUFSIZE 8

uint8_t analogRead() {
    uint8_t buf[BUFSIZE];
    //cout << "analogRead" << endl;
    read(STDIN_FILENO, buf, sizeof(buf));


    size_t size = sizeof(buf);
    double accum = 0;
    int const n_samples = size/2;
    for (int i = 0; i < size; i += 2)
    {
        // put two bytes into one __signed__ integer
        uint8_t val = buf[i] + ((uint8_t)buf[i+1] << 8);

        accum += val*val;
    }
    accum /= n_samples;

    cout << accum << endl;

    return accum;    
} 

int main(int argc, char** argv) {
    while(1) {
        cout << analogRead() << endl;
    }

    return 0;
}

Then I run my test like this:

arecord -t raw -f cd | ./mytest

Upvotes: 0

Views: 202

Answers (1)

ACCurrent
ACCurrent

Reputation: 385

Your types are all over the place. Analog read is declared as returning a uint8_t but it returns a double in your actual implementation.You seem to have misunderstood either the read()function or the sizeof operator. The first argument is correct, it is the file descritpor. The second argument is the buffer which is also correct. The 3rd argument is the size of the buffer. This is not obtained by the sizeof operator rather one would use BUFFER_SIZE*sizeof(uint8_t).

Furthermore you're command line arguement says to output the audio in cd format. CD format uses two tracks to create the stereo effect, we are only interested in one for uspeech. If you look at the man page for arecord it specifies:

  -f --format=FORMAT
          Sample format
          Recognized sample formats are: S8 U8 S16_LE S16_BE U16_LE U16_BE
          S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE U32_BE FLOAT_LE
          FLOAT_BE FLOAT64_LE  FLOAT64_BE  IEC958_SUBFRAME_LE  IEC958_SUB-
          FRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG GSM
          Some of these may not be available on selected hardware
          There are also two format shortcuts available:
          -f cd (16 bit little endian, 44100, stereo [-f S16_LE -c2 -r44100]
          -f dat (16 bit little endian, 48000, stereo) [-f S16_LE -c2 -r48000]
          If no format is given U8 is used.

For simplicity sake you'd prefer -c1. You could use any of the above formats. Since you chose uint8_t, it would be easiest if you used U8. Then you could rewrite your analog read function as:

  uint8_t analogRead() {
       uint8_t buf[1]; //This will read 1 byte at a time. Its not efficient but its the closest you will get to analogRead() if you're thinking in arduino terms.
       read(STDIN_FILENO, buf, 1);
       return buf[0];
  }

So once you fix it then you use the program like

arecord -t raw -f u8 -c 1 | ./mytest

Upvotes: 1

Related Questions