{"id":73,"date":"2022-10-18T22:19:34","date_gmt":"2022-10-18T22:19:34","guid":{"rendered":"http:\/\/www.kerneltrick.com\/?p=73"},"modified":"2022-10-18T22:19:34","modified_gmt":"2022-10-18T22:19:34","slug":"frequency-modulation-audio","status":"publish","type":"post","link":"https:\/\/www.kerneltrick.com\/?p=73","title":{"rendered":"Frequency Modulation Audio"},"content":{"rendered":"\n<p>Here is a simple example of how frequency modulation works in audio.<br>The frequency of one tone (carrier) is altered with another oscillator (modulator). At high speeds, the resulting combination will bring out extra harmonics.<br>There are no dependencies in the example.<br>Play with the sliders and see how the different tones are generated.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.kerneltrick.com\/wp-content\/uploads\/2022\/10\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"514\" height=\"527\" src=\"https:\/\/www.kerneltrick.com\/wp-content\/uploads\/2022\/10\/image.png\" alt=\"\" class=\"wp-image-74\" srcset=\"https:\/\/www.kerneltrick.com\/wp-content\/uploads\/2022\/10\/image.png 514w, https:\/\/www.kerneltrick.com\/wp-content\/uploads\/2022\/10\/image-293x300.png 293w\" sizes=\"auto, (max-width: 514px) 100vw, 514px\" \/><\/a><\/figure>\n\n\n\n<pre title=\"FM synth audio (Blitzmax)\" class=\"wp-block-code has-small-font-size\"><code lang=\"visual-basic\" class=\"language-visual-basic\">SuperStrict\nFramework brl.basic\nImport pub.freeaudio\nImport brl.glmax2d\nImport brl.retro\n\n'\/\/ If you get clicking in the audio, try restarting. Freeaudio is weird.\n\nAppTitle = \"Frequency Modulaton Example\"\n\nConst N% = 512\nConst TWOPI:Double = Pi * 2\nConst TWOPOS:Double = (2.0 * Pi) \/ N\n\nGlobal Buff#[N]\nGlobal Bp%\nGlobal CarFreq# = 440\nGlobal CarPhase#\nGlobal ModFreq# = 0\nGlobal ModPhase#\nGlobal ModAmp# = 1\nGlobal tim%\nGlobal CFslider:tSlider = New tSlider(20, 10, 350, 20, \"Carrier Freq\")\nGlobal MFslider:tSlider = New tSlider(20, 40, 350, 20, \"Modulator Freq\", 0)\nGlobal MAslider:tSlider = New tSlider(20, 70, 350, 20, \"Modulator Amp\", 0)\n\t\nGraphics 512, 500\n\nWhile Not KeyHit(KEY_ESCAPE)\n\tCls\n\t\tUpdateAudio()\n\t\tDrawWave()\n\t\tDrawSpeccy()\n\t\t\n\t\tCFslider.Update(MouseX(), MouseY())\n\t\tCarFreq = 20 + Lerp(20, 3000, CFslider.value() ^ 2)\n\t\tCFslider.Draw()\n\t\t\n\t\tMFslider.Update(MouseX(), MouseY())\n\t\tModFreq = Lerp(1, 3000, MFslider.value())\n\t\tMFslider.Draw()\n\t\t\n\t\tMAslider.Update(MouseX(), MouseY())\n\t\tModAmp = Lerp(1, 2000, MAslider.value())\n\t\tMAslider.Draw()\n\t\tDrawText(\"Mod\/Car Ratio: \" + (ModFreq \/ CarFreq), 300, 480)\n\tFlip\n\ttim:+1\nWend\n\n'------------------------------------------------------------------------------------------\nFunction GetAudio#()\n\t'\/\/Modulator\n\tModPhase:+ModFreq * TWOPI \/ 44100.0\n\tIf ModPhase > Pi Then ModPhase:-TWOPI\n\tLocal ModVal# = Sine(ModPhase) * ModAmp\n\t\n\t'\/\/Carrier\n\tCarPhase:+((CarFreq + ModVal)) * TWOPI \/ 44100.0\n\tIf CarPhase > Pi Then CarPhase:-TWOPI\n\n\tBuff[Bp &amp; 511] = Sine(CarPhase)\n\tBp:+1\n\n\tReturn Sine(CarPhase) * 0.2\nEnd Function\n'------------------------------------------------------------------------------------------\nFunction UpdateAudio()\n\tGlobal First:Int = True\n\tConst FRAG:Int = 2048 * 4\n\tGlobal buffer:Short[FRAG * 8]\n\tGlobal writepos:Int\t\n\tGlobal sound:Byte Ptr\n\tGlobal channel:Int\n\tGlobal streaming:Int\n\t\n\tIf First Then\n\t\tfa_Init(0)\n\t\tsound = fa_CreateSound(FRAG * 8, 16, 1, 44100, buffer, $80000000)\n\t\tchannel = fa_PlaySound(sound, FA_CHANNELSTATUS_STREAMING, 0)\n\t\tfa_SetChannelPaused(channel, False)\n\t\tFirst = False\n\t\tReturn\n\tEnd If\n\t\n\tLocal readpos:Int = fa_ChannelPosition(channel)\n\tLocal Write:Int = readpos + FRAG * 1 - writepos\n\tLocal frags:Int = Write \/ FRAG\n\t\n\tWhile frags > 0\n\t\tLocal Pos:Int = writepos Mod (FRAG * 8)\n\t\tFor Local f:Int = 0 Until FRAG\n\t\tbuffer[Pos + f] = GetAudio() * 30000\n\t\tNext\n\t\twritepos:+FRAG\n\t\tfrags:-1\n\tWend\nEnd Function\n'------------------------------------------------------------------------------------------\nFunction DrawWave()\n\tSetColor 255, 255, 255\n\tLocal prev% = Buff[0]\n\tFor Local i% = 0 Until N\n\t\tDrawRect(i, 150 + Buff[i] * 50, 2, 2)\n\t\tprev = Buff[i]\n\tNext\n\tDrawRect(0, 210, N, 1)\nEnd Function\n'------------------------------------------------------------------------------------------\nFunction DrawSpeccy()\n\tGlobal cp#[N]\n\tGlobal sp#[N]\n\tMemClear(Varptr cp[0], SizeOf(1#) * N)\n\tMemClear(Varptr sp[0], SizeOf(1#) * N)\n\tFor Local b% = 0 Until N \/ 4\n\t\tFor Local k% = 0 Until 256\n\t\t\tLocal a# = 2.0 * b * Pi * k \/ 256\n\t\t\tsp[b]:+Buff[k] * - 1 * Sine(a)\n\t\t\tcp[b]:+Buff[k] * Cosine(a)\n\t\tNext\n\tNext\n\tLocal prev# = 0\n\tFor Local i% = 1 Until N \/ 8\n\t\tLocal v# = (Sqr((sp[i] * sp[i]) + (cp[i] * cp[i])) \/ 64)\n\t\tDrawLine(i * 12, 500 - prev * 100, 12 + i * 12, 500 - v * 100)\n\t\tprev = v\n\tNext\nEnd Function\n\n\n\n\n\n\n\n\n\n'------------------------------------------------------------------------------------------\nFunction Sine:Double(x:Double) Inline\n\tReturn Sin(x \/ (Pi \/ 180.0))\nEnd Function\n'------------------------------------------------------------------------------------------\nFunction Cosine:Double(x:Double) Inline\n\tReturn Sine((3.1415926535897932 \/ 2.0) - x)\nEnd Function\n'------------------------------------------------------------------------------------------\nFunction Lerp:Float(a:Float, b:Float, x:Float)\n    Return a*(1-x)+b*x\nEnd Function\n'------------------------------------------------------------------------------------------\nFunction invLerp#(a#, b#, v#)\n    Return (v-a)\/(b-a)\nEnd Function\n'------------------------------------------------------------------------------------------\nType tSlider\n\tField x:Int, y:Int, w:Int, h:Int\n\tField val:Float = 0.5\n\tField Name$ = \"\"\n\t\n\tMethod New(x%, y%, w%, h%, Name$, defv# = 0.5)\n\t\tSelf.x = x\n\t\tSelf.y = y\n\t\tSelf.w = w\n\t\tSelf.h = h\n\t\tSelf.Name = Name\n\t\tval = defv\n\tEnd Method\n\t\n\tMethod MouseOver:Int(mx:Float, my:Float)\n\t\tReturn InsideRect(Mx, My, x, y, w, h)\n\tEnd Method\n\t\n\tMethod Update(mx:Float, my:Float)\n\t\tIf Not MouseOver(mx, my) Then Return\n\t\tIf Not MouseDown(1) Then Return\n\t\tLocal v:Float = Normalize(mx, 0, 1, x, x + w)\n\t\tval = Clamp(v, 0, 1)\n\tEnd Method\n\t\n\tMethod value#()\n\t\tReturn val ^ 2'0.3333\n\tEnd Method\n\t\n\tMethod Draw()\n\t\tSetColor 32, 32, 32\n\t\tDrawRect x, y, w, h\n\t\tSetColor 90, 64, 64\n\t\tDrawText(Left(val, 4), (x + w) \/ 2, y + 1)\n\t\tSetColor 255, 255, 255\n\t\tDrawRectHollow(x, y, w, h)\n\t\tLocal sv:Float = Normalize(val, x + 1, x + w - 1, 0, 1)\n\t\tSetColor 0, 255, 0\n\t\tDrawRect(sv, y, 2, h)\n\t\tDrawText(Name, x + w + 5, y)\n\tEnd Method\n\t\n\tFunction DrawRectHollow(x:Float, y:Float, w:Int, h:Int)\n\t\tDrawLine(x, y, x + w, y)\n\t\tDrawLine(x,y,x,y+h)\n\t\tDrawLine(x+w,y,x+w,y+h)\n\t\tDrawLine(x,y+h,x+w,y+h)\n\tEnd Function\n\t\n\tFunction InsideRect:Int(x:Float, y:Float, x2:Float, y2:Float, w:Float, h:Float)\n\t\tReturn _pointinrect(x, y, x2, y2, x2 + w, y2 + h)\n\tEnd Function\n\t\n\tFunction _pointinrect:Int(iPointX:Int, iPointY:Int, iXPos1:Int, iYPos1:Int, iXPos2:Int, iYPos2:Int)\n\t\tReturn  ((((iPointX-iXPos1) ~ (iPointX-iXPos2)) &amp; ((iPointY-iYPos1) ~ (iPointY-iYPos2))) &amp; $80000000)\n\tEnd Function\n\t\n\tFunction Normalize:Float(val:Float, desmin:Float, desmax:Float, natmin:Float, natmax:Float)\n\t\tReturn desmin + (val - natmin) * (desmax - desmin) \/ (natmax - natmin)\n\tEnd Function\n\t\n\tFunction Clamp:Float(x:Float, a:Float, b:Float)\n        If x &lt; a Then Return a\n        If x > b Then Return b\n        Return x\n\tEnd Function\nEnd Type\n\n\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Here is a simple example of how frequency modulation works in audio.The frequency of one tone (carrier) is altered with another oscillator (modulator). At high speeds, the resulting combination will bring out extra harmonics.There are no dependencies in the example.Play with the sliders and see how the different tones are generated. SuperStrict Framework brl.basic Import&#8230; <\/p>\n<div class=\"read-more navbutton\"><a href=\"https:\/\/www.kerneltrick.com\/?p=73\">Read More<i class=\"fa fa-angle-double-right\"><\/i><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21,6,1],"tags":[9,12,20,16],"class_list":["post-73","post","type-post","status-publish","format-standard","hentry","category-audio","category-programming","category-uncategorized","tag-blitzmax","tag-dsp","tag-dusty-old-project","tag-fft"],"_links":{"self":[{"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=\/wp\/v2\/posts\/73","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=73"}],"version-history":[{"count":0,"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=\/wp\/v2\/posts\/73\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=73"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=73"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kerneltrick.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=73"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}