Krisdigital BlogNews from the labhttps://www.krisdigital.com/en/blog2021-01-06T01:00:00+01:00KrisdigitalApple Appstore Now and Thenhttps://www.krisdigital.com/en/blog/2021/01/06/apple-appstore-now-and-then/2021-01-06T01:00:00+01:002023-12-02T21:57:21+01:00KrisdigitalStarted a test balloon to checkout the state of the app store<p>What to expect from being present in the Apple AppStore today, that is what I am trying to find out after a longer abstinence by starting a test balloon 🎈 </p>
<p>Standard disclaimer: These are just my impressions while trying out the app store after some time. Are yours different? Let me know in the comments!</p>
<p>I did not follow the app store business for some time now, I think I removed my last app around 2015. It was an app that let you find local fashion in stores, but I could not really convince enough stores to join, and without stores and products it was not really interesting for users (🐓🥚) so I gave up at some point. </p>
<p>Now, after creating a <a href="https://www,nooshub.com/">newsreader web app</a>, most feedback was like - is there an app?</p>
<p>So I checked all the different ways to create apps, from native apps, react native, flutter to turbolinks for iOS. And I thought why not create a small native app to get a toe back in the water.</p>
<p>As a guitar player I was looking for a decent tuner for some time, after the one I was using the last years was somehow discontiuned and disappeared when I switched phones. And what can I say, I was somehow shocked how much apps are on the app store that do nothing else as rip users off with subscriptions. I checked out a lot of apps, all free until I actually tried to use them. I ended up buying an app for about 4€ that worked okayish and looked like developed for iOS 3.1.</p>
<p>But what I see as more problematic is the scam that is going on in the app store. The first hit when you search “guitar tuner” is an app that uses a <a href="https://www.youtube.com/watch?v=kxkrdLI6e6M" title="How Dark Patterns Trick You Online - YouTube">dark pattern</a> of showing you three skip buttons, and the fourth button styled the same as the skip buttons starts a subscription for 8.50€ per week!(!!) I would think I am not easily tricked, but I had tapped the button, and only the fingerprint check prevented me from subscribing. Like I said, that is the top app in the app store, and tons of ratings say that it is a rip off.</p>
<p>After a little digging I found out that <a href="https://techcrunch.com/2018/10/15/sneaky-subscriptions-are-plaguing-the-app-store/" title="TechCrunch">this is a known problem in the store since some time now</a>. Don’t know if these companies start these moves after the review process or how this happens. But it seems to also trick the algorithms, because of course these scam apps make the most money and are then recommended by Apple again. Without much searching I was recommended a document scanner app where the negative reviews all told how they were tricked in subscribing.</p>
<p>There are some positive things to mention though. <a href="https://developer.apple.com/app-store/app-privacy-details/" title="App Privacy Details - App Store - Apple Developer">Apple made privacy a selling point</a> and that is now introduced to the app store. You can see for every app what data they are using. Big thumbs up!</p>
<p>Also there is a <a href="https://developer.apple.com/app-store/small-business-program/" title="App Store Small Business Program - Apple Developer">small business program</a> that has just started. That should cut the app store provision in half for most indie developers.</p>
<p>Also your apps are now simultanously desktop apps for M1 macs, not sure how good it works though.</p>
<p>So I started to develop <a href="https://apps.apple.com/us/app/lunatuna-guitar-tuner/id1546894160?itsct=apps_box&amp;itscg=30200" title="LunaTuna - Guitar Tuner on the App Store">the guitar tuner that I was looking for</a>. Of course it turned out harder than I thought it would, not the iOS stuff but the tuning algorithm. So after reading research papers and much trial and error I was ok with the results and decided to publish it as an app.</p>
<h3>Publishing the app takes time</h3>
<p>I wanted to fill everything out as good as possible. The problem is you have to make screen shots and recordings for at least four devices. If you own these four devices it is relatively simple - just start QuickTime, pick new recording from the menu and choose the phone as camera and audio. Then just record your devices four times and make screenshots for all of them.</p>
<p>Chances are that you do not own at least some of the devices, so what to do? There is a solution to this - you can record the simulator! But the catch is you cannot record the audio. Also I needed to switch to h264 codec to get a frame rate greater than one..</p>
<div class="highlight"><pre class="highlight plaintext"><code>xcrun simctl io booted recordVideo --codec h264 appvideo.mp4
</code></pre></div>
<p>So what I ended up doing was record some guitar notes, played that through a speaker, put a mic in front of the speaker that I could use as audio input for the simulator, and recorded the device screen while doing so. Then in iMovie there is actually a menu entry to create an app preview! I imported the recorded screen and the audio and exported it as app preview. When I had all device resolutions two days had passed figuring everything out. It was like completing a puzzle when every device in the iTunes-Connect form was filled out.</p>
<p>The app review is pretty fast, maybe about 8 hours max. </p>
<h3>What to expect</h3>
<p>I do not expect much but I was also curious to know if the app store is a business opportunity for indie developers. </p>
<p>On the first day I had about 50 free downloads, which was more than I had expected. After two days the installs started to decline to about half, but the app was also not available for some time as there was a problem with my account, which I found out by chance. So I will keep an eye on it.</p>
<p>There is virtually no app that costs money in this category, so probably if I take 1€ to get at least the appstore fee back, no one will download it at all. But I will update the article accordingly if I know more.</p>
<p>I think there is a missing functionality in the appstore to provide a trial period. This would be an awesome feature and it would maybe also make the preview videos obsolete, because you could just check yourself. But that is just my opinion.</p>
<p><img src="https://media.giphy.com/media/F3G8ymQkOkbII/giphy.gif" alt="my opinion" /></p>
<h3>Update 05/18/22</h3>
<p>It has been quite a while since I published the app and I wanted to give a first conclusion.
As expected, even taking one dollar for the app does not really work, at least as long as the app has not many ratings. So I decided to make the app free to get ratings first. I also included a Paypal link, which some actually used, I even got some really generous donations (Thank you very much!). I got awesome ratings and had really nice contacts from all over the world who helped making the algorithm work better in their circumstances. So it was a lot of fun and because of that it was worth doing, but from a business perspective I think it is tough even getting your app store fee back by just selling your app. In Germany the app is in the top 5 for guitar tuners and has a close to 5 star rating, but out of 1000 downloads maybe one rates the app, maybe out of 20.000 one donates money. </p>
<p>Next thing I tried was translating the app to other languages, but downloads in other countries than USA and Germany are growing pretty slowly, Mexico being third. Not sure why other countries like UK and France perform that badly even having the content translated…</p>
<p>An idea I already started is a theme shop, where you can buy custom designs to make the app more individual with an in app purchase. Playing around with OpenGL shaders at the moment, maybe that could also be an option for a guitar tuner more on the crazy side. So maybe I will try that next ☺️</p>
Amp Tonestack VST/AU Pluginhttps://www.krisdigital.com/en/blog/2020/10/24/tonestack-vst-au-plugin/2020-10-24T02:00:00+02:002022-02-28T13:38:36+01:00KrisdigitalA physical modeling Amp Tonestack plugin<p>A physical modeled version of the tonestack circuit of a well known Amp, use it in your VST host on Mac and Linux. <a href="/en/blog/2017/11/11/physical-modeling-audio-unit-extension-v3/">Read more about the theory here.</a></p>
<h2>Download (free)</h2>
<p><strong>MacOS</strong><br>
<a href="/files/bassboy.vst3.au.mac.zip">VST3 + AU</a></p>
<p><strong>Linux</strong><br>
<a href="/files/bassboy.vst3.linux86.zip">VST3</a></p>
Getting started with Chef 🤖https://www.krisdigital.com/en/blog/2019/01/03/getting-started-with-chef/2019-01-03T01:00:00+01:002022-02-28T13:38:36+01:00KrisdigitalHaving to migrate an app to a new server I asked myself, what is the best option to host and maintain my apps. Here is what I found out.<p>Chef is infrastructure automation toolset. It may seem overkill for managing one server, I tried to find a minimal solution to have my server configs in code. </p>
<h2>Why?</h2>
<p><strong>Having to migrate an app to a new server I asked myself, what is the best option to host and maintain my apps. Here is what I found out.</strong></p>
<p>Let’s say you need this setup for running your new carefully crafted app:</p>
<ul>
<li>Mailserver (Spamfilter, imap, postfix..)</li>
<li>Ruby, Python, nodejs</li>
<li>PostgreSql, Redis, memcached</li>
<li>Webserver</li>
<li>SSL</li>
<li>Resque or Sidekiq</li>
<li>DB and File Backup</li>
<li>Staging and production environments</li>
<li>Monitoring</li>
</ul>
<h3>System Requirements</h3>
<ul>
<li>ca. 4GB Ram</li>
<li>200GB SSD</li>
</ul>
<h2>Market: Comfort, Flexibility and Money 💸</h2>
<p>For me there are two different approaches to meet these requirements. </p>
<p><strong>1. Take something like heroku…</strong><br>
and add a service for everything. Get an email account at fastmail, send emails with mailgun, add a database option, a file server like S3, add a redis server and probably something else.
So for Heroku this would cost 50$, plus redis 10$, add S3, Postgres 50$ and so on. Before taking this road I recommend carefully checking the pricing for each service. For this article I checked Mailgun and wondered about the free plan with 10.000 messages included.
If you look closely you will recognize, it is only free until you hit 10.000 messages total, after that it is 79$/Month.. So it is basically like the 30days trial versions from back in the days.
There are probably services that cost less, but it will not get cheaper as hosting your own server.</p>
<p>Let’s be nice and assume <strong>200$</strong> for option one.</p>
<p>Pro:</p>
<ul>
<li>Easier to setup</li>
<li>Powerful services for many tasks</li>
</ul>
<p>Cons:</p>
<ul>
<li>Not as flexible as option 2</li>
<li>Mucho mucho expensive</li>
</ul>
<p><strong>2. Manage your own server</strong><br>
I usually use virtual servers, they are cheap and powerful enough for me. Now you have it, the freedom and power to do everything. But with power there comes responsibility.
Managing a production server can be tough.</p>
<p>You can find virtual servers that meet the requirements for <strong>20$</strong>.</p>
<p>Pro:</p>
<ul>
<li>As flexible as it can get</li>
<li>Cheap</li>
</ul>
<p>Cons:</p>
<ul>
<li>More difficult to setup</li>
<li>Need to be maintained</li>
</ul>
<h2>Managing your Server</h2>
<p>When you get your new server, you probably want to start quickly setting it up. But wait a minute. No matter if you have a virtual server or a real server, you cannot change the hardware.
For a virtual server that often means, that after 5years (for Debian or Ubuntu LTS) you will have to setup everything again. Or maybe you need to scale an setup another system.
Depending on your requirements there might be easier ways (maybe Docker containers), but what I want to write about is automated system configuration.</p>
<p>There are several prominent tools, Chef, Puppet and Ansible to name a few. I am using <a href="https://www.chef.sh/about/">Chef</a> for the examples. What all these solutions have in common, is that your infrastructure/server config is defined by code.
You can check this code in to your repository and easily use it to setup a new server in no time.</p>
<p>Chef is a little hard to get started, but I found a good minimal setup. In the documentation you will see ‘Chef Workstation’, ‘Chef Client’ and ‘Chef Server’. I only use the client that lives on the server and a tool called ‘knife solo’.</p>
<div class="highlight"><pre class="highlight console"><code><span class="gp">$</span><span class="w"> </span>gem <span class="nb">install </span>knife-solo
<span class="gp">$</span><span class="w"> </span>gem <span class="nb">install </span>knife-solo_data_bag
<span class="go">
</span><span class="gp">$</span><span class="w"> </span>knife solo init mychefrepo
</code></pre></div>
<p>These commands build your infrastructure project! For testing you can spin up a <a href="https://www.vagrantup.com">vagrant server</a>..</p>
<p>If you are using vagrant, make some adjustments to your Vagrantfile:</p>
<div class="highlight"><pre class="highlight plaintext"><code>config.vm.hostname = "yourwebsite.com"
config.vm.network "private_network", ip: "172.17.33.10"
</code></pre></div>
<p>It makes sense to have a special user on your server for running chef:</p>
<p>For Ubuntu:</p>
<div class="highlight"><pre class="highlight console"><code><span class="gp">$</span><span class="w"> </span>vagrant ssh
<span class="gp">$</span><span class="w"> </span>adduser chef
<span class="gp">$</span><span class="w"> </span>usermod <span class="nt">-aG</span> <span class="nb">sudo </span>chef
<span class="go">
</span><span class="gp">$</span><span class="w"> </span>visudo
<span class="go">chef ALL=(ALL) NOPASSWD:ALL
</span></code></pre></div>
<p>Then add your ssh key to <code>/home/chef/.ssh/authorized_keys</code></p>
<p>Next let’s install the chef client on your server!</p>
<div class="highlight"><pre class="highlight console"><code><span class="gp">$</span><span class="w"> </span>knife solo prepare chef@172.17.33.10
</code></pre></div>
<p>This should install the chef client on your server and you are ready to go!</p>
<p>But what are all the files and folders in your project you might ask. Those are the important ones:</p>
<div class="highlight"><pre class="highlight plaintext"><code>|
|- cookbooks..
|- data_bags..
|- nodes..
|- roles..
|- site-cookbooks
|- your_cookbook
|- recipes..
|- templates..
|- metadata.rb
|- Berksfile
</code></pre></div>
<p>The first cookbooks folder is for cookbooks that you get from the supermarket. That’s right, there is a supermarket, I will get to that in a minute.</p>
<ul>
<li><code>data_bags</code> is for storing json data that you can use in your receipts.</li>
<li><code>nodes</code> are your servers and specify what should run on which server.</li>
<li><code>site-cookbooks</code> is where your code resides</li>
<li><code>meta_data.rb</code> mucho important, you have to add your dependencies here.</li>
<li><code>Berksfile</code>, like a Gemfile to install cookbooks from the supermarket.</li>
</ul>
<p>So how would you install a database like Postgresql using this setup?
First go to the <code>site-cookbooks</code> folder and add a new folder with your cookbook name, e.g. ‘cooking_noodles’
Also add the other folders recipes, templates and the metadata.rb file.
Under the folder <code>recipes</code> add a file <code>default.rb</code>.</p>
<p>Let’s visit the <a href="https://supermarket.chef.io" title="Welcome - The resource for Chef cookbooks - Chef Supermarket">supermarket</a> and see if you find a solid PostgreSql cookbook that we can use.
Running the <a href="https://supermarket.chef.io/cookbooks?utf8=✓&amp;q=postgresql&amp;platforms%5B%5D=">search</a> turns out a good <a href="https://supermarket.chef.io/cookbooks/postgresql" title="postgresql versions">result</a> with instructions how to setup the PostgreSql database!</p>
<p>So add the following line to your <code>Berksfile</code>:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="n">cookbook</span> <span class="s1">'postgresql'</span><span class="p">,</span> <span class="s1">'~> 7.1.1'</span>
</code></pre></div>
<p>And - very important - add this line to your <code>metadata.rb</code> file:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="n">depends</span> <span class="s1">'postgresql'</span> <span class="c1">## https://supermarket.chef.io/cookbooks/postgresql</span>
</code></pre></div>
<p>Now edit your <code>default.rb</code> to install PostgreSQL and add some database:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="n">postgresql_client_install</span> <span class="s1">'My Postgresql Client install'</span> <span class="k">do</span>
<span class="n">version</span> <span class="s1">'10.0'</span>
<span class="k">end</span>
<span class="n">postgresql_server_install</span> <span class="s1">'Postgresql Server'</span> <span class="k">do</span>
<span class="n">version</span> <span class="s1">'10'</span>
<span class="n">setup_repo</span> <span class="kp">false</span>
<span class="n">initdb_locale</span> <span class="s1">'en_US.utf8'</span>
<span class="n">password</span> <span class="s1">'your_secret_password_should_not_be_here'</span>
<span class="k">end</span>
<span class="n">postgresql_user</span> <span class="s1">'some_user'</span> <span class="k">do</span>
<span class="n">password</span> <span class="s1">'your_other_secret_password_should_not_be_here'</span>
<span class="k">end</span>
<span class="n">postgresql_database</span> <span class="s1">'some_database'</span> <span class="k">do</span>
<span class="n">locale</span> <span class="s1">'en_US.utf8'</span>
<span class="n">template</span> <span class="s1">'template0'</span>
<span class="n">owner</span> <span class="s1">'some_user'</span>
<span class="k">end</span>
</code></pre></div>
<p>As I wrote, you should not check in your secret passwords in plain text. In chef there are encrypted data_bags for this use case!</p>
<p>There are different ways to approach it, here is how I do it..</p>
<p>First you need a text file that contains a strong encryption key. You use this file to encrypt or decrypt the file, also on your server.</p>
<p>Put this file in your project but do not check it in your repository!</p>
<p>Now <a href="https://github.com/thbishop/knife-solo_data_bag">add an encrypted <code>data_bag_item</code></a>:</p>
<div class="highlight"><pre class="highlight console"><code><span class="gp">$</span><span class="w"> </span>knife solo data bag create passwords db <span class="nt">--secret-file</span> <span class="s1">'YOUR_SECRET_FILE_PATH'</span>
</code></pre></div>
<p>Edit the file and add the secrets you need by following these <a href="https://github.com/thbishop/knife-solo_data_bag">instructions</a>.</p>
<p>Then you have to put your secret key somewhere on your server. After that you can use your secrets in your receipts:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="n">passwords</span> <span class="o">=</span> <span class="n">data_bag_item</span><span class="p">(</span><span class="s1">'passwords'</span><span class="p">,</span> <span class="s1">'db'</span><span class="p">,</span> <span class="no">IO</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="s1">'SECRET_FILE_PATH_ON_SERVER'</span><span class="p">).</span><span class="nf">strip</span><span class="p">)</span>
<span class="n">postgresql_user</span> <span class="s1">'some_user'</span> <span class="k">do</span>
<span class="n">password</span> <span class="n">passwords</span><span class="p">[</span><span class="ss">:YOUR_DATABASE_PASSWORD</span><span class="p">]</span>
<span class="k">end</span>
</code></pre></div>
<p>Ready to go! All that is left to do is cooking your recipe. In your <code>nodes</code> folder is a JSON file with your server ip. Open it up and edit the <code>run_list</code> section:</p>
<div class="highlight"><pre class="highlight ruby"><code> <span class="s2">"run_list"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"recipe[cooking_noodles]"</span>
<span class="p">]</span>
</code></pre></div>
<p>This tells the chef client to run your default recipe. Time to cook:</p>
<div class="highlight"><pre class="highlight console"><code><span class="gp">$</span><span class="w"> </span>knife solo cook chef@172.17.33.10
</code></pre></div>
<p>This should install PostgreSql and add a database on your server. From there on you can add more recipes to your cookbook, add it to your run list, add more cookbooks from the supermarket until you have all configured.</p>
<p>Once you are ready you can run your configuration on as many servers as you like or adapt it for another app. But for me doing the server setup this way has even more advantages:</p>
<ul>
<li>you write configuration in Ruby</li>
<li>you have an overview of your infrastructure in code</li>
<li>with some adjustments it should even work on different systems, Ubuntu, Debian, CentOS etc.</li>
</ul>
<p>I hope this little walkthrough worked out for you and helped to get you started. For me this was the most difficult thing, as there are so many different existing tools and products within Chef that had to be ruled out.</p>
<p>Let me know if something was unclear, there is always room for improvement.</p>
Vizzdom - macOS System Audio Spectrum and Level Analyzerhttps://www.krisdigital.com/en/blog/2018/08/23/vizzdom-mac-system-audio-spectrum-level-analyzer/2018-08-23T02:00:00+02:002022-05-07T16:02:55+02:00KrisdigitalVizzdom lets you inspect your system audio output spectrum and level on macOS, and includes a driver to record system audio.<p>Vizzdom is a little tool for macOS that lets you see the frequency spectrum, RMS and peak level of your system audio. It includes a small driver that you can also use to record your system audio in Garageband, QuickTime etc. </p>
<h3>How it works</h3>
<p>There is not really a way included in macOS to get the system audio, but luckily someone at Apple released an <a href="https://developer.apple.com/documentation/coreaudio/creating_an_audio_server_driver_plug-in">example code for a NullAudio driver</a> that basically does nothing yet, but points anybody in the right direction who wants to get their hands (really) dirty. Another example code, <a href="https://developer.apple.com/library/archive/samplecode/CAPlayThrough/Introduction/Intro.html">CAPlayThrough</a>, shows how to pipe audio from one audio device to another one connecting it with a varispeed node. I added a ringbuffer to the NullAudio driver so that it actually returns audio and connected the volume and mute events of the driver and the system output. When you install the driver (lives in <code>/Library/Audio/Plug-Ins/HAL/DriveThrough.driver</code>) you will have a new virtual device called <code>Drivethrough Device</code> in your system audio settings. That way you can also record your system audio: you choose the virtual device as the system output, and select it as input in your audio workstation, QuickTime etc.</p>
<p>After installing the driver you can hit start and the app will select the virtual device as output and pipe it to the selected real output device and mirror the volume settings between the two. Then you can watch the frequencies dance to your favorite tunes for hours ☺️</p>
<p>You can easily uninstall the driver from the <code>Setup</code> menu. You can also just delete the driver and restart coreaudio by running</p>
<div class="highlight"><pre class="highlight plaintext"><code>sudo kill `ps -ax | grep 'coreaudiod' | grep 'sbin' |awk '{print $1}'`
</code></pre></div>
<p>from your terminal.</p>
<h3>Disclaimer</h3>
<p>This is very alpha-ish software, mostly because I only tested it on my Macbook. It works flawless on my M1 Macbook running 12.3.1 and a lot of debugging went into it to make it work, but your mileage may vary ✌️</p>
<h3>Download</h3>
<div class="download" id="download">
<div class="download__logo">
<img src="/images/../images/blog/content/vizzdom-logo.png" alt="Vizzdom Logo" />
</div>
<div class="download__content">
<strong>Vizzdom Analyzer</strong><br/>
<a href="/files/VizzdomAnalyzer.zip">macOS</a> (ver. 1.10)
</div>
</div>
<h4>How to install and record system audio</h4>
<p>Anything that is playing through your speakers or headphones can be recorded after installing the driver.</p>
<ol>
<li>Download and open - if you like to use the analyzer, you need to grant microphone access when asked</li>
<li>You should see an “Install Driver” button to install the driver and restart coreaudio<br>
<img src="/images/../images/blog/content/vizzdom-install-screen.png" alt="Install screen" /></li>
<li>If you hit start, the app pipes your system audio through the virtual device and you should see the frequencies dance when playing audio 🕺 (not needed for recording)</li>
<li>To record audio, you go to your audio settings and choose “Drivethrough Device” as <strong>Output</strong><br>
<img src="/images/../images/blog/content/vizzdom-settings-screen.png" alt="Settings screen" /></li>
<li>Then you can use this device as <strong>Input</strong> in other apps like QuickTime, Garageband, Ableton, Logic, Cubase, Maschine etc. to record or sample audio coming from anything your computer can play.<br>
<img src="/images/../images/blog/content/vizzdom-quicktime-screen.png" alt="Quicktime screen" /></li>
</ol>
<p><small>Sorry for the german screen shots…</small></p>
<p>If you want to uninstall the driver, open the app and choose “Setup -> Uninstall Driver”!</p>
A Physical Modeling Audio Effecthttps://www.krisdigital.com/en/blog/2017/11/11/physical-modeling-audio-unit-extension-v3/2017-11-11T01:00:00+01:002022-07-18T13:30:24+02:00KrisdigitalBuilding an Amp tonestack analysing the circuit<p>I have been interested in Physical Modeling for some time. The fact that you reach a very similar result in two completely different ways is fascinating. I used a Line6 Pod (the first version) as a guitar amp for a long time and I still think it is fascinating how they managed to get this functionality on some lame ass CPU in 1997. </p>
<p>Twenty years later a freezer has probably more CPU power than the Line6 Pod and there are other possibilities for physical (Amp-)Modeling. Some <a href="https://en.wikipedia.org/wiki/Digital_audio_workstation">DAWs</a> have amp modeling built in, there are tons of amp modeling apps for iOS, and there is hardware from all major amp manufacturers and specialists like Kemper, Fractal Audio and Line6 amongst others. </p>
<p>Because the math behind DSP stuff is not easy, I picked a topic where I could check the result. There is <a href="http://www.duncanamps.com/tsc/">a tool for Windows (95!!)</a> that shows the frequency response for common guitar amp tonestacks. I also found <a href="https://ccrma.stanford.edu/~dtyeh/papers/DavidYehThesissinglesided.pdf">this dissertation by David Yeh at Stanford</a> which is a great read if you want to get into the topic. What is a tonestack? It is the EQ section (Low, Mid, Treble) of an amplifier.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Fender_Bassman">Fender Bassman</a> is a legendary amplifier introduced in 1952. As many other amps (Marshall amongst others) use the same electrical circuit for their tonestack, you could just change the values of the resistors and capacitors to simulate another amp’s tonestack.</p>
<div class="embed-responsive embed-responsive--16by9">
<lite-youtube videoid="5PaiDuiLzas">
</div>
<p>What I did:</p>
<ol>
<li>Analyze the circuit</li>
<li>Calculate the function of the output voltage</li>
<li>Transfer the equations to the digital domain</li>
<li>Implement the filter</li>
<li>Build an AudioUnit Extension</li>
</ol>
<p>A lot of work to be covered! As a motivation to read on, here is a video of the result (I know, there are some visual incontinuities with the knobs :=)). </p>
<div class="embed-responsive embed-responsive--16by9">
<lite-vimeo videoid="242464386">
</div>
<p>What is special about this filter?</p>
<ul>
<li>When you turn everything up, there is a mid cut, no flat curve</li>
<li>There are no independent filter bands, the paramaters influence each other</li>
</ul>
<h3>Analyze the circuit</h3>
<p>There is more than one way to analyze a circuit, I chose the technique of nodal analysis. The sum of currents at each node is equal to zero. I marked the nodes as “o” in the diagram.</p>
<div class="highlight"><pre class="highlight plaintext"><code> C1
+ +
Vi +------+-----+ +-----o Vex
| + + |
| +++
| | |
| | | (1-t)*R1
| | |
+++ +++
| | +
R4 | | o-------+ Vo
| | |
+++ |
| +++
| | |
| | | t*R1
| | |
| C2 +++
| |
| + + |
o-----+ +-----o
| + + |
| |
| +++
| | |
| | | l*R2
| | |
| +++
| |
| o
| +
| +++
| | |
| | | (1-m)*R3
| C3 | |
| +++
| + + |
+-----+ +-----o
+ + |
|
+++
| |
| | m*R3
| |
+++
|
|
+---+
+-+
+
</code></pre></div>
<p>The current through a capacitor is <code>i = C * dv/dt</code>, so for the voltage Vex in the diagram you will get the following equation:</p>
<p><code>C1*dv/dt*(Vi-Vex) + (Vo-Vex)/((1-t)*R1) = 0</code></p>
<p>Repeating this at the other nodes results in six equations for six voltages, we are interested in Vo. One problem are the terms <code>dv/dt</code>, but luckily there is a thing called <a href="https://en.wikipedia.org/wiki/Laplace_transform">Laplace Transform</a> that allows you to replace every occurence of <code>dv/dt</code> with an <code>s</code>.</p>
<h3>Calculate the function of the output voltage</h3>
<p>Still this linear equation system is hard to solve manually. Probably my old TI-89 calculator could have done it, but there is a great open source software called <a href="https://en.wikipedia.org/wiki/Maxima_(software)">Maxima</a>. It is based on software from 1968 and is still widely used. The only functions I needed were <code>linsolve</code> to solve the equations and <code>ratsimp</code> to factor out variables.</p>
<p>The result for Vo:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Vo = ((C1*R1*Vi*(C2*(C3*R3*R4-C3*R3*R4*m)+C2*C3*R2*R4*l)*s^3+C1*R1*(C3*R4+C2*R4)*Vi*s^2+C1*R1*Vi*s)*t+Vi*
(C1*(C2*(C3*R3^2*R4*m-C3*R3^2*R4*m^2)+C2*C3*R2*R3*R4*l*m)+C1*R1*(C2*(C3*R3^2*m-C3*R3^2*m^2)+C2*C3*R2*R3*l*m))*s^3+Vi*(C1*
(-C3*R3^2*m^2+R2*l*(C3*R3*m+C3*R4+C2*R4)+C3*R3^2*m+C3*R3*R4+C2*R3*R4)+C2*(C3*R3^2*m-C3*R3^2*m^2)+C1*R1*(C3*R3*m+C2*R2*l+C2*R3)+C2*C3*R2*
R3*l*m)*s^2+Vi*(C3*R3*m+C1*(R2*l+R3)+C2*R2*l+C2*R3)*s)/(
(C1*(C2*(C3*R3^2*R4*m-C3*R3^2*R4*m^2)+C2*C3*R2*R3*R4*l*m)+C1*R1*(C2*(-C3*R3^2*m^2+(C3*R3^2-C3*R3*R4)*m+C3*R3*R4)+C2*R2*l*(C3*R3*m+C3*R4)))*s^3+
(C1*(-C3*R3^2*m^2+R2*l*(C3*R3*m+C3*R4+C2*R4)+C3*R3^2*m+C3*R3*R4+C2*R3*R4)+C2*(-C3*R3^2*m^2+(C3*R3^2-C3*R3*R4)*m+C3*R3*R4)+C1*R1*
(C3*R3*m+C2*R2*l+C2*(R4+R3)+C3*R4)+C2*R2*l*(C3*R3*m+C3*R4))*s^2+(C3*R3*m+C1*(R2*l+R3)+C2*R2*l+C2*(R4+R3)+C3*R4+C1*R1)*s+1)
</code></pre></div>
<p>😳</p>
<h3>Transfer the equations to the digital domain</h3>
<p>For a filter we need the transfer function</p>
<div class="highlight"><pre class="highlight plaintext"><code>H(s) = Vo/Vi
</code></pre></div>
<p>Easily enough that just removes all occurrences of Vi in our equation for Vo.</p>
<p>For implementing the filter later we need to transform this to be of the form: </p>
<div class="highlight"><pre class="highlight plaintext"><code> b0 + b1*z^-1 + b2*z^-2 + b3*z^-3
H(z) = ------------------------------------
1 + a1*z^-1 + a2*z^-2 + a3*z^-3
</code></pre></div>
<p>For that the <a href="https://en.wikipedia.org/wiki/Bilinear_transform">bilinear transform</a> is used. We set <code>s = K*(1-z)/(1+z)</code> and I used <code>ratsimp</code>
in Maxima like <code>ratsimp(Vo, z)</code> to get the coefficients b0, b1, b2, b3 and a1, a2, a3. K is 1/T where T is the time interval between the digital samples, for example 1/44100 seconds.</p>
<div class="highlight"><pre class="highlight plaintext"><code>H(z) = (((C1*C2*C3*K^3*R1*R3*R4*m-C1*C2*C3*K^3*R1*R2*R4*l+(((-C1*C3-C1*C2)*K^2*R1-C1*C2*C3*K^3*R1*R3)*R4-C1*K*R1))*t+
(C1*C2*C3*K^3*R3^2*R4+(C1*C2*C3*K^3*R1+(C2+C1)*C3*K^2)*R3^2)*m^2+((((-C2-C1)*C3*K^2-C1*C2*C3*K^3*R1)*R2*R3-C1*C2*C3*K^3*R2*R3*R4)*l+
(-C1*C2*C3*K^3*R3^2*R4+((-C2-C1)*C3*K^2-C1*C2*C3*K^3*R1)*R3^2+(-C1*C3*K^2*R1-C3*K)*R3))*m+
((-C1*C3-C1*C2)*K^2*R2*R4+((-C2-C1)*K-C1*C2*K^2*R1)*R2)*l+((-C1*C3-C1*C2)*K^2*R3*R4+((-C2-C1)*K-C1*C2*K^2*R1)*R3))*z^3+(
(-3*C1*C2*C3*K^3*R1*R3*R4*m+3*C1*C2*C3*K^3*R1*R2*R4*l+((3*C1*C2*C3*K^3*R1*R3+(C1*C3+C1*C2)*K^2*R1)*R4-C1*K*R1))*t+
(((-C2-C1)*C3*K^2-3*C1*C2*C3*K^3*R1)*R3^2-3*C1*C2*C3*K^3*R3^2*R4)*m^2+((3*C1*C2*C3*K^3*R2*R3*R4+(3*C1*C2*C3*K^3*R1+(C2+C1)*C3*K^2)*R2*R3)*l+
(3*C1*C2*C3*K^3*R3^2*R4+(3*C1*C2*C3*K^3*R1+(C2+C1)*C3*K^2)*R3^2+(C1*C3*K^2*R1-C3*K)*R3))*m+
((C1*C3+C1*C2)*K^2*R2*R4+(C1*C2*K^2*R1+(-C2-C1)*K)*R2)*l+((C1*C3+C1*C2)*K^2*R3*R4+(C1*C2*K^2*R1+(-C2-C1)*K)*R3))*z^2+(
(3*C1*C2*C3*K^3*R1*R3*R4*m-3*C1*C2*C3*K^3*R1*R2*R4*l+(((C1*C3+C1*C2)*K^2*R1-3*C1*C2*C3*K^3*R1*R3)*R4+C1*K*R1))*t+
(3*C1*C2*C3*K^3*R3^2*R4+(3*C1*C2*C3*K^3*R1+(-C2-C1)*C3*K^2)*R3^2)*m^2+((((C2+C1)*C3*K^2-3*C1*C2*C3*K^3*R1)*R2*R3-3*C1*C2*C3*K^3*R2*R3*R4)*l+
(-3*C1*C2*C3*K^3*R3^2*R4+((C2+C1)*C3*K^2-3*C1*C2*C3*K^3*R1)*R3^2+(C1*C3*K^2*R1+C3*K)*R3))*m+
((C1*C3+C1*C2)*K^2*R2*R4+(C1*C2*K^2*R1+(C2+C1)*K)*R2)*l+((C1*C3+C1*C2)*K^2*R3*R4+(C1*C2*K^2*R1+(C2+C1)*K)*R3))*z+
(-C1*C2*C3*K^3*R1*R3*R4*m+C1*C2*C3*K^3*R1*R2*R4*l+((C1*C2*C3*K^3*R1*R3+(-C1*C3-C1*C2)*K^2*R1)*R4+C1*K*R1))*t+
(((C2+C1)*C3*K^2-C1*C2*C3*K^3*R1)*R3^2-C1*C2*C3*K^3*R3^2*R4)*m^2+((C1*C2*C3*K^3*R2*R3*R4+(C1*C2*C3*K^3*R1+(-C2-C1)*C3*K^2)*R2*R3)*l+
(C1*C2*C3*K^3*R3^2*R4+(C1*C2*C3*K^3*R1+(-C2-C1)*C3*K^2)*R3^2+(C3*K-C1*C3*K^2*R1)*R3))*m+
((-C1*C3-C1*C2)*K^2*R2*R4+((C2+C1)*K-C1*C2*K^2*R1)*R2)*l+((-C1*C3-C1*C2)*K^2*R3*R4+((C2+C1)*K-C1*C2*K^2*R1)*R3))/((
(C1*C2*C3*K^3*R3^2*R4+(C1*C2*C3*K^3*R1+(C2+C1)*C3*K^2)*R3^2)*m^2+((((-C2-C1)*C3*K^2-C1*C2*C3*K^3*R1)*R2*R3-C1*C2*C3*K^3*R2*R3*R4)*l+
((C1*C2*C3*K^3*R1+C2*C3*K^2)*R3-C1*C2*C3*K^3*R3^2)*R4+((-C2-C1)*C3*K^2-C1*C2*C3*K^3*R1)*R3^2+(-C1*C3*K^2*R1-C3*K)*R3)*m+
((((-C2-C1)*C3-C1*C2)*K^2-C1*C2*C3*K^3*R1)*R2*R4+((-C2-C1)*K-C1*C2*K^2*R1)*R2)*l+
((((-C2-C1)*C3-C1*C2)*K^2-C1*C2*C3*K^3*R1)*R3+(-C1*C3-C1*C2)*K^2*R1+(-C3-C2)*K)*R4+((-C2-C1)*K-C1*C2*K^2*R1)*R3-C1*K*R1-1)*z^3+(
(((-C2-C1)*C3*K^2-3*C1*C2*C3*K^3*R1)*R3^2-3*C1*C2*C3*K^3*R3^2*R4)*m^2+((3*C1*C2*C3*K^3*R2*R3*R4+(3*C1*C2*C3*K^3*R1+(C2+C1)*C3*K^2)*R2*R3)*l+
(3*C1*C2*C3*K^3*R3^2+(-3*C1*C2*C3*K^3*R1-C2*C3*K^2)*R3)*R4+(3*C1*C2*C3*K^3*R1+(C2+C1)*C3*K^2)*R3^2+(C1*C3*K^2*R1-C3*K)*R3)*m+
((3*C1*C2*C3*K^3*R1+((C2+C1)*C3+C1*C2)*K^2)*R2*R4+(C1*C2*K^2*R1+(-C2-C1)*K)*R2)*l+
((3*C1*C2*C3*K^3*R1+((C2+C1)*C3+C1*C2)*K^2)*R3+(C1*C3+C1*C2)*K^2*R1+(-C3-C2)*K)*R4+(C1*C2*K^2*R1+(-C2-C1)*K)*R3-C1*K*R1-3)*z^2+(
(3*C1*C2*C3*K^3*R3^2*R4+(3*C1*C2*C3*K^3*R1+(-C2-C1)*C3*K^2)*R3^2)*m^2+((((C2+C1)*C3*K^2-3*C1*C2*C3*K^3*R1)*R2*R3-3*C1*C2*C3*K^3*R2*R3*R4)*l+
((3*C1*C2*C3*K^3*R1-C2*C3*K^2)*R3-3*C1*C2*C3*K^3*R3^2)*R4+((C2+C1)*C3*K^2-3*C1*C2*C3*K^3*R1)*R3^2+(C1*C3*K^2*R1+C3*K)*R3)*m+
((((C2+C1)*C3+C1*C2)*K^2-3*C1*C2*C3*K^3*R1)*R2*R4+(C1*C2*K^2*R1+(C2+C1)*K)*R2)*l+
((((C2+C1)*C3+C1*C2)*K^2-3*C1*C2*C3*K^3*R1)*R3+(C1*C3+C1*C2)*K^2*R1+(C3+C2)*K)*R4+(C1*C2*K^2*R1+(C2+C1)*K)*R3+C1*K*R1-3)*z+
(((C2+C1)*C3*K^2-C1*C2*C3*K^3*R1)*R3^2-C1*C2*C3*K^3*R3^2*R4)*m^2+((C1*C2*C3*K^3*R2*R3*R4+(C1*C2*C3*K^3*R1+(-C2-C1)*C3*K^2)*R2*R3)*l+
(C1*C2*C3*K^3*R3^2+(C2*C3*K^2-C1*C2*C3*K^3*R1)*R3)*R4+(C1*C2*C3*K^3*R1+(-C2-C1)*C3*K^2)*R3^2+(C3*K-C1*C3*K^2*R1)*R3)*m+
((C1*C2*C3*K^3*R1+((-C2-C1)*C3-C1*C2)*K^2)*R2*R4+((C2+C1)*K-C1*C2*K^2*R1)*R2)*l+
((C1*C2*C3*K^3*R1+((-C2-C1)*C3-C1*C2)*K^2)*R3+(-C1*C3-C1*C2)*K^2*R1+(C3+C2)*K)*R4+((C2+C1)*K-C1*C2*K^2*R1)*R3+C1*K*R1-1)
</code></pre></div>
<p>😳😳</p>
<p>As you can see this rather simple electrical circuit results in a good chunk of mathematical operations in the digital domain!
Note that I did not normalize the equation at this point so that there is a <code>1+a1...</code> in the denominator, I did it later in the implementation by dividing all parameters.</p>
<h3>Calculate the magnitude of the transfer function</h3>
<p>For the visualization of the transfer function we need the magnitude as a function of the frequency. For stable systems like our filter we can set <code>z=e^-jw</code>, <a href="https://www.ee.columbia.edu/~dpwe/e4810/matlab/pezdemo/help/theory.html">here is a good explanation for that</a>. With <code>e^-jw = cos(w) - jsin(w)</code> we can put that in the equation of our transfer function and then calculate the magnitude for the nominator and denominator by <code>M1 = sqrt(Real^2 + Imaginary^2)</code>, so that the final magnitude is</p>
<div class="highlight"><pre class="highlight plaintext"><code> Mnominator
M = --------------
Mdenominator
</code></pre></div>
<p>A good way to check your results is using Python. There a great packages for doing signal processing and visualizations. To plot the frequency response of a digital filter you can use the <a href="https://docs.scipy.org/doc/scipy-0.19.1/reference/generated/scipy.signal.freqz.html">scipy.signal.freqz</a> function.</p>
<p><img src="/images/../images/blog/content/bassboy-l0-m0-t1.png" alt="Bassboy L0 M0 T1" />
Filter magnitude response for l=0, m=0, t=1</p>
<h3>Implement the filter</h3>
<p>At this point we have everything we need to implement the digital IIR filter. Actually it is fairly simple to implement, all you need to do is put the coefficients in the following equation:</p>
<div class="highlight"><pre class="highlight plaintext"><code>(b0 * x0) + (b1 * state.x1) + (b2 * state.x2) + (b3 * state.x3) - (a1 * state.y1) - (a2 * state.y2) - (a3 * state.y3)
</code></pre></div>
<p>Where <code>state</code> contains past values, so <code>state.x1</code> is <code>x[n-1]</code> etc.</p>
<p>The theory behind that is shown <a href="https://de.wikipedia.org/wiki/Filter_mit_unendlicher_Impulsantwort#/media/File:DF1.png">in this illustration</a>.</p>
<h3>Extra: Build an AudioUnit Extension</h3>
<p>At first I built this as an AudioUnitV3. I saw a presentation of the new technology and one of the code examples was an EQ, so it was a good starting point for prototyping. You can skip this as I ported the effect to VST3/AU in the meantime!</p>
<p>First off, what is an AudioUnit Extension. To be honest when I started this I thought it would just be the next version of AudioUnits, but it is a completly different concept, that Apple does not only use for Audio but <a href="https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/index.html">for all kinds of stuff</a>. I started with the <a href="https://developer.apple.com/library/content/samplecode/AudioUnitV3Example/Introduction/Intro.html">example code</a> which already includes a filter example, which comes handy.</p>
<p>App extensions always have to be embedded in an app, that is how they are distributed. The reason behind that is probably iOS and the app store: you need an app to get new software on iDevice. So when you launch the app, the contained AppExtension is registered and can then be used as usually.</p>
<p>I developed a macOS Audio Extension because I wanted to use it in Logic9 and Garageband, but I realized that is not supported yet. It does not even work in AU Lab either. There comes an AuV3ExampleHost with the example code that you can use. I will probably try to extract the audio unit and compile a good old AudioUnit so that I can share it more easily and use it myself. The newest Logic should support them, that is what I heard at least..</p>
<p>The example code has a pretty complex build setup to show you how to build the effect for iOS and macOS while reusing common framework code. If you start from scratch there is a template for the AudioUnit Extension build target.</p>
<p>But what I did is just to modify the appropriate functions in <code>FilterDSPKernel.hpp</code>, that is where the processing takes place. And of course the parameters have to be rewired.</p>
<h4>User Interface</h4>
<p>If you want an App Extension that runs on iOS and macOS you can only reuse the processing code, not the UI. iOS uses UIKit, macOS uses AppKit. They are similar, but still you cannot just reuse the UI-code and Interface-Builder files. For example in AppKit there is a circular slider element (=Knob), in UIKit there isn’t. While on iOS you will use UIClassName, on macOS it will be NSClassName etc.</p>
<p>For the filter I just needed some Knobs as a control for the parameters Low, Mid and Treble. For that I made a <a href="https://github.com/krisdigital/swift-appkit-image-knob">custom NSControl element</a>. What I learned here is the use of <code>@IBDesignable</code> and <code>@IBInspectable</code> to actually see the element in interface builder (IB) to tweak it:</p>
<p><img src="/images/../images/blog/content/bassboy-ib.png" alt="Bassboy Ib" />
As you can see you can select an image for the knob in IB and it is rendered in the preview.</p>
<p>Another thing is responsive design. As your extension might run on all kinds of devices, it is important that it behaves well on the different screen sizes. For that Autolayout is probably the way to go as it is here to stay. Even if I think the term ‘Autolayout’ is somewhat an euphemism :=)</p>
<p>To get the knobs scale relatively to the superview and to keep their position I used the following approach of aligning the centers and using a multiplier. 0 is left, 1 is middle, and 2 is right. Then I made the width of the knob a fraction of the superview width and the aspect ratio 1:1 et voilà..</p>
<p><img src="/images/../images/blog/content/bassboy-ib-knob-auto.png" alt="Bassboy Ib Knob Auto" /></p>
<h3>Download</h3>
<p>In the meantime I ported the plugin to VST/AU!</p>
<p><strong><a href="/en/blog/2020/10/24/tonestack-vst-au-plugin/">Get the VST/AU Plugin</a></strong></p>
Baywatcher - A Go Experimenthttps://www.krisdigital.com/en/blog/2017/07/22/baywatcher-experiment-with-go/2017-07-22T02:00:00+02:002022-02-28T13:38:36+01:00KrisdigitalMy notes after completing 'Baywatcher', an Ebay search assistant. It is not really a technical document, more like a business perspective of a programmer.<p>My notes after completing ‘Baywatcher’, an Ebay search assistant. It is not really a technical document, more like a business perspective of a programmer. </p>
<h3>Short Facts</h3>
<ul>
<li><strong>Aim of the app:</strong> Find Ebay items that match a query and are below a certain price short before the end of an auction and notify the user of it*.<br></li>
<li><strong>Why:</strong> Evaluate Go in a real world application.</li>
<li><strong>Where:</strong> <a href="http://baywatcher.krisdigital.com">http://baywatcher.krisdigital.com</a></li>
</ul>
<p>* On ebay you can follow a search, but you get items long before end of auction, which turned out to be not very useful for me.</p>
<h3>Functionality</h3>
<ul>
<li>Create an account and and a wishlist of items</li>
<li>A search consists of keywords, a max price, an ebay category and the ebay store (country)</li>
<li>Searches are done repeatedly for the user and if a search criteria is met 4 hours before end of auction, the user is notified by email</li>
</ul>
<h3>Tech Stack</h3>
<ul>
<li>Go, intentionally without any external dependencies</li>
<li>React for the frontend</li>
<li>Milligram CSS Framework for better optics ;)</li>
</ul>
<h3>Go experience</h3>
<p>I liked the minimal approach, the explicitness, the completeness of the toolset, from code formatting (using old school Textmate), great standard library (http, encryption, sql, xml, json etc.), to testing, there is everything included. At the end you get a compiled binary with top performance. It was also easy to pick up and get productive.</p>
<p>Statically typed, it prevents many errors upfront, but it does not get too much in the way either. Code amount vs progress efficiency is also good, as I would say.</p>
<p>I understand that the explicitness can also be seen negative, you have to write <code>if err == nil</code> very often, it is a matter of taste. I will check Elixir next and decide which I like better. For me it is a big plus to have code, that is easy to read.</p>
<p>Compared to RubyOnRails (which I use and will use quite often), where there are already 10 gems for every problem you can think of (which is good), in Go it is great to build stuff your own with the tools of Go. It helps you solve problems and does not get in the way doing so. That said, you probably will not find yourself programming a CMS like website or CRUD app with it, there are better tools for that out there.</p>
<h3>Right tool for this job</h3>
<p><strong>YES</strong></p>
<h3>Things Go is good for</h3>
<ul>
<li>Building services, especially if they work with http</li>
<li>everything performance and concurrency critical</li>
<li>Apis (imo as long not too much database complexity is involved)</li>
</ul>
<h3>Result</h3>
<p>The app not only works, but it also turned out to be quite useful for me $$$ ;)</p>