<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://trebledj.me">
  <title>TrebledJ&#39;s Pages</title>
  <subtitle>TrebledJ&#39;s personal blog on programming, cybersecurity, music, and memes.</subtitle>
  <link href="https://trebledj.me/feeds/music.xml" rel="self"/>
  <link href="https://trebledj.me"/>
  <updated>2024-01-20T00:00:00Z</updated>
  <id>https://trebledj.me</id>
  <author>
    <name>TrebledJ</name>
    <email>trebledjjj@gmail.com</email>
  </author>
  
    
      
      <entry>
        <title>Relay</title>
        <description>Electronica on racing light. A variation on one of my older pieces.</description>
        <link href="https://trebledj.me/posts/relay/"/>
        <updated>2024-01-20T00:00:00Z</updated>
        <id>https://trebledj.me/posts/relay/</id>
        <content xml:lang="en" type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The people walking in darkness&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;have seen a great light;&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;on those living in the land of deep darkness&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;a light has dawned.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;– Isaiah 9:2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;This took a long while to make.&quot; href=&quot;https://trebledj.me/img/posts/music/15-relay/assets/relay-4864w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-100 &quot; src=&quot;https://trebledj.me/img/posts/music/15-relay/assets/relay-4864w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 4864 / 3328&quot; alt=&quot;Hand reaching out to a helping hand above.&quot; title=&quot;This took a long while to make.&quot; srcset=&quot;https://trebledj.me/img/posts/music/15-relay/assets/relay-256w.webp 256w, https://trebledj.me/img/posts/music/15-relay/assets/relay-512w.webp 512w, https://trebledj.me/img/posts/music/15-relay/assets/relay-1024w.webp 1024w, https://trebledj.me/img/posts/music/15-relay/assets/relay-4864w.webp 4864w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 4864px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What is a relay? A race—passing a baton from one to the next. The passing of packets by a router or a gateway server. Or used plainly as a verb without technicalities, a relay may simply mean to receive and pass on information.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/relay/#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s worth taking a moment to reflect: what are we relaying? As time passes, more responsibility falls on our shoulders—the responsibility to be helpful (or useful?) in society; the responsibility to mentor; the responsibility to work, to execute; the responsibility to lead.&lt;/p&gt;
&lt;p&gt;What are we relaying? What torch are we passing on? What is our &lt;em&gt;light&lt;/em&gt;? And what keeps us moving?&lt;/p&gt;
&lt;p&gt;The average human &lt;a href=&quot;https://www.gettysburg.edu/news/stories?id=79db7b34-630c-4f49-ad32-4ab9ea48e72b&quot;&gt;works 90,000 hours&lt;/a&gt;. There&#39;s only so much experience, wealth, and knowledge we can accrue.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Light the torch and guide us through the dark.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Shadows, dispelled by balls of flame.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Relay to us this bright white shining spark.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Ready, for the race to carry on.&lt;/em&gt;&lt;br /&gt;
&lt;sup&gt;&lt;em&gt;(Some words to go along with the climactic sections.)&lt;/em&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Similar to &lt;a href=&quot;https://trebledj.me/posts/remorse&quot;&gt;Remorse&lt;/a&gt;, Relay was featured as part of a challenge in the HKUST Firebird CTF 2024 competition, a competition where teams hunt for hidden pieces of text.&lt;/em&gt;&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;It might also (in my mind) be a play-on of &amp;quot;&lt;strong&gt;r&lt;/strong&gt;hythmic d&lt;strong&gt;elay&lt;/strong&gt;&amp;quot;. &lt;a href=&quot;https://trebledj.me/posts/relay/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>electronica</category>
        
          <category>synths</category>
        
          <category>dubsy-wubsy</category>
        
          <category>modal</category>
        
          <category>faith</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Digital Audio Synthesis for Dummies: Part 3</title>
        <description>Efficiently streaming audio to speakers on embedded systems (with examples in STM32).</description>
        <link href="https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/"/>
        <updated>2023-05-24T00:00:00Z</updated>
        <id>https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/</id>
        <content xml:lang="en" type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Slap a timer, DMA, and DAC together, and BAM—non-blocking audio output!&lt;/em&gt;&lt;br /&gt;
— TrebledJ, &lt;a href=&quot;https://trebledj.me/posts/stm32-midi-keyboard/&quot;&gt;2022&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ah… embedded systems—the intersection of robust hardware and versatile software.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Most embedded audio applications employ timers, DMA, and double buffering for great good!&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/round-table-500w.webp&quot;&gt;&lt;img class=&quot;rw float-right m-1 jw-40&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/round-table-500w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 500 / 604&quot; alt=&quot;Most embedded audio applications employ timers, DMA, and double buffering for great good!&quot; title=&quot;Most embedded audio applications employ timers, DMA, and double buffering for great good!&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/round-table-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/round-table-500w.webp 500w&quot; sizes=&quot;(max-width: 256px) 256px, 500px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is the third (and culminating) post in a series on &lt;a href=&quot;https://trebledj.me/tags/audio-synthesis-for-dummies/&quot;&gt;digital audio synthesis&lt;/a&gt;; but the first (and only?) post touching embedded hardware. In the &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1&quot;&gt;first post&lt;/a&gt;, we introduced basic concepts on audio processing. In the &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2&quot;&gt;second post&lt;/a&gt;, we dived into audio synthesis and generation. In this post, we’ll discover how to effectively implement an audio synthesiser and player on an embedded device by marrying hardware (timers, &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Digital-to-Analogue Converters; explained later!&quot;&gt;DACs&lt;/abbr&gt;, &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Direct Memory Access; explained later!&quot;&gt;DMA&lt;/abbr&gt;) and software (double buffering plus other optimisations).&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;To understand these concepts even better, we’ll look at examples on an &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;A family of 32-bit microcontrollers.&quot;&gt;STM32&lt;/abbr&gt;. These examples are inspired from a &lt;a href=&quot;https://trebledj.me/posts/stm32-midi-keyboard&quot;&gt;MIDI keyboard project&lt;/a&gt; I previously worked on.
I&#39;ll be using an STM32F405RGT board in the examples. If you plan to follow along with your own board, make sure it&#39;s capable of timer-triggered DMA and DAC. An oscilloscope would also be handy for checking DAC output.&lt;/p&gt;
&lt;div class=&quot;alert alert-secondary d-flex align-items-start&quot;&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;This post is much longer than I expected. My suggested approach of reading is to first gain a high-level understanding (possibly skipping the nitty gritty examples), then dig into the examples for details.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;timers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#timers&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Timers ⏰&lt;/h2&gt;
&lt;p&gt;It turns out kitchens and embedded systems aren’t that different after all! Both perform input and output, and both have timers! Who knew?&lt;/p&gt;
&lt;!-- Tick-Tock Croc, perhaps.^[I think it&#39;s safe to say that Tick-Tock Croc also performs input-output and has a timer between his eyes. So Tick-Tock isn&#39;t too different from a kitchen! Or an embedded controller, for that matter.] --&gt;
&lt;!-- &lt;a class=&quot;lightbox-single&quot; title=&quot;Tick tock likey embedded timers?&quot; href=&quot;/img/posts/programming/digital-audio-synthesis/assets/tick-tock-600w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-55&quot; src=&quot;/img/posts/programming/digital-audio-synthesis/assets/tick-tock-600w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 600 / 450&quot; alt=&quot;Meme with tick tock croc from Peter Pan preferring embedded timers over kitchen timers.&quot; title=&quot;Tick tock likey embedded timers?&quot; srcset=&quot;/img/posts/programming/digital-audio-synthesis/assets/tick-tock-256w.webp 256w, /img/posts/programming/digital-audio-synthesis/assets/tick-tock-512w.webp 512w, /img/posts/programming/digital-audio-synthesis/assets/tick-tock-600w.webp 600w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 600px&quot; /&gt;&lt;/a&gt; --&gt;
&lt;!-- &lt;br/&gt;   --&gt;
&lt;h3 id=&quot;tick-tock&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#tick-tock&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Tick Tock&lt;/h3&gt;
&lt;p&gt;Timers in embedded systems are similar to those in the kitchen: they tick for a period of time and signal an event when finished. However, embedded timers are much fancier than kitchen timers, making them immensely useful in various applications. They can trigger repeatedly (via auto-reload), count up/down, and be used to generate rectangular (PWM) waves.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Timers can be used to count at regular intervals.&quot; href=&quot;https://trebledj.me/img/timer-548w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-75&quot; src=&quot;https://trebledj.me/img/timer-548w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 548 / 306&quot; alt=&quot;Timers can be used to count at regular intervals.&quot; title=&quot;Timers can be used to count at regular intervals.&quot; srcset=&quot;https://trebledj.me/img/timer-256w.webp 256w, https://trebledj.me/img/timer-512w.webp 512w, https://trebledj.me/img/timer-548w.webp 548w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 548px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Timers have various applications, such as to count signals. (Source: EmbeddedTutor&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn2&quot; id=&quot;fnref2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;)&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;So what makes timers tick?&lt;/p&gt;
&lt;p&gt;The &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Microcontroller Unit. No, not the Marvel Cinematic Universe!&quot;&gt;MCU&lt;/abbr&gt; clock!&lt;/p&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-bolt ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;The MCU clock is the &lt;em&gt;backbone&lt;/em&gt; of a controller. It controls the processing speed and pretty much everything!—timers, ADC, DAC, communication protocols, and whatnot. The signal itself is generated by an oscillator, typically a Quartz &lt;a href=&quot;https://www.electronics-tutorials.ws/oscillator/crystal.html&quot;&gt;crystal oscillator&lt;/a&gt; which is capable of generating high, stable, self-sustaining frequencies.&lt;/p&gt;
&lt;p&gt;The clock runs at a fixed frequency (168MHz on our board).
By dividing against it, we can achieve lower frequencies.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;&quot; href=&quot;https://trebledj.me/img/prescaler-420w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-100 &quot; src=&quot;https://trebledj.me/img/prescaler-420w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 420 / 119&quot; alt=&quot;undefined&quot; title=&quot;undefined&quot; srcset=&quot;https://trebledj.me/img/prescaler-256w.webp 256w, https://trebledj.me/img/prescaler-420w.webp 420w&quot; sizes=&quot;(max-width: 256px) 256px, 420px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;By using different prescalers, we can scale down the frequency according to our needs. (Source: EmbeddedTutor&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn2&quot; id=&quot;fnref2:1&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;)&lt;/sup&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The following diagram illustrates how the clock signal is divided on an STM. There are two divisors: the prescaler and auto-reload (aka counter period).&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Timing diagram of timer signal derived from a clock signal. We begin with the clock signal, which is divided at multiple points: first divided by the prescaler, then by the auto-reload.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/timing-diagram-1024w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-85&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/timing-diagram-1024w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1024 / 487&quot; alt=&quot;Timing diagram of timer signal derived from a clock signal. We begin with the clock signal, which is divided at multiple points: first divided by the prescaler, then by the auto-reload.&quot; title=&quot;Timing diagram of timer signal derived from a clock signal. We begin with the clock signal, which is divided at multiple points: first divided by the prescaler, then by the auto-reload.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/timing-diagram-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/timing-diagram-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/timing-diagram-1024w.webp 1024w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1024px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;How a timer frequency is derived from the clock signal. (Diagram adapted from uPesy.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn3&quot; id=&quot;fnref3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;)&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Here, the clock signal is first divided by a prescaler of 2, then further &amp;quot;divided&amp;quot; by an auto-reload of 6. On every overflow (arrow shooting up), the timer triggers an &lt;em&gt;interrupt&lt;/em&gt;. In this case, the timer runs at $&#92;frac{1}{12}$ the speed of the clock.&lt;/p&gt;
&lt;p&gt;These interrupts can trigger functionality such as DMA transfers (explored later) and ADC conversions.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn4&quot; id=&quot;fnref4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;
Heck, they can even be used to trigger other timers!&lt;/p&gt;
&lt;p&gt;Further Reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.upesy.com/blogs/tutorials/how-works-timers-in-micro-controllers&quot;&gt;How do microcontroller timers work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digikey.com/en/maker/projects/getting-started-with-stm32-timers-and-timer-interrupts/d08e6493cefa486fb1e79c43c0b08cc6&quot;&gt;Getting Started with STM32: Timers and Timer Interrupts&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;There are more prescalers behind the scenes! (APB2)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;example-initialising-the-timer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-initialising-the-timer&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Example: Initialising the Timer&lt;/h3&gt;
&lt;p&gt;Suppose we want to send a stream of audio output. We can use a timer with a frequency set to our desired &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1/#sampling&quot;&gt;sample rate&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We can derive the prescaler (PSC) and auto-reload (ARR) by finding integer factors that satisfy the following relationship.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;timer-relationship&quot;&gt;&lt;/a&gt;
$$
&#92;text{freq}_&#92;text{timer} = &#92;frac{&#92;text{freq}_&#92;text{clock}}{(&#92;text{PSC} + 1) &#92;times (&#92;text{ARR} + 1)}
$$&lt;/p&gt;
&lt;p&gt;where $&#92;text{freq}_&#92;text{timer}$ is the timer frequency (or specifically in our case, the sample rate), $&#92;text{freq}_&#92;text{clock}$ is the clock frequency.&lt;/p&gt;
&lt;p&gt;On our STM32F405, we configured $&#92;text{freq}_&#92;text{clock}$ to the maximum possible speed: 168MHz. If we’re aiming for an output sample rate of 42,000Hz, we’d need to divide our clock signal by 4,000, so that we correctly get $&#92;frac{168,000,000}{4,000} = 42,&#92;!000$. For now, we’ll choose register values of &lt;code&gt;PSC = 0&lt;/code&gt; and &lt;code&gt;ARR = 3999&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-bolt ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;Why do we add $+1$ to the PSC and ARR in the relationship above?&lt;/p&gt;
&lt;p&gt;On the STM32F4, PSC and ARR are 16-bit &lt;em&gt;registers&lt;/em&gt;, meaning they range from 0 to 65,535.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn5&quot; id=&quot;fnref5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;
To save space and enhance program correctness, we assign meaningful behaviour to the value 0.&lt;/p&gt;
&lt;p&gt;So in this page, when we say &lt;code&gt;PSC = 0&lt;/code&gt;, we actually mean a prescaler divisor of 1.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-bolt ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;Why &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;3999&lt;/code&gt; specifically?&lt;/p&gt;
&lt;p&gt;Other pairs of PSC and ARR can also work. We can &lt;em&gt;choose&lt;/em&gt; any PSC and ARR which get us to our desired timer frequency. Play around and try different pairs of PSC and ARR!&lt;/p&gt;
&lt;p&gt;Exercises for the reader:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is the difference between different pairs, such as &lt;code&gt;PSC = 0&lt;/code&gt;, &lt;code&gt;ARR = 3999&lt;/code&gt; vs. &lt;code&gt;PSC = 1&lt;/code&gt;, &lt;code&gt;ARR = 1999&lt;/code&gt;? (Hint: &lt;span class=&quot;spoiler&quot; tabindex=&quot;0&quot;&gt;counter&lt;/span&gt;.)&lt;/li&gt;
&lt;li&gt;Is there a PSC/ARR pair that is &amp;quot;better&amp;quot;?&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn6&quot; id=&quot;fnref6&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We can use &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;a GUI for configuring STM hardware&quot;&gt;STM32 CubeMX&lt;/abbr&gt; to initialise timer parameters. CubeMX allows us to generate code from these options, handling the conundrum of modifying the appropriate registers.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Timer settings from CubeMX.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-1-2278w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-85&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-1-2278w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 2278 / 1288&quot; alt=&quot;Timer settings from CubeMX.&quot; title=&quot;Timer settings from CubeMX.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-1-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-1-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-1-1024w.webp 1024w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-1-2278w.webp 2278w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 2278px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;In CubeMX, we first select a timer on the left. We then enable a channel (here Channel 4) to generate PWM.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn7&quot; id=&quot;fnref7&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; We also set the prescaler and auto-reload so that our timer frequency is 42,000Hz.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;More timer settings from CubeMX.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-2-raw-1716w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-65&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-2-raw-1716w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1716 / 784&quot; alt=&quot;More timer settings from CubeMX.&quot; title=&quot;More timer settings from CubeMX.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-2-raw-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-2-raw-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-2-raw-1024w.webp 1024w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-timer-2-raw-1716w.webp 1716w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1716px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Some other settings in CubeMX to check.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Remember to generate code once done.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn9&quot; id=&quot;fnref9&quot;&gt;9&lt;/a&gt;&lt;/sup&gt; CubeMX should generate the following code in &lt;code&gt;main.c&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MX_TIM8_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// --snip-- Initialise structs. --snip--&lt;/span&gt;

    htim8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Instance               &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TIM8&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    htim8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Init&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Prescaler         &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    htim8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Init&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CounterMode       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TIM_COUNTERMODE_UP&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    htim8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Init&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Period            &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    htim8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Init&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ClockDivision     &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TIM_CLOCKDIVISION_DIV1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    htim8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Init&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RepetitionCounter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    htim8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Init&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AutoReloadPreload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TIM_AUTORELOAD_PRELOAD_DISABLE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HAL_TIM_Base_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;htim8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; HAL_OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Error_Handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// --snip-- Initialise the clock source. --snip--&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HAL_TIM_PWM_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;htim8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; HAL_OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Error_Handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// --snip-- Initialise other things. --snip--&lt;/span&gt;
    
    &lt;span class=&quot;token function&quot;&gt;HAL_TIM_MspPostInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;htim8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;After initialisation, it&#39;s possible to change the timer frequency by setting the prescaler and auto-reload registers like so:&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;TIM8&lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt;PSC &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;// Prescaler: 1&lt;/span&gt;
TIM8&lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt;ARR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3999&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Auto-Reload: 4000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This is useful for applications where the frequency is dynamic (e.g. playing music with a piezoelectric buzzer), but it&#39;s also useful when we&#39;re too lazy to modify the .ioc file.&lt;/p&gt;
&lt;h3 id=&quot;example-playing-with-timers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-playing-with-timers&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Example: Playing with Timers&lt;/h3&gt;
&lt;p&gt;STM’s HAL library provides ready-made functions to interface with hardware.&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;HAL_TIM_Base_Start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;htim8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Start the timer.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;HAL_TIM_Base_Stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;htim8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Stop the timer.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;These functions are used to start/stop timers for basic timing and counting applications.
Functions for more specialised modes (e.g. PWM) are available in &lt;code&gt;stm32f4xx_hal_tim.h&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;digital-to-analogue-converters-dacs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#digital-to-analogue-converters-dacs&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Digital-to-Analogue Converters (DACs) 🌉&lt;/h2&gt;
&lt;p&gt;Let&#39;s delve into our second topic today: digital-to-analogue converters (DACs).&lt;/p&gt;
&lt;p&gt;Audio comes in several forms: sound waves, electrical voltages, and binary data.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Tolkien&#39;s world looks nothing like the three realms here.&quot; href=&quot;https://trebledj.me/img/CPT-Sound-ADC-DAC-1024w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-85&quot; src=&quot;https://trebledj.me/img/CPT-Sound-ADC-DAC-1011w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1011 / 348&quot; alt=&quot;Image showing how audio is represented in the analogue, electronic, and digital worlds.&quot; title=&quot;Tolkien&#39;s world looks nothing like the three realms here.&quot; srcset=&quot;https://trebledj.me/img/CPT-Sound-ADC-DAC-256w.webp 256w, https://trebledj.me/img/CPT-Sound-ADC-DAC-512w.webp 512w, https://trebledj.me/img/CPT-Sound-ADC-DAC-1011w.webp 1011w, https://trebledj.me/img/CPT-Sound-ADC-DAC-1024w.webp 1024w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1011px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Audio manifests in various forms. DACs transform our signal from the digital realm to the analogue world. (Source: Pluke, &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/3.0&quot;&gt;CC BY-SA 3.0&lt;/a&gt;, via Wikimedia Commons.)&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Since representations vastly differ, hence the need for interfaces to bridge the worlds. Between the digital and analogue realms, we have DACs and &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Analogue-to-Digital Converters&quot;&gt;ADCs&lt;/abbr&gt; as mediators. Generally, DACs are used for output while ADCs are for input.&lt;/p&gt;
&lt;h3 id=&quot;a-closer-look-at-dacs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#a-closer-look-at-dacs&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; A Closer Look at DACs&lt;/h3&gt;
&lt;p&gt;Remember &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1#sampling&quot;&gt;sampling&lt;/a&gt;? We took a continuous analogue signal and selected discrete points at regular intervals. An ADC is like a glorified sampler.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Free samples have returned!&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/sampling-800w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-85&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/sampling-800w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 800 / 400&quot; alt=&quot;Diagram sampling a sine wave at different frequencies (50 Hertz, 30 Hertz, 10 Hertz). There are more dots at higher frequencies.&quot; title=&quot;Free samples have returned!&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/sampling-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/sampling-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/sampling-800w.webp 800w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 800px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While ADCs take us from continuous to discrete, DACs (try to) take us from discrete to continuous. The shape of the resulting analogue waveform depends on the DAC implementation. Simple DACs will stagger the output at discrete levels. More complex DACs may interpolate between two discrete samples to “guess” the intermediate values. Some of these guesses will be off, but at least the signal is smoother.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Free samples have returned!&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/reconstruction-800w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-85&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/reconstruction-800w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 800 / 400&quot; alt=&quot;Another sampling diagram, but lines are drawn between dots, like staircases. This emulates how analogue signals are reconstructed from digital representations.&quot; title=&quot;Free samples have returned!&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/reconstruction-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/reconstruction-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/reconstruction-800w.webp 800w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 800px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;On our STM board, signal reconstruction is staggered, like old platformer games—not that I&#39;ve played any. At higher sampling rates, the staggered-ness is less apparent and the resulting curve is smoother.&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id=&quot;example-initialising-the-dac&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-initialising-the-dac&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Example: Initialising the DAC&lt;/h3&gt;
&lt;p&gt;Let’s return to CubeMX to set up our DAC.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;DAC settings from CubeMX.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-1-2280w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-85&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-1-2280w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 2280 / 1104&quot; alt=&quot;DAC settings from CubeMX.&quot; title=&quot;DAC settings from CubeMX.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-1-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-1-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-1-1024w.webp 1024w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-1-2280w.webp 2280w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 2280px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Enable DAC, and connect it to Timer 8 using the trigger setting. Our STM32F405 board supports two DAC output channels. This is useful if we want stereo audio output.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;DAC DMA settings from CubeMX.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-2-1728w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-65&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-2-1728w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1728 / 796&quot; alt=&quot;DAC DMA settings from CubeMX.&quot; title=&quot;DAC DMA settings from CubeMX.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-2-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-2-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-2-1024w.webp 1024w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-2-1728w.webp 1728w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1728px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Configure DMA settings for the DAC. We’ll cover DMA later.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Enable DAC DMA interrupts.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-3-1726w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-65&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-3-1726w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1726 / 410&quot; alt=&quot;Enable DAC DMA interrupts.&quot; title=&quot;Enable DAC DMA interrupts.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-3-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-3-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-3-1024w.webp 1024w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-cubemx-dac-3-1726w.webp 1726w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1726px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Enable interrupts for the DMA. These are needed to trigger DAC sends.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Again, remember to generate code when finished.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn9&quot; id=&quot;fnref9:1&quot;&gt;9&lt;/a&gt;&lt;/sup&gt; The &lt;code&gt;MX_DAC_Init()&lt;/code&gt; function should contain the generated DAC setup code and should already be called in &lt;code&gt;main()&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;example-using-the-dac&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-using-the-dac&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Example: Using the DAC&lt;/h3&gt;
&lt;p&gt;On our STM32, DAC accepts samples &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1#quantisation&quot;&gt;quantised&lt;/a&gt; to 8 bits or 12 bits.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn10&quot; id=&quot;fnref10&quot;&gt;10&lt;/a&gt;&lt;/sup&gt; We’ll go with superior resolution: 12 bits!&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Three options for DAC alignment are offered.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-dac-alignment-1024w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-65&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-dac-alignment-1024w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1024 / 287&quot; alt=&quot;Three options for DAC alignment are offered.&quot; title=&quot;Three options for DAC alignment are offered.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-dac-alignment-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-dac-alignment-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/stm32-dac-alignment-1024w.webp 1024w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1024px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;STM32 offers three different options to quantise and align DAC samples. We’ll only focus on the last option: 12-bit right aligned samples. (Source: RM0090 Reference Manual.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn8&quot; id=&quot;fnref8:1&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;)&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;For simplicity, let’s start with sending 1 DAC sample. This can be done like so:&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Start the DAC peripheral.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;HAL_DAC_Start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hdac&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_CHANNEL_1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Set the DAC value to 1024 on Channel 1, 12-bit right-aligned.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;HAL_DAC_SetValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hdac&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_CHANNEL_1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_ALIGN_12B_R&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This should output a voltage level of $&#92;frac{1024}{2^{12}} = 25&#92;%$ of the reference voltage $V_{&#92;text{REF}}$. Once it starts, the DAC will continue sending that voltage out until we change the DAC value or call &lt;code&gt;HAL_DAC_Stop()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;DAC_CHANNEL_1&lt;/code&gt; to select the first channel, and use &lt;code&gt;DAC_ALIGN_12B_R&lt;/code&gt; to accept 12-bit right-aligned samples.&lt;/p&gt;
&lt;p&gt;To fire a continuous stream of samples, we could use a loop and call &lt;code&gt;HAL_DAC_SetValue()&lt;/code&gt; repeatedly. Let’s use this method to generate a simple square wave.&lt;/p&gt;
&lt;div class=&quot;alert alert-warning d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-triangle-exclamation ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;An aside. The default &lt;code&gt;HAL_Delay()&lt;/code&gt; provided by STM will add 1ms to the delay time—well, at least in my version. I overrode it using a separate definition so that it sleeps the given number of ms.&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;HAL_Delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; ms&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;HAL_GetTick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HAL_GetTick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; ms&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;HAL_DAC_Start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hdac&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_CHANNEL_1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Alternate between high (4095) and low (0).&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt; high  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;uint16_t&lt;/span&gt; sample &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;high &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4095&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// max = 4095 = 2^12 - 1.&lt;/span&gt;
    high &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;HAL_DAC_SetValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hdac&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_CHANNEL_1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_ALIGN_12B_R&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sample&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Delay for 5ms.&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;HAL_Delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This generates a square wave with a period of 10ms, for a frequency of 100Hz.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;A square wave at 100Hz.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-square-wave-1024w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-75&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-square-wave-1024w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1024 / 768&quot; alt=&quot;A square wave at 100Hz.&quot; title=&quot;A square wave at 100Hz.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-square-wave-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-square-wave-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-square-wave-1024w.webp 1024w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1024px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Oscilloscope view of the signal. Oscilloscopes are very useful for debugging signals, especially periodic ones.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;But there are two issues with this looping method:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using a while loop blocks the thread, meaning we block the processor from doing other things while outputting the sine wave. We may wish to poll for input or send out other forms of output (TFT/LCD, Bluetooth, etc.).&lt;/li&gt;
&lt;li&gt;Since &lt;code&gt;HAL_Delay()&lt;/code&gt; delays in milliseconds, it becomes impossible to generate complex waveforms at high frequencies, since that requires us to send samples at &lt;strong&gt;microsecond&lt;/strong&gt; intervals.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;HAL Delay, y u no faster?&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/y-u-no-faster-500w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-45&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/y-u-no-faster-500w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 500 / 633&quot; alt=&quot;HAL Delay, y u no faster?&quot; title=&quot;HAL Delay, y u no faster?&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/y-u-no-faster-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/y-u-no-faster-500w.webp 500w&quot; sizes=&quot;(max-width: 256px) 256px, 500px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the next section, we’ll address these issues by combining DAC with timers and DMA.&lt;/p&gt;
&lt;p&gt;Further Reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://deepbluembedded.com/stm32-dac-tutorial-example-hal-code-analog-signal-genreation&quot;&gt;Deep Blue Embedded: STM32 DAC Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;direct-memory-access-dma&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#direct-memory-access-dma&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Direct Memory Access (DMA) 💉🧠&lt;/h2&gt;
&lt;p&gt;The final item on our agenda today! Direct Memory Access (DMA) may seem like three random words strung together, but it’s quite a powerful tool in the embedded programmer’s arsenal. How, you ask?&lt;/p&gt;
&lt;div class=&quot;alert alert-success d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-lightbulb ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;&lt;strong&gt;DMA enables data transfer without consuming processor resources.&lt;/strong&gt; (Well, it consumes some resources, but mainly for setup.) This frees up the processor to do other things while DMA takes care of moving data. We could use this saved time to prepare the next set of buffers, render the GUI, etc.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;DMA can be used to transfer data from memory-to-peripheral (e.g. DAC, &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;A common asynchronous communication protocol in the embedded world.&quot;&gt;UART&lt;/abbr&gt; &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;transfer&quot;&gt;TX&lt;/abbr&gt;, SPI TX), from peripheral-to-memory (e.g. ADC, UART &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;receive&quot;&gt;RX&lt;/abbr&gt;), across peripherals, or across memory. In this post, we&#39;re concerned with one particular memory-to-peripheral transfer: DAC.&lt;/p&gt;
&lt;p&gt;Further Reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/cs/dma-controllers&quot;&gt;Baeldung: How Do DMA Controllers Work?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;example-dma-with-single-buffering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-dma-with-single-buffering&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Example: DMA with Single Buffering&lt;/h3&gt;
&lt;p&gt;We&#39;ll now try using DMA with a single buffer, see why this is problematic, and motivate the need for double buffering.
If you’ve read this far, I presume you’ve followed the &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-initialising-the-dac&quot;&gt;previous section&lt;/a&gt; by initialising DMA and generating code with CubeMX.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Single buffers... forever alone.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/single-buffer-500w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-50&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/single-buffer-500w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 500 / 500&quot; alt=&quot;Single buffers... forever alone.&quot; title=&quot;Single buffers... forever alone.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/single-buffer-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/single-buffer-500w.webp 500w&quot; sizes=&quot;(max-width: 256px) 256px, 500px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;alert alert-warning d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-triangle-exclamation ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;DMA introduces syncing issues. After preparing a second round of buffers, how do we know if the first round has already finished?&lt;/p&gt;
&lt;p&gt;As with all processes which depend on a separate event, there are two approaches: &lt;strong&gt;polling&lt;/strong&gt; and &lt;strong&gt;interrupts&lt;/strong&gt;. In this context:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Polling&lt;/strong&gt;: Block and wait until the first round is finished, then send.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interrupts&lt;/strong&gt;: Trigger an interrupt signal when transfer finishes, and start the next round inside the interrupt handler.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which approach to choose depends on your application.&lt;/p&gt;
&lt;p&gt;In our examples, we’ll poll to check if DMA is finished:&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HAL_DAC_GetState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hdac&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; HAL_DAC_STATE_READY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With DMA, we’ll first need to &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#buffering&quot;&gt;buffer&lt;/a&gt; an array of samples. Our loop will run like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Buffer samples.&lt;/li&gt;
&lt;li&gt;Wait for DMA to be ready.&lt;/li&gt;
&lt;li&gt;Start the DMA.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do you notice a flaw in this approach? After starting DMA, we start buffering samples on the next iteration. We risk overwriting the buffer while it’s being sent.&lt;/p&gt;
&lt;p&gt;Let’s try to implement it anyway and play a simple 440Hz sine wave.&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;math.h&amp;gt;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// M_PI, sin&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;SAMPLE_RATE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;42000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;BUFFER_SIZE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;FREQUENCY&lt;/span&gt;   &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;440&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;uint16_t&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Time (in samples).&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Start the timer.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;HAL_TIM_Base_Start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;htim8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Prep the buffer.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; t&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; val &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; M_PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; FREQUENCY &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2047&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; val &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2047&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Scale the value from [-1, 1] to [0, 2^12-1).&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Wait for DAC to be ready, so that the buffer can be modified on the next iteration.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HAL_DAC_GetState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hdac&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; HAL_DAC_STATE_READY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Start the DMA.&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;HAL_DAC_Start_DMA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hdac&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_CHANNEL_1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DAC_ALIGN_12B_R&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The results? As expected, pesky little &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;glitches, disruptions&quot;&gt;artefacts&lt;/abbr&gt; invade our signal since our buffer is updated during DMA transfer. This may result in &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1#clicks&quot;&gt;unpleasant clicks from our speaker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Artefacts distort the signal, resulting in occasional clips and sound defects.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-glitch-768w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-75&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-glitch-768w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 768 / 576&quot; alt=&quot;Artefacts distort the signal, resulting in occasional clips and sound defects.&quot; title=&quot;Artefacts distort the signal, resulting in occasional clips and sound defects.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-glitch-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-glitch-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-glitch-768w.webp 768w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 768px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Prep, wait, start, repeat. Artefacts distort the signal from time to time.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;But what if we prep, then start, then wait? This way, the buffer won&#39;t be overwritten; but this causes the signal to stall while prepping.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn11&quot; id=&quot;fnref11&quot;&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;stall-img&quot;&gt;&lt;/a&gt;
&lt;a class=&quot;lightbox-single&quot; title=&quot;Oscilloscope of sine wave with stalls (horizontal breaks with no change).&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-stall-1024w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-75&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-stall-1024w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1024 / 768&quot; alt=&quot;Oscilloscope of sine wave with stalls (horizontal breaks with no change).&quot; title=&quot;Oscilloscope of sine wave with stalls (horizontal breaks with no change).&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-stall-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-stall-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-stall-1024w.webp 1024w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1024px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Prep, start, wait, repeat. The signal stalls (shown by horizontal lines) because the DAC isn’t updated while buffering.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;To resolve these issues, we&#39;ll unleash the final weapon in our arsenal.&lt;/p&gt;
&lt;h3 id=&quot;example-dma-with-double-buffering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-dma-with-double-buffering&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Example: DMA with Double Buffering&lt;/h3&gt;
&lt;p&gt;We saw previously how a single buffer spectacularly fails to deal with &amp;quot;concurrent&amp;quot; buffering.
With double buffering, we introduce an additional buffer. While one buffer is being displayed/streamed, the other buffer is updated. This ensures our audio can be delivered in one continuous stream.&lt;/p&gt;
&lt;p&gt;In code, we’ll add another buffer by declaring &lt;code&gt;uint16_t[2][BUFFER_SIZE]&lt;/code&gt; instead of &lt;code&gt;uint16_t[BUFFER_SIZE]&lt;/code&gt;. We’ll also declare a variable &lt;code&gt;curr&lt;/code&gt; (0 or 1) to index which buffer is currently available.&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;uint16_t&lt;/span&gt; buffers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// New: add a second buffer.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt; curr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                 &lt;span class=&quot;token comment&quot;&gt;// Index of current buffer.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; t   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Start the timer.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;HAL_TIM_Base_Start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;htim8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;uint16_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;curr&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Get the buffer being written.&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// --snip-- Same as before...&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Prep the buffer.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Wait for DAC to be ready.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Start the DMA.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// --snip--&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Point to the other buffer, so that we&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// prepare it while the previous one&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// is being sent.&lt;/span&gt;
    curr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;curr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Now our 440Hz sine wave is unblemished!&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Pure sine goodness. A proper 440Hz sine rendered on our oscilloscope.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-2-1024w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-75&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-2-1024w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1024 / 768&quot; alt=&quot;Pure sine goodness. A proper 440Hz sine rendered on our oscilloscope.&quot; title=&quot;Pure sine goodness. A proper 440Hz sine rendered on our oscilloscope.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-2-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-2-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-sine-440-2-1024w.webp 1024w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1024px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Waveform of a pure 440Hz sine tone.&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-bolt ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;Double buffering is also used for video and displays, where each buffer stores a 2D frame instead of a 1D signal.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;example-playing-multiple-notes-with-dma-and-double-buffering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-playing-multiple-notes-with-dma-and-double-buffering&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Example: Playing Multiple Notes with DMA and Double Buffering 🎶&lt;/h3&gt;
&lt;p&gt;With some minor changes, we can make our device generate audio for multiple notes. Let’s go ahead and play an A major chord!&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Prep the buffer.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;uint16_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;curr&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; t&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Compute value for each note.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; M_PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;440&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; cs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; M_PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;554.37&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; e &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; M_PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;659.25&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; val &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; cs &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Sum and normalise to [-1, 1].&lt;/span&gt;
    buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2047&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; val &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2047&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Map [-1, 1] to [0, 2^12-1).&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;If you flash the above code and feed the output to an oscilloscope, you may find it doesn’t really work. Our signal &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#stall-img&quot;&gt;stalls&lt;/a&gt;, for similar reasons as before.&lt;/p&gt;
&lt;div class=&quot;alert alert-warning d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-triangle-exclamation ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;Even with DMA, stalls may occur. This is usually a sign that buffering (and other processes) consume too much time. In this case, breaks in the data occur—the stream is no longer continuous, because the buffer doesn&#39;t finish prepping on time.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;optimisations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#optimisations&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Optimisations 🏎&lt;/h3&gt;
&lt;p&gt;So our code is slow. How do we speed it up?&lt;/p&gt;
&lt;p&gt;Here are a few common tricks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Precompute constants&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Instead of computing &lt;code&gt;2 * M_PI * FREQUENCY / SAMPLE_RATE&lt;/code&gt; every iteration, we can precompute it before the loop, saving many arithmetic instructions.&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Precompute a factor of the 440Hz signal.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; two_pi_f_over_sr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; M_PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; FREQUENCY &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Prep the buffer.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;uint16_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;curr&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; t&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Use the precomputed value...&lt;/span&gt;
        buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2047&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;two_pi_f_over_sr &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2047&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#wavetable-synthesis&quot;&gt;&lt;strong&gt;Wavetable synthesis&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Math functions such as &lt;code&gt;sin&lt;/code&gt; can be computationally expensive, especially when used a lot. By caching the waveform in a lookup table, we can speed up the process of computing samples.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Increase the buffer size&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;By increasing the buffer size, we spend less overhead switching between tasks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Decrease the sample rate&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If all else fails, we can decrease the load by compromising the sample rate, say from 42000Hz to 21000Hz. With a buffer size of 1024, that means we’ve gone from a constraint of $&#92;frac{1,024}{42,000} = 24.4$ms to $&#92;frac{1,024}{21,000} = 48.8$ms per buffer.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To avoid complicating things, I lowered the sample rate to 21000Hz. This means changing the auto-reload register to 7999, so that our timer frequency is $$&#92;frac{168,000,000}{(0 + 1) &#92;times (7,999 + 1)} = 21,&#92;!000&#92;text{Hz.}$$&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;TIM8&lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt;ARR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7999&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;After all this hassle, we get a beautiful chord.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;The curves are mesmerising.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-a-major-1024w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-75&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-a-major-1024w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1024 / 768&quot; alt=&quot;Picture of oscilloscope showing A major.&quot; title=&quot;The curves are mesmerising.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-a-major-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-a-major-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/osc-a-major-1024w.webp 1024w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1024px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;A nifty waveform of an A major chord (440Hz + 554.37Hz + 659.25Hz).&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;recap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#recap&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Recap 🔁&lt;/h2&gt;
&lt;p&gt;By utilising both hardware and software, we reap the benefits of parallel processing while implementing an efficient, robust audio application. On the hardware side, we explored:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#timers&quot;&gt;Timers&lt;/a&gt;, which are an useful and inexpensive way to trigger actions at regular intervals.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#digital-to-analogue-converters-dacs&quot;&gt;DACs&lt;/a&gt;, which enable us to communicate with a speaker by translating digital samples into analogue signals.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#direct-memory-access-dma&quot;&gt;DMA&lt;/a&gt;, which enables data transfer with minimal processor resources. This way, we can process other things while streaming audio.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In software, we explored:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#example-dma-with-double-buffering&quot;&gt;Double buffering&lt;/a&gt;, a software technique for buffering data to achieve continuous or faster output.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#optimisations&quot;&gt;Various optimisations&lt;/a&gt;, which enable us to squeeze more processing into our tiny board.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When combined, we save processing resources, which can possibly be spent on additional features.&lt;/p&gt;
&lt;p&gt;In case you want to go further, here are some other things to explore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generating stereo audio. We’ve generated audio for Channel 1. What about stereo audio for Channel 2? If you’re using reverb effects and wish for a fuller stereo sound, you’ll need an extra pair of buffers (and more processing!).&lt;/li&gt;
&lt;li&gt;Streaming via UART (+ DMA).&lt;/li&gt;
&lt;li&gt;Using &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Single Instruction, Multiple Data&quot;&gt;SIMD&lt;/abbr&gt; instructions to buffer two (or more?) samples at a time.
&lt;ul&gt;
&lt;li&gt;Other assembly-level bit-hacking tricks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Real-Time Operating System&quot;&gt;RTOS&lt;/abbr&gt; for multitasking.&lt;/li&gt;
&lt;li&gt;Other boards or hardware with specialised audio features.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hope you enjoyed this series of posts! Leave a comment if you like to see more or have any feedback!&lt;/p&gt;
&lt;h2 id=&quot;full-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#full-code&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Full Code&lt;/h2&gt;
&lt;p&gt;The complete code for DMA with double buffering has been uploaded as a &lt;a href=&quot;https://gist.github.com/TrebledJ/5c45ba3366918352a3d56625a636bafa&quot;&gt;GitHub Gist&lt;/a&gt;. It hasn&#39;t been fully optimised yet. I&#39;ll leave that as an exercise for the reader.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Each of these components (especially hardware) deserve their own post to be properly introduced; but for the sake of keeping this post short, I’ll only introduce them briefly and link to other resources for further perusal. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.embeddedtutor.com/2019/02/timercounter-in-embedded-system.html&quot;&gt;Timer/Counter in Embedded System&lt;/a&gt; &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt; &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref2:1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.upesy.com/blogs/tutorials/how-works-timers-in-micro-controllers&quot;&gt;How do microcontroller timers work?&lt;/a&gt; – A decent article on timers. Diagrams are in French though. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;The extent of timer events depends on hardware support. Timers can do a lot on ST boards. For other brands, you may need to check the datasheet or reference manual. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Some other timers have 32-bit ARR registers. But eh, we can achieve a lot with just 16-bit ones. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn6&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;What is the difference between pairs of prescaler/auto-reload, such as &lt;code&gt;PSC = 0&lt;/code&gt;, &lt;code&gt;ARR = 3999&lt;/code&gt; vs. &lt;code&gt;PSC = 1&lt;/code&gt;, &lt;code&gt;ARR = 1999&lt;/code&gt;? &lt;br /&gt; Indeed, given a fixed clock frequency, the same timer frequency will be generated (since the divisor is the same: 2000). However, the difference lies in the counter. Recall each step of auto-reload equals a step of the counter. &lt;br /&gt; The counter is used in calculating the on-time (or duty cycle). By using a &lt;em&gt;higher&lt;/em&gt; &lt;code&gt;ARR&lt;/code&gt;, we gain a &lt;em&gt;higher resolution&lt;/em&gt; in the counter, which allows us to say, control servos with finer granularity. Thus, a lower prescaler is often preferred. &lt;br /&gt; Of course, different vendors may implement timers differently or have different features attached to timer peripherals. Other considerations may come into play, depending on the vendor and your application. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref6&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn7&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;We chose Timer 8 (with Channel 4) because it&#39;s an advanced control timer (a beefy boi!), capable of a lot, though probably overkill for our simple examples. The timer and channel you use depends on your STM board and model. If you’re following along with this post, make sure to choose a timer which has DMA generation. When in doubt, refer to the reference manual.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fn8&quot; id=&quot;fnref8&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref7&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn8&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.st.com/resource/en/reference_manual/rm0090-stm32f405415-stm32f407417-stm32f427437-and-stm32f429439-advanced-armbased-32bit-mcus-stmicroelectronics.pdf&quot;&gt;STM&#39;s Official Reference Manual for F405/F415, F407/F417, F427/F437, F429/F439 boards&lt;/a&gt;. Definitely something to refer to if you’re working on one of those boards. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref8&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt; &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref8:1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn9&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;In CubeMX, you can generate code by choosing the &lt;em&gt;Project&lt;/em&gt; &amp;gt; &lt;em&gt;Generate Code&lt;/em&gt; menu option. When coding, keep in mind that only code between &lt;code&gt;USER CODE BEGIN&lt;/code&gt; and &lt;code&gt;USER CODE END&lt;/code&gt; comments will be preserved by ST&#39;s code generator. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref9&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt; &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref9:1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn10&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;There are pros to using 8-bit or 12-bit DAC. 8-bit conversion is faster, whereas 12-bit offers higher resolution. To slightly complicate things, the 12-bit DAC option on our STM32 can be aligned either left or right. That is, we can choose whether our data takes up the first 12 bits or last 12 bits on a 16-bit (2-byte) space. Alignment exists to &lt;a href=&quot;https://electronics.stackexchange.com/a/565451&quot;&gt;save you a shift operation&lt;/a&gt;, which depends on your application. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref10&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn11&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Not sure if &lt;em&gt;stall&lt;/em&gt; is the right word. Let me know if there&#39;s a better one. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3/#fnref11&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
          <category>programming</category>
        
          <category>tutorial</category>
        
          <category>dsp</category>
        
          <category>embedded</category>
        
          <category>c</category>
        
          <category>cpp</category>
        
          <category>stm32</category>
        
          <category>music</category>
        
          <category>audio-synthesis-for-dummies</category>
        
          <category>synths</category>
        
          <category>notes</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Midnight Enigma</title>
        <description>A mysterious mix of minimalism and modal musings.</description>
        <link href="https://trebledj.me/posts/midnight-enigma/"/>
        <updated>2023-04-13T00:00:00Z</updated>
        <id>https://trebledj.me/posts/midnight-enigma/</id>
        <content xml:lang="en" type="html">&lt;p&gt;&lt;em&gt;Midnight Enigma&lt;/em&gt; is composed for a &lt;a href=&quot;https://musescore.com/groups/fun-musical-challenges/discuss/5180866&quot;&gt;musical challenge&lt;/a&gt; constraining pitches within two octaves, with the bonus theme of game music.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/midnight-enigma/#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Pitch and range constraints aren&#39;t that unusual. When writing for any instrument or voice, it&#39;s important to keep in mind its range and register. You probably don&#39;t want to see (let alone hear) a bass singer singing an A5 note.&lt;/p&gt;
&lt;p&gt;Though being limited to two octaves bordered on draconian, I made do. I had to cut some corners melodically, since imitation was more difficult and flamboyant melodies couldn&#39;t be expressed. Nonetheless, I focused on exploring other aspects of music: the rhythm, extended chords, microtones, and whatnot. I also decided to have fun with the Phrygian mode a bit more.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/midnight-enigma/#fn2&quot; id=&quot;fnref2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; I started playing with this mode in &lt;a href=&quot;https://trebledj.me/posts/remorse/&quot;&gt;Remorse&lt;/a&gt; (without knowing about it 🫢), and still find it very interesting to use. (Perhaps this will become the topic of a blog post?)&lt;/p&gt;
&lt;p&gt;I decided to go with a band/minimalist/electronic fusion with a mix of drums, Reichian phasing, and electronic-inspired delay. I took (mental) inspiration from open world games such as Minecraft, where a huge number of possibilities lie at your fingertips and consequences aren&#39;t drastic.&lt;/p&gt;
&lt;p&gt;A majority of the piece was composed during midnight hours in the days before the challenge deadline, hence the title. (Yes, I messed up my sleep schedule then.)&lt;/p&gt;
&lt;p&gt;On another note, this was my first time using MIDI vocals. They sound better than I expected; might play with them in future pieces. :)&lt;/p&gt;
&lt;p&gt;Enjoy~&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;The octaves I chose were G2-G3 + G4-G5. Pitches can be anywhere inside these ranges, but not between (G3-G4) or outside. &lt;a href=&quot;https://trebledj.me/posts/midnight-enigma/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;The Phrygian mode is characterised by the flat-2nd. As &lt;em&gt;Midnight Enigma&lt;/em&gt; is primarily in C minor, the flat-2nd would be the D-flat. &lt;a href=&quot;https://trebledj.me/posts/midnight-enigma/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>minimalism</category>
        
          <category>fusion</category>
        
          <category>synths</category>
        
          <category>modal</category>
        
          <category>microtonal</category>
        
          <category>band</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Déjà Vu – Cycle of Power</title>
        <description>The first variation in a series exploring repetition and meaning in life.</description>
        <link href="https://trebledj.me/posts/deja-vu-cycle-of-power/"/>
        <updated>2023-04-09T00:00:00Z</updated>
        <id>https://trebledj.me/posts/deja-vu-cycle-of-power/</id>
        <content xml:lang="en" type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;And in the days of those kings the God of heaven will set up a kingdom that shall never be destroyed, nor shall the kingdom be left to another people. It shall break in pieces all these kingdoms and bring them to an end, and it shall stand forever…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;— Daniel 2:44 (NIV)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Organisations, institutions, nations, governments, civilisations. Whether big or small, strong or weak, aggressive or meek, each eventually fades and another rises to take its place. Though on the outside, they seem different; in the inside, they are underscored by a common denominator: the human nature of selfishness and stupidity (or put bluntly, sin).&lt;/p&gt;
&lt;p&gt;Does this mean we should dissolve into anarchy? Well, no. Organisation, with enough trust, is better than disorganisation. Proper care should be taken to manage resources, especially on a nation-wide level.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What has been is what will be, and what has been done is what will be done, and there is nothing new under the sun.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;— Ecclesiastes 1:9 (NIV)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;quot;Gibberish, ChatGPT is new under the sun!&amp;quot; But if we take into account all history and the timeline of events, there’s really not much new. Did you know before computers were invented, a &lt;em&gt;computer&lt;/em&gt; used to be a &lt;a href=&quot;https://en.wikipedia.org/wiki/Computer_(occupation)&quot;&gt;job title&lt;/a&gt;? It wouldn’t be surprising if, later on, an &lt;em&gt;engineer&lt;/em&gt; or &lt;em&gt;artist&lt;/em&gt; refers to a computer program.&lt;/p&gt;
&lt;p&gt;My point lies in the cycle of power and time. Developments, alliances, wars, laws, technologies, and disasters become mere motifs in the grand scheme of things. Standards of living, science, technology, and health have all improved over the past millennia, but nations still rage like a ceaseless tempest. Conflicts arise, almost inevitably, as if they were meant to be. Such is human nature.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Déjà Vu – Cycle of Power&lt;/em&gt; is my impression of all the above. The musical ideas in this piece were not without inspiration. Some notable inspirations were Fauré&#39;s melodic tune in &lt;em&gt;Libera Me&lt;/em&gt;, Holst&#39;s militaristic rhythm in &lt;em&gt;Mars&lt;/em&gt;, and John Adams’ minimalist works.&lt;/p&gt;
&lt;p&gt;This piece is scored for orchestra, with repeated sections to capture the essence of a cycle. Throughout this timeless journey, civilisations rise and fall. They come in different shapes and sizes, from the grand to the subdued, from the pacifists to the militarists. A fleeting escape is made into a lucid dreamlike passage where flourishing arpeggios elevate us from reality; yet order lurks in the background. The piece culminates in an oddly familiar setting as history seemingly repeats itself.&lt;/p&gt;
&lt;p&gt;Each motif and section comes to an end, their place taken by a new motif—and ultimately silence. But there’s a motif which doesn’t end—which can’t be captured on sheets of music.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/deja-vu-cycle-of-power/#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Although the world we live in may seem like an inescapable matrix&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/deja-vu-cycle-of-power/#fn2&quot; id=&quot;fnref2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, each of us has the opportunity to learn, to teach, to experience different perspectives, and to share the hope of something unseen—something more.&lt;/p&gt;
&lt;p&gt;On this Easter Sunday (and well… all Easter Sundays), we commemorate the resurrection of Jesus Christ, remembering the glorious occasion of His power—and victory—over death, sin, and evil.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;How do you apply dimension reduction on the infinite without discarding an &lt;em&gt;ounce&lt;/em&gt; of its beauty? Good luck trying to use PCA or whatever dimensionality reduction algorithm is popular at the time of reading. I mean, I suppose it&#39;s still possible to focus on some aspects and reduce accordingly. Maybe for a later time. &lt;a href=&quot;https://trebledj.me/posts/deja-vu-cycle-of-power/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Alluding to the &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Matrix&quot;&gt;movie&lt;/a&gt;. Go watch it if you haven’t already. &lt;sub&gt;&lt;em&gt;cough&lt;/em&gt; - You know who you are.&lt;/sub&gt; &lt;a href=&quot;https://trebledj.me/posts/deja-vu-cycle-of-power/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>faith</category>
        
          <category>orchestral</category>
        
          <category>fusion</category>
        
          <category>deja-vu</category>
        
          <category>essay</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Digital Audio Synthesis for Dummies: Part 2</title>
        <description>Generating audio signals for great good through additive synthesis and wavetable synthesis.</description>
        <link href="https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/"/>
        <updated>2023-03-09T00:00:00Z</updated>
        <id>https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/</id>
        <content xml:lang="en" type="html">&lt;p&gt;This is the second post in a series of posts on Digital Audio Processing. Similar to the &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1&quot;&gt;previous post&lt;/a&gt;, this post stems from a lil’ &lt;a href=&quot;https://trebledj.me/posts/stm32-midi-keyboard&quot;&gt;MIDI keyboard&lt;/a&gt; project I worked on last semester and is an attempt to share the knowledge I&#39;ve gained with others. This post will dive into the wonderful world of audio synthesis and introduce two important synthesis techniques: additive synthesis and wavetable synthesis.&lt;/p&gt;
&lt;h2 id=&quot;audio-synthesis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#audio-synthesis&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Audio Synthesis 🎶&lt;/h2&gt;
&lt;p&gt;Where do audio signals come from? Our signal might be…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;recorded&lt;/strong&gt;. Sound waves are picked up by special hardware (e.g. a microphone) and translated to a digital signal through an &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Analog-to-Digital Converter&quot;&gt;ADC&lt;/abbr&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;loaded&lt;/strong&gt; from a file. There are many audio formats out there, but the most common ones are .wav and .mp3. The .wav format is simple: just store the samples as-is. Other formats compress audio to achieve smaller file sizes (which in turn, means faster upload/download speeds).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;synthesised&lt;/strong&gt;. We generate audio out of thin air (or rather, code and electronics).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ll mainly focus on &lt;strong&gt;synthesis&lt;/strong&gt;. We’ll start by finding out how to generate a single tone, then learn how to generate multiple tones simultaneously.&lt;/p&gt;
&lt;h2 id=&quot;buffering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#buffering&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Buffering 📦&lt;/h2&gt;
&lt;p&gt;A naive approach to generate audio might be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Process one sample&lt;/li&gt;
&lt;li&gt;Feed it to the &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;Digital-to-Analogue Converter&quot;&gt;DAC&lt;/abbr&gt;/speaker&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But there are several issues with this: function call overhead may impact performance, and we have little room left to do other things. For the sound to play smoothly while sampling at 44100Hz, each sample needs to be delivered within $&#92;frac{1}{44100}$ s = $22.6$ µs.&lt;/p&gt;
&lt;p&gt;A better approach is to use a &lt;em&gt;buffer&lt;/em&gt; and work in batches. The buffer will hold onto our samples before feeding it to the speaker.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Process $N$ samples and store them in a buffer&lt;/li&gt;
&lt;li&gt;Feed all $N$ samples to the DAC/speaker&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&#39;ll focus more on step 1 (processing) for now. We&#39;ll cover step 2 (output) in the next post.&lt;/p&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-circle-info ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;In a previous post, we discussed &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1#quantisation&quot;&gt;quantisation&lt;/a&gt; and how different representations (such as integers and floats) are suited for different tasks. Integers are discrete numbers, while floats are (imprecise) real numbers. Since we&#39;re concerned with audio processing, we&#39;ll be using floats and quantising from -1 to 1.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In C/C++, we can generate a sine tone like so:&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;SAMPLE_RATE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;44100&lt;/span&gt;  &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// Number of samples per second.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;BUFFER_SIZE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt;   &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// Length of the buffer.&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Define an array for storing samples.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Buffer of samples to populate, each ranging from -1 to 1.&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * Generate samples of a sine wave and store them in a buffer.
 * @param freq  Frequency of the sine wave, in Hz.
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generate_samples&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; freq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Populate the buffer with a sine tone with frequency `freq`.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; freq &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;And that’s it—we’ve just whooshed pure sine tone goodness from nothing! Granted, there are some flaws with this method (it could be more efficient, and the signal clicks when repeated); but hey, it demonstrates synthesis.&lt;/p&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-bolt ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;Note on Buffers: Usually, the buffer size is medium-sized power of 2 (e.g. 512, 1024, 2048, 4096...). This enhances cache loads and processing speed (dividing by a power of 2 is super easy for processors!).&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-fourier-theorem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#the-fourier-theorem&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; The Fourier Theorem 📊&lt;/h2&gt;
&lt;p&gt;One fundamental theorem in signal processing is the &lt;strong&gt;Fourier Theorem&lt;/strong&gt;, which relates to the composition of signals. It can be summarised into:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any &lt;em&gt;periodic&lt;/em&gt; signal can be &lt;em&gt;broken down&lt;/em&gt; into a &lt;em&gt;sum&lt;/em&gt; of sine waves.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can express this mathematically as
$$
f(x) = a_0&#92;sin(f_0x + b_0) + a_1&#92;sin(f_1x + b_1) + &#92;cdots + a_n&#92;sin(f_nx + b_n)
$$
where $a_i$, $f_i$, and $b_i$ are the amplitude, frequency, and phase of each constituent sine wave.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Skipper&#39;s partial to Fourier. They&#39;re the best of chums.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/fourier-analysis-1125w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-55&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/fourier-analysis-1125w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 1125 / 832&quot; alt=&quot;Skipper&#39;s partial to Fourier. They&#39;re the best of chums.&quot; title=&quot;Skipper&#39;s partial to Fourier. They&#39;re the best of chums.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/fourier-analysis-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/fourier-analysis-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/fourier-analysis-1024w.webp 1024w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/fourier-analysis-1125w.webp 1125w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 1125px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-bolt ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;The Fourier Theorem and Fourier Transform are ubiquitous in modern day technology. It is the basis for many audio processing techniques such as filtering, equalisation, and noise cancellation. By manipulating the individual sine waves that make up a sound, we can alter its characteristics and create new sounds. The Fourier Transform is also a key component in compression, such as the JPG image format.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;What’s cool about this theorem is that we can apply it the other way: any periodic signal can be &lt;em&gt;generated&lt;/em&gt; by adding sine waves. This lays the groundwork for additive synthesis and generating audio with multiple pitches (e.g. a chord).&lt;/p&gt;
&lt;h2 id=&quot;additive-synthesis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#additive-synthesis&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Additive Synthesis ➕&lt;/h2&gt;
&lt;p&gt;The principle of &lt;strong&gt;additive synthesis&lt;/strong&gt; is pretty straightforward: signals can be combined by adding samples along time.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Example of additive synthesis, localised on this very webpage.&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/additive-synthesis-640w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-65&quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/additive-synthesis-640w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 640 / 480&quot; alt=&quot;Example of additive synthesis, localised on this very webpage.&quot; title=&quot;Example of additive synthesis, localised on this very webpage.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/additive-synthesis-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/additive-synthesis-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/additive-synthesis-640w.webp 640w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 640px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Example of additive synthesis. The first and second signal show pure sine tones at 440Hz ($s_1$) and 660Hz ($s_2$). The third signal adds the two signals ($s_1 + s_2$). The fourth signal scales the third signal down to fit within $[-1, 1]$ ($(s_1 + s_2) / 2$). (&lt;a href=&quot;https://gist.github.com/TrebledJ/14b8842ef3696b09e299c34ba0da9e6c&quot;&gt;Source Code&lt;/a&gt;)&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;To sound another pitch, we simply add a second sine wave to the buffer.&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;SAMPLE_RATE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;44100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;BUFFER_SIZE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * Generate samples of two sine waves played together and store them in a buffer.
 * @param freq  Frequency of the first sine wave, in Hz.
 * @param freq2 Frequency of the second sine wave, in Hz.
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generate_samples2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; freq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; freq2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5f&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; freq &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5f&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; PI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; freq2 &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Again, the code above populates the buffer with 1024 samples of audio. But this time, we introduced a second frequency &lt;code&gt;freq2&lt;/code&gt; and added a second sample to the buffer. We also made sure to scale the resulting sample back down to the $[-1, 1]$ range by multiplying each sample by 0.5.&lt;/p&gt;
&lt;p&gt;We can see additive synthesis in action with some help from &lt;a href=&quot;https://www.audacityteam.org/&quot;&gt;Audacity&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Let’s start off with one tone.
&lt;ul&gt;
&lt;li&gt;Generate a 440Hz tone (Generate &amp;gt; Tone… &amp;gt; Sine).&lt;/li&gt;
&lt;li&gt;Play it. You’ll hear a pure tone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Now let’s add another tone.
&lt;ul&gt;
&lt;li&gt;Make a new track (Tracks &amp;gt; Add New &amp;gt; Mono Track).&lt;/li&gt;
&lt;li&gt;Generate an 880Hz tone in the new track. Same method as above.&lt;/li&gt;
&lt;li&gt;Play it to hear a beautiful sounding octave.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;The audacity of it all!&quot; href=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/audacity-2000w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-100 &quot; src=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/audacity-2000w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 2000 / 650&quot; alt=&quot;Screenshot of Audacity with the 440 Hertz and 880 Hertz sine tone.&quot; title=&quot;The audacity of it all!&quot; srcset=&quot;https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/audacity-256w.webp 256w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/audacity-512w.webp 512w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/audacity-1024w.webp 1024w, https://trebledj.me/img/posts/programming/digital-audio-synthesis/assets/audacity-2000w.webp 2000w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 2000px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;During playback, Audacity will combine the samples from both tracks by summing them and play the summed signal.&lt;/p&gt;
&lt;p&gt;You can try layering other frequencies (554Hz, 659Hz) to play a nifty A Major chord.&lt;/p&gt;
&lt;h2 id=&quot;fundamental-frequency&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#fundamental-frequency&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Fundamental Frequency&lt;/h2&gt;
&lt;p&gt;A side note. When combining two frequencies with additive synthesis, something subtle happens. The ground shifts and our feet fumble! The fundamental frequency implicitly changes!&lt;/p&gt;
&lt;div class=&quot;alert alert-success d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-lightbulb ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;&lt;strong&gt;DIY Example&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fire up Audacity.&lt;/li&gt;
&lt;li&gt;Generate a 400Hz sine tone. (Generate &amp;gt; Tone...)&lt;/li&gt;
&lt;li&gt;Generate a 402Hz sine tone on a different track.&lt;/li&gt;
&lt;li&gt;Play the audio and observe. How many times does the audio &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;i.e. hit a maximum point&quot;&gt;peak&lt;/abbr&gt; per second?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It peaks &lt;span class=&quot;spoiler&quot; tabindex=&quot;0&quot;&gt;twice&lt;/span&gt; per second. (That is, we implicitly added a &lt;span class=&quot;spoiler&quot; tabindex=&quot;0&quot;&gt;2Hz&lt;/span&gt; signal beneath!)&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Specifically, the fundamental changes to the &lt;strong&gt;greatest common divisor&lt;/strong&gt; (GCD) of the two frequencies.&lt;/p&gt;
&lt;p&gt;More notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When we play a note and its 5th (in &lt;em&gt;Just Temperament&lt;/em&gt;), say 440Hz and 660Hz, our fundamental is 220Hz.&lt;/li&gt;
&lt;li&gt;With octaves, the fundamental frequency is just the frequency of the lower note.&lt;/li&gt;
&lt;li&gt;This also leads to some interesting phenomena.
&lt;ul&gt;
&lt;li&gt;When we play two super-low-register notes a semitone apart, we get funny, dissonant pulses emanating from our keyboard or piano.&lt;/li&gt;
&lt;li&gt;This may also lead to unpleasant buzzes when mixing synths, possibly due to frequency modulation on top of a steady tone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wavetable-synthesis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#wavetable-synthesis&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Wavetable Synthesis 🌊&lt;/h2&gt;
&lt;p&gt;In previous code blocks, we computed samples using &lt;code&gt;sin()&lt;/code&gt;. But what if we wanted to compute something more complex? Do we really just reverse the Fourier theorem and apply additive synthesis on a bunch of sine signals? It turns out there&#39;s a better way.&lt;/p&gt;
&lt;p&gt;A more efficient approach is to interpolate over &lt;em&gt;pre-generated values&lt;/em&gt;, sacrificing a bit of memory for faster runtime performance. This is known as &lt;strong&gt;wavetable synthesis&lt;/strong&gt; or &lt;strong&gt;table-lookup synthesis&lt;/strong&gt;. The idea is to pre-generate one cycle of the wave (e.g. a sine) and store it in a lookup table. Then when generating samples for our audio, we would look up the pre-generated samples and derive intermediate values if necessary (via interpolation).&lt;/p&gt;
&lt;p&gt;This is akin to preparing a cheat sheet for an exam, but you&#39;re only allowed to bring one sheet of paper—space is precious. You decide to only include the most crucial equations, key points, and references. Then when taking the exam you refer to the cheat sheet for ideas, connect the dots, and combine them with your thoughts to form an answer.&lt;/p&gt;
&lt;div class=&quot;mb-2 rw center jw-75 video&quot;&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; class=&quot;jw-100&quot;&gt;&lt;source src=&quot;https://trebledj.me/img/wavetable-synthesis.mp4&quot; type=&quot;video/mp4&quot; /&gt;&lt;/video&gt;&lt;/div&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Example of wavetable synthesis. The blue dots (above) show a pre-generated wavetable of length 32. The red dots (below) are samples of a 8Hz sine wave sampled at 100Hz, generated by interpolating on the wavetable. (&lt;a href=&quot;https://gist.github.com/TrebledJ/f42f9030d1bee0ece8af7fc0db5d0151&quot;&gt;Source Code&lt;/a&gt;)&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Wavetable synthesis can be implemented in C++ like so:&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;SINE_WAVETABLE_SIZE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;SAMPLE_RATE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;44100&lt;/span&gt;  &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// Number of samples per second (of the target waveform).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;BUFFER_SIZE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The pre-generated wavetable. It should capture one cycle of the desired waveform (in this case, a sine).&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; sine_wavetable&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;SINE_WAVETABLE_SIZE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* pre-generated values ... */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The phase indicates how far along the wavetable we are.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// We&#39;re concerned with two components: the integer and decimal.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// The integer part indicates the index of left sample along the wavetable, modulus the size.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// The decimal part indicates the fraction between the left and right samples.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; phase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * Generate samples of a sine wave by interpolating a wavetable.
 * @param freq  Frequency of the sine wave, in Hz.
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_next_sample&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; freq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    size_t idx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;size_t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;phase&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Integer part.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; frac &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; phase &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; idx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;// Decimal part.&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Get the pre-generated sample to the LEFT of the current sample.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; samp0 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sine_wavetable&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;idx&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Get the pre-generated sample to the RIGHT of the current sample.&lt;/span&gt;
    idx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;idx &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; SINE_WAVETABLE_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; samp1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sine_wavetable&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;idx&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Interpolate between the left and right samples to get the current sample.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; inter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;samp0 &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;samp1 &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; samp0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; frac&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Advance the phase to prepare for the next sample.&lt;/span&gt;
    phase &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; SINE_WAVETABLE_SIZE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; freq &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; SAMPLE_RATE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; inter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generate_samples_w&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; freq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; BUFFER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_next_sample&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;freq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// We&#39;ve offloaded the calculations to `get_next_sample`.&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;C++&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;For a sine wave, we don&#39;t gain much in terms of performance. But when it comes to generating complex waveforms, wavetable synthesis rocks!&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#fn2&quot; id=&quot;fnref2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-bolt ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;Wavetable synthesis is commonly used by &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;a protocol for music&quot;&gt;MIDI&lt;/abbr&gt; to generate sounds. Each instrument has its own &lt;em&gt;soundfont&lt;/em&gt;, which is a collection of wavetables of different pitches. This unifies the synthesis approach for all instruments, as some may be simple to generate (e.g. clarinet) while others are more complex.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;alert alert-success d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-lightbulb ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;Additive synthesis and wavetable synthesis serve two very different purposes!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Additive synthesis aims to &lt;em&gt;combine multiple waveforms&lt;/em&gt;, of &lt;em&gt;any&lt;/em&gt; shape and size (e.g. playing chords, or combining guitar and voice tracks).&lt;/li&gt;
&lt;li&gt;Wavetable synthesis aims to generate a &lt;em&gt;specific&lt;/em&gt; waveform (in a fast manner).&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Besides this software approach, we can also leverage hardware to speed up processing. But this is a matter for the next post.&lt;/p&gt;
&lt;p&gt;Exercise for the reader:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What variables affect the speed at which we iterate through the pre-generated wavetable?&lt;/li&gt;
&lt;li&gt;What happens if we try to generate a waveform with frequency equal to half the sample rate? Or with frequency equal &lt;em&gt;to&lt;/em&gt; the sample rate itself?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;recap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#recap&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Recap 🔁&lt;/h2&gt;
&lt;p&gt;Audio generation is pretty fun once we dive deep, as are its applications: toys, electronic instruments, virtual instruments, digital synths, speakers, hearing aids, and whatnot.  As before, I hope we communicated on the same wavelength and the information on this post did not experience aliasing. 😏&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3&quot;&gt;next post&lt;/a&gt;, we&#39;ll dive even deeper into audio synthesis (particularly in embedded systems) and engineer a simple tone generator.&lt;/p&gt;
&lt;p&gt;To recap…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Audio samples may come from several sources. It may be recorded, loaded from a file, or &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#audio-synthesis&quot;&gt;synthesised&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We can synthesise musical pitches by &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#buffering&quot;&gt;buffering&lt;/a&gt; samples and feeding them to hardware.&lt;/li&gt;
&lt;li&gt;According to the &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#the-fourier-theorem&quot;&gt;Fourier Theorem&lt;/a&gt;, all signals can be broken into a summation of sine waves.&lt;/li&gt;
&lt;li&gt;To combine audio signals, we can apply &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#additive-synthesis&quot;&gt;additive synthesis&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;This also allows us to play multiple pitches simultaneously (chords).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We can generate complex waveforms by using &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#wavetable-synthesis&quot;&gt;wavetable synthesis&lt;/a&gt;, which trades memory for speed by sampling pre-generated signals.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Further Reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Waveforms (Sine, Square, Triangle, Sawtooth)
&lt;ul&gt;
&lt;li&gt;Most audio synthesis tutorials cover simple waveforms; but as internet content is saturated here, I&#39;ll just drop a couple links. I couldn&#39;t find an article I like that introduces these waveforms in all their glory. If you know of better articles, let me know.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.perfectcircuit.com/signal/difference-between-waveforms&quot;&gt;Perfect Circuit&lt;/a&gt; (conceptual, high-level)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.electronics-tutorials.ws/waveforms/waveforms.html&quot;&gt;Electronics Tutorial&lt;/a&gt; (geared towards electronics; would be a nice read to prepare for the &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3&quot;&gt;next post&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://musictech.com/guides/essential-guide/beginners-guide-to-synthesis-in-music-production/&quot;&gt;Beginner’s Guide: Everything you need to know about synthesis in music production&lt;/a&gt; – Introduces more forms of audio synthesis, geared towards music production.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Boy, do I have a lot to say about buffers. Why is the buffer size important? Small buffers may reduce the efficacy of batching operations (which is the primary purpose of buffers). Large buffers may block the processor too much, making it sluggish to respond to new input. Choosing an appropriate buffer size also depends on your sampling rate. With a buffer size of 1024 sampling at 44100Hz, we would need to generate our samples every $&#92;frac{1024}{44.1&#92;text{kHz}} &#92;approx 23.2$ ms. On a single processor, this means we have &lt;em&gt;less than&lt;/em&gt; 23.2 ms to perform other tasks (e.g. handle UI, events, etc.). &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Guess what? There are more ways to optimise wavetable synthesis—so it&#39;ll rock even more! See the open source &lt;a href=&quot;https://github.com/spiricom/LEAF/blob/a0b0b7915cce3792ea00f06d0a6861be1a73d609/leaf/Src/leaf-oscillators.c#L67&quot;&gt;LEAF&lt;/a&gt; library for an example of optimised wavetable synthesis in C. &lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
          <category>programming</category>
        
          <category>tutorial</category>
        
          <category>dsp</category>
        
          <category>c</category>
        
          <category>cpp</category>
        
          <category>music</category>
        
          <category>audio-synthesis-for-dummies</category>
        
          <category>synths</category>
        
          <category>notes</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Amorama</title>
        <description>A fun little dance slash love medley.</description>
        <link href="https://trebledj.me/posts/amorama/"/>
        <updated>2023-02-14T00:00:00Z</updated>
        <id>https://trebledj.me/posts/amorama/</id>
        <content xml:lang="en" type="html">&lt;p&gt;&lt;em&gt;Amorama&lt;/em&gt; was composed for a fun little musical challenge on the theme of love ❤️ with the constraint of using the rarely-sighted 13/16 metre. Often, music is made for more balanced, basic metres such as 4/4, 3/4, and 6/8. For some reason, we seem to prefer small subdivisions of 2 or 3. We can still apply this principle with 13/16 though, and it turns out that&#39;s what most contestants did. :)&lt;/p&gt;
&lt;p&gt;I chose to blend Cuban rhythms, some sweet little tunes, and—since it&#39;s February—various love themes (see if you recognise any!). The piece is scored for violin, piano, double bass, castanets (the clacky things), and drums. The violin and piano are responsible for the melody, while the bass, castanets, and drums primarily generate rhythm and provide the swaying dance line.&lt;/p&gt;
&lt;p&gt;As encouraged by Spotify advertisements, go and dance with abandon!&lt;/p&gt;
&lt;p&gt;Happy Valentine&#39;s Day, God bless, and enjoy~ ❤️&lt;/p&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>fusion</category>
        
          <category>medley</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Remorse</title>
        <description>Hiding messages with counterpoint.</description>
        <link href="https://trebledj.me/posts/remorse/"/>
        <updated>2023-01-27T00:00:00Z</updated>
        <id>https://trebledj.me/posts/remorse/</id>
        <content xml:lang="en" type="html">&lt;p&gt;A reflection of the past, composed and mixed during my 7-day covid quarantine.&lt;/p&gt;
&lt;p&gt;Time ebbs past,&lt;br /&gt;
As anguish holds fast.&lt;br /&gt;
Without you I’m filled with remorse,&lt;br /&gt;
For you are my one driving force.&lt;/p&gt;
&lt;p&gt;As the season turns,&lt;br /&gt;
My heart still churns.&lt;br /&gt;
I’ll leave my sins and remorse,&lt;br /&gt;
Heading on a different course.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The purpose of composing this piece is threefold: it served as an expression of faith and emotions, a challenge for a &lt;a href=&quot;https://trebledj.me/tags/ctf/&quot;&gt;Capture-the-Flag (CTF)&lt;/a&gt; competition, and an enjoyable way to pass quarantine. There wasn&#39;t any priority to a particular purpose; all of them seemed to develop together.&lt;/p&gt;
&lt;p&gt;This piece was composed for the HKUST Firebird 2023 Internal CTF. Such competitions are designed to challenge players with cybersecurity know-how. Once players identify and exploit a vulnerability, they are rewarded with a &lt;em&gt;flag&lt;/em&gt; (a piece of text), which awards points to the player when submitted. Occasionally, some challenges deviate from the norm and test players in other areas. In this case, my challenge tested players in analysing music and patterns.&lt;/p&gt;
&lt;p&gt;When composing this piece, I aimed to compose something listenable and motivic. I decided to keep constraints flexible within limits. If a music is too constrained, it sounds choked, inevitable, or unimaginative. Some music ciphers out there encode letters into pitches and duration. This was a bit too far for my liking, as it becomes painstakingly difficult to find a pleasurable tune.&lt;/p&gt;
&lt;p&gt;As hinted by the title, I first translated the flag into Morse using an &lt;a href=&quot;https://onlineasciitools.com/convert-ascii-to-morse&quot;&gt;online converter&lt;/a&gt; with the extended Morse character set. This allowed for some punctuation such as &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;_&lt;/code&gt;, and funky non-ASCII characters such as &lt;code&gt;é&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With plaintext, we need to encode at least 50 distinct letters. With Morse, we just need to encode 3 instead: &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, and space (as a word separator). So things are relatively simple.&lt;/p&gt;
&lt;p&gt;I toyed around with a few ideas of encoding these three characters. Eventually I ended up with this mapping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.&lt;/code&gt; → &amp;quot;Note On&amp;quot; in upper stave (treble clef)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt; → &amp;quot;Note On&amp;quot; in lower stave (bass clef)&lt;/li&gt;
&lt;li&gt;space → &amp;quot;Note On&amp;quot; in both staves&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This lent the music well to a contrapuntal form, with the occasional grace-note or glissando to pack characters in a way that preserves the melodic contour. After composing the sheet music, I ended up mixing it with Reaper for some extra flair and charged resonance, making the night seem younger.&lt;/p&gt;
&lt;p&gt;Enjoy the result!&lt;/p&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>faith</category>
        
          <category>piano</category>
        
          <category>counterpoint</category>
        
          <category>modal</category>
        
          <category>electronica</category>
        
          <category>dubsy-wubsy</category>
        
          <category>synths</category>
        
          <category>ctf</category>
        
          <category>writeup</category>
        
          <category>stego</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Seaside Garden</title>
        <description>A first attempt at songwriting.</description>
        <link href="https://trebledj.me/posts/seaside-garden/"/>
        <updated>2023-01-01T00:00:00Z</updated>
        <id>https://trebledj.me/posts/seaside-garden/</id>
        <content xml:lang="en" type="html">&lt;p&gt;&lt;em&gt;Seaside Garden&lt;/em&gt; is composed for HKUST&#39;s Call for Scores for the School Anthem.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; I present my rationale below, at the expense of being cheesy.&lt;/p&gt;
&lt;h2 id=&quot;rationale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/seaside-garden/#rationale&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Rationale&lt;/h2&gt;
&lt;p&gt;My journey with HKUST started three and a half years ago. This was a period of becoming, exploration, and development. To me, the university is like a garden: cultivating and nurturing flora and fauna, a peaceful sanctuary, a place of life and beauty. Situated near the sea, HKUST stands firm as waves ceaselessly crash against its foundation.&lt;/p&gt;
&lt;p&gt;But what&#39;s a garden without birds? A garden is a place where birds can flourish and grow before departing and exploring the outside world. There are countless kinds of birds: wisened owls, agile peregrines, shrewd crows, and hardworking weavers among others. The garden and birds live in symbiosis. The garden provides nutrition and shelter; in exchange, birds spread seeds and pollinate flowers. It is well-known that birds digest fruit from one end and discharge (plus fertilise!) seeds from the other end, planting these gifts to who-knows-where. Without birds, the world becomes a very dark and dismal place.&lt;/p&gt;
&lt;p&gt;HKUST&#39;s iconic sundial goes by many names. In Cantonese, it&#39;s colloquially known as the turkey (literally, fire chicken). Some university groups such as the Red Bird and Firebird teams name themselves after the sculpture. Indeed, it is difficult not to feel a fiery sensation when looking at the sundial.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fn2&quot; id=&quot;fnref2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; The name it was officially given was &amp;quot;&lt;em&gt;Circle of Time&lt;/em&gt;&amp;quot;, a timeless tribute to humanity and a reflection of Earth&#39;s endless cycle. Although the two HKUST campuses are separated by a border, the two are united by such a monument.&lt;/p&gt;
&lt;p&gt;Further references include the purple orchid, storms, and other subtle things. The purple orchid—aka the Bauhinia, Hong Kong&#39;s national flower—was included in view of HKUST&#39;s commitment towards the development of Hong Kong. Storms, on the other hand, are an inevitable part of life in Hong Kong and neighbouring ports.&lt;/p&gt;
&lt;p&gt;Composed in the final week of the year 2022 and released on New Year&#39;s Day 2023, it is my wish that this song instils vision and harmony in learning and teaching throughout the HKUST community.&lt;/p&gt;
&lt;h2 id=&quot;lyrics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/seaside-garden/#lyrics&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Lyrics&lt;/h2&gt;
&lt;p&gt;I&#39;m no lyricist, but for completeness and posterity here are my jank lyrics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verse 1&lt;/strong&gt;&lt;br /&gt;
Seedlings sprout forth&lt;br /&gt;
As purple orchids bloom.&lt;br /&gt;
And birds start the morning&lt;br /&gt;
As they sing a joyful tune.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pre-Chorus 1&lt;/strong&gt;&lt;br /&gt;
Oh the sun rises and falls,&lt;br /&gt;
In an endless Circle of Time.&lt;br /&gt;
And clouds can&#39;t hide the rays that shine from above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chorus 1&lt;/strong&gt;&lt;br /&gt;
But though storms and strife may rage all night,&lt;br /&gt;
Our journey carries on.&lt;br /&gt;
Oh, the seaside garden,&lt;br /&gt;
Our community.&lt;/p&gt;
&lt;p&gt;Through storms and strife we&#39;ll find our way&lt;br /&gt;
As one in unity.&lt;br /&gt;
In the seaside garden,&lt;br /&gt;
Our community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verse 2&lt;/strong&gt;&lt;br /&gt;
Dandelions&lt;br /&gt;
Blow far, far away.&lt;br /&gt;
And birds leave the treetops&lt;br /&gt;
As they fly off on their way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pre-Chorus 2&lt;/strong&gt;&lt;br /&gt;
The stars rise and fall&lt;br /&gt;
In an endless Circle of Time.&lt;br /&gt;
And clouds can&#39;t hide our voice and fiery call&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chorus 2&lt;/strong&gt;&lt;br /&gt;
And through the books, the toil,&lt;br /&gt;
The sleepless nights,&lt;br /&gt;
Our journey carries on.&lt;br /&gt;
Though storms and strife may rage all night,&lt;br /&gt;
Our path is not forgone&lt;br /&gt;
Let vision guide all our hearts&lt;br /&gt;
Through vivid dreams and youthful hope.&lt;br /&gt;
In the seaside garden,&lt;br /&gt;
Our community.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fn3&quot; id=&quot;fnref3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chorus 3&lt;/strong&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fn4&quot; id=&quot;fnref4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
And through the times, the trials,&lt;br /&gt;
The countless miles,&lt;br /&gt;
Our venture knows no end.&lt;br /&gt;
Wind and water carry far&lt;br /&gt;
The gifts that we present.&lt;br /&gt;
Let virtues latch on our wings&lt;br /&gt;
With steadfast bonds and harmony.&lt;br /&gt;
Oh seaside garden,&lt;br /&gt;
Our family.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fn3&quot; id=&quot;fnref3:1&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outro&lt;/strong&gt;&lt;br /&gt;
From the seaside garden,&lt;br /&gt;
We fly!&lt;br /&gt;
We fly!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;It didn&#39;t get accepted, sadly. But that&#39;s okay. &lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Up to interpretation, of course. Perhaps it&#39;s a fiery love. A fiery joy. A fiery excitement. It could just as well be a fiery hatred, anger, or diarrhoea. &lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;May interchange between &amp;quot;community&amp;quot; or &amp;quot;family&amp;quot;. &lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt; &lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fnref3:1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;May repeat Chorus 2 instead, or sing Chorus 3 twice. Ad lib. &lt;a href=&quot;https://trebledj.me/posts/seaside-garden/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>song</category>
        
          <category>piano</category>
        
          <category>chamber</category>
        
          <category>hkust</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>STM32 MIDI Keyboard</title>
        <description>Boing boing plunk plunk. Constructing a MIDI keyboard from scratch.</description>
        <link href="https://trebledj.me/posts/stm32-midi-keyboard/"/>
        <updated>2022-12-20T00:00:00Z</updated>
        <id>https://trebledj.me/posts/stm32-midi-keyboard/</id>
        <content xml:lang="en" type="html">&lt;p&gt;This project was made for a course on embedded systems and is published &lt;a href=&quot;https://github.com/TrebledJ/stm32-midi-keyboard&quot;&gt;online&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;synopsis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/stm32-midi-keyboard/#synopsis&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Synopsis&lt;/h2&gt;
&lt;p&gt;The STM32 MIDI Keyboard was a project aimed to practice &lt;a href=&quot;https://trebledj.me/tags/embedded/&quot;&gt;embedded systems&lt;/a&gt; design while also have fun developing a tactile music application. Here are some features found on the keyboard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2+ octaves (29) piano keys to flexibly play various melodies&lt;/li&gt;
&lt;li&gt;Supports multi-press, so that we aren&#39;t stuck with boring one-note tunes and can play chords&lt;/li&gt;
&lt;li&gt;Volume control, so that we don’t disturb our neighbours&lt;/li&gt;
&lt;li&gt;Metronome, in case the user can’t keep track of tempo&lt;/li&gt;
&lt;li&gt;TFT display and menu selection&lt;/li&gt;
&lt;li&gt;Record and playback music (supports multiple channels!)&lt;/li&gt;
&lt;li&gt;Load/store MIDI in flash memory, in case power runs out&lt;/li&gt;
&lt;li&gt;Send MIDI signals through Serial USB (UART)
&lt;ul&gt;
&lt;li&gt;Receiving is handled by a script (receive.py)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Extra fanciful features:
&lt;ul&gt;
&lt;li&gt;Transpose: shift pitches up/down on the diatonic scale&lt;/li&gt;
&lt;li&gt;Auto-Chord: quality-of-life function to play octaves, triads, and open triads by just pressing the root key&lt;/li&gt;
&lt;li&gt;Instruments: supports playback of sine, triangle, square, and sawtooth signals&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/stm32-midi-keyboard/#development&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Development&lt;/h2&gt;
&lt;p&gt;I was lucky to work with &lt;a href=&quot;https://github.com/TangYanYee&quot;&gt;another member&lt;/a&gt; of the &lt;a href=&quot;https://trebledj.me/posts/hkust-robotics-team&quot;&gt;Robotics Team&lt;/a&gt; at HKUST. She did the electrical work of designing and soldering the &lt;abbr data-bs-placement=&quot;top&quot; data-bs-toggle=&quot;tooltip&quot; title=&quot;The printed circuit board. It&amp;#039;s the underlying hardware that makes everything work!&quot;&gt;PCB&lt;/abbr&gt;. Both of us weren&#39;t familiar with mechanical design, so we ended up sticking things onto plywood and screwing things &lt;s&gt;up&lt;/s&gt; together. But hey, at least it&#39;s a minimum viable product.&lt;/p&gt;
&lt;p&gt;Although the course provided us with a multi-functional board (STM32F103VET6), we ended up using with a different board (STM32F405). The F4 series comes with more processing power, flash memory, and RAM. These are important considerations when it comes to a real-time music system. Audio buffering needs to be fast and steady, and sufficient memory is required for storage and buffering.&lt;/p&gt;
&lt;p&gt;We used C++20 for the project.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://trebledj.me/posts/stm32-midi-keyboard/#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Although most objects and peripherals were singletons, classes (and templates!) proved useful, especially for containers (such as a &lt;a href=&quot;https://github.com/TrebledJ/stm32-midi-keyboard/blob/main/Core/Inc/utils/tinyvector.hpp&quot;&gt;fixed-size vector&lt;/a&gt;). C++ also allowed us to have static reflection for enums, thanks to &lt;a href=&quot;https://github.com/Neargye/magic_enum&quot;&gt;magic_enum&lt;/a&gt;. The alternative would&#39;ve been X-macros or hard-coding, both less maintainable options.&lt;/p&gt;
&lt;p&gt;Most MIDI keyboards out there don&#39;t produce sound by themselves, and sometimes I&#39;d rather just noodle around without having to set up any computer software. So one of our goals was to have the keyboard produce sound. This was pretty straightforward. Slap a timer, &lt;abbr data-bs-toggle=&quot;tooltip&quot; title=&quot;Direct Memory Access. Allows data to be transferred without using CPU processing resources. Great for performance!&quot;&gt;DMA&lt;/abbr&gt;, and &lt;abbr data-bs-toggle=&quot;tooltip&quot; title=&quot;Digital-to-audio converter. Converts 1s and 0s to bzzzt-pzzt-mzzt-woink (analog signals).&quot;&gt;DAC&lt;/abbr&gt; together, and &lt;abbr data-bs-toggle=&quot;tooltip&quot; title=&quot;This isn&#39;t an abbreviation. :P&quot;&gt;BAM&lt;/abbr&gt;—non-blocking audio output!&lt;/p&gt;
&lt;p&gt;We had more trouble with the speakers. They truly annoyed the heck out of us. Earlier on, we used a pair of small woofers. These were connected to an amplifier (because the voltage delivered by the board&#39;s DAC was not enough). The audio output generated when playing one tone (e.g. 440Hz sine) was fine. However for some unknown reason, playing &lt;em&gt;multiple&lt;/em&gt; tones (e.g. 440Hz sine + 660Hz sine) was catastrophic. I asked a question on &lt;a href=&quot;https://dsp.stackexchange.com/questions/85140/adding-two-sine-waves-results-in-a-low-buzz&quot;&gt;dsp.se&lt;/a&gt;, where some users suggested it being a psychoacoustic issue. Thankfully, that was not the case. Eventually we solved the issue by changing to different speakers, the kind used by end-users.&lt;/p&gt;
&lt;h2 id=&quot;concluding-remarks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/stm32-midi-keyboard/#concluding-remarks&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Concluding Remarks&lt;/h2&gt;
&lt;p&gt;It was quite relaxing and nice to have a (semi-?)personal project developing and designing an embedded application from head to tail. The instructors for the course were really helpful as well.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in trying something similar, here are some things we planned but didn&#39;t incorporate into our project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On/off switch&lt;/li&gt;
&lt;li&gt;Rechargeable battery&lt;/li&gt;
&lt;li&gt;MIDI-USB output + Real-time MIDI input into software&lt;/li&gt;
&lt;li&gt;LED backlight under the keyboard?&lt;/li&gt;
&lt;li&gt;Stereo audio (L/R)&lt;/li&gt;
&lt;li&gt;Reverb/Chorus settings&lt;/li&gt;
&lt;li&gt;Note velocity! (Our buttons weren&#39;t responsive enough—even though we used the Yamaha ones.)&lt;/li&gt;
&lt;li&gt;Better storage (currently we only load/store MIDI for one piece)&lt;/li&gt;
&lt;li&gt;Explore and use &lt;a href=&quot;https://github.com/FluidSynth/fluidsynth&quot;&gt;FluidSynth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;More instrument options&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;ve also published some follow-up tutorials on digital audio synthesis, in case you&#39;re interested in getting your feet wet with audio processing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-1&quot;&gt;Part 1: Digital Signal Processing Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-2&quot;&gt;Part 2: Audio Synthesis Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trebledj.me/posts/digital-audio-synthesis-for-dummies-part-3&quot;&gt;Part 3: Audio Synthesis on Embedded Systems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I was excited to try C++20 modules—which gcc-arm v11 supports!—but CMake doesn&#39;t support modules yet. The &lt;a href=&quot;https://gitlab.kitware.com/cmake/cmake/-/issues/18355&quot;&gt;issue&lt;/a&gt; is still ongoing as I write. I think they&#39;re trying, but I guess nobody likes dealing with compilation order? C&#39;mon CMake! It&#39;s been three years already! &lt;a href=&quot;https://trebledj.me/posts/stm32-midi-keyboard/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
          <category>project</category>
        
          <category>project</category>
        
          <category>embedded</category>
        
          <category>cpp</category>
        
          <category>c</category>
        
          <category>stm32</category>
        
          <category>software-engineering</category>
        
          <category>dsp</category>
        
          <category>music</category>
        
          <category>hkust</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>MuseScore Navigation Plugins</title>
        <description>Developing plugins to enhance the music editors&#39; quality of life.</description>
        <link href="https://trebledj.me/posts/musescore-navigation-plugins/"/>
        <updated>2022-09-10T00:00:00Z</updated>
        <id>https://trebledj.me/posts/musescore-navigation-plugins/</id>
        <content xml:lang="en" type="html">&lt;p&gt;MuseScore, a music notation desktop application, allows mini-extensions through its QML Plugins. MuseScore is built with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Qt_(software)&quot;&gt;Qt&lt;/a&gt; framework and leverages the QML ecosystem for rapid prototyping and user-developed plugins.&lt;/p&gt;
&lt;p&gt;QML is a fun language to work with. Generally, the UI is coded in a declarative style and the logic is coded in JavaScript. This, of course, has the downside of losing the static type-checking of C++; so I would often be in the situation where I need to reload and fix things several times before getting it functioning properly.&lt;/p&gt;
&lt;p&gt;But the freedom and “I don’t care whether your types are correct” attitude of JS were quite nostalgic. Having played with QML/JS before, I decided I wanted to write some MuseScore plugins for fun &lt;s&gt;and also because I felt a need for them&lt;/s&gt;.&lt;/p&gt;
&lt;p&gt;In this post, I’ll introduce my first set of MuseScore plugins and give a brief developer’s account of them. These plugins aren’t really related to music. Rather, they’re inspired by VSCode plugins and features which I find useful. In a way, the plugins below make MuseScore more of a developer’s second home.&lt;/p&gt;
&lt;h2 id=&quot;todo-list&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/musescore-navigation-plugins/#todo-list&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; todo-list&lt;/h2&gt;
&lt;div class=&quot;alert alert-info d-flex align-items-start&quot;&gt; &lt;i class=&quot;fas fa-circle-info ms-1 me-3 mt-1 fs-4&quot; role=&quot;img&quot;&gt;&lt;/i&gt; &lt;div class=&quot;alert-content flex-fill mt-0&quot;&gt;
&lt;p&gt;An update has been published for MuseScore 4.1+. Please refer to the &lt;a href=&quot;https://github.com/TrebledJ/musescore-todo-list/releases/tag/v4.0.0&quot;&gt;new release&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;View the project on: &lt;a href=&quot;https://musescore.org/en/project/musescore-do-list&quot;&gt;MuseScore&lt;/a&gt; / &lt;a href=&quot;https://github.com/TrebledJ/musescore-todo-list&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In software development, to-dos are commonly added into source code as reminders to the poor developers toiling away writing code. To-dos come in many forms: bugs to be fixed, issues to be resolved, feature requests, etc.&lt;/p&gt;
&lt;p&gt;Sometimes when composing, I find myself lost in a sea of to-dos. During a composing session, I might drop a to-do note to follow-up on it next time.&lt;/p&gt;
&lt;p&gt;Here are some examples of to-dos I might encounter while composing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TODO: Explore different chord progressions for this transition.&lt;/li&gt;
&lt;li&gt;TODO: More brass to this section.&lt;/li&gt;
&lt;li&gt;FIXME: Playback sounds wonky.&lt;/li&gt;
&lt;li&gt;TODO: Revise counterpoint.&lt;/li&gt;
&lt;li&gt;TODO: Add bowing articulation to strings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class=&quot;lightbox-single&quot; title=&quot;Image showing the TODO-list plugin in action.&quot; href=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-todo-list-2458w.webp&quot;&gt;&lt;img class=&quot;mb-2 rw center jw-100 &quot; src=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-todo-list-2458w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;aspect-ratio: auto 2458 / 1328&quot; alt=&quot;Image showing the TODO-list plugin in action.&quot; title=&quot;Image showing the TODO-list plugin in action.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-todo-list-256w.webp 256w, https://trebledj.me/img/posts/programming/musescore/assets/plugin-todo-list-512w.webp 512w, https://trebledj.me/img/posts/programming/musescore/assets/plugin-todo-list-1024w.webp 1024w, https://trebledj.me/img/posts/programming/musescore/assets/plugin-todo-list-2458w.webp 2458w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, (max-width: 1024px) 1024px, 2458px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To allow for different to-do styles and text, I provided several settings for the user to modify. These are listed in on the &lt;a href=&quot;https://github.com/TrebledJ/musescore-todo-list&quot;&gt;GitHub readme&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;developer-s-note&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/musescore-navigation-plugins/#developer-s-note&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Developer’s Note&lt;/h3&gt;
&lt;p&gt;This plugin is inspired by the todo-tree plugin in VSCode, which searches files in the current workspace for &lt;code&gt;TODO&lt;/code&gt;s/&lt;code&gt;FIXME&lt;/code&gt;s and lists them in a tree view. I toyed with idea of replicating this on MuseScore—listing to-dos on all open scores—but eventually decided to embrace the &lt;a href=&quot;https://en.wikipedia.org/wiki/KISS_principle&quot;&gt;KISS principle&lt;/a&gt; and just list to-dos for the current score.&lt;/p&gt;
&lt;p&gt;When starting, I took reference of &lt;a href=&quot;https://musescore.org/en/project/annotations&quot;&gt;jeetee’s annotation plugin&lt;/a&gt;. I noticed jeetee used Qt Quick Controls 1.0 instead of 2.0 used in some other plugins. Apparently, QML had made some drastic changes to the styling of controls (buttons, checkboxes, etc.). In 1.0, controls used the native style (e.g. Apple’s aqua style for macs). On the other hand, 2.0 controls require developers to customise styling; this may sound great for design flexibility, but in my experience it’s annoying to get it working with both light and dark themes.&lt;/p&gt;
&lt;div class=&quot;center rw mb-2 h-auto lightbox-gallery&quot;&gt;
&lt;a class=&quot;&quot; title=&quot;Qt-Quick examples.&quot; href=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick1-880w.webp&quot;&gt;&lt;img class=&quot;multi&quot; src=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick1-880w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:49.59%;aspect-ratio: auto 880 / 504&quot; alt=&quot;Qt-Quick examples.&quot; title=&quot;Qt-Quick examples.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick1-256w.webp 256w, https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick1-512w.webp 512w, https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick1-880w.webp 880w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 880px&quot; /&gt;&lt;/a&gt;
&lt;a class=&quot;&quot; title=&quot;Qt-Quick examples.&quot; href=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick2-876w.webp&quot;&gt;&lt;img class=&quot;multi&quot; src=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick2-876w.webp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:45.41%;aspect-ratio: auto 876 / 548&quot; alt=&quot;Qt-Quick examples.&quot; title=&quot;Qt-Quick examples.&quot; srcset=&quot;https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick2-256w.webp 256w, https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick2-512w.webp 512w, https://trebledj.me/img/posts/programming/musescore/assets/plugin-qtquick2-876w.webp 876w&quot; sizes=&quot;(max-width: 256px) 256px, (max-width: 512px) 512px, 876px&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p class=&quot;caption&quot;&gt;&lt;sup&gt;Qt Quick Controls 1.0 vs 2.0. The latter comes with barely any default and takes more effort to properly set up.&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Implementation-wise, the todo-list plugin aims to be self-contained and simple. Self-contained, meaning that everything is in a single .qml file, so that the user doesn’t need to bother with structure too much. Simple, meaning that it doesn’t store too much metadata. The plugin only stores the configuration options mentioned above. I avoid storing data such as measure and staff—which are alike the x and y position in a score—because things get messy when the stored to-do is displaced, e.g. when a user inserts a bunch of measures or removes an instrument.&lt;/p&gt;
&lt;p&gt;Even though I’ve used Qt before, I was still surprised with how easy it was to set up a form dialog to configure user settings. Just slap together a &lt;code&gt;Dialog&lt;/code&gt;, &lt;code&gt;GridLayout&lt;/code&gt;, several &lt;code&gt;Label&lt;/code&gt;s and &lt;code&gt;TextField&lt;/code&gt;s, code the logic, and violà—we have our settings dialog.&lt;/p&gt;
&lt;h2 id=&quot;history&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/musescore-navigation-plugins/#history&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; History&lt;/h2&gt;
&lt;p&gt;View the project on: &lt;a href=&quot;https://musescore.org/en/project/musescore-navigation&quot;&gt;MuseScore&lt;/a&gt; / &lt;a href=&quot;https://github.com/TrebledJ/musescore-navigation&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This plugin keeps track of where your cursor has been so that you can easily jump back and forth between different points in time (effectively making you a time traveller!).&lt;/p&gt;
&lt;p&gt;When programming in an IDE, it is sometimes necessary to jump to a different part of code, then jump back to where you were before. For example, you might want to check the implementation of a certain function.&lt;/p&gt;
&lt;p&gt;Similarly, when editing a score one might wish to visit a section, perhaps copy something, then return to their previous position.&lt;/p&gt;
&lt;p&gt;The History module comprises three separate plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go Back,&lt;/li&gt;
&lt;li&gt;Go Forward, and&lt;/li&gt;
&lt;li&gt;the UI.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first two are action plugins—plugins without any visual component, and just run—whereas the third contains a simple UI. The need for a UI makes the module slightly inflexible for reasons explained below.&lt;/p&gt;
&lt;h3 id=&quot;developer-s-note-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/musescore-navigation-plugins/#developer-s-note-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Developer’s Note&lt;/h3&gt;
&lt;p&gt;There are some limitations to this module, the root cause being the limited MuseScore plugin API.&lt;/p&gt;
&lt;p&gt;For the plugins to work properly, the UI plugin must be activated at all times. This plugin is responsible for recording cursor positions, since MuseScore does not provide a way for plugins to record score/cursor information in the background. We &lt;em&gt;could&lt;/em&gt; start a subprocess, keylog user input, and interpret it to determine where the cursor currently is… but this is of course out of the question, it’s much too tedious and not worth the effort.&lt;/p&gt;
&lt;p&gt;Another drawback is that plugins can’t jump across scores. This is very convenient in IDEs when you have several files open and want to quickly check/copy something from a different file. In MuseScore however, this simply isn’t possible (as far as I could see). So for now, we’ll have to be content with keeping cursor history isolated within each score.&lt;/p&gt;
&lt;h2 id=&quot;bookmarks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/musescore-navigation-plugins/#bookmarks&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Bookmarks&lt;/h2&gt;
&lt;p&gt;View the project on: &lt;a href=&quot;https://musescore.org/en/project/musescore-navigation&quot;&gt;MuseScore&lt;/a&gt; / &lt;a href=&quot;https://github.com/TrebledJ/musescore-navigation&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Marks down a section, saving it so that you can easily return to it later without the pain of scrolling.&lt;/p&gt;
&lt;p&gt;This is really useful for large scores, where scrolling from front to middle to end can be pain. An existing built-in way to jump around sections is to use rehearsal marks plus MuseScore&#39;s timeline. However, I find this insufficient since a rehearsal mark only carries horizontal positioning info (measures), but not vertical positioning info (staffs).&lt;/p&gt;
&lt;p&gt;The Bookmarks module comprises four plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to Previous Bookmark,&lt;/li&gt;
&lt;li&gt;Go to Next Bookmark,&lt;/li&gt;
&lt;li&gt;Toggle Bookmark at Cursor, and&lt;/li&gt;
&lt;li&gt;Clear All Bookmarks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these are action plugins, so in my mind they’re fairly simple and straightforward.&lt;/p&gt;
&lt;h3 id=&quot;developer-s-note-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/musescore-navigation-plugins/#developer-s-note-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Developer’s Note&lt;/h3&gt;
&lt;p&gt;This module was inspired by the VSCode bookmarks plugin. In VSCode, bookmarks allowed you to jump between bookmarks across files and long stretches of code. Sadly alike History, Bookmarks doesn’t jump across files.&lt;/p&gt;
&lt;p&gt;Something else to note—and this applies to all my plugins here: currently, I use a rather hacky method to jump to the selected notes:&lt;/p&gt;
&lt;div class=&quot;code-toolbar&quot;&gt;&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;note-input&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;note-input&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;toolbar&quot;&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;span class=&quot;lang&quot;&gt;JavaScript&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;toolbar-item&quot;&gt;&lt;button class=&quot;copy-to-clipboard-button&quot; type=&quot;button&quot; title=&quot;Copy Code&quot;&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;We call the command twice to toggle between the two different modes (default and note-input).&lt;/p&gt;
&lt;p&gt;However, when jumping to a specific measure + staff, MuseScore will scroll to the correct measure, but not the staff. Logic-wise, nothing is affected since the correct measure + staff are selected. The problem is just a UI issue which the MuseScore Plugins API doesn’t have a solution for. 😢&lt;/p&gt;
&lt;p&gt;For History and Bookmark, I decided to use separate JS files to hold all the logic. This promotes code reuse. For example, both &lt;em&gt;History: Go Back&lt;/em&gt; and &lt;em&gt;History: Go Forward&lt;/em&gt; use the same underlying function to iterate across the score.&lt;/p&gt;
&lt;p&gt;I tried commenting my code cleanly, in case I need to come back to it later; I’m quite forgetful.&lt;/p&gt;
&lt;p&gt;JavaScript’s lack of type checking really irks me. I’m toying with the idea of using TypeScript and compiling the file to JavaScript for testing. I’ve already set up a MakeFile for packaging (zipping) the files anyway, so might as well add a rule that compiles .ts into .js and gain type safety.&lt;/p&gt;
&lt;h2 id=&quot;epilogue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;md-anchor&quot; href=&quot;https://trebledj.me/posts/musescore-navigation-plugins/#epilogue&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt; Epilogue&lt;/h2&gt;
&lt;p&gt;If you’ve read this far, then you’re probably aware that these plugins aren’t perfect. But most of these issues can&#39;t be trivially fixed due to limitations with the Plugin API.&lt;/p&gt;
&lt;p&gt;In my development roadmap, I’ve planned several new (music-related!) plugins. As MuseScore 4 is coming out, I’ll also need to plan the maintenance of the above plugins.&lt;/p&gt;
&lt;p&gt;If you’re interested in using the plugins or contributing, you can check the MuseScore or GitHub links below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To-Do List&lt;/strong&gt;: &lt;a href=&quot;https://musescore.org/en/project/musescore-do-list&quot;&gt;MuseScore&lt;/a&gt; / &lt;a href=&quot;https://github.com/TrebledJ/musescore-todo-list&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;History + Bookmarks&lt;/strong&gt;: &lt;a href=&quot;https://musescore.org/en/project/musescore-navigation&quot;&gt;MuseScore&lt;/a&gt; / &lt;a href=&quot;https://github.com/TrebledJ/musescore-navigation&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and happy musing!&lt;/p&gt;
</content>
        
          <category>programming</category>
        
          <category>project</category>
        
          <category>qml</category>
        
          <category>js</category>
        
          <category>apps</category>
        
          <category>qt</category>
        
          <category>music</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Space Penguin</title>
        <description>And yet another school year begins.</description>
        <link href="https://trebledj.me/posts/space-penguin/"/>
        <updated>2022-08-26T00:00:00Z</updated>
        <id>https://trebledj.me/posts/space-penguin/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Dedicated to everyone feeling stressed, down, lost, or under the weather.&lt;/p&gt;
&lt;p&gt;As we all know, penguins are great swimmers. Sadly however they can&#39;t fly (or so we think!). But as the &lt;a href=&quot;https://learntofly.fandom.com/wiki/Learn_To_Fly_Wiki&quot;&gt;&amp;quot;Learn to Fly&amp;quot; game series&lt;/a&gt; teaches us, with enough dedication, penguins can indeed fly. And with each attempt they reach higher altitudes, even if simply done using a tiny booster rocket.&lt;/p&gt;
&lt;p&gt;Hopefully this little piece may be a booster rocket for you.&lt;/p&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>electronica</category>
        
          <category>synths</category>
        
          <category>dubsy-wubsy</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Joyride in D</title>
        <description>Jetpack Joyride but without a jetpack, and in D.</description>
        <link href="https://trebledj.me/posts/joyride-in-d/"/>
        <updated>2022-01-20T00:00:00Z</updated>
        <id>https://trebledj.me/posts/joyride-in-d/</id>
        <content xml:lang="en" type="html">&lt;p&gt;This upbeat track is an offshoot of &lt;a href=&quot;https://trebledj.me/posts/morning-rush/&quot;&gt;Morning Rush&lt;/a&gt;, spawned from a melody in the latter&#39;s interlude. Couldn&#39;t resist going ham on the drums.&lt;/p&gt;
&lt;p&gt;Unlike &lt;a href=&quot;https://trebledj.me/posts/the-breath-of-life/&quot;&gt;Breath of Life&lt;/a&gt; and Morning Rush, this piece doesn&#39;t have any particular meaning imbued into it, just a fun little composition. I enjoyed writing the keyboard solo (although in its current state, it&#39;s not exactly playable), as well as the guitar countermelody at 2:50. Also writing for drums wasn&#39;t as boring as I thought.&lt;/p&gt;
&lt;p&gt;This is the third of my three 2021 compositions, uploaded to mark the start of 2022. Enjoy.&lt;/p&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>band</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Morning Rush</title>
        <description>&quot;Quickly! School starts in 15 minutes and you still haven&#39;t changed out of your pajamas!&quot;</description>
        <link href="https://trebledj.me/posts/morning-rush/"/>
        <updated>2022-01-19T00:00:00Z</updated>
        <id>https://trebledj.me/posts/morning-rush/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Do you feel the exhilaration of the morning air? The excitement of stepping out of bed? Chomping down breakfast?&lt;/p&gt;
&lt;p&gt;This upbeat track is an offshoot of &lt;a href=&quot;https://trebledj.me/posts/the-breath-of-life/&quot;&gt;The Breath of Life&lt;/a&gt;, rendering its minimalistic elements with a modern instrumentation and at a faster pace. In particular, it combines the 1564 chord progression with the 332 rhythmic pattern in the rhythm guitar.&lt;/p&gt;
&lt;p&gt;This is the second of my three 2021 compositions, uploaded to mark the start of 2022. Enjoy.&lt;/p&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>band</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>The Breath of Life</title>
        <description>Humans are complicated individuals even though we all start from two cells.</description>
        <link href="https://trebledj.me/posts/the-breath-of-life/"/>
        <updated>2022-01-18T00:00:00Z</updated>
        <id>https://trebledj.me/posts/the-breath-of-life/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Slow. Growing. Contemplating. Lush. Carefree. Hopeful. Yearning. This piece seeks to paint a diverse set of feelings. Listen for the string ensemble easing in and out of the void, the solemn moments of silence, the lightheartedness of the syncopated pizzicato, the relentless cycle of tension and relief.&lt;/p&gt;
&lt;p&gt;In some sections, I aimed for a more contemplative and reflective atmosphere. One key inspirations was Steve Reich&#39;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Music_for_18_Musicians&quot;&gt;Music for 18 Musicians&lt;/a&gt; (an hour-long piece!) where Reich demonstrates the idea of &amp;quot;pulsing&amp;quot;, where a note is repeated rapidly at regular intervals with an increase then decrease in dynamics. The overall effect is quite serene, making the soundscape ebb in and out.&lt;/p&gt;
&lt;p&gt;To capture this atmosphere of serenity in The Breath of Life but maintain a slow and steady tempo, I decided for the lower strings (cello + double bass) to play long breves. At the same time, the music would &amp;quot;breathe in&amp;quot; and &amp;quot;breathe out&amp;quot; both dynamically and sometimes harmonically. As the lower strings play a third, the measure tenses up a bit. Examples of these are at 2:24 and 8:00.&lt;/p&gt;
&lt;p&gt;This is the first of my three 2021 compositions, uploaded to mark the start of 2022. Enjoy.&lt;/p&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>minimalism</category>
        
          <category>strings</category>
        
      </entry>
    
  
    
      
      <entry>
        <title>Reticence</title>
        <description>Alternate title: sad.mp3.</description>
        <link href="https://trebledj.me/posts/reticence/"/>
        <updated>2021-08-21T00:00:00Z</updated>
        <id>https://trebledj.me/posts/reticence/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Something about the past few years has been very poignant—deep, memorable, touching yet almost hurting; somewhat close yet also far; cold and distant yet warm inside.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Reticence&lt;/em&gt; was composed as a final project for an introductory course to music composition. Originally, I wanted the piece to be faster and more brisk (akin to a stressed state of mind). But after some reflection (and on further advice by instructors), I settled with a slower tempo. Following further modifications, the final result attempts to capture a held back, cold yet comforting, and ultimately poignant mood.&lt;/p&gt;
&lt;p&gt;The piece was performed by Galison Lau and Ka Lap Wong in the final concert of the course. The SoundCloud upload is a software rendition.&lt;/p&gt;
</content>
        
          <category>composition</category>
        
          <category>music</category>
        
          <category>piano</category>
        
          <category>strings</category>
        
          <category>chamber</category>
        
          <category>counterpoint</category>
        
          <category>hkust</category>
        
      </entry>
    
  
</feed>