0
votes

I am trying to read the data from SPH0645LM4H-B https://www.knowles.com/docs/default-source/model-downloads/sph0645lm4h-b-datasheet-rev-c.pdf?sfvrsn=4 and convert it to .wav format, so that I can verify whether my sensor is working correctly. So far, I have managed to interface the sensor and read data samples via i2s-dma transfer.

Also, I found that most mainstream computer soundfile formats consist of a header (containing the length, etc.) followed by 16-bit two's-complement PCM https://www.dsprelated.com/freebooks/mdft/Number_Systems_Digital_Audio.html

For converting the PCM data to wave format, I have referred converting PCM to wav file

Now, the sensor data format is I2S, 24-bit, 2’s compliment, MSB first. The data precision is 18 bits; unused bits are zeros. I have converted the sensor data to 32-bit (MSB is the sign bit)

I have used the code from the following link (and the links mentioned in it) to create the .wav file:- Append .pcm audio raw data into wav (in C)

//.wav file header data

struct wavfile
{
char            id[4];          // should always contain "RIFF"
int             totallength;    // total file length minus 8
char            wavefmt[8];     // should be "WAVEfmt "
int             format;         // 16 for PCM format
short           pcm;            // WAVE_FORMAT_IEEE_FLOAT (3).
short           channels;       // channels
int             frequency;      // sampling frequency, 16000 in this case
int             bytes_per_second;
short           bytes_by_capture;
short           bits_per_sample;
char            data[4];        // should always contain "data"
int             bytes_in_data;
};

//Writing the header to output .wav file

void write_wav_header(char* name, int samples, int channels)
{
struct wavfile filler;
FILE *pFile;
strcpy(filler.id, "RIFF");
filler.totallength = (samples * channels) + sizeof(struct wavfile) - 8;
strcpy(filler.wavefmt, "WAVEfmt ");
filler.format = 16;
filler.pcm = 3; // WAVE_FORMAT_IEEE_FLOAT (3).
filler.channels = channels;
filler.frequency = 32000;
filler.bits_per_sample = 32;
filler.bytes_per_second = filler.channels * filler.frequency * filler.bits_per_sample/8;
filler.bytes_by_capture = filler.channels*filler.bits_per_sample/8;
filler.bytes_in_data = samples * filler.channels * filler.bits_per_sample/8;
strcpy(filler.data, "data");
pFile = fopen(name, "wb");
fwrite(&filler, 1, sizeof(filler), pFile);
fclose(pFile);
}

//Appending the audio sensor data to this .wav file

void write_pcm_data_to_file(char* inFile, char* outFile)
{
char buffer[SAMPLE_SIZE];
size_t n;
FILE *fin,*fout;
fin = fopen(inFile,"r");
fout = fopen(outFile,"a");
while((n = fread(buffer, 1, sizeof(buffer), fin)) > 0)
{
    if(n != fwrite(buffer, 1, n, fout))
    {
        perror("fwrite");
        exit(1);
    }
}
fclose(fin);
fclose(fout);
}

This is how the resulting .wav file looks in hex editor:- .wav file in hex editor I can see that the wav header values are set correctly, followed by my PCM data from Audio Sensor.

However, when I play the .wav file, I am not able to play the input audio. Instead, I hear a constant tone. I tried changing the input audio (played different music, songs), yet the resulting .wav file plays the same constant tone.

In order to recreate the input music played to the microphone into a wav file, what modifications should I do?

Thanks in advance.

Edit:-

According to 42LeapsOfFaith 's answer, to convert my samples to hex, I used the following code:-

hexValue = strtoll(sample, NULL, 16);

I converted each value in the buffer, then wrote it into my .wav file. Now my .wav file looks like modified .wav file in hex editor

However, even this wav file does not play the audio. Any further suggestions to recreate the input music played to the microphone into a wav file?

Help is very much appreciated

1

1 Answers

2
votes

For starters, you are storing the PCM data in the file as ascii-hex. I hope that helps.

This is a 'hack' you can use...

char c[2];
while((n = fread(&c[0], 2, 1, fin)) > 0)
 { 
    if (c[0] > 0x39) c[0] -= 7;
    c[0] &= 0x0F;
    if (c[1] > 0x39) c[1] -= 7;
    c[1] &= 0x0F;
    c[1] |= c[0] << 4;
    if(1 != fwrite(&c[1], 1, 1, fout))