I am trying to read an audio wave file from a database of wave files. My code for reading the wave file looks like so
/**
* Read and parse a wave file
*
**/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "wave.h"
#define TRUE 1
#define FALSE 0
// WAVE header structure
unsigned char buffer4[4];
unsigned char buffer2[2];
char* seconds_to_time(float seconds);
FILE *ptr;
char *filename;
struct HEADER header;
int main(int argc, char **argv) {
filename = (char*) malloc(sizeof(char) * 1024);
if (filename == NULL) {
printf("Error in malloc\n");
exit(1);
}
// get file path
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
strcpy(filename, cwd);
// get filename from command line
if (argc < 2) {
printf("No wave file specified\n");
return;
}
strcat(filename, "/");
strcat(filename, argv[1]);
printf("%s\n", filename);
}
// open file
printf("Opening file..\n");
ptr = fopen(filename, "rb");
if (ptr == NULL) {
printf("Error opening file\n");
exit(1);
}
int read = 0;
// read header parts
read = fread(header.riff, sizeof(header.riff), 1, ptr);
printf("(1-4): %s \n", header.riff);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
// convert little endian to big endian 4 byte int
header.overall_size = buffer4[0] |
(buffer4[1]<<8) |
(buffer4[2]<<16) |
(buffer4[3]<<24);
printf("(5-8) Overall size: bytes:%u, Kb:%u \n", header.overall_size, header.overall_size/1024);
read = fread(header.wave, sizeof(header.wave), 1, ptr);
printf("(9-12) Wave marker: %s\n", header.wave);
read = fread(header.fmt_chunk_marker, sizeof(header.fmt_chunk_marker), 1, ptr);
printf("(13-16) Fmt marker: %s\n", header.fmt_chunk_marker);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
// convert little endian to big endian 4 byte integer
header.length_of_fmt = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24);
printf("(17-20) Length of Fmt header: %u \n", header.length_of_fmt);
read = fread(buffer2, sizeof(buffer2), 1, ptr); printf("%u %u \n", buffer2[0], buffer2[1]);
header.format_type = buffer2[0] | (buffer2[1] << 8);
char format_name[10] = "";
if (header.format_type == 1)
strcpy(format_name,"PCM");
else if (header.format_type == 6)
strcpy(format_name, "A-law");
else if (header.format_type == 7)
strcpy(format_name, "Mu-law");
printf("(21-22) Format type: %u %s \n", header.format_type, format_name);
read = fread(buffer2, sizeof(buffer2), 1, ptr);
printf("%u %u \n", buffer2[0], buffer2[1]);
header.channels = buffer2[0] | (buffer2[1] << 8);
printf("(23-24) Channels: %u \n", header.channels);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
header.sample_rate = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24);
printf("(25-28) Sample rate: %u\n", header.sample_rate);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
header.byterate = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24);
printf("(29-32) Byte Rate: %u , Bit Rate:%u\n", header.byterate, header.byterate*8);
read = fread(buffer2, sizeof(buffer2), 1, ptr);
printf("%u %u \n", buffer2[0], buffer2[1]);
header.block_align = buffer2[0] |
(buffer2[1] << 8);
printf("(33-34) Block Alignment: %u \n", header.block_align);
read = fread(buffer2, sizeof(buffer2), 1, ptr);
printf("%u %u \n", buffer2[0], buffer2[1]);
header.bits_per_sample = buffer2[0] |
(buffer2[1] << 8);
printf("(35-36) Bits per sample: %u \n", header.bits_per_sample);
read = fread(header.data_chunk_header, sizeof(header.data_chunk_header), 1, ptr);
printf("(37-40) Data Marker: %s \n", header.data_chunk_header);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
header.data_size = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24 );
printf("(41-44) Size of data chunk: %u \n", header.data_size);
// calculate no.of samples
long num_samples = (8 * header.data_size) / (header.channels * header.bits_per_sample);
printf("Number of samples:%lu \n", num_samples);
long size_of_each_sample = (header.channels * header.bits_per_sample) / 8;
printf("Size of each sample:%ld bytes\n", size_of_each_sample);
// calculate duration of file
float duration_in_seconds = (float) header.overall_size / header.byterate;
printf("Approx.Duration in seconds=%f\n", duration_in_seconds);
printf("Approx.Duration in h:m:s=%s\n", seconds_to_time(duration_in_seconds));
// read each sample from data chunk if PCM
if (header.format_type == 1) { // PCM
printf("Dump sample data? Y/N?");
char c = 'n';
scanf("%c", &c);
if (c == 'Y' || c == 'y') {
long i =0;
char data_buffer[size_of_each_sample];
int size_is_correct = TRUE;
// make sure that the bytes-per-sample is completely divisible by num.of channels
long bytes_in_each_channel = (size_of_each_sample / header.channels);
if ((bytes_in_each_channel * header.channels) != size_of_each_sample) {
printf("Error: %ld x %ud <> %ld\n", bytes_in_each_channel, header.channels, size_of_each_sample);
size_is_correct = FALSE;
}
if (size_is_correct) {
// the valid amplitude range for values based on the bits per sample
long low_limit = 0l;
long high_limit = 0l;
switch (header.bits_per_sample) {
case 8:
low_limit = -128;
high_limit = 127;
break;
case 16:
low_limit = -32768;
high_limit = 32767;
break;
case 32:
low_limit = -2147483648;
high_limit = 2147483647;
break;
}
printf("\n\n.Valid range for data values : %ld to %ld \n", low_limit, high_limit);
for (i =1; i <= num_samples; i++) {
printf("==========Sample %ld / %ld=============\n", i, num_samples);
read = fread(data_buffer, sizeof(data_buffer), 1, ptr);
if (read == 1) {
// dump the data read
unsigned int xchannels = 0;
int data_in_channel = 0;
for (xchannels = 0; xchannels < header.channels; xchannels ++ ) {
printf("Channel#%d : ", (xchannels+1));
// convert data from little endian to big endian based on bytes in each channel sample
if (bytes_in_each_channel == 4) {
data_in_channel = data_buffer[0] |
(data_buffer[1]<<8) |
(data_buffer[2]<<16) |
(data_buffer[3]<<24);
}
else if (bytes_in_each_channel == 2) {
data_in_channel = data_buffer[0] |
(data_buffer[1] << 8);
}
else if (bytes_in_each_channel == 1) {
data_in_channel = data_buffer[0];
}
printf("%d ", data_in_channel);
// check if value was in range
if (data_in_channel < low_limit || data_in_channel > high_limit)
printf("**value out of range\n");
printf(" | ");
}
printf("\n");
}
else {
printf("Error reading file. %d bytes\n", read);
break;
}
} // for (i =1; i <= num_samples; i++) {
} // if (size_is_correct) {
} // if (c == 'Y' || c == 'y') {
} // if (header.format_type == 1) {
printf("Closing file..\n");
fclose(ptr);
// cleanup before quitting
free(filename);
return 0;
}
/**
* Convert seconds into hh:mm:ss format
* Params:
* seconds - seconds value
* Returns: hms - formatted string
**/
char* seconds_to_time(float raw_seconds) {
char *hms;
int hours, hours_residue, minutes, seconds, milliseconds;
hms = (char*) malloc(100);
sprintf(hms, "%f", raw_seconds);
hours = (int) raw_seconds/3600;
hours_residue = (int) raw_seconds % 3600;
minutes = hours_residue/60;
seconds = hours_residue % 60;
milliseconds = 0;
// get the decimal part of raw_seconds to get milliseconds
char *pos;
pos = strchr(hms, '.');
int ipos = (int) (pos - hms);
char decimalpart[15];
memset(decimalpart, ' ', sizeof(decimalpart));
strncpy(decimalpart, &hms[ipos+1], 3);
milliseconds = atoi(decimalpart);
sprintf(hms, "%d:%d:%d.%d", hours, minutes, seconds, milliseconds);
return hms;
}
the wave.h that is included looks like this
// WAVE file header format
struct HEADER {
unsigned char riff[4]; // RIFF string
unsigned int overall_size ; // overall size of file in bytes
unsigned char wave[4]; // WAVE string
unsigned char fmt_chunk_marker[4]; // fmt string with trailing null char
unsigned int length_of_fmt; // length of the format data
unsigned int format_type; // format type. 1-PCM, 3- IEEE float, 6 - 8bit A law, 7 - 8bit mu law
unsigned int channels; // no.of channels
unsigned int sample_rate; // sampling rate (blocks per second)
unsigned int byterate; // SampleRate * NumChannels * BitsPerSample/8
unsigned int block_align; // NumChannels * BitsPerSample/8
unsigned int bits_per_sample; // bits per sample, 8- 8bits, 16- 16 bits etc
unsigned char data_chunk_header [4]; // DATA string or FLLR string
unsigned int data_size; // NumSamples * NumChannels * BitsPerSample/8 - size of the next chunk that will be read
};
. I have tried with other wav files and seem to get the correct output (i.e. "RIFF" and "WAVE" from the header). However, with the one I care about this is the output
________________________________________________________________________________~/Downloads/libmfcc-master $: ./a.out audioclip-1523814201.wav
/home/sfelde2/Downloads/libmfcc-master/audioclip-1523814201.wav
Opening file..
(1-4):
102 116 121 112
(5-8) Overall size: bytes:1887007846, Kb:1842781
(9-12) Wave marker: isom
(13-16) Fmt marker:
105 115 111 109
(17-20) Length of Fmt header: 1836020585
105 115
(21-22) Format type: 29545
111 50
(23-24) Channels: 12911
109 112 52 49
(25-28) Sample rate: 825520237
0 0 0 8
(29-32) Byte Rate: 134217728 , Bit Rate:1073741824
102 114
(33-34) Block Alignment: 29286
101 101
(35-36) Bits per sample: 25957
(37-40) Data Marker:
109 100 97 116
(41-44) Size of data chunk: 1952539757
Number of samples:8
Size of each sample:41891353 bytes
Approx.Duration in seconds=14.059304
Approx.Duration in h:m:s=0:0:14.59
Closing file..
I have started to wonder if the wave field where it says "isom" might signify it is aligned differently but I haven't been able to find anything on ISOM. Thiiis along with the fact that it is not printing the RIFF string and spitting out the wrong values for the data makes me wonder if there is anyway I can figure out where the data starts. Any ideas on what could be the issue or if theres anyway I can debug this so that I can use the wav file would be greatly appreciated.
int
fields are at offsets that are a multiple of 4). The wav header predates the existence of packed structs, so it handled it with careful design. - Craig Estey