0
votes

I wrote a code that supposedly should read an audio file as an input in order to write a csv file containing every sample. This is the code:

FILE *pipein;
          pipein = popen("ffmpeg -i test1.wav -f s16le -ac 1 -", "r");
          fread(buf, 2, sample_number, pipein);
          pclose(pipein);

          // Print the sample values in the buffer to a CSV file
          FILE *csvfile;
          csvfile = fopen("samples.csv", "w");

          while (n<=sample_number) {

            //if (buf[n]!=0) {

                    fprintf(csvfile, "%d %f\n", buf[cont], Sam_freq*cont);
                    cont++;

         //  }

             n++;

          }

          fclose(csvfile);

This is how the csv file looks like after running the code:

10 43.150544
-36 43.150567
11 43.150590
30 43.150612
-29 43.150635
61 43.150658
13 43.150680
46 43.150703
121 43.150726
61 43.150748
144 43.150771
128 43.150794
130 43.150816
131 43.150839

I tried to plot the data of samples.csv using gnuplot but I don't understand which physical dimension is represented on y axis.

waveform plot I read on other posts that values on y axis represent the deformation of the membrane in the microphone. Does anyone know a mathematical relation in order to extract from these values the physical dimension I need?

1
Possible duplicate of PCM audio amplitude values?user8153

1 Answers

4
votes

Issues:

  1. That is not a CSV file, it is just a text file.

  2. Your code does not look like that. It is far from being compilable, and you made mistakes copying the "relevant parts" to this question.

    In particular, you used n as the loop variable, but cont in accessing the buffer. If your code was actually that, you'd only see a single pair of values, duplicated, in the output.

  3. You do not define the sample rate.

Consider the following counter-example:

#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <string.h>
#include <endian.h>
#include <stdio.h>

#ifndef   SAMPLE_RATE
#define   SAMPLE_RATE  48000
#endif

#define  NO_SAMPLE  INT_MIN

#if (__BYTE_ORDER-0 == __BIG_ENDIAN-0)

/* Use big-endian samples */

#define  SAMPLE_FORMAT  "s16be"
static inline int read_sample(FILE *source)
{
    int16_t sample;

    if (fread(&sample, sizeof sample, 1, source) == 1)
        return (int)sample;
    else
        return NO_SAMPLE;
}

#elif (__BYTE_ORDER-0 == __LITTLE_ENDIAN-0) || (__BYTE_ORDER-0 == __PDP_ENDIAN-0)

/* Use little-endian samples */

#define  SAMPLE_FORMAT  "s16le"
static inline int read_sample(FILE *source)
{
    int16_t sample;

    if (fread(&sample, sizeof sample, 1, source) == 1)
        return (int)sample;
    else
        return NO_SAMPLE;
}

#else

/* Use little-endian (two's complement) samples, but
   read them byte-by-byte. */

#define  SAMPLE_FORMAT  "s16le"
static inline int16_t read_sample(FILE *source)
{
    unsigned char  bytes[2];
    int            sample;
    if (fread(bytes, 2, 1, source) != 2)
        return NO_SAMPLE;

    sample = bytes[0] + 256*bytes[1];
    if (sample > 32767)
        return sample - 65536;
    else
        return sample;
}
#endif

int main(void)
{
    const double   sample_rate = SAMPLE_RATE;
    FILE          *in;
    unsigned long  i;
    int            sample;

    in = popen("ffmpeg -i test1.wav -v -8 -nostats -f " SAMPLE_FORMAT " -ac 1 -", "r");
    if (!in)
        return EXIT_FAILURE;

    i = 0u;
    while ((sample = read_sample(in)) != NO_SAMPLE) {
        printf("%.6f %9.6f\n", (double)i / sample_rate, (double)sample / 32768.0);
        i++;
    }

    pclose(in);

    return EXIT_SUCCESS;
}

It assumes the sample rate is 48,000 samples per second (you could use ffmpeg to find out the sample rate first), then prints out each sample, one sample per line, with time in the first column, and sample value (-1.0 to just under +1.0) in the second column.

In the physics sense, the first column reflects the time dimension of the sample, and the second column the relative pressure change at that moment in the sensor -- however, neither the sign or the linearity of the pressure change is really known for sure, as it depends on the exact microphone, amplification, and ADC used.

Let's say you compile and run the above, redirecting the output to test1.out:

gcc -Wall -O2 example.c -o example
./example > test1.out

You can draw this in Gnuplot easily. Start gnuplot, and tell it

set xlabel "Time [seconds]"
set ylabel "Relative pressure change [f((P-P0)/Pmax)]"
plot "test1.out" u 1:2 notitle w lines

For the vertical axis, P is the pressure at the moment indicated on the horizontal axis, P0 is the ambient pressure, Pmax is the maximum pressure change the microphone can detect, and f() is the inverse of the nonlinearity of the microphone, microphone amplifier, and analog-to-digital converter circuitry used. (Both f() and Pmax likely depend on the ambient pressure P0, too.)