{"id":2230,"date":"2015-09-04T09:30:22","date_gmt":"2015-09-04T09:30:22","guid":{"rendered":"http:\/\/truelogic.org\/wordpress\/?p=2230"},"modified":"2020-07-25T10:57:11","modified_gmt":"2020-07-25T10:57:11","slug":"parsing-a-wav-file-in-c","status":"publish","type":"post","link":"https:\/\/truelogic.org\/wordpress\/2015\/09\/04\/parsing-a-wav-file-in-c\/","title":{"rendered":"Parsing a WAV file in C"},"content":{"rendered":"            <script type=\"text\/javascript\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/plugins\/wordpress-code-snippet\/scripts\/shBrushCpp.js\"><\/script>\n<p>The WAV (or PCM) audio format is the most basic format for storing audio. WAV files can be of different extended formats , but PCM is the most popular and common. The other formats are A-law and Mu-law. The PCM format stores raw audio data without any compression or conversion, thus leading to the largest file sizes, as compared to other formats like AIFF or MP3 or OGG.<\/p>\n<p>While there are existing libraries in several languages which allow you to work with WAV files, this post is an attempt to understand how to read the WAV file format without any external library. The language used here is C, and has been compiled using GCC under Linux, but it can be easily run under Windows also with minimal modifications. Most likely for VC++ you will have to replace #include &lt;unistd.h&gt; with #include &lt;io.h&gt;<\/p>\n<h4>WAV HEADER STRUCTURE<\/h4>\n<p>The header structure is 44 bytes long and has the following structure:<\/p>\n<p>\u00a0<\/p>\n<table border=\"1\" summary=\"WAV File Header\">\n<tbody>\n<tr>\n<td>Positions<\/td>\n<td>Sample Value<\/td>\n<td>Description<\/td>\n<\/tr>\n<tr>\n<td>1 &#8211; 4<\/td>\n<td>&#8220;RIFF&#8221;<\/td>\n<td>Marks the file as a riff file. Characters are each 1 byte long.<\/td>\n<\/tr>\n<tr>\n<td>5 &#8211; 8<\/td>\n<td>File size (integer)<\/td>\n<td>Size of the overall file &#8211; 8 bytes, in bytes (32-bit integer). Typically, you&#8217;d fill this in after creation.<\/td>\n<\/tr>\n<tr>\n<td>9 -12<\/td>\n<td>&#8220;WAVE&#8221;<\/td>\n<td>File Type Header. For our purposes, it always equals &#8220;WAVE&#8221;.<\/td>\n<\/tr>\n<tr>\n<td>13-16<\/td>\n<td>&#8220;fmt &#8220;<\/td>\n<td>Format chunk marker. Includes trailing null<\/td>\n<\/tr>\n<tr>\n<td>17-20<\/td>\n<td>16<\/td>\n<td>Length of format data as listed above<\/td>\n<\/tr>\n<tr>\n<td>21-22<\/td>\n<td>1<\/td>\n<td>Type of format (1 is PCM) &#8211; 2 byte integer<\/td>\n<\/tr>\n<tr>\n<td>23-24<\/td>\n<td>2<\/td>\n<td>Number of Channels &#8211; 2 byte integer<\/td>\n<\/tr>\n<tr>\n<td>25-28<\/td>\n<td>44100<\/td>\n<td>Sample Rate &#8211; 32 byte integer. Common values are 44100 (CD), 48000 (DAT). Sample Rate = Number of Samples per second, or Hertz.<\/td>\n<\/tr>\n<tr>\n<td>29-32<\/td>\n<td>176400<\/td>\n<td>(Sample Rate * BitsPerSample * Channels) \/ 8.<\/td>\n<\/tr>\n<tr>\n<td>33-34<\/td>\n<td>4<\/td>\n<td>(BitsPerSample * Channels) \/ 8.1 &#8211; 8 bit mono2 &#8211; 8 bit stereo\/16 bit mono4 &#8211; 16 bit stereo<\/td>\n<\/tr>\n<tr>\n<td>35-36<\/td>\n<td>16<\/td>\n<td>Bits per sample<\/td>\n<\/tr>\n<tr>\n<td>37-40<\/td>\n<td>&#8220;data&#8221;<\/td>\n<td>&#8220;data&#8221; chunk header. Marks the beginning of the data section.<\/td>\n<\/tr>\n<tr>\n<td>41-44<\/td>\n<td>File size (data)<\/td>\n<td>Size of the data section.<\/td>\n<\/tr>\n<tr>\n<td colspan=\"3\">Sample values are given above for a 16-bit stereo source.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>It is important to note that the WAV\u00a0 format uses little-endian format to store bytes, so you need to convert the bytes to big-endian in code for the values to make sense.<\/p>\n<h4>EDIT: AUG 2020<\/h4>\n<p>Thanks to a bug 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<a href=\"https:\/\/github.com\/BridgesUNCC\/bridges-cxx\/blob\/master\/src\/AudioClip.h\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" https:\/\/github.com\/BridgesUNCC\/bridges-cxx\/blob\/master\/src\/AudioClip.h (opens in a new tab)\"> https:\/\/github.com\/BridgesUNCC\/bridges-cxx\/blob\/master\/src\/AudioClip.h<\/a><\/p>\n<h4>CODE<\/h4>\n<p>The code consists of a header file wave.h which is included in wave.c . Once you compile it and run it, it 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 audio.<\/p>\n<p><strong>wave.h<\/strong><br \/><pre class=\"brush: cpp\">\/\/ WAVE file header format\r\nstruct HEADER {\r\n\tunsigned char riff[4];\t\t\t\t\t\t\/\/ RIFF string\r\n\tunsigned int overall_size\t;\t\t\t\t\/\/ overall size of file in bytes\r\n\tunsigned char wave[4];\t\t\t\t\t\t\/\/ WAVE string\r\n\tunsigned char fmt_chunk_marker[4];\t\t\t\/\/ fmt string with trailing null char\r\n\tunsigned int length_of_fmt;\t\t\t\t\t\/\/ length of the format data\r\n\tunsigned int format_type;\t\t\t\t\t\/\/ format type. 1-PCM, 3- IEEE float, 6 - 8bit A law, 7 - 8bit mu law\r\n\tunsigned int channels;\t\t\t\t\t\t\/\/ no.of channels\r\n\tunsigned int sample_rate;\t\t\t\t\t\/\/ sampling rate (blocks per second)\r\n\tunsigned int byterate;\t\t\t\t\t\t\/\/ SampleRate * NumChannels * BitsPerSample\/8\r\n\tunsigned int block_align;\t\t\t\t\t\/\/ NumChannels * BitsPerSample\/8\r\n\tunsigned int bits_per_sample;\t\t\t\t\/\/ bits per sample, 8- 8bits, 16- 16 bits etc\r\n\tunsigned char data_chunk_header [4];\t\t\/\/ DATA string or FLLR string\r\n\tunsigned int data_size;\t\t\t\t\t\t\/\/ NumSamples * NumChannels * BitsPerSample\/8 - size of the next chunk that will be read\r\n};\r\n<\/pre><\/p>\n<p><strong>wave.c<\/strong><\/p>\n<p><pre class=\"brush: cpp\">\/**\r\n * Read and parse a wave file\r\n *\r\n **\/\r\n#include &lt;unistd.h&gt;\r\n#include &lt;stdio.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &quot;wave.h&quot;\r\n#define TRUE 1 \r\n#define FALSE 0\r\n\r\n\/\/ WAVE header structure\r\n\r\nunsigned char buffer4[4];\r\nunsigned char buffer2[2];\r\n\r\nchar* seconds_to_time(float seconds);\r\n\r\n\r\n FILE *ptr;\r\n char *filename;\r\n struct HEADER header;\r\n\r\nint main(int argc, char **argv) {\r\n\r\n filename = (char*) malloc(sizeof(char) * 1024);\r\n if (filename == NULL) {\r\n   printf(&quot;Error in mallocn&quot;);\r\n   exit(1);\r\n }\r\n\r\n \/\/ get file path\r\n char cwd[1024];\r\n if (getcwd(cwd, sizeof(cwd)) != NULL) {\r\n   \r\n\tstrcpy(filename, cwd);\r\n\r\n\t\/\/ get filename from command line\r\n\tif (argc &lt; 2) {\r\n\t  printf(&quot;No wave file specifiedn&quot;);\r\n\t  return;\r\n\t}\r\n\t\r\n\tstrcat(filename, &quot;\/&quot;);\r\n\tstrcat(filename, argv[1]);\r\n\tprintf(&quot;%sn&quot;, filename);\r\n }\r\n\r\n \/\/ open file\r\n printf(&quot;Opening  file..n&quot;);\r\n ptr = fopen(filename, &quot;rb&quot;);\r\n if (ptr == NULL) {\r\n\tprintf(&quot;Error opening filen&quot;);\r\n\texit(1);\r\n }\r\n \r\n int read = 0;\r\n \r\n \/\/ read header parts\r\n\r\n read = fread(header.riff, sizeof(header.riff), 1, ptr);\r\n printf(&quot;(1-4): %s n&quot;, header.riff); \r\n\r\n read = fread(buffer4, sizeof(buffer4), 1, ptr);\r\n printf(&quot;%u %u %u %un&quot;, buffer4[0], buffer4[1], buffer4[2], buffer4[3]);\r\n \r\n \/\/ convert little endian to big endian 4 byte int\r\n header.overall_size  = buffer4[0] | \r\n\t\t\t\t\t\t(buffer4[1]&lt;&lt;8) | \r\n\t\t\t\t\t\t(buffer4[2]&lt;&lt;16) | \r\n\t\t\t\t\t\t(buffer4[3]&lt;&lt;24);\r\n\r\n printf(&quot;(5-8) Overall size: bytes:%u, Kb:%u n&quot;, header.overall_size, header.overall_size\/1024);\r\n\r\n read = fread(header.wave, sizeof(header.wave), 1, ptr);\r\n printf(&quot;(9-12) Wave marker: %sn&quot;, header.wave);\r\n\r\n read = fread(header.fmt_chunk_marker, sizeof(header.fmt_chunk_marker), 1, ptr);\r\n printf(&quot;(13-16) Fmt marker: %sn&quot;, header.fmt_chunk_marker);\r\n\r\n read = fread(buffer4, sizeof(buffer4), 1, ptr);\r\n printf(&quot;%u %u %u %un&quot;, buffer4[0], buffer4[1], buffer4[2], buffer4[3]);\r\n\r\n \/\/ convert little endian to big endian 4 byte integer\r\n header.length_of_fmt = buffer4[0] |\r\n\t\t\t\t\t\t\t(buffer4[1] &lt;&lt; 8) |\r\n\t\t\t\t\t\t\t(buffer4[2] &lt;&lt; 16) |\r\n\t\t\t\t\t\t\t(buffer4[3] &lt;&lt; 24);\r\n printf(&quot;(17-20) Length of Fmt header: %u n&quot;, header.length_of_fmt);\r\n\r\n read = fread(buffer2, sizeof(buffer2), 1, ptr); printf(&quot;%u %u n&quot;, buffer2[0], buffer2[1]);\r\n \r\n header.format_type = buffer2[0] | (buffer2[1] &lt;&lt; 8);\r\n char format_name[10] = &quot;&quot;;\r\n if (header.format_type == 1)\r\n   strcpy(format_name,&quot;PCM&quot;); \r\n else if (header.format_type == 6)\r\n  strcpy(format_name, &quot;A-law&quot;);\r\n else if (header.format_type == 7)\r\n  strcpy(format_name, &quot;Mu-law&quot;);\r\n\r\n printf(&quot;(21-22) Format type: %u %s n&quot;, header.format_type, format_name);\r\n\r\n read = fread(buffer2, sizeof(buffer2), 1, ptr);\r\n printf(&quot;%u %u n&quot;, buffer2[0], buffer2[1]);\r\n\r\n header.channels = buffer2[0] | (buffer2[1] &lt;&lt; 8);\r\n printf(&quot;(23-24) Channels: %u n&quot;, header.channels);\r\n\r\n read = fread(buffer4, sizeof(buffer4), 1, ptr);\r\n printf(&quot;%u %u %u %un&quot;, buffer4[0], buffer4[1], buffer4[2], buffer4[3]);\r\n\r\n header.sample_rate = buffer4[0] |\r\n\t\t\t\t\t\t(buffer4[1] &lt;&lt; 8) |\r\n\t\t\t\t\t\t(buffer4[2] &lt;&lt; 16) |\r\n\t\t\t\t\t\t(buffer4[3] &lt;&lt; 24);\r\n\r\n printf(&quot;(25-28) Sample rate: %un&quot;, header.sample_rate);\r\n\r\n read = fread(buffer4, sizeof(buffer4), 1, ptr);\r\n printf(&quot;%u %u %u %un&quot;, buffer4[0], buffer4[1], buffer4[2], buffer4[3]);\r\n\r\n header.byterate  = buffer4[0] |\r\n\t\t\t\t\t\t(buffer4[1] &lt;&lt; 8) |\r\n\t\t\t\t\t\t(buffer4[2] &lt;&lt; 16) |\r\n\t\t\t\t\t\t(buffer4[3] &lt;&lt; 24);\r\n printf(&quot;(29-32) Byte Rate: %u , Bit Rate:%un&quot;, header.byterate, header.byterate*8);\r\n\r\n read = fread(buffer2, sizeof(buffer2), 1, ptr);\r\n printf(&quot;%u %u n&quot;, buffer2[0], buffer2[1]);\r\n\r\n header.block_align = buffer2[0] |\r\n\t\t\t\t\t(buffer2[1] &lt;&lt; 8);\r\n printf(&quot;(33-34) Block Alignment: %u n&quot;, header.block_align);\r\n\r\n read = fread(buffer2, sizeof(buffer2), 1, ptr);\r\n printf(&quot;%u %u n&quot;, buffer2[0], buffer2[1]);\r\n\r\n header.bits_per_sample = buffer2[0] |\r\n\t\t\t\t\t(buffer2[1] &lt;&lt; 8);\r\n printf(&quot;(35-36) Bits per sample: %u n&quot;, header.bits_per_sample);\r\n\r\n read = fread(header.data_chunk_header, sizeof(header.data_chunk_header), 1, ptr);\r\n printf(&quot;(37-40) Data Marker: %s n&quot;, header.data_chunk_header);\r\n\r\n read = fread(buffer4, sizeof(buffer4), 1, ptr);\r\n printf(&quot;%u %u %u %un&quot;, buffer4[0], buffer4[1], buffer4[2], buffer4[3]);\r\n\r\n header.data_size = buffer4[0] |\r\n\t\t\t\t(buffer4[1] &lt;&lt; 8) |\r\n\t\t\t\t(buffer4[2] &lt;&lt; 16) | \r\n\t\t\t\t(buffer4[3] &lt;&lt; 24 );\r\n printf(&quot;(41-44) Size of data chunk: %u n&quot;, header.data_size);\r\n\r\n\r\n \/\/ calculate no.of samples\r\n long num_samples = (8 * header.data_size) \/ (header.channels * header.bits_per_sample);\r\n printf(&quot;Number of samples:%lu n&quot;, num_samples);\r\n\r\n long size_of_each_sample = (header.channels * header.bits_per_sample) \/ 8;\r\n printf(&quot;Size of each sample:%ld bytesn&quot;, size_of_each_sample);\r\n\r\n \/\/ calculate duration of file\r\n float duration_in_seconds = (float) header.overall_size \/ header.byterate;\r\n printf(&quot;Approx.Duration in seconds=%fn&quot;, duration_in_seconds);\r\n printf(&quot;Approx.Duration in h:m:s=%sn&quot;, seconds_to_time(duration_in_seconds));\r\n\r\n\r\n\r\n \/\/ read each sample from data chunk if PCM\r\n if (header.format_type == 1) { \/\/ PCM\r\n    printf(&quot;Dump sample data? Y\/N?&quot;);\r\n\tchar c = &#039;n&#039;;\r\n\tscanf(&quot;%c&quot;, &amp;c);\r\n\tif (c == &#039;Y&#039; || c == &#039;y&#039;) { \r\n\t\tlong i =0;\r\n\t\tchar data_buffer[size_of_each_sample];\r\n\t\tint  size_is_correct = TRUE;\r\n\r\n\t\t\/\/ make sure that the bytes-per-sample is completely divisible by num.of channels\r\n\t\tlong bytes_in_each_channel = (size_of_each_sample \/ header.channels);\r\n\t\tif ((bytes_in_each_channel  * header.channels) != size_of_each_sample) {\r\n\t\t\tprintf(&quot;Error: %ld x %ud &lt;&gt; %ldn&quot;, bytes_in_each_channel, header.channels, size_of_each_sample);\r\n\t\t\tsize_is_correct = FALSE;\r\n\t\t}\r\n \r\n\t\tif (size_is_correct) { \r\n\t\t\t\t\t\/\/ the valid amplitude range for values based on the bits per sample\r\n\t\t\tlong low_limit = 0l;\r\n\t\t\tlong high_limit = 0l;\r\n\r\n\t\t\tswitch (header.bits_per_sample) {\r\n\t\t\t\tcase 8:\r\n\t\t\t\t\tlow_limit = -128;\r\n\t\t\t\t\thigh_limit = 127;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 16:\r\n\t\t\t\t\tlow_limit = -32768;\r\n\t\t\t\t\thigh_limit = 32767;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 32:\r\n\t\t\t\t\tlow_limit = -2147483648;\r\n\t\t\t\t\thigh_limit = 2147483647;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\t\t\t\t\t\r\n\r\n\t\t\tprintf(&quot;nn.Valid range for data values : %ld to %ld n&quot;, low_limit, high_limit);\r\n\t\t\tfor (i =1; i &lt;= num_samples; i++) {\r\n\t\t\t\tprintf(&quot;==========Sample %ld \/ %ld=============n&quot;, i, num_samples);\r\n\t\t\t\tread = fread(data_buffer, sizeof(data_buffer), 1, ptr);\r\n\t\t\t\tif (read == 1) {\r\n\t\t\t\t\r\n\t\t\t\t\t\/\/ dump the data read\r\n\t\t\t\t\tunsigned int  xchannels = 0;\r\n\t\t\t\t\tint data_in_channel = 0;\r\n\t\t\t\t\tint offset = 0; \/\/ move the offset for every iteration in the loop below\r\n\t\t\t\t\tfor (xchannels = 0; xchannels &lt; header.channels; xchannels ++ ) {\r\n\t\t\t\t\t\tprintf(&quot;Channel#%d : &quot;, (xchannels+1));\r\n\t\t\t\t\t\t\/\/ convert data from little endian to big endian based on bytes in each channel sample\r\n\t\t\t\t\t\tif (bytes_in_each_channel == 4) {\r\n\t\t\t\t\t\t\tdata_in_channel = (data_buffer[offset] &amp; 0x00ff) | \r\n\t\t\t\t\t\t\t\t\t\t\t\t((data_buffer[offset + 1] &amp; 0x00ff) &lt;&lt;8) | \r\n\t\t\t\t\t\t\t\t\t\t\t\t((data_buffer[offset + 2] &amp; 0x00ff) &lt;&lt;16) | \r\n\t\t\t\t\t\t\t\t\t\t\t\t(data_buffer[offset + 3]&lt;&lt;24);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if (bytes_in_each_channel == 2) {\r\n\t\t\t\t\t\t\tdata_in_channel = (data_buffer[offset] &amp; 0x00ff) |\r\n\t\t\t\t\t\t\t\t\t\t\t\t(data_buffer[offset + 1] &lt;&lt; 8);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if (bytes_in_each_channel == 1) {\r\n\t\t\t\t\t\t\tdata_in_channel = data_buffer[offset] &amp; 0x00ff;\r\n\t\t\t\t\t\t\tdata_in_channel -= 128; \/\/in wave, 8-bit are unsigned, so shifting to signed\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\toffset += bytes_in_each_channel;\t\t\r\n\t\t\t\t\t\tprintf(&quot;%d &quot;, data_in_channel);\r\n\r\n\t\t\t\t\t\t\/\/ check if value was in range\r\n\t\t\t\t\t\tif (data_in_channel &lt; low_limit || data_in_channel &gt; high_limit)\r\n\t\t\t\t\t\t\tprintf(&quot;**value out of rangen&quot;);\r\n\r\n\t\t\t\t\t\tprintf(&quot; | &quot;);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tprintf(&quot;n&quot;);\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tprintf(&quot;Error reading file. %d bytesn&quot;, read);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t} \/\/ \tfor (i =1; i &lt;= num_samples; i++) {\r\n\r\n\t\t} \/\/ \tif (size_is_correct) { \r\n\r\n\t } \/\/ if (c == &#039;Y&#039; || c == &#039;y&#039;) { \r\n } \/\/  if (header.format_type == 1) { \r\n\r\n printf(&quot;Closing file..n&quot;);\r\n fclose(ptr);\r\n\r\n  \/\/ cleanup before quitting\r\n free(filename);\r\n return 0;\r\n\r\n}\r\n\r\n\/**\r\n * Convert seconds into hh:mm:ss format\r\n * Params:\r\n *\tseconds - seconds value\r\n * Returns: hms - formatted string\r\n **\/\r\n char* seconds_to_time(float raw_seconds) {\r\n  char *hms;\r\n  int hours, hours_residue, minutes, seconds, milliseconds;\r\n  hms = (char*) malloc(100);\r\n\r\n  sprintf(hms, &quot;%f&quot;, raw_seconds);\r\n\r\n  hours = (int) raw_seconds\/3600;\r\n  hours_residue = (int) raw_seconds % 3600;\r\n  minutes = hours_residue\/60;\r\n  seconds = hours_residue % 60;\r\n  milliseconds = 0;\r\n\r\n  \/\/ get the decimal part of raw_seconds to get milliseconds\r\n  char *pos;\r\n  pos = strchr(hms, &#039;.&#039;);\r\n  int ipos = (int) (pos - hms);\r\n  char decimalpart[15];\r\n  memset(decimalpart, &#039; &#039;, sizeof(decimalpart));\r\n  strncpy(decimalpart, &amp;hms[ipos+1], 3);\r\n  milliseconds = atoi(decimalpart);\t\r\n\r\n  \r\n  sprintf(hms, &quot;%d:%d:%d.%d&quot;, hours, minutes, seconds, milliseconds);\r\n  return hms;\r\n}\r\n\r\n<\/pre><br \/>A sample run is given below:<\/p>\n<p><a href=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2015\/09\/Screenshot-from-2015-09-05-192920.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-medium wp-image-2245\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2015\/09\/Screenshot-from-2015-09-05-192920-620x471.png\" alt=\"Screenshot from 2015-09-05 19:29:20\" width=\"620\" height=\"471\" srcset=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2015\/09\/Screenshot-from-2015-09-05-192920-620x471.png 620w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2015\/09\/Screenshot-from-2015-09-05-192920-300x228.png 300w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2015\/09\/Screenshot-from-2015-09-05-192920.png 788w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/a><\/p>\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong> <\/strong><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>The WAV (or PCM) audio format is the most basic format for storing audio. WAV files can be of different extended formats , but PCM <a class=\"mh-excerpt-more\" href=\"https:\/\/truelogic.org\/wordpress\/2015\/09\/04\/parsing-a-wav-file-in-c\/\" title=\"Parsing a WAV file in C\">[&#8230;]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":2233,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[301,298,296],"tags":[],"class_list":["post-2230","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-audio","category-linux","category-slideshow"],"_links":{"self":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2230","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/comments?post=2230"}],"version-history":[{"count":10,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2230\/revisions"}],"predecessor-version":[{"id":4352,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2230\/revisions\/4352"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/media\/2233"}],"wp:attachment":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/media?parent=2230"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/categories?post=2230"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/tags?post=2230"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}