How to Read Wav File in C++
The WAV (or PCM) sound format is the most basic format for storing audio. WAV files tin be of different extended formats , but PCM is the most popular and mutual. The other formats are A-law and Mu-law. The PCM format stores raw audio data without whatsoever compression or conversion, thus leading to the largest file sizes, as compared to other formats like AIFF or MP3 or OGG.
While there are existing libraries in several languages which let you to work with WAV files, this postal service is an attempt to understand how to read the WAV file format without whatever external library. The language used here is C, and has been compiled using GCC nether Linux, only it can be easily run under Windows also with minimal modifications. Nearly likely for VC++ you will accept to replace #include <unistd.h> with #include <io.h>
WAV HEADER STRUCTURE
The header construction is 44 bytes long and has the following structure:
| Positions | Sample Value | Description |
| ane – 4 | "RIFF" | Marks the file equally a riff file. Characters are each one byte long. |
| 5 – eight | File size (integer) | Size of the overall file – viii bytes, in bytes (32-bit integer). Typically, you lot'd make full this in after creation. |
| ix -12 | "Moving ridge" | File Type Header. For our purposes, information technology ever equals "WAVE". |
| thirteen-16 | "fmt " | Format chunk marker. Includes trailing goose egg |
| 17-xx | 16 | Length of format data equally listed above |
| 21-22 | ane | Type of format (1 is PCM) – 2 byte integer |
| 23-24 | ii | Number of Channels – 2 byte integer |
| 25-28 | 44100 | Sample Rate – 32 byte integer. Common values are 44100 (CD), 48000 (DAT). Sample Rate = Number of Samples per 2nd, or Hertz. |
| 29-32 | 176400 | (Sample Rate * BitsPerSample * Channels) / 8. |
| 33-34 | four | (BitsPerSample * Channels) / 8.1 – viii flake mono2 – 8 fleck stereo/xvi bit mono4 – xvi bit stereo |
| 35-36 | 16 | $.25 per sample |
| 37-xl | "data" | "data" chunk header. Marks the showtime of the data section. |
| 41-44 | File size (data) | Size of the information section. |
| Sample values are given above for a 16-chip stereo source. | ||
It is important to note that the WAV format uses footling-endian format to store bytes, then you need to catechumen the bytes to large-endian in code for the values to make sense.
EDIT: AUG 2020
Thanks to a issues pointed out by Kalpathi Subramanian, the code has been updated to rectify the bug. He has adapted this code into a C++ implementation which is available on https://github.com/BridgesUNCC/bridges-cxx/blob/master/src/AudioClip.h
Code
The lawmaking consists of a header file wave.h which is included in moving ridge.c . One time yous compile information technology and run it, information technology accepts the path of a wav file from the command line and dumps the structure information including the size of each sample and the total duration of the wav sound.
wave.h
// Moving ridge file header format struct HEADER { unsigned char riff[four]; // 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 abaft null char unsigned int length_of_fmt; // length of the format data unsigned int format_type; // format blazon. ane-PCM, 3- IEEE float, half-dozen - 8bit A law, seven - 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/viii unsigned int bits_per_sample; // bits per sample, 8- 8bits, 16- 16 bits etc unsigned char data_chunk_header [four]; // DATA string or FLLR string unsigned int data_size; // NumSamples * NumChannels * BitsPerSample/eight - size of the next chunk that will be read }; wave.c
/** * Read and parse a wave file * **/ #include <unistd.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include "wave.h" #define Truthful i #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 principal(int argc, char **argv) { filename = (char*) malloc(sizeof(char) * 1024); if (filename == Zip) { printf("Error in mallocn"); exit(1); } // get file path char cwd[1024]; if (getcwd(cwd, sizeof(cwd)) != Cipher) { strcpy(filename, cwd); // get filename from control line if (argc < 2) { printf("No wave file specifiedn"); render; } strcat(filename, "/"); strcat(filename, argv[ane]); printf("%sn", filename); } // open file printf("Opening file..n"); ptr = fopen(filename, "rb"); if (ptr == Cipher) { printf("Error opening filen"); exit(1); } int read = 0; // read header parts read = fread(header.riff, sizeof(header.riff), 1, ptr); printf("(one-four): %s n", header.riff); read = fread(buffer4, sizeof(buffer4), 1, ptr); printf("%u %u %u %un", 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[ii]<<16) | (buffer4[three]<<24); printf("(5-8) Overall size: bytes:%u, Kb:%u due north", header.overall_size, header.overall_size/1024); read = fread(header.wave, sizeof(header.wave), 1, ptr); printf("(9-12) Wave marking: %sn", header.wave); read = fread(header.fmt_chunk_marker, sizeof(header.fmt_chunk_marker), 1, ptr); printf("(13-sixteen) Fmt mark: %sn", header.fmt_chunk_marker); read = fread(buffer4, sizeof(buffer4), one, ptr); printf("%u %u %u %un", buffer4[0], buffer4[1], buffer4[2], buffer4[iii]); // catechumen petty endian to big endian four byte integer header.length_of_fmt = buffer4[0] | (buffer4[i] << eight) | (buffer4[two] << 16) | (buffer4[3] << 24); printf("(17-20) Length of Fmt header: %u due north", header.length_of_fmt); read = fread(buffer2, sizeof(buffer2), 1, ptr); printf("%u %u northward", buffer2[0], buffer2[1]); header.format_type = buffer2[0] | (buffer2[1] << eight); char format_name[10] = ""; if (header.format_type == 1) strcpy(format_name,"PCM"); else if (header.format_type == six) strcpy(format_name, "A-law"); else if (header.format_type == 7) strcpy(format_name, "Mu-police force"); 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[one]); 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 %un", buffer4[0], buffer4[1], buffer4[2], buffer4[iii]); header.sample_rate = buffer4[0] | (buffer4[1] << 8) | (buffer4[two] << 16) | (buffer4[3] << 24); printf("(25-28) Sample rate: %un", header.sample_rate); read = fread(buffer4, sizeof(buffer4), i, ptr); printf("%u %u %u %un", buffer4[0], buffer4[1], buffer4[2], buffer4[iii]); header.byterate = buffer4[0] | (buffer4[1] << 8) | (buffer4[2] << 16) | (buffer4[3] << 24); printf("(29-32) Byte Charge per unit: %u , Bit Charge per unit:%un", header.byterate, header.byterate*viii); 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) Cake Alignment: %u n", header.block_align); read = fread(buffer2, sizeof(buffer2), 1, ptr); printf("%u %u n", buffer2[0], buffer2[i]); header.bits_per_sample = buffer2[0] | (buffer2[ane] << 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 %united nations", buffer4[0], buffer4[ane], buffer4[two], buffer4[3]); header.data_size = buffer4[0] | (buffer4[i] << 8) | (buffer4[two] << 16) | (buffer4[3] << 24 ); printf("(41-44) Size of data clamper: %u due north", header.data_size); // summate 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) / eight; printf("Size of each sample:%ld bytesn", size_of_each_sample); // calculate duration of file float duration_in_seconds = (bladder) header.overall_size / header.byterate; printf("Approx.Duration in seconds=%fn", duration_in_seconds); printf("Approx.Duration in h:thousand:s=%sn", seconds_to_time(duration_in_seconds)); // read each sample from data chunk if PCM if (header.format_type == ane) { // PCM printf("Dump sample data? Y/Northward?"); char c = 'northward'; 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("Fault: %ld x %ud <> %ldn", bytes_in_each_channel, header.channels, size_of_each_sample); size_is_correct = False; } if (size_is_correct) { // the valid aamplitude range for values based on the $.25 per sample long low_limit = 0l; long high_limit = 0l; switch (header.bits_per_sample) { case eight: low_limit = -128; high_limit = 127; pause; case 16: low_limit = -32768; high_limit = 32767; break; example 32: low_limit = -2147483648; high_limit = 2147483647; pause; } printf("nn.Valid range for information 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), one, ptr); if (read == one) { // dump the data read unsigned int xchannels = 0; int data_in_channel = 0; int start = 0; // motion the outset for every iteration in the loop below for (xchannels = 0; xchannels < header.channels; xchannels ++ ) { printf("Channel#%d : ", (xchannels+1)); // convert information from little endian to big endian based on bytes in each channel sample if (bytes_in_each_channel == 4) { data_in_channel = (data_buffer[commencement] & 0x00ff) | ((data_buffer[offset + 1] & 0x00ff) <<8) | ((data_buffer[offset + ii] & 0x00ff) <<16) | (data_buffer[get-go + 3]<<24); } else if (bytes_in_each_channel == two) { data_in_channel = (data_buffer[offset] & 0x00ff) | (data_buffer[offset + one] << 8); } else if (bytes_in_each_channel == one) { data_in_channel = data_buffer[offset] & 0x00ff; data_in_channel -= 128; //in wave, 8-bit are unsigned, so shifting to signed } commencement += bytes_in_each_channel; 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 rangen"); printf(" | "); } printf("n"); } else { printf("Error reading file. %d bytesn", 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 gratis(filename); return 0; } /** * Catechumen 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 % sixty; milliseconds = 0; // become the decimal part of raw_seconds to get milliseconds char *pos; pos = strchr(hms, '.'); int ipos = (int) (pos - hms); char decimalpart[xv]; memset(decimalpart, ' ', sizeof(decimalpart)); strncpy(decimalpart, &hms[ipos+i], three); milliseconds = atoi(decimalpart); sprintf(hms, "%d:%d:%d.%d", hours, minutes, seconds, milliseconds); return hms; } A sample run is given beneath:

vickersduchou1963.blogspot.com
Source: http://truelogic.org/wordpress/2015/09/04/parsing-a-wav-file-in-c/
0 Response to "How to Read Wav File in C++"
Post a Comment