{"id":888,"date":"2019-04-26T18:40:40","date_gmt":"2019-04-27T01:40:40","guid":{"rendered":"https:\/\/www.earlevel.com\/main\/?p=888"},"modified":"2019-04-26T18:40:40","modified_gmt":"2019-04-27T01:40:40","slug":"how-i-write-code","status":"publish","type":"post","link":"https:\/\/www.earlevel.com\/main\/2019\/04\/26\/how-i-write-code\/","title":{"rendered":"How I write code"},"content":{"rendered":"<p>Next article I\u2019ll post an update of our wave table oscillator, but first I\u2019ll take the opportunity to discuss how I write code these days. Maybe it will help make sense of some of the choices in the code I post going forward.<\/p>\n<p><i>I tend to build all DSP units as inlines in header files<\/i><\/p>\n<p>True story: Recently, I moved an audio plug-in project I was developing on the Mac in Xcode, to Windows and Visual Studio. I was shocked to see that my source files had disappeared! There was only the main implementation cpp file (not counting the plugin framework), and my headers files. All files were backed up, of course, but it was still unsettling\u2014what could have happened? Then it sank in\u2014I\u2019d written most of the good stuff in header files, so that outside of the plug-in framework, there was indeed only one cpp file\u2014leveraging 28 header files.<\/p>\n<p>The main reason my DSP functions reside in header files is that I make my basic functions inline-able for speed. In a perfectly orderly world, that still might be a header file for the smallest and most critical functions, and a companion C++ source file (.cpp) for the rest. But it\u2019s faster to code and make changes to a single file instead of bouncing between two. And I need only include the header where I use it, instead of also pulling in and marking companion cpp files for compilation.<\/p>\n<p>Further, I write \u201catomic\u201d DSP components that handle basic functions, and build more complex components from these atomic functions. For instance, I have a delay line function, from which I make an allpass delay. Writing a reverb function can be very short and clear, combining these basic functions with other filter functions and feedback. And feedback is easy because all components process a sample at a time instead of blocks. Examples of my library files: OnePole.h, Biquad.h, StateVar.h, DelayLine.h, FIR.h, Noise.h, Gain.h, ADSR.h, WaveTableOsc.h.<\/p>\n<p>Note that \u201cinline\u201d is a request to the compiler. But compilers are pretty good about honoring it. Remember, inline matters most for small functions, where function call overhead is a bigger consideration. And small functions are easiest to inline, so there\u2019s little reason for a compiler to not comply. If you\u2019re concerned, just list and examine the preprocessor output of a source file to see it.<\/p>\n<p>By the way, the usual argument against inlines\u2014\u201cthey lead to bloated code\u201d\u2014doesn\u2019t apply much in the DSP context. These are not large functions used many places in your code. They are built for efficiency. The process routines are localized to your audio processing function, and the setting routines mostly in your plug-in\u2019s parameter handling code.<\/p>\n<p><i>My DSP units are designed for individual samples, not blocks of samples<\/i><\/p>\n<p>Dedicated DSP chips usually process audio a sample at a time. But DSP run on a host computer\u2019s process must handle audio a buffer at a time, to minimize the overhead of context switching. So, if you look at open source DSP libraries, you\u2019ll see that many are written to operate on a buffer of samples.<\/p>\n<p>I don\u2019t do that\u2014my inline functions process a single sample at a time. Of course, you can easily wrap that in a for loop, perhaps partially unrolled to minimize loop overhead. The the next process that acts on the entire buffer, then the next. Or you can string them together, one after the other, to complete your entire algorithm one sample at a time, with an outer loop to iterate through the buffer. The former might work better do the caching advantages, at the expense of more loop overhead. But it\u2019s easier to make this choice with single-sample processes than for a library that\u2019s entirely optimized for buffer processing.<\/p>\n<p><i>I usually write my DSP units as templates<\/i><\/p>\n<p>Mainly, I template them to handle float or double. I use double when developing, but have the option of float available. Filters are a case in which I\u2019ll always use double. For a wavetable oscillator, I want double parameters but float wavetables. A delay line element might be float or double depending on the need. I\u2019d rather build the choice into the DSP unit than to run into a different need and have to take time to rewrite the DSP unit or make a new version of it.<\/p>\n<p>I tend to avoid posting templated stuff on my website, because it can be a distraction from what I\u2019m trying to show.<\/p>\n<p><i>No virtual functions<\/i><\/p>\n<p>I don\u2019t want a vtable. I\u2019m not going to inherit from these basic DSP functions anyway, they are built to do one thing efficiently.<\/p>\n<p>Minor detail: I wrap each DSP header file in a namespace. (I use namespace ESP\u2014which stand for \u201cEarLevel Signal Processing\u201d.) Then I can be lazy with my class names without concern of one day having a namespace collision issue (my \u201cBiquad\u201d versus another \u201cBiquad\u201d built into the plug-in library, for instance).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Next article I\u2019ll post an update of our wave table oscillator, but first I\u2019ll take the opportunity to discuss how I write code these days. Maybe it will help make sense of some of the choices in the code I &hellip; <a href=\"https:\/\/www.earlevel.com\/main\/2019\/04\/26\/how-i-write-code\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"_links":{"self":[{"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/posts\/888"}],"collection":[{"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/comments?post=888"}],"version-history":[{"count":3,"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/posts\/888\/revisions"}],"predecessor-version":[{"id":891,"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/posts\/888\/revisions\/891"}],"wp:attachment":[{"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/media?parent=888"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/categories?post=888"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.earlevel.com\/main\/wp-json\/wp\/v2\/tags?post=888"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}