69 lines
5.3 KiB
HTML
69 lines
5.3 KiB
HTML
<html>
|
|
<head>
|
|
<!-- __CINERA_INCLUDES__ -->
|
|
</head>
|
|
<body>
|
|
<!-- __CINERA_MENUS__ -->
|
|
<!-- __CINERA_PLAYER__ -->
|
|
<!-- __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'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
|
|
"purer" tone, and will enhance our ear'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 "significant figures" 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's defined in <code>math.h</code>. Its defined to accept a float
|
|
"angle" 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 "angle" 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'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 "WavePeriods" we'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>
|