her.esy.fun/src/Scratch/en/blog/2010-10-14-Fun-with-wav/index.html

352 lines
34 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>YBlog - Fun with wav</title>
<meta name="keywords" content="wav, C, format, programming" />
<link rel="shortcut icon" type="image/x-icon" href="../../../../Scratch/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/css/y.css" />
<link rel="stylesheet" type="text/css" href="/css/legacy.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="apple-touch-icon" href="../../../../Scratch/img/about/FlatAvatar@2x.png" />
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->
<!-- IndieAuth -->
<link href="https://twitter.com/yogsototh" rel="me">
<link href="https://github.com/yogsototh" rel="me">
<link href="mailto:yann.esposito@gmail.com" rel="me">
<link rel="pgpkey" href="../../../../pubkey.txt">
</head>
<body lang="en" class="article">
<div id="content">
<div id="header">
<div id="choix">
<span id="choixlang">
<a href="../../../../Scratch/fr/blog/2010-10-14-Fun-with-wav/">French</a>
</span>
<span class="tomenu"><a href="#navigation">↓ Menu ↓</a></span>
<span class="flush"></span>
</div>
</div>
<div id="titre">
<h1>Fun with wav</h1>
</div>
<div class="flush"></div>
<div id="afterheader" class="article">
<div class="corps">
<div class="intro">
<p><span class="sc"><abbr title="Too long; didn't read">tl;dr</abbr>: </span> Played to process a <code>wav</code> file. <code>C</code> was easier and cleaner than Ruby.</p>
<p>edit: I wanted this program to work only on one specific machine (a x86 on a 32 bit Ubuntu). Therefore I didnt had any portability consideration. This is only a <em>hack</em>.</p>
</div>
<p>I had to compute the sum of the absolute values of data of a <code>.wav</code> file. For efficiency (and fun) reasons, I had chosen <code>C</code> language.</p>
<p>I didnt programmed in <code>C</code> for a long time. From my memory it was a pain to read and write to files. But in the end I was really impressed by the code I get. It was really clean. This is even more impressive knowing I used mostly low level functions.</p>
<p>A <code>wav</code> file has an header containing many metadata. This header was optimized to take as few space as possible. The header is then a block of packed bytes.</p>
<ul>
<li>The 4th first bytes must contains <code>RIFF</code> in ASCII,</li>
<li>the following 4th Bytes is an 32 bits integer giving the size of the file minus 8, etc…</li>
</ul>
<p>Surprisingly, I believe that reading this kind of file is easier in <code>C</code> than in most higher level language. Proof: I only have to search on the web the complete header format and write it in a struct.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb1-1" title="1"><span class="kw">struct</span> wavfile</a>
<a class="sourceLine" id="cb1-2" title="2">{</a>
<a class="sourceLine" id="cb1-3" title="3"> <span class="dt">char</span> id[<span class="dv">4</span>]; <span class="co">// should always contain &quot;RIFF&quot;</span></a>
<a class="sourceLine" id="cb1-4" title="4"> <span class="dt">int</span> totallength; <span class="co">// total file length minus 8</span></a>
<a class="sourceLine" id="cb1-5" title="5"> <span class="dt">char</span> wavefmt[<span class="dv">8</span>]; <span class="co">// should be &quot;WAVEfmt &quot;</span></a>
<a class="sourceLine" id="cb1-6" title="6"> <span class="dt">int</span> format; <span class="co">// 16 for PCM format</span></a>
<a class="sourceLine" id="cb1-7" title="7"> <span class="dt">short</span> pcm; <span class="co">// 1 for PCM format</span></a>
<a class="sourceLine" id="cb1-8" title="8"> <span class="dt">short</span> channels; <span class="co">// channels</span></a>
<a class="sourceLine" id="cb1-9" title="9"> <span class="dt">int</span> frequency; <span class="co">// sampling frequency</span></a>
<a class="sourceLine" id="cb1-10" title="10"> <span class="dt">int</span> bytes_per_second;</a>
<a class="sourceLine" id="cb1-11" title="11"> <span class="dt">short</span> bytes_by_capture;</a>
<a class="sourceLine" id="cb1-12" title="12"> <span class="dt">short</span> bits_per_sample;</a>
<a class="sourceLine" id="cb1-13" title="13"> <span class="dt">char</span> data[<span class="dv">4</span>]; <span class="co">// should always contain &quot;data&quot;</span></a>
<a class="sourceLine" id="cb1-14" title="14"> <span class="dt">int</span> bytes_in_data;</a>
<a class="sourceLine" id="cb1-15" title="15">};</a></code></pre></div>
<p>To read this kind of data in Ruby, I certainly had to write a block of code for each element in the struct. But in <code>C</code> I simply written:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb2-1" title="1">fread(&amp;header,<span class="kw">sizeof</span>(header),<span class="dv">1</span>,wav)</a></code></pre></div>
<p>Only one step to fill my data structure. Magic!</p>
<p>Then, get an int value coded on two Bytes is also not a natural operation for high level language. In <code>C</code>, to read a sequence of 2 Bytes numbers I only had to write:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb3-1" title="1"><span class="dt">short</span> value=<span class="dv">0</span>;</a>
<a class="sourceLine" id="cb3-2" title="2"><span class="cf">while</span>( fread(&amp;value,<span class="kw">sizeof</span>(value),<span class="dv">1</span>,wav) ) {</a>
<a class="sourceLine" id="cb3-3" title="3"> <span class="co">// do something with value</span></a>
<a class="sourceLine" id="cb3-4" title="4">}</a></code></pre></div>
<p>Finally I ended with the following code. Remark I know the wav format (16 bit / 48000Hz):</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb4-1" title="1"><span class="pp">#include </span><span class="im">&lt;stdio.h&gt;</span></a>
<a class="sourceLine" id="cb4-2" title="2"><span class="pp">#include </span><span class="im">&lt;stdlib.h&gt;</span></a>
<a class="sourceLine" id="cb4-3" title="3"><span class="pp">#include </span><span class="im">&lt;stdint.h&gt;</span></a>
<a class="sourceLine" id="cb4-4" title="4"></a>
<a class="sourceLine" id="cb4-5" title="5"><span class="kw">struct</span> wavfile</a>
<a class="sourceLine" id="cb4-6" title="6">{</a>
<a class="sourceLine" id="cb4-7" title="7"> <span class="dt">char</span> id[<span class="dv">4</span>]; <span class="co">// should always contain &quot;RIFF&quot;</span></a>
<a class="sourceLine" id="cb4-8" title="8"> <span class="dt">int</span> totallength; <span class="co">// total file length minus 8</span></a>
<a class="sourceLine" id="cb4-9" title="9"> <span class="dt">char</span> wavefmt[<span class="dv">8</span>]; <span class="co">// should be &quot;WAVEfmt &quot;</span></a>
<a class="sourceLine" id="cb4-10" title="10"> <span class="dt">int</span> format; <span class="co">// 16 for PCM format</span></a>
<a class="sourceLine" id="cb4-11" title="11"> <span class="dt">short</span> pcm; <span class="co">// 1 for PCM format</span></a>
<a class="sourceLine" id="cb4-12" title="12"> <span class="dt">short</span> channels; <span class="co">// channels</span></a>
<a class="sourceLine" id="cb4-13" title="13"> <span class="dt">int</span> frequency; <span class="co">// sampling frequency</span></a>
<a class="sourceLine" id="cb4-14" title="14"> <span class="dt">int</span> bytes_per_second;</a>
<a class="sourceLine" id="cb4-15" title="15"> <span class="dt">short</span> bytes_by_capture;</a>
<a class="sourceLine" id="cb4-16" title="16"> <span class="dt">short</span> bits_per_sample;</a>
<a class="sourceLine" id="cb4-17" title="17"> <span class="dt">char</span> data[<span class="dv">4</span>]; <span class="co">// should always contain &quot;data&quot;</span></a>
<a class="sourceLine" id="cb4-18" title="18"> <span class="dt">int</span> bytes_in_data;</a>
<a class="sourceLine" id="cb4-19" title="19">};</a>
<a class="sourceLine" id="cb4-20" title="20"></a>
<a class="sourceLine" id="cb4-21" title="21"><span class="dt">int</span> main(<span class="dt">int</span> argc, <span class="dt">char</span> *argv[]) {</a>
<a class="sourceLine" id="cb4-22" title="22"> <span class="dt">char</span> *filename=argv[<span class="dv">1</span>];</a>
<a class="sourceLine" id="cb4-23" title="23"> <span class="dt">FILE</span> *wav = fopen(filename,<span class="st">&quot;rb&quot;</span>);</a>
<a class="sourceLine" id="cb4-24" title="24"> <span class="kw">struct</span> wavfile header;</a>
<a class="sourceLine" id="cb4-25" title="25"></a>
<a class="sourceLine" id="cb4-26" title="26"> <span class="cf">if</span> ( wav == NULL ) {</a>
<a class="sourceLine" id="cb4-27" title="27"> fprintf(stderr,<span class="st">&quot;Can't open input file %s&quot;</span>, filename);</a>
<a class="sourceLine" id="cb4-28" title="28"> exit(<span class="dv">1</span>);</a>
<a class="sourceLine" id="cb4-29" title="29"> }</a>
<a class="sourceLine" id="cb4-30" title="30"></a>
<a class="sourceLine" id="cb4-31" title="31"> <span class="co">// read header</span></a>
<a class="sourceLine" id="cb4-32" title="32"> <span class="cf">if</span> ( fread(&amp;header,<span class="kw">sizeof</span>(header),<span class="dv">1</span>,wav) &lt; <span class="dv">1</span> )</a>
<a class="sourceLine" id="cb4-33" title="33"> {</a>
<a class="sourceLine" id="cb4-34" title="34"> fprintf(stderr,<span class="st">&quot;Can't read file header</span><span class="sc">\n</span><span class="st">&quot;</span>);</a>
<a class="sourceLine" id="cb4-35" title="35"> exit(<span class="dv">1</span>);</a>
<a class="sourceLine" id="cb4-36" title="36"> }</a>
<a class="sourceLine" id="cb4-37" title="37"> <span class="cf">if</span> ( header.id[<span class="dv">0</span>] != <span class="ch">'R'</span></a>
<a class="sourceLine" id="cb4-38" title="38"> || header.id[<span class="dv">1</span>] != <span class="ch">'I'</span> </a>
<a class="sourceLine" id="cb4-39" title="39"> || header.id[<span class="dv">2</span>] != <span class="ch">'F'</span> </a>
<a class="sourceLine" id="cb4-40" title="40"> || header.id[<span class="dv">3</span>] != <span class="ch">'F'</span> ) { </a>
<a class="sourceLine" id="cb4-41" title="41"> fprintf(stderr,<span class="st">&quot;ERROR: Not wav format</span><span class="sc">\n</span><span class="st">&quot;</span>); </a>
<a class="sourceLine" id="cb4-42" title="42"> exit(<span class="dv">1</span>); </a>
<a class="sourceLine" id="cb4-43" title="43"> }</a>
<a class="sourceLine" id="cb4-44" title="44"></a>
<a class="sourceLine" id="cb4-45" title="45"> fprintf(stderr,<span class="st">&quot;wav format</span><span class="sc">\n</span><span class="st">&quot;</span>);</a>
<a class="sourceLine" id="cb4-46" title="46"></a>
<a class="sourceLine" id="cb4-47" title="47"> <span class="co">// read data</span></a>
<a class="sourceLine" id="cb4-48" title="48"> <span class="dt">long</span> sum=<span class="dv">0</span>;</a>
<a class="sourceLine" id="cb4-49" title="49"> <span class="dt">short</span> value=<span class="dv">0</span>;</a>
<a class="sourceLine" id="cb4-50" title="50"> <span class="cf">while</span>( fread(&amp;value,<span class="kw">sizeof</span>(value),<span class="dv">1</span>,wav) ) {</a>
<a class="sourceLine" id="cb4-51" title="51"> <span class="co">// fprintf(stderr,&quot;%d\n&quot;, value);</span></a>
<a class="sourceLine" id="cb4-52" title="52"> <span class="cf">if</span> (value&lt;<span class="dv">0</span>) { value=-value; }</a>
<a class="sourceLine" id="cb4-53" title="53"> sum += value;</a>
<a class="sourceLine" id="cb4-54" title="54"> }</a>
<a class="sourceLine" id="cb4-55" title="55"> printf(<span class="st">&quot;%ld</span><span class="sc">\n</span><span class="st">&quot;</span>,sum);</a>
<a class="sourceLine" id="cb4-56" title="56"> exit(<span class="dv">0</span>);</a>
<a class="sourceLine" id="cb4-57" title="57">}</a></code></pre></div>
<p>Of course it is only a hack. But we can see how easy and clean it should be to improve. As I say often: the right tool for your need instead of the same tool for all your needs. Because here <code>C</code> is clearly far superior than Ruby to handle this simple tasks.</p>
<p>I am curious to know if somebody know a nice way to do this with Ruby or Python.</p>
<p><em>edit: for compatibility reasons (64bit machines) used <code>int16_t</code> instead of <code>short</code> and <code>int</code> instead of <code>int</code>.</em></p>
<div class="intro">
<p>Edit (2): after most consideration about portability I made an <em>hopefully</em> more portable version. But I must confess this task was a bit tedious. The code remain as readable as before. But I had to use some compiler specific declaration to force the structure to be packed:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb5-1" title="1">__attribute__((__packed__))</a></code></pre></div>
<p>Therefore this implementation should for big and little endian architecture. However, it must be compiled with <code>gcc</code>. The new code make more tests but still dont use <code>mmap</code>. Here it is:</p>
</div>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb6-1" title="1"><span class="pp">#include </span><span class="im">&lt;stdio.h&gt;</span></a>
<a class="sourceLine" id="cb6-2" title="2"><span class="pp">#include </span><span class="im">&lt;stdlib.h&gt;</span></a>
<a class="sourceLine" id="cb6-3" title="3"><span class="pp">#include </span><span class="im">&lt;string.h&gt;</span><span class="pp"> </span><span class="co">// for memcmp</span></a>
<a class="sourceLine" id="cb6-4" title="4"><span class="pp">#include </span><span class="im">&lt;stdint.h&gt;</span><span class="pp"> </span><span class="co">// for int16_t and int32_t</span></a>
<a class="sourceLine" id="cb6-5" title="5"></a>
<a class="sourceLine" id="cb6-6" title="6"><span class="kw">struct</span> wavfile</a>
<a class="sourceLine" id="cb6-7" title="7">{</a>
<a class="sourceLine" id="cb6-8" title="8"> <span class="dt">char</span> id[<span class="dv">4</span>]; <span class="co">// should always contain &quot;RIFF&quot;</span></a>
<a class="sourceLine" id="cb6-9" title="9"> <span class="dt">int32_t</span> totallength; <span class="co">// total file length minus 8</span></a>
<a class="sourceLine" id="cb6-10" title="10"> <span class="dt">char</span> wavefmt[<span class="dv">8</span>]; <span class="co">// should be &quot;WAVEfmt &quot;</span></a>
<a class="sourceLine" id="cb6-11" title="11"> <span class="dt">int32_t</span> format; <span class="co">// 16 for PCM format</span></a>
<a class="sourceLine" id="cb6-12" title="12"> <span class="dt">int16_t</span> pcm; <span class="co">// 1 for PCM format</span></a>
<a class="sourceLine" id="cb6-13" title="13"> <span class="dt">int16_t</span> channels; <span class="co">// channels</span></a>
<a class="sourceLine" id="cb6-14" title="14"> <span class="dt">int32_t</span> frequency; <span class="co">// sampling frequency</span></a>
<a class="sourceLine" id="cb6-15" title="15"> <span class="dt">int32_t</span> bytes_per_second;</a>
<a class="sourceLine" id="cb6-16" title="16"> <span class="dt">int16_t</span> bytes_by_capture;</a>
<a class="sourceLine" id="cb6-17" title="17"> <span class="dt">int16_t</span> bits_per_sample;</a>
<a class="sourceLine" id="cb6-18" title="18"> <span class="dt">char</span> data[<span class="dv">4</span>]; <span class="co">// should always contain &quot;data&quot;</span></a>
<a class="sourceLine" id="cb6-19" title="19"> <span class="dt">int32_t</span> bytes_in_data;</a>
<a class="sourceLine" id="cb6-20" title="20">} __attribute__((__packed__));</a>
<a class="sourceLine" id="cb6-21" title="21"></a>
<a class="sourceLine" id="cb6-22" title="22"><span class="dt">int</span> is_big_endian(<span class="dt">void</span>) {</a>
<a class="sourceLine" id="cb6-23" title="23"> <span class="kw">union</span> {</a>
<a class="sourceLine" id="cb6-24" title="24"> <span class="dt">uint32_t</span> i;</a>
<a class="sourceLine" id="cb6-25" title="25"> <span class="dt">char</span> c[<span class="dv">4</span>];</a>
<a class="sourceLine" id="cb6-26" title="26"> } bint = {<span class="bn">0x01000000</span>};</a>
<a class="sourceLine" id="cb6-27" title="27"> <span class="cf">return</span> bint.c[<span class="dv">0</span>]==<span class="dv">1</span>;</a>
<a class="sourceLine" id="cb6-28" title="28">}</a>
<a class="sourceLine" id="cb6-29" title="29"></a>
<a class="sourceLine" id="cb6-30" title="30"><span class="dt">int</span> main(<span class="dt">int</span> argc, <span class="dt">char</span> *argv[]) {</a>
<a class="sourceLine" id="cb6-31" title="31"> <span class="dt">char</span> *filename=argv[<span class="dv">1</span>];</a>
<a class="sourceLine" id="cb6-32" title="32"> <span class="dt">FILE</span> *wav = fopen(filename,<span class="st">&quot;rb&quot;</span>);</a>
<a class="sourceLine" id="cb6-33" title="33"> <span class="kw">struct</span> wavfile header;</a>
<a class="sourceLine" id="cb6-34" title="34"></a>
<a class="sourceLine" id="cb6-35" title="35"> <span class="cf">if</span> ( wav == NULL ) {</a>
<a class="sourceLine" id="cb6-36" title="36"> fprintf(stderr,<span class="st">&quot;Can't open input file %s</span><span class="sc">\n</span><span class="st">&quot;</span>, filename);</a>
<a class="sourceLine" id="cb6-37" title="37"> exit(<span class="dv">1</span>);</a>
<a class="sourceLine" id="cb6-38" title="38"> }</a>
<a class="sourceLine" id="cb6-39" title="39"></a>
<a class="sourceLine" id="cb6-40" title="40"> <span class="co">// read header</span></a>
<a class="sourceLine" id="cb6-41" title="41"> <span class="cf">if</span> ( fread(&amp;header,<span class="kw">sizeof</span>(header),<span class="dv">1</span>,wav) &lt; <span class="dv">1</span> ) {</a>
<a class="sourceLine" id="cb6-42" title="42"> fprintf(stderr,<span class="st">&quot;Can't read input file header %s</span><span class="sc">\n</span><span class="st">&quot;</span>, filename);</a>
<a class="sourceLine" id="cb6-43" title="43"> exit(<span class="dv">1</span>);</a>
<a class="sourceLine" id="cb6-44" title="44"> }</a>
<a class="sourceLine" id="cb6-45" title="45"></a>
<a class="sourceLine" id="cb6-46" title="46"> <span class="co">// if wav file isn't the same endianness than the current environment</span></a>
<a class="sourceLine" id="cb6-47" title="47"> <span class="co">// we quit</span></a>
<a class="sourceLine" id="cb6-48" title="48"> <span class="cf">if</span> ( is_big_endian() ) {</a>
<a class="sourceLine" id="cb6-49" title="49"> <span class="cf">if</span> ( memcmp( header.id,<span class="st">&quot;RIFX&quot;</span>, <span class="dv">4</span>) != <span class="dv">0</span> ) {</a>
<a class="sourceLine" id="cb6-50" title="50"> fprintf(stderr,<span class="st">&quot;ERROR: %s is not a big endian wav file</span><span class="sc">\n</span><span class="st">&quot;</span>, filename); </a>
<a class="sourceLine" id="cb6-51" title="51"> exit(<span class="dv">1</span>);</a>
<a class="sourceLine" id="cb6-52" title="52"> }</a>
<a class="sourceLine" id="cb6-53" title="53"> } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb6-54" title="54"> <span class="cf">if</span> ( memcmp( header.id,<span class="st">&quot;RIFF&quot;</span>, <span class="dv">4</span>) != <span class="dv">0</span> ) {</a>
<a class="sourceLine" id="cb6-55" title="55"> fprintf(stderr,<span class="st">&quot;ERROR: %s is not a little endian wav file</span><span class="sc">\n</span><span class="st">&quot;</span>, filename); </a>
<a class="sourceLine" id="cb6-56" title="56"> exit(<span class="dv">1</span>);</a>
<a class="sourceLine" id="cb6-57" title="57"> }</a>
<a class="sourceLine" id="cb6-58" title="58"> }</a>
<a class="sourceLine" id="cb6-59" title="59"></a>
<a class="sourceLine" id="cb6-60" title="60"> <span class="cf">if</span> ( memcmp( header.wavefmt, <span class="st">&quot;WAVEfmt &quot;</span>, <span class="dv">8</span>) != <span class="dv">0</span> </a>
<a class="sourceLine" id="cb6-61" title="61"> || memcmp( header.data, <span class="st">&quot;data&quot;</span>, <span class="dv">4</span>) != <span class="dv">0</span> </a>
<a class="sourceLine" id="cb6-62" title="62"> ) {</a>
<a class="sourceLine" id="cb6-63" title="63"> fprintf(stderr,<span class="st">&quot;ERROR: Not wav format</span><span class="sc">\n</span><span class="st">&quot;</span>); </a>
<a class="sourceLine" id="cb6-64" title="64"> exit(<span class="dv">1</span>); </a>
<a class="sourceLine" id="cb6-65" title="65"> }</a>
<a class="sourceLine" id="cb6-66" title="66"> <span class="cf">if</span> (header.format != <span class="dv">16</span>) {</a>
<a class="sourceLine" id="cb6-67" title="67"> fprintf(stderr,<span class="st">&quot;</span><span class="sc">\n</span><span class="st">ERROR: not 16 bit wav format.&quot;</span>);</a>
<a class="sourceLine" id="cb6-68" title="68"> exit(<span class="dv">1</span>);</a>
<a class="sourceLine" id="cb6-69" title="69"> }</a>
<a class="sourceLine" id="cb6-70" title="70"> fprintf(stderr,<span class="st">&quot;format: %d bits&quot;</span>, header.format);</a>
<a class="sourceLine" id="cb6-71" title="71"> <span class="cf">if</span> (header.format == <span class="dv">16</span>) {</a>
<a class="sourceLine" id="cb6-72" title="72"> fprintf(stderr,<span class="st">&quot;, PCM&quot;</span>);</a>
<a class="sourceLine" id="cb6-73" title="73"> } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb6-74" title="74"> fprintf(stderr,<span class="st">&quot;, not PCM (%d)&quot;</span>, header.format);</a>
<a class="sourceLine" id="cb6-75" title="75"> }</a>
<a class="sourceLine" id="cb6-76" title="76"> <span class="cf">if</span> (header.pcm == <span class="dv">1</span>) {</a>
<a class="sourceLine" id="cb6-77" title="77"> fprintf(stderr, <span class="st">&quot; uncompressed&quot;</span> );</a>
<a class="sourceLine" id="cb6-78" title="78"> } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb6-79" title="79"> fprintf(stderr, <span class="st">&quot; compressed&quot;</span> );</a>
<a class="sourceLine" id="cb6-80" title="80"> }</a>
<a class="sourceLine" id="cb6-81" title="81"> fprintf(stderr,<span class="st">&quot;, channel %d&quot;</span>, header.pcm);</a>
<a class="sourceLine" id="cb6-82" title="82"> fprintf(stderr,<span class="st">&quot;, freq %d&quot;</span>, header.frequency );</a>
<a class="sourceLine" id="cb6-83" title="83"> fprintf(stderr,<span class="st">&quot;, %d bytes per sec&quot;</span>, header.bytes_per_second );</a>
<a class="sourceLine" id="cb6-84" title="84"> fprintf(stderr,<span class="st">&quot;, %d bytes by capture&quot;</span>, header.bytes_by_capture );</a>
<a class="sourceLine" id="cb6-85" title="85"> fprintf(stderr,<span class="st">&quot;, %d bits per sample&quot;</span>, header.bytes_by_capture );</a>
<a class="sourceLine" id="cb6-86" title="86"> fprintf(stderr,<span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span> );</a>
<a class="sourceLine" id="cb6-87" title="87"></a>
<a class="sourceLine" id="cb6-88" title="88"> <span class="cf">if</span> ( memcmp( header.data, <span class="st">&quot;data&quot;</span>, <span class="dv">4</span>) != <span class="dv">0</span> ) { </a>
<a class="sourceLine" id="cb6-89" title="89"> fprintf(stderr,<span class="st">&quot;ERROR: Prrroblem?</span><span class="sc">\n</span><span class="st">&quot;</span>); </a>
<a class="sourceLine" id="cb6-90" title="90"> exit(<span class="dv">1</span>); </a>
<a class="sourceLine" id="cb6-91" title="91"> }</a>
<a class="sourceLine" id="cb6-92" title="92"> fprintf(stderr,<span class="st">&quot;wav format</span><span class="sc">\n</span><span class="st">&quot;</span>);</a>
<a class="sourceLine" id="cb6-93" title="93"></a>
<a class="sourceLine" id="cb6-94" title="94"> <span class="co">// read data</span></a>
<a class="sourceLine" id="cb6-95" title="95"> <span class="dt">long</span> <span class="dt">long</span> sum=<span class="dv">0</span>;</a>
<a class="sourceLine" id="cb6-96" title="96"> <span class="dt">int16_t</span> value;</a>
<a class="sourceLine" id="cb6-97" title="97"> <span class="dt">int</span> i=<span class="dv">0</span>;</a>
<a class="sourceLine" id="cb6-98" title="98"> fprintf(stderr,<span class="st">&quot;---</span><span class="sc">\n</span><span class="st">&quot;</span>, value);</a>
<a class="sourceLine" id="cb6-99" title="99"> <span class="cf">while</span>( fread(&amp;value,<span class="kw">sizeof</span>(value),<span class="dv">1</span>,wav) ) {</a>
<a class="sourceLine" id="cb6-100" title="100"> <span class="cf">if</span> (value&lt;<span class="dv">0</span>) { value=-value; }</a>
<a class="sourceLine" id="cb6-101" title="101"> sum += value;</a>
<a class="sourceLine" id="cb6-102" title="102"> }</a>
<a class="sourceLine" id="cb6-103" title="103"> printf(<span class="st">&quot;%lld</span><span class="sc">\n</span><span class="st">&quot;</span>,sum);</a>
<a class="sourceLine" id="cb6-104" title="104"> exit(<span class="dv">0</span>);</a>
<a class="sourceLine" id="cb6-105" title="105">}</a></code></pre></div>
<p><em>Edit(3)</em>: On <a href="http://reddit.com">reddit</a> <a href="http://www.reddit.com/user/Bogdanp">Bogdanp</a> proposed a Python version:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb7-1" title="1"><span class="co">#!/usr/bin/env python</span></a>
<a class="sourceLine" id="cb7-2" title="2"><span class="im">from</span> struct <span class="im">import</span> calcsize, unpack</a>
<a class="sourceLine" id="cb7-3" title="3"><span class="im">from</span> sys <span class="im">import</span> argv, exit</a>
<a class="sourceLine" id="cb7-4" title="4"></a>
<a class="sourceLine" id="cb7-5" title="5"><span class="kw">def</span> word_iter(f):</a>
<a class="sourceLine" id="cb7-6" title="6"> <span class="cf">while</span> <span class="va">True</span>:</a>
<a class="sourceLine" id="cb7-7" title="7"> _bytes <span class="op">=</span> f.read(<span class="dv">2</span>)</a>
<a class="sourceLine" id="cb7-8" title="8"></a>
<a class="sourceLine" id="cb7-9" title="9"> <span class="cf">if</span> <span class="bu">len</span>(_bytes) <span class="op">!=</span> <span class="dv">2</span>:</a>
<a class="sourceLine" id="cb7-10" title="10"> <span class="cf">raise</span> <span class="pp">StopIteration</span></a>
<a class="sourceLine" id="cb7-11" title="11"></a>
<a class="sourceLine" id="cb7-12" title="12"> <span class="cf">yield</span> unpack(<span class="st">&quot;=h&quot;</span>, _bytes)[<span class="dv">0</span>]</a>
<a class="sourceLine" id="cb7-13" title="13"></a>
<a class="sourceLine" id="cb7-14" title="14"><span class="cf">try</span>:</a>
<a class="sourceLine" id="cb7-15" title="15"> <span class="cf">with</span> <span class="bu">open</span>(argv[<span class="dv">1</span>], <span class="st">&quot;rb&quot;</span>) <span class="im">as</span> f:</a>
<a class="sourceLine" id="cb7-16" title="16"> wav <span class="op">=</span> <span class="st">&quot;=4ci8cihhiihh4ci&quot;</span></a>
<a class="sourceLine" id="cb7-17" title="17"> wav_size <span class="op">=</span> calcsize(wav)</a>
<a class="sourceLine" id="cb7-18" title="18"> metadata <span class="op">=</span> unpack(wav, f.read(wav_size))</a>
<a class="sourceLine" id="cb7-19" title="19"></a>
<a class="sourceLine" id="cb7-20" title="20"> <span class="cf">if</span> <span class="st">&quot;&quot;</span>.join(metadata[:<span class="dv">4</span>]) <span class="op">!=</span> <span class="st">&quot;RIFF&quot;</span>:</a>
<a class="sourceLine" id="cb7-21" title="21"> <span class="bu">print</span> <span class="st">&quot;error: not wav file.&quot;</span></a>
<a class="sourceLine" id="cb7-22" title="22"> exit(<span class="dv">1</span>)</a>
<a class="sourceLine" id="cb7-23" title="23"></a>
<a class="sourceLine" id="cb7-24" title="24"> <span class="bu">print</span> <span class="bu">sum</span>(<span class="bu">abs</span>(word) <span class="cf">for</span> word <span class="kw">in</span> word_iter(f))</a>
<a class="sourceLine" id="cb7-25" title="25"><span class="cf">except</span> <span class="pp">IOError</span>:</a>
<a class="sourceLine" id="cb7-26" title="26"> <span class="bu">print</span> <span class="st">&quot;error: can't open input file '</span><span class="sc">%s</span><span class="st">'.&quot;</span> <span class="op">%</span> argv[<span class="dv">1</span>]</a>
<a class="sourceLine" id="cb7-27" title="27"> exit(<span class="dv">1</span>)</a></code></pre></div>
<p>and <a href="http://www.reddit.com/user/luikore">luikore</a> proposed an impressive Ruby version:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode ruby"><code class="sourceCode ruby"><a class="sourceLine" id="cb8-1" title="1">data = <span class="dt">ARGF</span>.read</a>
<a class="sourceLine" id="cb8-2" title="2"> keys =<span class="ot"> %w[</span><span class="st">id totallength wavefmt format</span></a>
<a class="sourceLine" id="cb8-3" title="3"><span class="st"> pcm channels frequency bytes_per_second</span></a>
<a class="sourceLine" id="cb8-4" title="4"><span class="st"> bytes_by_capture bits_per_sample</span></a>
<a class="sourceLine" id="cb8-5" title="5"><span class="st"> data bytes_in_data sum</span></a>
<a class="sourceLine" id="cb8-6" title="6"><span class="st"> </span><span class="ot">]</span></a>
<a class="sourceLine" id="cb8-7" title="7"> values = data.unpack <span class="st">'Z4 i Z8 i s s i i s s Z4 i s*'</span></a>
<a class="sourceLine" id="cb8-8" title="8"> sum = values.drop(<span class="dv">12</span>).map(&amp;<span class="st">:abs</span>).inject(:+)</a>
<a class="sourceLine" id="cb8-9" title="9"> keys.zip(values.take(<span class="dv">12</span>) &lt;&lt; sum) {|k, v|</a>
<a class="sourceLine" id="cb8-10" title="10"> puts <span class="st">&quot;</span><span class="ot">#{</span>k.ljust <span class="dv">17</span><span class="ot">}</span><span class="st">: </span><span class="ot">#{</span>v<span class="ot">}</span><span class="st">&quot;</span></a>
<a class="sourceLine" id="cb8-11" title="11"> }</a></code></pre></div>
</div>
<div id="afterarticle">
<div id="social">
<a href="/rss.xml" target="_blank" rel="noopener noreferrer nofollow" class="social">RSS</a>
·
<a href="https://twitter.com/home?status=http%3A%2F%2Fyannesposito.com/Scratch/en/blog/2010-10-14-Fun-with-wav/%20via%20@yogsototh" target="_blank" rel="noopener noreferrer nofollow" class="social">Tweet</a>
·
<a href="http://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fyannesposito.com/Scratch/en/blog/2010-10-14-Fun-with-wav/" target="_blank" rel="noopener noreferrer nofollow" class="social">FB</a>
<br />
<a class="message" href="../../../../Scratch/en/blog/Social-link-the-right-way/">These social sharing links preserve your privacy</a>
</div>
<div id="navigation">
<a href="../../../../">Home</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/blog">Blog</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/softwares">Softwares</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/about">About</a>
</div>
<div id="totop"><a href="#header">↑ Top ↑</a></div>
<div id="bottom">
<div>
Published on 2010-10-14
</div>
<div>
<a href="https://twitter.com/yogsototh">Follow @yogsototh</a>
</div>
<div>
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US">Yann Esposito©</a>
</div>
<div>
Done with
<a href="http://www.vim.org" target="_blank" rel="noopener noreferrer nofollow"><strike>Vim</strike></a>
<a href="http://spacemacs.org" target="_blank" rel="noopener noreferrer nofollow">spacemacs</a>
<span class="pala">&amp;</span>
<a href="http://nanoc.ws" target="_blank" rel="noopener noreferrer nofollow"><strike>nanoc</strike></a>
<a href="http://jaspervdj.be/hakyll" target="_blank" rel="noopener noreferrer nofollow">Hakyll</a>
</div>
<hr />
<div style="max-width: 100%">
<a href="https://cardanohub.org">
<img src="../../../../Scratch/img/ada-logo.png" class="simple" style="height: 16px;
border-radius: 50%;
vertical-align:middle;
display:inline-block;" />
ADA:
</a>
<code style="display:inline-block;
word-wrap:break-word;
text-align: left;
vertical-align: top;
max-width: 85%;">
DdzFFzCqrhtAvdkmATx5Fm8NPJViDy85ZBw13p4XcNzVzvQg8e3vWLXq23JQWFxPEXK6Kvhaxxe7oJt4VMYHxpA2vtCFiP8fziohN6Yp
</code>
</div>
</div>
</div>
</div>
</div>
</body>
</html>