2

I am trying to copy a WAV sound in C. the original file is a 2 seconds file, but I want to replicate the data in the destination file several times, so that it plays longer. For example, if I copy it 3 times, it should play for 6 seconds... right?

But for some reason, even though the destination file is bigger than the original file, it still plays for 2 seconds... Can anyone help please?

Here is my code:

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

using namespace std;

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()

{
    FILE * infile = fopen("../files/man1_nb.wav","rb");     // Open wave file in read mode
    FILE * outfile = fopen("../files/Output.wav","wb");     // Create output ( wave format) file in write mode

    int BUFSIZE   = 2;                  // 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 byes returned
    if (infile)
    {
        fread(meta, 1, sizeof(header), infile); // Read only the header
        fwrite(meta,1, sizeof(*meta), outfile); // copy header to destination file
        int looper = 0;                         // number of times sound data is copied
        for(looper=0; looper <2; looper++){

        while (!feof(infile))
        {
            nb = fread(buff16,1,BUFSIZE,infile);        // Reading data in chunks of BUFSIZE
            count++;                                    // Incrementing Number of frames
            fwrite(buff16,1,nb,outfile);                // Writing read data into output file
        }
        fseek(infile, 44, SEEK_SET);                    // Go back to end of header
        }
    }
fclose(infile); fclose(outfile);
return 0;
}
PhoenixBlue
  • 967
  • 2
  • 9
  • 26
  • 1
    You don't do any changements in the header of the output file. Look [here](http://soundfile.sapp.org/doc/WaveFormat/) for the format description. You should probably focus on the `Subchunk2Size` field. – Jabberwocky May 04 '17 at 09:14
  • I did not made any changes in the header. I thought about it though but even if I do change the number of samples and copy the audio once, it still plays. Of course, there are some fields that MUST stay unchanged (such as sample rate, number of channels, etc...) – PhoenixBlue May 04 '17 at 09:18
  • I don't know the details, but it seems obvious that the header must be adapted in some way to accomodate the new length. – Jabberwocky May 04 '17 at 09:20
  • 1
    Check [this Stack Overflow Entry about the WAVE Format](http://stackoverflow.com/a/28137825/3828957). It indicates that there is a *filesize* and a *data section size* which is the same as the small file in your case. – makadev May 04 '17 at 09:23
  • @makadev that post is actually not correct as well because it assumes that wav files have the same fixed-size header. – user7860670 May 04 '17 at 09:32
  • @VTT I see what you mean, but your comment lacks reasoning/references which makes it hard to follow. As far as I understand it, for a typical [RIFF WAVE](https://en.wikipedia.org/wiki/WAV#RIFF_WAVE) for PCM data with a single data chunk consisting of an array of samples copying the samples and increasing the sizes should suffice. Otherwise, if it's not (L)PCM with a single sample array it may be needed to interpret - possible many different - data (sub) chunks and write/update them. – makadev May 04 '17 at 10:21
  • @makadev actually I already wrote an answer describing these aspects – user7860670 May 04 '17 at 10:25

2 Answers2

2

Both of your read and write code parts are wrong.

wav files have RIFF format and consists of tlv chunks. Each chunk consists of header and data. Typically wav file consists of 3 chunks: format chunk with FOURCC code, format chunk with PCMWAVEFORMAT struct and data chunk with sound data. Also since size of each chunk is limited by 32 bit of length holding field, large files are constructed by concatenating wav files together.

You need to parse file chunk-by-chunk, and write into destination chunk-by-chunk, updating headers accordingly.

user7860670
  • 35,849
  • 4
  • 58
  • 84
0

When you change size of your data you'll need to update output header as well.

long total_bytes_written_to_outfile = ftell(outfile);

// correct chunk_size and subchunk2_size just before closing outfile:
fseek(outfile, 0, SEEK_SET);
int size = total_bytes_written_to_outfile - sizeof(*meta);
meta->chunk_size = sizeof(header) - sizeof(meta->chunk_id) - sizeof(meta->chunk_size) + size;
meta->subchunk2_size = size;
fwrite(meta, 1, sizeof(*meta), outfile);
fclose(outfile);

Also, to make sure you are reading correct file check that meta->chunk_size == file size of man1_nb.wav - 8

Pavel P
  • 15,789
  • 11
  • 79
  • 128
  • @PhoenixBlue It's number of bytes past chunk_size field. 36 is `sizeof(header) - sizeof(meta->chunk_id) - sizeof(meta->chunk_size)` – Pavel P May 04 '17 at 09:56