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:

Screenshot from 2015-09-05 19:29:20

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

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel