Volume changing program in C

As I continue learning computer science, here is my walkthrough of week 4’s problem:

Complete the implementation of volume.c, such that it changes the volume of a sound file by a given factor.

The program should accept three command-line arguments. The first is input, which represents the name of the original audio file. The second is output, which represents the name of the new audio file that should be generated. The third is factor, which is the amount by which the volume of the original audio file should be scaled. For example, if factor is 2.0, then your program should double the volume of the audio file in input and save the newly generated audio file in output.

Your program should first read the header from the input file and write the header to the output file.

Your program should then read the rest of the data from the WAV file, one 16-bit (2-byte) sample at a time. Your program should multiply each sample by the factor and write the new sample to the output file. You may assume that the WAV file will use 16-bit signed values as samples. In practice, WAV files can have varying numbers of bits per sample, but we’ll assume 16-bit samples for this problem.

Your program, if it uses malloc, must not leak any memory.

Let me explain what this program does. It’s a simple C program that modifies the volume of an audio file in the WAV format. The user needs to provide three command-line arguments when running the program: the input audio file name, the output audio file name, and a scaling factor for adjusting the volume.

First, I check if the user provided the correct number of command-line arguments. If not, I print a message explaining the correct usage and exit the program with an error code:

// Check command-line arguments:
if (argc != 4)
{
    printf("Usage: ./volume input.wav output.wav factor\n");
    return 1;
}

Next, I open the input (in the read mode) and output (in the write mode) audio files specified by the user. If the input file cannot be opened, an error message is displayed, and the program exits. Similarly, if the output file cannot be opened, I print an error message and exit the program. The third command-line argument is converted from a string to a floating-point number, representing the scaling factor:

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

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

float factor = atof(argv[3]);

Here, I copy the 44-byte WAV header from the input file to the output file:

// Copy WAV Header:
uint8_t header[HEADER_SIZE];
fread(header, HEADER_SIZE, 1, input);
fwrite(header, HEADER_SIZE, 1, output);

A me from a week ago wouldn’t know what this is, so let me elaborate a bit more. I use the data type uint8_t to create an array called header that is 44 elements in size. Each element in this array represents one byte of data. The reason I chose uint8_t is because it is an unsigned (meaning it can only represent non-negative values) 8-bit integer data type.

The WAV file format uses bytes to store information in its header. Using an 8-bit data type ensures that each element of the header array corresponds to one byte of data. This is essential for accurately copying the header, as the header size is 44 bytes, so I’ll assign the value of 44 to this global constant HEADER_SIZE.

Next, I declare a variable buffer to hold a single audio sample:

// Create buffer for a single sample:
int16_t buffer;

Notice the int16_t data type here. In digital audio processing, an audio sample represents the amplitude of a sound wave at a specific point in time. The int16_t data type is a 16-bit signed integer, which means it can represent both positive and negative values using 16 bits (or 2 bytes) of storage. And the choice of int16_t corresponds to the standard bit depth used in many audio files, including WAV files.

Now, I need to read audio samples one by one from the input file, multiply each sample by the scaling factor to adjust the volume, and then modify the sample to write it to the output file. For that task, I use a while loop that continues until the fread function returns 0, indicating that there are no more samples to read:

// Modify Volume and Write to Output:
while (fread(&buffer, sizeof(int16_t), 1, input) != 0)
{
    buffer *= factor;
    fwrite(&buffer, sizeof(int16_t), 1, output);
}

Finally, I close both the input and output files to ensure that all changes are saved. The program has now processed the audio file, adjusted its volume, and saved the modified version to a new file.

Here is my final code:

// 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);

    // Create a buffer for a single sample
    int16_t buffer;

    // Read single sample from input into buffer while there are samples left to read
    while (fread(&buffer, sizeof(int16_t), 1, input) != 0)
    {
        // Update volume of sample
        buffer *= factor;

        // Write updated sample to new file
        fwrite(&buffer, sizeof(int16_t), 1, output);
    }

    // Close files
    fclose(input);
    fclose(output);
}
 61   1 mo   C   CS50   Programming
Next
© Daniel Sokolovskiy, 2024
Powered by Aegea