<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Em'</title>
    <description>The latest articles on DEV Community by Em' (@whispem).</description>
    <link>https://dev.to/whispem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3627036%2F6bfa3634-0d10-43d1-b178-062505f39eed.jpeg</url>
      <title>DEV Community: Em'</title>
      <link>https://dev.to/whispem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whispem"/>
    <language>en</language>
    <item>
      <title>I taught my CPU to sing — in pure Assembly</title>
      <dc:creator>Em'</dc:creator>
      <pubDate>Mon, 17 Aug 2026 12:10:51 +0000</pubDate>
      <link>https://dev.to/whispem/i-taught-my-cpu-to-sing-in-pure-assembly-1baj</link>
      <guid>https://dev.to/whispem/i-taught-my-cpu-to-sing-in-pure-assembly-1baj</guid>
      <description>&lt;p&gt;I didn't come from computers. &lt;br&gt;
My background is languages and translation — human grammar, the kind with conjugations and declensions. &lt;br&gt;
I started coding in October 2025, with Rust, and somewhere between a table of verb endings and my first compiler error, something clicked: a programming language is just another grammar, one where intention becomes action.&lt;/p&gt;

&lt;p&gt;Since then my curiosity has only pulled me lower. &lt;br&gt;
Rust, then C++, then assembly — because assembly lets nothing hide. I'd already made my CPU count, sort, hash, and draw. &lt;br&gt;
There was one thing left that isn't useful at all, and that's exactly why I wanted it: I wanted to make it sing.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;asm.fm&lt;/strong&gt; — a chiptune synthesizer written entirely in x86-64 assembly. &lt;br&gt;
No libc. No audio library. No sound card driver. &lt;br&gt;
The rule was simple: syscalls or nothing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Sound is just a list of numbers
&lt;/h2&gt;

&lt;p&gt;Here's the whole secret, the thing that makes this possible at all.&lt;/p&gt;

&lt;p&gt;A sound is a list of numbers. &lt;br&gt;
44,100 of them per second, each one describing where a speaker's cone should sit at that instant. &lt;br&gt;
Play those numbers back in order and the speaker moves; the air moves; you hear something. &lt;br&gt;
That's it. That's all a &lt;code&gt;.wav&lt;/code&gt; file is — a tiny header, then a very long list of positions.&lt;/p&gt;

&lt;p&gt;So the entire synthesizer is one idea repeated: &lt;strong&gt;compute the right numbers, write them out.&lt;/strong&gt; &lt;br&gt;
Generate a square wave? Emit &lt;code&gt;+amplitude&lt;/code&gt; for half a period, &lt;code&gt;-amplitude&lt;/code&gt; for the other half, over and over. &lt;br&gt;
Want it in tune? A note's frequency tells you how many samples one period lasts. &lt;br&gt;
Everything else is arithmetic on that list.&lt;/p&gt;

&lt;p&gt;There's no &lt;code&gt;printf&lt;/code&gt; to lean on, no &lt;code&gt;libsndfile&lt;/code&gt; to write the file. You build the 44-byte WAV header by hand — &lt;code&gt;"RIFF"&lt;/code&gt;, the sizes, &lt;code&gt;"fmt "&lt;/code&gt;, the sample rate, &lt;code&gt;"data"&lt;/code&gt; — and then you &lt;code&gt;write()&lt;/code&gt; the bytes straight to stdout. &lt;br&gt;
Redirect that to a file and you have music.&lt;/p&gt;
&lt;h2&gt;
  
  
  Four voices, then more
&lt;/h2&gt;

&lt;p&gt;From there it grew the way synthesizers historically grew.&lt;/p&gt;

&lt;p&gt;First the oscillators: square, sawtooth, triangle, and — for drums — an LFSR generating pseudo-random noise, the exact trick the NES used for its percussion. &lt;br&gt;
Then polyphony: melody, bass, and drums at once, each voice computed and summed into one buffer, a tiny tracker in a few hundred instructions.&lt;/p&gt;

&lt;p&gt;Then the notes stopped clicking. &lt;br&gt;
A raw note starts and stops at full volume, and that hard edge &lt;em&gt;clicks&lt;/em&gt;. &lt;strong&gt;ADSR envelopes&lt;/strong&gt; fix it — attack, decay, sustain, release — so each note fades in, holds, and fades out. The note breathes.&lt;/p&gt;
&lt;h2&gt;
  
  
  The "fm" was never just about radio
&lt;/h2&gt;

&lt;p&gt;The part I'm proudest of is FM synthesis — the technique behind the Yamaha DX7 and the Sega Genesis, the source of every bell-like, metallic, electric-piano tone of the 1980s.&lt;/p&gt;

&lt;p&gt;The idea is deceptively small. &lt;br&gt;
You take one oscillator (the &lt;em&gt;carrier&lt;/em&gt;) and wobble its frequency using a second oscillator (the &lt;em&gt;modulator&lt;/em&gt;), added right into its phase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modulator = sin(f_mod · t)
carrier   = sin(f_car · t  +  index · modulator)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single addition — feeding one wave into another's phase — spawns a whole spectrum of new harmonics. &lt;br&gt;
A pure tone becomes a shimmering bell.&lt;/p&gt;

&lt;p&gt;The catch: there's no &lt;code&gt;sin()&lt;/code&gt; without a math library. &lt;br&gt;
So I build a 1,024-entry sine table at startup, by hand, using a 7th-century polynomial approximation (Bhaskara I's), and look values up from it. &lt;br&gt;
The synthesizer computes its own trigonometry before it plays a note.&lt;/p&gt;

&lt;h2&gt;
  
  
  And then it kept going
&lt;/h2&gt;

&lt;p&gt;Once the core was there, the effects followed, each one a small idea layered on the last.&lt;/p&gt;

&lt;p&gt;First came &lt;strong&gt;modulation&lt;/strong&gt; — making the sound move. &lt;br&gt;
&lt;strong&gt;Vibrato&lt;/strong&gt; and &lt;strong&gt;tremolo&lt;/strong&gt;: a slow oscillator nudging the pitch, then the volume. &lt;br&gt;
&lt;strong&gt;PWM&lt;/strong&gt;, sliding the square wave's duty cycle so the timbre shivers while the pitch holds still. &lt;br&gt;
A &lt;strong&gt;delay&lt;/strong&gt;, which needed something new — memory. &lt;br&gt;
You keep the last fraction of a second of output in the buffer and read it back, faded; reading your own faded output &lt;em&gt;again&lt;/em&gt; is what makes the echo repeat and decay, all from one line of feedback.&lt;/p&gt;

&lt;p&gt;Then came &lt;strong&gt;sculpting the timbre&lt;/strong&gt; itself. &lt;br&gt;
A &lt;strong&gt;low-pass filter&lt;/strong&gt; — a one-pole smoother that softens a bright waveform into something warm and round. &lt;br&gt;
A &lt;strong&gt;bitcrusher&lt;/strong&gt;, snapping each sample to a handful of levels for that lo-fi, gritty crunch (a nice irony, degrading a synth that's already 8-bit at heart). &lt;br&gt;
&lt;strong&gt;Ring modulation&lt;/strong&gt;, which simply multiplies two waves — and out come their sum and difference frequencies, the originals gone entirely, leaving the metallic, clangorous voice famously used for the Daleks.&lt;/p&gt;

&lt;p&gt;And the one I love most: a &lt;strong&gt;resonant filter sweep&lt;/strong&gt;. &lt;br&gt;
A state-variable filter that feeds a band-pass term back on itself to boost the frequencies right at the cutoff — that resonant peak is the &lt;em&gt;squelch&lt;/em&gt; — while an LFO sweeps the cutoff up and down. &lt;br&gt;
It's the acid "wah", opening and closing, and it makes the filter seem to sing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do this?
&lt;/h2&gt;

&lt;p&gt;None of this belongs in production. That was never the point.&lt;/p&gt;

&lt;p&gt;The point is that after you write your own WAV header, you never quite hear a &lt;code&gt;.wav&lt;/code&gt; the same way. &lt;br&gt;
After you build FM synthesis from a hand-rolled sine table, you understand — in your fingers, not just your notes — what a synthesizer actually &lt;em&gt;is&lt;/em&gt;. &lt;br&gt;
Assembly doesn't forgive and it doesn't explain, which is exactly why it teaches so much. &lt;br&gt;
There's nothing between the math and the speaker but you.&lt;/p&gt;

&lt;p&gt;I made my processor count, sort, hash, and draw. Now it sings.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The repo is open, MIT-licensed: &lt;a href="https://github.com/whispem/asm.fm" rel="noopener noreferrer"&gt;github.com/whispem/asm.fm&lt;/a&gt; — feedback on the assembly is very welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>assembly</category>
      <category>programming</category>
      <category>music</category>
      <category>chiptune</category>
    </item>
  </channel>
</rss>
