Given below is my solution to CS50's Week 4: Volume. The problem I was trying to solve was to read a .wav file and change its volume based on a comandline argument 'factor'.
Problem:
When I was testing this code I initially used
fread(header, HEADER_SIZE, 1, input);
My code would compile without error and an output file would be produced for the following:
./volume input.wav output.wav 1.0
But a currupted output file would be produced if I changed the volume factor to anything else other than 1.0.
// 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;
void copy_header(FILE *input, FILE *output);
void copy_samples(FILE *input, FILE *output, float factor);
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(input, output);
copy_samples(input, output, factor);
// Close files
fclose(input);
fclose(output);
}
void copy_header(FILE *input, FILE *output)
{
uint8_t header[HEADER_SIZE];
fread(header, sizeof(HEADER_SIZE), 1, input);
fwrite(header, sizeof(HEADER_SIZE), 1, output);
printf("header: %s; header_size: %lu; HEADER_s: %lu\n", header, sizeof(header), sizeof(HEADER_SIZE));
}
void copy_samples(FILE *input, FILE *output, float factor)
{
int16_t buffer;
while (fread(&buffer, sizeof(int16_t), 1, input) != 0)
{
buffer = buffer * factor;
fwrite(&buffer, sizeof(int16_t), 1, output);
}
}
After a lot of digging, I found that the output for:
printf("header: %s; header_size: %lu; HEADER_s: %lu\n", header, sizeof(header), sizeof(HEADER_SIZE));
Would be:
header: RIFFDb; header_size: 44; HEADER_s: 4
Why did the value of sizeof(HEADER_SIZE) change to 4? Am I completely missing something here? Did I approach this problem right?
I fixed the error in my code by using:
fread(header, sizeof(header), 1, input);
But i want to know why and how I borked this code. Thanks in advance!
When looking at these lines:
uint8_t header[HEADER_SIZE];
fread(header, sizeof(HEADER_SIZE), 1, input);
fwrite(header, sizeof(HEADER_SIZE), 1, output);
You seem to be under the impression that, after the declaration of header
, that the size of HEADER_SIZE
is now linked to the size of header
. That is not the case.
The sizeof
operator evaluates to the size in bytes of its operand. In the case of sizeof(HEADER_SIZE)
the operand is the variable HEADER_SIZE
(or more accurately, the parenthesized variable) whose type is int
. This evaluates to 4 because an int
takes up 4 bytes on your system.
This caused problem in your code by only reading in 4 bytes instead of 44 as you intended.
This works:
fread(header, sizeof(header), 1, input);
Because sizeof(header)
gives you the size in bytes of the header
array which is 44.
This would also work:
fread(header, HEADER_SIZE, 1, input);
As it would be passing in 44 as the number of bytes to be read.