C language: change file sound volume


In the fourth week of the CS50 (Harvard) course, we learned how to work with memory, which will help you perform a laboratory work on changing the volume of the sound in a .wav file using a program that receives the original music file and receives the value of the factor via the command line (how many times you need to change volume). So if the user enters a factor of 2, this means that the resulting file should become twice as loud (volume.c).

To complete this task, you need to take into account that the music file has a 44-byte header that contains metadata, and only after that there are 2-byte (16-bit) values ​​that describe the sounds. To overwrite a new file with a changed volume, you need to read and change the values ​​of each of the two bytes that describe the sound. To separate the header values, you can enter a new uint8_t header[44] data array, and write the rest of the values ​​into an int16_t buffer (these are two special types of variables that can then be used as an argument in the fread and fwrite functions).

Programme code by Shtukensia

// Modifies the volume of an audio file

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

// Number of bytes in .wav header
const int HEADER_SIZE = 44;

int main(int argc, char *argv[])
{
    // Check command-line arguments
    if (argc != 4)
    {
        printf("Usage: ./volume input.wav output.wav factor\n");
        return 1;
    }

    // Open files and determine scaling factor
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    FILE *output = fopen(argv[2], "w");
    if (output == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    float factor = atof(argv[3]);

    // Copy header from input file to output file
    uint8_t header[HEADER_SIZE];

    fread(header, HEADER_SIZE, 1, input);
    fwrite(header, HEADER_SIZE, 1, output);

    // TODO: Read samples from input file and write updated data to output file

    int16_t buffer;
    int buffer_size = 2;
    while (fread(&buffer, buffer_size, 1, input))
    {
        buffer *= factor;
        fwrite(&buffer, buffer_size, 1, output);
    }

    // Close files
    fclose(input);
    fclose(output);
}

Code from Igroglaz with detailed comments:

// Modifies the volume of an audio file

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

// Number of bytes in .wav header
const int HEADER_SIZE = 44;
// array to store header data
uint8_t header[HEADER_SIZE];
// variable which will be used as buffer - to store minimum audio sample
int16_t buffer;

int main(int argc, char *argv[])
{
    // Check command-line arguments
    if (argc != 4)
    {
        printf("Usage: ./volume input.wav output.wav factor\n");
        return 1;
    }

    // STEP 1: open files and determine scaling factor:

    // open input file with 'read' mode
    FILE *input = fopen(argv[1], "r");
    // check was it opened correctly
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    // open output file with 'write' mode
    FILE *output = fopen(argv[2], "w");
    // check was it opened correctly
    if (output == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    // convert volume factor from char to float
    float factor = atof(argv[3]);

    // STEP 2: copy header from input file to output file

    //- 1) read the header (44 bytes) from input file

    // fread() - read bytes from file to memory
    // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

    // reads `nmemb` items of data,
    // each `size` bytes long,
    // from the stream pointed to by `stream`,
    // storing them at the location given by `ptr`.

    fread(header, 1, HEADER_SIZE, input);

    //- 2) write the header (44 bytes) to output file

    // fwrite() - write bytes from memory to file
    // size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);

    // writes `nmemb` items of data,
    // each `size` bytes long,
    // to the stream pointed to by `stream`,
    // obtaining them from the location given by `ptr`.

    fwrite(header, 1, HEADER_SIZE, output);

    // !!! fopen() "remembers" the number of bytes that were successfully read.
    // So until we fclose() - we can continue to work with the rest of data !!!

    // STEP 3: read samples from input file and write updated data to output file

    // 1) make a loop until we got to the end of file (EOF)
    // 2) read whole file
    // 3) multiply by factor

    while (fread(&buffer, 2, 1, input))
    {
        buffer = buffer * (float)factor;
        fwrite(&buffer, 2, 1, output);
    }

    // Close files
    fclose(input);
    fclose(output);
}

This entry was posted in C language (en). Bookmark the permalink.

Leave a Reply

🇬🇧 Attention! Comments with URLs/email are not allowed.
🇷🇺 Комментарии со ссылками/email удаляются автоматически.