Martin
Martin

Reputation: 644

c - writing data to wav file

I'm working on an small tool that reads data from an wav file. This tool first extracts the header followed by separating the audio data into left and right channel. Audio files are just files with a sampling frequency of 44100Hz, 16Bit PCM and dual-channel.

After manipulating the data I want to write back the data to an output file and append 100 zeros on each channel. Here the problem occurs: first just half of the desired samples are append on each channel. Secondly the first half of the appended 'zeros' are random data.

See my code below

#include <stdlib.h>
#include <stdio.h>

#define BUFFSIZE 1024
#define NUM_ZEROS 100

#include <stdio.h>
#include <stdlib.h>

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;
    int byte_rate;
    short int block_align;
    short int bits_per_sample;
    char subchunk2_id[4];
    int subchunk2_size;
} header;

typedef struct header_file* header_p;


int main(int argc, char** argv){

    if( argc != 3 ){
        printf("Wrong number of input arguments. Aborting.\n");
        return -1;
    }

    char *inputFile = argv[1];
    char *outputFile = argv[2];

    FILE * infile = fopen(inputFile, "r+");
    FILE * outfile = fopen(outputFile, "w+");

    int count = 0;                                      // For counting number of frames in wave file.
    short int buff16[2*BUFFSIZE];                       // short int used for 16 bit as input data format is 16 bit PCM audio
    short int buffLeft[BUFFSIZE], buffRight[BUFFSIZE];
    header_p meta = (header_p)malloc(sizeof(header));   // header_p points to a header struct that contains the wave file metadata fields
    int nb, cnt;                                        // variable storing number of bytes returned

    printf("Buffers initialized.\n");

    if (infile)
    {
        fread(meta, 1, sizeof(header), infile);
        meta->subchunk2_size = meta->subchunk2_size + 2 * NUM_ZEROS;
        fwrite(meta,1, sizeof(*meta), outfile);


        while (!feof(infile))
        {
            nb = fread(buff16,1,BUFFSIZE,infile);       // Reading data in chunks of BUFSIZE
            count++;                                    // Incrementing Number of frames

            for(cnt = 0; cnt < nb/2; cnt++){
                buffLeft[cnt] = buff16[2*cnt];
                buffRight[cnt] = buff16[2*cnt+1];
            }

            /*
             * TODO: INSERT SIGNAL PROCESSING PART
             */

            for(cnt = 0; cnt < nb/2; cnt++){
                buff16[2*cnt] = buffLeft[cnt];
                buff16[2*cnt+1] = buffRight[cnt];
            }

            fwrite(buff16,1,nb,outfile);
        }

        for(cnt = 0; cnt < 2*NUM_ZEROS; cnt++){
            buff16[cnt] = 0;
        }
        fwrite(buff16,1, 2*NUM_ZEROS,outfile);

        printf("Number of frames in the input wave file are %d.\n", count);
    }

    fclose(infile);
    fclose(outfile);

    return 0;
}

Does somebody have an idea what I did wrong?

Upvotes: 2

Views: 3002

Answers (2)

Anty
Anty

Reputation: 1506

You have

#define NUM_ZEROS 100

and

fwrite(buff16,1, 2*NUM_ZEROS,outfile);

Aim:

I want to write back the data to an output file and append 100 zeros on each channel.

I think it should be 100 SAMPLES at each channel. As you have 16bit PCM each sample is 2 bytes. So one channel needs 200 bytes (zeros) to be written. Stereo means 400 bytes.

Your fwrite saves just 2*NUM_ZEROS so 200 bytes - this is answer to part about missing samples.

Additionally you declare

short int buff16[2*BUFFSIZE];

while reading just half of it and using half of half (nb/2) for processing. Than write full buffer (actually half of declared) with upper half full of random garbage from memory.

Upvotes: 0

Gerhardh
Gerhardh

Reputation: 12404

Are you sure that only a part of the added zeros is garbage?

You mess up the data size for fread and fwrite

Your buffers are short int:

short int buff16[2*BUFFSIZE]; // BUFFSIZE*2*sizeof(short) bytes

You read only 1/4 of that size:

nb = fread(buff16,1,BUFFSIZE,infile);  // BUFFSIZE bytes

This reads BUFSIZE bytes as you only specify a size of 1 per element. Instead of BUFFSIZE*2 shorts you only read BUFFSIZE bytes. The return value is number of read elements, i.e. bytes again. In your buffer that amount of data is only sufficient for nb/2 elements but you access buff16[0] .. buff16[nb-1] where second half of it was not read from the file. Luckily you also do not write the second half back into the new file as the same error with length is also present there. And finally the same problem is present when you append the zero values to the file.

tl;dr

Change your size parameter for fread and fwrite to sizeof(short int).

Upvotes: 1

Related Questions