cinera_handmade.network/cmuratori/hero/code/code009_template.html

70 lines
5.3 KiB
HTML
Raw Permalink Normal View History

<html>
<head>
<!-- __CINERA_INCLUDES__ -->
</head>
<body>
<div>
<!-- __CINERA_MENUS__ -->
<!-- __CINERA_PLAYER__ -->
</div>
<!-- __CINERA_SCRIPT__ -->
<article id="video-notes">
<h1><!-- __CINERA_TITLE__ --></h1>
<h3 id="the-parable-of-the-game-jam">The parable of the Game Jam</h3>
<p>Don&#39;t let this happen to you, kids. You need good audio hardware to debug audio code.</p>
<h2 id="debugging-the-audio-code">Debugging the audio code</h2>
<h3 id="square-vs-sine-waves">Square vs Sine Waves</h3>
<p>Because square waves are already pretty harsh, they prevent our ability to diagnose some audio bugs. A Sine wave is a
&quot;purer&quot; tone, and will enhance our ear&#39;s ability to pick up on weirdness. The <code>sin</code> function, however, is defined to
return a value between -1 and 1, so we need to talk how to represent fractional numbers on a computer.</p>
<h4 id="fixed-point-arithmetic">Fixed-point arithmetic</h4>
<p>Fixed point is just integer math. We define some number of bits at the low end of our integer to represent the
fractional part of the number, and the remaining bits represent the whole part. Normal addition, subtraction,
multiplication, and division work fine, although we need to be aware of the rounding characteristics of fixed-point
when doing any numeric computation.</p>
<p>Fixed-point math was used more widely before computers commonly had floating point hardware. Today every computer, GPU,
and phone has very strong floating point capabilities, and so it is the defacto way to do numerics on a modern computer.</p>
<h4 id="floating-point-representation">Floating-point representation</h4>
<p>Floating-point is a more complicated (although very rigorously defined) way to represent fractional values. It
approaches the problem by dividing the available bits into:</p>
<ul>
<li>Sign bit</li>
<li>Exponent</li>
<li>Mantissa</li>
</ul>
<p>Such that the value represented is given by (sign)(mantissa * 2^exponent). This allows us to preserve a consistent
number of bits of precision (like &quot;significant figures&quot; from your physics class), given by the size of the mantissa,
regardless of the scale of our numbers, given by the exponent. This means that values representable by floating point
will be more densely packed near zero, and more sparse near the limits.</p>
<p>Floating Point values come in a few different precisions: <code>float</code> (single-precision, 32-bit), <code>double</code>
(double-precision, 64-bit), and <code>long double</code> (128-bit). We will rely on single-precision <code>float</code>s almost exclusively,
because they are good enough, and often we can operate on them twice as quickly as <code>double</code>s.</p>
<h3 id="generating-a-sine-wave-test-tone">Generating a sine-wave test tone</h3>
<p>For the test code, we use the c standard <code>sinf</code> function. It&#39;s defined in <code>math.h</code>. Its defined to accept a float
&quot;angle&quot; and return a float in the range [-1.0f, 1.0f]. The angle is a function of:</p>
<ul>
<li>How many samples we have written in total. Call it <code>RunningSampleIndex</code>.</li>
<li>The sampling frequency</li>
<li>The frequency of the tone we want to play (200-500 Hz is a good range for testing).</li>
</ul>
<p>When we set the tone frequency, we calculate its period in samples, and call it <code>WavePeriod</code>.</p>
<p>The &quot;angle&quot; is then given by <code>2.0f*PI*((float)RunningSampleIndex / (float)WavePeriod)</code>.</p>
<p>The <code>SampleValue</code> is given by the <code>sinf(angle) * Volume</code>.</p>
<h3 id="smoothing-the-waveform-on-frequency-change">Smoothing the waveform on frequency change</h3>
<p>When you change the frequency with the current code, you&#39;ll end up with an artifact. To combat this, you need to track
an additional value in your synth, basically your progress through the period of the wave, here called <code>tSine</code>.
Incrementally accumulate it per sample written:</p>
<pre><code>tSine += 2.0f*Pi32*1.0f/(float)WavePeriod // tSine = 2*Pi*how many &quot;WavePeriods&quot; we&#39;ve played since we started
</code></pre><p>Then just use it as the angle for the <code>SampleValue</code> calculation.</p>
<pre><code>SampleValue = sinf(tSine) * ToneVolume;
</code></pre><h2 id="additional-fixes">Additional Fixes</h2>
<ul>
<li>There is yet another XInput version that may be the only one available on some Windows 8 installs. <code>xinput9_1_0.dll</code>.
Add it to the chain when loading libs.</li>
<li>Bitshifting to divide will give you unexpected results for negative numbers. Use actual divide instead.</li>
</ul>
</article>
</body>
</html>