2

I want to read an audio (.wav) file using C++.

So far I have read the header of the wav file. How do I loop into the data part of the wav file convert it between -1 and 1 and then write it out to a txt file.

I have done the following but when I plot the resulting txt file using MATLAB, the signal seems to be distorted.

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
//double byteToDouble( char firstByte, char secondByte );

// WAVE PCM soundfile format (you can find more in https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ )
typedef struct header_file
{
    char chunk_id[4];
    int chunk_size;
    char format[4];
    char subchunk1_id[4];
    int subchunk1_size;
    short int audio_format;
    short int num_channels;
    int sample_rate;            // sample_rate denotes the sampling rate.
    int byte_rate;
    short int block_align;
    short int bits_per_sample;
    char subchunk2_id[4];
    int subchunk2_size; // subchunk2_size denotes the number of samples.
    //char data; // actual data : Added by tarmizi
} header;

typedef struct header_file* header_p;




int main()

{
    ofstream myFile;
    myFile.open("mizi.txt");


    FILE * infile = fopen("0BF1S1T0.wav","rb");     // Open wave file in read mode
    FILE * outfile = fopen("Output.txt","wb");      // Create output ( wave format) file in write mode;
    FILE * svFile;

    int BUFSIZE = 256;                  // BUFSIZE can be changed according to the frame size required (eg:512)
    int count = 0;                      // For counting number of frames in wave file.
    short int buff16[BUFSIZE];              // short int used for 16 bit as input data format is 16 bit PCM audio
    header_p meta = (header_p)malloc(sizeof(header));   // header_p points to a header struct that contains the wave file metadata fields
    int nb;                         // variable storing number of bytes returned

    if (infile)
    {
        fread(meta, 1, sizeof(header), infile);
        //fwrite(meta,1, sizeof(*meta), outfile);


        cout << "first chunk is :" << sizeof(meta->chunk_id) << " bytes in size" << endl;
        cout << "The file is a :" << meta->chunk_id << " format" << endl;
        cout << " Size of Header file is "<<sizeof(*meta)<<" bytes" << endl;
        cout << " Sampling rate of the input wave file is "<< meta->sample_rate <<" Hz" << endl;
        cout << " Number of bits per sample is: "<< meta->bits_per_sample <<"bits" << endl;
        cout << " Size of data in the audio is: " << sizeof(meta->subchunk2_size)<< " bytes" << endl;
        cout << " The number of channels of the file is "<< meta->num_channels << " channels" << endl;
        cout << " The audio format is PCM:"<< meta->audio_format << endl;
        //cout << " The size of actual data is "<< sizeof(meta->data) << "bytes" << endl;



        while (!feof(infile))          //(nb = fread(buff16,1,BUFSIZE,infile))>0
        {
                    // Reading data in chunks of BUFSIZE
            //cout << nb <<endl;
            nb = fread(buff16,1,BUFSIZE,infile);
            count++;
                            // Incrementing > of frame
            for (int i = 0; i<BUFSIZE; i+=meta->num_channels) //  BUFSIZE = 256, meta->num_channels = 1
                {



                        int c = (buff16[i]<<8) | buff16[1+i];
                        double t = c/32768.0;

                        myFile << t<< endl;

                    }
                   


        }

    cout << " Number of frames in the input wave file are " <<count << endl;


/
return 0;
}
}

Any idea? I think I am not looping through the data and converting properly. Can anyone help show the right way in my case here?

BoP
  • 2,310
  • 1
  • 15
  • 24
tarmizi
  • 173
  • 3
  • 18
  • I assume you're aware of (libsndfile([http://www.mega-nerd.com/libsndfile/]? There seems to be a bit of wheel reinvention here. – marko Nov 17 '13 at 11:53
  • yes i am aware of it. however, I am trying to avoid depending on other libraries. ;) – tarmizi Nov 17 '13 at 15:17

3 Answers3

1

The way you are combining the two bytes into an int is always going to produce a positive result. In order to handle the sign properly you should combine the bytes into a short instead of an int.

ScottMcP-MVP
  • 10,337
  • 2
  • 15
  • 15
0

The problem seems to be in the line:

nb = fread(buff16,1,BUFSIZE,infile);

it actually reads 1 * BUFSIZE bytes, while it should read 2 * BUFSIZE bytes (2 bytes for each element). Change the line to following:

nb = fread(buff16,sizeof(short int),BUFSIZE,infile);

Also, in the line

int c = (buff16[i]<<8) | buff16[1+i];

buff16[i] should be shifted by 16 bits.

I don't know much about audio formats. So there may be other errors.

asif
  • 975
  • 8
  • 16
  • Thanks, i think i've almost got it... however there are values that are way beyond -1 and 1.... So when i plot it, these extreme values seems to distort the signal.. any clues ? – tarmizi Nov 17 '13 at 09:54
0

This code looks wrong:

int c = (buff16[i]<<8) | buff16[1+i];
double t = c/32768.0;

You should instead declare the buffer as an array of unsigned char[32].

Then compute t like this for each channel:

int hi = (signed char) buffer[i + 1]; // always little endian
int c = (hi << 8) | buffer[i + 0];
double t = c / 32768.0;
i += 2;
Roland Illig
  • 40,703
  • 10
  • 88
  • 121