cwav

How to make a program to reverse the sound of a wav clip and create a new wav file with the reversed audio in the C language


This code generates the output file successfully but no sound actually, I don't know what's wrong yet

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

#include "wav.h"
#include <string.h>

typedef uint8_t BYTE;

const int HEADER_SIZE = 44;

int check_format(WAVHEADER header);
int get_block_size(WAVHEADER header);

int main(int argc, char *argv[])
{
    // Ensure proper usage
    // TODO #1
    if (argc != 3)
    {
        printf("usage: ./reverse input.wav output.wav\n");
        return 1;
    }

    // Open input file for reading
    // TODO #2
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("could not open file\n");
        return 2;
    }

    // Read header into an array
    // TODO #3
    WAVHEADER header;
    fread(&header, HEADER_SIZE, 1, input);

    // Use check_format to ensure WAV format
    // TODO #4

    if (check_format(header) == 5)
    {
        printf("Incorrect file format\n");
        return 3;
    }

    // Open output file for writing
    // TODO #5
    FILE *output = fopen(argv[2], "w");
    if (output == NULL)
    {
        printf("could not open file\n");
        return 4;
    }

    // Write header to file
    // TODO #6
    fwrite(&header, HEADER_SIZE, 1, output);

    // Use get_block_size to calculate size of block
    // TODO #7
    int block_size = get_block_size(header);
    printf("block size is: %d\n", block_size);

    // Write reversed audio to file
    // TODO #8
    fseek(input, 0, SEEK_END);
    long here = ftell(input);

    while (here > HEADER_SIZE)
    {
        int *Buffer[4];
        fread(Buffer, 4, 1, input);
        fwrite(Buffer, 4, 1, output);

        fseek(input, -4, SEEK_CUR);
        here -= 4;
    }
    fclose(input);
    fclose(output);
}


int check_format(WAVHEADER header)
{
    // TODO #4
    BYTE *format = header.format;

    if (format[0] == 'W' && format[1] == 'A' && format[2] == 'V' && format[3] == 'E')
    {
        printf("is a wave file\n");
        return 0;
    }
    else
    {
        printf("Bad\n");
        return 5;
    }
}

int get_block_size(WAVHEADER header)
{
    // TODO #7
    int block_size = header.numChannels * (header.bitsPerSample / 8);
    return block_size;
}

I have already checked that it is an wav segment and print the header of the file, after that it is supposed to print each block from the input file to the output file starting from the end of the input file until reaching the header of the file (avoid printing the file header again), and I calculated the size of each block of the file .

We like to keep the order of channels for each audio block. For example, in a two-channel WAV file (stereophonic audio), we want to ensure that the first channel of the last input audio block becomes the first channel of the first output audio block.


Solution

  • I post this as an answer for the formatting, but I just want to explain a few things. When you open a file, that file has an associated position. That is like an index in the data. Using fseek() you can change this position, but when you simply fread() the position also increases.

    Here you seek to the end, so a few lines later, you read past the end. There's no data there. So after that seek to the end, you should seek back 4 bytes. This ensures that you start with reading the last 4 bytes.

    fseek(input, 0, SEEK_END);
    ...
    while (here > HEADER_SIZE)
    {
        ...
        fread(Buffer, 4, 1, input);
        fseek(input, -4, SEEK_CUR);
    

    Now, as you can see that read moves the position forward by 4, and then the seek moves it back by 4 as well. So you end up looping over the same bytes. Instead, you should seek back 8 bytes. The here variable is not affected by this, so you were right to decrease that with 4 every step.