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

352 lines
34 KiB
HTML
Raw Normal View History

2021-04-18 10:23:24 +00:00
<!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" />
2021-05-25 20:25:47 +00:00
<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" />
2021-04-18 10:23:24 +00:00
<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">
2021-05-25 20:25:47 +00:00
<a href="/rss.xml" target="_blank" rel="noopener noreferrer nofollow" class="social">RSS</a>
2021-04-18 10:23:24 +00:00
·
<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>